Move lock checks to CLIENT_SELECTION_FILTER.

Also checks render item visibility as well as layer visibility
when making selections.

Fixes: lp:1066220
* https://bugs.launchpad.net/kicad/+bug/1066220

Fixes: lp:1541756
* https://bugs.launchpad.net/kicad/+bug/1541756
This commit is contained in:
Jeff Young 2018-09-25 15:23:38 +01:00
parent 686f1b878b
commit 37f7faf433
16 changed files with 162 additions and 247 deletions

View File

@ -262,11 +262,13 @@ NET_SELECTOR::NET_SELECTOR( wxWindow *parent, wxWindowID id,
m_netSelectorPopup( nullptr ) m_netSelectorPopup( nullptr )
{ } { }
void NET_SELECTOR::DoSetPopupControl( wxComboPopup* aPopup ) void NET_SELECTOR::DoSetPopupControl( wxComboPopup* aPopup )
{ {
m_popup = nullptr; m_popup = nullptr;
} }
void NET_SELECTOR::OnButtonClick() void NET_SELECTOR::OnButtonClick()
{ {
wxRect comboRect = GetScreenRect(); wxRect comboRect = GetScreenRect();
@ -287,11 +289,13 @@ void NET_SELECTOR::OnButtonClick()
SetSelectedNetcode( popup->GetSelectedNetcode() ); SetSelectedNetcode( popup->GetSelectedNetcode() );
} }
void NET_SELECTOR::SetNetInfo( NETINFO_LIST* aNetInfoList ) void NET_SELECTOR::SetNetInfo( NETINFO_LIST* aNetInfoList )
{ {
m_netinfoList = aNetInfoList; m_netinfoList = aNetInfoList;
} }
void NET_SELECTOR::SetSelectedNetcode( int aNetcode ) void NET_SELECTOR::SetSelectedNetcode( int aNetcode )
{ {
m_netcode = aNetcode; m_netcode = aNetcode;
@ -311,17 +315,20 @@ void NET_SELECTOR::SetSelectedNetcode( int aNetcode )
} }
} }
void NET_SELECTOR::SetIndeterminate() void NET_SELECTOR::SetIndeterminate()
{ {
m_netcode = -1; m_netcode = -1;
SetValue( INDETERMINATE ); SetValue( INDETERMINATE );
} }
bool NET_SELECTOR::IsIndeterminate() bool NET_SELECTOR::IsIndeterminate()
{ {
return m_netcode == -1; return m_netcode == -1;
} }
int NET_SELECTOR::GetSelectedNetcode() int NET_SELECTOR::GetSelectedNetcode()
{ {
return m_netcode; return m_netcode;

View File

@ -422,7 +422,7 @@ public:
* @param module * @param module
* @param aDC (can be NULL ) = the current Device Context, to draw the new footprint * @param aDC (can be NULL ) = the current Device Context, to draw the new footprint
*/ */
void AddModuleToBoard( MODULE* module, wxDC* aDC = nullptr ); virtual void AddModuleToBoard( MODULE* module );
/** /**
* Function SelectFootprintFromLibBrowser * Function SelectFootprintFromLibBrowser

View File

@ -402,14 +402,22 @@ void FOOTPRINT_EDIT_FRAME::restoreLastFootprint()
MODULE* module = loadFootprint( id ); MODULE* module = loadFootprint( id );
if( module ) if( module )
{ AddModuleToBoard( module );
m_footprintNameWhenLoaded = curFootprintName;
GetBoard()->Add( module );
}
} }
} }
void FOOTPRINT_EDIT_FRAME::AddModuleToBoard( MODULE* aFootprint )
{
m_footprintNameWhenLoaded = aFootprint->GetFPID().GetLibItemName();
// Pads are always editable in Footprint Editor
aFootprint->SetPadsLocked( false );
PCB_BASE_EDIT_FRAME::AddModuleToBoard( aFootprint );
}
const wxChar* FOOTPRINT_EDIT_FRAME::GetFootprintEditorFrameName() const wxChar* FOOTPRINT_EDIT_FRAME::GetFootprintEditorFrameName()
{ {
return FOOTPRINT_EDIT_FRAME_NAME; return FOOTPRINT_EDIT_FRAME_NAME;

View File

@ -478,6 +478,12 @@ public:
*/ */
bool OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl = 0 ) override; bool OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl = 0 ) override;
/**
* Override from PCB_BASE_EDIT_FRAME which adds a module to the editor's dummy board,
* NOT to the user's PCB.
*/
void AddModuleToBoard( MODULE* module ) override;
/** /**
* Allows Modedit to install its preferences panel into the preferences dialog. * Allows Modedit to install its preferences panel into the preferences dialog.
*/ */

View File

@ -297,7 +297,6 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break; break;
SetCrossHairPosition( wxPoint( 0, 0 ) ); SetCrossHairPosition( wxPoint( 0, 0 ) );
m_footprintNameWhenLoaded = module->GetFPID().GetLibItemName();
AddModuleToBoard( module ); AddModuleToBoard( module );
// Initialize data relative to nets and netclasses (for a new // Initialize data relative to nets and netclasses (for a new
@ -359,8 +358,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
SetCrossHairPosition( wxPoint( 0, 0 ) ); SetCrossHairPosition( wxPoint( 0, 0 ) );
// Add the new object to board // Add the new object to board
m_footprintNameWhenLoaded = module->GetFPID().GetLibItemName(); AddModuleToBoard( module );
GetBoard()->Add( module, ADD_APPEND );
// Initialize data relative to nets and netclasses (for a new // Initialize data relative to nets and netclasses (for a new
// module the defaults are used) // module the defaults are used)
@ -509,7 +507,6 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break; break;
SetCrossHairPosition( wxPoint( 0, 0 ) ); SetCrossHairPosition( wxPoint( 0, 0 ) );
m_footprintNameWhenLoaded = module->GetFPID().GetLibItemName();
AddModuleToBoard( module ); AddModuleToBoard( module );
if( GetBoard()->m_Modules ) if( GetBoard()->m_Modules )

View File

@ -321,8 +321,7 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module( const wxString& aName )
module->SetFPID( LIB_ID( wxEmptyString, moduleName ) ); module->SetFPID( LIB_ID( wxEmptyString, moduleName ) );
// Insert footprint in list // Insert footprint in list
m_footprintNameWhenLoaded = module->GetFPID().GetLibItemName(); AddModuleToBoard( module );
GetBoard()->Add( module );
// Display info : // Display info :
SetMsgPanel( module ); SetMsgPanel( module );

View File

@ -121,8 +121,7 @@ bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule )
newModule->ClearFlags(); newModule->ClearFlags();
newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) ); newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) );
m_footprintNameWhenLoaded = newModule->GetFPID().GetLibItemName(); AddModuleToBoard( newModule );
GetBoard()->Add( newModule );
// Clear references to any net info, because the footprint editor // Clear references to any net info, because the footprint editor
// does know any thing about nets handled by the current edited board. // does know any thing about nets handled by the current edited board.
@ -271,41 +270,6 @@ MODULE* PCB_BASE_FRAME::SelectFootprintFromLibTree( bool aAllowBrowser )
} }
void PCB_BASE_FRAME::AddModuleToBoard( MODULE* module, wxDC* aDC )
{
if( module )
{
GetBoard()->Add( module, ADD_APPEND );
module->SetFlags( IS_NEW );
module->SetLink( 0 );
if( IsGalCanvasActive() )
module->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
else
module->SetPosition( GetCrossHairPosition() );
module->SetTimeStamp( GetNewTimeStamp() );
GetBoard()->m_Status_Pcb = 0;
// Put it on FRONT layer,
// (Can be stored flipped if the lib is an archive built from a board)
if( module->IsFlipped() )
module->Flip( module->GetPosition() );
// Place it in orientation 0,
// even if it is not saved with orientation 0 in lib
// (Can happen if the lib is an archive built from a board)
Rotate_Module( NULL, module, 0, false );
//RecalculateAllTracksNetcode();
if( aDC )
module->Draw( m_canvas, aDC, GR_OR );
}
}
MODULE* PCB_BASE_FRAME::LoadFootprint( const LIB_ID& aFootprintId ) MODULE* PCB_BASE_FRAME::LoadFootprint( const LIB_ID& aFootprintId )
{ {
MODULE* module = NULL; MODULE* module = NULL;

View File

@ -369,7 +369,11 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
if( module ) if( module )
{ {
m_canvas->MoveCursorToCrossHair(); m_canvas->MoveCursorToCrossHair();
AddModuleToBoard( module, aDC ); AddModuleToBoard( module );
if( aDC )
module->Draw( m_canvas, aDC, GR_OR );
StartMoveModule( module, aDC, false ); StartMoveModule( module, aDC, false );
} }
} }

View File

@ -212,6 +212,36 @@ void PCB_BASE_FRAME::SetBoard( BOARD* aBoard )
} }
void PCB_BASE_FRAME::AddModuleToBoard( MODULE* module )
{
if( module )
{
GetBoard()->Add( module, ADD_APPEND );
module->SetFlags( IS_NEW );
module->SetLink( 0 );
if( IsGalCanvasActive() )
module->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
else
module->SetPosition( GetCrossHairPosition() );
module->SetTimeStamp( GetNewTimeStamp() );
GetBoard()->m_Status_Pcb = 0;
// Put it on FRONT layer,
// (Can be stored flipped if the lib is an archive built from a board)
if( module->IsFlipped() )
module->Flip( module->GetPosition() );
// Place it in orientation 0,
// even if it is not saved with orientation 0 in lib
// (Can happen if the lib is an archive built from a board)
module->SetOrientation( 0 );
}
}
void PCB_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings ) void PCB_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
{ {
wxASSERT( m_Pcb ); wxASSERT( m_Pcb );

View File

@ -169,14 +169,19 @@ TOOL_ACTION PCB_ACTIONS::cutToClipboard( "pcbnew.InteractiveEdit.CutToClipboard"
_( "Cut" ), _( "Cut selected content to clipboard" ), _( "Cut" ), _( "Cut selected content to clipboard" ),
cut_xpm ); cut_xpm );
void filterItems( GENERAL_COLLECTOR& aCollector, bool sanitizePads, bool ensureEditable )
void EditToolSelectionFilter( GENERAL_COLLECTOR& aCollector, int aFlags )
{ {
// 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 ];
if( sanitizePads && item->Type() == PCB_PAD_T ) if( ( aFlags & EXCLUDE_LOCKED ) && item->IsLocked() )
{
aCollector.Remove( item );
}
else if( item->Type() == PCB_PAD_T )
{ {
MODULE* mod = static_cast<MODULE*>( item->GetParent() ); MODULE* mod = static_cast<MODULE*>( item->GetParent() );
@ -193,7 +198,7 @@ void filterItems( GENERAL_COLLECTOR& aCollector, bool sanitizePads, bool ensureE
if( mod && aCollector.HasItem( mod ) ) if( mod && aCollector.HasItem( mod ) )
aCollector.Remove( item ); aCollector.Remove( item );
} }
else if( ensureEditable && item->Type() == PCB_MARKER_T ) else if( ( aFlags & EXCLUDE_TRANSIENTS ) && item->Type() == PCB_MARKER_T )
{ {
aCollector.Remove( item ); aCollector.Remove( item );
} }
@ -201,24 +206,6 @@ void filterItems( GENERAL_COLLECTOR& aCollector, bool sanitizePads, bool ensureE
} }
void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, true, true );
}
void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, true, false );
}
void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, false, true );
}
EDIT_TOOL::EDIT_TOOL() : EDIT_TOOL::EDIT_TOOL() :
PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ),
m_dragging( false ) m_dragging( false )
@ -246,14 +233,6 @@ bool EDIT_TOOL::Init()
return false; return false;
} }
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
m_defaultSelectionFilter = SanitizePadsEnsureEditableFilter;
// Allow pad editing in Footprint Editor
if( editFrame->IsType( FRAME_PCB_MODULE_EDITOR ) )
m_defaultSelectionFilter = EnsureEditableFilter;
auto editingModuleCondition = [ this ] ( const SELECTION& aSelection ) { auto editingModuleCondition = [ this ] ( const SELECTION& aSelection ) {
return m_editModules; return m_editModules;
}; };
@ -356,7 +335,9 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
// Be sure that there is at least one item that we can modify. If nothing was selected before, // Be sure that there is at least one item that we can modify. If nothing was selected before,
// try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -622,10 +603,9 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{ {
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
const auto& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); const auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
return 0;
// Tracks & vias are treated in a special way: // Tracks & vias are treated in a special way:
if( ( SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) )( selection ) ) if( ( SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) )( selection ) )
@ -665,14 +645,13 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{ {
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
updateModificationPoint( selection ); updateModificationPoint( selection );
const int rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent ); const int rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent );
@ -742,10 +721,9 @@ static void mirrorPadX( D_PAD& aPad, const wxPoint& aMirrorPoint )
int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
{ {
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
return 0;
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -822,10 +800,9 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
{ {
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
return 0;
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -869,10 +846,9 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
return 0; return 0;
// get a copy instead of reference (as we're going to clear the selection before removing items) // get a copy instead of reference (as we're going to clear the selection before removing items)
auto selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); auto selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
return 0;
// is this "alternative" remove? // is this "alternative" remove?
const bool isAlt = aEvent.Parameter<intptr_t>() == (int) PCB_ACTIONS::REMOVE_FLAGS::ALT; const bool isAlt = aEvent.Parameter<intptr_t>() == (int) PCB_ACTIONS::REMOVE_FLAGS::ALT;
@ -930,10 +906,9 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{ {
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); const auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
return 0;
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1007,7 +982,9 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement ); bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement );
// Be sure that there is at least one item that we can modify // Be sure that there is at least one item that we can modify
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); const auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS ); } );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1152,7 +1129,9 @@ private:
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent ) int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
{ {
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); const auto& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS ); } );
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
@ -1436,7 +1415,9 @@ int EDIT_TOOL::doCopyToClipboard( bool withAnchor )
Activate(); Activate();
SELECTION& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS ); } );
if( selection.Empty() ) if( selection.Empty() )
return 1; return 1;

View File

@ -36,16 +36,16 @@ class BOARD_ITEM;
class CONNECTIVITY_DATA; class CONNECTIVITY_DATA;
/** /**
* Function SanitizePadsEnsureEditableFilter * Function EditToolSelectionFilter
* *
* A CLIENT_SELECTION_FILTER which promotes pad selections to their parent modules and * A CLIENT_SELECTION_FILTER which promotes pad selections to their parent modules and
* excludes non-editable items (such as markers). * optionally excludes locked items and/or transient items (such as markers).
*/ */
void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items );
void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& items ); #define EXCLUDE_LOCKED 0x0002
#define EXCLUDE_TRANSIENTS 0x0004
void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items ); void EditToolSelectionFilter( GENERAL_COLLECTOR& aCollector, int aFlags );
/** /**
@ -189,8 +189,6 @@ private:
///> Selection tool used for obtaining selected items ///> Selection tool used for obtaining selected items
SELECTION_TOOL* m_selectionTool; SELECTION_TOOL* m_selectionTool;
CLIENT_SELECTION_FILTER m_defaultSelectionFilter;
///> Flag determining if anything is being dragged right now ///> Flag determining if anything is being dragged right now
bool m_dragging; bool m_dragging;

View File

@ -798,7 +798,9 @@ static bool deleteItem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
const SELECTION& selection = selectionTool->RequestSelection( SanitizePadsFilter ); const SELECTION& selection = selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED ); } );
if( selection.Empty() ) if( selection.Empty() )
return true; return true;

View File

@ -183,90 +183,18 @@ ALIGNMENT_RECTS GetBoundingBoxes( const SELECTION &sel )
} }
void ALIGN_DISTRIBUTE_TOOL::filterPadsWithModules( SELECTION &selection )
{
std::set<BOARD_ITEM*> rejected;
for( auto i : selection )
{
auto item = static_cast<BOARD_ITEM*>( i );
if( item->Type() == PCB_PAD_T )
{
MODULE* mod = static_cast<MODULE*>( item->GetParent() );
// selection contains both the module and its pads - remove the pads
if( mod && selection.Contains( mod ) )
rejected.insert( item );
}
}
for( BOARD_ITEM* item : rejected )
selection.Remove( item );
}
int ALIGN_DISTRIBUTE_TOOL::checkLockedStatus( const SELECTION &selection ) const
{
SELECTION moving_items( selection );
// Remove the anchor from the list
moving_items.Remove( moving_items.Front() );
bool containsLocked = false;
// Check if the selection contains locked items
for( const auto& item : moving_items )
{
switch ( item->Type() )
{
case PCB_MODULE_T:
if( static_cast< MODULE* >( item )->IsLocked() )
containsLocked = true;
break;
case PCB_PAD_T:
case PCB_MODULE_EDGE_T:
case PCB_MODULE_TEXT_T:
if( static_cast< MODULE* >( item->GetParent() )->IsLocked() )
containsLocked = true;
break;
default: // suppress warnings
break;
}
}
if( containsLocked )
{
KIDIALOG dlg( getEditFrame< PCB_EDIT_FRAME >(),
_( "Selection contains locked items. Do you want to continue?" ),
_( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
dlg.SetOKLabel( _( "Continue" ) );
dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
if( dlg.ShowModal() == wxID_OK )
return SELECTION_LOCK_OVERRIDE;
else
return SELECTION_LOCKED;
}
return SELECTION_UNLOCKED;
}
int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortTopmostY ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortTopmostY );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -296,17 +224,15 @@ int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::AlignBottom( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignBottom( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortBottommostY ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortBottommostY );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -351,17 +277,15 @@ int ALIGN_DISTRIBUTE_TOOL::AlignLeft( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::doAlignLeft() int ALIGN_DISTRIBUTE_TOOL::doAlignLeft()
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortLeftmostX ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortLeftmostX );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -406,17 +330,15 @@ int ALIGN_DISTRIBUTE_TOOL::AlignRight( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::doAlignRight() int ALIGN_DISTRIBUTE_TOOL::doAlignRight()
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortRightmostX ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortRightmostX );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -446,17 +368,15 @@ int ALIGN_DISTRIBUTE_TOOL::doAlignRight()
int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortCenterX ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortCenterX );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -487,17 +407,15 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
filterPadsWithModules( selection );
auto itemsToAlign = GetBoundingBoxes( selection ); auto itemsToAlign = GetBoundingBoxes( selection );
std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortCenterY ); std::sort( itemsToAlign.begin(), itemsToAlign.end(), SortCenterY );
if( checkLockedStatus( selection ) == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -528,14 +446,13 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::DistributeHorizontally( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::DistributeHorizontally( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );
@ -614,14 +531,13 @@ void ALIGN_DISTRIBUTE_TOOL::doDistributeCentersHorizontally( ALIGNMENT_RECTS &it
int ALIGN_DISTRIBUTE_TOOL::DistributeVertically( const TOOL_EVENT& aEvent ) int ALIGN_DISTRIBUTE_TOOL::DistributeVertically( const TOOL_EVENT& aEvent )
{ {
auto frame = getEditFrame<PCB_BASE_FRAME>(); auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter ); SELECTION& selection = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
if( selection.Size() <= 1 ) if( selection.Size() <= 1 )
return 0; return 0;
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
BOARD_COMMIT commit( frame ); BOARD_COMMIT commit( frame );
commit.StageItems( selection, CHT_MODIFY ); commit.StageItems( selection, CHT_MODIFY );

View File

@ -119,11 +119,6 @@ private:
CONTEXT_MENU* m_placementMenu; CONTEXT_MENU* m_placementMenu;
/**
* Remove pads from a multi-unit select that also includes the pads' parents
*/
void filterPadsWithModules( SELECTION &selection );
/** /**
* Check a selection to ensure locks are valid for alignment. * Check a selection to ensure locks are valid for alignment.
* *

View File

@ -80,15 +80,12 @@ bool POSITION_RELATIVE_TOOL::Init()
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>();
CLIENT_SELECTION_FILTER filter = SanitizePadsEnsureEditableFilter;
// Allow pad editing in Footprint Editor const auto& selection = m_selectionTool->RequestSelection(
if( editFrame->IsType( FRAME_PCB_MODULE_EDITOR ) ) []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
filter = EnsureEditableFilter; { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
const auto& selection = m_selectionTool->RequestSelection( filter ); if( selection.Empty() )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED || selection.Empty() )
return 0; return 0;
m_selection = selection; m_selection = selection;
@ -148,7 +145,9 @@ int POSITION_RELATIVE_TOOL::SelectPositionRelativeItem( const TOOL_EVENT& aEvent
picker->SetClickHandler( [&]( const VECTOR2D& aPoint ) -> bool picker->SetClickHandler( [&]( const VECTOR2D& aPoint ) -> bool
{ {
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
const SELECTION& sel = m_selectionTool->RequestSelection( EnsureEditableFilter ); const SELECTION& sel = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
{ EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS ); } );
if( sel.Empty() ) if( sel.Empty() )
return true; // still looking for an item return true; // still looking for an item

View File

@ -752,16 +752,7 @@ int SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent )
{ {
CLIENT_SELECTION_FILTER aClientFilter = aEvent.Parameter<CLIENT_SELECTION_FILTER>(); CLIENT_SELECTION_FILTER aClientFilter = aEvent.Parameter<CLIENT_SELECTION_FILTER>();
if( m_selection.Empty() ) // Try to find an item that could be modified selectCursor( false, aClientFilter );
{
selectCursor( true, aClientFilter );
if( CheckLock() == SELECTION_LOCKED )
{
clearSelection();
return 0;
}
}
return 0; return 0;
} }
@ -1691,10 +1682,28 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
if( aItem->Type() == PCB_PAD_T ) if( aItem->Type() == PCB_PAD_T )
{ {
// In editor, pads are selectable if any draw layer is visible
auto pad = static_cast<const D_PAD*>( aItem ); auto pad = static_cast<const D_PAD*>( aItem );
// Check render mode (from the Items tab) first
switch( pad->GetAttribute() )
{
case PAD_ATTRIB_STANDARD:
case PAD_ATTRIB_HOLE_NOT_PLATED:
if( !board()->IsElementVisible( LAYER_PADS_TH ) )
return false;
break;
case PAD_ATTRIB_CONN:
case PAD_ATTRIB_SMD:
if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
return false;
else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
return false;
break;
}
// Otherwise, pads are selectable if any draw layer is visible
// Shortcut: check copper layer visibility // Shortcut: check copper layer visibility
if( board()->IsLayerVisible( F_Cu ) && pad->IsOnLayer( F_Cu ) ) if( board()->IsLayerVisible( F_Cu ) && pad->IsOnLayer( F_Cu ) )
return true; return true;