chiark / gitweb /
Add post processing plugin support.
authordaid303 <daid303@gmail.com>
Wed, 31 Oct 2012 10:04:08 +0000 (11:04 +0100)
committerdaid303 <daid303@gmail.com>
Wed, 31 Oct 2012 10:04:08 +0000 (11:04 +0100)
Cura/gui/mainWindow.py
Cura/gui/pluginPanel.py [new file with mode: 0644]
Cura/gui/sliceProgessPanel.py
Cura/util/profile.py

index c20e9c914c05bba0cef27dd335e43ad46e6be9d4..6fa27cac8b1e3e4b9e4afa3ac0e08bb395abad8f 100644 (file)
@@ -8,6 +8,7 @@ from gui import expertConfig
 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
@@ -224,31 +225,10 @@ class mainWindow(configBase.configWindowBase):
                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)
@@ -498,3 +478,4 @@ class mainWindow(configBase.configWindowBase):
                super(mainWindow, self).updateProfileToControls()
                self.preview3d.updateProfileToControls()
                self.alterationPanel.updateProfileToControls()
+               self.pluginPanel.updateProfileToControls()
diff --git a/Cura/gui/pluginPanel.py b/Cura/gui/pluginPanel.py
new file mode 100644 (file)
index 0000000..fa0599a
--- /dev/null
@@ -0,0 +1,140 @@
+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)
index cc2a34c1f83d8b679605d6ff34e3332849e6aa47..98cd249626dca484491c3b79b1b0fb47e8ecde69 100644 (file)
@@ -168,7 +168,7 @@ class WorkerThread(threading.Thread):
                                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)
index 16d15fec698985fa65a825684a824a4c80a03c64..0458622d85eeb7c89ee6d40822063d189251e77c 100644 (file)
@@ -4,6 +4,7 @@ from __future__ import division
 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
@@ -73,6 +74,7 @@ profileDefaultSettings = {
        '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
@@ -531,41 +533,86 @@ def getAlterationFileContents(filename):
                        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