Pcbnew: fix occasional failure-to-select for dragging

In the Drag tool client filter function, sometimes,
GuessSelectionCandidates trims the collector's item list.
But we used the old contents of the per-type vectors to make
judgements about what was connected.

If a call came in with 2 tracks (e.g. near a knee) and one
was removed by GuessSelectionCandidates, sometimes the
other one would be the one selected for removal in the
2 tracks/0 via case. This leaves the collector empty.

The other case, where the item removed by GuessSelectionCandidates
was removed from the collector is silent, as removing an item
not in the collector is a no-op.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/21517
This commit is contained in:
John Beard 2025-08-20 19:28:45 +08:00
parent 54349c5845
commit 105b9fcfe8

View File

@ -557,20 +557,28 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
std::vector<PCB_TRACK*> vias; std::vector<PCB_TRACK*> vias;
std::vector<FOOTPRINT*> footprints; std::vector<FOOTPRINT*> footprints;
for( EDA_ITEM* item : aCollector ) // Gather items from the collector into per-type vectors
{ const auto gatherItemsByType =
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) ) [&]()
{ {
if( track->Type() == PCB_VIA_T ) for( EDA_ITEM* item : aCollector )
vias.push_back( track ); {
else if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
tracks.push_back( track ); {
} if( track->Type() == PCB_VIA_T )
else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item ) ) vias.push_back( track );
{ else
footprints.push_back( footprint ); tracks.push_back( track );
} }
} else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item ) )
{
footprints.push_back( footprint );
}
}
};
// Initial gathering of items
gatherItemsByType();
if( !sTool->GetSelection().IsHover() && footprints.size() ) if( !sTool->GetSelection().IsHover() && footprints.size() )
{ {
@ -587,8 +595,17 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
* First trim down selection to active layer, tracks vs zones, etc. * First trim down selection to active layer, tracks vs zones, etc.
*/ */
if( aCollector.GetCount() > 1 ) if( aCollector.GetCount() > 1 )
{
sTool->GuessSelectionCandidates( aCollector, aPt ); sTool->GuessSelectionCandidates( aCollector, aPt );
// Re-gather items after trimming to update counts
tracks.clear();
vias.clear();
footprints.clear();
gatherItemsByType();
}
/* /*
* If we have a knee between two tracks, or a via attached to two tracks, * If we have a knee between two tracks, or a via attached to two tracks,
* then drop the selection to a single item. We don't want a selection * then drop the selection to a single item. We don't want a selection