From 73aa4372590ea6258ac99a6358d3fd97a10b94eb Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Wed, 6 Aug 2025 16:05:03 -0700 Subject: [PATCH] Finalize lasso selection tool - Move under rectangular selection - Simplify available modes - Link to new icon - Make selection state persistent - Allow additive/subtractive with KiCad configurable keys --- common/preview_items/selection_area.cpp | 12 +- common/tool/actions.cpp | 49 +--- include/tool/actions.h | 12 +- include/tool/selection_tool.h | 3 +- include/tool/tool_event.h | 5 - pcbnew/footprint_edit_frame.cpp | 7 - pcbnew/menubar_footprint_editor.cpp | 6 - pcbnew/menubar_pcb_editor.cpp | 6 - pcbnew/pcb_edit_frame.cpp | 7 - pcbnew/toolbars_footprint_editor.cpp | 9 +- pcbnew/toolbars_pcb_editor.cpp | 9 +- pcbnew/tools/pcb_actions.cpp | 2 +- pcbnew/tools/pcb_selection_tool.cpp | 373 +++++++++--------------- pcbnew/tools/pcb_selection_tool.h | 58 +--- pcbnew/zone.h | 2 +- 15 files changed, 179 insertions(+), 381 deletions(-) diff --git a/common/preview_items/selection_area.cpp b/common/preview_items/selection_area.cpp index 3fe4fcd9c2..19fc87a876 100644 --- a/common/preview_items/selection_area.cpp +++ b/common/preview_items/selection_area.cpp @@ -87,7 +87,6 @@ const BOX2I SELECTION_AREA::ViewBBox() const break; case SELECTION_MODE::INSIDE_LASSO: case SELECTION_MODE::TOUCHING_LASSO: - case SELECTION_MODE::TOUCHING_PATH: tmp = m_shape_poly.BBox(); break; } @@ -136,10 +135,6 @@ void SELECTION_AREA::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const if( m_shape_poly.PointCount() > 1 ) gal.DrawPolygon( m_shape_poly ); break; - case SELECTION_MODE::TOUCHING_PATH: - if( m_shape_poly.PointCount() > 0 ) - gal.DrawPolyline( m_shape_poly ); - break; } }; @@ -151,9 +146,6 @@ void SELECTION_AREA::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const // draw the fill as the second object so that Z test will not clamp // the single-pixel-wide rectangle sides - if( m_mode != SELECTION_MODE::TOUCHING_PATH ) - { - gal.SetIsFill( true ); - drawSelectionShape(); - } + gal.SetIsFill( true ); + drawSelectionShape(); } diff --git a/common/tool/actions.cpp b/common/tool/actions.cpp index 723c27d625..cbc3b28734 100644 --- a/common/tool/actions.cpp +++ b/common/tool/actions.cpp @@ -347,50 +347,19 @@ TOOL_ACTION ACTIONS::paste( TOOL_ACTION_ARGS() .Flags( AF_NONE ) .UIId( wxID_PASTE ) ); -TOOL_ACTION ACTIONS::selectInsideRectangle( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectInsideRectangle" ) +TOOL_ACTION ACTIONS::selectSetRect( TOOL_ACTION_ARGS() + .Name( "common.Interactive.selectSetRect" ) .Scope( AS_GLOBAL ) - .FriendlyName( _( "Inside Rectangle" ) ) - .Tooltip( _( "Select all items fully contained within the rectangular area" ) ) - .Parameter( SELECTION_MODE::INSIDE_RECTANGLE ) ); + .FriendlyName( _( "Rectangle" ) ) + .Tooltip( _( "Set selection mode to use rectangle" ) ) + .Icon( BITMAPS::cursor ) ); -TOOL_ACTION ACTIONS::selectTouchingRectangle( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectTouchingRectangle" ) - .Scope( AS_GLOBAL ) - .FriendlyName( _( "Touching Rectangle" ) ) - .Tooltip( _( "Select all items that touch or intersect the rectangular area" ) ) - .Parameter( SELECTION_MODE::TOUCHING_RECTANGLE ) ); - -TOOL_ACTION ACTIONS::selectInsideLasso( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectInsideLasso" ) - .Scope( AS_GLOBAL ) - .FriendlyName( _( "Inside Lasso" ) ) - .Tooltip( _( "Select all items fully contained within the lasso area" ) ) - .Icon( BITMAPS::add_graphical_polygon ) // TODO: add proper icon - .Parameter( SELECTION_MODE::INSIDE_LASSO ) ); - -TOOL_ACTION ACTIONS::selectTouchingLasso( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectTouchingLasso" ) - .Scope( AS_GLOBAL ) - .FriendlyName( _( "Touching Lasso" ) ) - .Tooltip( _( "Select all items that touch or intersect the lasso area" ) ) - .Icon( BITMAPS::add_dashed_line ) // TODO: add proper icon - .Parameter( SELECTION_MODE::TOUCHING_LASSO ) ); - -TOOL_ACTION ACTIONS::selectAutoLasso( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectAutoLasso" ) +TOOL_ACTION ACTIONS::selectSetLasso( TOOL_ACTION_ARGS() + .Name( "common.Interactive.selectSetLasso" ) .Scope( AS_GLOBAL ) .FriendlyName( _( "Lasso" ) ) - .Tooltip( _( "Select all items fully contained within or touching the lasso area, depending on the drawing direction" ) ) - .Icon( BITMAPS::opt_show_polygon ) ); // TODO: add proper icon - -TOOL_ACTION ACTIONS::selectTouchingPath( TOOL_ACTION_ARGS() - .Name( "common.Interactive.selectTouchingPath" ) - .Scope( AS_GLOBAL ) - .FriendlyName( _( "Touching Path" ) ) - .Tooltip( _( "Select all items that touch or intersect the drawn path" ) ) - .Icon( BITMAPS::add_line ) // TODO: add proper icon - .Parameter( SELECTION_MODE::TOUCHING_PATH ) ); + .Tooltip( _( "Set selection mode to use polygon lasso" ) ) + .Icon( BITMAPS::lasso ) ); TOOL_ACTION ACTIONS::selectAll( TOOL_ACTION_ARGS() .Name( "common.Interactive.selectAll" ) diff --git a/include/tool/actions.h b/include/tool/actions.h index a5c70510da..24a6921c44 100644 --- a/include/tool/actions.h +++ b/include/tool/actions.h @@ -213,15 +213,9 @@ public: /// Select a single item under the cursor position static TOOL_ACTION selectionCursor; - /// Run a box selection tool in a fixed mode - static TOOL_ACTION selectInsideRectangle; - static TOOL_ACTION selectTouchingRectangle; - - /// Run a lasso selection tool - static TOOL_ACTION selectInsideLasso; - static TOOL_ACTION selectTouchingLasso; - static TOOL_ACTION selectAutoLasso; - static TOOL_ACTION selectTouchingPath; + /// Set lasso selection mode + static TOOL_ACTION selectSetRect; + static TOOL_ACTION selectSetLasso; /// Clear the current selection static TOOL_ACTION selectionClear; diff --git a/include/tool/selection_tool.h b/include/tool/selection_tool.h index 1575b8a3fd..031039c3ee 100644 --- a/include/tool/selection_tool.h +++ b/include/tool/selection_tool.h @@ -39,8 +39,7 @@ enum class SELECTION_MODE INSIDE_RECTANGLE, TOUCHING_RECTANGLE, INSIDE_LASSO, - TOUCHING_LASSO, - TOUCHING_PATH + TOUCHING_LASSO }; diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index cb41733c20..40afefc914 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -522,11 +522,6 @@ public: m_param = aParam; } - bool HasParameter() const - { - return m_param.has_value(); - } - std::optional GetCommandId() const { return m_commandId; diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 6290efa401..0c76e03cf8 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -1181,7 +1181,6 @@ void FOOTPRINT_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new COMMON_CONTROL ); m_toolManager->RegisterTool( new COMMON_TOOLS ); m_toolManager->RegisterTool( new PCB_SELECTION_TOOL ); - m_toolManager->RegisterTool( new PCB_LASSO_SELECTION_TOOL ); m_toolManager->RegisterTool( new ZOOM_TOOL ); m_toolManager->RegisterTool( new EDIT_TOOL ); m_toolManager->RegisterTool( new PCB_EDIT_TABLE_TOOL ); @@ -1317,12 +1316,6 @@ void FOOTPRINT_EDIT_FRAME::setupUIConditions() mgr->SetConditions( ACTIONS::pasteSpecial, ENABLE( SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) ); mgr->SetConditions( ACTIONS::doDelete, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::duplicate, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectInsideRectangle, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingRectangle,ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectInsideLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectAutoLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingPath, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::selectAll, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::unselectAll, ENABLE( cond.HasItems() ) ); diff --git a/pcbnew/menubar_footprint_editor.cpp b/pcbnew/menubar_footprint_editor.cpp index 14500be7c8..3baa4175e8 100644 --- a/pcbnew/menubar_footprint_editor.cpp +++ b/pcbnew/menubar_footprint_editor.cpp @@ -112,12 +112,6 @@ void FOOTPRINT_EDIT_FRAME::doReCreateMenuBar() // Select Submenu ACTION_MENU* selectSubMenu = new ACTION_MENU( false, selTool ); selectSubMenu->SetTitle( _( "&Select" ) ); - selectSubMenu->Add( ACTIONS::selectInsideRectangle ); - selectSubMenu->Add( ACTIONS::selectTouchingRectangle ); - selectSubMenu->Add( ACTIONS::selectInsideLasso ); - selectSubMenu->Add( ACTIONS::selectTouchingLasso ); - selectSubMenu->Add( ACTIONS::selectTouchingPath ); - selectSubMenu->AppendSeparator(); selectSubMenu->Add( ACTIONS::selectAll ); selectSubMenu->Add( ACTIONS::unselectAll ); diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index a4824af130..3f22c8c6de 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -184,12 +184,6 @@ void PCB_EDIT_FRAME::doReCreateMenuBar() ACTION_MENU* selectSubMenu = new ACTION_MENU( false, selTool ); selectSubMenu->SetTitle( _( "&Select" ) ); - selectSubMenu->Add( ACTIONS::selectInsideRectangle ); - selectSubMenu->Add( ACTIONS::selectTouchingRectangle ); - selectSubMenu->Add( ACTIONS::selectInsideLasso ); - selectSubMenu->Add( ACTIONS::selectTouchingLasso ); - selectSubMenu->Add( ACTIONS::selectTouchingPath ); - selectSubMenu->AppendSeparator(); selectSubMenu->Add( ACTIONS::selectAll ); selectSubMenu->Add( ACTIONS::unselectAll ); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 884a35e530..5624fbb9ab 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -731,7 +731,6 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new COMMON_CONTROL ); m_toolManager->RegisterTool( new COMMON_TOOLS ); m_toolManager->RegisterTool( new PCB_SELECTION_TOOL ); - m_toolManager->RegisterTool( new PCB_LASSO_SELECTION_TOOL ); m_toolManager->RegisterTool( new ZOOM_TOOL ); m_toolManager->RegisterTool( new PCB_PICKER_TOOL ); m_toolManager->RegisterTool( new ROUTER_TOOL ); @@ -833,12 +832,6 @@ void PCB_EDIT_FRAME::setupUIConditions() mgr->SetConditions( ACTIONS::copy, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::paste, ENABLE( SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) ); mgr->SetConditions( ACTIONS::pasteSpecial, ENABLE( SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) ); - mgr->SetConditions( ACTIONS::selectInsideRectangle, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingRectangle, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectInsideLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectAutoLasso, ENABLE( cond.HasItems() ) ); - mgr->SetConditions( ACTIONS::selectTouchingPath, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::selectAll, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::unselectAll, ENABLE( cond.HasItems() ) ); mgr->SetConditions( ACTIONS::doDelete, ENABLE( cond.HasItems() ) ); diff --git a/pcbnew/toolbars_footprint_editor.cpp b/pcbnew/toolbars_footprint_editor.cpp index 65071d5f84..c170c80977 100644 --- a/pcbnew/toolbars_footprint_editor.cpp +++ b/pcbnew/toolbars_footprint_editor.cpp @@ -83,12 +83,9 @@ std::optional FOOTPRINT_EDIT_TOOLBAR_SETTINGS::DefaultToo break; case TOOLBAR_LOC::RIGHT: - config.AppendAction( ACTIONS::selectionTool ) - .AppendGroup( TOOLBAR_GROUP_CONFIG( _( "Lasso selection tools" ) ) - .AddAction( ACTIONS::selectAutoLasso ) - .AddAction( ACTIONS::selectInsideLasso ) - .AddAction( ACTIONS::selectTouchingLasso ) - .AddAction( ACTIONS::selectTouchingPath ) ); + config.AppendGroup( TOOLBAR_GROUP_CONFIG( _( "Selection modes" ) ) + .AddAction( ACTIONS::selectSetRect ) + .AddAction( ACTIONS::selectSetLasso ) ); config.AppendSeparator() .AppendAction( PCB_ACTIONS::placePad ) diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index 951897c2ae..946bc3fe7d 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -187,12 +187,9 @@ std::optional PCB_EDIT_TOOLBAR_SETTINGS::DefaultToolbarCo break; case TOOLBAR_LOC::RIGHT: - config.AppendAction( ACTIONS::selectionTool ) - .AppendGroup( TOOLBAR_GROUP_CONFIG( _( "Lasso selection tools" ) ) - .AddAction( ACTIONS::selectAutoLasso ) - .AddAction( ACTIONS::selectInsideLasso ) - .AddAction( ACTIONS::selectTouchingLasso ) - .AddAction( ACTIONS::selectTouchingPath ) ) + config.AppendGroup( TOOLBAR_GROUP_CONFIG( _( "Selection modes" ) ) + .AddAction( ACTIONS::selectSetRect ) + .AddAction( ACTIONS::selectSetLasso ) ) .AppendAction( PCB_ACTIONS::localRatsnestTool ); config.AppendSeparator() diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 30012d7dfb..10818685fc 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -422,7 +422,7 @@ TOOL_ACTION PCB_ACTIONS::magneticSnapToggle( TOOL_ACTION_ARGS() TOOL_ACTION PCB_ACTIONS::deleteLastPoint( TOOL_ACTION_ARGS() .Name( "pcbnew.InteractiveDrawing.deleteLastPoint" ) - .Scope( AS_GLOBAL ) + .Scope( AS_CONTEXT ) .DefaultHotkey( WXK_BACK ) .FriendlyName( _( "Delete Last Point" ) ) .Tooltip( _( "Delete the last point added to the current item" ) ) diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp index ff5ee6eef2..20a0266017 100644 --- a/pcbnew/tools/pcb_selection_tool.cpp +++ b/pcbnew/tools/pcb_selection_tool.cpp @@ -132,6 +132,7 @@ PCB_SELECTION_TOOL::PCB_SELECTION_TOOL() : m_isFootprintEditor( false ), m_nonModifiedCursor( KICURSOR::ARROW ), m_enteredGroup( nullptr ), + m_selectionMode( SELECTION_MODE::INSIDE_RECTANGLE ), m_priv( std::make_unique() ) { m_filter.lockedItems = false; @@ -450,13 +451,18 @@ int PCB_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) m_toolMgr->RunAction( PCB_ACTIONS::move ); } } - else if( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT ) + else if( ( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT ) + || ( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY ) ) { - SelectRectArea( aEvent ); - } - else if( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY ) - { - SelectRectArea( aEvent ); + if( m_selectionMode == SELECTION_MODE::INSIDE_RECTANGLE || m_selectionMode == SELECTION_MODE::TOUCHING_RECTANGLE ) + SelectRectArea( aEvent ); + else if( m_selectionMode == SELECTION_MODE::INSIDE_LASSO || m_selectionMode == SELECTION_MODE::TOUCHING_LASSO ) + SelectPolyArea( aEvent ); + else + { + wxASSERT_MSG( false, wxT( "Unknown selection mode" ) ); + SelectRectArea( aEvent ); + } } else { @@ -1063,41 +1069,23 @@ int PCB_SELECTION_TOOL::SelectRectArea( const TOOL_EVENT& aEvent ) bool cancelled = false; // Was the tool canceled while it was running? m_multiple = true; // Multiple selection mode is active KIGFX::VIEW* view = getView(); - bool fixedMode = false; - SELECTION_MODE selectionMode = SELECTION_MODE::INSIDE_RECTANGLE; - - if( aEvent.HasParameter() ) - { - fixedMode = true; - selectionMode = aEvent.Parameter(); - } KIGFX::PREVIEW::SELECTION_AREA area; view->Add( &area ); while( TOOL_EVENT* evt = Wait() ) { - if( !fixedMode ) - { - int width = area.GetEnd().x - area.GetOrigin().x; + /* Selection mode depends on direction of drag-selection: + * Left > Right : Select objects that are fully enclosed by selection + * Right > Left : Select objects that are crossed by selection + */ + bool greedySelection = area.GetEnd().x < area.GetOrigin().x; - /* Selection mode depends on direction of drag-selection: - * Left > Right : Select objects that are fully enclosed by selection - * Right > Left : Select objects that are crossed by selection - */ - bool touchingSelection = width >= 0 ? false : true; + if( view->IsMirroredX() ) + greedySelection = !greedySelection; - if( view->IsMirroredX() ) - touchingSelection = !touchingSelection; - - selectionMode = touchingSelection ? SELECTION_MODE::TOUCHING_RECTANGLE - : SELECTION_MODE::INSIDE_RECTANGLE; - } - - if( selectionMode == SELECTION_MODE::INSIDE_RECTANGLE ) - m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_WINDOW ); - else - m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO ); + m_frame->GetCanvas()->SetCurrentCursor( !greedySelection ? KICURSOR::SELECT_WINDOW + : KICURSOR::SELECT_LASSO ); if( evt->IsCancelInteractive() || evt->IsActivate() ) { @@ -1122,7 +1110,9 @@ int PCB_SELECTION_TOOL::SelectRectArea( const TOOL_EVENT& aEvent ) area.SetAdditive( m_drag_additive ); area.SetSubtractive( m_drag_subtractive ); area.SetExclusiveOr( false ); - area.SetMode( selectionMode ); + area.SetMode( greedySelection + ? SELECTION_MODE::TOUCHING_RECTANGLE + : SELECTION_MODE::INSIDE_RECTANGLE ); view->SetVisible( &area, true ); view->Update( &area ); @@ -1160,6 +1150,122 @@ int PCB_SELECTION_TOOL::SelectRectArea( const TOOL_EVENT& aEvent ) } +int PCB_SELECTION_TOOL::SetSelectPoly( const TOOL_EVENT& aEvent ) +{ + m_selectionMode = SELECTION_MODE::INSIDE_LASSO; + m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO ); + m_toolMgr->PostAction( ACTIONS::selectionTool ); + return 0; // No need to wait for an event, just set the mode +} + + +int PCB_SELECTION_TOOL::SetSelectRect( const TOOL_EVENT& aEvent ) +{ + m_selectionMode = SELECTION_MODE::INSIDE_RECTANGLE; + m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW ); + m_toolMgr->PostAction( ACTIONS::selectionTool ); + return 0; // No need to wait for an event, just set the mode +} + + +int PCB_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent ) +{ + bool cancelled = false; // Was the tool canceled while it was running? + + SELECTION_MODE selectionMode = SELECTION_MODE::TOUCHING_LASSO; + m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SELECT_LASSO ); + + + SHAPE_LINE_CHAIN points; + points.SetClosed( true ); + + KIGFX::PREVIEW::SELECTION_AREA area; + getView()->Add( &area ); + getView()->SetVisible( &area, true ); + getViewControls()->SetAutoPan( true ); + + while( TOOL_EVENT* evt = Wait() ) + { + // Auto mode: clockwise = inside, counterclockwise = touching + double shapeArea = area.GetPoly().Area( false ); + bool isClockwise = shapeArea > 0 ? true : false; + + if( getView()->IsMirroredX() && shapeArea != 0 ) + isClockwise = !isClockwise; + + selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO + : SELECTION_MODE::TOUCHING_LASSO; + + if( evt->IsCancelInteractive() || evt->IsActivate() ) + { + cancelled = true; + evt->SetPassEvent( false ); + break; + } + else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) + || evt->IsAction( &ACTIONS::cursorClick ) ) + { + points.Append( evt->Position() ); + } + else if( evt->IsDblClick( BUT_LEFT ) || evt->IsAction( &ACTIONS::cursorDblClick ) + || evt->IsAction( &ACTIONS::finishInteractive ) ) + { + area.GetPoly().GenerateBBoxCache(); + SelectMultiple( area, m_subtractive, m_exclusive_or ); + evt->SetPassEvent( false ); + break; + } + else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) + || evt->IsAction( &ACTIONS::doDelete ) + || evt->IsAction( &ACTIONS::undo ) ) + { + if( points.GetPointCount() > 0 ) + { + getViewControls()->SetCursorPosition( points.CLastPoint() ); + points.Remove( points.GetPointCount() - 1 ); + } + } + else + { + // Allow navigation actions + passEvent( evt, allowedActions ); + } + + if( points.PointCount() > 0 ) + { + if( !m_drag_additive && !m_drag_subtractive ) + { + if( m_selection.GetSize() > 0 ) + { + ClearSelection( true /*quiet mode*/ ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + } + } + } + + area.SetPoly( points ); + area.GetPoly().Append( m_toolMgr->GetMousePosition() ); + area.SetAdditive( m_additive ); + area.SetSubtractive( m_subtractive ); + area.SetExclusiveOr( false ); + area.SetMode( selectionMode ); + getView()->Update( &area ); + } + + getViewControls()->SetAutoPan( false ); + getView()->SetVisible( &area, false ); + getView()->Remove( &area ); + m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW ); + + if( !cancelled ) + GetSelection().ClearReferencePoint(); + + m_toolMgr->ProcessEvent( EVENTS::UninhibitSelectionEditing ); + + return cancelled; +} + + void PCB_SELECTION_TOOL::SelectMultiple( KIGFX::PREVIEW::SELECTION_AREA& aArea, bool aSubtractive, bool aExclusiveOr ) { @@ -4249,205 +4355,10 @@ void PCB_SELECTION_TOOL::setTransitions() Go( &PCB_SELECTION_TOOL::SelectRows, ACTIONS::selectRows.MakeEvent() ); Go( &PCB_SELECTION_TOOL::SelectTable, ACTIONS::selectTable.MakeEvent() ); - Go( &PCB_SELECTION_TOOL::SelectRectArea, ACTIONS::selectInsideRectangle.MakeEvent() ); - Go( &PCB_SELECTION_TOOL::SelectRectArea, ACTIONS::selectTouchingRectangle.MakeEvent() ); + Go( &PCB_SELECTION_TOOL::SetSelectPoly, ACTIONS::selectSetLasso.MakeEvent() ); + Go( &PCB_SELECTION_TOOL::SetSelectRect, ACTIONS::selectSetRect.MakeEvent() ); Go( &PCB_SELECTION_TOOL::SelectAll, ACTIONS::selectAll.MakeEvent() ); Go( &PCB_SELECTION_TOOL::UnselectAll, ACTIONS::unselectAll.MakeEvent() ); Go( &PCB_SELECTION_TOOL::disambiguateCursor, EVENTS::DisambiguatePoint ); } - - -PCB_LASSO_SELECTION_TOOL::PCB_LASSO_SELECTION_TOOL() : - PCB_TOOL_BASE( "common.InteractiveLassoSelection" ) -{ -} - - -PCB_LASSO_SELECTION_TOOL::~PCB_LASSO_SELECTION_TOOL() -{ -} - - -bool PCB_LASSO_SELECTION_TOOL::Init() -{ - return true; -} - - -void PCB_LASSO_SELECTION_TOOL::Reset( RESET_REASON aReason ) -{ -} - - -int PCB_LASSO_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent ) -{ - bool cancelled = false; // Was the tool canceled while it was running? - bool fixedMode = false; - bool additive = false; - bool subtractive = false; - bool exclusiveOr = false; - PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool(); - SELECTION_MODE selectionMode = SELECTION_MODE::TOUCHING_LASSO; - - auto updateModifiersAndCursor = - [&]( wxTimerEvent& aEvent ) - { - KICURSOR cursor; - wxMouseState keyboardState = wxGetMouseState(); - - subtractive = keyboardState.ControlDown() && keyboardState.ShiftDown(); - additive = !keyboardState.ControlDown() && keyboardState.ShiftDown(); - exclusiveOr = keyboardState.ControlDown() && !keyboardState.ShiftDown(); - - if( additive ) - cursor = KICURSOR::ADD; - else if( subtractive ) - cursor = KICURSOR::SUBTRACT; - else if( exclusiveOr ) - cursor = KICURSOR::XOR ; - else if( selectionMode == SELECTION_MODE::INSIDE_LASSO ) - cursor = KICURSOR::SELECT_WINDOW; - else - cursor = KICURSOR::SELECT_LASSO; - - frame()->GetCanvas()->SetCurrentCursor( cursor ); - }; - - // No events are sent for modifier keys, so we need to poll them using a timer. - wxTimer timer; - timer.Bind( wxEVT_TIMER, updateModifiersAndCursor ); - timer.Start( 100 ); - - if( aEvent.HasParameter() ) - { - fixedMode = true; - selectionMode = aEvent.Parameter(); - } - - SHAPE_LINE_CHAIN points; - - if( selectionMode != SELECTION_MODE::TOUCHING_PATH ) - points.SetClosed( true ); - - KIGFX::PREVIEW::SELECTION_AREA area; - view()->Add( &area ); - view()->SetVisible( &area, true ); - - controls()->SetAutoPan( true ); - - frame()->PushTool( aEvent ); - Activate(); - - while( TOOL_EVENT* evt = Wait() ) - { - if( !fixedMode ) - { - // Auto Mode: The selection mode depends on the drawing direction of the selection shape: - // - Clockwise: Contained selection - // - Counterclockwise: Touching selection - double shapeArea = area.GetPoly().Area( false ); - bool isClockwise = shapeArea > 0 ? true : false; - - // Flip the selection mode if the view is mirrored, but only if the area is non-zero. - // A zero area means the selection shape is a line, so the mode should always be "touching". - if( view()->IsMirroredX() && shapeArea != 0 ) - isClockwise = !isClockwise; - - selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO - : SELECTION_MODE::TOUCHING_LASSO; - } - - if( evt->IsCancelInteractive() || evt->IsActivate() ) - { - // Cancel the selection - cancelled = true; - evt->SetPassEvent( false ); - - break; - } - else if( evt->IsDrag( BUT_LEFT ) // Lasso selection - || evt->IsClick( BUT_LEFT ) // Polygon selection - || evt->IsAction( &ACTIONS::cursorClick ) ) // Return key - { - // Add a point to the selection shape - points.Append( evt->Position() ); - } - else if( evt->IsDblClick( BUT_LEFT ) - || evt->IsAction( &ACTIONS::cursorDblClick ) // End key - || evt->IsAction( &ACTIONS::finishInteractive ) ) - { - // Finish the selection - area.GetPoly().GenerateBBoxCache(); - - selectionTool->SelectMultiple( area, subtractive, exclusiveOr ); - - evt->SetPassEvent( false ); - - break; - } - else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) - || evt->IsAction( &ACTIONS::doDelete ) - || evt->IsAction( &ACTIONS::undo ) ) - { - // Delete the last point in the selection shape - if( points.GetPointCount() > 0 ) - { - controls()->SetCursorPosition( points.CLastPoint() ); - points.Remove( points.GetPointCount() - 1 ); - } - } - else - { - // Allow some actions for navigation - passEvent( evt, allowedActions ); - } - - if( points.PointCount() > 0 ) - { - // Clear existing selection if not in add/sub/xor mode - if( !additive && !subtractive && !exclusiveOr ) - { - if( !selectionTool->GetSelection().Empty() ) - { - selectionTool->ClearSelection( true /*quiet mode*/ ); - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - } - } - } - - // Draw selection shape - area.SetPoly( points ); - area.GetPoly().Append( m_toolMgr->GetMousePosition() ); - - area.SetAdditive( additive ); - area.SetSubtractive( subtractive ); - area.SetExclusiveOr( exclusiveOr ); - area.SetMode( selectionMode ); - - view()->Update( &area ); - } - - frame()->PopTool( aEvent ); - - controls()->SetAutoPan( false ); - view()->SetVisible( &area, false ); - view()->Remove( &area ); // Stop drawing the selection shape - frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW ); // Reset cursor to default - - if( !cancelled ) - selectionTool->GetSelection().ClearReferencePoint(); - - m_toolMgr->ProcessEvent( EVENTS::UninhibitSelectionEditing ); - - return cancelled; -} - - -void PCB_LASSO_SELECTION_TOOL::setTransitions() -{ - Go( &PCB_LASSO_SELECTION_TOOL::SelectPolyArea, ACTIONS::selectInsideLasso.MakeEvent() ); - Go( &PCB_LASSO_SELECTION_TOOL::SelectPolyArea, ACTIONS::selectTouchingLasso.MakeEvent() ); - Go( &PCB_LASSO_SELECTION_TOOL::SelectPolyArea, ACTIONS::selectAutoLasso.MakeEvent() ); - Go( &PCB_LASSO_SELECTION_TOOL::SelectPolyArea, ACTIONS::selectTouchingPath.MakeEvent() ); -} diff --git a/pcbnew/tools/pcb_selection_tool.h b/pcbnew/tools/pcb_selection_tool.h index 81e86e1c3a..42ae4668e4 100644 --- a/pcbnew/tools/pcb_selection_tool.h +++ b/pcbnew/tools/pcb_selection_tool.h @@ -120,6 +120,10 @@ public: ///< Unselect all items on the board int UnselectAll( const TOOL_EVENT& aEvent ); + ///< Change the selection mode + int SetSelectRect( const TOOL_EVENT& aEvent ); + int SetSelectPoly( const TOOL_EVENT& aEvent ); + /** * Handles drawing a selection box that allows multiple items to be selected simultaneously. * @@ -127,6 +131,14 @@ public: */ int SelectRectArea( const TOOL_EVENT& aEvent ); + /** + * Handles drawing a lasso selection area that allows multiple items to be selected + * simultaneously. + * + * @return true if the operation was canceled (i.e. a CancelEvent was received). + */ + int SelectPolyArea( const TOOL_EVENT& aEvent ); + /** * Selects multiple PCB items within a specified area. */ @@ -477,53 +489,11 @@ private: // members of this group KIGFX::VIEW_GROUP m_enteredGroupOverlay; // Overlay for the entered group's frame. + SELECTION_MODE m_selectionMode; // Current selection mode + /// Private state (opaque pointer/compilation firewall) class PRIV; std::unique_ptr m_priv; }; -/** - * The PCB_LASSO_SELECTION_TOOL is a tool that allows the user to select multiple items - * by drawing a polygon, lasso or polyline on the PCB. - * It is used for selecting items in a more flexible way than the standard rectangle selection. - */ -class PCB_LASSO_SELECTION_TOOL : public PCB_TOOL_BASE -{ -public: - PCB_LASSO_SELECTION_TOOL(); - ~PCB_LASSO_SELECTION_TOOL(); - - /// @copydoc TOOL_BASE::Init() - bool Init() override; - - /// @copydoc TOOL_BASE::Reset() - void Reset( RESET_REASON aReason ) override; - - ///< Set up handlers for various events. - void setTransitions() override; - - /** - * Handles drawing a selection polygon (lasso) or polyline (path) that allows multiple items - * to be selectedsimultaneously. - * @return true if the operation was canceled (i.e. a CancelEvent was received). - */ - int SelectPolyArea( const TOOL_EVENT& aEvent ); - -protected: - KIGFX::PCB_VIEW* view() const - { - return static_cast( getView() ); - } - - KIGFX::VIEW_CONTROLS* controls() const - { - return getViewControls(); - } - - PCB_BASE_FRAME* frame() const - { - return getEditFrame(); - } -}; - #endif /* PCB_SELECTION_TOOL_H */ diff --git a/pcbnew/zone.h b/pcbnew/zone.h index f0462824af..7d2342f3b0 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -455,7 +455,7 @@ public: /** * @copydoc EDA_ITEM::HitTest(const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const */ - bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const; + bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override; /** * Removes the zone filling.