from gui import preview3d
from gui import sliceProgessPanel
from gui import alterationPanel
+from gui import pluginPanel
from gui import preferencesDialog
from gui import configWizard
from gui import firmwareInstall
validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 3.0 / 4.0), "A bottom layer of more then %.2fmm (3/4 nozzle size) usually give bad results and is not recommended.")
c = configBase.SettingRow(right, "Enable 'skin'", 'enable_skin', False, 'Skin prints the outer lines of the prints twice, each time with half the thickness. This gives the illusion of a higher print quality.')
- #Effects page
- self.effectList = profile.getEffectsList()
- if len(self.effectList) > 0:
- self.effectPanel = wx.Panel(nb)
- sizer = wx.GridBagSizer(2, 2)
- self.effectPanel.SetSizer(sizer)
-
- effectStringList = []
- for effect in self.effectList:
- effectStringList.append(effect['name'])
-
- self.listbox = wx.ListBox(self.effectPanel, -1, choices=effectStringList)
- title = wx.StaticText(self.effectPanel, -1, "Effects:")
- title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
- addButton = wx.Button(self.effectPanel, -1, '>', style=wx.BU_EXACTFIT)
- remButton = wx.Button(self.effectPanel, -1, '<', style=wx.BU_EXACTFIT)
- sizer.Add(self.listbox, (1,0), span=(2,1), border=10, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM)
- sizer.Add(title, (0,0), border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP)
- sizer.Add(addButton, (1,1), border=5, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)
- sizer.Add(remButton, (2,1), border=5, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_TOP)
-
- sizer.AddGrowableCol(2)
- sizer.AddGrowableRow(1)
- sizer.AddGrowableRow(2)
- nb.AddPage(self.effectPanel, "Effects")
+ #Plugin page
+ self.pluginPanel = pluginPanel.pluginPanel(nb)
+ if len(self.pluginPanel.pluginList) > 0:
+ nb.AddPage(self.pluginPanel, "Plugins")
#Alteration page
self.alterationPanel = alterationPanel.alterationPanel(nb)
super(mainWindow, self).updateProfileToControls()
self.preview3d.updateProfileToControls()
self.alterationPanel.updateProfileToControls()
+ self.pluginPanel.updateProfileToControls()
--- /dev/null
+import wx,wx.stc
+import sys,math,threading,os
+from wx.lib import scrolledpanel
+
+from util import profile
+
+class pluginPanel(wx.Panel):
+ def __init__(self, parent):
+ wx.Panel.__init__(self, parent,-1)
+ #Plugin page
+ self.pluginList = profile.getPluginList()
+
+ sizer = wx.GridBagSizer(2, 2)
+ self.SetSizer(sizer)
+
+ effectStringList = []
+ for effect in self.pluginList:
+ effectStringList.append(effect['name'])
+
+ self.listbox = wx.ListBox(self, -1, choices=effectStringList)
+ title = wx.StaticText(self, -1, "Plugins:")
+ title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
+ addButton = wx.Button(self, -1, '>', style=wx.BU_EXACTFIT)
+ sb = wx.StaticBox(self, label="Enabled plugins")
+ boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
+ self.pluginEnabledPanel = scrolledpanel.ScrolledPanel(self)
+ self.pluginEnabledPanel.SetupScrolling(False, True)
+
+ sizer.Add(title, (0,0), border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP)
+ sizer.Add(self.listbox, (1,0), span=(2,1), border=10, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+ sizer.Add(addButton, (1,1), border=5, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)
+ sizer.Add(boxsizer, (1,2), span=(2,1), border=10, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+ boxsizer.Add(self.pluginEnabledPanel, 1, flag=wx.EXPAND)
+
+ sizer.AddGrowableCol(2)
+ sizer.AddGrowableRow(1)
+ sizer.AddGrowableRow(2)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ self.pluginEnabledPanel.SetSizer(sizer)
+
+ self.Bind(wx.EVT_BUTTON, self.OnAdd, addButton)
+ self.panelList = []
+ self.updateProfileToControls()
+
+ def updateProfileToControls(self):
+ self.pluginConfig = profile.getPluginConfig()
+ for p in self.panelList:
+ p.Show(False)
+ self.pluginEnabledPanel.GetSizer().Detach(p)
+ self.panelList = []
+ for pluginConfig in self.pluginConfig:
+ self._buildPluginPanel(pluginConfig)
+
+ def _buildPluginPanel(self, pluginConfig):
+ plugin = None
+ for pluginTest in self.pluginList:
+ if pluginTest['filename'] == pluginConfig['filename']:
+ plugin = pluginTest
+ if plugin == None:
+ return False
+
+ pluginPanel = wx.Panel(self.pluginEnabledPanel)
+ s = wx.GridBagSizer(2, 2)
+ pluginPanel.SetSizer(s)
+ title = wx.StaticText(pluginPanel, -1, plugin['name'])
+ title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
+ remButton = wx.Button(pluginPanel, -1, 'X', style=wx.BU_EXACTFIT)
+ s.Add(title, pos=(0,0), span=(1,2), flag=wx.ALIGN_BOTTOM|wx.TOP|wx.LEFT|wx.RIGHT, border=5)
+ s.Add(remButton, pos=(0,2), span=(1,1), flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.ALIGN_RIGHT, border=5)
+ s.Add(wx.StaticLine(pluginPanel), pos=(1,0), span=(1,3), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3)
+ info = wx.StaticText(pluginPanel, -1, plugin['info'])
+ info.Wrap(300)
+ s.Add(info, pos=(2,0), span=(1,3), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3)
+
+ pluginPanel.paramCtrls = {}
+ i = 0
+ for param in plugin['params']:
+ value = param['default']
+ if param['name'] in pluginConfig['params']:
+ value = pluginConfig['params'][param['name']]
+
+ ctrl = wx.TextCtrl(pluginPanel, -1, value)
+ s.Add(wx.StaticText(pluginPanel, -1, param['description']), pos=(3+i,0), span=(1,1), flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,border=3)
+ s.Add(ctrl, pos=(3+i,2), span=(1,1), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3)
+
+ ctrl.Bind(wx.EVT_TEXT, self.OnSettingChange)
+
+ pluginPanel.paramCtrls[param['name']] = ctrl
+
+ i += 1
+ s.Add(wx.StaticLine(pluginPanel), pos=(3+i,0), span=(1,3), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3)
+
+ self.Bind(wx.EVT_BUTTON, self.OnRem, remButton)
+
+ s.AddGrowableCol(2)
+ pluginPanel.SetBackgroundColour(self.GetParent().GetBackgroundColour())
+ self.pluginEnabledPanel.GetSizer().Add(pluginPanel, flag=wx.EXPAND)
+ self.pluginEnabledPanel.Layout()
+ self.pluginEnabledPanel.SetSize((1,1))
+ self.Layout()
+ self.pluginEnabledPanel.ScrollChildIntoView(pluginPanel)
+ self.panelList.append(pluginPanel)
+ return True
+
+ def OnSettingChange(self, e):
+ for panel in self.panelList:
+ idx = self.panelList.index(panel)
+ for k in panel.paramCtrls.keys():
+ self.pluginConfig[idx]['params'][k] = panel.paramCtrls[k].GetValue()
+ profile.setPluginConfig(self.pluginConfig)
+
+ def OnAdd(self, e):
+ if self.listbox.GetSelection() < 0:
+ return
+ plugin = self.pluginList[self.listbox.GetSelection()]
+ newConfig = {'filename': plugin['filename'], 'params': {}}
+ if not self._buildPluginPanel(newConfig):
+ return
+ self.pluginConfig.append(newConfig)
+ profile.setPluginConfig(self.pluginConfig)
+
+ def OnRem(self, e):
+ panel = e.GetEventObject().GetParent()
+ sizer = self.pluginEnabledPanel.GetSizer()
+ idx = self.panelList.index(panel)
+
+ panel.Show(False)
+ for p in self.panelList:
+ sizer.Detach(p)
+ self.panelList.pop(idx)
+ for p in self.panelList:
+ sizer.Add(p, flag=wx.EXPAND)
+
+ self.pluginEnabledPanel.Layout()
+ self.pluginEnabledPanel.SetSize((1,1))
+ self.Layout()
+
+ self.pluginConfig.pop(idx)
+ profile.setPluginConfig(self.pluginConfig)
if logLine.startswith('Model error('):
gcodefile.write(';%s\n' % (logLine))
gcodefile.close()
- profile.runPostProcessingEffects(gcodeFilename)
+ profile.runPostProcessingPlugins(gcodeFilename)
self.gcode = gcodeInterpreter.gcode()
self.gcode.load(gcodeFilename)
profile.replaceGCodeTags(gcodeFilename, self.gcode)
import __init__\r
\r
import os, traceback, math, re, zlib, base64, time, sys, platform, glob\r
+import cPickle as pickle\r
if sys.version_info[0] < 3:\r
import ConfigParser\r
else:\r
'raft_base_material_amount': '100',\r
'raft_interface_material_amount': '100',\r
'bottom_thickness': '0.3',\r
+ 'plugin_config': '',\r
\r
'add_start_end_gcode': 'True',\r
'gcode_extension': 'gcode',\r
alterationContents = ''\r
return unicode(prefix + re.sub("(.)\{([^\}]*)\}", replaceTagMatch, alterationContents).rstrip() + '\n' + postfix).strip().encode('utf-8')\r
\r
-def getEffectBasePath():\r
- return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'post_process'))\r
+###### PLUGIN #####\r
\r
-def getEffectsList():\r
+def getPluginConfig():\r
+ try:\r
+ return pickle.loads(getProfileSetting('plugin_config'))\r
+ except:\r
+ return []\r
+\r
+def setPluginConfig(config):\r
+ putProfileSetting('plugin_config', pickle.dumps(config))\r
+\r
+def getPluginBasePaths():\r
+ ret = [os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'plugins'))]\r
+ if platform.system() != "Windows":\r
+ ret.append(os.path.expanduser('~/.cura/plugins/'))\r
+ return ret\r
+\r
+def getPluginList():\r
ret = []\r
- for filename in glob.glob(os.path.join(getEffectBasePath(), '*.py')):\r
- filename = os.path.basename(filename)\r
- if filename.startswith('_'):\r
- continue\r
- with open(os.path.join(getEffectBasePath(), filename), "r") as f:\r
- item = {'name': None, 'info': None, 'params': []}\r
- for line in f:\r
- line = line.strip()\r
- if not line.startswith('#'):\r
- break\r
- line = line[1:].split(':', 1)\r
- if len(line) != 2:\r
- continue\r
- if line[0].upper() == 'NAME':\r
- item['name'] = line[1].strip()\r
- elif line[0].upper() == 'INFO':\r
- item['info'] = line[1].strip()\r
- elif line[0].upper() == 'PARAM':\r
- m = re.match('([a-zA-Z]*)\(([a-zA-Z_]*)\) +(.*)', line[1].strip())\r
- if m != None:\r
- item['params'].append({'name': m.group(1), 'type': m.group(2), 'description': m.group(3)})\r
- else:\r
- print "Unknown item in effect meta data: %s %s" % (line[0], line[1])\r
- if item['name'] != None:\r
- ret.append(item)\r
+ for basePath in getPluginBasePaths():\r
+ for filename in glob.glob(os.path.join(basePath, '*.py')):\r
+ filename = os.path.basename(filename)\r
+ if filename.startswith('_'):\r
+ continue\r
+ with open(os.path.join(basePath, filename), "r") as f:\r
+ item = {'filename': filename, 'name': None, 'info': None, 'type': None, 'params': []}\r
+ for line in f:\r
+ line = line.strip()\r
+ if not line.startswith('#'):\r
+ break\r
+ line = line[1:].split(':', 1)\r
+ if len(line) != 2:\r
+ continue\r
+ if line[0].upper() == 'NAME':\r
+ item['name'] = line[1].strip()\r
+ elif line[0].upper() == 'INFO':\r
+ item['info'] = line[1].strip()\r
+ elif line[0].upper() == 'TYPE':\r
+ item['type'] = line[1].strip()\r
+ elif line[0].upper() == 'PARAM':\r
+ m = re.match('([a-zA-Z]*)\(([a-zA-Z_]*)(?:\:([^\)]*))?\) +(.*)', line[1].strip())\r
+ if m != None:\r
+ item['params'].append({'name': m.group(1), 'type': m.group(2), 'default': m.group(3), 'description': m.group(4)})\r
+ else:\r
+ print "Unknown item in effect meta data: %s %s" % (line[0], line[1])\r
+ if item['name'] != None and item['type'] == 'postprocess':\r
+ ret.append(item)\r
return ret\r
\r
-def runPostProcessingEffects(filename):\r
- pass\r
- #print "runPostProcessingEffects: %s" % (filename)\r
+def runPostProcessingPlugins(gcodefilename):\r
+ pluginConfigList = getPluginConfig()\r
+ pluginList = getPluginList()\r
\r
- #pythonFile = os.path.join(getEffectBasePath(), 'embedImage.py')\r
- #execfile(pythonFile, {'filename': filename})\r
+ for pluginConfig in pluginConfigList:\r
+ plugin = None\r
+ for pluginTest in pluginList:\r
+ if pluginTest['filename'] == pluginConfig['filename']:\r
+ plugin = pluginTest\r
+ if plugin == None:\r
+ continue\r
+ \r
+ pythonFile = None\r
+ for basePath in getPluginBasePaths():\r
+ testFilename = os.path.join(basePath, pluginConfig['filename'])\r
+ if os.path.isfile(testFilename):\r
+ pythonFile = testFilename\r
+ if pythonFile == None:\r
+ continue\r
+ \r
+ locals = {'filename': gcodefilename}\r
+ for param in plugin['params']:\r
+ value = param['default']\r
+ if param['name'] in pluginConfig['params']:\r
+ value = pluginConfig['params'][param['name']]\r
+ \r
+ if param['type'] == 'float':\r
+ try:\r
+ value = float(value)\r
+ except:\r
+ value = 0.0\r
+ \r
+ locals[param['name']] = value\r
+ execfile(pythonFile, locals)\r