diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 7fabf84ea3..c1e8c8a494 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -483,6 +483,7 @@ target_link_libraries( common kimath kiplatform gal + scripting pybind11::embed ${Boost_LIBRARIES} ${CURL_LIBRARIES} diff --git a/common/pgm_base.cpp b/common/pgm_base.cpp index eccf6ef277..33d4cf0839 100644 --- a/common/pgm_base.cpp +++ b/common/pgm_base.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -204,7 +205,6 @@ const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEdit bool PGM_BASE::InitPgm( bool aHeadless ) { - printf("InitPgm()\n"); wxFileName pgm_name( App().argv[0] ); wxInitAllImageHandlers(); @@ -286,6 +286,8 @@ bool PGM_BASE::InitPgm( bool aHeadless ) ReadPdfBrowserInfos(); // needs GetCommonSettings() + m_python_scripting = std::make_unique(); + #ifdef __WXMAC__ // Always show filters on Open dialog to be able to choose plugin wxSystemOptions::SetOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1 ); diff --git a/include/pgm_base.h b/include/pgm_base.h index e016d5c627..2a09c69021 100644 --- a/include/pgm_base.h +++ b/include/pgm_base.h @@ -47,6 +47,7 @@ class wxWindow; class COMMON_SETTINGS; class SETTINGS_MANAGER; +class SCRIPTING; /** * A small class to handle the list of existing translations. @@ -305,6 +306,8 @@ protected: std::unique_ptr m_settings_manager; + std::unique_ptr m_python_scripting; + /// prevents multiple instances of a program from being run at the same time. wxSingleInstanceChecker* m_pgm_checker; diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 249bdb7b16..b319a31caa 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -370,6 +370,7 @@ set( PCBNEW_SCRIPTING_PYTHON_HELPERS swig/pcbnew_footprint_wizards.cpp swig/pcbnew_scripting_helpers.cpp swig/pcbnew_scripting.cpp + swig/pcb_scripting_tool.cpp ) diff --git a/pcbnew/dialogs/panel_pcbnew_action_plugins.cpp b/pcbnew/dialogs/panel_pcbnew_action_plugins.cpp index 16b30de9fd..e2b34344f9 100644 --- a/pcbnew/dialogs/panel_pcbnew_action_plugins.cpp +++ b/pcbnew/dialogs/panel_pcbnew_action_plugins.cpp @@ -18,19 +18,20 @@ * with this program. If not, see . */ -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include -#include - +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #define GRID_CELL_MARGIN 4 @@ -138,7 +139,7 @@ void PANEL_PCBNEW_ACTION_PLUGINS::SwapRows( int aRowA, int aRowB ) void PANEL_PCBNEW_ACTION_PLUGINS::OnReloadButtonClick( wxCommandEvent& event ) { - m_frame->PythonPluginsReload(); + m_frame->GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload, true ); TransferDataToWindow(); } @@ -231,7 +232,7 @@ bool PANEL_PCBNEW_ACTION_PLUGINS::TransferDataToWindow() void PANEL_PCBNEW_ACTION_PLUGINS::OnOpenDirectoryButtonClick( wxCommandEvent& event ) { - m_frame->PythonPluginsShowFolder(); + m_frame->GetToolManager()->RunAction( PCB_ACTIONS::pluginsShowFolder ); } void PANEL_PCBNEW_ACTION_PLUGINS::OnShowErrorsButtonClick( wxCommandEvent& event ) diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 6b69b77e6e..3985d53449 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -31,6 +31,7 @@ #include "tools/placement_tool.h" #include "tools/pcb_point_editor.h" #include "tools/pcb_selection_tool.h" +#include #include <3d_viewer/eda_3d_viewer.h> #include #include @@ -943,6 +944,7 @@ void FOOTPRINT_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS ); m_toolManager->RegisterTool( new GROUP_TOOL ); m_toolManager->RegisterTool( new CONVERT_TOOL ); + m_toolManager->RegisterTool( new SCRIPTING_TOOL ); m_toolManager->GetTool()->SetIsFootprintEditor( true ); m_toolManager->GetTool()->SetIsFootprintEditor( true ); @@ -953,6 +955,7 @@ void FOOTPRINT_EDIT_FRAME::setupTools() m_toolManager->GetTool()->SetIsFootprintEditor( true ); m_toolManager->GetTool()->SetIsFootprintEditor( true ); m_toolManager->GetTool()->SetIsFootprintEditor( true ); + m_toolManager->GetTool()->SetIsFootprintEditor( true ); m_toolManager->GetTool()->SetFootprintFrame( true ); m_toolManager->InitTools(); diff --git a/pcbnew/footprint_wizard_frame.cpp b/pcbnew/footprint_wizard_frame.cpp index be6298a71b..b180909737 100644 --- a/pcbnew/footprint_wizard_frame.cpp +++ b/pcbnew/footprint_wizard_frame.cpp @@ -647,7 +647,7 @@ void FOOTPRINT_WIZARD_FRAME::PythonPluginsReload() auto brd_frame = static_cast( Kiway().Player( FRAME_PCB_EDITOR, false ) ); if( brd_frame ) - brd_frame->PythonPluginsReload(); + brd_frame->GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload ); else - PythonPluginsReloadBase(); + GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload ); } diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index 90d3c1550e..600ac561c8 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -413,21 +413,9 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() submenuActionPlugins->SetTitle( _( "External Plugins" ) ); submenuActionPlugins->SetIcon( BITMAPS::puzzle_piece ); - submenuActionPlugins->Add( _( "Refresh Plugins" ), - _( "Reload all python plugins and refresh plugin menus" ), - ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, - BITMAPS::reload ); -#ifdef __APPLE__ - submenuActionPlugins->Add( _( "Reveal Plugin Folder in Finder" ), - _( "Reveals the plugins folder in a Finder window" ), - ID_TOOLBARH_PCB_ACTION_PLUGIN_SHOW_FOLDER, - BITMAPS::directory_open ); -#else - submenuActionPlugins->Add( _( "Open Plugin Directory" ), - _( "Opens the directory in the default system file manager" ), - ID_TOOLBARH_PCB_ACTION_PLUGIN_SHOW_FOLDER, - BITMAPS::directory_open ); -#endif + submenuActionPlugins->Add( PCB_ACTIONS::pluginsReload ); + submenuActionPlugins->Add( PCB_ACTIONS::pluginsShowFolder ); + // Populate the Action Plugin sub-menu: Must be done before Add // Since the object is cloned by Add submenuActionPlugins->AppendSeparator(); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 4fbe479064..3f6bf3c00e 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -147,9 +148,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_CHOICE( ID_AUX_TOOLBAR_PCB_TRACK_WIDTH, PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event ) EVT_CHOICE( ID_AUX_TOOLBAR_PCB_VIA_SIZE, PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event ) - EVT_TOOL( ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, PCB_EDIT_FRAME::OnActionPluginRefresh ) - EVT_TOOL( ID_TOOLBARH_PCB_ACTION_PLUGIN_SHOW_FOLDER, PCB_EDIT_FRAME::OnActionPluginShowFolder ) - // Tracks and vias sizes general options EVT_MENU_RANGE( ID_POPUP_PCB_SELECT_WIDTH_START_RANGE, ID_POPUP_PCB_SELECT_WIDTH_END_RANGE, PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event ) @@ -496,6 +494,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS ); m_toolManager->RegisterTool( new CONVERT_TOOL ); m_toolManager->RegisterTool( new GROUP_TOOL ); + m_toolManager->RegisterTool( new SCRIPTING_TOOL ); m_toolManager->InitTools(); // Run the selection tool, it is supposed to be always active @@ -1498,43 +1497,6 @@ void PCB_EDIT_FRAME::RunEeschema() } -void PCB_EDIT_FRAME::PythonPluginsReload() -{ - // Reload Python plugins if they are newer than the already loaded, and load new plugins - // Remove all action plugins so that we don't keep references to old versions - ACTION_PLUGINS::UnloadAll(); - - // Reload plugin list: reload Python plugins if they are newer than the already loaded, - // and load new plugins - PythonPluginsReloadBase(); - - // Action plugins can be modified, therefore the plugins menu must be updated: - ReCreateMenuBar(); - // Recreate top toolbar to add action plugin buttons - ReCreateHToolbar(); -} - - -void PCB_EDIT_FRAME::PythonPluginsShowFolder() -{ -#ifdef __WXMAC__ - wxString msg; - - // Quote in case there are spaces in the path. - msg.Printf( "open \"%s\"", PyPluginsPath( true ) ); - - system( msg.c_str() ); -#else - wxString pypath( PyPluginsPath( true ) ); - - // Quote in case there are spaces in the path. - AddDelimiterString( pypath ); - - wxLaunchDefaultApplication( pypath ); -#endif -} - - void PCB_EDIT_FRAME::PythonSyncEnvironmentVariables() { const ENV_VAR_MAP& vars = Pgm().GetLocalEnvVariables(); diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 94659c72b2..4ba8351ae6 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -93,12 +93,6 @@ public: */ bool IsContentModified() const override; - /** - * Reload the Python plugins if they are newer than the already loaded, and load new - * plugins if any. - */ - void PythonPluginsReload(); - /** * Open the plugins folder in the default system file browser. */ diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index a3a78598c6..c7275c051a 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -216,26 +216,6 @@ PGM_BASE* PgmOrNull() } #endif - -void PythonPluginsReloadBase() -{ - // Reload plugin list: reload Python plugins if they are newer than the already loaded, - // and load new plugins - char cmd[1024]; - - snprintf( cmd, sizeof( cmd ), "pcbnew.LoadPlugins(\"%s\", \"%s\")", TO_UTF8( PyScriptingPath() ), - TO_UTF8( PyScriptingPath( true ) ) ); - - PyLOCK lock; - - // ReRun the Python method pcbnew.LoadPlugins (already called when starting Pcbnew) - int retv = PyRun_SimpleString( cmd ); - - if( retv != 0 ) - wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd ); -} - - /// The global footprint library table. This is not dynamically allocated because /// in a multiple project environment we must keep its address constant (since it is /// the fallback table for multiple projects). diff --git a/pcbnew/pcbnew.h b/pcbnew/pcbnew.h index c0eefa7adf..be4d9e1346 100644 --- a/pcbnew/pcbnew.h +++ b/pcbnew/pcbnew.h @@ -33,14 +33,4 @@ #define TEXTS_MAX_WIDTH Mils2iu( 10000 ) ///< Maximum text width in internal units (10 inches) -/** - * Helper function PythonPluginsReloadBase - * Reload Python plugins if they are newer than - * the already loaded, and load new plugins if any - * It calls the LoadPlugins(bundlepath) Python method - * see kicadplugins.i - */ -void PythonPluginsReloadBase(); - - #endif // PCBNEW_H diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index c1846d69fb..492b945055 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -88,8 +88,6 @@ enum pcbnew_ids ID_GEN_EXPORT_FILE_GENCADFORMAT, ID_TOOLBARH_PCB_ACTION_PLUGIN, - ID_TOOLBARH_PCB_ACTION_PLUGIN_REFRESH, - ID_TOOLBARH_PCB_ACTION_PLUGIN_SHOW_FOLDER, ID_PCB_GEN_CMP_FILE, ID_PCB_GEN_BOM_FILE_FROM_BOARD, diff --git a/pcbnew/swig/pcb_scripting_tool.cpp b/pcbnew/swig/pcb_scripting_tool.cpp new file mode 100644 index 0000000000..d026ef8e75 --- /dev/null +++ b/pcbnew/swig/pcb_scripting_tool.cpp @@ -0,0 +1,155 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 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 3 + * 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/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "pcb_scripting_tool.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using initfunc = PyObject* (*)(void); + +SCRIPTING_TOOL::SCRIPTING_TOOL() : + PCB_TOOL_BASE( "pcbnew.ScriptingTool" ) +{} + + +SCRIPTING_TOOL::~SCRIPTING_TOOL() +{} + + +void SCRIPTING_TOOL::Reset( RESET_REASON aReason ) +{ +} + + +bool SCRIPTING_TOOL::Init() +{ + PyLOCK lock; + PyObject* mod_name = PyUnicode_FromString( "_pcbnew" ); + + if( PyObject* existing_mod = PyImport_GetModule( mod_name ) ) + { + Py_DecRef( existing_mod ); + } + else + { + KIFACE* kiface = frame()->Kiway().KiFACE( KIWAY::FACE_PCB ); + initfunc pcbnew_init = reinterpret_cast( kiface->IfaceOrAddress( KIFACE_SCRIPTING_LEGACY ) ); + PyImport_AddModule( "_pcbnew" ); + PyObject* mod = pcbnew_init(); + PyObject* sys_mod = PyImport_GetModuleDict(); + PyDict_SetItemString( sys_mod, "_pcbnew", mod ); + Py_DECREF( mod ); + } + + Py_DecRef( mod_name ); + + // Load pcbnew inside Python and load all the user plugins and package-based plugins + { + using namespace pybind11::literals; + + auto locals = pybind11::dict( "sys_path"_a = TO_UTF8( SCRIPTING::PyScriptingPath( false ) ), + "user_path"_a = TO_UTF8( SCRIPTING::PyScriptingPath( true ) ) ); + + pybind11::exec( R"( +import sys +import pcbnew +pcbnew.LoadPlugins( sys_path, user_path ) + )", pybind11::globals(), locals ); + + } + + return true; +} + + +int SCRIPTING_TOOL::reloadPlugins( const TOOL_EVENT& aEvent ) +{ + if( !m_isFootprintEditor ) + // Reload Python plugins if they are newer than the already loaded, and load new plugins + // Remove all action plugins so that we don't keep references to old versions + ACTION_PLUGINS::UnloadAll(); + + { + PyLOCK lock; + + using namespace pybind11::literals; + auto locals = pybind11::dict( "sys_path"_a = SCRIPTING::PyScriptingPath( false ), + "user_path"_a = SCRIPTING::PyScriptingPath( true ) ); + + pybind11::exec( R"( +import sys +import pcbnew +pcbnew.LoadPlugins( sys_path, user_path ) + )", pybind11::globals(), locals ); + } + + if( !m_isFootprintEditor ) + { + // Action plugins can be modified, therefore the plugins menu must be updated: + frame()->ReCreateMenuBar(); + // Recreate top toolbar to add action plugin buttons + frame()->ReCreateHToolbar(); + } + + return 0; +} + + +int SCRIPTING_TOOL::showPluginFolder( const TOOL_EVENT& aEvent ) +{ +#ifdef __WXMAC__ + wxString msg; + + // Quote in case there are spaces in the path. + msg.Printf( "open \"%s\"", SCRIPTING::PyPluginsPath( true ) ); + + system( msg.c_str() ); +#else + wxString pypath( SCRIPTING::PyPluginsPath( true ) ); + + // Quote in case there are spaces in the path. + AddDelimiterString( pypath ); + + wxLaunchDefaultApplication( pypath ); +#endif + + return 0; +} + + +void SCRIPTING_TOOL::setTransitions() +{ + + Go( &SCRIPTING_TOOL::reloadPlugins, PCB_ACTIONS::pluginsReload.MakeEvent() ); + Go( &SCRIPTING_TOOL::showPluginFolder, PCB_ACTIONS::pluginsShowFolder.MakeEvent() ); +} diff --git a/pcbnew/swig/pcb_scripting_tool.h b/pcbnew/swig/pcb_scripting_tool.h new file mode 100644 index 0000000000..a0d1775f51 --- /dev/null +++ b/pcbnew/swig/pcb_scripting_tool.h @@ -0,0 +1,61 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 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 3 + * 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/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCBNEW_PCB_SCRIPTING_TOOL_H_ +#define PCBNEW_PCB_SCRIPTING_TOOL_H_ + + +#include + +class ACTION_MENU; + +/** + * Tool relating to pads and pad settings. + */ +class SCRIPTING_TOOL : public PCB_TOOL_BASE +{ +public: + SCRIPTING_TOOL(); + ~SCRIPTING_TOOL(); + + ///< React to model/view changes + void Reset( RESET_REASON aReason ) override; + + ///< Basic initialization + bool Init() override; + +private: + + ///< Reload Python plugins and reset toolbar (if in pcbnew) + int reloadPlugins( const TOOL_EVENT& aEvent ); + + ///< Open the user's plugin folder in the system browser + int showPluginFolder( const TOOL_EVENT& aEvent ); + + ///< Bind handlers to corresponding TOOL_ACTIONs. + void setTransitions() override; + +}; + + +#endif /* PCBNEW_PCB_SCRIPTING_TOOL_H_ */ diff --git a/pcbnew/swig/pcbnew_action_plugins.cpp b/pcbnew/swig/pcbnew_action_plugins.cpp index fad7a84502..dd58dbdf01 100644 --- a/pcbnew/swig/pcbnew_action_plugins.cpp +++ b/pcbnew/swig/pcbnew_action_plugins.cpp @@ -197,6 +197,7 @@ void PCB_EDIT_FRAME::OnActionPluginMenu( wxCommandEvent& aEvent ) RunActionPlugin( actionPlugin ); } + void PCB_EDIT_FRAME::OnActionPluginButton( wxCommandEvent& aEvent ) { ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByButton( aEvent.GetId() ); diff --git a/pcbnew/swig/pcbnew_scripting.cpp b/pcbnew/swig/pcbnew_scripting.cpp index f61f9763c0..be7105cb0d 100644 --- a/pcbnew/swig/pcbnew_scripting.cpp +++ b/pcbnew/swig/pcbnew_scripting.cpp @@ -49,35 +49,6 @@ #include -/** - * Initialize the python environment and publish the Pcbnew interface inside it. - * - * This initializes all the wxPython interface and returns the python thread control structure - */ -bool pcbnewInitPythonScripting( const char* aStockScriptingPath, const char* aUserScriptingPath ) -{ - int retv; - char cmd[1024]; - - // Load pcbnew inside Python and load all the user plugins and package-based plugins - { - PyLOCK lock; - - // Load os so that we can modify the environment variables through python - snprintf( cmd, sizeof( cmd ), "import sys, os, traceback\n" - "sys.path.append(\".\")\n" - "import pcbnew\n" - "pcbnew.LoadPlugins(\"%s\", \"%s\")", - aStockScriptingPath, aUserScriptingPath ); - retv = PyRun_SimpleString( cmd ); - - if( retv != 0 ) - wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd ); - } - - return true; -} - /** * Run a python method from the pcbnew module. diff --git a/pcbnew/swig/pcbnew_scripting.h b/pcbnew/swig/pcbnew_scripting.h index 250c87011b..72e2f64aad 100644 --- a/pcbnew/swig/pcbnew_scripting.h +++ b/pcbnew/swig/pcbnew_scripting.h @@ -27,11 +27,6 @@ #include -/** - * Initialize the Python engine inside pcbnew. - */ -bool pcbnewInitPythonScripting( const char* aStockScriptingPath, const char* aUserScriptingPath ); - /** * Collect the list of python scripts which could not be loaded. * diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index bb492a226f..3e6cfd08ca 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -539,6 +539,22 @@ TOOL_ACTION PCB_ACTIONS::defaultPadProperties( "pcbnew.PadTool.defaultPadPropert BITMAPS::options_pad ); +// SCRIPTING TOOL +// +TOOL_ACTION PCB_ACTIONS::pluginsReload( "pcbnew.ScriptingTool.pluginsReload", + AS_GLOBAL, 0, "", + _( "Refresh Plugins" ), _( "Reload all python plugins and refresh plugin menus" ), + BITMAPS::reload ); + +TOOL_ACTION PCB_ACTIONS::pluginsShowFolder( "pcbnew.ScriptingTool.pluginsShowFolder", + AS_GLOBAL, 0, "", +#ifdef __WXMAC__ + _( "Reveal Plugin Folder in Finder" ), _( "Reveals the plugins folder in a Finder window" ), +#else + _( "Open Plugin Directory" ), _( "Opens the directory in the default system file manager" ), +#endif + BITMAPS::directory_open ); + // BOARD_EDITOR_CONTROL // TOOL_ACTION PCB_ACTIONS::boardSetup( "pcbnew.EditorControl.boardSetup", diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 304358bf8f..04bc35fbae 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -315,6 +315,10 @@ public: /// Duplicate zone onto another layer static TOOL_ACTION zoneDuplicate; + /// Scripting Actions + static TOOL_ACTION pluginsReload; + static TOOL_ACTION pluginsShowFolder; + // Global edit tool static TOOL_ACTION boardSetup; static TOOL_ACTION editTracksAndVias; diff --git a/scripting/python_scripting.cpp b/scripting/python_scripting.cpp index cf13753953..8cdf4d30b8 100644 --- a/scripting/python_scripting.cpp +++ b/scripting/python_scripting.cpp @@ -41,7 +41,6 @@ #include #include -#include #include #include #include @@ -52,22 +51,15 @@ #include -using initfunc = PyObject* (*)(void); -SCRIPTING::SCRIPTING( KIWAY* aKiway ) +SCRIPTING::SCRIPTING() { int retv; char cmd[1024]; scriptingSetup(); - KIFACE* pcbnew_kiface = nullptr; - - pcbnew_kiface = aKiway->KiFACE( KIWAY::FACE_PCB ); - initfunc pcbnew_init = reinterpret_cast( pcbnew_kiface->IfaceOrAddress( KIFACE_SCRIPTING_LEGACY ) ); - PyImport_AppendInittab( "_pcbnew", pcbnew_init ); - #ifdef _MSC_VER // Under vcpkg/msvc, we need to explicitly set the python home // or else it'll start consuming system python registry keys and the like instead @@ -85,35 +77,12 @@ SCRIPTING::SCRIPTING( KIWAY* aKiway ) Py_SetPythonHome( pyHome.GetFullPath().c_str() ); } #endif -// -// Py_Initialize(); + pybind11::initialize_interpreter(); -// PySys_SetArgv( Pgm().App().argc, Pgm().App().argv ); - -#if PY_VERSION_HEX < 0x03070000 // PyEval_InitThreads() is called by Py_Initialize() starting with version 3.7 - PyEval_InitThreads(); -#endif // if PY_VERSION_HEX < 0x03070000 - // Save the current Python thread state and release the // Global Interpreter Lock. m_python_thread_state = PyEval_SaveThread(); - - // Load pcbnew inside Python and load all the user plugins and package-based plugins - { - PyLOCK lock; - - // Load os so that we can modify the environment variables through python - snprintf( cmd, sizeof( cmd ), "import sys, os, traceback\n" - "sys.path.append(\".\")\n" - "import pcbnew\n" - "pcbnew.LoadPlugins(\"%s\", \"%s\")", - TO_UTF8( PyScriptingPath() ), TO_UTF8( PyScriptingPath( true) ) ); - retv = PyRun_SimpleString( cmd ); - - if( retv != 0 ) - wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd ); - } } SCRIPTING::~SCRIPTING() @@ -316,6 +285,7 @@ void UpdatePythonEnvVar( const wxString& aVar, const wxString& aValue ) snprintf( cmd, sizeof( cmd ), "# coding=utf-8\n" // The values could potentially be UTF8 + "import os\n" "os.environ[\"%s\"]=\"%s\"\n", TO_UTF8( escapedVar ), TO_UTF8( escapedVal ) ); @@ -444,7 +414,7 @@ wxString PyErrStringWithTraceback() /** * Find the Python scripting path. */ -wxString PyScriptingPath( bool aUserPath ) +wxString SCRIPTING::PyScriptingPath( bool aUserPath ) { wxString path; @@ -471,7 +441,7 @@ wxString PyScriptingPath( bool aUserPath ) } -wxString PyPluginsPath( bool aUserPath ) +wxString SCRIPTING::PyPluginsPath( bool aUserPath ) { // Note we are using unix path separator, because window separator sometimes // creates issues when passing a command string to a python method by PyRun_SimpleString diff --git a/scripting/python_scripting.h b/scripting/python_scripting.h index 56a25ca1e0..485f811c1a 100644 --- a/scripting/python_scripting.h +++ b/scripting/python_scripting.h @@ -45,12 +45,10 @@ #include #include -class KIWAY; - class SCRIPTING { public: - SCRIPTING( KIWAY* aKiway ); + SCRIPTING(); ~SCRIPTING(); /// We do not allow secondary creation of the scripting system @@ -59,13 +57,14 @@ public: static bool IsWxAvailable(); + static wxString PyScriptingPath( bool aUserPath = false ); + static wxString PyPluginsPath( bool aUserPath = false ); + private: bool scriptingSetup(); PyThreadState* m_python_thread_state; - - KIWAY* aKiway; }; /** @@ -93,7 +92,4 @@ wxString PyStringToWx( PyObject* str ); wxArrayString PyArrayStringToWx( PyObject* arr ); wxString PyErrStringWithTraceback(); -wxString PyScriptingPath( bool aUserPath = false ); -wxString PyPluginsPath( bool aUserPath = false ); - #endif // __PYTHON_SCRIPTING_H