Hi all, Please find attached the patch for the action plugin menu.
There is a build option to enable/disable this feature: KICAD_SCRIPTING_ACTION_MENU => It's disabled by default Now there is a refresh button. It took new plugins, update existing ... like in footprint wizard dialog. I had remove the example from the patch as asked. Regards, Le 11/01/2017 à 18:58, jp charras a écrit : > Le 11/01/2017 à 17:36, Jean-Samuel Reynaud a écrit : >>>> Pay a particular attention to the fact plugins can be *now* updated (when >>>> the source file has >>>> changed), and therefore menus can also be updated. >>>> the "PCB_EDIT_FRAME::createActionPluginMenus()" method calls Connect, but >>>> Disconnect is never called >>>> by destructors. >>>> It can create issues when updating scripts, because it could be called >>>> more than once. >>> >>> If you need to update the menus when a script file changes, you would >>> have to connect a wxFileWatcherEvent to the appropriate wxMainFrame >>> object to monitor the loaded script file and update the menus >>> accordingly. It can be done but I would proceed with caution here. >>> >> Is it really necessary to add a file watcher ? Once python plugins are >> loaded, python subsystem run the plugin as it was at start time (As I >> understand). >> I had perform a little test for that. If you modify a plugin while >> pcbnew is running, this is always the "old" version that is running. Not >> sure that is true for all OS... > > I am thinking you are talking only about tests on footprint wizards. > > On Windows, the newer is reloaded (as long as you run > onUpdatePythonModulesClick). > This is easy to see if the description string in the footprint plugin is > modified. > >> So menu are not supposed to change even if file change. >> An other point: if I implement that file watching, I should also >> implement a "directory watcher". In case a new plugins is installed >> during pcbnew is running ;) >> Perhaps an "update button": like onUpdatePythonModulesClick for >> footprint plugins ? > > From my experience when debugging a footprint wizard module: > An "update button" is certainly enough: it is mainly for python script > developers when they are > writing and debugging a python script, not for an user who just uses a script. > An automatic update is not useful, and perhaps not good. > > The update button was asked since a long time, and I perfectly understand > this wish. > (The old way was: closing and rerun kicad) > It is intended to reload python modules during their development. > > Remark: onUpdatePythonModulesClick updates all loaded python modules. > Of course only python modules which are newer than the currently loaded are > reloaded. > Therefore onUpdatePythonModulesClick will also update the action plugins. >
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d71af2..52de977 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,10 @@ option( KICAD_SCRIPTING_WXPYTHON "Build wxPython implementation for wx interface building in Python and py.shell (default OFF)." ) +option( KICAD_SCRIPTING_ACTION_MENU + "Build a tools menu with registred python plugins: actions plugins (default OFF)." + ) + option( KICAD_USE_SCH_IO_MANAGER "Build Eeschema with the I/O manager for handling schematic and symbol library I/O. (default OFF)" ) @@ -87,6 +91,12 @@ if ( KICAD_SCRIPTING_MODULES AND NOT KICAD_SCRIPTING ) set ( KICAD_SCRIPTING ON ) endif() +# same with KICAD_SCRIPTING_ACTION_MENUS +if ( KICAD_SCRIPTING_ACTION_MENU AND NOT KICAD_SCRIPTING ) + message(STATUS "Changing KICAD_SCRIPTING to ON as needed by KICAD_SCRIPTING_ACTION_MENU") + set ( KICAD_SCRIPTING ON ) +endif() + option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." ON ) option( KICAD_SPICE "Build Kicad with internal Spice simulator." OFF ) @@ -289,6 +299,10 @@ if( KICAD_SCRIPTING_WXPYTHON ) add_definitions( -DKICAD_SCRIPTING_WXPYTHON ) endif() +if( KICAD_SCRIPTING_ACTION_MENU ) + add_definitions( -DKICAD_SCRIPTING_ACTION_MENU ) +endif() + if( KICAD_SPICE ) add_definitions( -DKICAD_SPICE ) endif() diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 2968614..dc4200e 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -117,6 +117,28 @@ protected: */ void enableGALSpecificMenus(); +#if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU) + /** + * Function initActionPluginMenus + * Fill action menu with all registred action plugins + */ + void initActionPluginMenus(); + + /** + * Function OnActionPlugin + * Launched by the menu when an action is called + * @param aEvent sent by wx + */ + void OnActionPlugin( wxCommandEvent& aEvent); + + /** + * Function OnActionPluginRefresh + * Refresh plugin list (reload Python plugins) + * @param aEvent sent by wx + */ + void OnActionPluginRefresh( wxCommandEvent& aEvent); +#endif + // Has meaning only if DKICAD_SCRIPTING_WXPYTHON option is on /** diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index be46007..f6f7023 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -274,6 +274,7 @@ set( PCBNEW_CLASS_SRCS zones_polygons_test_connections.cpp zones_test_and_combine_areas.cpp class_footprint_wizard.cpp + class_action_plugin.cpp tools/selection_tool.cpp tools/selection_area.cpp @@ -320,6 +321,7 @@ set( PCBNEW_SCRIPTING_PYTHON_HELPERS swig/python_scripting.cpp swig/pcbnew_scripting_helpers.cpp swig/pcbnew_footprint_wizards.cpp + swig/pcbnew_action_plugins.cpp ) if( KICAD_SCRIPTING ) diff --git a/pcbnew/class_action_plugin.cpp b/pcbnew/class_action_plugin.cpp new file mode 100644 index 0000000..4133907 --- /dev/null +++ b/pcbnew/class_action_plugin.cpp @@ -0,0 +1,155 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +/** + * @file class_action_plugin.cpp + * @brief Class ACTION_PLUGIN and ACTION_PLUGINS + */ + +#include "class_action_plugin.h" + + +ACTION_PLUGIN::~ACTION_PLUGIN() +{ +} + + +void ACTION_PLUGIN::register_action() +{ + ACTION_PLUGINS::register_action( this ); +} + + +std::vector<ACTION_PLUGIN*> ACTION_PLUGINS::m_Actions; +std::vector<int> ACTION_PLUGINS::m_ActionsMenu; + + +ACTION_PLUGIN* ACTION_PLUGINS::GetAction( int aIndex ) +{ + return m_Actions[aIndex]; +} + + +ACTION_PLUGIN* ACTION_PLUGINS::GetActionByMenu( int menu ) +{ + int max = GetActionsCount(); + + for( int i = 0; i<max; i++ ) + { + if( m_ActionsMenu[i] == menu ) + return m_Actions[i]; + } + + return NULL; +} + + +void ACTION_PLUGINS::SetActionMenu( int aIndex, int idMenu ) +{ + m_ActionsMenu[aIndex] = idMenu; +} + + +int ACTION_PLUGINS::GetActionMenu( int aIndex ) +{ + return m_ActionsMenu[aIndex]; +} + + +ACTION_PLUGIN* ACTION_PLUGINS::GetAction( wxString aName ) +{ + int max = GetActionsCount(); + + for( int i = 0; i<max; i++ ) + { + ACTION_PLUGIN* action = GetAction( i ); + + wxString name = action->GetName(); + + if( name.Cmp( aName )==0 ) + return action; + } + + return NULL; +} + + +int ACTION_PLUGINS::GetActionsCount() +{ + return m_Actions.size(); +} + + +void ACTION_PLUGINS::register_action( ACTION_PLUGIN* aAction ) +{ + int updatedMenu = 0; + + // Search for this entry do not register twice this action: + for( int ii = 0; ii < GetActionsCount(); ii++ ) + { + if( aAction == GetAction( ii ) ) // Already registered + return; + } + + // Search for a action with the same name, and remove it if found + for( int ii = 0; ii < GetActionsCount(); ii++ ) + { + ACTION_PLUGIN* action = GetAction( ii ); + + if( action->GetName() == aAction->GetName() ) + { + updatedMenu = GetActionMenu( ii ); + m_Actions.erase( m_Actions.begin() + ii ); + m_ActionsMenu.erase( m_ActionsMenu.begin() + ii ); + + delete action; + + break; + } + } + + m_Actions.push_back( aAction ); + m_ActionsMenu.push_back( updatedMenu ); +} + + +bool ACTION_PLUGINS::deregister_object( void* aObject ) +{ + int max = GetActionsCount(); + + for( int i = 0; i<max; i++ ) + { + ACTION_PLUGIN* action = GetAction( i ); + + if( action->GetObject() == aObject ) + { + m_Actions.erase( m_Actions.begin() + i ); + m_ActionsMenu.erase( m_ActionsMenu.begin() + i ); + delete action; + return true; + } + } + + return false; +} diff --git a/pcbnew/class_action_plugin.h b/pcbnew/class_action_plugin.h new file mode 100644 index 0000000..5249e93 --- /dev/null +++ b/pcbnew/class_action_plugin.h @@ -0,0 +1,173 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +/** + * @file class_action_plugin.h + * @brief Class PCBNEW_ACTION_PLUGINS + */ + +#ifndef CLASS_ACTION_PLUGIN_H +#define CLASS_ACTION_PLUGIN_H +#include <vector> +#include <wxPcbStruct.h> + +/** + * Class ACTION_PLUGIN + * This is the parent class from where any action plugin class must + * derive + */ +class ACTION_PLUGIN +{ +public: + ACTION_PLUGIN() {} + virtual ~ACTION_PLUGIN(); + + /** + * Function GetCategoryName + * @return the category name of the action (to be able to group action under the same submenu) + */ + virtual wxString GetCategoryName() = 0; + + /** + * Function GetName + * @return the name of the action + */ + + virtual wxString GetName() = 0; + + /** + * Function GetDescription + * @return a description of the action plugin + */ + virtual wxString GetDescription() = 0; + + /** + * Function GetObject + * This method gets the pointer to the object from where this action constructs + * @return it's a void pointer, as it could be a PyObject or any other + */ + virtual void* GetObject() = 0; + + /** + * Function Run + * This method the the action + */ + virtual void Run() = 0; + + /** + * Function register_action + * It's the standard method of a "ACTION_PLUGIN" to register itself into + * the ACTION_PLUGINS singleton manager + */ + void register_action(); +}; + + +/** + * Class ACTION_PLUGINS + * Mainly static. Storing all plugins informations. + */ +class ACTION_PLUGINS +{ +private: + /** + * ACTION_PLUGIN system wide static list + */ + static std::vector<ACTION_PLUGIN*> m_Actions; + + /** + * system wide static association between Plugin and menu id + */ + static std::vector<int> m_ActionsMenu; + +public: + + /** + * Function register_action + * An action calls this static method when it wants to register itself + * into the system actions + * + * @param aAction is the action plugin to be registered + */ + static void register_action( ACTION_PLUGIN* aAction ); + + /** + * Function deregister_object + * Anyone calls this method to deregister an object which builds a action, + * it will lookup on the vector calling GetObject until find, then removed + * and deleted + * + * @param aObject is the action plugin object to be deregistered + */ + static bool deregister_object( void* aObject ); + + /** + * Function GetAction + * @param aName is the action plugin name + * @return a action object by it's name or NULL if it isn't available. + */ + static ACTION_PLUGIN* GetAction( wxString aName ); + + /** + * Function SetActionMenu + * Associate a menu id to an action plugin + * @param aInded is the action index + * @param idMenu is the associated menuitem id + */ + static void SetActionMenu( int aIndex, int idMenu ); + + + /** + * Function GetActionMenu + * Provide menu id for a plugin index + * @param aIndex is the action index + * @return associated menuitem id + */ + static int GetActionMenu( int aIndex ); + + + /** + * Function GetActionByMenu + * find action plugin associated to a menu id + * @param menu is the menu id (defined with SetActionMenu) + * @return the associated ACTION_PLUGIN (or null if not found) + */ + static ACTION_PLUGIN* GetActionByMenu( int menu ); + + + /** + * Function GetAction + * @return a action object by it's number or NULL if it isn't available. + * @param aIndex is the action index in list + */ + static ACTION_PLUGIN* GetAction( int aIndex ); + + /** + * Function GetActionsCount + * @return the number of actions available into the system + */ + static int GetActionsCount(); +}; + +#endif /* PCBNEW_ACTION_PLUGINS_H */ diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index dbc9ebc..f1fb778 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -642,6 +642,25 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() KiBitmap( py_script_xpm ) ); #endif +#if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU) + wxMenu* submenuActionPluginsMenu = new wxMenu(); + + AddMenuItem( toolsMenu, submenuActionPluginsMenu, ID_TOOLBARH_PCB_ACTION_PLUGIN, + _( "&External plugins" ), + _( "Give access to python action plugin" ), + KiBitmap( hammer_xpm ) ); + + AddMenuItem( submenuActionPluginsMenu, ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, + _( "&Refresh" ), + _( "Reload all python plugins and refresh menu" ), + KiBitmap( reload_xpm ) ); + + submenuActionPluginsMenu->AppendSeparator(); + +#endif + + + wxMenu* designRulesMenu = new wxMenu; AddMenuItem( designRulesMenu, ID_MENU_PCB_SHOW_DESIGN_RULES_DIALOG, diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 35c743e..c38ba75 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -218,6 +218,11 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_TOOL( ID_TOOLBARH_PCB_MODE_TRACKS, PCB_EDIT_FRAME::OnSelectAutoPlaceMode ) EVT_TOOL( ID_TOOLBARH_PCB_FREEROUTE_ACCESS, PCB_EDIT_FRAME::Access_to_External_Tool ) + +#if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU) + EVT_TOOL( ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, PCB_EDIT_FRAME::OnActionPluginRefresh ) +#endif + #if defined( KICAD_SCRIPTING_WXPYTHON ) // has meaning only with KICAD_SCRIPTING_WXPYTHON enabled EVT_TOOL( ID_TOOLBARH_PCB_SCRIPTING_CONSOLE, PCB_EDIT_FRAME::ScriptingConsoleEnableDisable ) @@ -474,6 +479,10 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : enableGALSpecificMenus(); +#if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU) + initActionPluginMenus(); +#endif + // disable Export STEP item if kicad2step does not exist wxString strK2S = Pgm().GetExecutablePath(); #ifdef __WXMAC__ diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index 19614c0..8e98979 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -280,6 +280,9 @@ enum pcbnew_ids ID_TOOLBARH_PCB_FREEROUTE_ACCESS, ID_TOOLBARH_PCB_SCRIPTING_CONSOLE, + ID_TOOLBARH_PCB_ACTION_PLUGIN, + ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, + ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR, ID_PCB_GEN_POS_MODULES_FILE, diff --git a/pcbnew/swig/pcbnew_action_plugins.cpp b/pcbnew/swig/pcbnew_action_plugins.cpp new file mode 100644 index 0000000..5a2a248 --- /dev/null +++ b/pcbnew/swig/pcbnew_action_plugins.cpp @@ -0,0 +1,242 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file pcbnew_action_plugins.cpp + * @brief Class PCBNEW_PYTHON_ACTION_PLUGINS + */ + +#include "pcbnew_action_plugins.h" +#include <python_scripting.h> +#include <stdio.h> +#include <macros.h> +#include <pcbnew_id.h> +#include <menus_helpers.h> +#include <class_drawpanel.h> // m_canvas +#include <class_board.h> +#include <class_module.h> +#include <class_track.h> +#include <board_commit.h> +#include <kicad_device_context.h> + +PYTHON_ACTION_PLUGIN::PYTHON_ACTION_PLUGIN( PyObject* aAction ) +{ + PyLOCK lock; + + this->m_PyAction = aAction; + Py_XINCREF( aAction ); +} + + +PYTHON_ACTION_PLUGIN::~PYTHON_ACTION_PLUGIN() +{ + PyLOCK lock; + + Py_XDECREF( this->m_PyAction ); +} + + +PyObject* PYTHON_ACTION_PLUGIN::CallMethod( const char* aMethod, PyObject* aArglist ) +{ + PyLOCK lock; + + PyErr_Clear(); + // pFunc is a new reference to the desired method + PyObject* pFunc = PyObject_GetAttrString( this->m_PyAction, aMethod ); + + if( pFunc && PyCallable_Check( pFunc ) ) + { + PyObject* result = PyObject_CallObject( pFunc, aArglist ); + + if( PyErr_Occurred() ) + { + wxMessageBox( PyErrStringWithTraceback(), + wxT( "Exception on python action plugin code" ), + wxICON_ERROR | wxOK ); + } + + if( result ) + { + Py_XDECREF( pFunc ); + return result; + } + } + else + { + printf( "method not found, or not callable: %s\n", aMethod ); + } + + if( pFunc ) + { + Py_XDECREF( pFunc ); + } + + return NULL; +} + + +wxString PYTHON_ACTION_PLUGIN::CallRetStrMethod( const char* aMethod, PyObject* aArglist ) +{ + wxString ret; + PyLOCK lock; + + PyObject* result = CallMethod( aMethod, aArglist ); + + if( result ) + { + const char* str_res = PyString_AsString( result ); + ret = FROM_UTF8( str_res ); + Py_DECREF( result ); + } + + return ret; +} + + +wxString PYTHON_ACTION_PLUGIN::GetCategoryName() +{ + PyLOCK lock; + + return CallRetStrMethod( "GetCategoryName" ); +} + + +wxString PYTHON_ACTION_PLUGIN::GetName() +{ + PyLOCK lock; + + return CallRetStrMethod( "GetName" ); +} + + +wxString PYTHON_ACTION_PLUGIN::GetDescription() +{ + PyLOCK lock; + + return CallRetStrMethod( "GetDescription" ); +} + + +void PYTHON_ACTION_PLUGIN::Run() +{ + PyLOCK lock; + + CallMethod( "Run" ); +} + + +void* PYTHON_ACTION_PLUGIN::GetObject() +{ + return (void*) m_PyAction; +} + + +void PYTHON_ACTION_PLUGINS::register_action( PyObject* aPyAction ) +{ + PYTHON_ACTION_PLUGIN* fw = new PYTHON_ACTION_PLUGIN( aPyAction ); + + fw->register_action(); +} + + +void PYTHON_ACTION_PLUGINS::deregister_action( PyObject* aPyAction ) +{ + // deregister also destroyes the previously created "PYTHON_ACTION_PLUGIN object" + ACTION_PLUGINS::deregister_object( (void*) aPyAction ); +} + + +#if defined(KICAD_SCRIPTING) && defined(KICAD_SCRIPTING_ACTION_MENU) + +void PCB_EDIT_FRAME::OnActionPlugin( wxCommandEvent& aEvent ) +{ + int id = aEvent.GetId(); + + ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByMenu( id ); + + if( actionPlugin ) + { + // TODO: Adding recovery point for jobs + // BOARD_COMMIT commit( this ); + // commit.Push( _( "External plugin" ) ); + + actionPlugin->Run(); + + OnModify(); + + if( IsGalCanvasActive() ) + { + UseGalCanvas( GetGalCanvas() ); + } + else + { + GetScreen()->SetModify(); + Refresh(); + } + } +} + + +void PCB_EDIT_FRAME::OnActionPluginRefresh( wxCommandEvent& aEvent ) +{ + char cmd[1024]; + + snprintf( cmd, sizeof(cmd), + "pcbnew.LoadPlugins(\"%s\")", TO_UTF8( PyScriptingPath() ) ); + + PyLOCK lock; + // ReRun the Python method pcbnew.LoadPlugins (already called when starting Pcbnew) + PyRun_SimpleString( cmd ); + + initActionPluginMenus(); +} + + +void PCB_EDIT_FRAME::initActionPluginMenus() +{ + wxMenu* actionMenu = GetMenuBar()->FindItem( ID_TOOLBARH_PCB_ACTION_PLUGIN )->GetSubMenu(); + + for( int i = 0; i < ACTION_PLUGINS::GetActionsCount(); i++ ) + { + // Init menu only for not already created Items + if( ACTION_PLUGINS::GetActionMenu( i ) == 0 ) + { + wxMenuItem* item = AddMenuItem( actionMenu, wxID_ANY, + ACTION_PLUGINS::GetAction( i )->GetName(), + ACTION_PLUGINS::GetAction( i )->GetDescription(), + KiBitmap( hammer_xpm ) ); + + ACTION_PLUGINS::SetActionMenu( i, item->GetId() ); + + Connect( + item->GetId(), wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) & + PCB_EDIT_FRAME::OnActionPlugin ); + } + + // Delete is not handled by plugins system (yet) + } +} + + +#endif diff --git a/pcbnew/swig/pcbnew_action_plugins.h b/pcbnew/swig/pcbnew_action_plugins.h new file mode 100644 index 0000000..da2cbdb --- /dev/null +++ b/pcbnew/swig/pcbnew_action_plugins.h @@ -0,0 +1,62 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file pcbnew_action_plugins.h + * @brief Class PCBNEW_ACTION_PLUGINS + */ + +#ifndef PCBNEW_ACTION_PLUGINS_H +#define PCBNEW_ACTION_PLUGINS_H +#include <Python.h> +#include <vector> +#include <class_action_plugin.h> + + +class PYTHON_ACTION_PLUGIN : public ACTION_PLUGIN +{ + PyObject* m_PyAction; + PyObject* CallMethod( const char* aMethod, + PyObject* aArglist = NULL ); + wxString CallRetStrMethod( const char* aMethod, + PyObject* aArglist = NULL ); + +public: + PYTHON_ACTION_PLUGIN( PyObject* action ); + ~PYTHON_ACTION_PLUGIN(); + wxString GetCategoryName() override; + wxString GetName() override; + wxString GetDescription() override; + void Run() override; + void* GetObject() override; +}; + + +class PYTHON_ACTION_PLUGINS +{ +public: + static void register_action( PyObject* aPyAction ); + static void deregister_action( PyObject* aPyAction ); +}; + +#endif /* PCBNEW_ACTION_PLUGINS_H */ diff --git a/pcbnew/swig/plugins.i b/pcbnew/swig/plugins.i index cff768b..118d407 100644 --- a/pcbnew/swig/plugins.i +++ b/pcbnew/swig/plugins.i @@ -24,6 +24,7 @@ %{ #include <pcbnew_footprint_wizards.h> +#include <pcbnew_action_plugins.h> %} class PYTHON_FOOTPRINT_WIZARDS @@ -33,3 +34,11 @@ public: static void deregister_wizard( PyObject* wizard ); }; + +class PYTHON_ACTION_PLUGINS +{ +public: + static void register_action( PyObject* wizard ); + static void deregister_action( PyObject* wizard ); + +}; diff --git a/scripting/kicadplugins.i b/scripting/kicadplugins.i index 57a3405..a008d04 100644 --- a/scripting/kicadplugins.i +++ b/scripting/kicadplugins.i @@ -208,7 +208,8 @@ class KiCadPlugin: return if isinstance(self,ActionPlugin): - pass # register to action plugins in C++ + PYTHON_ACTION_PLUGINS.register_action(self) + return return @@ -221,7 +222,8 @@ class KiCadPlugin: return if isinstance(self,ActionPlugin): - pass # deregister to action plugins in C++ + PYTHON_ACTION_PLUGINS.deregister_action(self) + return return @@ -560,8 +562,26 @@ class FootprintWizardPlugin(KiCadPlugin, object): return text -class ActionPlugin(KiCadPlugin): - def __init__(self): - KiCadPlugin.__init__(self) +class ActionPlugin(KiCadPlugin, object): + def __init__( self ): + KiCadPlugin.__init__( self ) + self.defaults() + + def defaults( self ): + self.name = "Undefined Action plugin" + self.category = "Undefined" + self.description = "" + + def GetName( self ): + return self.name + + def GetCategoryName( self ): + return self.category + + def GetDescription( self ): + return self.description + + def Run(self): + return }
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp