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>
37 
38 
42 enum
43 {
47 };
48 
49 
53 enum
54 {
57 };
58 
59 
60 wxDEFINE_EVENT( EVT_FOOTPRINT_SELECTED, wxCommandEvent );
61 
62 
64  FOOTPRINT_ASYNC_LOADER& aLoader, std::unique_ptr<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_loader( aLoader ),
73  m_fp_list( aFpList )
74 {
75  m_zero_filter = true;
76  m_sizer = new wxBoxSizer( wxVERTICAL );
77  m_progress_timer = std::make_unique<wxTimer>( this );
78  m_book = new wxSimplebook( this, wxID_ANY );
79  m_progress_ctrl = new wxGauge( m_book, wxID_ANY, 100 );
80  m_fp_sel_ctrl = new FOOTPRINT_CHOICE( m_book, wxID_ANY );
81 
82  m_book->SetEffect( wxSHOW_EFFECT_BLEND );
83  m_book->AddPage( m_progress_ctrl, "", true );
84  m_book->AddPage( m_fp_sel_ctrl, "", false );
85  m_sizer->Add( m_book, 1, wxEXPAND | wxALL, 5 );
86 
87  SetSizer( m_sizer );
88  Layout();
89  m_sizer->Fit( this );
90 
91  Bind( wxEVT_TIMER, &FOOTPRINT_SELECT_WIDGET::OnProgressTimer, this, m_progress_timer->GetId() );
92  m_fp_sel_ctrl->Bind( wxEVT_COMBOBOX, &FOOTPRINT_SELECT_WIDGET::OnComboBox, this );
93  m_fp_sel_ctrl->Bind(
94  EVT_INTERACTIVE_CHOICE, &FOOTPRINT_SELECT_WIDGET::OnComboInteractive, this );
95 }
96 
97 
98 void FOOTPRINT_SELECT_WIDGET::Load( KIWAY& aKiway, PROJECT& aProject )
99 {
100  m_kiway = &aKiway;
101 
102  try
103  {
104  auto fp_lib_table = aProject.PcbFootprintLibs( aKiway );
105 
106  if( m_fp_loader.GetProgress() == 0 || !m_fp_loader.IsSameTable( fp_lib_table ) )
107  {
110  m_fp_loader.Start( fp_lib_table );
111  }
112 
113  m_progress_timer->Start( 200 );
114  }
115  catch( ... )
116  {
117  // no footprint libraries available
118  }
119 }
120 
121 
122 void FOOTPRINT_SELECT_WIDGET::OnProgressTimer( wxTimerEvent& aEvent )
123 {
124  int prog = m_fp_loader.GetProgress();
125  m_progress_ctrl->SetValue( prog );
126 
127  if( prog == 100 )
128  {
129  wxBusyCursor busy;
130 
131  m_fp_loader.Join();
133  m_progress_timer->Stop();
134 
135  m_book->SetSelection( PAGE_SELECT );
136  m_finished_loading = true;
137 
138  if( m_update )
139  UpdateList();
140  }
141 }
142 
143 
144 void FOOTPRINT_SELECT_WIDGET::OnComboBox( wxCommandEvent& aEvent )
145 {
146  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
147  int sel = m_fp_sel_ctrl->GetSelection();
148 
149  switch( sel )
150  {
151  case wxNOT_FOUND: return;
152 
153  case POS_SEPARATOR:
154  // User somehow managed to select the separator. This should not be
155  // possible, but just in case... deselect it
156  m_fp_sel_ctrl->SetSelection( m_last_item );
157  break;
158 
159  case POS_OTHER:
160  // When POS_OTHER is selected, a dialog should be shown. However, we don't want to
161  // do this ALL the time, as some times (e.g. when moving around with the arrow keys)
162  // it could be very annoying. Therefore showing the picker is done from the custom
163  // "interactive select" event on FOOTPRINT_CHOICE, which only fires for more direct
164  // choice actions.
165  break;
166 
167  default:
168  {
169  wxStringClientData* clientdata =
170  static_cast<wxStringClientData*>( m_fp_sel_ctrl->GetClientObject( sel ) );
171  wxASSERT( clientdata );
172 
173  evt.SetString( clientdata->GetData() );
174  wxPostEvent( this, evt );
175  }
176  }
177 }
178 
179 
180 void FOOTPRINT_SELECT_WIDGET::OnComboInteractive( wxCommandEvent& aEvent )
181 {
182  if( aEvent.GetInt() == POS_OTHER && !m_fp_sel_ctrl->IsPopupShown() )
183  {
184  DoOther();
185  }
186 }
187 
188 
190 {
191  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
192 
193  wxString fpname = ShowPicker();
194  m_other_footprint = fpname;
195  UpdateList();
196  m_fp_sel_ctrl->SetSelection( POS_OTHER );
198 
199  evt.SetString( m_other_footprint );
200  wxPostEvent( this, evt );
201 }
202 
203 
205 {
206  wxString fpname;
207  wxWindow* parent = ::wxGetTopLevelParent( this );
208  DIALOG_SHIM* dsparent = dynamic_cast<DIALOG_SHIM*>( parent );
209 
210  // Only quasimodal dialogs can launch modal kiface dialogs. Otherwise the
211  // event loop goes all silly.
212  wxASSERT( !dsparent || dsparent->IsQuasiModal() );
213 
214  auto frame = m_kiway->Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );
215 
216  if( !frame->ShowModal( &fpname, parent ) )
217  {
218  fpname = wxEmptyString;
219  }
220 
221  frame->Destroy();
222 
223  return fpname;
224 }
225 
226 
228 {
230  m_default_footprint.Clear();
231  m_other_footprint.Clear();
232  m_zero_filter = false;
233 }
234 
235 
237 {
238  m_fp_filter.FilterByPinCount( aPinCount );
239 }
240 
241 
243  wxArrayString const& aFilters, bool aZeroFilters )
244 {
245  if( aZeroFilters && aFilters.size() == 0 )
246  m_zero_filter = true;
247  else
248  m_zero_filter = false;
249 
251 }
252 
253 
255 {
256  m_default_footprint = aFp;
257 }
258 
259 
261 {
262  int n_items = 0;
263 
264  if( !m_fp_list || !m_finished_loading )
265  return false;
266 
267  wxWindowUpdateLocker lock( m_fp_sel_ctrl );
268  m_fp_sel_ctrl->Clear();
269 
270  // Be careful adding items! "Default" must occupy POS_DEFAULT,
271  // "Other" must occupy POS_OTHER, and the separator must occupy POS_SEPARATOR.
272 
273  m_fp_sel_ctrl->Append( m_default_footprint.IsEmpty() ?
274  _( "No default footprint" ) :
275  "[" + _( "Default" ) + "] " + m_default_footprint,
276  new wxStringClientData( m_default_footprint ) );
277 
278  m_fp_sel_ctrl->Append( m_other_footprint.IsEmpty() ?
279  _( "Other..." ) :
280  "[" + _( "Other..." ) + "] " + m_other_footprint,
281  new wxStringClientData( m_other_footprint ) );
282 
283  m_fp_sel_ctrl->Append( "", new wxStringClientData( "" ) );
284 
285  if( !m_zero_filter )
286  {
287  for( auto& fpinfo : m_fp_filter )
288  {
289  wxString display_name( fpinfo.GetNickname() + ":" + fpinfo.GetFootprintName() );
290 
291  m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) );
292  ++n_items;
293 
294  if( n_items >= m_max_items )
295  break;
296  }
297  }
298 
299  SelectDefault();
300  return true;
301 }
302 
303 
305 {
306  m_fp_sel_ctrl->SetSelection( POS_DEFAULT );
307 }
308 
309 
311 {
312  return m_fp_sel_ctrl->Enable( aEnable );
313 }
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.
void FilterByFootprintFilters(wxArrayString const &aFilters)
Set a list of footprint filters to filter by.
FOOTPRINT_ASYNC_LOADER & m_fp_loader
void ClearFilters()
Clear all filter criteria.
void SetDefaultFootprint(wxString const &aFp)
Set the default footprint for a part.
std::unique_ptr< FOOTPRINT_LIST > & m_fp_list
Customized combo box for footprint selection.
This class can be used to populate a FOOTPRINT_LIST asynchronously.
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:60
wxDEFINE_EVENT(EVT_FOOTPRINT_SELECTED, wxCommandEvent)
static std::unique_ptr< FOOTPRINT_LIST > GetInstance(KIWAY &aKiway)
Factory function to return a new FOOTPRINT_LIST via Kiway.
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.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, KIWAY_PLAYER *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:302
void Start(FP_LIB_TABLE *aTable, wxString const *aNickname=nullptr, unsigned aNThreads=DEFAULT_THREADS)
Launch the worker threads.
void OnComboBox(wxCommandEvent &aEvent)
bool IsQuasiModal()
Definition: dialog_shim.h:93
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:257
virtual bool Enable(bool aEnable=true) override
Enable or disable the control for input.
void OnProgressTimer(wxTimerEvent &aEvent)
bool Join()
Wait until the worker threads are finished, and then perform any required single-threaded finishing o...
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
void SelectDefault()
Set current selection to the default footprint.
FOOTPRINT_SELECT_WIDGET(wxWindow *aParent, FOOTPRINT_ASYNC_LOADER &aLoader, std::unique_ptr< FOOTPRINT_LIST > &aFpList, bool aUpdate=true, int aMaxItems=400)
Construct a footprint selector widget.
Implementation of std::make_unique for pre C++14 compilation environments.
int GetProgress() const
Get the current completion percentage.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void Load(KIWAY &aKiway, PROJECT &aProject)
Start loading.
void SetList(FOOTPRINT_LIST *aList)
Assign a FOOTPRINT_LIST to the loader.
std::unique_ptr< wxTimer > m_progress_timer
bool IsSameTable(FP_LIB_TABLE *aOther)
Return true if the given table is the same as the last table loaded.
void FilterByPinCount(int aPinCount)
Filter by pin count.