From 483dc24e874522fdb6fa992461584de6b28fe7a3 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 9 Jul 2019 20:50:40 +0100 Subject: [PATCH] Homogenize selection tools around our HIG. In particular make addative and exclusive-or selections work the same way. Also give Highlight Net a hotkey now that it can't use ctrl-click anymore. --- common/hotkey_store.cpp | 5 +- common/preview_items/selection_area.cpp | 32 +-- eeschema/tools/ee_actions.cpp | 5 +- eeschema/tools/ee_selection_tool.cpp | 127 ++++---- eeschema/tools/ee_selection_tool.h | 13 +- gerbview/tools/gerbview_actions.cpp | 3 - gerbview/tools/gerbview_selection_tool.cpp | 272 +++--------------- gerbview/tools/gerbview_selection_tool.h | 62 +--- include/preview_items/selection_area.h | 9 +- pagelayout_editor/tools/pl_selection_tool.cpp | 87 +++--- pagelayout_editor/tools/pl_selection_tool.h | 11 +- pcbnew/tools/selection_tool.cpp | 152 ++++------ pcbnew/tools/selection_tool.h | 10 +- 13 files changed, 234 insertions(+), 554 deletions(-) diff --git a/common/hotkey_store.cpp b/common/hotkey_store.cpp index 4de3244735..4d55cfc77d 100644 --- a/common/hotkey_store.cpp +++ b/common/hotkey_store.cpp @@ -40,14 +40,13 @@ public: }; static GESTURE_PSEUDO_ACTION* g_gesturePseudoActions[] = { - new GESTURE_PSEUDO_ACTION( _( "Highlight Net" ), MD_CTRL + PSEUDO_WXK_CLICK ), - new GESTURE_PSEUDO_ACTION( _( "Clear Net Highlighting" ), MD_CTRL + PSEUDO_WXK_CLICK ), new GESTURE_PSEUDO_ACTION( _( "Pan Left/Right" ), MD_CTRL + PSEUDO_WXK_WHEEL ), new GESTURE_PSEUDO_ACTION( _( "Pan Up/Down" ), MD_SHIFT + PSEUDO_WXK_WHEEL ), new GESTURE_PSEUDO_ACTION( _( "Finish Drawing" ), PSEUDO_WXK_DBLCLICK ), new GESTURE_PSEUDO_ACTION( _( "Show Clarify Selection Menu" ), MD_ALT + PSEUDO_WXK_CLICK ), new GESTURE_PSEUDO_ACTION( _( "Add to Selection" ), MD_SHIFT + PSEUDO_WXK_CLICK ), - new GESTURE_PSEUDO_ACTION( _( "Remove from Selection" ), MD_CTRL + PSEUDO_WXK_CLICK ), + new GESTURE_PSEUDO_ACTION( _( "Toggle Selection State" ), MD_CTRL + PSEUDO_WXK_CLICK ), + new GESTURE_PSEUDO_ACTION( _( "Remove from Selection" ), MD_SHIFT + MD_CTRL + PSEUDO_WXK_CLICK ), new GESTURE_PSEUDO_ACTION( _( "Ignore Grid Snaps" ), MD_ALT ), new GESTURE_PSEUDO_ACTION( _( "Ignore Other Snaps" ), MD_SHIFT ), }; diff --git a/common/preview_items/selection_area.cpp b/common/preview_items/selection_area.cpp index 48e348ab20..e647ef25c0 100644 --- a/common/preview_items/selection_area.cpp +++ b/common/preview_items/selection_area.cpp @@ -35,6 +35,7 @@ struct SELECTION_COLORS COLOR4D normal; COLOR4D additive; COLOR4D subtract; + COLOR4D exclusiveOr; COLOR4D outline_l2r; COLOR4D outline_r2l; }; @@ -44,6 +45,7 @@ static const SELECTION_COLORS selectionColorScheme[2] = { COLOR4D( 0.3, 0.3, 0.7, 0.3 ), // Slight blue COLOR4D( 0.3, 0.7, 0.3, 0.3 ), // Slight green COLOR4D( 0.7, 0.3, 0.3, 0.3 ), // Slight red + COLOR4D( 0.7, 0.3, 0.3, 0.3 ), // Slight red COLOR4D( 1.0, 1.0, 0.4, 1.0 ), // yellow COLOR4D( 0.4, 0.4, 1.0, 1.0 ) // blue @@ -52,6 +54,7 @@ static const SELECTION_COLORS selectionColorScheme[2] = { COLOR4D( 0.5, 0.3, 1.0, 0.5 ), // Slight blue COLOR4D( 0.5, 1.0, 0.5, 0.5 ), // Slight green COLOR4D( 1.0, 0.5, 0.5, 0.5 ), // Slight red + COLOR4D( 1.0, 0.5, 0.5, 0.5 ), // Slight red COLOR4D( 0.7, 0.7, 0.0, 1.0 ), // yellow COLOR4D( 0.1, 0.1, 1.0, 1.0 ) // blue @@ -61,27 +64,10 @@ static const SELECTION_COLORS selectionColorScheme[2] = { SELECTION_AREA::SELECTION_AREA() : m_additive( false ), - m_subtractive( false ) -{ - -} - - -void SELECTION_AREA::SetAdditive( bool aAdditive ) -{ - m_additive = aAdditive; - - if( m_additive ) - m_subtractive = false; -} - - -void SELECTION_AREA::SetSubtractive( bool aSubtractive ) + m_subtractive( false ), + m_exclusiveOr( false ) { - m_subtractive = aSubtractive; - if( m_subtractive ) - m_additive = false; } @@ -106,17 +92,13 @@ void SELECTION_AREA::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const // Set the fill of the selection rectangle // based on the selection mode if( m_additive ) - { gal.SetFillColor( scheme.additive ); - } else if( m_subtractive ) - { gal.SetFillColor( scheme.subtract ); - } + else if( m_exclusiveOr ) + gal.SetFillColor( scheme.exclusiveOr ); else - { gal.SetFillColor( scheme.normal ); - } gal.SetIsStroke( true ); gal.SetIsFill( true ); diff --git a/eeschema/tools/ee_actions.cpp b/eeschema/tools/ee_actions.cpp index 0cc3b5a560..6778bbcf4d 100644 --- a/eeschema/tools/ee_actions.cpp +++ b/eeschema/tools/ee_actions.cpp @@ -508,7 +508,10 @@ TOOL_ACTION EE_ACTIONS::simTune( "eeschema.Simulation.tune", _( "Select a value to be tuned" ), "" ); TOOL_ACTION EE_ACTIONS::highlightNet( "eeschema.EditorControl.highlightNet", - AS_GLOBAL ); + AS_GLOBAL, + '`', "", + _( "Highlight Net" ), _( "Highlight net under cursor" ), + net_highlight_schematic_xpm ); TOOL_ACTION EE_ACTIONS::clearHighlight( "eeschema.EditorControl.clearHighlight", AS_GLOBAL ); diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 736ebc9352..646b8342ba 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -124,6 +124,7 @@ EE_SELECTION_TOOL::EE_SELECTION_TOOL() : m_frame( nullptr ), m_additive( false ), m_subtractive( false ), + m_exclusive_or( false ), m_multiple( false ), m_skip_heuristics( false ), m_isLibEdit( false ), @@ -288,13 +289,14 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( m_frame->ToolStackIsEmpty() ) m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); - // Should selected items be added to the current selection or - // become the new selection (discarding previously selected items) - m_additive = evt->Modifier( MD_SHIFT ); + m_additive = m_subtractive = m_exclusive_or = false; - // Should selected items be REMOVED from the current selection? - // This will be ignored if the SHIFT modifier is pressed - m_subtractive = !m_additive && evt->Modifier( MD_CTRL ); + if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) + m_subtractive = true; + else if( evt->Modifier( MD_SHIFT ) ) + m_additive = true; + else if( evt->Modifier( MD_CTRL ) ) + m_exclusive_or = true; // Is the user requesting that the selection list include all possible // items without removing less likely selection candidates @@ -303,18 +305,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // Single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { - if( evt->Modifier( MD_CTRL ) && dynamic_cast( m_frame ) ) - { - m_toolMgr->RunAction( EE_ACTIONS::highlightNet, true ); - } - else - { - // If no modifier keys are pressed, clear the selection - if( !m_additive ) - ClearSelection(); - - SelectPoint( evt->Position()); - } + SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, false, + m_additive, m_subtractive, m_exclusive_or ); } // right click? if there is any object - show the context menu @@ -349,22 +341,17 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them else if( evt->IsDrag( BUT_LEFT ) ) { - bool empty = m_selection.Empty(); - - // selection is empty? try to start dragging the item under the point where drag started - if( empty ) - { - m_selection = RequestSelection( movableItems ); - empty = m_selection.Empty(); - } - - // selection STILL empty? attempt a rectangle multi-selection - if( m_additive || m_subtractive || empty || m_frame->GetDragAlwaysSelects() ) + if( m_additive || m_subtractive || m_exclusive_or || m_frame->GetDragAlwaysSelects() ) { selectMultiple(); } else { + // selection is empty? try to start dragging the item under the point where drag + // started + if( m_selection.Empty() ) + m_selection = RequestSelection( movableItems ); + // Check if dragging has started within any of selected items bounding box if( selectionContains( evt->Position() ) ) { @@ -373,8 +360,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) } else { - // No -> clear the selection list - ClearSelection(); + // No -> drag a selection box + selectMultiple(); } } } @@ -428,7 +415,8 @@ EE_SELECTION& EE_SELECTION_TOOL::GetSelection() EDA_ITEM* EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList, - bool* aSelectionCancelledFlag, bool aCheckLocked ) + bool* aSelectionCancelledFlag, bool aCheckLocked, + bool aAdd, bool aSubtract, bool aExclusiveOr ) { EDA_ITEM* start; EE_COLLECTOR collector; @@ -445,8 +433,6 @@ EDA_ITEM* EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) ); collector.Collect( start, aFilterList, (wxPoint) aWhere, m_unit, m_convert ); - bool anyCollected = collector.GetCount() > 0; - // Post-process collected items for( int i = collector.GetCount() - 1; i >= 0; --i ) { @@ -501,17 +487,27 @@ EDA_ITEM* EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* } } + if( !aAdd && !aSubtract && !aExclusiveOr ) + ClearSelection(); + if( collector.GetCount() == 1 ) { EDA_ITEM* item = collector[ 0 ]; - toggleSelection( item ); - return item; + if( aSubtract || ( aExclusiveOr && item->IsSelected() ) ) + { + unselect( item ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + return nullptr; + } + else + { + select( item ); + m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + return item; + } } - if( !m_additive && anyCollected ) - ClearSelection(); - return nullptr; } @@ -609,7 +605,10 @@ EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const KICAD_T aFilterList[] ) EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i ); if( !item->IsType( aFilterList ) ) - toggleSelection( item ); + { + unselect( item ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + } } } @@ -666,11 +665,15 @@ bool EE_SELECTION_TOOL::selectMultiple() if( evt->IsDrag( BUT_LEFT ) ) { + if( !m_additive && !m_subtractive && !m_exclusive_or ) + ClearSelection(); + // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); area.SetAdditive( m_additive ); area.SetSubtractive( m_subtractive ); + area.SetExclusiveOr( m_exclusive_or ); view->SetVisible( &area, true ); view->Update( &area ); @@ -701,12 +704,14 @@ bool EE_SELECTION_TOOL::selectMultiple() * Right > Left : Select objects that are crossed by selection */ bool windowSelection = width >= 0; + bool anyAdded = false; + bool anySubtracted = false; if( view->IsMirroredX() ) windowSelection = !windowSelection; // Construct an EDA_RECT to determine EDA_ITEM selection - EDA_RECT selectionRect( (wxPoint)area.GetOrigin(), wxSize( width, height ) ); + EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) ); selectionRect.Normalize(); @@ -719,12 +724,16 @@ bool EE_SELECTION_TOOL::selectMultiple() if( item->HitTest( selectionRect, windowSelection ) ) { - if( m_subtractive ) + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { unselect( item ); + anySubtracted = true; + } else { select( item ); item->SetFlags( STARTPOINT | ENDPOINT ); + anyAdded = true; } } } @@ -732,9 +741,12 @@ bool EE_SELECTION_TOOL::selectMultiple() m_selection.SetIsHover( false ); // Inform other potentially interested tools - if( !m_selection.Empty() ) + if( anyAdded ) m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + if( anySubtracted ) + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + break; // Stop waiting for events } } @@ -1116,35 +1128,6 @@ void EE_SELECTION_TOOL::ClearSelection() } -void EE_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem, bool aForce ) -{ - if( aItem->IsSelected() ) - { - unselect( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - } - else - { - if( !m_additive ) - ClearSelection(); - - // Prevent selection of invisible or inactive items - if( aForce || selectable( aItem ) ) - { - select( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - } - } - - if( m_frame ) - m_frame->GetCanvas()->ForceRefresh(); -} - - void EE_SELECTION_TOOL::select( EDA_ITEM* aItem ) { highlight( aItem, SELECTED, &m_selection ); diff --git a/eeschema/tools/ee_selection_tool.h b/eeschema/tools/ee_selection_tool.h index 6faed4987d..b40fff0de8 100644 --- a/eeschema/tools/ee_selection_tool.h +++ b/eeschema/tools/ee_selection_tool.h @@ -101,7 +101,8 @@ public: */ EDA_ITEM* SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList = EE_COLLECTOR::AllItems, - bool* aSelectionCancelledFlag = NULL, bool aCheckLocked = false ); + bool* aSelectionCancelledFlag = NULL, bool aCheckLocked = false, + bool aAdd = false, bool aSubtract = false, bool aExclusiveOr = false ); int AddItemToSel( const TOOL_EVENT& aEvent ); void AddItemToSel( EDA_ITEM* aItem, bool aQuietMode = false ); @@ -169,15 +170,6 @@ private: */ bool doSelectionMenu( EE_COLLECTOR* aItems ); - /** - * Function toggleSelection() - * Changes selection status of a given item. - * - * @param aItem is the item to have selection status changed. - * @param aForce causes the toggle to happen without checking selectability - */ - void toggleSelection( EDA_ITEM* aItem, bool aForce = false ); - /** * Function selectable() * Checks conditions for an item to be selected. @@ -242,6 +234,7 @@ private: bool m_additive; // Items should be added to selection (instead of replacing) bool m_subtractive; // Items should be removed from selection + bool m_exclusive_or; // Items' selection state should be toggled bool m_multiple; // Multiple selection mode is active bool m_skip_heuristics; // Heuristics are not allowed when choosing item under cursor diff --git a/gerbview/tools/gerbview_actions.cpp b/gerbview/tools/gerbview_actions.cpp index 3865298b15..61bd001e6d 100644 --- a/gerbview/tools/gerbview_actions.cpp +++ b/gerbview/tools/gerbview_actions.cpp @@ -131,9 +131,6 @@ TOOL_ACTION GERBVIEW_ACTIONS::selectionActivate( "gerbview.InteractiveSelection" AS_GLOBAL, 0, "", "", "", NULL, AF_ACTIVATE ); // No description, it is not supposed to be shown anywhere -TOOL_ACTION GERBVIEW_ACTIONS::selectionCursor( "gerbview.InteractiveSelection.Cursor", - AS_GLOBAL ); - TOOL_ACTION GERBVIEW_ACTIONS::selectItem( "gerbview.InteractiveSelection.SelectItem", AS_GLOBAL ); diff --git a/gerbview/tools/gerbview_selection_tool.cpp b/gerbview/tools/gerbview_selection_tool.cpp index 1f6fe14d10..6d40c0abc2 100644 --- a/gerbview/tools/gerbview_selection_tool.cpp +++ b/gerbview/tools/gerbview_selection_tool.cpp @@ -33,7 +33,6 @@ using namespace std::placeholders; #include #include #include -#include #include #include #include @@ -108,10 +107,12 @@ private: GERBVIEW_SELECTION_TOOL::GERBVIEW_SELECTION_TOOL() : TOOL_INTERACTIVE( "gerbview.InteractiveSelection" ), - m_frame( NULL ), m_additive( false ), m_subtractive( false ), + m_frame( NULL ), + m_additive( false ), + m_subtractive( false ), + m_exclusive_or( false ), m_multiple( false ) { - // these members are initialized to avoid warnings about non initialized vars m_preliminary = true; } @@ -131,7 +132,6 @@ int GERBVIEW_SELECTION_TOOL::UpdateMenu( const TOOL_EVENT& aEvent ) } - GERBVIEW_SELECTION_TOOL::~GERBVIEW_SELECTION_TOOL() { getView()->Remove( &m_selection ); @@ -186,6 +186,15 @@ int GERBVIEW_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( m_frame->ToolStackIsEmpty() ) m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); + m_additive = m_subtractive = m_exclusive_or = false; + + if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) + m_subtractive = true; + else if( evt->Modifier( MD_SHIFT ) ) + m_additive = true; + else if( evt->Modifier( MD_CTRL ) ) + m_exclusive_or = true; + // This is kind of hacky: activate RMB drag on any event. // There doesn't seem to be any other good way to tell when another tool // is canceled and control returns to the selection tool, except by the @@ -204,9 +213,6 @@ int GERBVIEW_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { - if( !m_additive ) - clearSelection(); - selectPoint( evt->Position() ); } @@ -244,34 +250,6 @@ GERBVIEW_SELECTION& GERBVIEW_SELECTION_TOOL::GetSelection() } -void GERBVIEW_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem ) -{ - if( aItem->IsSelected() ) - { - unselect( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - } - else - { - if( !m_additive ) - clearSelection(); - - // Prevent selection of invisible or inactive items - if( selectable( aItem ) ) - { - select( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - } - } - - m_frame->GetCanvas()->ForceRefresh(); -} - - bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag ) { EDA_ITEM* item = NULL; @@ -280,8 +258,6 @@ bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag collector.Collect( model, GERBER_COLLECTOR::AllItems, wxPoint( aWhere.x, aWhere.y ) ); - bool anyCollected = collector.GetCount() != 0; - // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0; --i ) { @@ -289,42 +265,39 @@ bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag collector.Remove( i ); } - switch( collector.GetCount() ) + if( collector.GetCount() > 1 ) { - case 0: - if( !m_additive && anyCollected ) - clearSelection(); + if( aOnDrag ) + Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); - return false; + item = disambiguationMenu( &collector ); - case 1: - toggleSelection( collector[0] ); - - return true; - - default: - // Let's see if there is still disambiguation in selection.. - if( collector.GetCount() == 1 ) + if( item ) { - toggleSelection( collector[0] ); - - return true; + collector.Empty(); + collector.Append( item ); } - else if( collector.GetCount() > 1 ) - { - if( aOnDrag ) - Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); + } - item = disambiguationMenu( &collector ); + if( !m_additive && !m_subtractive && !m_exclusive_or ) + clearSelection(); - if( item ) - { - toggleSelection( item ); + if( collector.GetCount() == 1 ) + { + item = collector[ 0 ]; - return true; - } + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { + unselect( item ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + return false; + } + else + { + select( item ); + m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + return true; } - break; } return false; @@ -343,120 +316,14 @@ bool GERBVIEW_SELECTION_TOOL::selectCursor( bool aSelectAlways ) } -bool GERBVIEW_SELECTION_TOOL::selectMultiple() -{ - bool cancelled = false; // Was the tool cancelled while it was running? - m_multiple = true; // Multiple selection mode is active - KIGFX::VIEW* view = getView(); - getViewControls()->SetAutoPan( true ); - - KIGFX::PREVIEW::SELECTION_AREA area; - view->Add( &area ); - - while( TOOL_EVENT* evt = Wait() ) - { - if( evt->IsCancelInteractive() ) - { - cancelled = true; - break; - } - - if( evt->IsDrag( BUT_LEFT ) ) - { - - // Start drawing a selection box - area.SetOrigin( evt->DragOrigin() ); - area.SetEnd( evt->Position() ); - area.SetAdditive( m_additive ); - area.SetSubtractive( m_subtractive ); - - view->SetVisible( &area, true ); - view->Update( &area ); - } - - if( evt->IsMouseUp( BUT_LEFT ) ) - { - // End drawing the selection box - view->SetVisible( &area, false ); - - // Mark items within the selection box as selected - std::vector selectedItems; - - // Filter the view items based on the selection box - BOX2I selectionBox = area.ViewBBox(); - view->Query( selectionBox, selectedItems ); // Get the list of selected items - - std::vector::iterator it, it_end; - - int width = area.GetEnd().x - area.GetOrigin().x; - int height = area.GetEnd().y - area.GetOrigin().y; - - // Construct an EDA_RECT to determine EDA_ITEM selection - EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ), - wxSize( width, height ) ); - - selectionRect.Normalize(); - - for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) - { - auto item = static_cast( it->first ); - - if( !item || !selectable( item ) ) - continue; - - /* 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 - */ - if( item->HitTest( selectionRect, width >= 0 ) ) - { - if( m_subtractive ) - unselect( item ); - else - select( item ); - } - } - - // Inform other potentially interested tools - if( !m_selection.Empty() ) - m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - - break; // Stop waiting for events - } - } - - // Stop drawing the selection box - view->Remove( &area ); - m_multiple = false; // Multiple selection mode is inactive - getViewControls()->SetAutoPan( false ); - - return cancelled; -} - - void GERBVIEW_SELECTION_TOOL::setTransitions() { - Go( &GERBVIEW_SELECTION_TOOL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::Main, GERBVIEW_ACTIONS::selectionActivate.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::CursorSelection, GERBVIEW_ACTIONS::selectionCursor.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::ClearSelection, GERBVIEW_ACTIONS::selectionClear.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::SelectItem, GERBVIEW_ACTIONS::selectItem.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::UnselectItem, GERBVIEW_ACTIONS::unselectItem.MakeEvent() ); - Go( &GERBVIEW_SELECTION_TOOL::MeasureTool, ACTIONS::measureTool.MakeEvent() ); -} - - -int GERBVIEW_SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent ) -{ - if( m_selection.Empty() ) // Try to find an item that could be modified - { - selectCursor( true ); - - clearSelection(); - return 0; - } - - return 0; + Go( &GERBVIEW_SELECTION_TOOL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() ); + Go( &GERBVIEW_SELECTION_TOOL::Main, GERBVIEW_ACTIONS::selectionActivate.MakeEvent() ); + Go( &GERBVIEW_SELECTION_TOOL::ClearSelection, GERBVIEW_ACTIONS::selectionClear.MakeEvent() ); + Go( &GERBVIEW_SELECTION_TOOL::SelectItem, GERBVIEW_ACTIONS::selectItem.MakeEvent() ); + Go( &GERBVIEW_SELECTION_TOOL::UnselectItem, GERBVIEW_ACTIONS::unselectItem.MakeEvent() ); + Go( &GERBVIEW_SELECTION_TOOL::MeasureTool, ACTIONS::measureTool.MakeEvent() ); } @@ -474,12 +341,9 @@ int GERBVIEW_SELECTION_TOOL::SelectItems( const TOOL_EVENT& aEvent ) if( items ) { - // Perform individual selection of each item - // before processing the event. + // Perform individual selection of each item before processing the event. for( auto item : *items ) - { select( item ); - } m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); } @@ -511,12 +375,9 @@ int GERBVIEW_SELECTION_TOOL::UnselectItems( const TOOL_EVENT& aEvent ) if( items ) { - // Perform individual unselection of each item - // before processing the event + // Perform individual unselection of each item before processing the event for( auto item : *items ) - { unselect( item ); - } m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); } @@ -557,28 +418,6 @@ void GERBVIEW_SELECTION_TOOL::clearSelection() } -void GERBVIEW_SELECTION_TOOL::zoomFitSelection( void ) -{ - //Should recalculate the view to zoom in on the selection - auto selectionBox = m_selection.ViewBBox(); - auto view = getView(); - - VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false ); - - if( !( selectionBox.GetWidth() == 0 ) || !( selectionBox.GetHeight() == 0 ) ) - { - VECTOR2D vsize = selectionBox.GetSize(); - double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ), - fabs( vsize.y / screenSize.y ) ); - view->SetScale( scale ); - view->SetCenter( selectionBox.Centre() ); - view->Add( &m_selection ); - } - - m_frame->GetCanvas()->ForceRefresh(); -} - - EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollector ) { EDA_ITEM* current = NULL; @@ -684,9 +523,7 @@ bool GERBVIEW_SELECTION_TOOL::selectable( const EDA_ITEM* aItem ) const void GERBVIEW_SELECTION_TOOL::select( EDA_ITEM* aItem ) { if( aItem->IsSelected() ) - { return; - } m_selection.Add( aItem ); getView()->Add( &m_selection ); @@ -732,25 +569,6 @@ void GERBVIEW_SELECTION_TOOL::unselectVisually( EDA_ITEM* aItem ) } -bool GERBVIEW_SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const -{ - const unsigned GRIP_MARGIN = 20; - VECTOR2D margin = getView()->ToWorld( VECTOR2D( GRIP_MARGIN, GRIP_MARGIN ), false ); - - // Check if the point is located within any of the currently selected items bounding boxes - for( auto item : m_selection ) - { - BOX2I itemBox = item->ViewBBox(); - itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item - - if( itemBox.Contains( aPoint ) ) - return true; - } - - return false; -} - - int GERBVIEW_SELECTION_TOOL::MeasureTool( const TOOL_EVENT& aEvent ) { auto& view = *getView(); diff --git a/gerbview/tools/gerbview_selection_tool.h b/gerbview/tools/gerbview_selection_tool.h index 1b24713221..312f22d9ab 100644 --- a/gerbview/tools/gerbview_selection_tool.h +++ b/gerbview/tools/gerbview_selection_tool.h @@ -73,9 +73,6 @@ public: */ GERBVIEW_SELECTION& GetSelection(); - ///> Select a single item under cursor event handler. - int CursorSelection( const TOOL_EVENT& aEvent ); - ///> Clear current selection event handler. int ClearSelection( const TOOL_EVENT& aEvent ); @@ -97,9 +94,6 @@ public: ///> Sets up handlers for various events. void setTransitions() override; - ///> Zooms the screen to center and fit the current selection. - void zoomFitSelection( void ); - private: /** * Function selectPoint() @@ -123,15 +117,6 @@ private: */ bool selectCursor( bool aSelectAlways = false ); - /** - * Function selectMultiple() - * Handles drawing a selection box that allows one to select many items at - * the same time. - * - * @return true if the function was cancelled (i.e. CancelEvent was received). - */ - bool selectMultiple(); - /** * Function clearSelection() * Clears the current selection. @@ -147,14 +132,6 @@ private: */ EDA_ITEM* disambiguationMenu( GERBER_COLLECTOR* aItems ); - /** - * Function toggleSelection() - * Changes selection status of a given item. - * - * @param aItem is the item to have selection status changed. - */ - void toggleSelection( EDA_ITEM* aItem ); - /** * Function selectable() * Checks conditions for an item to be selected. @@ -193,39 +170,14 @@ private: */ void unselectVisually( EDA_ITEM* aItem ); - /** - * Function selectionContains() - * Checks if the given point is placed within any of selected items' bounding box. - * - * @return True if the given point is contained in any of selected items' bouding box. - */ - bool selectionContains( const VECTOR2I& aPoint ) const; - - /** - * Function guessSelectionCandidates() - * Tries to guess best selection candidates in case multiple items are clicked, by - * doing some braindead heuristics. - * @param aCollector is the collector that has a list of items to be queried. - */ - void guessSelectionCandidates( GERBER_COLLECTOR& aCollector ) const; - - /// Pointer to the parent frame. - GERBVIEW_FRAME* m_frame; - - /// Current state of selection. - GERBVIEW_SELECTION m_selection; - - /// Flag saying if items should be added to the current selection or rather replace it. - bool m_additive; - - /// Flag saying if items should be removed from the current selection - bool m_subtractive; - - /// Flag saying if multiple selection mode is active. - bool m_multiple; + GERBVIEW_FRAME* m_frame; // Pointer to the parent frame. + GERBVIEW_SELECTION m_selection; // Current state of selection. - /// Determines if the selection is preliminary or final. - bool m_preliminary; + bool m_additive; // Items should be added to selection (instead of replacing) + bool m_subtractive; // Items should be removed from selection + bool m_exclusive_or; // Items' selection state should be toggled + bool m_multiple; // Multiple selection mode is active + bool m_preliminary; // Determines if the selection is preliminary or final. }; #endif diff --git a/include/preview_items/selection_area.h b/include/preview_items/selection_area.h index d2dd1aef25..ea0239e45d 100644 --- a/include/preview_items/selection_area.h +++ b/include/preview_items/selection_area.h @@ -80,11 +80,9 @@ public: VECTOR2I GetEnd() const { return m_end; } - bool IsAdditive() const { return m_additive; } - bool IsSubtractive() const { return m_subtractive; } - - void SetAdditive( bool aAdditive ); - void SetSubtractive( bool aSubtractive ); + void SetAdditive( bool aAdditive ) { m_additive = aAdditive; } + void SetSubtractive( bool aSubtractive ) { m_subtractive = aSubtractive; } + void SetExclusiveOr( bool aExclusiveOr ) { m_exclusiveOr = aExclusiveOr; } void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final; @@ -92,6 +90,7 @@ private: bool m_additive; bool m_subtractive; + bool m_exclusiveOr; VECTOR2I m_origin, m_end; }; diff --git a/pagelayout_editor/tools/pl_selection_tool.cpp b/pagelayout_editor/tools/pl_selection_tool.cpp index fa5c025dd8..750e851034 100644 --- a/pagelayout_editor/tools/pl_selection_tool.cpp +++ b/pagelayout_editor/tools/pl_selection_tool.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include "pl_selection_tool.h" @@ -58,6 +57,7 @@ PL_SELECTION_TOOL::PL_SELECTION_TOOL() : m_frame( nullptr ), m_additive( false ), m_subtractive( false ), + m_exclusive_or( false ), m_multiple( false ), m_skip_heuristics( false ) { @@ -114,13 +114,14 @@ int PL_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( m_frame->ToolStackIsEmpty() ) m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); - // Should selected items be added to the current selection or - // become the new selection (discarding previously selected items) - m_additive = evt->Modifier( MD_SHIFT ); + m_additive = m_subtractive = m_exclusive_or = false; - // Should selected items be REMOVED from the current selection? - // This will be ignored if the SHIFT modifier is pressed - m_subtractive = !m_additive && evt->Modifier( MD_CTRL ); + if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) + m_subtractive = true; + else if( evt->Modifier( MD_SHIFT ) ) + m_additive = true; + else if( evt->Modifier( MD_CTRL ) ) + m_exclusive_or = true; // Is the user requesting that the selection list include all possible // items without removing less likely selection candidates @@ -129,10 +130,6 @@ int PL_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // Single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { - // If no modifier keys are pressed, clear the selection - if( !m_additive ) - ClearSelection(); - SelectPoint( evt->Position()); } @@ -160,7 +157,7 @@ int PL_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them else if( evt->IsDrag( BUT_LEFT ) ) { - if( m_additive || m_subtractive || m_selection.Empty() ) + if( m_additive || m_subtractive || m_exclusive_or || m_selection.Empty() ) { selectMultiple(); } @@ -223,8 +220,6 @@ EDA_ITEM* PL_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, bool* aSelecti } } - bool anyCollected = collector.GetCount() != 0; - m_selection.ClearReferencePoint(); // Apply some ugly heuristics to avoid disambiguation menus whenever possible @@ -250,17 +245,27 @@ EDA_ITEM* PL_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, bool* aSelecti } } + if( !m_additive && !m_subtractive && !m_exclusive_or ) + ClearSelection(); + if( collector.GetCount() == 1 ) { EDA_ITEM* item = collector[ 0 ]; - toggleSelection( item ); - return item; + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { + unselect( item ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + return nullptr; + } + else + { + select( item ); + m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + return item; + } } - if( !m_additive && anyCollected ) - ClearSelection(); - return nullptr; } @@ -316,11 +321,15 @@ bool PL_SELECTION_TOOL::selectMultiple() if( evt->IsDrag( BUT_LEFT ) ) { + if( !m_additive && !m_subtractive && !m_exclusive_or ) + ClearSelection(); + // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); area.SetAdditive( m_additive ); area.SetSubtractive( m_subtractive ); + area.SetExclusiveOr( m_exclusive_or ); view->SetVisible( &area, true ); view->Update( &area ); @@ -342,6 +351,8 @@ bool PL_SELECTION_TOOL::selectMultiple() * Right > Left : Select objects that are crossed by selection */ bool windowSelection = width >= 0 ? true : false; + bool anyAdded = false; + bool anySubtracted = false; // Construct an EDA_RECT to determine EDA_ITEM selection EDA_RECT selectionRect( (wxPoint)area.GetOrigin(), wxSize( width, height ) ); @@ -354,18 +365,27 @@ bool PL_SELECTION_TOOL::selectMultiple() { if( item->HitTest( selectionRect, windowSelection ) ) { - if( m_subtractive ) + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { unselect( item ); + anySubtracted = true; + } else + { select( item ); + anyAdded = true; + } } } } // Inform other potentially interested tools - if( !m_selection.Empty() ) + if( anyAdded ) m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + if( anySubtracted ) + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + break; // Stop waiting for events } } @@ -609,31 +629,6 @@ void PL_SELECTION_TOOL::ClearSelection() } -void PL_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem ) -{ - if( aItem->IsSelected() ) - { - unselect( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - } - else - { - if( !m_additive ) - ClearSelection(); - - select( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - } - - if( m_frame ) - m_frame->GetCanvas()->ForceRefresh(); -} - - void PL_SELECTION_TOOL::select( EDA_ITEM* aItem ) { highlight( aItem, SELECTED, &m_selection ); diff --git a/pagelayout_editor/tools/pl_selection_tool.h b/pagelayout_editor/tools/pl_selection_tool.h index 16a9e5737b..01ef93582b 100644 --- a/pagelayout_editor/tools/pl_selection_tool.h +++ b/pagelayout_editor/tools/pl_selection_tool.h @@ -49,7 +49,7 @@ class PL_SELECTION_TOOL : public TOOL_INTERACTIVE { public: PL_SELECTION_TOOL(); - ~PL_SELECTION_TOOL() { } + ~PL_SELECTION_TOOL() override { } /// @copydoc TOOL_BASE::Init() bool Init() override; @@ -149,14 +149,6 @@ private: */ bool doSelectionMenu( COLLECTOR* aItems ); - /** - * Function toggleSelection() - * Changes selection status of a given item. - * - * @param aItem is the item to have selection status changed. - */ - void toggleSelection( EDA_ITEM* aItem ); - /** * Function select() * Takes necessary action mark an item as selected. @@ -208,6 +200,7 @@ private: bool m_additive; // Items should be added to selection (instead of replacing) bool m_subtractive; // Items should be removed from selection + bool m_exclusive_or; // Items' selection state should be toggled bool m_multiple; // Multiple selection mode is active bool m_skip_heuristics; // Heuristics are not allowed when choosing item under cursor }; diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 2a3ae12b24..314031189b 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -23,27 +23,22 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include #include using namespace std::placeholders; - #include #include #include #include -#include #include #include - -#include #include #include #include #include #include #include -#include #include #include #include @@ -119,6 +114,7 @@ SELECTION_TOOL::SELECTION_TOOL() : m_frame( NULL ), m_additive( false ), m_subtractive( false ), + m_exclusive_or( false ), m_multiple( false ), m_skip_heuristics( false ), m_locked( true ), @@ -193,13 +189,15 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( m_frame->ToolStackIsEmpty() ) m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); - // Should selected items be added to the current selection or - // become the new selection (discarding previously selected items) - m_additive = evt->Modifier( MD_SHIFT ); + bool dragAlwaysSelects = getEditFrame()->Settings().m_DragSelects; + m_additive = m_subtractive = m_exclusive_or = false; - // Should selected items be REMOVED from the current selection? - // This will be ignored if the SHIFT modifier is pressed - m_subtractive = !m_additive && evt->Modifier( MD_CTRL ); + if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) + m_subtractive = true; + else if( evt->Modifier( MD_SHIFT ) ) + m_additive = true; + else if( evt->Modifier( MD_CTRL ) ) + m_exclusive_or = true; // Is the user requesting that the selection list include all possible // items without removing less likely selection candidates @@ -208,18 +206,7 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // Single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { - if( evt->Modifier( MD_CTRL ) && !m_editModules ) - { - m_toolMgr->RunAction( PCB_ACTIONS::highlightNet, true ); - } - else - { - // If no modifier keys are pressed, clear the selection - if( !m_additive ) - clearSelection(); - - selectPoint( evt->Position() ); - } + selectPoint( evt->Position() ); } // right click? if there is any object - show the context menu @@ -249,28 +236,17 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them else if( evt->IsDrag( BUT_LEFT ) ) { - if( m_additive || m_subtractive ) + if( m_additive || m_subtractive || m_exclusive_or || dragAlwaysSelects ) { selectMultiple(); } - else if( m_selection.Empty() ) + else { - // There is nothing selected, so try to select something - if( getEditFrame()->Settings().m_DragSelects || !selectCursor() ) - { - // If nothings has been selected, user wants to select more or selection - // box is preferred to dragging - draw selection box - selectMultiple(); - } - else - { + // selection is empty? try to start dragging the item under the point where drag + // started + if( m_selection.Empty() && selectCursor() ) m_selection.SetIsHover( true ); - m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); - } - } - else - { // Check if dragging has started within any of selected items bounding box if( selectionContains( evt->Position() ) ) { @@ -279,8 +255,8 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) } else { - // No -> clear the selection list - clearSelection(); + // No -> drag a selection box + selectMultiple(); } } } @@ -316,7 +292,8 @@ PCBNEW_SELECTION& SELECTION_TOOL::GetSelection() PCBNEW_SELECTION& SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aClientFilter, - std::vector* aFiltered, bool aConfirmLockedItems ) + std::vector* aFiltered, + bool aConfirmLockedItems ) { bool selectionEmpty = m_selection.Empty(); m_selection.SetIsHover( selectionEmpty ); @@ -346,15 +323,17 @@ PCBNEW_SELECTION& SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aCli * This can happen if the locked pads select the module instead */ std::vector new_items; - std::set_difference( collector.begin(), collector.end(), m_selection.begin(), m_selection.end(), - std::back_inserter( new_items ) ); + std::set_difference( collector.begin(), collector.end(), + m_selection.begin(), m_selection.end(), + std::back_inserter( new_items ) ); /** * The second step is to find the items that were removed by the client filter */ std::vector diff; - std::set_difference( m_selection.begin(), m_selection.end(), collector.begin(), collector.end(), - std::back_inserter( diff ) ); + std::set_difference( m_selection.begin(), m_selection.end(), + collector.begin(), collector.end(), + std::back_inserter( diff ) ); if( aFiltered ) { @@ -379,34 +358,6 @@ PCBNEW_SELECTION& SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aCli } -void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem, bool aForce ) -{ - if( aItem->IsSelected() ) - { - unselect( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - } - else - { - if( !m_additive ) - clearSelection(); - - // Prevent selection of invisible or inactive items - if( aForce || selectable( aItem ) ) - { - select( aItem ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - } - } - - if( m_frame ) - m_frame->GetCanvas()->ForceRefresh(); -} - const GENERAL_COLLECTORS_GUIDE SELECTION_TOOL::getCollectorsGuide() const { GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(), @@ -446,8 +397,6 @@ bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, m_editModules ? GENERAL_COLLECTOR::ModuleItems : GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); - bool anyCollected = collector.GetCount() != 0; - // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0; --i ) { @@ -472,9 +421,7 @@ bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, if( collector.GetCount() > 1 ) { if( aOnDrag ) - { Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); - } if( !doSelectionMenu( &collector, _( "Clarify Selection" ) ) ) { @@ -485,17 +432,27 @@ bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, } } + if( !m_additive && !m_subtractive && !m_exclusive_or ) + clearSelection(); + if( collector.GetCount() == 1 ) { BOARD_ITEM* item = collector[ 0 ]; - toggleSelection( item ); - return true; + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { + unselect( item ); + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + return false; + } + else + { + select( item ); + m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + return true; + } } - if( !m_additive && anyCollected ) - clearSelection(); - return false; } @@ -531,11 +488,15 @@ bool SELECTION_TOOL::selectMultiple() if( evt->IsDrag( BUT_LEFT ) ) { + if( !m_additive && !m_subtractive && !m_exclusive_or ) + clearSelection(); + // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); area.SetAdditive( m_additive ); area.SetSubtractive( m_subtractive ); + area.SetExclusiveOr( m_exclusive_or ); view->SetVisible( &area, true ); view->Update( &area ); @@ -566,13 +527,14 @@ bool SELECTION_TOOL::selectMultiple() * Right > Left : Select objects that are crossed by selection */ bool windowSelection = width >= 0 ? true : false; + bool anyAdded = false; + bool anySubtracted = false; if( view->IsMirroredX() ) windowSelection = !windowSelection; // Construct an EDA_RECT to determine BOARD_ITEM selection - EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ), - wxSize( width, height ) ); + EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) ); selectionRect.Normalize(); @@ -585,17 +547,28 @@ bool SELECTION_TOOL::selectMultiple() if( item->HitTest( selectionRect, windowSelection ) ) { - if( m_subtractive ) + if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) + { unselect( item ); + anySubtracted = true; + } else + { select( item ); + anyAdded = true; + } } } + m_selection.SetIsHover( false ); + // Inform other potentially interested tools - if( !m_selection.Empty() ) + if( anyAdded ) m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); + if( anySubtracted ) + m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); + break; // Stop waiting for events } } @@ -1142,7 +1115,8 @@ int SELECTION_TOOL::findMove( const TOOL_EVENT& aEvent ) { KIGFX::VIEW_CONTROLS* viewCtrls = getViewControls(); clearSelection(); - toggleSelection( module, true ); + select( module ); + m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); auto cursorPosition = viewCtrls->GetCursorPosition( false ); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index fe987d9b97..a5a000e499 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -261,15 +261,6 @@ private: */ BOARD_ITEM* pickSmallestComponent( GENERAL_COLLECTOR* aCollector ); - /** - * Function toggleSelection() - * Changes selection status of a given item. - * - * @param aItem is the item to have selection status changed. - * @param aForce causes the toggle to happen without checking selectability - */ - void toggleSelection( BOARD_ITEM* aItem, bool aForce = false ); - /** * Function selectable() * Checks conditions for an item to be selected. @@ -347,6 +338,7 @@ private: bool m_additive; // Items should be added to selection (instead of replacing) bool m_subtractive; // Items should be removed from selection + bool m_exclusive_or; // Items' selection state should be toggled bool m_multiple; // Multiple selection mode is active bool m_skip_heuristics; // Heuristics are not allowed when choosing item under cursor bool m_locked; // Other tools are not allowed to modify locked items