chiark / gitweb /
Add progress window to project planner.
authordaid <daid303@gmail.com>
Fri, 20 Apr 2012 15:06:50 +0000 (17:06 +0200)
committerdaid <daid303@gmail.com>
Fri, 20 Apr 2012 15:06:50 +0000 (17:06 +0200)
Cura/gui/projectPlanner.py
Cura/util/profile.py

index 02de4e2ef703cf2e03a02ff223335cf57b00b2ef..f664d53d572313b0553565854424648c1ac39fa1 100644 (file)
@@ -1,7 +1,7 @@
 from __future__ import absolute_import\r
 import __init__\r
 \r
-import wx, os, platform, types, webbrowser, math, subprocess\r
+import wx, os, platform, types, webbrowser, math, subprocess, threading, time\r
 import ConfigParser\r
 \r
 from wx import glcanvas\r
@@ -24,6 +24,9 @@ from util import util3d
 from util import stl\r
 from util import sliceRun\r
 \r
+class Action():\r
+       pass\r
+\r
 class projectPlanner(wx.Frame):\r
        "Main user interface window"\r
        def __init__(self):\r
@@ -223,6 +226,8 @@ class projectPlanner(wx.Frame):
                put('add_start_end_gcode', 'False')\r
                put('gcode_extension', 'project_tmp')\r
                \r
+               clearZ = 0\r
+               actionList = []\r
                for item in self.list:\r
                        put('machine_center_x', item.centerX)\r
                        put('machine_center_y', item.centerY)\r
@@ -234,7 +239,14 @@ class projectPlanner(wx.Frame):
                        put('swap_xz', item.swapXZ)\r
                        put('swap_yz', item.swapYZ)\r
                        \r
-                       item.sliceCmd = sliceRun.getSliceCommand(item.filename)\r
+                       action = Action()\r
+                       action.sliceCmd = sliceRun.getSliceCommand(item.filename)\r
+                       action.centerX = item.centerX\r
+                       action.centerY = item.centerY\r
+                       action.filename = item.filename\r
+                       clearZ = max(clearZ, item.getMaximum().z * item.scale)\r
+                       action.clearZ = clearZ\r
+                       actionList.append(action)\r
                \r
                #Restore the old profile.\r
                profile.loadGlobalProfileFromString(oldProfile)\r
@@ -244,44 +256,12 @@ class projectPlanner(wx.Frame):
                if dlg.ShowModal() != wx.ID_OK:\r
                        dlg.Destroy()\r
                        return\r
-               resultFile = open(dlg.GetPath(), "w")\r
+               resultFilename = dlg.GetPath()\r
                dlg.Destroy()\r
                \r
-               i = 1\r
-               maxZ = 0\r
-               prevItem = None\r
-               for item in self.list:\r
-                       subprocess.call(item.sliceCmd)\r
-                       \r
-                       maxZ = max(maxZ, item.getMaximum().z * item.scale)\r
-                       put('machine_center_x', item.centerX)\r
-                       put('machine_center_y', item.centerY)\r
-                       put('clear_z', maxZ)\r
-                       \r
-                       if prevItem == None:\r
-                               resultFile.write(';TYPE:CUSTOM\n')\r
-                               resultFile.write(profile.getAlterationFileContents('start.gcode'))\r
-                       else:\r
-                               #reset the extrusion length, and move to the next object center.\r
-                               resultFile.write(';TYPE:CUSTOM\n')\r
-                               resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))\r
-                       resultFile.write(';PRINTNR:%d\n' % (i))\r
-                       profile.loadGlobalProfileFromString(oldProfile)\r
-                       \r
-                       f = open(item.filename[: item.filename.rfind('.')] + "_export.project_tmp", "r")\r
-                       data = f.read(4096)\r
-                       while data != '':\r
-                               resultFile.write(data)\r
-                               data = f.read(4096)\r
-                       f.close()\r
-                       os.remove(item.filename[: item.filename.rfind('.')] + "_export.project_tmp")\r
-                       i += 1\r
-                       \r
-                       prevItem = item\r
-               \r
-               resultFile.write(';TYPE:CUSTOM\n')\r
-               resultFile.write(profile.getAlterationFileContents('end.gcode'))\r
-               resultFile.close()\r
+               pspw = ProjectSliceProgressWindow(actionList, resultFilename)\r
+               pspw.Centre()\r
+               pspw.Show(True)\r
        \r
        def loadModelFile(self, item):\r
                item.load(item.filename)\r
@@ -561,6 +541,129 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                \r
                glFlush()\r
 \r
+class ProjectSliceProgressWindow(wx.Frame):\r
+       def __init__(self, actionList, resultFilename):\r
+               super(ProjectSliceProgressWindow, self).__init__(None, title='Cura')\r
+               self.actionList = actionList\r
+               self.resultFilename = resultFilename\r
+               self.abort = False\r
+               self.prevStep = 'start'\r
+               self.totalDoneFactor = 0.0\r
+               self.startTime = time.time()\r
+               \r
+               #How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.\r
+               # TODO: Duplicate with sliceProgressPanel, move to sliceRun.\r
+               self.sliceStepTimeFactor = {\r
+                       'start': 3.3713991642,\r
+                       'slice': 15.4984838963,\r
+                       'preface': 5.17178297043,\r
+                       'inset': 116.362634182,\r
+                       'fill': 215.702672005,\r
+                       'multiply': 21.9536788464,\r
+                       'speed': 12.759510994,\r
+                       'raft': 31.4580039978,\r
+                       'skirt': 19.3436040878,\r
+                       'skin': 1.0,\r
+                       'joris': 1.0,\r
+                       'comb': 23.7805759907,\r
+                       'cool': 27.148763895,\r
+                       'dimension': 90.4914340973\r
+               }\r
+               self.totalRunTimeFactor = 0\r
+               for v in self.sliceStepTimeFactor.itervalues():\r
+                       self.totalRunTimeFactor += v\r
+               \r
+               self.sizer = wx.GridBagSizer(2, 2) \r
+               self.statusText = wx.StaticText(self, -1, "Building: %s" % (resultFilename))\r
+               self.progressGauge = wx.Gauge(self, -1)\r
+               self.progressGauge.SetRange(10000)\r
+               self.progressGauge2 = wx.Gauge(self, -1)\r
+               self.progressGauge2.SetRange(len(self.actionList))\r
+               self.abortButton = wx.Button(self, -1, "Abort")\r
+               self.sizer.Add(self.statusText, (0,0), flag=wx.ALIGN_CENTER)\r
+               self.sizer.Add(self.progressGauge, (1, 0), flag=wx.EXPAND)\r
+               self.sizer.Add(self.progressGauge2, (2, 0), flag=wx.EXPAND)\r
+               self.sizer.Add(self.abortButton, (3,0), flag=wx.ALIGN_CENTER)\r
+\r
+               self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)\r
+               self.SetSizer(self.sizer)\r
+               self.Layout()\r
+               self.Fit()\r
+               \r
+               threading.Thread(target=self.OnRun).start()\r
+\r
+       def OnAbort(self, e):\r
+               self.abort = True\r
+\r
+       def SetProgress(self, stepName, layer, maxLayer):\r
+               if self.prevStep != stepName:\r
+                       self.totalDoneFactor += self.sliceStepTimeFactor[self.prevStep]\r
+                       newTime = time.time()\r
+                       #print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName\r
+                       self.startTime = newTime\r
+                       self.prevStep = stepName\r
+               \r
+               progresValue = ((self.totalDoneFactor + self.sliceStepTimeFactor[stepName] * layer / maxLayer) / self.totalRunTimeFactor) * 10000\r
+               self.progressGauge.SetValue(int(progresValue))\r
+               self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")\r
+       \r
+       def OnRun(self):\r
+               resultFile = open(self.resultFilename, "w")\r
+               put = profile.putProfileSetting\r
+               for action in self.actionList:\r
+                       p = subprocess.Popen(action.sliceCmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\r
+                       line = p.stdout.readline()\r
+               \r
+                       maxValue = 1\r
+                       self.progressLog = []\r
+                       while(len(line) > 0):\r
+                               line = line.rstrip()\r
+                               if line[0:9] == "Progress[" and line[-1:] == "]":\r
+                                       progress = line[9:-1].split(":")\r
+                                       if len(progress) > 2:\r
+                                               maxValue = int(progress[2])\r
+                                       wx.CallAfter(self.SetProgress, progress[0], int(progress[1]), maxValue)\r
+                               else:\r
+                                       print line\r
+                                       self.progressLog.append(line)\r
+                                       wx.CallAfter(self.statusText.SetLabel, line)\r
+                               if self.abort:\r
+                                       p.terminate()\r
+                                       wx.CallAfter(self.statusText.SetLabel, "Aborted by user.")\r
+                                       return\r
+                               line = p.stdout.readline()\r
+                       self.returnCode = p.wait()\r
+                       \r
+                       oldProfile = profile.getGlobalProfileString()\r
+                       put('machine_center_x', action.centerX)\r
+                       put('machine_center_y', action.centerY)\r
+                       put('clear_z', action.clearZ)\r
+                       \r
+                       if action == self.actionList[0]:\r
+                               resultFile.write(';TYPE:CUSTOM\n')\r
+                               resultFile.write(profile.getAlterationFileContents('start.gcode'))\r
+                       else:\r
+                               #reset the extrusion length, and move to the next object center.\r
+                               resultFile.write(';TYPE:CUSTOM\n')\r
+                               resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))\r
+                       resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))\r
+                       profile.loadGlobalProfileFromString(oldProfile)\r
+                       \r
+                       f = open(action.filename[: action.filename.rfind('.')] + "_export.project_tmp", "r")\r
+                       data = f.read(4096)\r
+                       while data != '':\r
+                               resultFile.write(data)\r
+                               data = f.read(4096)\r
+                       f.close()\r
+                       os.remove(action.filename[: action.filename.rfind('.')] + "_export.project_tmp")\r
+                       \r
+                       wx.CallAfter(self.progressGauge.SetValue, 10000)\r
+                       wx.CallAfter(self.progressGauge2.SetValue, self.actionList.index(action) + 1)\r
+               \r
+               resultFile.write(';TYPE:CUSTOM\n')\r
+               resultFile.write(profile.getAlterationFileContents('end.gcode'))\r
+               resultFile.close()\r
+\r
 def main():\r
        app = wx.App(False)\r
        projectPlanner().Show(True)\r
index 66dc8ea9ecff845b06f7c2d35185d6b2841cf25b..55fc7f188d079c23577568bfc0d438a8a082247e 100644 (file)
@@ -115,17 +115,16 @@ def getGlobalProfileString():
        return '#'.join(ret)\r
 \r
 def getProfileSetting(name):\r
-       if name in profileDefaultSettings:\r
-               default = profileDefaultSettings[name]\r
-       else:\r
-               print "Missing default setting for: '" + name + "'"\r
-               profileDefaultSettings[name] = ''\r
-               default = ''\r
-       \r
        #Check if we have a configuration file loaded, else load the default.\r
        if not globals().has_key('globalProfileParser'):\r
                loadGlobalProfile(getDefaultProfilePath())\r
        if not globalProfileParser.has_option('profile', name):\r
+               if name in profileDefaultSettings:\r
+                       default = profileDefaultSettings[name]\r
+               else:\r
+                       print "Missing default setting for: '" + name + "'"\r
+                       profileDefaultSettings[name] = ''\r
+                       default = ''\r
                if not globalProfileParser.has_section('profile'):\r
                        globalProfileParser.add_section('profile')\r
                globalProfileParser.set('profile', name, str(default))\r