Separate locked & unlocked vias in global deletions.

Also allows a dialog to opt out of control-state
saving at the top level (rather than on every control).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21441
This commit is contained in:
Jeff Young 2025-08-06 18:19:17 +01:00
parent 3f8709ff55
commit 241d9a4c30
5 changed files with 1495 additions and 1508 deletions

View File

@ -421,41 +421,48 @@ void DIALOG_SHIM::SaveControlState()
geom[ "h" ] = rect.GetHeight();
dlgMap[ "__geometry" ] = geom;
std::function<void( wxWindow* )> saveFn = [&]( wxWindow* win )
std::function<void( wxWindow* )> saveFn =
[&]( wxWindow* win )
{
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( win->GetClientData() ) )
{
if( !props->GetPropertyOr( "persist", false ) )
return;
}
std::string key = generateKey( win );
if( !key.empty() )
{
if( wxComboBox* combo = dynamic_cast<wxComboBox*>( win ) )
dlgMap[ key ] = combo->GetSelection();
else if( wxChoice* choice = dynamic_cast<wxChoice*>( win ) )
dlgMap[ key ] = choice->GetSelection();
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( win ) )
dlgMap[ key ] = check->GetValue();
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( win ) )
dlgMap[ key ] = spin->GetValue();
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( win ) )
dlgMap[ key ] = radio->GetValue();
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( win ) )
dlgMap[ key ] = radioBox->GetSelection();
else if( wxSplitterWindow* splitter = dynamic_cast<wxSplitterWindow*>( win ) )
dlgMap[ key ] = splitter->GetSashPosition();
else if( wxScrolledWindow* scrolled = dynamic_cast<wxScrolledWindow*>( win ) )
dlgMap[ key ] = scrolled->GetScrollPos( wxVERTICAL );
else if( wxNotebook* notebook = dynamic_cast<wxNotebook*>( win ) )
dlgMap[ key ] = notebook->GetSelection();
}
for( wxWindow* child : win->GetChildren() )
saveFn( child );
};
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( GetClientData() ) )
{
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( win->GetClientData() ) )
{
if( !props->GetPropertyOr( "persist", false ) )
return;
}
std::string key = generateKey( win );
if( !key.empty() )
{
if( wxComboBox* combo = dynamic_cast<wxComboBox*>( win ) )
dlgMap[ key ] = combo->GetSelection();
else if( wxChoice* choice = dynamic_cast<wxChoice*>( win ) )
dlgMap[ key ] = choice->GetSelection();
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( win ) )
dlgMap[ key ] = check->GetValue();
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( win ) )
dlgMap[ key ] = spin->GetValue();
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( win ) )
dlgMap[ key ] = radio->GetValue();
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( win ) )
dlgMap[ key ] = radioBox->GetSelection();
else if( wxSplitterWindow* splitter = dynamic_cast<wxSplitterWindow*>( win ) )
dlgMap[ key ] = splitter->GetSashPosition();
else if( wxScrolledWindow* scrolled = dynamic_cast<wxScrolledWindow*>( win ) )
dlgMap[ key ] = scrolled->GetScrollPos( wxVERTICAL );
else if( wxNotebook* notebook = dynamic_cast<wxNotebook*>( win ) )
dlgMap[ key ] = notebook->GetSelection();
}
for( wxWindow* child : win->GetChildren() )
saveFn( child );
};
if( !props->GetPropertyOr( "persist", false ) )
return;
}
for( wxWindow* child : GetChildren() )
saveFn( child );
@ -473,75 +480,82 @@ void DIALOG_SHIM::LoadControlState()
const auto& dlgMap = dlgIt->second;
std::function<void( wxWindow* )> loadFn = [&]( wxWindow* win )
{
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( win->GetClientData() ) )
{
if( !props->GetPropertyOr( "persist", false ) )
return;
}
std::string key = generateKey( win );
if( !key.empty() )
{
auto it = dlgMap.find( key );
if( it != dlgMap.end() )
std::function<void( wxWindow* )> loadFn =
[&]( wxWindow* win )
{
const nlohmann::json& j = it->second;
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( win->GetClientData() ) )
{
if( !props->GetPropertyOr( "persist", false ) )
return;
}
if( wxComboBox* combo = dynamic_cast<wxComboBox*>( win ) )
{
if( j.is_string() )
combo->SetValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
}
else if( wxChoice* choice = dynamic_cast<wxChoice*>( win ) )
{
if( j.is_number_integer() )
choice->SetSelection( j.get<int>() );
}
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( win ) )
{
if( j.is_boolean() )
check->SetValue( j.get<bool>() );
}
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( win ) )
{
if( j.is_number_integer() )
spin->SetValue( j.get<int>() );
}
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( win ) )
{
if( j.is_boolean() )
radio->SetValue( j.get<bool>() );
}
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( win ) )
{
if( j.is_number_integer() )
radioBox->SetSelection( j.get<int>() );
}
else if( wxSplitterWindow* splitter = dynamic_cast<wxSplitterWindow*>( win ) )
{
if( j.is_number_integer() )
splitter->SetSashPosition( j.get<int>() );
}
else if( wxScrolledWindow* scrolled = dynamic_cast<wxScrolledWindow*>( win ) )
{
if( j.is_number_integer() )
scrolled->SetScrollPos( wxVERTICAL, j.get<int>() );
}
else if( wxNotebook* notebook = dynamic_cast<wxNotebook*>( win ) )
{
if( j.is_number_integer() )
notebook->SetSelection( j.get<int>() );
}
}
}
std::string key = generateKey( win );
for( wxWindow* child : win->GetChildren() )
loadFn( child );
};
if( !key.empty() )
{
auto it = dlgMap.find( key );
if( it != dlgMap.end() )
{
const nlohmann::json& j = it->second;
if( wxComboBox* combo = dynamic_cast<wxComboBox*>( win ) )
{
if( j.is_string() )
combo->SetValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
}
else if( wxChoice* choice = dynamic_cast<wxChoice*>( win ) )
{
if( j.is_number_integer() )
choice->SetSelection( j.get<int>() );
}
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( win ) )
{
if( j.is_boolean() )
check->SetValue( j.get<bool>() );
}
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( win ) )
{
if( j.is_number_integer() )
spin->SetValue( j.get<int>() );
}
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( win ) )
{
if( j.is_boolean() )
radio->SetValue( j.get<bool>() );
}
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( win ) )
{
if( j.is_number_integer() )
radioBox->SetSelection( j.get<int>() );
}
else if( wxSplitterWindow* splitter = dynamic_cast<wxSplitterWindow*>( win ) )
{
if( j.is_number_integer() )
splitter->SetSashPosition( j.get<int>() );
}
else if( wxScrolledWindow* scrolled = dynamic_cast<wxScrolledWindow*>( win ) )
{
if( j.is_number_integer() )
scrolled->SetScrollPos( wxVERTICAL, j.get<int>() );
}
else if( wxNotebook* notebook = dynamic_cast<wxNotebook*>( win ) )
{
if( j.is_number_integer() )
notebook->SetSelection( j.get<int>() );
}
}
}
for( wxWindow* child : win->GetChildren() )
loadFn( child );
};
if( PROPERTY_HOLDER* props = PROPERTY_HOLDER::SafeCast( GetClientData() ) )
{
if( !props->GetPropertyOr( "persist", false ) )
return;
}
for( wxWindow* child : GetChildren() )
loadFn( child );

View File

@ -24,6 +24,7 @@
#include <functional>
using namespace std::placeholders;
#include <property_holder.h>
#include <confirm.h>
#include <pcb_edit_frame.h>
#include <ratsnest/ratsnest_data.h>
@ -38,18 +39,24 @@ using namespace std::placeholders;
DIALOG_GLOBAL_DELETION::DIALOG_GLOBAL_DELETION( PCB_EDIT_FRAME* parent ) :
DIALOG_GLOBAL_DELETION_BASE( parent )
DIALOG_GLOBAL_DELETION_BASE( parent )
{
m_Parent = parent;
m_currentLayer = F_Cu;
m_trackFilterLocked->Enable( m_delTracks->GetValue() );
m_trackFilterUnlocked->Enable( m_delTracks->GetValue() );
m_trackFilterVias->Enable( m_delTracks->GetValue() );
m_viaFilterLocked->Enable( m_delTracks->GetValue() );
m_viaFilterUnlocked->Enable( m_delTracks->GetValue() );
m_footprintFilterLocked->Enable( m_delFootprints->GetValue() );
m_footprintFilterUnlocked->Enable( m_delFootprints->GetValue() );
m_drawingFilterLocked->Enable( m_delDrawings->GetValue() );
m_drawingFilterUnlocked->Enable( m_delDrawings->GetValue() );
// This is a destructive dialog. Don't save control state; we always want to come up in a benign state.
PROPERTY_HOLDER* props = new PROPERTY_HOLDER();
props->SetProperty( "persist", false );
SetClientData( props );
SetupStandardButtons();
SetFocus();
@ -75,7 +82,9 @@ int GLOBAL_EDIT_TOOL::GlobalDeletions( const TOOL_EVENT& aEvent )
void DIALOG_GLOBAL_DELETION::SetCurrentLayer( int aLayer )
{
m_currentLayer = aLayer;
m_textCtrlCurrLayer->SetValue( m_Parent->GetBoard()->GetLayerName( ToLAYER_ID( aLayer ) ) );
m_rbLayersOption->SetString( 1, wxString::Format( m_rbLayersOption->GetString( 1 ),
m_Parent->GetBoard()->GetLayerName( ToLAYER_ID( aLayer ) ) ) );
m_rbLayersOption->SetSelection( 0 );
}
@ -83,7 +92,8 @@ void DIALOG_GLOBAL_DELETION::onCheckDeleteTracks( wxCommandEvent& event )
{
m_trackFilterLocked->Enable( m_delTracks->GetValue() );
m_trackFilterUnlocked->Enable( m_delTracks->GetValue() );
m_trackFilterVias->Enable( m_delTracks->GetValue() );
m_viaFilterLocked->Enable( m_delTracks->GetValue() );
m_viaFilterUnlocked->Enable( m_delTracks->GetValue() );
}
@ -239,18 +249,29 @@ void DIALOG_GLOBAL_DELETION::DoGlobalDeletions()
}
else if( track->Type() == PCB_VIA_T )
{
if( m_trackFilterVias->GetValue() )
processConnectedItem( track, layers_filter );
}
else if( track->IsLocked() )
{
if( m_trackFilterLocked->GetValue() )
processConnectedItem( track, layers_filter );
if( track->IsLocked() )
{
if( m_viaFilterLocked->GetValue() )
processConnectedItem( track, layers_filter );
}
else
{
if( m_viaFilterUnlocked->GetValue() )
processConnectedItem( track, layers_filter );
}
}
else
{
if( m_trackFilterUnlocked->GetValue() )
processConnectedItem( track, layers_filter );
if( track->IsLocked() )
{
if( m_trackFilterLocked->GetValue() )
processConnectedItem( track, layers_filter );
}
else
{
if( m_trackFilterUnlocked->GetValue() )
processConnectedItem( track, layers_filter );
}
}
}
}

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -57,60 +57,56 @@ DIALOG_GLOBAL_DELETION_BASE::DIALOG_GLOBAL_DELETION_BASE( wxWindow* parent, wxWi
sbFilter = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Filter Settings") ), wxVERTICAL );
wxFlexGridSizer* fgSizer2;
fgSizer2 = new wxFlexGridSizer( 0, 1, 3, 0 );
fgSizer2->SetFlexibleDirection( wxBOTH );
fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_drawingFilterLocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Locked graphics"), wxDefaultPosition, wxDefaultSize, 0 );
sbFilter->Add( m_drawingFilterLocked, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
fgSizer2->Add( m_drawingFilterLocked, 0, wxRIGHT|wxLEFT, 5 );
m_drawingFilterUnlocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Unlocked graphics"), wxDefaultPosition, wxDefaultSize, 0 );
sbFilter->Add( m_drawingFilterUnlocked, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_drawingFilterUnlocked->SetValue(true);
fgSizer2->Add( m_drawingFilterUnlocked, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_footprintFilterLocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Locked footprints"), wxDefaultPosition, wxDefaultSize, 0 );
sbFilter->Add( m_footprintFilterLocked, 0, wxALL, 5 );
fgSizer2->Add( m_footprintFilterLocked, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_footprintFilterUnlocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Unlocked footprints"), wxDefaultPosition, wxDefaultSize, 0 );
m_footprintFilterUnlocked->SetValue(true);
sbFilter->Add( m_footprintFilterUnlocked, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 );
fgSizer2->Add( m_footprintFilterUnlocked, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 );
m_trackFilterLocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Locked tracks"), wxDefaultPosition, wxDefaultSize, 0 );
sbFilter->Add( m_trackFilterLocked, 0, wxALL, 5 );
fgSizer2->Add( m_trackFilterLocked, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_trackFilterUnlocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Unlocked tracks"), wxDefaultPosition, wxDefaultSize, 0 );
m_trackFilterUnlocked->SetValue(true);
sbFilter->Add( m_trackFilterUnlocked, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
fgSizer2->Add( m_trackFilterUnlocked, 0, wxRIGHT|wxLEFT, 5 );
m_trackFilterVias = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Vias"), wxDefaultPosition, wxDefaultSize, 0 );
m_trackFilterVias->SetValue(true);
sbFilter->Add( m_trackFilterVias, 0, wxRIGHT|wxLEFT, 5 );
m_viaFilterLocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Locked vias"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer2->Add( m_viaFilterLocked, 0, wxRIGHT|wxLEFT, 5 );
m_viaFilterUnlocked = new wxCheckBox( sbFilter->GetStaticBox(), wxID_ANY, _("Unlocked vias"), wxDefaultPosition, wxDefaultSize, 0 );
m_viaFilterUnlocked->SetValue(true);
fgSizer2->Add( m_viaFilterUnlocked, 0, wxRIGHT|wxLEFT, 5 );
bSizerRight->Add( sbFilter, 0, wxALL|wxEXPAND, 5 );
sbFilter->Add( fgSizer2, 1, wxEXPAND, 5 );
wxString m_rbLayersOptionChoices[] = { _("All layers"), _("Current layer only") };
bSizerRight->Add( sbFilter, 1, wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 5 );
bSizerUpper->Add( bSizerRight, 0, wxEXPAND|wxLEFT, 5 );
bSizerMain->Add( bSizerUpper, 1, wxEXPAND|wxALL, 5 );
wxString m_rbLayersOptionChoices[] = { _("All layers"), _("Current layer (%s) only") };
int m_rbLayersOptionNChoices = sizeof( m_rbLayersOptionChoices ) / sizeof( wxString );
m_rbLayersOption = new wxRadioBox( this, wxID_ANY, _("Layer Filter"), wxDefaultPosition, wxDefaultSize, m_rbLayersOptionNChoices, m_rbLayersOptionChoices, 1, wxRA_SPECIFY_COLS );
m_rbLayersOption->SetSelection( 0 );
bSizerRight->Add( m_rbLayersOption, 0, wxALL|wxEXPAND, 5 );
bSizerUpper->Add( bSizerRight, 0, wxEXPAND, 5 );
bSizerMain->Add( bSizerUpper, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxFlexGridSizer* fgSizer1;
fgSizer1 = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer1->AddGrowableCol( 1 );
fgSizer1->SetFlexibleDirection( wxBOTH );
fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText1 = new wxStaticText( this, wxID_ANY, _("Current layer:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
fgSizer1->Add( m_staticText1, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_textCtrlCurrLayer = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY );
fgSizer1->Add( m_textCtrlCurrLayer, 0, wxEXPAND|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizerMain->Add( fgSizer1, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
m_rbLayersOption->SetSelection( 1 );
bSizerMain->Add( m_rbLayersOption, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK );

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -20,14 +20,11 @@
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/radiobox.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_GLOBAL_DELETION_BASE
///////////////////////////////////////////////////////////////////////////////
@ -52,10 +49,9 @@ class DIALOG_GLOBAL_DELETION_BASE : public DIALOG_SHIM
wxCheckBox* m_footprintFilterUnlocked;
wxCheckBox* m_trackFilterLocked;
wxCheckBox* m_trackFilterUnlocked;
wxCheckBox* m_trackFilterVias;
wxCheckBox* m_viaFilterLocked;
wxCheckBox* m_viaFilterUnlocked;
wxRadioBox* m_rbLayersOption;
wxStaticText* m_staticText1;
wxTextCtrl* m_textCtrlCurrLayer;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;