Don't allow selection crossing a parent/child relationship.

Fixes https://gitlab.com/kicad/code/kicad/issues/8292

Fixes https://gitlab.com/kicad/code/kicad/issues/7255
This commit is contained in:
Jeff Young 2021-04-26 18:41:35 +01:00
parent e06a3cf3b4
commit 5bf37a9b24
4 changed files with 43 additions and 16 deletions

View File

@ -296,7 +296,7 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
}
}
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
},
!m_isFootprintEditor /* prompt user regarding locked items */ );
@ -1439,7 +1439,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
},
!m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ );
@ -1574,7 +1574,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
},
!m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ );
@ -1698,7 +1698,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
},
!m_dragging && !m_isFootprintEditor/* prompt user regarding locked items */ );
@ -1991,7 +1991,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
},
!m_isFootprintEditor /* prompt user regarding locked items */ );
@ -2113,7 +2113,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
} );
if( selection.Empty() )
@ -2280,7 +2280,7 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
} );
if( selection.Empty() )

View File

@ -202,7 +202,7 @@ int GLOBAL_EDIT_TOOL::RemoveUnusedPads( const TOOL_EVENT& aEvent )
PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
sTool->FilterCollectorForGroups( aCollector );
sTool->FilterCollectorForHierarchy( aCollector );
} );
DIALOG_UNUSED_PAD_LAYERS dlg( editFrame, selection, *m_commit );

View File

@ -707,7 +707,7 @@ bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
// Apply the stateful filter
FilterCollectedItems( collector );
FilterCollectorForGroups( collector );
FilterCollectorForHierarchy( collector );
// Apply some ugly heuristics to avoid disambiguation menus whenever possible
if( collector.GetCount() > 1 && !m_skip_heuristics )
@ -809,8 +809,8 @@ bool PCB_SELECTION_TOOL::selectMultiple()
if( view->IsMirroredX() )
windowSelection = !windowSelection;
m_frame->GetCanvas()->SetCurrentCursor(
windowSelection ? KICURSOR::SELECT_WINDOW : KICURSOR::SELECT_LASSO );
m_frame->GetCanvas()->SetCurrentCursor( windowSelection ? KICURSOR::SELECT_WINDOW
: KICURSOR::SELECT_LASSO );
if( evt->IsCancelInteractive() || evt->IsActivate() )
{
@ -872,7 +872,7 @@ bool PCB_SELECTION_TOOL::selectMultiple()
// Apply the stateful filter
FilterCollectedItems( collector );
FilterCollectorForGroups( collector );
FilterCollectorForHierarchy( collector );
for( EDA_ITEM* i : collector )
{
@ -2515,11 +2515,22 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
}
void PCB_SELECTION_TOOL::FilterCollectorForGroups( GENERAL_COLLECTOR& aCollector ) const
void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector ) const
{
std::unordered_set<BOARD_ITEM*> toAdd;
// If any element is a member of a group, replace those elements with the top containing group.
// Set TEMP_SELECTED on all parents which are included in the GENERAL_COLLECTOR. This
// algorithm is O3n, whereas checking for the parent inclusion could potentially be On^2.
for( int j = 0; j < aCollector.GetCount(); j++ )
{
if( aCollector[j]->GetParent() )
aCollector[j]->GetParent()->ClearFlags( TEMP_SELECTED );
}
for( int j = 0; j < aCollector.GetCount(); j++ )
aCollector[j]->SetFlags( TEMP_SELECTED );
for( int j = 0; j < aCollector.GetCount(); )
{
BOARD_ITEM* item = aCollector[j];
@ -2529,6 +2540,8 @@ void PCB_SELECTION_TOOL::FilterCollectorForGroups( GENERAL_COLLECTOR& aCollector
if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
start = parent;
// If any element is a member of a group, replace those elements with the top containing
// group.
PCB_GROUP* aTop = PCB_GROUP::TopLevelGroup( start, m_enteredGroup, m_isFootprintEditor );
if( aTop )
@ -2536,6 +2549,8 @@ void PCB_SELECTION_TOOL::FilterCollectorForGroups( GENERAL_COLLECTOR& aCollector
if( aTop != item )
{
toAdd.insert( aTop );
aTop->SetFlags( TEMP_SELECTED );
aCollector.Remove( item );
continue;
}
@ -2548,6 +2563,14 @@ void PCB_SELECTION_TOOL::FilterCollectorForGroups( GENERAL_COLLECTOR& aCollector
continue;
}
// Footprints are a bit easier as they can't be nested.
if( parent && parent->GetFlags() & TEMP_SELECTED )
{
// Remove children of selected items
aCollector.Remove( item );
continue;
}
++j;
}

View File

@ -186,10 +186,14 @@ public:
*/
void ExitGroup( bool aSelectGroup = false );
void FilterCollectorForGroups( GENERAL_COLLECTOR& aCollector ) const;
PCB_GROUP* GetEnteredGroup() { return m_enteredGroup; }
/**
* In general we don't want to select both a parent and any of it's children. This includes
* both footprints and their items, and groups and their members.
*/
void FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector ) const;
///< Apply the SELECTION_FILTER_OPTIONS to a collection of items
void FilterCollectedItems( GENERAL_COLLECTOR& aCollector );