diff --git a/pcbnew/dialogs/dialog_filter_selection.cpp b/pcbnew/dialogs/dialog_filter_selection.cpp index 3678a28245..82c8818a85 100644 --- a/pcbnew/dialogs/dialog_filter_selection.cpp +++ b/pcbnew/dialogs/dialog_filter_selection.cpp @@ -29,20 +29,10 @@ DIALOG_FILTER_SELECTION::DIALOG_FILTER_SELECTION( PCB_BASE_FRAME* aParent, OPTIO DIALOG_FILTER_SELECTION_BASE( aParent ), m_options( aOptions ) { - m_Include_Modules->SetValue( m_options.includeModules ); - m_IncludeLockedModules->SetValue( m_options.includeLockedModules ); + setCheckboxStatesFromOptions( aOptions ); - if( m_Include_Modules->GetValue() ) - m_IncludeLockedModules->Enable(); - else - m_IncludeLockedModules->Disable(); - - m_Include_Tracks->SetValue( m_options.includeTracks ); - m_Include_Vias->SetValue( m_options.includeVias ); - m_Include_Zones->SetValue( m_options.includeZones ); - m_Include_Draw_Items->SetValue( m_options.includeItemsOnTechLayers ); - m_Include_Edges_Items->SetValue( m_options.includeBoardOutlineLayer ); - m_Include_PcbTextes->SetValue( m_options.includePcbTexts ); + // Update "All Items" checkbox based on how many items are currently checked + m_All_Items->Set3StateValue( GetSuggestedAllItemsState() ); m_sdbSizer1OK->SetDefault(); SetFocus(); @@ -57,6 +47,126 @@ void DIALOG_FILTER_SELECTION::checkBoxClicked( wxCommandEvent& aEvent ) m_IncludeLockedModules->Enable(); else m_IncludeLockedModules->Disable(); + + // Update "All Items" checkbox based on how many items are currently checked + m_All_Items->Set3StateValue( GetSuggestedAllItemsState() ); +} + + +void DIALOG_FILTER_SELECTION::setCheckboxStatesFromOptions( OPTIONS& aOptions ) +{ + m_Include_Modules->SetValue( m_options.includeModules ); + m_IncludeLockedModules->SetValue( m_options.includeLockedModules ); + + if( m_Include_Modules->GetValue() ) + m_IncludeLockedModules->Enable(); + else + m_IncludeLockedModules->Disable(); + + m_Include_Tracks->SetValue( m_options.includeTracks ); + m_Include_Vias->SetValue( m_options.includeVias ); + m_Include_Zones->SetValue( m_options.includeZones ); + m_Include_Draw_Items->SetValue( m_options.includeItemsOnTechLayers ); + m_Include_Edges_Items->SetValue( m_options.includeBoardOutlineLayer ); + m_Include_PcbTexts->SetValue( m_options.includePcbTexts ); +} + + +void DIALOG_FILTER_SELECTION::forceCheckboxStates( bool aNewState ) +{ + m_Include_Modules->SetValue( aNewState ); + m_IncludeLockedModules->SetValue( aNewState ); + + if( aNewState ) // Make enable state match checkbox state + m_IncludeLockedModules->Enable(); + else + m_IncludeLockedModules->Disable(); + + m_Include_Tracks->SetValue( aNewState ); + m_Include_Vias->SetValue( aNewState ); + m_Include_Zones->SetValue( aNewState ); + m_Include_Draw_Items->SetValue( aNewState ); + m_Include_Edges_Items->SetValue( aNewState ); + m_Include_PcbTexts->SetValue( aNewState ); +} + +wxCheckBoxState DIALOG_FILTER_SELECTION::GetSuggestedAllItemsState( void ) +{ + int NumChecked = 0; + int NumCheckboxesOnDlg = 0; + wxCheckBoxState SuggestedState = wxCHK_UNDETERMINED; // Assume some but not all are checked + + // Find out how many checkboxes are on this dialog. We do this at runtime so future + // changes to the dialog are easier to handle or automatic, depending on the change. + const wxWindowList& list = this->GetChildren(); + for( wxWindowList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) + { + wxWindow* current = node->GetData(); + + // If casting the child window to a checkbox isn't NULL, then the child is a checkbox + wxCheckBox* CurrCB = dynamic_cast( current ); + + if( CurrCB ) + { + // Need to get count of checkboxes, but not include the "All Items" checkbox (the only + // one that allows the 3rd state) or the hidden one (the only one with an empty label) + // that keeps the dialog formatted properly + + if( !( "" == CurrCB->GetLabelText() || CurrCB->Is3State() ) ) + NumCheckboxesOnDlg++; + } + } + + // Tally how many checkboxes are checked. Only include "locked footprints" in the total + // if "footprints" is checked. + if( m_Include_Modules->GetValue() ) + { + NumChecked++; + + if( m_IncludeLockedModules->GetValue() ) + NumChecked++; + } + else + { + // If include modules isn't checked then ignore the "Locked Footprints" checkbox in tally + NumCheckboxesOnDlg--; + } + + if( m_Include_Tracks->GetValue() ) + NumChecked++; + + if( m_Include_Vias->GetValue() ) + NumChecked++; + + if( m_Include_Zones->GetValue() ) + NumChecked++; + + if( m_Include_Draw_Items->GetValue() ) + NumChecked++; + + if( m_Include_Edges_Items->GetValue() ) + NumChecked++; + + if( m_Include_PcbTexts->GetValue() ) + NumChecked++; + + // Change suggestion if all or none are checked + + if( !NumChecked ) + SuggestedState = wxCHK_UNCHECKED; + else if( NumChecked == NumCheckboxesOnDlg ) + SuggestedState = wxCHK_CHECKED; + + return SuggestedState; +} + + +void DIALOG_FILTER_SELECTION::allItemsClicked( wxCommandEvent& aEvent ) +{ + if( wxCHK_CHECKED == m_All_Items->Get3StateValue() ) + forceCheckboxStates( true ); // Select all items + else + forceCheckboxStates( false ); // Clear all items } @@ -65,6 +175,7 @@ bool DIALOG_FILTER_SELECTION::TransferDataFromWindow() if( !wxDialog::TransferDataFromWindow() ) return false; + m_options.allItems = m_All_Items->Get3StateValue(); m_options.includeModules = m_Include_Modules->GetValue(); m_options.includeLockedModules = m_IncludeLockedModules->GetValue(); m_options.includeTracks = m_Include_Tracks->GetValue(); @@ -72,7 +183,7 @@ bool DIALOG_FILTER_SELECTION::TransferDataFromWindow() m_options.includeZones = m_Include_Zones->GetValue(); m_options.includeItemsOnTechLayers = m_Include_Draw_Items->GetValue(); m_options.includeBoardOutlineLayer = m_Include_Edges_Items->GetValue(); - m_options.includePcbTexts = m_Include_PcbTextes->GetValue(); + m_options.includePcbTexts = m_Include_PcbTexts->GetValue(); return true; } diff --git a/pcbnew/dialogs/dialog_filter_selection.h b/pcbnew/dialogs/dialog_filter_selection.h index 0d1f7a1ac1..f63e245132 100644 --- a/pcbnew/dialogs/dialog_filter_selection.h +++ b/pcbnew/dialogs/dialog_filter_selection.h @@ -37,6 +37,7 @@ public: */ struct OPTIONS { + wxCheckBoxState allItems = wxCHK_UNDETERMINED; bool includeModules = true; bool includeLockedModules = true; bool includeTracks = true; @@ -64,7 +65,14 @@ protected: bool TransferDataFromWindow() override; private: + wxCheckBoxState CurrCbState; + void checkBoxClicked( wxCommandEvent& aEvent ) override; + void allItemsClicked( wxCommandEvent& aEvent ) override; + + void setCheckboxStatesFromOptions( OPTIONS& aOptions ); + void forceCheckboxStates( bool aNewState ); + wxCheckBoxState GetSuggestedAllItemsState( void ); ///< Reference to the options struct to fill. OPTIONS& m_options; diff --git a/pcbnew/dialogs/dialog_filter_selection_base.cpp b/pcbnew/dialogs/dialog_filter_selection_base.cpp index c6f9ea0d8e..e6a29b50f9 100644 --- a/pcbnew/dialogs/dialog_filter_selection_base.cpp +++ b/pcbnew/dialogs/dialog_filter_selection_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 3.9.0 Jun 18 2020) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -17,13 +17,21 @@ DIALOG_FILTER_SELECTION_BASE::DIALOG_FILTER_SELECTION_BASE( wxWindow* parent, wx bSizerMain = new wxBoxSizer( wxVERTICAL ); wxGridSizer* gSizer1; - gSizer1 = new wxGridSizer( 4, 2, 3, 3 ); + gSizer1 = new wxGridSizer( 0, 2, 3, 3 ); + + m_All_Items = new wxCheckBox( this, wxID_ANY, _("All items"), wxPoint( -1,-1 ), wxDefaultSize, wxCHK_3STATE ); + gSizer1->Add( m_All_Items, 0, 0, 5 ); + + m_Hidden_Spacer = new wxCheckBox( this, wxID_ANY, wxEmptyString, wxPoint( -1,-1 ), wxDefaultSize, 0 ); + m_Hidden_Spacer->Hide(); + + gSizer1->Add( m_Hidden_Spacer, 0, wxRESERVE_SPACE_EVEN_IF_HIDDEN, 0 ); m_Include_Modules = new wxCheckBox( this, wxID_ANY, _("Include &footprints"), wxDefaultPosition, wxDefaultSize, 0 ); gSizer1->Add( m_Include_Modules, 0, 0, 5 ); - m_Include_PcbTextes = new wxCheckBox( this, wxID_ANY, _("Include t&ext items"), wxDefaultPosition, wxDefaultSize, 0 ); - gSizer1->Add( m_Include_PcbTextes, 0, 0, 5 ); + m_Include_PcbTexts = new wxCheckBox( this, wxID_ANY, _("Include t&ext items"), wxDefaultPosition, wxDefaultSize, 0 ); + gSizer1->Add( m_Include_PcbTexts, 0, 0, 5 ); m_IncludeLockedModules = new wxCheckBox( this, wxID_ANY, _("Include &locked footprints"), wxDefaultPosition, wxDefaultSize, 0 ); gSizer1->Add( m_IncludeLockedModules, 0, 0, 5 ); @@ -66,8 +74,9 @@ DIALOG_FILTER_SELECTION_BASE::DIALOG_FILTER_SELECTION_BASE( wxWindow* parent, wx this->Centre( wxBOTH ); // Connect Events + m_All_Items->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::allItemsClicked ), NULL, this ); m_Include_Modules->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); - m_Include_PcbTextes->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); + m_Include_PcbTexts->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_IncludeLockedModules->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_Include_Draw_Items->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_Include_Tracks->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); @@ -80,8 +89,9 @@ DIALOG_FILTER_SELECTION_BASE::DIALOG_FILTER_SELECTION_BASE( wxWindow* parent, wx DIALOG_FILTER_SELECTION_BASE::~DIALOG_FILTER_SELECTION_BASE() { // Disconnect Events + m_All_Items->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::allItemsClicked ), NULL, this ); m_Include_Modules->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); - m_Include_PcbTextes->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); + m_Include_PcbTexts->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_IncludeLockedModules->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_Include_Draw_Items->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); m_Include_Tracks->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FILTER_SELECTION_BASE::checkBoxClicked ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_filter_selection_base.fbp b/pcbnew/dialogs/dialog_filter_selection_base.fbp index 61f343b355..8c5d3e72b0 100644 --- a/pcbnew/dialogs/dialog_filter_selection_base.fbp +++ b/pcbnew/dialogs/dialog_filter_selection_base.fbp @@ -14,7 +14,6 @@ dialog_filter_selection_base 1000 none - 1 dialog_filter_selection_base @@ -26,7 +25,6 @@ 1 1 UI - 0 0 0 @@ -70,8 +68,137 @@ gSizer1 none - 4 + 0 3 + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + All items + + 0 + + + 0 + + 1 + m_All_Items + 1 + + + protected + 1 + -1,-1 + Resizable + 1 + + wxCHK_3STATE + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + allItemsClicked + + + + 0 + wxRESERVE_SPACE_EVEN_IF_HIDDEN + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 1 + wxID_ANY + + + 0 + + + 0 + + 1 + m_Hidden_Spacer + 1 + + + protected + 1 + -1,-1 + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + 5 @@ -178,7 +305,7 @@ 0 1 - m_Include_PcbTextes + m_Include_PcbTexts 1 diff --git a/pcbnew/dialogs/dialog_filter_selection_base.h b/pcbnew/dialogs/dialog_filter_selection_base.h index e43f829383..bae467405a 100644 --- a/pcbnew/dialogs/dialog_filter_selection_base.h +++ b/pcbnew/dialogs/dialog_filter_selection_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 3.9.0 Jun 18 2020) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -33,8 +33,10 @@ class DIALOG_FILTER_SELECTION_BASE : public DIALOG_SHIM private: protected: + wxCheckBox* m_All_Items; + wxCheckBox* m_Hidden_Spacer; wxCheckBox* m_Include_Modules; - wxCheckBox* m_Include_PcbTextes; + wxCheckBox* m_Include_PcbTexts; wxCheckBox* m_IncludeLockedModules; wxCheckBox* m_Include_Draw_Items; wxCheckBox* m_Include_Tracks; @@ -47,6 +49,7 @@ class DIALOG_FILTER_SELECTION_BASE : public DIALOG_SHIM wxButton* m_sdbSizer1Cancel; // Virtual event handlers, overide them in your derived class + virtual void allItemsClicked( wxCommandEvent& event ) { event.Skip(); } virtual void checkBoxClicked( wxCommandEvent& event ) { event.Skip(); } virtual void ExecuteCommand( wxCommandEvent& event ) { event.Skip(); } diff --git a/qa/qa_utils/mocks.cpp b/qa/qa_utils/mocks.cpp index 4a0287bcc1..dd251226f6 100644 --- a/qa/qa_utils/mocks.cpp +++ b/qa/qa_utils/mocks.cpp @@ -216,7 +216,7 @@ DIALOG_FILTER_SELECTION_BASE::DIALOG_FILTER_SELECTION_BASE( wxWindow* parent, wx { // these members are initialized only to avoid warnings about non initialized vars m_Include_Modules = nullptr; - m_Include_PcbTextes = nullptr; + m_Include_PcbTexts = nullptr; m_IncludeLockedModules = nullptr; m_Include_Draw_Items = nullptr; m_Include_Tracks = nullptr; @@ -251,6 +251,11 @@ void DIALOG_FILTER_SELECTION::checkBoxClicked( wxCommandEvent& aEvent ) } +void DIALOG_FILTER_SELECTION::allItemsClicked( wxCommandEvent& aEvent ) +{ +} + + bool DIALOG_FILTER_SELECTION::TransferDataFromWindow() { return true;