KiCad PCB EDA Suite
pcbnew_action_plugins.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
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
29 #include "pcbnew_action_plugins.h"
30 #include <python_scripting.h>
31 #include <stdio.h>
32 #include <macros.h>
33 #include <pcbnew_id.h>
34 #include <menus_helpers.h>
35 #include <class_drawpanel.h> // m_canvas
36 #include <class_board.h>
37 #include <class_module.h>
38 #include <class_track.h>
39 #include <class_drawsegment.h>
40 #include <class_zone.h>
41 #include <board_commit.h>
42 #include <kicad_device_context.h>
43 
45 {
46  PyLOCK lock;
47 
48  this->m_PyAction = aAction;
49  Py_XINCREF( aAction );
50 }
51 
52 
54 {
55  PyLOCK lock;
56 
57  Py_XDECREF( this->m_PyAction );
58 }
59 
60 
61 PyObject* PYTHON_ACTION_PLUGIN::CallMethod( const char* aMethod, PyObject* aArglist )
62 {
63  PyLOCK lock;
64 
65  PyErr_Clear();
66  // pFunc is a new reference to the desired method
67  PyObject* pFunc = PyObject_GetAttrString( this->m_PyAction, aMethod );
68 
69  if( pFunc && PyCallable_Check( pFunc ) )
70  {
71  PyObject* result = PyObject_CallObject( pFunc, aArglist );
72 
73  if( PyErr_Occurred() )
74  {
75  wxMessageBox( PyErrStringWithTraceback(),
76  _( "Exception on python action plugin code" ),
77  wxICON_ERROR | wxOK );
78  }
79 
80  if( result )
81  {
82  Py_XDECREF( pFunc );
83  return result;
84  }
85  }
86  else
87  {
88  wxString msg = wxString::Format( _( "Method \"%s\" not found, or not callable" ), aMethod );
89  wxMessageBox( msg, _( "Unknown Method" ), wxICON_ERROR | wxOK );
90  }
91 
92  if( pFunc )
93  {
94  Py_XDECREF( pFunc );
95  }
96 
97  return NULL;
98 }
99 
100 
101 wxString PYTHON_ACTION_PLUGIN::CallRetStrMethod( const char* aMethod, PyObject* aArglist )
102 {
103  wxString ret;
104  PyLOCK lock;
105 
106  PyObject* result = CallMethod( aMethod, aArglist );
107 
108  ret = PyStringToWx( result );
109  Py_XDECREF( result );
110 
111  return ret;
112 }
113 
114 
116 {
117  PyLOCK lock;
118 
119  return CallRetStrMethod( "GetCategoryName" );
120 }
121 
122 
124 {
125  PyLOCK lock;
126 
127  return CallRetStrMethod( "GetName" );
128 }
129 
130 
132 {
133  PyLOCK lock;
134 
135  return CallRetStrMethod( "GetDescription" );
136 }
137 
138 
140 {
141  PyLOCK lock;
142 
143  PyObject* result = CallMethod( "GetShowToolbarButton");
144 
145  return PyObject_IsTrue(result);
146 }
147 
148 
150 {
151  PyLOCK lock;
152 
153  return CallRetStrMethod( "GetIconFileName" );
154 }
155 
156 
158 {
159  PyLOCK lock;
160 
161  return CallRetStrMethod( "GetPluginPath" );
162 }
163 
164 
166 {
167  PyLOCK lock;
168 
169  CallMethod( "Run" );
170 }
171 
172 
174 {
175  return (void*) m_PyAction;
176 }
177 
178 
179 void PYTHON_ACTION_PLUGINS::register_action( PyObject* aPyAction )
180 {
181  PYTHON_ACTION_PLUGIN* fw = new PYTHON_ACTION_PLUGIN( aPyAction );
182 
183  fw->register_action();
184 }
185 
186 
187 void PYTHON_ACTION_PLUGINS::deregister_action( PyObject* aPyAction )
188 {
189  // deregister also destroys the previously created "PYTHON_ACTION_PLUGIN object"
190  ACTION_PLUGINS::deregister_object( (void*) aPyAction );
191 }
192 
193 
194 #if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU)
195 
196 void PCB_EDIT_FRAME::OnActionPluginMenu( wxCommandEvent& aEvent )
197 {
198  ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByMenu( aEvent.GetId() );
199 
200  if( actionPlugin )
201  RunActionPlugin( actionPlugin );
202 }
203 
204 void PCB_EDIT_FRAME::OnActionPluginButton( wxCommandEvent& aEvent )
205 {
206  ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByButton( aEvent.GetId() );
207 
208  if( actionPlugin )
209  RunActionPlugin( actionPlugin );
210 }
211 
212 void PCB_EDIT_FRAME::RunActionPlugin( ACTION_PLUGIN* aActionPlugin )
213 {
214  PICKED_ITEMS_LIST itemsList;
215  BOARD* currentPcb = GetBoard();
216  bool fromEmpty = false;
217 
218  itemsList.m_Status = UR_CHANGED;
219 
220  OnModify();
221 
222  // Append tracks:
223  for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() )
224  {
225  ITEM_PICKER picker( item, UR_CHANGED );
226  itemsList.PushItem( picker );
227  }
228 
229  // Append modules:
230  for( BOARD_ITEM* item = currentPcb->m_Modules; item != NULL; item = item->Next() )
231  {
232  ITEM_PICKER picker( item, UR_CHANGED );
233  itemsList.PushItem( picker );
234  }
235 
236  // Append drawings
237  for( BOARD_ITEM* item = currentPcb->m_Drawings; item != NULL; item = item->Next() )
238  {
239  ITEM_PICKER picker( item, UR_CHANGED );
240  itemsList.PushItem( picker );
241  }
242 
243  // Append zones outlines
244  for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
245  {
246  ITEM_PICKER picker( (EDA_ITEM*) currentPcb->GetArea(
247  ii ), UR_CHANGED );
248  itemsList.PushItem( picker );
249  }
250 
251  // Append zones segm:
252  for( BOARD_ITEM* item = currentPcb->m_SegZoneDeprecated; item != NULL; item = item->Next() )
253  {
254  ITEM_PICKER picker( item, UR_CHANGED );
255  itemsList.PushItem( picker );
256  }
257 
258  if( itemsList.GetCount() > 0 )
259  SaveCopyInUndoList( itemsList, UR_CHANGED, wxPoint( 0.0, 0.0 ) );
260  else
261  fromEmpty = true;
262 
263  itemsList.ClearItemsList();
264 
265  // Execute plugin itself...
267  aActionPlugin->Run();
269 
270  currentPcb->m_Status_Pcb = 0;
271 
272  // Get back the undo buffer to fix some modifications
273  PICKED_ITEMS_LIST* oldBuffer = NULL;
274 
275  if( fromEmpty )
276  {
277  oldBuffer = new PICKED_ITEMS_LIST();
278  oldBuffer->m_Status = UR_NEW;
279  }
280  else
281  {
282  oldBuffer = GetScreen()->PopCommandFromUndoList();
283  wxASSERT( oldBuffer );
284  }
285 
286  // Try do discover what was modified
287 
288  PICKED_ITEMS_LIST deletedItemsList;
289 
290  // Found deleted modules
291  for( unsigned int i = 0; i < oldBuffer->GetCount(); i++ )
292  {
293  BOARD_ITEM* item = (BOARD_ITEM*) oldBuffer->GetPickedItem( i );
294  ITEM_PICKER picker( item, UR_DELETED );
295 
296  wxASSERT( item );
297 
298  switch( item->Type() )
299  {
300  case PCB_NETINFO_T:
301  case PCB_MARKER_T:
302  case PCB_MODULE_T:
303  case PCB_TRACE_T:
304  case PCB_VIA_T:
305  case PCB_LINE_T:
306  case PCB_TEXT_T:
307  case PCB_DIMENSION_T:
308  case PCB_TARGET_T:
309  case PCB_SEGZONE_T:
310 
311  // If item has a list it's mean that the element is on the board
312  if( item->GetList() == NULL )
313  {
314  deletedItemsList.PushItem( picker );
315  }
316 
317  break;
318 
319  case PCB_ZONE_AREA_T:
320  {
321  bool zoneFound = false;
322 
323  for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
324  zoneFound |= currentPcb->GetArea( ii ) == item;
325 
326  if( !zoneFound )
327  {
328  deletedItemsList.PushItem( picker );
329  }
330 
331  break;
332  }
333 
334  default:
335  wxString msg;
336  msg.Printf( _( "(PCB_EDIT_FRAME::OnActionPlugin) needs work: "
337  "BOARD_ITEM type (%d) not handled" ),
338  item->Type() );
339  wxFAIL_MSG( msg );
340  break;
341  }
342  }
343 
344  // Mark deleted elements in undolist
345  for( unsigned int i = 0; i < deletedItemsList.GetCount(); i++ )
346  {
347  oldBuffer->PushItem( deletedItemsList.GetItemWrapper( i ) );
348  }
349 
350  // Find new modules
351  for( BOARD_ITEM* item = currentPcb->m_Modules; item != NULL; item = item->Next() )
352  {
353  if( !oldBuffer->ContainsItem( item ) )
354  {
355  ITEM_PICKER picker( item, UR_NEW );
356  oldBuffer->PushItem( picker );
357  }
358  }
359 
360  for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() )
361  {
362  if( !oldBuffer->ContainsItem( item ) )
363  {
364  ITEM_PICKER picker( item, UR_NEW );
365  oldBuffer->PushItem( picker );
366  }
367  }
368 
369  for( BOARD_ITEM* item = currentPcb->m_Drawings; item != NULL; item = item->Next() )
370  {
371  if( !oldBuffer->ContainsItem( item ) )
372  {
373  ITEM_PICKER picker( item, UR_NEW );
374  oldBuffer->PushItem( picker );
375  }
376  }
377 
378  for( BOARD_ITEM* item = currentPcb->m_SegZoneDeprecated; item != NULL; item = item->Next() )
379  {
380  if( !oldBuffer->ContainsItem( item ) )
381  {
382  ITEM_PICKER picker( item, UR_NEW );
383  oldBuffer->PushItem( picker );
384  }
385  }
386 
387  for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
388  {
389  if( !oldBuffer->ContainsItem( (EDA_ITEM*) currentPcb->GetArea( ii ) ) )
390  {
391  ITEM_PICKER picker( (EDA_ITEM*) currentPcb->GetArea(
392  ii ), UR_NEW );
393  oldBuffer->PushItem( picker );
394  }
395  }
396 
397 
398  GetScreen()->PushCommandToUndoList( oldBuffer );
399 
400  if( IsGalCanvasActive() )
401  {
402  UseGalCanvas( GetGalCanvas() );
403  }
404  else
405  {
407  GetScreen()->SetModify();
408  Refresh();
409  }
410 }
411 
412 
413 void PCB_EDIT_FRAME::RebuildActionPluginMenus()
414 {
415  wxMenu* actionMenu = GetMenuBar()->FindItem( ID_TOOLBARH_PCB_ACTION_PLUGIN )->GetSubMenu();
416 
417  if( !actionMenu ) // Should not occur.
418  return;
419 
420  // First, remove existing submenus, if they are too many
421  wxMenuItemList list = actionMenu->GetMenuItems();
422  // The first menuitems are the refresh menu and separator. do not count them
423  int act_menu_count = -2;
424 
425  std::vector<wxMenuItem*> available_menus;
426 
427  for( auto iter = list.begin(); iter != list.end(); ++iter, act_menu_count++ )
428  {
429  if( act_menu_count < 0 )
430  continue;
431 
432  wxMenuItem* item = *iter;
433 
434  if( act_menu_count < ACTION_PLUGINS::GetActionsCount() )
435  {
436  available_menus.push_back( item );
437  continue;
438  }
439 
440  // Remove menus which are not usable for our current plugin list
441  Disconnect( item->GetId(), wxEVT_COMMAND_MENU_SELECTED,
442  (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
443  PCB_EDIT_FRAME::OnActionPluginMenu );
444  actionMenu->Delete( item );
445  }
446 
447  for( int ii = 0; ii < ACTION_PLUGINS::GetActionsCount(); ii++ )
448  {
449  wxMenuItem* item;
451  const wxBitmap& bitmap = ap->iconBitmap.IsOk() ? ap->iconBitmap : KiBitmap( hammer_xpm );
452 
453  if( ii < (int) available_menus.size() )
454  {
455  item = available_menus[ii];
456  item->SetItemLabel( ap->GetName() );
457  item->SetHelp( ap->GetDescription() );
458 
459  // On windows we need to set "unchecked" bitmap
460 #if defined(__WXMSW__)
461  item->SetBitmap( bitmap, false );
462 #else
463  item->SetBitmap( bitmap );
464 #endif
465  }
466  else
467  {
468  item = AddMenuItem( actionMenu, wxID_ANY,
469  ap->GetName(),
470  ap->GetDescription(),
471  bitmap );
472 
473  Connect( item->GetId(), wxEVT_COMMAND_MENU_SELECTED,
474  (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
475  PCB_EDIT_FRAME::OnActionPluginMenu );
476  }
477 
478  ACTION_PLUGINS::SetActionMenu( ii, item->GetId() );
479  }
480 }
481 
482 
483 void PCB_EDIT_FRAME::AddActionPluginTools()
484 {
485  bool need_separator = true;
486  const auto& orderedPlugins = GetOrderedActionPlugins();
487 
488  for( const auto& ap : orderedPlugins )
489  {
490  if( GetActionPluginButtonVisible( ap->GetPluginPath(), ap->GetShowToolbarButton() ) )
491  {
492 
493  if ( need_separator )
494  {
495  KiScaledSeparator( m_mainToolBar, this );
496  need_separator = false;
497  }
498 
499  // Add button
500  wxBitmap bitmap;
501 
502  if ( ap->iconBitmap.IsOk() )
503  bitmap = KiScaledBitmap( ap->iconBitmap, this );
504  else
505  bitmap = KiScaledBitmap( hammer_xpm, this );
506 
507  wxAuiToolBarItem* button = m_mainToolBar->AddTool(
508  wxID_ANY, wxEmptyString, bitmap, ap->GetName() );
509 
510  Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
511  (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
512  PCB_EDIT_FRAME::OnActionPluginButton );
513 
514  // Link action plugin to button
515  ACTION_PLUGINS::SetActionButton( ap, button->GetId() );
516  }
517  }
518 }
519 
520 
521 void PCB_EDIT_FRAME::SetActionPluginSettings( const std::vector< std::pair<wxString, wxString> >& aPluginSettings )
522 {
523  m_configSettings.m_pluginSettings = aPluginSettings;
524 }
525 
526 
527 std::vector< std::pair<wxString, wxString> > PCB_EDIT_FRAME::GetActionPluginSettings()
528 {
529  return m_configSettings.m_pluginSettings;
530 }
531 
532 
533 std::vector<ACTION_PLUGIN*> PCB_EDIT_FRAME::GetOrderedActionPlugins()
534 {
535  std::vector<ACTION_PLUGIN*> orderedPlugins;
536  const auto& pluginSettings = GetActionPluginSettings();
537 
538  // First add plugins that have entries in settings
539  for( size_t ii = 0; ii < pluginSettings.size(); ii++ )
540  {
541  for( int jj = 0; jj < ACTION_PLUGINS::GetActionsCount(); jj++ )
542  {
543  if( ACTION_PLUGINS::GetAction( jj )->GetPluginPath() == pluginSettings[ii].first )
544  orderedPlugins.push_back( ACTION_PLUGINS::GetAction( jj ) );
545  }
546  }
547 
548  // Now append new plugins that have not been configured yet
549  for( int ii = 0; ii < ACTION_PLUGINS::GetActionsCount(); ii++ )
550  {
551  bool found = false;
552 
553  for( size_t jj = 0; jj < orderedPlugins.size(); jj++ )
554  {
555  if( ACTION_PLUGINS::GetAction( ii ) == orderedPlugins[jj] )
556  found = true;
557  }
558 
559  if ( !found )
560  orderedPlugins.push_back( ACTION_PLUGINS::GetAction( ii ) );
561  }
562 
563  return orderedPlugins;
564 }
565 
566 
567 bool PCB_EDIT_FRAME::GetActionPluginButtonVisible( const wxString& aPluginPath, bool aPluginDefault )
568 {
569  auto& settings = m_configSettings.m_pluginSettings;
570 
571  for(const auto& entry : settings )
572  {
573  if (entry.first == aPluginPath )
574  return entry.second == wxT( "Visible" );
575  }
576 
577  // Plugin is not in settings, return default.
578  return aPluginDefault;
579 }
580 
581 
582 #endif
virtual wxString GetName()=0
Function GetName.
void UpdateUserInterface()
Update the layer manager and other widgets from the board setup (layer and items visibility, colors ...) (note: it is automatically called by action plugins, after running the plugin, so call this function is usually not needed inside action plugins.
DHEAD * GetList() const
Definition: base_struct.h:212
wxString PyStringToWx(PyObject *aString)
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
Class ACTION_PLUGIN This is the parent class from where any action plugin class must derive...
Definition: action_plugin.h:40
wxString GetName() override
Function GetName.
wxString CallRetStrMethod(const char *aMethod, PyObject *aArglist=NULL)
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:223
Class BOARD to handle a board.
virtual wxString GetDescription()=0
Function GetDescription.
wxBitmap iconBitmap
Definition: action_plugin.h:50
MODULE * Next() const
Definition: class_module.h:123
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:102
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
Classes to handle copper zones.
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
void register_action()
Function register_action It&#39;s the standard method of a "ACTION_PLUGIN" to register itself into the AC...
wxBitmap KiScaledBitmap(BITMAP_DEF aBitmap, EDA_BASE_FRAME *aWindow)
Construct a wxBitmap from a memory record, scaling it if device DPI demands it.
Definition: bitmap.cpp:116
Functions relatives to tracks, vias and segments used to fill zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
This file contains miscellaneous commonly used macros and functions.
SEGZONE * Next() const
Definition: class_track.h:363
virtual wxString GetPluginPath()=0
Function GetPluginPath.
BOARD_ITEM * Next() const
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
bool ContainsItem(const EDA_ITEM *aItem) const
Function IsItemInList.
class MODULE, a footprint
Definition: typeinfo.h:89
static void deregister_action(PyObject *aPyAction)
void * GetObject() override
Function GetObject This method gets the pointer to the object from where this action constructs...
a helper to handle the real device context used in KiCad
wxString GetDescription() override
Function GetDescription.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
virtual void Run()=0
Function Run This method the the action.
static ACTION_PLUGIN * GetActionByMenu(int aMenu)
Function GetActionByMenu find action plugin associated to a menu id.
wxString GetPluginPath() override
Function GetPluginPath.
DLIST< SEGZONE > m_SegZoneDeprecated
Definition: class_board.h:250
void Run() override
Function Run This method the the action.
static int GetActionsCount()
Function GetActionsCount.
DLIST< BOARD_ITEM > m_Drawings
Definition: class_board.h:244
PYTHON_ACTION_PLUGIN(PyObject *action)
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:1020
wxString GetIconFileName() override
Function GetIconFileName.
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
bool GetShowToolbarButton() override
Function GetShowToolbarButton.
PyObject * CallMethod(const char *aMethod, PyObject *aArglist=NULL)
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:100
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:101
unsigned GetCount() const
Function GetCount.
BOARD * GetBoard()
static void SetActionButton(ACTION_PLUGIN *aAction, int idButton)
Function SetActionButton Associate a button id to an action plugin.
static ACTION_PLUGIN * GetAction(const wxString &aName)
Function GetAction.
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:99
TRACK * Next() const
Definition: class_track.h:99
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:991
Class to handle a graphic segment.
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
EDA_ITEM * GetPickedItem(unsigned int aIdx) const
Function GetPickedItem.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
static void SetActionMenu(int aIndex, int idMenu)
Function SetActionMenu Associate a menu id to an action plugin.
DLIST< MODULE > m_Modules
Definition: class_board.h:248
Class PCBNEW_ACTION_PLUGINS.
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:104
size_t i
Definition: json11.cpp:597
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:154
wxString PyErrStringWithTraceback()
void ClearItemsList()
Function ClearItemsList deletes only the list of pickers, NOT the picked data itself.
void KiScaledSeparator(wxAuiToolBar *aToolbar, EDA_BASE_FRAME *aWindow)
Add a separator to the given toolbar scaled the same way as KiScaledBitmap.
Definition: bitmap.cpp:167
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DLIST< TRACK > m_Track
Definition: class_board.h:249
Module description (excepted pads)
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
static void register_action(PyObject *aPyAction)
class SEGZONE, a segment used to fill a zone area (segment on a
Definition: typeinfo.h:97
ITEM_PICKER GetItemWrapper(unsigned int aIdx) const
Function GetItemWrapper.
static bool deregister_object(void *aObject)
Function deregister_object Anyone calls this method to deregister an object which builds a action...
static ACTION_PLUGIN * GetActionByButton(int aButton)
Function GetActionByButton find action plugin associated to a button id.
static void SetActionRunning(bool aRunning)
Function SetActionRunning.
wxString GetCategoryName() override
Function GetCategoryName.
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:240