diff --git a/gerbview/tools/selection_tool.cpp b/gerbview/tools/selection_tool.cpp index c961a6df13..294f87d032 100644 --- a/gerbview/tools/selection_tool.cpp +++ b/gerbview/tools/selection_tool.cpp @@ -260,31 +260,6 @@ SELECTION& GERBVIEW_SELECTION_TOOL::GetSelection() } -SELECTION& GERBVIEW_SELECTION_TOOL::RequestSelection( int aFlags ) -{ - std::vector removed_items; - if( m_selection.Empty() ) - { - m_toolMgr->RunAction( GERBVIEW_ACTIONS::selectionCursor, true, 0 ); - m_selection.SetIsHover( true ); - } - - - // Be careful with iterators: items can be removed from list that invalidate iterators. - for( auto item : m_selection ) - { - if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T ) - removed_items.push_back( item ); - } - - // Now safely remove the items from the selection - for( auto item : removed_items ) - unselect( static_cast( item ) ); - - return m_selection; -} - - void GERBVIEW_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem ) { if( aItem->IsSelected() ) diff --git a/gerbview/tools/selection_tool.h b/gerbview/tools/selection_tool.h index 4b42e4cab5..bafd6248f5 100644 --- a/gerbview/tools/selection_tool.h +++ b/gerbview/tools/selection_tool.h @@ -72,14 +72,6 @@ public: */ SELECTION& GetSelection(); - /** - * Function RequestSelection() - * - * Returns the current selection set, filtered according to aFlags. - * If the set is empty, performs the legacy-style hover selection. - */ - SELECTION& RequestSelection( int aFlags = SELECTION_DEFAULT ); - inline TOOL_MENU& GetToolMenu() { return m_menu; diff --git a/include/tool/selection.h b/include/tool/selection.h index f1c4200778..e30a034756 100644 --- a/include/tool/selection.h +++ b/include/tool/selection.h @@ -231,21 +231,5 @@ enum SELECTION_LOCK_FLAGS SELECTION_LOCKED = 2 }; -// Selection type flags for RequestSelection() -enum SELECTION_TYPE_FLAGS -{ - // Items that can be deleted (but not necessarily modified, eg. DRC markers) - SELECTION_DELETABLE = 1, - // Items that can be edited (moved, rotated, properties) - SELECTION_EDITABLE = 2, - // Remove pads without a host module - SELECTION_SANITIZE_PADS = 4, - // Request a hover-only selection - SELECTION_HOVER = 8, - // Select locked parts without asking the user - SELECTION_FORCE_UNLOCK = 16, - - SELECTION_DEFAULT = 0x7 -}; #endif diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 54af031137..159e4e6e3e 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -259,6 +259,56 @@ static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS } +void filterItems( GENERAL_COLLECTOR& aCollector, bool sanitizePads, bool ensureEditable ) +{ + // Iterate from the back so we don't have to worry about removals. + for( int i = aCollector.GetCount() - 1; i >= 0; --i ) + { + BOARD_ITEM* item = aCollector[ i ]; + + if( sanitizePads && item->Type() == PCB_PAD_T ) + { + MODULE* mod = static_cast( item->GetParent() ); + + // case 1: module (or its pads) are locked + if( mod && ( mod->PadsLocked() || mod->IsLocked() ) ) + { + aCollector.Remove( item ); + + if( !mod->IsLocked() && !aCollector.HasItem( mod ) ) + aCollector.Append( mod ); + } + + // case 2: selection contains both the module and its pads - remove the pads + if( mod && aCollector.HasItem( mod ) ) + aCollector.Remove( item ); + } + else if( ensureEditable && item->Type() == PCB_MARKER_T ) + { + aCollector.Remove( item ); + } + } +} + + +void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector ) +{ + filterItems( aCollector, true, true ); +} + + +void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector ) +{ + filterItems( aCollector, true, false ); +} + + +void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector ) +{ + filterItems( aCollector, false, true ); +} + + EDIT_TOOL::EDIT_TOOL() : PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), m_dragging( false ) @@ -286,6 +336,13 @@ bool EDIT_TOOL::Init() return false; } + PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); + + m_defaultSelectionFilter = SanitizePadsEnsureEditableFilter; + + if( editFrame->IsType( FRAME_PCB_MODULE_EDITOR ) ) + m_defaultSelectionFilter = EnsureEditableFilter; + auto editingModuleCondition = [ this ] ( const SELECTION& aSelection ) { return m_editModules; }; @@ -388,7 +445,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Be sure that there is at least one item that we can modify. If nothing was selected before, // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) - auto& selection = m_selectionTool->RequestSelection( SELECTION_DEFAULT ); + auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( selection.Empty() ) return 0; @@ -643,10 +700,9 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) { PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - const auto& selection = m_selectionTool->RequestSelection( - SELECTION_EDITABLE | SELECTION_DELETABLE | SELECTION_FORCE_UNLOCK ); + const auto& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); - if( selection.Empty() ) + if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; // Tracks & vias are treated in a special way: @@ -689,7 +745,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) { PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - auto& selection = m_selectionTool->RequestSelection(); + auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( selection.Empty() ) return 0; @@ -760,7 +816,7 @@ static void mirrorPadX( D_PAD& aPad, const wxPoint& aMirrorPoint ) int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) { - auto& selection = m_selectionTool->RequestSelection(); + auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; @@ -834,7 +890,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) { - auto& selection = m_selectionTool->RequestSelection(); + auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; @@ -875,7 +931,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) return 0; // get a copy instead of reference (as we're going to clear the selectio before removing items) - auto selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS ); + auto selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; @@ -909,7 +965,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) { - const auto& selection = m_selectionTool->RequestSelection(); + const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; @@ -966,7 +1022,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement ); // Be sure that there is at least one item that we can modify - const auto& selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS ); + const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( selection.Empty() ) return 0; @@ -1111,7 +1167,7 @@ private: int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent ) { - const auto& selection = m_selectionTool->RequestSelection(); + const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( selection.Empty() ) return 0; @@ -1139,7 +1195,7 @@ void EDIT_TOOL::FootprintFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector int EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent ) { - const auto& selection = m_selectionTool->RequestSelection( 0, FootprintFilter ); + const auto& selection = m_selectionTool->RequestSelection( FootprintFilter ); bool updateMode = aEvent.IsAction( &PCB_ACTIONS::updateFootprints ); @@ -1323,7 +1379,7 @@ bool EDIT_TOOL::updateModificationPoint( SELECTION& aSelection ) int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) { - const auto& selection = m_selectionTool->RequestSelection( 0, FootprintFilter ); + const auto& selection = m_selectionTool->RequestSelection( FootprintFilter ); if( selection.Empty() ) return 0; @@ -1388,7 +1444,7 @@ int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent ) std::vector msgItems = { item1 }; - SELECTION& selection = m_selectionTool->RequestSelection(); + SELECTION& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); if( selection.Empty() ) return 1; diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index a6389acdf3..2b620baae6 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -28,13 +28,26 @@ #include #include +#include class BOARD_COMMIT; class BOARD_ITEM; -class SELECTION_TOOL; class CONNECTIVITY_DATA; +/** + * Function SanitizePadsEnsureEditableFilter + * + * A CLIENT_SELECTION_FILTER which promotes pad selections to their parent modules and + * excludes non-editable items (such as markers). + */ +void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items ); + +void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& items ); + +void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items ); + + /** * Class EDIT_TOOL * @@ -172,6 +185,8 @@ private: ///> Selection tool used for obtaining selected items SELECTION_TOOL* m_selectionTool; + CLIENT_SELECTION_FILTER m_defaultSelectionFilter; + ///> Flag determining if anything is being dragged right now bool m_dragging; @@ -191,21 +206,6 @@ private: bool changeTrackWidthOnClick( const SELECTION& selection ); bool pickCopyReferencePoint( VECTOR2I& aP ); - - /** - * Function hoverSelection() - * - * If there are no items currently selected, it tries to choose the - * item that is under he cursor or displays a disambiguation menu - * if there are multiple items. - * - * @param aSanitize sanitize selection using SanitizeSelection() - * @return true if the eventual selection contains any items, or - * false if it fails to select any items. - */ - bool hoverSelection( bool aSanitize = true ); - - std::unique_ptr m_commit; }; diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp index 6e18bb6630..3b0d5e64cf 100644 --- a/pcbnew/tools/pcbnew_control.cpp +++ b/pcbnew/tools/pcbnew_control.cpp @@ -797,10 +797,8 @@ static bool deleteItem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition ) wxCHECK( selectionTool, false ); aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); - aToolMgr->RunAction( PCB_ACTIONS::selectionCursor, true ); - selectionTool->SanitizeSelection(); - const SELECTION& selection = selectionTool->GetSelection(); + const SELECTION& selection = selectionTool->RequestSelection( SanitizePadsFilter ); if( selection.Empty() ) return true; diff --git a/pcbnew/tools/placement_tool.cpp b/pcbnew/tools/placement_tool.cpp index c4c742e12f..6f9dc20d52 100644 --- a/pcbnew/tools/placement_tool.cpp +++ b/pcbnew/tools/placement_tool.cpp @@ -25,6 +25,7 @@ #include "placement_tool.h" #include "pcb_actions.h" #include "selection_tool.h" +#include "edit_tool.h" #include #include @@ -252,7 +253,7 @@ int ALIGN_DISTRIBUTE_TOOL::checkLockedStatus( const SELECTION &selection ) const int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -292,7 +293,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignBottom( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -347,7 +348,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignLeft( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::doAlignLeft() { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -402,7 +403,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignRight( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::doAlignRight() { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -442,7 +443,7 @@ int ALIGN_DISTRIBUTE_TOOL::doAlignRight() int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -483,7 +484,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE ); + SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -524,8 +525,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::DistributeHorizontally( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( - SELECTION_EDITABLE | SELECTION_SANITIZE_PADS ); + SELECTION& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; @@ -611,8 +611,7 @@ void ALIGN_DISTRIBUTE_TOOL::doDistributeCentersHorizontally( ALIGNMENT_RECTS &it int ALIGN_DISTRIBUTE_TOOL::DistributeVertically( const TOOL_EVENT& aEvent ) { auto frame = getEditFrame(); - SELECTION& selection = m_selectionTool->RequestSelection( - SELECTION_EDITABLE | SELECTION_SANITIZE_PADS ); + SELECTION& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter ); if( selection.Size() <= 1 ) return 0; diff --git a/pcbnew/tools/position_relative_tool.cpp b/pcbnew/tools/position_relative_tool.cpp index 8cf43bd481..ab2c2ac6c3 100644 --- a/pcbnew/tools/position_relative_tool.cpp +++ b/pcbnew/tools/position_relative_tool.cpp @@ -27,6 +27,7 @@ using namespace std::placeholders; #include "position_relative_tool.h" #include "pcb_actions.h" #include "selection_tool.h" +#include "edit_tool.h" #include "picker_tool.h" #include @@ -84,7 +85,7 @@ bool POSITION_RELATIVE_TOOL::Init() int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent ) { - const auto& selection = m_selectionTool->RequestSelection(); + const auto& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter ); if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; @@ -119,10 +120,8 @@ static bool selectPRitem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition ) wxCHECK( positionRelativeTool, false ); aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); - aToolMgr->RunAction( PCB_ACTIONS::selectionCursor, true ); - selectionTool->SanitizeSelection(); - const SELECTION& selection = selectionTool->GetSelection(); + const SELECTION& selection = selectionTool->RequestSelection( SanitizePadsFilter ); if( selection.Empty() ) return true; diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 6d14e4799c..43b8400907 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -380,35 +380,34 @@ SELECTION& SELECTION_TOOL::GetSelection() } -SELECTION& SELECTION_TOOL::RequestSelection( int aFlags, CLIENT_SELECTION_FILTER aClientFilter ) +SELECTION& SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aClientFilter ) { - std::vector removed_items; bool selectionEmpty = m_selection.Empty(); m_selection.SetIsHover( selectionEmpty ); if( selectionEmpty ) { - if( aFlags & SELECTION_FORCE_UNLOCK ) - m_locked = false; - m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter ); m_selection.ClearReferencePoint(); } - - // Be careful with iterators: items can be removed from list that invalidate iterators. - for( auto item : m_selection ) + else if( aClientFilter ) { - if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T ) - removed_items.push_back( item ); + GENERAL_COLLECTOR collector; + + for( auto item : m_selection.Items() ) + collector.Append( item ); + + aClientFilter( VECTOR2I(), collector ); + + clearSelection(); + + for( int i = 0; i < collector.GetCount(); ++i ) + { + m_additive = true; + toggleSelection( collector[ i ] ); + } } - // Now safely remove the items from the selection - for( auto item : removed_items ) - unselect( static_cast( item ) ); - - if( aFlags & SELECTION_SANITIZE_PADS ) - SanitizeSelection(); - return m_selection; } @@ -2228,58 +2227,6 @@ int SELECTION_TOOL::updateSelection( const TOOL_EVENT& aEvent ) } -bool SELECTION_TOOL::SanitizeSelection() -{ - std::set rejected; - std::set added; - - if( !m_editModules ) - { - for( auto i : m_selection ) - { - auto item = static_cast( i ); - if( item->Type() == PCB_PAD_T ) - { - MODULE* mod = static_cast( item->GetParent() ); - - // case 1: module (or its pads) are locked - if( mod && ( mod->PadsLocked() || mod->IsLocked() ) ) - { - rejected.insert( item ); - - if( !mod->IsLocked() && !mod->IsSelected() ) - added.insert( mod ); - } - - // case 2: multi-item selection contains both the module and its pads - remove the pads - if( mod && m_selection.Contains( mod ) ) - rejected.insert( item ); - } - } - } - - if( !rejected.empty() ) - { - for( BOARD_ITEM* item : rejected ) - unselect( item ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( UnselectedEvent ); - } - - if( !added.empty() ) - { - for( BOARD_ITEM* item : added ) - select( item ); - - // Inform other potentially interested tools - m_toolMgr->ProcessEvent( SelectedEvent ); - } - - return true; -} - - const TOOL_EVENT SELECTION_TOOL::SelectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.selected" ); const TOOL_EVENT SELECTION_TOOL::UnselectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.unselected" ); const TOOL_EVENT SELECTION_TOOL::ClearedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.cleared" ); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 35e097415a..e5f3333b78 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -94,8 +94,7 @@ public: * and aClientFilter. * If the set is empty, performs the legacy-style hover selection. */ - SELECTION& RequestSelection( int aFlags = SELECTION_DEFAULT, - CLIENT_SELECTION_FILTER aClientFilter = NULL ); + SELECTION& RequestSelection( CLIENT_SELECTION_FILTER aClientFilter ); inline TOOL_MENU& GetToolMenu() @@ -112,10 +111,6 @@ public: ///> Clear current selection event handler. int ClearSelection( const TOOL_EVENT& aEvent ); - ///> Makes sure a group selection does not contain items that would cause - ///> conflicts when moving/rotating together (e.g. a footprint and one of the same footprint's pads) - bool SanitizeSelection(); - ///> Item selection event handler. int SelectItem( const TOOL_EVENT& aEvent );