Account for groups in undo of Position Relative To.

Also fixes a bug were pads weren't correctly being found for anchoring
the selection before the Position Relative To.

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

(cherry picked from commit 1e68c353f1)
This commit is contained in:
Jeff Young 2022-08-22 22:32:42 +01:00
parent 9bce3c243a
commit 9d0d45450b
2 changed files with 46 additions and 41 deletions

View File

@ -2678,7 +2678,7 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
std::unordered_set<BOARD_ITEM*> toAdd; std::unordered_set<BOARD_ITEM*> toAdd;
// Set TEMP_SELECTED on all parents which are included in the GENERAL_COLLECTOR. This // 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. // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
for( int j = 0; j < aCollector.GetCount(); j++ ) for( int j = 0; j < aCollector.GetCount(); j++ )
{ {
if( aCollector[j]->GetParent() ) if( aCollector[j]->GetParent() )

View File

@ -25,18 +25,18 @@
#include <memory> #include <memory>
using namespace std::placeholders; using namespace std::placeholders;
#include "position_relative_tool.h" #include <tools/position_relative_tool.h>
#include "pcb_actions.h" #include <tools/pcb_actions.h>
#include "pcb_selection_tool.h" #include <tools/pcb_selection_tool.h>
#include "edit_tool.h" #include <tools/pcb_picker_tool.h>
#include "pcb_picker_tool.h"
#include <dialogs/dialog_position_relative.h> #include <dialogs/dialog_position_relative.h>
#include <status_popup.h> #include <status_popup.h>
#include <board_commit.h> #include <board_commit.h>
#include <bitmaps.h>
#include <confirm.h> #include <confirm.h>
#include <collectors.h> #include <collectors.h>
#include <pad.h> #include <pad.h>
#include <footprint.h>
#include <pcb_group.h>
POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() : POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() :
@ -64,44 +64,16 @@ bool POSITION_RELATIVE_TOOL::Init()
} }
// TODO: Clean up this global once TOOL_EVENT supports std::functions as parameters
BOARD_ITEM* g_PositionRelativePadAnchor;
int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent ) int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent )
{ {
PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
g_PositionRelativePadAnchor = nullptr;
const auto& selection = m_selectionTool->RequestSelection( const auto& 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*> to_add; sTool->FilterCollectorForHierarchy( aCollector, true );
sTool->FilterCollectorForMarkers( aCollector );
// Iterate from the back so we don't have to worry about removals. sTool->FilterCollectorForFreePads( aCollector );
for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{
BOARD_ITEM* item = aCollector[i];
if( item->Type() == PCB_MARKER_T )
aCollector.Remove( item );
/// Locked pads do not get moved independently of the footprint
if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T && item->IsLocked()
&& !item->GetParent()->IsLocked() )
{
if( !aCollector.HasItem( item->GetParent() ) )
to_add.insert( item->GetParent() );
g_PositionRelativePadAnchor = item;
aCollector.Remove( item );
}
}
for( BOARD_ITEM* item : to_add )
aCollector.Append( item );
}, },
!m_isFootprintEditor /* prompt user regarding locked items */ ); !m_isFootprintEditor /* prompt user regarding locked items */ );
@ -110,8 +82,30 @@ int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent )
m_selection = selection; m_selection = selection;
if( g_PositionRelativePadAnchor ) static KICAD_T padsOnly[] = { PCB_PAD_T, EOT };
m_selectionAnchor = static_cast<PAD*>( g_PositionRelativePadAnchor )->GetPosition(); PCB_TYPE_COLLECTOR collector;
collector.Collect( static_cast<BOARD_ITEM*>( m_selection.GetTopLeftItem() ), padsOnly );
if( collector.GetCount() == 0 )
{
for( FOOTPRINT* footprint : editFrame->GetBoard()->Footprints() )
{
for( PAD* pad : footprint->Pads() )
{
if( pad->IsSelected() )
collector.Append( pad );
if( collector.GetCount() > 0 )
break;
}
if( collector.GetCount() > 0 )
break;
}
}
if( collector.GetCount() > 0 )
m_selectionAnchor = collector[0]->GetPosition();
else else
m_selectionAnchor = m_selection.GetTopLeftItem()->GetPosition(); m_selectionAnchor = m_selection.GetTopLeftItem()->GetPosition();
@ -138,13 +132,24 @@ int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( const wxPoint& aPosAnchor
{ {
wxPoint aggregateTranslation = aPosAnchor + aTranslation - GetSelectionAnchorPosition(); wxPoint aggregateTranslation = aPosAnchor + aTranslation - GetSelectionAnchorPosition();
for( auto item : m_selection ) for( EDA_ITEM* item : m_selection )
{ {
// Don't move a pad by itself unless editing the footprint // Don't move a pad by itself unless editing the footprint
if( item->Type() == PCB_PAD_T && frame()->IsType( FRAME_PCB_EDITOR ) ) if( item->Type() == PCB_PAD_T && frame()->IsType( FRAME_PCB_EDITOR ) )
item = item->GetParent(); item = item->GetParent();
m_commit->Modify( item ); m_commit->Modify( item );
// If moving a group, record position of all the descendants for undo
if( item->Type() == PCB_GROUP_T )
{
PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
{
m_commit->Modify( bItem );
});
}
static_cast<BOARD_ITEM*>( item )->Move( aggregateTranslation ); static_cast<BOARD_ITEM*>( item )->Move( aggregateTranslation );
} }