Scripting: replace PyCrust shell with enhanced PyAlaMode shell.
This commit is contained in:
parent
a11bbffe9b
commit
c3d3a7a4c8
|
@ -679,6 +679,12 @@ if( KICAD_SCRIPTING )
|
|||
DESTINATION ${KICAD_DATA}/scripting/plugins
|
||||
FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
|
||||
)
|
||||
|
||||
# scripting python shell
|
||||
install( DIRECTORY ${PROJECT_SOURCE_DIR}/pcbnew/scripting/kicad_pyshell/
|
||||
DESTINATION ${KICAD_DATA}/scripting/kicad_pyshell
|
||||
FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
|
||||
)
|
||||
endif()
|
||||
|
||||
if( KICAD_SCRIPTING_MODULES )
|
||||
|
|
|
@ -70,8 +70,6 @@
|
|||
#include <tool/tool_dispatcher.h>
|
||||
#include <tools/common_actions.h>
|
||||
|
||||
#include <scripting/python_console_frame.h>
|
||||
|
||||
#if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON)
|
||||
#include <python_scripting.h>
|
||||
#endif
|
||||
|
@ -984,9 +982,6 @@ void PCB_EDIT_FRAME::UpdateTitle()
|
|||
}
|
||||
|
||||
|
||||
wxSize PYTHON_CONSOLE_FRAME::m_frameSize; ///< The size of the PYTHON_CONSOLE_FRAME frame, stored during a session
|
||||
wxPoint PYTHON_CONSOLE_FRAME::m_framePos; ///< The position ofPYTHON_CONSOLE_FRAME the frame, stored during a session
|
||||
|
||||
void PCB_EDIT_FRAME::ScriptingConsoleEnableDisable( wxCommandEvent& aEvent )
|
||||
{
|
||||
|
||||
|
@ -994,7 +989,7 @@ void PCB_EDIT_FRAME::ScriptingConsoleEnableDisable( wxCommandEvent& aEvent )
|
|||
bool pythonPanelShown = true;
|
||||
|
||||
if( pythonPanelFrame == NULL )
|
||||
pythonPanelFrame = new PYTHON_CONSOLE_FRAME( this, pythonConsoleNameId() );
|
||||
pythonPanelFrame = CreatePythonShellWindow( this, pythonConsoleNameId() );
|
||||
else
|
||||
pythonPanelShown = ! pythonPanelFrame->IsShown();
|
||||
|
||||
|
|
|
@ -241,36 +241,26 @@ static bool scriptingSetup()
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: make this path definable by the user, and set more than one path
|
||||
// (and remove the fixed paths from <src>/scripting/kicadplugins.i)
|
||||
|
||||
// wizard plugins are stored in kicad/bin/plugins.
|
||||
// so add this path to python scripting default search paths
|
||||
// wizard plugins are stored in ../share/kicad/scripting/plugins.
|
||||
// so add the base scripting path to python scripting default search paths
|
||||
// which are ( [KICAD_PATH] is an environment variable to define)
|
||||
// [KICAD_PATH]/scripting
|
||||
// [KICAD_PATH]/scripting/plugins
|
||||
// Add this default search path:
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting/plugins" );
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting" );
|
||||
|
||||
#elif defined( __WXMAC__ )
|
||||
// TODO:
|
||||
// For scripting currently only the bundle scripting path and the path
|
||||
// defined by $(KICAD_PATH)/scripting/plugins is defined.
|
||||
// These paths are defined here and in kicadplugins.i
|
||||
// In future, probably more paths are of interest:
|
||||
// * User folder (~/Library/Application Support/kicad/scripting/plugins)
|
||||
// => GetOSXKicadUserDataDir() + wxT( "/scripting/plugins" );
|
||||
// * Machine folder (/Library/Application Support/kicad/scripting/plugins)
|
||||
// => GetOSXKicadMachineDataDir() + wxT( "/scripting/plugins" );
|
||||
|
||||
// This path is given to LoadPlugins() from kicadplugins.i, which
|
||||
// only supports one path. Only use bundle scripting path for now.
|
||||
path_frag = GetOSXKicadDataDir() + wxT( "/scripting/plugins" );
|
||||
// only supports one path, the bundle scripting path for now.
|
||||
// All other paths are determined by the pcbnew.py initialisation code
|
||||
path_frag = GetOSXKicadDataDir() + wxT( "/scripting" );
|
||||
|
||||
// Add default paths to PYTHONPATH
|
||||
wxString pypath;
|
||||
|
||||
// Bundle scripting folder (<kicad.app>/Contents/SharedSupport/scripting/plugins)
|
||||
pypath += GetOSXKicadDataDir() + wxT( "/scripting/plugins" );
|
||||
// Bundle scripting folder (<kicad.app>/Contents/SharedSupport/scripting)
|
||||
pypath += GetOSXKicadDataDir() + wxT( "/scripting" );
|
||||
|
||||
// $(KICAD_PATH)/scripting/plugins is always added in kicadplugins.i
|
||||
if( wxGetenv("KICAD_PATH") != NULL )
|
||||
|
@ -303,9 +293,11 @@ static bool scriptingSetup()
|
|||
wxSetEnv( wxT( "PYTHONPATH" ), pypath );
|
||||
|
||||
// Add this default search path:
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting/plugins" );
|
||||
path_frag = Pgm().GetExecutablePath() + wxT( "../share/kicad/scripting" );
|
||||
#endif
|
||||
|
||||
// path_frag is the path to the bundled scripts and plugins, all other paths are
|
||||
// determined by the python pcbnew.py initialisation code.
|
||||
if( !pcbnewInitPythonScripting( TO_UTF8( path_frag ) ) )
|
||||
{
|
||||
wxLogError( wxT( "pcbnewInitPythonScripting() failed." ) );
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""KiCad Python Shell.
|
||||
|
||||
This module provides the python shell for KiCad.
|
||||
|
||||
Currently the shell is only available inside PCBNEW.
|
||||
|
||||
PCBNEW starts the shell once, by calling makePcbnewShellWindow() the
|
||||
first time it is opened, subsequently the shell window is just hidden
|
||||
or shown, as per user requirements.
|
||||
|
||||
IF makePcbnewShellWindow() is called again, a second/third shell window
|
||||
can be created. PCBNEW does not do this, but a user may call this from
|
||||
the first shell if they require.
|
||||
|
||||
"""
|
||||
import wx
|
||||
import sys
|
||||
import os
|
||||
|
||||
from wx.py import crust, editor, version, dispatcher
|
||||
from wx.py.editor import EditorNotebook
|
||||
|
||||
import pcbnew
|
||||
|
||||
INTRO = "KiCAD:PCBNEW - Python Shell - PyAlaMode %s" % version.VERSION
|
||||
|
||||
|
||||
class PcbnewPyShell(editor.EditorNotebookFrame):
|
||||
|
||||
"""The Pythonshell of PCBNEW."""
|
||||
|
||||
def _setup_startup(self):
|
||||
"""Initialise the startup script."""
|
||||
# Create filename for startup script.
|
||||
self.startup_file = os.path.join(self.config_dir,
|
||||
"PyShell_pcbnew_startup.py")
|
||||
self.execStartupScript = True
|
||||
|
||||
# Check if startup script exists
|
||||
if not os.path.isfile(self.startup_file):
|
||||
# Not, so create a default.
|
||||
default_startup = open(self.startup_file, 'w')
|
||||
# provide the content for the default startup file.
|
||||
default_startup.write(
|
||||
"### DEFAULT STARTUP FILE FOR KiCad:PCBNEW Python Shell\n" +
|
||||
"# Enter any Python code you would like to execute when" +
|
||||
" the PCBNEW python shell first runs.\n" +
|
||||
"\n" +
|
||||
"# Eg:\n" +
|
||||
"\n" +
|
||||
"# import pcbnew\n" +
|
||||
"# board = pcbnew.GetBoard()\n")
|
||||
default_startup.close()
|
||||
|
||||
def _setup(self):
|
||||
"""
|
||||
Setup prior to first buffer creation.
|
||||
|
||||
Called automatically by base class during init.
|
||||
"""
|
||||
self.notebook = EditorNotebook(parent=self)
|
||||
intro = 'Py %s' % version.VERSION
|
||||
import imp
|
||||
module = imp.new_module('__main__')
|
||||
import __builtin__
|
||||
module.__dict__['__builtins__'] = __builtin__
|
||||
namespace = module.__dict__.copy()
|
||||
|
||||
self.config_dir = pcbnew.GetKicadConfigPath()
|
||||
self.dataDir = self.config_dir
|
||||
|
||||
self._setup_startup()
|
||||
self.history_file = os.path.join(self.config_dir,
|
||||
"PyShell_pcbnew.history")
|
||||
|
||||
self.config_file = os.path.join(self.config_dir,
|
||||
"PyShell_pcbnew.cfg")
|
||||
self.config = wx.FileConfig(localFilename=self.config_file)
|
||||
self.config.SetRecordDefaults(True)
|
||||
self.autoSaveSettings = False
|
||||
self.autoSaveHistory = False
|
||||
self.LoadSettings()
|
||||
|
||||
self.crust = crust.Crust(parent=self.notebook,
|
||||
intro=intro, locals=namespace,
|
||||
rootLabel="locals()",
|
||||
startupScript=self.startup_file,
|
||||
execStartupScript=self.execStartupScript)
|
||||
|
||||
self.shell = self.crust.shell
|
||||
# Override the filling so that status messages go to the status bar.
|
||||
self.crust.filling.tree.setStatusText = self.SetStatusText
|
||||
# Override the shell so that status messages go to the status bar.
|
||||
self.shell.setStatusText = self.SetStatusText
|
||||
# Fix a problem with the sash shrinking to nothing.
|
||||
self.crust.filling.SetSashPosition(200)
|
||||
self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
|
||||
self.setEditor(self.crust.editor)
|
||||
self.crust.editor.SetFocus()
|
||||
|
||||
self.LoadHistory()
|
||||
|
||||
def OnAbout(self, event):
|
||||
"""Display an About window."""
|
||||
title = 'About : KiCad:PCBNEW - Python Shell'
|
||||
text = "Enahnced Python Shell for KiCad:PCBNEW\n\n" + \
|
||||
"This KiCad Python Shell is based on wxPython PyAlaMode.\n\n" + \
|
||||
"see: http://wiki.wxpython.org/PyAlaMode\n\n" + \
|
||||
"KiCad Revision: %s\n" % "??.??" + \
|
||||
"PyAlaMode Revision : %s\n" % version.VERSION + \
|
||||
"Platform: %s\n" % sys.platform + \
|
||||
"Python Version: %s\n" % sys.version.split()[0] + \
|
||||
"wxPython Version: %s\n" % wx.VERSION_STRING + \
|
||||
("\t(%s)\n" % ", ".join(wx.PlatformInfo[1:]))
|
||||
|
||||
dialog = wx.MessageDialog(self, text, title,
|
||||
wx.OK | wx.ICON_INFORMATION)
|
||||
dialog.ShowModal()
|
||||
dialog.Destroy()
|
||||
|
||||
def EditStartupScript(self):
|
||||
"""Open a Edit buffer of the startup script file."""
|
||||
self.bufferCreate(filename=self.startup_file)
|
||||
|
||||
def LoadSettings(self):
|
||||
"""Load settings for the shell."""
|
||||
if self.config is not None:
|
||||
editor.EditorNotebookFrame.LoadSettings(self, self.config)
|
||||
self.autoSaveSettings = \
|
||||
self.config.ReadBool('Options/AutoSaveSettings', False)
|
||||
self.execStartupScript = \
|
||||
self.config.ReadBool('Options/ExecStartupScript', True)
|
||||
self.autoSaveHistory = \
|
||||
self.config.ReadBool('Options/AutoSaveHistory', False)
|
||||
self.hideFoldingMargin = \
|
||||
self.config.ReadBool('Options/HideFoldingMargin', True)
|
||||
|
||||
def SaveSettings(self, force=False):
|
||||
"""
|
||||
Save settings for the shell.
|
||||
|
||||
Arguments:
|
||||
|
||||
force -- False - Autosaving. True - Manual Saving.
|
||||
"""
|
||||
if self.config is not None:
|
||||
# always save these
|
||||
self.config.WriteBool('Options/AutoSaveSettings',
|
||||
self.autoSaveSettings)
|
||||
if self.autoSaveSettings or force:
|
||||
editor.EditorNotebookFrame.SaveSettings(self, self.config)
|
||||
|
||||
self.config.WriteBool('Options/AutoSaveHistory',
|
||||
self.autoSaveHistory)
|
||||
self.config.WriteBool('Options/ExecStartupScript',
|
||||
self.execStartupScript)
|
||||
self.config.WriteBool('Options/HideFoldingMargin',
|
||||
self.hideFoldingMargin)
|
||||
if self.autoSaveHistory:
|
||||
self.SaveHistory()
|
||||
|
||||
def DoSaveSettings(self):
|
||||
"""Menu function to trigger saving the shells settings."""
|
||||
if self.config is not None:
|
||||
self.SaveSettings(force=True)
|
||||
self.config.Flush()
|
||||
|
||||
def SaveHistory(self):
|
||||
"""Save shell history to the shell history file."""
|
||||
if self.dataDir:
|
||||
try:
|
||||
name = self.history_file
|
||||
f = file(name, 'w')
|
||||
hist = []
|
||||
enc = wx.GetDefaultPyEncoding()
|
||||
for h in self.shell.history:
|
||||
if isinstance(h, unicode):
|
||||
h = h.encode(enc)
|
||||
hist.append(h)
|
||||
hist = '\x00\n'.join(hist)
|
||||
f.write(hist)
|
||||
f.close()
|
||||
except:
|
||||
d = wx.MessageDialog(self, "Error saving history file.",
|
||||
"Error", wx.ICON_EXCLAMATION | wx.OK)
|
||||
d.ShowModal()
|
||||
d.Destroy()
|
||||
raise
|
||||
|
||||
def LoadHistory(self):
|
||||
"""Load shell history from the shell history file."""
|
||||
if self.dataDir:
|
||||
name = self.history_file
|
||||
if os.path.exists(name):
|
||||
try:
|
||||
f = file(name, 'U')
|
||||
hist = f.read()
|
||||
f.close()
|
||||
self.shell.history = hist.split('\x00\n')
|
||||
dispatcher.send(signal="Shell.loadHistory",
|
||||
history=self.shell.history)
|
||||
except:
|
||||
d = wx.MessageDialog(self,
|
||||
"Error loading history file!",
|
||||
"Error", wx.ICON_EXCLAMATION | wx.OK)
|
||||
d.ShowModal()
|
||||
d.Destroy()
|
||||
|
||||
|
||||
def makePcbnewShellWindow(parent=None):
|
||||
"""
|
||||
Create a new Shell Window and return its handle.
|
||||
|
||||
Arguments:
|
||||
parent -- The parent window to attach to.
|
||||
|
||||
Returns:
|
||||
The handle to the new window.
|
||||
"""
|
||||
pyshell = PcbnewPyShell(parent, id=-1, title=INTRO)
|
||||
pyshell.Show()
|
||||
return pyshell
|
|
@ -78,21 +78,59 @@ def ReloadPlugins():
|
|||
ReloadPlugin(k)
|
||||
|
||||
|
||||
def LoadPlugins(plugpath):
|
||||
def LoadPlugins(bundlepath=None):
|
||||
"""
|
||||
Initialise Scripting/Plugin python environment and load plugins.
|
||||
|
||||
Arguments:
|
||||
scriptpath -- The path to the bundled scripts.
|
||||
The bunbled Plugins are relative to this path, in the
|
||||
"plugins" subdirectory.
|
||||
|
||||
NOTE: These are all of the possible "default" search paths for kicad
|
||||
python scripts. These paths will ONLY be added to the python
|
||||
search path ONLY IF they already exist.
|
||||
|
||||
The Scripts bundled with the KiCad installation:
|
||||
<bundlepath>/
|
||||
<bundlepath>/plugins/
|
||||
|
||||
The Scripts relative to the KiCad search path environment variable:
|
||||
[KICAD_PATH]/scripting/
|
||||
[KICAD_PATH]/scripting/plugins/
|
||||
|
||||
The Scripts relative to the KiCad Users configuration:
|
||||
<kicad_config_path>/scripting/
|
||||
<kicad_config_path>/scripting/plugins/
|
||||
|
||||
And on Linux ONLY, extra paths relative to the users home directory:
|
||||
~/.kicad_plugins/
|
||||
~/.kicad/scripting/
|
||||
~/.kicad/scripting/plugins/
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import pcbnew
|
||||
|
||||
kicad_path = os.environ.get('KICAD_PATH')
|
||||
config_path = pcbnew.GetKicadConfigPath()
|
||||
plugin_directories=[]
|
||||
|
||||
if plugpath:
|
||||
plugin_directories.append(plugpath)
|
||||
if bundlepath:
|
||||
plugin_directories.append(bundlepath)
|
||||
plugin_directories.append(os.path.join(bundlepath, 'plugins'))
|
||||
|
||||
if kicad_path:
|
||||
plugin_directories.append(os.path.join(kicad_path, 'scripting'))
|
||||
plugin_directories.append(os.path.join(kicad_path, 'scripting', 'plugins'))
|
||||
|
||||
if config_path:
|
||||
plugin_directories.append(os.path.join(config_path, 'scripting'))
|
||||
plugin_directories.append(os.path.join(config_path, 'scripting', 'plugins'))
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad_plugins/')
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad/scripting/')
|
||||
plugin_directories.append(os.environ['HOME']+'/.kicad/scripting/plugins/')
|
||||
|
||||
for plugins_dir in plugin_directories:
|
||||
|
|
|
@ -136,7 +136,7 @@ static void swigSwitchPythonBuiltin()
|
|||
|
||||
PyThreadState* g_PythonMainTState;
|
||||
|
||||
bool pcbnewInitPythonScripting( const char * aUserPluginsPath )
|
||||
bool pcbnewInitPythonScripting( const char * aUserScriptingPath )
|
||||
{
|
||||
swigAddBuiltin(); // add builtin functions
|
||||
swigAddModules(); // add our own modules
|
||||
|
@ -191,7 +191,7 @@ bool pcbnewInitPythonScripting( const char * aUserPluginsPath )
|
|||
snprintf( cmd, sizeof(cmd), "import sys, traceback\n"
|
||||
"sys.path.append(\".\")\n"
|
||||
"import pcbnew\n"
|
||||
"pcbnew.LoadPlugins(\"%s\")", aUserPluginsPath );
|
||||
"pcbnew.LoadPlugins(\"%s\")", aUserScriptingPath );
|
||||
PyRun_SimpleString( cmd );
|
||||
}
|
||||
|
||||
|
@ -227,20 +227,15 @@ void RedirectStdio()
|
|||
}
|
||||
|
||||
|
||||
wxWindow* CreatePythonShellWindow( wxWindow* parent )
|
||||
wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameId )
|
||||
{
|
||||
const char* pycrust_panel =
|
||||
"import wx\n"
|
||||
"from wx.py import shell, version\n"
|
||||
"\n"
|
||||
"intro = \"PyCrust %s - KiCAD Python Shell\" % version.VERSION\n"
|
||||
const char* pcbnew_pyshell =
|
||||
"import kicad_pyshell\n"
|
||||
"\n"
|
||||
"def makeWindow(parent):\n"
|
||||
" pycrust = shell.Shell(parent, -1, introText=intro)\n"
|
||||
" return pycrust\n"
|
||||
" return kicad_pyshell.makePcbnewShellWindow(parent)\n"
|
||||
"\n";
|
||||
|
||||
|
||||
wxWindow* window = NULL;
|
||||
PyObject* result;
|
||||
|
||||
|
@ -257,7 +252,7 @@ wxWindow* CreatePythonShellWindow( wxWindow* parent )
|
|||
Py_DECREF( builtins );
|
||||
|
||||
// Execute the code to make the makeWindow function we defined above
|
||||
result = PyRun_String( pycrust_panel, Py_file_input, globals, globals );
|
||||
result = PyRun_String( pcbnew_pyshell, Py_file_input, globals, globals );
|
||||
|
||||
// Was there an exception?
|
||||
if( !result )
|
||||
|
@ -297,6 +292,8 @@ wxWindow* CreatePythonShellWindow( wxWindow* parent )
|
|||
|
||||
wxASSERT_MSG( success, _T( "Returned object was not a wxWindow!" ) );
|
||||
Py_DECREF( result );
|
||||
|
||||
window->SetName( aFramenameId );
|
||||
}
|
||||
|
||||
// Release the python objects we still have
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
* Initializes the Python engine inside pcbnew
|
||||
*/
|
||||
|
||||
bool pcbnewInitPythonScripting( const char * aUserPluginsPath );
|
||||
bool pcbnewInitPythonScripting( const char * aUserScriptingPath );
|
||||
void pcbnewFinishPythonScripting();
|
||||
|
||||
|
||||
#ifdef KICAD_SCRIPTING_WXPYTHON
|
||||
|
||||
void RedirectStdio();
|
||||
wxWindow* CreatePythonShellWindow( wxWindow* parent );
|
||||
wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameId );
|
||||
|
||||
class PyLOCK
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue