KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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
25#include <pgm_base.h>
27#include <pcbnew_settings.h>
28#include <bitmaps.h>
29#include <board.h>
30#include <board_commit.h>
32#include <footprint.h>
34#include <pcb_track.h>
35#include <zone.h>
36#include <pcbnew_settings.h>
37#include <tool/action_menu.h>
38#include <tool/action_toolbar.h>
39#include <tool/tool_manager.h>
40#include <tools/pcb_actions.h>
42#include <pcb_painter.h>
43#include <wx/msgdlg.h>
44#include <kiplatform/app.h>
45#include "../../scripting/python_scripting.h"
46
48{
49 PyLOCK lock;
50
51 m_PyAction = aAction;
52 Py_XINCREF( aAction );
53}
54
55
57{
58 PyLOCK lock;
59
60 Py_XDECREF( m_PyAction );
61}
62
63
64PyObject* PYTHON_ACTION_PLUGIN::CallMethod( const char* aMethod, PyObject* aArglist )
65{
66 PyLOCK lock;
67
68 PyErr_Clear();
69
70 // pFunc is a new reference to the desired method
71 PyObject* pFunc = PyObject_GetAttrString( m_PyAction, aMethod );
72
73 if( pFunc && PyCallable_Check( pFunc ) )
74 {
75 PyObject* result = PyObject_CallObject( pFunc, aArglist );
76
77 if( !wxTheApp )
79
80 if( PyErr_Occurred() )
81 {
82 wxString message = _HKI( "Exception on python action plugin code" );
83 wxString traceback = PyErrStringWithTraceback();
84
85 std::cerr << message << std::endl << std::endl;
86 std::cerr << traceback << std::endl;
87
88 if( wxTheApp )
89 wxSafeShowMessage( wxGetTranslation( message ), traceback );
90 }
91
92 if( !wxTheApp )
93 {
94 wxArrayString messages;
95 messages.Add( "Fatal error");
96 messages.Add( wxString::Format(
97 "The application handle was destroyed after running Python plugin '%s'.",
98 m_cachedName ) );
99
100 // Poor man's ASCII message box
101 {
102 int maxLen = 0;
103
104 for( const wxString& msg : messages )
105 if( (int)msg.length() > maxLen )
106 maxLen = msg.length();
107
108 wxChar ch = '*';
109 wxString border( ch, 3 );
110
111 std::cerr << wxString( ch, maxLen + 2 + border.length() * 2 ) << std::endl;
112 std::cerr << border << ' ' << wxString( ' ', maxLen ) << ' ' << border << std::endl;
113
114 for( wxString msg : messages )
115 std::cerr << border << ' ' << msg.Pad( maxLen - msg.length() ) << ' ' << border
116 << std::endl;
117
118 std::cerr << border << ' ' << wxString( ' ', maxLen ) << ' ' << border << std::endl;
119 std::cerr << wxString( ch, maxLen + 2 + border.length() * 2 ) << std::endl;
120 }
121
122#ifdef _WIN32
123 std::cerr << std::endl << "Press any key to abort..." << std::endl;
124 (void) std::getchar();
125#endif
126
127 abort();
128 }
129
130 if( result )
131 {
132 Py_XDECREF( pFunc );
133 return result;
134 }
135 }
136 else
137 {
138 wxString msg = wxString::Format( _( "Method '%s' not found, or not callable" ), aMethod );
139 wxMessageBox( msg, _( "Unknown Method" ), wxICON_ERROR | wxOK );
140 }
141
142 if( pFunc )
143 {
144 Py_XDECREF( pFunc );
145 }
146
147 return nullptr;
148}
149
150
151wxString PYTHON_ACTION_PLUGIN::CallRetStrMethod( const char* aMethod, PyObject* aArglist )
152{
153 wxString ret;
154 PyLOCK lock;
155
156 PyObject* result = CallMethod( aMethod, aArglist );
157
158 ret = PyStringToWx( result );
159 Py_XDECREF( result );
160
161 return ret;
162}
163
164
166{
167 PyLOCK lock;
168
169 return CallRetStrMethod( "GetCategoryName" );
170}
171
172
174{
175 PyLOCK lock;
176
177 wxString name = CallRetStrMethod( "GetName" );
179
180 return name;
181}
182
183
185{
186 PyLOCK lock;
187
188 return CallRetStrMethod( "GetDescription" );
189}
190
191
193{
194 PyLOCK lock;
195
196 PyObject* result = CallMethod( "GetShowToolbarButton");
197
198 return PyObject_IsTrue(result);
199}
200
201
203{
204 PyLOCK lock;
205
206 PyObject* arglist = Py_BuildValue( "(i)", static_cast<int>( aDark ) );
207
208 wxString result = CallRetStrMethod( "GetIconFileName", arglist );
209
210 Py_DECREF( arglist );
211
212 return result;
213}
214
215
217{
218 PyLOCK lock;
219
220 return CallRetStrMethod( "GetPluginPath" );
221}
222
223
225{
226 PyLOCK lock;
227
228 CallMethod( "Run" );
229}
230
231
233{
234 return (void*) m_PyAction;
235}
236
237
238void PYTHON_ACTION_PLUGINS::register_action( PyObject* aPyAction )
239{
240 PYTHON_ACTION_PLUGIN* fw = new PYTHON_ACTION_PLUGIN( aPyAction );
241
242 fw->register_action();
243}
244
245
247{
248 // deregister also destroys the previously created "PYTHON_ACTION_PLUGIN object"
249 ACTION_PLUGINS::deregister_object( (void*) aPyAction );
250}
251
252
253void PCB_EDIT_FRAME::OnActionPluginMenu( wxCommandEvent& aEvent )
254{
255 ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByMenu( aEvent.GetId() );
256
257 if( actionPlugin )
258 RunActionPlugin( actionPlugin );
259}
260
261
262void PCB_EDIT_FRAME::OnActionPluginButton( wxCommandEvent& aEvent )
263{
264 ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByButton( aEvent.GetId() );
265
266 if( actionPlugin )
267 RunActionPlugin( actionPlugin );
268}
269
271{
272
273 PICKED_ITEMS_LIST itemsList;
274 BOARD* currentPcb = GetBoard();
275 bool fromEmpty = false;
276
277 // Append tracks:
278 for( PCB_TRACK* item : currentPcb->Tracks() )
279 {
280 ITEM_PICKER picker( nullptr, item, UNDO_REDO::CHANGED );
281 itemsList.PushItem( picker );
282 }
283
284 // Append footprints:
285 for( FOOTPRINT* item : currentPcb->Footprints() )
286 {
287 ITEM_PICKER picker( nullptr, item, UNDO_REDO::CHANGED );
288 itemsList.PushItem( picker );
289 }
290
291 // Append drawings
292 for( BOARD_ITEM* item : currentPcb->Drawings() )
293 {
294 ITEM_PICKER picker( nullptr, item, UNDO_REDO::CHANGED );
295 itemsList.PushItem( picker );
296 }
297
298 // Append zones outlines
299 for( ZONE* zone : currentPcb->Zones() )
300 {
301 ITEM_PICKER picker( nullptr, zone, UNDO_REDO::CHANGED );
302 itemsList.PushItem( picker );
303 }
304
305 if( itemsList.GetCount() > 0 )
306 SaveCopyInUndoList( itemsList, UNDO_REDO::CHANGED );
307 else
308 fromEmpty = true;
309
310 itemsList.ClearItemsList();
311
312 BOARD_COMMIT commit( this );
313
314 // Execute plugin itself...
316 aActionPlugin->Run();
318
319 // Get back the undo buffer to fix some modifications
320 PICKED_ITEMS_LIST* oldBuffer = nullptr;
321
322 if( fromEmpty )
323 {
324 oldBuffer = new PICKED_ITEMS_LIST();
325 }
326 else
327 {
328 oldBuffer = PopCommandFromUndoList();
329 wxASSERT( oldBuffer );
330 }
331
332 // Try do discover what was modified
333 PICKED_ITEMS_LIST deletedItemsList;
334
335 // The list of existing items after running the action script
336 const auto currItemList = currentPcb->GetItemSet();
337
338 // Found deleted items
339 for( unsigned int i = 0; i < oldBuffer->GetCount(); i++ )
340 {
341 BOARD_ITEM* item = (BOARD_ITEM*) oldBuffer->GetPickedItem( i );
342 ITEM_PICKER picker( nullptr, item, UNDO_REDO::DELETED );
343
344 wxASSERT( item );
345
346 if( currItemList.find( item ) == currItemList.end() )
347 {
348 deletedItemsList.PushItem( picker );
349 commit.Removed( item );
350 }
351 }
352
353 // Mark deleted elements in undolist
354
355 for( unsigned int i = 0; i < deletedItemsList.GetCount(); i++ )
356 {
357 oldBuffer->PushItem( deletedItemsList.GetItemWrapper( i ) );
358 }
359
360 // Find new footprints
361 for( FOOTPRINT* item : currentPcb->Footprints() )
362 {
363 if( !oldBuffer->ContainsItem( item ) )
364 {
365 ITEM_PICKER picker( nullptr, item, UNDO_REDO::NEWITEM );
366 oldBuffer->PushItem( picker );
367 commit.Added( item );
368 }
369 }
370
371 for( PCB_TRACK* item : currentPcb->Tracks() )
372 {
373 if( !oldBuffer->ContainsItem( item ) )
374 {
375 ITEM_PICKER picker( nullptr, item, UNDO_REDO::NEWITEM );
376 oldBuffer->PushItem( picker );
377 commit.Added( item );
378 }
379 }
380
381 for( BOARD_ITEM* item : currentPcb->Drawings() )
382 {
383 if( !oldBuffer->ContainsItem( item ) )
384 {
385 ITEM_PICKER picker( nullptr, item, UNDO_REDO::NEWITEM );
386 oldBuffer->PushItem( picker );
387 commit.Added( item );
388 }
389 }
390
391 for( ZONE* zone : currentPcb->Zones() )
392 {
393 if( !oldBuffer->ContainsItem( zone ) )
394 {
395 ITEM_PICKER picker( nullptr, zone, UNDO_REDO::NEWITEM );
396 oldBuffer->PushItem( picker );
397 commit.Added( zone );
398 }
399 }
400
401 if( oldBuffer->GetCount() )
402 {
403 OnModify();
404 PushCommandToUndoList( oldBuffer );
405 }
406 else
407 {
408 delete oldBuffer;
409 }
410
411 // Apply changes, UndoList already handled
412 commit.Push( _( "Apply Action Script" ), SKIP_UNDO | SKIP_SET_DIRTY );
413
415}
416
417
419{
420 // The list of existing items after running the action script
421 const BOARD_ITEM_SET items = GetBoard()->GetItemSet();
422
423 // Sync selection with items selection state
424 SELECTION& selection = GetCurrentSelection();
426 EDA_ITEMS to_add;
427 EDA_ITEMS to_remove;
428
429 for( BOARD_ITEM* item : items )
430 {
431 if( item->IsSelected() && !selection.Contains( item ) )
432 {
433 item->ClearSelected(); // temporarily
434 to_add.push_back( item );
435 }
436 }
437
438 for( EDA_ITEM* item : selection.GetItems() )
439 {
440 if( !item->IsSelected() )
441 to_remove.push_back( static_cast<BOARD_ITEM*>( item ) );
442 }
443
444 if( !to_add.empty() )
445 selTool->AddItemsToSel( &to_add );
446
447 if( !to_remove.empty() )
448 selTool->RemoveItemsFromSel( &to_remove );
449
451
452 PCB_DRAW_PANEL_GAL* canvas = GetCanvas();
453
454 canvas->GetView()->Clear();
455 canvas->GetView()->InitPreview();
457 canvas->DisplayBoard( m_pcb );
458
459 // allow tools to re-add their view items (selection previews, grids, etc.)
460 if( m_toolManager )
462
463 // reload the drawing-sheet
465
466 canvas->SyncLayersVisibility( m_pcb );
467
468 canvas->Refresh();
469}
470
471
473{
474 if( !actionMenu ) // Should not occur.
475 return;
476
477 for( int ii = 0; ii < ACTION_PLUGINS::GetActionsCount(); ii++ )
478 {
479 wxMenuItem* item;
481 const wxBitmap& bitmap = ap->iconBitmap.IsOk() ? ap->iconBitmap :
482 KiBitmap( BITMAPS::puzzle_piece );
483
484 item = KIUI::AddMenuItem( actionMenu, wxID_ANY, ap->GetName(), ap->GetDescription(),
485 bitmap );
486
487 Connect( item->GetId(), wxEVT_COMMAND_MENU_SELECTED,
488 wxCommandEventHandler( PCB_EDIT_FRAME::OnActionPluginMenu ) );
489
490 ACTION_PLUGINS::SetActionMenu( ii, item->GetId() );
491 }
492}
493
494
496{
497 bool need_separator = true;
498 const std::vector<ACTION_PLUGIN*>& orderedPlugins = GetOrderedActionPlugins();
499
500 for( ACTION_PLUGIN* ap : orderedPlugins )
501 {
502 if( GetActionPluginButtonVisible( ap->GetPluginPath(), ap->GetShowToolbarButton() ) )
503 {
504 if( need_separator )
505 {
507 need_separator = false;
508 }
509
510 // Add button
511 wxBitmap bitmap;
512
513 if ( ap->iconBitmap.IsOk() )
514 bitmap = KiScaledBitmap( ap->iconBitmap, this );
515 else
516 bitmap = KiScaledBitmap( BITMAPS::puzzle_piece, this );
517
518 wxAuiToolBarItem* button = m_mainToolBar->AddTool( wxID_ANY, wxEmptyString,
519 bitmap, ap->GetName() );
520
521 Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
522 wxCommandEventHandler( PCB_EDIT_FRAME::OnActionPluginButton ) );
523
524 // Link action plugin to button
525 ACTION_PLUGINS::SetActionButton( ap, button->GetId() );
526 }
527 }
528}
529
530
531std::vector<ACTION_PLUGIN*> PCB_EDIT_FRAME::GetOrderedActionPlugins()
532{
534
535 std::vector<ACTION_PLUGIN*> plugins;
536 std::vector<ACTION_PLUGIN*> orderedPlugins;
537
538 for( int i = 0; i < ACTION_PLUGINS::GetActionsCount(); i++ )
539 plugins.push_back( ACTION_PLUGINS::GetAction( i ) );
540
541 // First add plugins that have entries in settings
542 for( const auto& pair : cfg->m_VisibleActionPlugins )
543 {
544 auto loc = std::find_if( plugins.begin(), plugins.end(),
545 [pair] ( ACTION_PLUGIN* plugin )
546 {
547 return plugin->GetPluginPath() == pair.first;
548 } );
549
550 if( loc != plugins.end() )
551 {
552 orderedPlugins.push_back( *loc );
553 plugins.erase( loc );
554 }
555 }
556
557 // Now append new plugins that have not been configured yet
558 for( auto remaining_plugin : plugins )
559 orderedPlugins.push_back( remaining_plugin );
560
561 return orderedPlugins;
562}
563
564
565bool PCB_EDIT_FRAME::GetActionPluginButtonVisible( const wxString& aPluginPath,
566 bool aPluginDefault )
567{
569
570 for( const auto& entry : cfg->m_VisibleActionPlugins )
571 {
572 if( entry.first == aPluginPath )
573 return entry.second;
574 }
575
576 // Plugin is not in settings, return default.
577 return aPluginDefault;
578}
const char * name
Definition: DXF_plotter.cpp:57
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
wxBitmap KiScaledBitmap(BITMAPS aBitmap, wxWindow *aWindow, int aHeight, bool aQuantized)
Construct a wxBitmap from a memory record, scaling it if device DPI demands it.
Definition: bitmap.cpp:147
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition: board.h:265
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
static bool deregister_object(void *aObject)
Deregister an object which builds a action.
static ACTION_PLUGIN * GetActionByMenu(int aMenu)
Find action plugin associated to a menu ID.
static int GetActionsCount()
static ACTION_PLUGIN * GetAction(const wxString &aName)
static void SetActionButton(ACTION_PLUGIN *aAction, int idButton)
Associate a button id to an action plugin.
static void SetActionMenu(int aIndex, int idMenu)
Associate a menu id to an action plugin.
static void SetActionRunning(bool aRunning)
static ACTION_PLUGIN * GetActionByButton(int aButton)
Find action plugin associated to a button ID.
This is the parent class from where any action plugin class must derive.
Definition: action_plugin.h:39
wxBitmap iconBitmap
void register_action()
It's the standard method of a "ACTION_PLUGIN" to register itself into the ACTION_PLUGINS singleton ma...
virtual wxString GetDescription()=0
virtual wxString GetName()=0
virtual void Run()=0
This method the the action.
void AddScaledSeparator(wxWindow *aWindow)
Add a separator that introduces space on either side to not squash the tools when scaled.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
const VECTOR2I & GetGridOrigin()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:281
const PAGE_INFO & GetPageSettings() const
Definition: board.h:668
const ZONES & Zones() const
Definition: board.h:326
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:180
const FOOTPRINTS & Footprints() const
Definition: board.h:322
const BOARD_ITEM_SET GetItemSet()
Definition: board.cpp:2843
const TRACKS & Tracks() const
Definition: board.h:320
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
const DRAWINGS & Drawings() const
Definition: board.h:324
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:86
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:98
virtual void PushCommandToUndoList(PICKED_ITEMS_LIST *aItem)
Add a command to undo in the undo list.
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
ACTION_TOOLBAR * m_mainToolBar
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
void SetGridOrigin(const VECTOR2D &aGridOrigin)
Set the origin point for the grid.
void Clear()
Remove all items from the view.
Definition: view.cpp:1124
void InitPreview()
Definition: view.cpp:1668
ACTION_PLUGIN_SETTINGS_LIST m_VisibleActionPlugins
void SaveCopyInUndoList(EDA_ITEM *aItemToCopy, UNDO_REDO aTypeCommand) override
Create a new entry in undo list of commands.
Definition: undo_redo.cpp:162
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void DisplayBoard(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr)
Add all items from the current board to the VIEW, so they can be displayed by GAL.
void SyncLayersVisibility(const BOARD *aBoard)
Update "visibility" property of each layer of a given BOARD.
void OnModify() override
Must be called after a board change to set the modified flag.
static std::vector< ACTION_PLUGIN * > GetOrderedActionPlugins()
Return ordered list of plugins in sequence in which they should appear on toolbar or in settings.
void SetPageSettings(const PAGE_INFO &aPageSettings) override
void OnActionPluginButton(wxCommandEvent &aEvent)
Launched by the button when an action is called.
void RunActionPlugin(ACTION_PLUGIN *aActionPlugin)
Execute action plugin's Run() method and updates undo buffer.
void buildActionPluginMenus(ACTION_MENU *aActionMenu)
Fill action menu with all registered action plugins.
void RebuildAndRefresh()
Rebuilds board connectivity, refreshes canvas.
static bool GetActionPluginButtonVisible(const wxString &aPluginPath, bool aPluginDefault)
Return true if button visibility action plugin setting was set to true or it is unset and plugin defa...
SELECTION & GetCurrentSelection() override
Get the current selection from the canvas area.
void OnActionPluginMenu(wxCommandEvent &aEvent)
Launched by the menu when an action is called.
void AddActionPluginTools()
Append action plugin buttons to main toolbar.
The selection tool: currently supports:
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:142
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
ITEM_PICKER GetItemWrapper(unsigned int aIdx) const
bool ContainsItem(const EDA_ITEM *aItem) const
unsigned GetCount() const
void ClearItemsList()
Delete only the list of pickers NOT the picked data itself.
EDA_ITEM * GetPickedItem(unsigned int aIdx) const
static void deregister_action(PyObject *aPyAction)
static void register_action(PyObject *aPyAction)
bool GetShowToolbarButton() override
wxString CallRetStrMethod(const char *aMethod, PyObject *aArglist=nullptr)
PyObject * CallMethod(const char *aMethod, PyObject *aArglist=nullptr)
wxString GetCategoryName() override
wxString GetName() override
wxString GetDescription() override
wxString GetPluginPath() override
PYTHON_ACTION_PLUGIN(PyObject *action)
void Run() override
This method the the action.
wxString GetIconFileName(bool aDark) override
void * GetObject() override
This method gets the pointer to the object from where this action constructs.
int AddItemsToSel(const TOOL_EVENT &aEvent)
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:120
bool Contains(EDA_ITEM *aItem) const
Definition: selection.cpp:84
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:167
@ REDRAW
Full drawing refresh.
Definition: tool_base.h:83
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Reset all tools (i.e.
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
#define _HKI(x)
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:532
bool AttachConsole(bool aTryAlloc)
Tries to attach a console window with stdout, stderr and stdin.
Definition: gtk/app.cpp:51
KICOMMON_API wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
Definition: ui_common.cpp:369
Class PCBNEW_ACTION_PLUGINS.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
#define SKIP_SET_DIRTY
Definition: sch_commit.h:43
#define SKIP_UNDO
Definition: sch_commit.h:41
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587