KiCad PCB EDA Suite
footprint_select_widget.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <dialog_shim.h>
21 #include <kiway.h>
22 #include <kiway_player.h>
23 #include <make_unique.h>
24 #include <project.h>
27 
28 #include <functional>
29 #include <wx/combo.h>
30 #include <wx/gauge.h>
31 #include <wx/odcombo.h>
32 #include <wx/simplebook.h>
33 #include <wx/sizer.h>
34 #include <wx/timer.h>
35 #include <wx/utils.h>
36 #include <wx/wupdlock.h>
38 
42 enum
43 {
47 };
48 
49 
53 enum
54 {
57 };
58 
59 
60 wxDEFINE_EVENT( EVT_FOOTPRINT_SELECTED, wxCommandEvent );
61 
62 
64  FOOTPRINT_LIST* aFpList, bool aUpdate,
65  int aMaxItems )
66  : wxPanel( aParent ),
67  m_kiway( nullptr ),
68  m_update( aUpdate ),
69  m_finished_loading( false ),
70  m_max_items( aMaxItems ),
71  m_last_item( 0 ),
72  m_fp_list( aFpList )
73 {
74  m_zero_filter = true;
75  m_sizer = new wxBoxSizer( wxVERTICAL );
76  m_book = new wxSimplebook( this, wxID_ANY );
78  m_fp_sel_ctrl = new FOOTPRINT_CHOICE( m_book, wxID_ANY );
79 
80  m_book->SetEffect( wxSHOW_EFFECT_BLEND );
81  m_book->AddPage( m_progress_ctrl, "", true );
82  m_book->AddPage( m_fp_sel_ctrl, "", false );
83  m_sizer->Add( m_book, 1, wxEXPAND | wxALL, 5 );
84 
85  SetSizer( m_sizer );
86  Layout();
87  m_sizer->Fit( this );
88 
89  m_fp_sel_ctrl->Bind( wxEVT_COMBOBOX, &FOOTPRINT_SELECT_WIDGET::OnComboBox, this );
90  m_fp_sel_ctrl->Bind(
91  EVT_INTERACTIVE_CHOICE, &FOOTPRINT_SELECT_WIDGET::OnComboInteractive, this );
92 }
93 
94 
95 void FOOTPRINT_SELECT_WIDGET::Load( KIWAY& aKiway, PROJECT& aProject )
96 {
97  m_kiway = &aKiway;
98 
99  try
100  {
101  auto fp_lib_table = aProject.PcbFootprintLibs( aKiway );
103 
104  m_fp_list->ReadFootprintFiles( fp_lib_table, nullptr, m_progress_ctrl );
106  }
107  catch( ... )
108  {
109  // no footprint libraries available
110  }
111 }
112 
113 
115 {
117 
118  m_book->SetSelection( PAGE_SELECT );
119  m_finished_loading = true;
120 
121  if( m_update )
122  UpdateList();
123 }
124 
125 
126 void FOOTPRINT_SELECT_WIDGET::OnComboBox( wxCommandEvent& aEvent )
127 {
128  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
129  int sel = m_fp_sel_ctrl->GetSelection();
130 
131  switch( sel )
132  {
133  case wxNOT_FOUND: return;
134 
135  case POS_SEPARATOR:
136  // User somehow managed to select the separator. This should not be
137  // possible, but just in case... deselect it
138  m_fp_sel_ctrl->SetSelection( m_last_item );
139  break;
140 
141  case POS_OTHER:
142  // When POS_OTHER is selected, a dialog should be shown. However, we don't want to
143  // do this ALL the time, as some times (e.g. when moving around with the arrow keys)
144  // it could be very annoying. Therefore showing the picker is done from the custom
145  // "interactive select" event on FOOTPRINT_CHOICE, which only fires for more direct
146  // choice actions.
147  break;
148 
149  default:
150  {
151  wxStringClientData* clientdata =
152  static_cast<wxStringClientData*>( m_fp_sel_ctrl->GetClientObject( sel ) );
153  wxASSERT( clientdata );
154 
155  evt.SetString( clientdata->GetData() );
156  wxPostEvent( this, evt );
157  }
158  }
159 }
160 
161 
162 void FOOTPRINT_SELECT_WIDGET::OnComboInteractive( wxCommandEvent& aEvent )
163 {
164  if( aEvent.GetInt() == POS_OTHER && !m_fp_sel_ctrl->IsPopupShown() )
165  {
166  DoOther();
167  }
168 }
169 
170 
172 {
173  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
174 
175  wxString fpname = ShowPicker();
176  m_other_footprint = fpname;
177  UpdateList();
178  m_fp_sel_ctrl->SetSelection( POS_OTHER );
180 
181  evt.SetString( m_other_footprint );
182  wxPostEvent( this, evt );
183 }
184 
185 
187 {
188  wxString fpname;
189  wxWindow* parent = ::wxGetTopLevelParent( this );
190  DIALOG_SHIM* dsparent = dynamic_cast<DIALOG_SHIM*>( parent );
191 
192  // Only quasimodal dialogs can launch modal kiface dialogs. Otherwise the
193  // event loop goes all silly.
194  wxASSERT( !dsparent || dsparent->IsQuasiModal() );
195 
196  auto frame = m_kiway->Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );
197 
198  if( !frame->ShowModal( &fpname, parent ) )
199  {
200  fpname = wxEmptyString;
201  }
202 
203  frame->Destroy();
204 
205  return fpname;
206 }
207 
208 
210 {
212  m_default_footprint.Clear();
213  m_other_footprint.Clear();
214  m_zero_filter = false;
215 }
216 
217 
219 {
220  m_fp_filter.FilterByPinCount( aPinCount );
221 }
222 
223 
225  wxArrayString const& aFilters, bool aZeroFilters )
226 {
227  if( aZeroFilters && aFilters.size() == 0 )
228  m_zero_filter = true;
229  else
230  m_zero_filter = false;
231 
233 }
234 
235 
237 {
238  m_default_footprint = aFp;
239 }
240 
241 
243 {
244  int n_items = 0;
245 
246  if( !m_fp_list || !m_finished_loading )
247  return false;
248 
249  wxWindowUpdateLocker lock( m_fp_sel_ctrl );
250  m_fp_sel_ctrl->Clear();
251 
252  // Be careful adding items! "Default" must occupy POS_DEFAULT,
253  // "Other" must occupy POS_OTHER, and the separator must occupy POS_SEPARATOR.
254 
255  m_fp_sel_ctrl->Append( m_default_footprint.IsEmpty() ?
256  _( "No default footprint" ) :
257  "[" + _( "Default" ) + "] " + m_default_footprint,
258  new wxStringClientData( m_default_footprint ) );
259 
260  m_fp_sel_ctrl->Append( m_other_footprint.IsEmpty() ?
261  _( "Other..." ) :
262  "[" + _( "Other..." ) + "] " + m_other_footprint,
263  new wxStringClientData( m_other_footprint ) );
264 
265  m_fp_sel_ctrl->Append( "", new wxStringClientData( "" ) );
266 
267  if( !m_zero_filter )
268  {
269  for( auto& fpinfo : m_fp_filter )
270  {
271  wxString display_name( fpinfo.GetNickname() + ":" + fpinfo.GetFootprintName() );
272 
273  m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) );
274  ++n_items;
275 
276  if( n_items >= m_max_items )
277  break;
278  }
279  }
280 
281  SelectDefault();
282  return true;
283 }
284 
285 
287 {
288  m_fp_sel_ctrl->SetSelection( POS_DEFAULT );
289 }
290 
291 
293 {
294  return m_fp_sel_ctrl->Enable( aEnable );
295 }
void SetList(FOOTPRINT_LIST &aList)
Set the list to filter.
Class PROJECT holds project specific data.
Definition: project.h:56
void FilterByFootprintFilters(wxArrayString const &aFilters, bool aZeroFilters)
Filter by footprint filter list.
void OnComboInteractive(wxCommandEvent &aEvent)
void DoOther()
Handle activation of the "Other..." item.
FOOTPRINT_SELECT_WIDGET(wxWindow *aParent, FOOTPRINT_LIST *aFpList, bool aUpdate=true, int aMaxItems=400)
Construct a footprint selector widget.
void FilterByFootprintFilters(wxArrayString const &aFilters)
Set a list of footprint filters to filter by.
void ClearFilters()
Clear all filter criteria.
void SetDefaultFootprint(wxString const &aFp)
Set the default footprint for a part.
Customized combo box for footprint selection.
wxString ShowPicker()
Show the component picker and return the selected component. Used by DoOther()
Class DIALOG_SHIM may sit in the inheritance tree between wxDialog and any class written by wxFormBui...
Definition: dialog_shim.h:70
wxDEFINE_EVENT(EVT_FOOTPRINT_SELECTED, wxCommandEvent)
GAUGE_PROGRESS_REPORTER * m_progress_ctrl
void ClearFilters()
Clear all filters.
bool UpdateList()
Update the contents of the list to match the filters.
void FilterByPinCount(int aPinCount)
Set a pin count to filter by.
static FOOTPRINT_LIST * GetInstance(KIWAY &aKiway)
Factory function to return a FOOTPRINT_LIST via Kiway.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:300
virtual bool ReadFootprintFiles(FP_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)=0
Read all the footprints provided by the combination of aTable and aNickname.
void OnComboBox(wxCommandEvent &aEvent)
bool IsQuasiModal()
Definition: dialog_shim.h:103
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:258
virtual bool Enable(bool aEnable=true) override
Enable or disable the control for input.
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
void SelectDefault()
Set current selection to the default footprint.
Holds a list of FOOTPRINT_INFO objects, along with a list of IO_ERRORs or PARSE_ERRORs that were thro...
Implementation of std::make_unique for pre C++14 compilation environments.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void Load(KIWAY &aKiway, PROJECT &aProject)
Start loading.
void FilterByPinCount(int aPinCount)
Filter by pin count.