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_sizer = new wxBoxSizer( wxVERTICAL );
76  m_progress_timer = std::make_unique<wxTimer>( this );
77  m_book = new wxSimplebook( this, wxID_ANY );
78  m_progress_ctrl = new wxGauge( m_book, wxID_ANY, 100 );
79  m_fp_sel_ctrl = new FOOTPRINT_CHOICE( m_book, wxID_ANY );
80 
81  m_book->SetEffect( wxSHOW_EFFECT_BLEND );
82  m_book->AddPage( m_progress_ctrl, "", true );
83  m_book->AddPage( m_fp_sel_ctrl, "", false );
84  m_sizer->Add( m_book, 1, wxEXPAND | wxALL, 5 );
85 
86  SetSizer( m_sizer );
87  Layout();
88  m_sizer->Fit( this );
89 
90  Bind( wxEVT_TIMER, &FOOTPRINT_SELECT_WIDGET::OnProgressTimer, this, m_progress_timer->GetId() );
91  m_fp_sel_ctrl->Bind( wxEVT_COMBOBOX, &FOOTPRINT_SELECT_WIDGET::OnComboBox, this );
92  m_fp_sel_ctrl->Bind(
93  EVT_INTERACTIVE_CHOICE, &FOOTPRINT_SELECT_WIDGET::OnComboInteractive, this );
94 }
95 
96 
97 void FOOTPRINT_SELECT_WIDGET::Load( KIWAY& aKiway, PROJECT& aProject )
98 {
99  m_kiway = &aKiway;
100  auto fp_lib_table = aProject.PcbFootprintLibs( aKiway );
101 
102  if( m_fp_loader.GetProgress() == 0 || !m_fp_loader.IsSameTable( fp_lib_table ) )
103  {
106  m_fp_loader.Start( fp_lib_table );
107  }
108 
109  m_progress_timer->Start( 200 );
110 }
111 
112 
113 void FOOTPRINT_SELECT_WIDGET::OnProgressTimer( wxTimerEvent& aEvent )
114 {
115  int prog = m_fp_loader.GetProgress();
116  m_progress_ctrl->SetValue( prog );
117 
118  if( prog == 100 )
119  {
120  wxBusyCursor busy;
121 
122  m_fp_loader.Join();
124  m_progress_timer->Stop();
125 
126  m_book->SetSelection( PAGE_SELECT );
127  m_finished_loading = true;
128 
129  if( m_update )
130  UpdateList();
131  }
132 }
133 
134 
135 void FOOTPRINT_SELECT_WIDGET::OnComboBox( wxCommandEvent& aEvent )
136 {
137  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
138  int sel = m_fp_sel_ctrl->GetSelection();
139 
140  switch( sel )
141  {
142  case wxNOT_FOUND: return;
143 
144  case POS_SEPARATOR:
145  // User somehow managed to select the separator. This should not be
146  // possible, but just in case... deselect it
147  m_fp_sel_ctrl->SetSelection( m_last_item );
148  break;
149 
150  case POS_OTHER:
151  // When POS_OTHER is selected, a dialog should be shown. However, we don't want to
152  // do this ALL the time, as some times (e.g. when moving around with the arrow keys)
153  // it could be very annoying. Therefore showing the picker is done from the custom
154  // "interactive select" event on FOOTPRINT_CHOICE, which only fires for more direct
155  // choice actions.
156  break;
157 
158  default:
159  {
160  wxStringClientData* clientdata =
161  static_cast<wxStringClientData*>( m_fp_sel_ctrl->GetClientObject( sel ) );
162  wxASSERT( clientdata );
163 
164  evt.SetString( clientdata->GetData() );
165  wxPostEvent( this, evt );
166  }
167  }
168 }
169 
170 
171 void FOOTPRINT_SELECT_WIDGET::OnComboInteractive( wxCommandEvent& aEvent )
172 {
173  if( aEvent.GetInt() == POS_OTHER && !m_fp_sel_ctrl->IsPopupShown() )
174  {
175  DoOther();
176  }
177 }
178 
179 
181 {
182  wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
183 
184  wxString fpname = ShowPicker();
185  m_other_footprint = fpname;
186  UpdateList();
187  m_fp_sel_ctrl->SetSelection( POS_OTHER );
189 
190  evt.SetString( m_other_footprint );
191  wxPostEvent( this, evt );
192 }
193 
194 
196 {
197  wxString fpname;
198  wxWindow* parent = ::wxGetTopLevelParent( this );
199  DIALOG_SHIM* dsparent = dynamic_cast<DIALOG_SHIM*>( parent );
200 
201  // Only quasimodal dialogs can launch modal kiface dialogs. Otherwise the
202  // event loop goes all silly.
203  wxASSERT( !dsparent || dsparent->IsQuasiModal() );
204 
205  auto frame = m_kiway->Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );
206 
207  if( !frame->ShowModal( &fpname, parent ) )
208  {
209  fpname = wxEmptyString;
210  }
211 
212  frame->Destroy();
213 
214  return fpname;
215 }
216 
217 
219 {
221  m_default_footprint.Clear();
222  m_other_footprint.Clear();
223  m_zero_filter = false;
224 }
225 
226 
228 {
229  m_fp_filter.FilterByPinCount( aPinCount );
230 }
231 
232 
234  wxArrayString const& aFilters, bool aZeroFilters )
235 {
236  if( aZeroFilters && aFilters.size() == 0 )
237  m_zero_filter = true;
238  else
239  m_zero_filter = false;
240 
242 }
243 
244 
246 {
247  m_default_footprint = aFp;
248 }
249 
250 
252 {
253  int n_items = 0;
254 
255  if( !m_fp_list || !m_finished_loading )
256  return false;
257 
258  wxWindowUpdateLocker lock( m_fp_sel_ctrl );
259  m_fp_sel_ctrl->Clear();
260 
261  // Be careful adding items! "Default" must occupy POS_DEFAULT,
262  // "Other" must occupy POS_OTHER, and the separator must occupy POS_SEPARATOR.
263 
264  m_fp_sel_ctrl->Append( m_default_footprint.IsEmpty() ?
265  _( "No default footprint" ) :
266  "[" + _( "Default" ) + "] " + m_default_footprint,
267  new wxStringClientData( m_default_footprint ) );
268 
269  m_fp_sel_ctrl->Append( m_other_footprint.IsEmpty() ?
270  _( "Other..." ) :
271  "[" + _( "Other..." ) + "] " + m_other_footprint,
272  new wxStringClientData( m_other_footprint ) );
273 
274  m_fp_sel_ctrl->Append( "", new wxStringClientData( "" ) );
275 
276  if( !m_zero_filter )
277  {
278  for( auto& fpinfo : m_fp_filter )
279  {
280  wxString display_name( fpinfo.GetNickname() + ":" + fpinfo.GetFootprintName() );
281 
282  m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) );
283  ++n_items;
284 
285  if( n_items >= m_max_items )
286  break;
287  }
288  }
289 
290  SelectDefault();
291  return true;
292 }
293 
294 
296 {
297  m_fp_sel_ctrl->SetSelection( POS_DEFAULT );
298 }
299 
300 
302 {
303  return m_fp_sel_ctrl->Enable( aEnable );
304 }
void SetList(FOOTPRINT_LIST &aList)
Set the list to filter.
Class PROJECT holds project specific data.
Definition: project.h:52
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.