Separate logic for multi-select and click-select when filtering.

Also removes a bunch of old implementations of pad locking and
filtering which are no longer needed.  (They're now handled by the
uniform locking code.)

Also removes some of the auto-promotion logic.  Rotating a footprint
when a pad was selected is going to be surprising whether the pad
is locked or not.

Fixes https://gitlab.com/kicad/code/kicad/issues/8322
This commit is contained in:
Jeff Young 2021-04-28 23:53:31 +01:00
parent 39a0bc6252
commit 91421f9908
6 changed files with 30 additions and 154 deletions

View File

@ -157,7 +157,8 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( !( changeFlags & CHT_DONE ) ) if( !( changeFlags & CHT_DONE ) )
board->Footprints().front()->Add( boardItem ); board->Footprints().front()->Add( boardItem );
} }
else if( boardItem->Type() == PCB_FP_TEXT_T || else if( boardItem->Type() == PCB_PAD_T ||
boardItem->Type() == PCB_FP_TEXT_T ||
boardItem->Type() == PCB_FP_SHAPE_T || boardItem->Type() == PCB_FP_SHAPE_T ||
boardItem->Type() == PCB_FP_ZONE_T ) boardItem->Type() == PCB_FP_ZONE_T )
{ {

View File

@ -437,7 +437,7 @@ public:
m_ignoreLockedItems = false; m_ignoreLockedItems = false;
#if defined(USE_MATCH_LAYER) #if defined(USE_MATCH_LAYER)
m_IncludeSecondary = false; m_includeSecondary = false;
#else #else
m_includeSecondary = true; m_includeSecondary = true;
#endif #endif

View File

@ -286,8 +286,7 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
BOARD_ITEM* item = aCollector[ i ]; BOARD_ITEM* item = aCollector[ i ];
// We don't operate on pads; convert them to footprint selections // We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->IsLocked() && item->Type() == PCB_PAD_T if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T )
&& !item->GetParent()->IsLocked() )
{ {
aCollector.Remove( item ); aCollector.Remove( item );
@ -296,9 +295,9 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
} }
} }
sTool->FilterCollectorForHierarchy( aCollector ); sTool->FilterCollectorForHierarchy( aCollector, true );
}, },
!m_isFootprintEditor /* prompt user regarding locked items */ ); true /* prompt user regarding locked items */ );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1413,35 +1412,9 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
PCB_SELECTION& selection = m_selectionTool->RequestSelection( PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items; sTool->FilterCollectorForHierarchy( aCollector, true );
// 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];
// We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
&& !item->GetParent()->IsLocked() )
{
aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
// We can't rotate both a footprint and its text in the same operation, so if
// both are selected, remove the text
if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
aCollector.Remove( item );
}
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
}, },
!m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ ); !m_dragging /* prompt user regarding locked items */ );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1553,30 +1526,9 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
PCB_SELECTION& selection = m_selectionTool->RequestSelection( PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items; sTool->FilterCollectorForHierarchy( aCollector, true );
// 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];
// We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
&& !item->GetParent()->IsLocked() )
{
aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
}
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
}, },
!m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ ); !m_dragging /* prompt user regarding locked items */ );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1672,35 +1624,9 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
PCB_SELECTION& selection = m_selectionTool->RequestSelection( PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items; sTool->FilterCollectorForHierarchy( aCollector, true );
// 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];
// We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
&& !item->GetParent()->IsLocked() )
{
aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
// We can't flip both a footprint and its text in the same operation, so if
// both are selected, remove the text
if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
aCollector.Remove( item );
}
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
}, },
!m_dragging && !m_isFootprintEditor/* prompt user regarding locked items */ ); !m_dragging /* prompt user regarding locked items */ );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1968,8 +1894,6 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
const PCB_SELECTION& selection = m_selectionTool->RequestSelection( const PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items;
// Iterate from the back so we don't have to worry about removals. // Iterate from the back so we don't have to worry about removals.
for( int i = aCollector.GetCount() - 1; i >= 0; --i ) for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{ {
@ -1977,23 +1901,11 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
if( item->Type() == PCB_MARKER_T ) if( item->Type() == PCB_MARKER_T )
aCollector.Remove( item ); aCollector.Remove( item );
// We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T )
{
aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
} }
for( BOARD_ITEM* item : added_items ) sTool->FilterCollectorForHierarchy( aCollector, true );
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
}, },
!m_isFootprintEditor /* prompt user regarding locked items */ ); true /* prompt user regarding locked items */ );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -2092,28 +2004,16 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
const PCB_SELECTION& selection = m_selectionTool->RequestSelection( const PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items;
// Iterate from the back so we don't have to worry about removals. // Iterate from the back so we don't have to worry about removals.
for( int i = aCollector.GetCount() - 1; i >= 0; --i ) for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{ {
BOARD_ITEM* item = aCollector[i]; BOARD_ITEM* item = aCollector[i];
// We don't operate on pads; convert them to footprint selections if( item->Type() == PCB_MARKER_T )
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
&& !item->GetParent()->IsLocked() )
{
aCollector.Remove( item ); aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
} }
for( BOARD_ITEM* item : added_items ) sTool->FilterCollectorForHierarchy( aCollector, true );
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
} ); } );
if( selection.Empty() ) if( selection.Empty() )
@ -2181,17 +2081,9 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
dupe_item = static_cast<PCB_GROUP*>( orig_item )->DeepDuplicate(); dupe_item = static_cast<PCB_GROUP*>( orig_item )->DeepDuplicate();
break; break;
case PCB_PAD_T:
case PCB_FP_TEXT_T:
case PCB_FP_SHAPE_T:
case PCB_FP_ZONE_T:
case PCB_MARKER_T:
// Silently drop these items (such as footprint texts) from duplication
break;
default: default:
wxASSERT_MSG( false, wxASSERT_MSG( false, wxString::Format( "Unhandled item type %d",
wxString::Format( "Unknown item type %d", orig_item->Type() ) ); orig_item->Type() ) );
break; break;
} }
} }
@ -2259,28 +2151,7 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
const auto& selection = m_selectionTool->RequestSelection( const auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
std::set<BOARD_ITEM*> added_items; sTool->FilterCollectorForHierarchy( aCollector, true );
// 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];
// We don't operate on pads; convert them to footprint selections
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
&& !item->GetParent()->IsLocked() )
{
aCollector.Remove( item );
if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
added_items.insert( item->GetParent() );
}
}
for( BOARD_ITEM* item : added_items )
aCollector.Append( item );
sTool->FilterCollectorForHierarchy( aCollector );
} ); } );
if( selection.Empty() ) if( selection.Empty() )

View File

@ -202,7 +202,7 @@ int GLOBAL_EDIT_TOOL::RemoveUnusedPads( const TOOL_EVENT& aEvent )
PCB_SELECTION& selection = m_selectionTool->RequestSelection( PCB_SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{ {
sTool->FilterCollectorForHierarchy( aCollector ); sTool->FilterCollectorForHierarchy( aCollector, true );
} ); } );
DIALOG_UNUSED_PAD_LAYERS dlg( editFrame, selection, *m_commit ); 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 // Apply the stateful filter
FilterCollectedItems( collector ); FilterCollectedItems( collector );
FilterCollectorForHierarchy( collector ); FilterCollectorForHierarchy( collector, false );
// Apply some ugly heuristics to avoid disambiguation menus whenever possible // Apply some ugly heuristics to avoid disambiguation menus whenever possible
if( collector.GetCount() > 1 && !m_skip_heuristics ) if( collector.GetCount() > 1 && !m_skip_heuristics )
@ -872,7 +872,7 @@ bool PCB_SELECTION_TOOL::selectMultiple()
// Apply the stateful filter // Apply the stateful filter
FilterCollectedItems( collector ); FilterCollectedItems( collector );
FilterCollectorForHierarchy( collector ); FilterCollectorForHierarchy( collector, true );
for( EDA_ITEM* i : collector ) for( EDA_ITEM* i : collector )
{ {
@ -985,7 +985,7 @@ int PCB_SELECTION_TOOL::SelectAll( const TOOL_EVENT& aEvent )
collection.Append( item ); collection.Append( item );
} }
FilterCollectorForHierarchy( collection ); FilterCollectorForHierarchy( collection, true );
for( EDA_ITEM* item : collection ) for( EDA_ITEM* item : collection )
select( static_cast<BOARD_ITEM*>( item ) ); select( static_cast<BOARD_ITEM*>( item ) );
@ -2523,7 +2523,8 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
} }
void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector ) const void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector,
bool aMultiselect ) const
{ {
std::unordered_set<BOARD_ITEM*> toAdd; std::unordered_set<BOARD_ITEM*> toAdd;
@ -2536,8 +2537,11 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
aCollector[j]->GetParent()->ClearFlags( TEMP_SELECTED ); aCollector[j]->GetParent()->ClearFlags( TEMP_SELECTED );
} }
for( int j = 0; j < aCollector.GetCount(); j++ ) if( aMultiselect )
{
for( int j = 0; j < aCollector.GetCount(); j++ )
aCollector[j]->SetFlags( TEMP_SELECTED ); aCollector[j]->SetFlags( TEMP_SELECTED );
}
for( int j = 0; j < aCollector.GetCount(); ) for( int j = 0; j < aCollector.GetCount(); )
{ {

View File

@ -192,7 +192,7 @@ public:
* In general we don't want to select both a parent and any of it's children. This includes * 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. * both footprints and their items, and groups and their members.
*/ */
void FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector ) const; void FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector, bool aMultiselect ) const;
///< Apply the SELECTION_FILTER_OPTIONS to a collection of items ///< Apply the SELECTION_FILTER_OPTIONS to a collection of items
void FilterCollectedItems( GENERAL_COLLECTOR& aCollector ); void FilterCollectedItems( GENERAL_COLLECTOR& aCollector );