From 7077e59395a943cfce84b36a8dd5461c18dfe3d3 Mon Sep 17 00:00:00 2001 From: Roberto Fernandez Bautista Date: Sat, 27 Mar 2021 14:44:51 +0000 Subject: [PATCH] Make moving pads independent of footprint much harder with new setting It is still possible to move a pad independent of footprint through the pad properties dialog. This is a much more conscious decision than using the move tools. ADDED: "Allow free pads" preference setting in pcbnew, default to off. When enabled, allows moving unlocked pads independent of the footprint (i.e. previous behaviour). When disabled (default), any attempt to move a pad will move the parent footprint instead. REMOVED: "Lock pads of newly added footprints" preference setting in pcbnew. (Pad lock state is now loaded from the footprint definition) CHANGED: There are now only two possible lock states for a footprint: locked and unlocked. The lock state of the pads in the footprint is now independent of the footprint lock state. Also fixed a latent bug that would allow a pad to be moved when the parent footprint was locked (see m_selectionTool->RequestSelection lambdas in edit_tool.cpp) Fixes https://gitlab.com/kicad/code/kicad/-/issues/7739 --- .../dialog_edit_footprint_for_fp_editor.cpp | 3 +- ...alog_edit_footprint_for_fp_editor_base.cpp | 4 +- ...alog_edit_footprint_for_fp_editor_base.fbp | 4 +- .../dialogs/dialog_footprint_properties.cpp | 24 +--- .../dialog_footprint_properties_base.cpp | 2 +- .../dialog_footprint_properties_base.fbp | 6 +- pcbnew/dialogs/panel_edit_options.cpp | 5 +- pcbnew/dialogs/panel_edit_options_base.cpp | 10 +- pcbnew/dialogs/panel_edit_options_base.fbp | 128 +++++++++--------- pcbnew/dialogs/panel_edit_options_base.h | 2 +- pcbnew/footprint_viewer_frame.cpp | 1 - .../netlist_reader/board_netlist_updater.cpp | 1 - pcbnew/pcbnew_settings.cpp | 8 +- pcbnew/pcbnew_settings.h | 7 +- pcbnew/tools/board_editor_control.cpp | 1 - pcbnew/tools/edit_tool.cpp | 48 ++++++- 16 files changed, 134 insertions(+), 120 deletions(-) diff --git a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp index 29175daf86..8c1e41b5cc 100644 --- a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp +++ b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp @@ -227,8 +227,7 @@ bool DIALOG_FOOTPRINT_FP_EDITOR::TransferDataToWindow() wxGridTableMessage tmsg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_texts->GetNumberRows() ); m_itemsGrid->ProcessTableMessage( tmsg ); - // Module Properties - + // Footprint Properties m_AutoPlaceCtrl->SetSelection( m_footprint->IsLocked() ? 1 : 0 ); m_AutoPlaceCtrl->SetItemToolTip( 0, _( "Enable hotkey move commands and Auto Placement" ) ); m_AutoPlaceCtrl->SetItemToolTip( 1, _( "Disable hotkey move commands and Auto Placement" ) ); diff --git a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.cpp b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.cpp index 0d05062f4c..e28fda98d7 100644 --- a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.cpp +++ b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.cpp @@ -132,10 +132,10 @@ DIALOG_FOOTPRINT_FP_EDITOR_BASE::DIALOG_FOOTPRINT_FP_EDITOR_BASE( wxWindow* pare wxBoxSizer* bSizerProperties; bSizerProperties = new wxBoxSizer( wxHORIZONTAL ); - wxString m_AutoPlaceCtrlChoices[] = { _("Free"), _("Lock footprint") }; + wxString m_AutoPlaceCtrlChoices[] = { _("Unlock footprint"), _("Lock footprint") }; int m_AutoPlaceCtrlNChoices = sizeof( m_AutoPlaceCtrlChoices ) / sizeof( wxString ); m_AutoPlaceCtrl = new wxRadioBox( m_PanelGeneral, wxID_ANY, _("Move and Place"), wxDefaultPosition, wxDefaultSize, m_AutoPlaceCtrlNChoices, m_AutoPlaceCtrlChoices, 1, wxRA_SPECIFY_COLS ); - m_AutoPlaceCtrl->SetSelection( 0 ); + m_AutoPlaceCtrl->SetSelection( 1 ); bSizerProperties->Add( m_AutoPlaceCtrl, 1, wxTOP|wxRIGHT|wxLEFT, 5 ); m_sizerAP = new wxStaticBoxSizer( new wxStaticBox( m_PanelGeneral, wxID_ANY, _("Auto-placement Rules") ), wxVERTICAL ); diff --git a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.fbp b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.fbp index 7dd643b11e..9d3cb4ecd5 100644 --- a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.fbp +++ b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor_base.fbp @@ -868,7 +868,7 @@ 1 0 - "Free" "Lock footprint" + "Unlock footprint" "Lock footprint" 1 1 @@ -900,7 +900,7 @@ 1 Resizable - 0 + 1 1 wxRA_SPECIFY_COLS diff --git a/pcbnew/dialogs/dialog_footprint_properties.cpp b/pcbnew/dialogs/dialog_footprint_properties.cpp index 121dea4cc2..08fed7ebc4 100644 --- a/pcbnew/dialogs/dialog_footprint_properties.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties.cpp @@ -326,21 +326,11 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataToWindow() updateOrientationControl(); - if( m_footprint->IsLocked() ) - m_AutoPlaceCtrl->SetSelection( 2 ); - else if( allPadsLocked( m_footprint ) ) - m_AutoPlaceCtrl->SetSelection( 1 ); - else - m_AutoPlaceCtrl->SetSelection( 0 ); + m_AutoPlaceCtrl->SetSelection( m_footprint->IsLocked() ? 1 : 0 ); m_AutoPlaceCtrl->SetItemToolTip( 0, _( "Footprint can be freely moved and oriented on the " - "canvas. At least some of the footprint's pads are " - "unlocked and can be moved with respect to the " - "footprint." ) ); - m_AutoPlaceCtrl->SetItemToolTip( 1, _( "Footprint can be freely moved and oriented on the " - "canvas, but all of its pads are locked with respect " - "to their position within in the footprint." ) ); - m_AutoPlaceCtrl->SetItemToolTip( 2, _( "Footprint is locked: it cannot be freely moved and " + "canvas." ) ); + m_AutoPlaceCtrl->SetItemToolTip( 1, _( "Footprint is locked: it cannot be freely moved and " "oriented on the canvas and can only be selected when " "the 'Locked items' checkbox is enabled in the " "selection filter." ) ); @@ -735,13 +725,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow() // Set Footprint Position wxPoint pos( m_posX.GetValue(), m_posY.GetValue() ); m_footprint->SetPosition( pos ); - m_footprint->SetLocked( m_AutoPlaceCtrl->GetSelection() == 2 ); - - if( m_AutoPlaceCtrl->GetSelection() == 1 ) - { - for( PAD* pad : m_footprint->Pads() ) - pad->SetLocked( true ); - } + m_footprint->SetLocked( m_AutoPlaceCtrl->GetSelection() == 1 ); int attributes = 0; diff --git a/pcbnew/dialogs/dialog_footprint_properties_base.cpp b/pcbnew/dialogs/dialog_footprint_properties_base.cpp index a18bd062f8..1fc58ec6a8 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_base.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_base.cpp @@ -192,7 +192,7 @@ DIALOG_FOOTPRINT_PROPERTIES_BASE::DIALOG_FOOTPRINT_PROPERTIES_BASE( wxWindow* pa wxBoxSizer* bSizerMiddle; bSizerMiddle = new wxBoxSizer( wxVERTICAL ); - wxString m_AutoPlaceCtrlChoices[] = { _("Free"), _("Lock pads"), _("Lock footprint") }; + wxString m_AutoPlaceCtrlChoices[] = { _("Unlock footprint"), _("Lock footprint") }; int m_AutoPlaceCtrlNChoices = sizeof( m_AutoPlaceCtrlChoices ) / sizeof( wxString ); m_AutoPlaceCtrl = new wxRadioBox( m_PanelGeneral, wxID_ANY, _("Move and Place"), wxDefaultPosition, wxDefaultSize, m_AutoPlaceCtrlNChoices, m_AutoPlaceCtrlChoices, 1, wxRA_SPECIFY_COLS ); m_AutoPlaceCtrl->SetSelection( 0 ); diff --git a/pcbnew/dialogs/dialog_footprint_properties_base.fbp b/pcbnew/dialogs/dialog_footprint_properties_base.fbp index 4e29bf2216..a66ccddeff 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_base.fbp +++ b/pcbnew/dialogs/dialog_footprint_properties_base.fbp @@ -1446,11 +1446,11 @@ - + 5 wxEXPAND|wxTOP 1 - + bSizerMiddle wxVERTICAL @@ -1473,7 +1473,7 @@ 1 0 - "Free" "Lock pads" "Lock footprint" + "Unlock footprint" "Lock footprint" 1 1 diff --git a/pcbnew/dialogs/panel_edit_options.cpp b/pcbnew/dialogs/panel_edit_options.cpp index a942738b8a..59393269f1 100644 --- a/pcbnew/dialogs/panel_edit_options.cpp +++ b/pcbnew/dialogs/panel_edit_options.cpp @@ -38,7 +38,6 @@ PANEL_EDIT_OPTIONS::PANEL_EDIT_OPTIONS( PCB_BASE_EDIT_FRAME* aFrame, PAGED_DIALO m_magneticPads->Show( dynamic_cast( m_frame ) != nullptr ); m_magneticGraphics->Show( dynamic_cast( m_frame ) != nullptr ); m_flipLeftRight->Show( dynamic_cast( m_frame ) != nullptr ); - m_autoLockPads->Show( dynamic_cast( m_frame ) != nullptr ); #ifdef __WXOSX_MAC__ m_mouseCmdsOSX->Show( true ); @@ -73,7 +72,6 @@ bool PANEL_EDIT_OPTIONS::TransferDataToWindow() m_magneticTrackChoice->SetSelection( static_cast( general_opts.m_MagneticItems.tracks ) ); m_magneticGraphicsChoice->SetSelection( !general_opts.m_MagneticItems.graphics ); m_flipLeftRight->SetValue( general_opts.m_FlipLeftRight ); - m_autoLockPads->SetValue( !general_opts.m_AddUnlockedPads ); switch( general_opts.m_TrackDragAction ) { @@ -84,6 +82,7 @@ bool PANEL_EDIT_OPTIONS::TransferDataToWindow() m_Show_Page_Limits->SetValue( m_frame->ShowPageLimits() ); m_Auto_Refill_Zones->SetValue( general_opts.m_AutoRefillZones ); + m_Allow_Free_Pads->SetValue( general_opts.m_AllowFreePads ); } else if( dynamic_cast( m_frame ) ) { @@ -119,8 +118,8 @@ bool PANEL_EDIT_OPTIONS::TransferDataFromWindow() m_frame->Settings().m_FlipLeftRight = m_flipLeftRight->GetValue(); m_frame->SetShowPageLimits( m_Show_Page_Limits->GetValue() ); - m_frame->Settings().m_AddUnlockedPads = !m_autoLockPads->GetValue(); m_frame->Settings().m_AutoRefillZones = m_Auto_Refill_Zones->GetValue(); + m_frame->Settings().m_AllowFreePads = m_Allow_Free_Pads->GetValue(); if( m_rbTrackDragMove->GetValue() ) pcbnewSettings.m_TrackDragAction = TRACK_DRAG_ACTION::MOVE; diff --git a/pcbnew/dialogs/panel_edit_options_base.cpp b/pcbnew/dialogs/panel_edit_options_base.cpp index 77dac46183..152de00bee 100644 --- a/pcbnew/dialogs/panel_edit_options_base.cpp +++ b/pcbnew/dialogs/panel_edit_options_base.cpp @@ -38,11 +38,6 @@ PANEL_EDIT_OPTIONS_BASE::PANEL_EDIT_OPTIONS_BASE( wxWindow* parent, wxWindowID i wxBoxSizer* bSizerBoardEdit; bSizerBoardEdit = new wxBoxSizer( wxVERTICAL ); - m_autoLockPads = new wxCheckBox( bOptionsSizer->GetStaticBox(), wxID_ANY, _("Lock pads of newly added footprints"), wxDefaultPosition, wxDefaultSize, 0 ); - m_autoLockPads->SetToolTip( _("If checked, when a footprint is added to the board, its pads will be locked and not movable with respect to the footprint.") ); - - bSizerBoardEdit->Add( m_autoLockPads, 0, wxBOTTOM, 15 ); - m_flipLeftRight = new wxCheckBox( bOptionsSizer->GetStaticBox(), wxID_ANY, _("Flip board items L/R (default is T/B)"), wxDefaultPosition, wxDefaultSize, 0 ); bSizerBoardEdit->Add( m_flipLeftRight, 0, wxBOTTOM, 15 ); @@ -371,6 +366,11 @@ PANEL_EDIT_OPTIONS_BASE::PANEL_EDIT_OPTIONS_BASE( wxWindow* parent, wxWindowID i sbSizer4->Add( m_Auto_Refill_Zones, 0, wxALL, 5 ); + m_Allow_Free_Pads = new wxCheckBox( sbSizer4->GetStaticBox(), wxID_ANY, _("Allow free pads"), wxDefaultPosition, wxDefaultSize, 0 ); + m_Allow_Free_Pads->SetToolTip( _("If unchecked (default), any attempt to move unlocked pads will instead move the footprint as a whole.\nIf checked, unlocked pads can be moved freely with respect to the rest of the footprint. \nNote: Locked pads cannot be moved with respect to the parent footprint regardless of this setting.") ); + + sbSizer4->Add( m_Allow_Free_Pads, 0, wxALL, 5 ); + pcbOptionsSizer->Add( sbSizer4, 1, wxEXPAND|wxTOP, 5 ); diff --git a/pcbnew/dialogs/panel_edit_options_base.fbp b/pcbnew/dialogs/panel_edit_options_base.fbp index 2436feae13..2e8ba9daed 100644 --- a/pcbnew/dialogs/panel_edit_options_base.fbp +++ b/pcbnew/dialogs/panel_edit_options_base.fbp @@ -232,70 +232,6 @@ bSizerBoardEdit wxVERTICAL none - - 15 - wxBOTTOM - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Lock pads of newly added footprints - - 0 - - - 0 - - 1 - m_autoLockPads - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - If checked, when a footprint is added to the board, its pads will be locked and not movable with respect to the footprint. - - wxFILTER_NONE - wxDefaultValidator - - - - - - 15 wxBOTTOM @@ -3487,6 +3423,70 @@ + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Allow free pads + + 0 + + + 0 + + 1 + m_Allow_Free_Pads + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + If unchecked (default), any attempt to move unlocked pads will instead move the footprint as a whole. If checked, unlocked pads can be moved freely with respect to the rest of the footprint. Note: Locked pads cannot be moved with respect to the parent footprint regardless of this setting. + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/pcbnew/dialogs/panel_edit_options_base.h b/pcbnew/dialogs/panel_edit_options_base.h index 6241f9d988..8da338c879 100644 --- a/pcbnew/dialogs/panel_edit_options_base.h +++ b/pcbnew/dialogs/panel_edit_options_base.h @@ -43,7 +43,6 @@ class PANEL_EDIT_OPTIONS_BASE : public wxPanel wxCheckBox* m_magneticPads; wxCheckBox* m_magneticGraphics; - wxCheckBox* m_autoLockPads; wxCheckBox* m_flipLeftRight; wxCheckBox* m_segments45OnlyCtrl; wxStaticText* m_staticTextRotationAngle; @@ -67,6 +66,7 @@ class PANEL_EDIT_OPTIONS_BASE : public wxPanel wxRadioButton* m_rbTrackDragFree; wxCheckBox* m_Show_Page_Limits; wxCheckBox* m_Auto_Refill_Zones; + wxCheckBox* m_Allow_Free_Pads; public: diff --git a/pcbnew/footprint_viewer_frame.cpp b/pcbnew/footprint_viewer_frame.cpp index 4993c5a0d1..7559d5e365 100644 --- a/pcbnew/footprint_viewer_frame.cpp +++ b/pcbnew/footprint_viewer_frame.cpp @@ -753,7 +753,6 @@ void FOOTPRINT_VIEWER_FRAME::AddFootprintToPCB( wxCommandEvent& aEvent ) { // Set the pads ratsnest settings to the global settings pad->SetLocalRatsnestVisible( pcbframe->GetDisplayOptions().m_ShowGlobalRatsnest ); - pad->SetLocked( !pcbframe->Settings().m_AddUnlockedPads ); // Pads in the library all have orphaned nets. Replace with Default. pad->SetNetCode( 0 ); diff --git a/pcbnew/netlist_reader/board_netlist_updater.cpp b/pcbnew/netlist_reader/board_netlist_updater.cpp index 03388022e4..21f4fcd3a3 100644 --- a/pcbnew/netlist_reader/board_netlist_updater.cpp +++ b/pcbnew/netlist_reader/board_netlist_updater.cpp @@ -172,7 +172,6 @@ FOOTPRINT* BOARD_NETLIST_UPDATER::addNewComponent( COMPONENT* aComponent ) { // Set the pads ratsnest settings to the global settings pad->SetLocalRatsnestVisible( m_frame->GetDisplayOptions().m_ShowGlobalRatsnest ); - pad->SetLocked( !m_frame->Settings().m_AddUnlockedPads ); // Pads in the library all have orphaned nets. Replace with Default. pad->SetNetCode( 0 ); diff --git a/pcbnew/pcbnew_settings.cpp b/pcbnew/pcbnew_settings.cpp index d6ed975967..358f3b8b58 100644 --- a/pcbnew/pcbnew_settings.cpp +++ b/pcbnew/pcbnew_settings.cpp @@ -67,11 +67,11 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_TrackDragAction( TRACK_DRAG_ACTION::DRAG ), m_Use45DegreeGraphicSegments( false ), m_FlipLeftRight( false ), - m_AddUnlockedPads( false ), m_PolarCoords( false ), m_RotationAngle( 900 ), m_ShowPageLimits( true ), m_AutoRefillZones( true ), + m_AllowFreePads( false ), m_PnsSettings( nullptr ), m_FootprintViewerAutoZoom( false ), m_FootprintViewerZoom( 1.0 ) @@ -104,9 +104,6 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_params.emplace_back( new PARAM( "editing.flip_left_right", &m_FlipLeftRight, true ) ); - m_params.emplace_back( new PARAM( "editing.add_unlocked_pads", - &m_AddUnlockedPads, false ) ); - m_params.emplace_back( new PARAM( "editing.magnetic_graphics", &m_MagneticItems.graphics, true ) ); @@ -131,6 +128,9 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_params.emplace_back( new PARAM( "editing.auto_fill_zones", &m_AutoRefillZones, true ) ); + m_params.emplace_back( new PARAM( "editing.allow_free_pads", + &m_AllowFreePads, false ) ); + m_params.emplace_back( new PARAM( "pcb_display.graphic_items_fill", &m_Display.m_DisplayGraphicsFill, true ) ); diff --git a/pcbnew/pcbnew_settings.h b/pcbnew/pcbnew_settings.h index ff2ffb1477..4b90cf4215 100644 --- a/pcbnew/pcbnew_settings.h +++ b/pcbnew/pcbnew_settings.h @@ -281,9 +281,6 @@ public: bool m_FlipLeftRight; // True: Flip footprints across Y axis // False: Flip footprints across X axis - bool m_AddUnlockedPads; // True: Pads are unlocked when new footprints are added to the board - // False: Pads are locked in new footprints - bool m_PolarCoords; int m_RotationAngle; @@ -293,6 +290,10 @@ public: ///<@todo Implement real auto zone filling (not just after zone properties are edited) bool m_AutoRefillZones; // Fill zones after editing the zone using the Zone Properties dialog + bool m_AllowFreePads; // True: unlocked pads can be moved freely with respect to the footprint. + // False (default): all pads are treated as locked for the purposes of + // movement and any attempt to move them will move the footprint instead. + wxString m_FootprintTextShownColumns; std::unique_ptr m_PnsSettings; diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp index 442fc1478d..1e4c2f9cf4 100644 --- a/pcbnew/tools/board_editor_control.cpp +++ b/pcbnew/tools/board_editor_control.cpp @@ -1022,7 +1022,6 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent ) for( PAD* pad : fp->Pads() ) { pad->SetLocalRatsnestVisible( m_frame->GetDisplayOptions().m_ShowGlobalRatsnest ); - pad->SetLocked( !m_frame->Settings().m_AddUnlockedPads ); // Pads in the library all have orphaned nets. Replace with Default. pad->SetNetCode( 0 ); diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index cc84418eac..6d4395d197 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -634,7 +634,9 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference ) // Now filter out locked and grouped items. We cannot do this in the first RequestSelection() // as we need the item_layers when a pad is the selection front. - selection = m_selectionTool->RequestSelection( + if( frame()->Settings().m_AllowFreePads ) + { + selection = m_selectionTool->RequestSelection( []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) { std::set to_add; @@ -642,14 +644,14 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference ) // 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 ]; + 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() ) + // Locked pads do not get moved independently of the footprint + if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T + && item->IsLocked() ) { if( !aCollector.HasItem( item->GetParent() ) ) to_add.insert( item->GetParent() ); @@ -662,6 +664,39 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference ) aCollector.Append( item ); }, !m_isFootprintEditor /* prompt user regarding locked items only in pcb editor*/ ); + } + else + { + // Unlocked pads are treated as locked if the setting m_AllowFreePads is false + selection = m_selectionTool->RequestSelection( + []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, + PCB_SELECTION_TOOL* sTool ) + { + std::set to_add; + + // 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( item->Type() == PCB_MARKER_T ) + aCollector.Remove( item ); + + // Treat all pads as locked (i.e. cannot be moved indepenendtly of footprint) + if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T ) + { + if( !aCollector.HasItem( item->GetParent() ) ) + to_add.insert( item->GetParent() ); + + aCollector.Remove( item ); + } + } + + for( BOARD_ITEM* item : to_add ) + aCollector.Append( item ); + }, + !m_isFootprintEditor /* prompt user regarding locked items only in pcb editor*/ ); + } if( selection.Empty() ) return 0; @@ -1835,8 +1870,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) aCollector.Remove( item ); // We don't operate on pads; convert them to footprint selections - if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T - && !item->GetParent()->IsLocked() ) + if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T ) { aCollector.Remove( item );