KiCad PCB EDA Suite
load_select_footprint.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) 2018 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <functional>
27 using namespace std::placeholders;
28 
29 #include <fctsys.h>
30 #include <pcb_draw_panel_gal.h>
31 #include <confirm.h>
32 #include <eda_doc.h>
33 #include <kicad_string.h>
34 #include <pgm_base.h>
35 #include <kiway.h>
36 #include <view/view_controls.h>
37 #include <pcb_edit_frame.h>
38 #include <dialog_helpers.h>
39 #include <filter_reader.h>
40 #include <gr_basic.h>
41 #include <macros.h>
42 #include <fp_lib_table.h>
43 #include <lib_id.h>
44 #include <footprint_tree_pane.h>
45 #include <class_board.h>
46 #include <class_module.h>
47 #include <io_mgr.h>
49 #include <pcbnew.h>
50 #include <footprint_edit_frame.h>
51 #include <footprint_info.h>
52 #include <footprint_info_impl.h>
55 #include <footprint_viewer_frame.h>
58 #include <widgets/lib_tree.h>
59 #include "fp_tree_model_adapter.h"
60 
61 
62 static wxArrayString s_ModuleHistoryList;
63 static unsigned s_ModuleHistoryMaxCount = 8;
64 
65 static void AddModuleToHistory( const wxString& aName )
66 {
67  // Remove duplicates
68  for( int ii = s_ModuleHistoryList.GetCount() - 1; ii >= 0; --ii )
69  {
70  if( s_ModuleHistoryList[ ii ] == aName )
71  s_ModuleHistoryList.RemoveAt( (size_t) ii );
72  }
73 
74  // Add the new name at the beginning of the history list
75  s_ModuleHistoryList.Insert( aName, 0 );
76 
77  // Remove extra names
78  while( s_ModuleHistoryList.GetCount() >= s_ModuleHistoryMaxCount )
79  s_ModuleHistoryList.RemoveAt( s_ModuleHistoryList.GetCount() - 1 );
80 }
81 
82 
83 static void clearModuleItemFlags( BOARD_ITEM* aItem )
84 {
85  aItem->ClearFlags();
86 }
87 
88 #include "pcbnew_id.h"
89 #include <bitmaps.h>
91 {
92  bool is_last_fp_from_brd = IsCurrentFPFromBoard();
93 
94  MODULE* newModule;
96 
97  if( frame == NULL ) // happens if no board editor opened
98  return false;
99 
100  if( aModule == NULL )
101  {
102  if( !frame->GetBoard() || !frame->GetBoard()->GetFirstModule() )
103  return false;
104 
105  aModule = SelectFootprintFromBoard( frame->GetBoard() );
106  }
107 
108  if( aModule == NULL )
109  return false;
110 
111  if( !Clear_Pcb( true ) )
112  return false;
113 
114  newModule = new MODULE( *aModule );
115  newModule->SetParent( GetBoard() );
116  newModule->SetLink( aModule->GetTimeStamp() );
117 
118  newModule->ClearFlags();
119  newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) );
120 
121  AddModuleToBoard( newModule );
122 
123  // Clear references to any net info, because the footprint editor
124  // does know any thing about nets handled by the current edited board.
125  // Morever we do not want to save any reference to an unknown net when
126  // saving the footprint in lib cache
127  // so we force the ORPHANED dummy net info for all pads
128  newModule->ClearAllNets();
129 
130  GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
131  PlaceModule( newModule );
132  newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
133 
134  // Put it on FRONT layer,
135  // because this is the default in ModEdit, and in libs
136  if( newModule->GetLayer() != F_Cu )
137  newModule->Flip( newModule->GetPosition(), frame->Settings().m_FlipLeftRight );
138 
139  // Put it in orientation 0,
140  // because this is the default orientation in ModEdit, and in libs
141  newModule->SetOrientation( 0 );
142 
143  Zoom_Automatique( false );
144 
145  m_adapter->SetPreselectNode( newModule->GetFPID(), 0 );
146 
147  GetScreen()->ClearUndoRedoList();
148  GetScreen()->ClrModify();
149 
150  // Update the save items if needed.
151  if( !is_last_fp_from_brd )
152  {
153  ReCreateMenuBar();
154  ReCreateHToolbar();
155  }
156 
157  Update3DView( true );
158  updateView();
159  GetCanvas()->Refresh();
160  m_treePane->GetLibTree()->RefreshLibTree(); // update any previously-highlighted items
161 
162  return true;
163 }
164 
165 
167 {
168  // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode:
169  FOOTPRINT_VIEWER_FRAME* viewer;
171 
172  if( viewer )
173  {
174  viewer->Destroy();
175  // Destroy() does not immediately delete the viewer, if some events are pending.
176  // (for this reason delete operator cannot be used blindly with "top level" windows)
177  // so gives a slice of time to delete the viewer frame.
178  // This is especially important in OpenGL mode to avoid recreating context before
179  // the old one is deleted
180  wxSafeYield();
181  }
182 
183  SetFocus();
184 
185  // Creates the modal Lib browser:
187 
188  wxString fpid;
189  int ret = viewer->ShowModal( &fpid, this );
190  (void) ret; // make static analyser quiet
191 
192  viewer->Destroy();
193 
194  return fpid;
195 }
196 
197 
199 {
200  FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs();
201  wxString moduleName;
202  LIB_ID fpid;
203  MODULE* module = NULL;
204 
205  static wxString lastComponentName;
206 
207  // Load footprint files:
208  WX_PROGRESS_REPORTER* progressReporter = new WX_PROGRESS_REPORTER( this,
209  _( "Loading Footprint Libraries" ), 3 );
210  GFootprintList.ReadFootprintFiles( fpTable, nullptr, progressReporter );
211  bool cancel = progressReporter->WasCancelled();
212  progressReporter->Destroy();
213 
214  if( cancel )
215  return nullptr;
216 
219 
220  auto adapterPtr( FP_TREE_MODEL_ADAPTER::Create( fpTable ) );
221  auto adapter = static_cast<FP_TREE_MODEL_ADAPTER*>( adapterPtr.get() );
222 
223  std::vector<LIB_TREE_ITEM*> historyInfos;
224 
225  for( auto const& item : s_ModuleHistoryList )
226  {
227  LIB_TREE_ITEM* fp_info = GFootprintList.GetModuleInfo( item );
228 
229  // this can be null, for example, if the footprint has been deleted from a library.
230  if( fp_info != nullptr )
231  historyInfos.push_back( fp_info );
232  }
233 
234  adapter->DoAddLibrary( "-- " + _( "Recently Used" ) + " --", wxEmptyString, historyInfos, true );
235 
236  if( aPreselect.IsValid() )
237  adapter->SetPreselectNode( aPreselect, 0 );
238  else if( historyInfos.size() )
239  adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 );
240 
241  adapter->AddLibraries();
242 
243  wxString title;
244  title.Printf( _( "Choose Footprint (%d items loaded)" ), adapter->GetItemCount() );
245 
246  DIALOG_CHOOSE_FOOTPRINT dialog( this, title, adapterPtr );
247 
248  if( dialog.ShowQuasiModal() == wxID_CANCEL )
249  return NULL;
250 
251  if( dialog.IsExternalBrowserSelected() )
252  {
253  // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e.
254  // <lib_name>/<footprint name> or LIB_ID format "lib_name:fp_name:rev#"
255  moduleName = SelectFootprintFromLibBrowser();
256 
257  if( moduleName.IsEmpty() ) // Cancel command
258  return NULL;
259  else
260  fpid.Parse( moduleName, LIB_ID::ID_PCB );
261  }
262  else
263  {
264  fpid = dialog.GetSelectedLibId();
265 
266  if( !fpid.IsValid() )
267  return NULL;
268  else
269  moduleName = fpid.Format();
270  }
271 
272  try
273  {
274  module = loadFootprint( fpid );
275  }
276  catch( const IO_ERROR& ioe )
277  {
278  wxLogDebug( wxT( "Error loading footprint '%s'.\n\nError: %s" ),
279  fpid.Format().c_str(),
280  ioe.What() );
281  }
282 
283  if( module )
284  {
285  lastComponentName = moduleName;
286  AddModuleToHistory( moduleName );
287  }
288 
289  return module;
290 }
291 
292 
294 {
295  MODULE* module = NULL;
296 
297  try
298  {
299  module = loadFootprint( aFootprintId );
300  }
301  catch( const IO_ERROR& ioe )
302  {
303  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
304  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
305  }
306 
307  return module;
308 }
309 
310 
312 {
313  FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs();
314 
315  wxCHECK_MSG( fptbl, NULL, wxT( "Cannot look up LIB_ID in NULL FP_LIB_TABLE." ) );
316 
317  MODULE *module = nullptr;
318  try
319  {
320  module = fptbl->FootprintLoadWithOptionalNickname( aFootprintId );
321  }
322  catch( const IO_ERROR& ioe )
323  {
324  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
325  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
326  }
327 
328  // If the module is found, clear all net info,
329  // to be sure there is no broken links
330  // to any netinfo list (should be not needed, but it can be edited from
331  // the footprint editor )
332  if( module )
333  module->ClearAllNets();
334 
335  return module;
336 }
337 
338 
340 {
341  static wxString oldName; // Save name of last module selected.
342 
343  wxString fpname;
344  wxString msg;
345  wxArrayString listnames;
346 
347  for( auto module : aPcb->Modules() )
348  listnames.Add( module->GetReference() );
349 
350  msg.Printf( _( "Footprints [%u items]" ), (unsigned) listnames.GetCount() );
351 
352  wxArrayString headers;
353 
354  headers.Add( _( "Footprint" ) );
355 
356  std::vector<wxArrayString> itemsToDisplay;
357 
358  // Conversion from wxArrayString to vector of ArrayString
359  for( unsigned i = 0; i < listnames.GetCount(); i++ )
360  {
361  wxArrayString item;
362 
363  item.Add( listnames[i] );
364  itemsToDisplay.push_back( item );
365  }
366 
367  EDA_LIST_DIALOG dlg( this, msg, headers, itemsToDisplay, wxEmptyString );
368 
369  if( dlg.ShowModal() == wxID_OK )
370  fpname = dlg.GetTextSelection();
371  else
372  return NULL;
373 
374  oldName = fpname;
375 
376  for( auto mod : aPcb->Modules() )
377  {
378  if( fpname == mod->GetReference() )
379  return mod;
380  }
381 
382  return nullptr;
383 }
384 
385 
386 bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
387 {
388  const wxString& curLibPath = aLibraryPath;
389  wxString dstLibPath = CreateNewLibrary();
390 
391  if( !dstLibPath )
392  return false; // user aborted in CreateNewLibrary()
393 
394  wxBusyCursor dummy;
395  wxString msg;
396 
399 
400  try
401  {
402  PLUGIN::RELEASER cur( IO_MGR::PluginFind( curType ) );
403  PLUGIN::RELEASER dst( IO_MGR::PluginFind( dstType ) );
404 
405  wxArrayString footprints;
406 
407  cur->FootprintEnumerate( footprints, curLibPath, false );
408 
409  for( unsigned i = 0; i < footprints.size(); ++i )
410  {
411  const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
412  dst->FootprintSave( dstLibPath, footprint );
413 
414  msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );
415  SetStatusText( msg );
416  }
417  }
418  catch( const IO_ERROR& ioe )
419  {
420  DisplayError( this, ioe.What() );
421  return false;
422  }
423 
424  msg = wxString::Format( _( "Footprint library \"%s\" saved as \"%s\"." ),
425  curLibPath,
426  dstLibPath );
427 
428  DisplayInfoMessage( this, msg );
429 
430  SetStatusText( wxEmptyString );
431  return true;
432 }
433 
434 
435 static MODULE* s_ModuleInitialCopy = NULL; // Copy of module for abort/undo command
436 
437 static PICKED_ITEMS_LIST s_PickedList; // a pick-list to save initial module
438 // and dragged tracks
439 
440 
442 {
443  wxString moduleName;
444  wxArrayString fplist;
445 
446  // Build list of available fp references, to display them in dialog
447  for( auto fp : GetBoard()->Modules() )
448  fplist.Add( fp->GetReference() + wxT(" ( ") + fp->GetValue() + wxT(" )") );
449 
450  fplist.Sort();
451 
452  DIALOG_GET_FOOTPRINT_BY_NAME dlg( this, fplist );
453 
454  if( dlg.ShowModal() != wxID_OK ) //Aborted by user
455  return NULL;
456 
457  moduleName = dlg.GetValue();
458  moduleName.Trim( true );
459  moduleName.Trim( false );
460 
461  if( !moduleName.IsEmpty() )
462  {
463  for( auto mod : GetBoard()->Modules() )
464  {
465  if( mod->GetReference().CmpNoCase( moduleName ) == 0 )
466  return mod;
467  }
468  }
469 
470  return nullptr;
471 }
472 
473 
474 void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, bool aRecreateRatsnest )
475 {
476  if( aModule == 0 )
477  return;
478 
479  OnModify();
480 
481  if( aModule->IsNew() )
482  {
483  SaveCopyInUndoList( aModule, UR_NEW );
484  }
485  else if( aModule->IsMoving() )
486  {
487  ITEM_PICKER picker( aModule, UR_CHANGED );
488  picker.SetLink( s_ModuleInitialCopy );
489  s_PickedList.PushItem( picker );
490  s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy.
491  }
492 
493  if( s_PickedList.GetCount() )
494  {
495  SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
496 
497  // Clear list, but DO NOT delete items, because they are owned by the saved undo
498  // list and they therefore in use
500  }
501 
502  aModule->SetPosition( (wxPoint) GetCanvas()->GetViewControls()->GetCursorPosition() );
503  aModule->ClearFlags();
504 
505  delete s_ModuleInitialCopy;
506  s_ModuleInitialCopy = NULL;
507 
508  if( aRecreateRatsnest )
509  m_Pcb->GetConnectivity()->Update( aModule );
510 
511  if( aRecreateRatsnest )
512  Compile_Ratsnest( true );
513 
514  SetMsgPanel( aModule );
515 }
516 
517 
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:236
wxString SelectFootprintFromLibBrowser()
Function SelectFootprintFromLibBrowser launches the footprint viewer to select the name of a footprin...
static void AddModuleToHistory(const wxString &aName)
bool ShowModal(wxString *aFootprint, wxWindow *aParent) override
Function ShowModal.
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog.
Definition: displlst.cpp:141
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
FOOTPRINT_INFO * GetModuleInfo(const wxString &aFootprintId)
Get info for a module by id.
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
This file is part of the common library.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
VIEW_CONTROLS class definition.
This file is part of the common library.
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
Definition: lib_tree_item.h:39
PROJECT & Prj()
Definition: kicad.cpp:303
static PICKED_ITEMS_LIST s_PickedList
bool IsMoving() const
Definition: base_struct.h:230
Component library viewer main window.
void DisplayErrors(wxTopLevelWindow *aCaller=NULL)
MODULE * SelectFootprintFromLibTree(LIB_ID aPreselect=LIB_ID())
Function SelectFootprintFromLibTree opens a dialog to select a footprint.
class EDA_LIST_DIALOG
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
const LIB_ID & GetFPID() const
Definition: class_module.h:222
Dialog class to select a footprint from the libraries.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
bool IsValid() const
Definition: lib_id.h:171
void SetLink(EDA_ITEM *aItem)
unsigned GetCount() const
Function GetCount.
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath)
Function GuessPluginTypeFromLibPath returns a plugin type given a footprint library's libPath.
Definition: io_mgr.cpp:124
This file contains miscellaneous commonly used macros and functions.
bool IsNew() const
Definition: base_struct.h:228
const char * c_str() const
Definition: utf8.h:107
MODULE * SelectFootprintFromBoard(BOARD *aPcb)
Display the list of modules currently existing on the BOARD.
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:577
DIALOG_GET_FOOTPRINT_BY_NAME is a helper dialog to select a footprint by its reference One can enter ...
FOOTPRINT_LIST_IMPL GFootprintList
The global footprint info table.
Definition: pcbnew.cpp:316
void ClearAllNets()
Function ClearAllNets Clear (i.e.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
static MODULE * s_ModuleInitialCopy
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
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:341
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
MODULES & Modules()
Definition: class_board.h:227
bool SaveLibraryAs(const wxString &aLibraryPath)
Save a library to a new name and/or library type.
void SetLink(timestamp_t aLink)
Definition: class_module.h:546
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:225
PCB_GENERAL_SETTINGS & Settings()
int ShowQuasiModal()
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
MODULE * GetFirstModule() const
Gets the first module in the list (used in footprint viewer/editor) or NULL if none.
Definition: class_board.h:276
Definition of file extensions used in Kicad.
timestamp_t GetTimeStamp() const
Definition: base_struct.h:216
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
Helper dialog and control classes.
bool Load_Module_From_BOARD(MODULE *Module)
Load in Modedit a footprint from the main board.
void SetPosition(const wxPoint &aPos) override
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
#define _(s)
UTF8 Format() const
Definition: lib_id.cpp:237
static unsigned s_ModuleHistoryMaxCount
BOARD * GetBoard()
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
static PTR Create(LIB_TABLE *aLibs)
Factory function: create a model adapter in a reference-counting container.
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
see class PGM_BASE
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
void SetOrientation(double newangle)
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save,...
Definition: io_mgr.cpp:58
size_t i
Definition: json11.cpp:649
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
unsigned GetErrorCount() const
void ClearItemsList()
Function ClearItemsList deletes only the list of pickers, NOT the picked data itself.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
bool ReadFootprintFiles(FP_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the footprints provided by the combination of aTable and aNickname.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:266
static void clearModuleItemFlags(BOARD_ITEM *aItem)
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
MODULE * GetFootprintFromBoardByReference()
Function GetFootprintFromBoardByReference.
Module description (excepted pads)
BOARD * GetBoard() const
void PlaceModule(MODULE *aModule, bool aRecreateRatsnest=true)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
PCB_FILE_T
Enum PCB_FILE_T is a set of file types that the IO_MGR knows about, and for which there has been a pl...
Definition: io_mgr.h:54
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:264
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
const wxPoint GetPosition() const override
Definition: class_module.h:213
MODULE * loadFootprint(const LIB_ID &aFootprintId)
Function loadFootprint attempts to load aFootprintId from the footprint library table.
#define mod(a, n)
Definition: greymap.cpp:24
static wxArrayString s_ModuleHistoryList
KIWAY Kiway