1 from __future__ import absolute_import
4 import wx, sys, os, shutil, math, threading, subprocess, time, re, platform
6 from gui import taskbar
7 from gui import preferencesDialog
8 from util import profile
9 from util import sliceRun
10 from util import exporer
11 from util import gcodeInterpreter
13 class sliceProgessPanel(wx.Panel):
14 def __init__(self, mainWindow, parent, filelist):
15 wx.Panel.__init__(self, parent, -1)
16 self.mainWindow = mainWindow
17 self.filelist = filelist
20 box = wx.StaticBox(self, -1, filelist[0])
21 self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
23 mainSizer = wx.BoxSizer(wx.VERTICAL)
24 mainSizer.Add(self.sizer, 0, flag=wx.EXPAND)
26 self.statusText = wx.StaticText(self, -1, "Starting...")
27 self.progressGauge = wx.Gauge(self, -1)
28 self.progressGauge.SetRange(10000 * len(filelist))
29 self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
30 self.sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER )
31 self.sizer.Add(self.progressGauge, 2)
32 self.sizer.Add(self.abortButton, 0)
34 self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
36 self.SetSizer(mainSizer)
37 self.prevStep = 'start'
38 self.totalDoneFactor = 0.0
39 self.startTime = time.time()
40 if profile.getPreference('save_profile') == 'True':
41 profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
43 for filename in self.filelist:
44 idx = self.filelist.index(filename)
47 profile.setTempOverride('fan_enabled', 'False')
48 profile.setTempOverride('skirt_line_count', '0')
49 profile.setTempOverride('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
50 profile.setTempOverride('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
51 profile.setTempOverride('alternative_center', self.filelist[0])
52 if len(self.filelist) > 1:
53 profile.setTempOverride('add_start_end_gcode', 'False')
54 profile.setTempOverride('gcode_extension', 'multi_extrude_tmp')
55 cmdList.append(sliceRun.getSliceCommand(filename))
56 profile.resetTempOverride()
57 self.thread = WorkerThread(self, filelist, cmdList)
61 self.mainWindow.removeSliceProgress(self)
65 def OnShowGCode(self, e):
66 self.mainWindow.preview3d.loadModelFiles(self.filelist)
67 self.mainWindow.preview3d.setViewMode("GCode")
69 def OnShowLog(self, e):
70 LogWindow('\n'.join(self.progressLog))
72 def OnOpenFileLocation(self, e):
73 exporer.openExporer(sliceRun.getExportFilename(self.filelist[0]))
75 def OnCopyToSD(self, e):
76 if profile.getPreference('sdpath') == '':
77 wx.MessageBox("You need to configure your SD card drive first before you can copy files to it.\nOpening the preferences now.", 'No SD card drive.', wx.OK | wx.ICON_INFORMATION)
78 prefDialog = preferencesDialog.preferencesDialog(self.GetParent())
81 if profile.getPreference('sdpath') == '':
84 exportFilename = sliceRun.getExportFilename(self.filelist[0])
85 filename = os.path.basename(exportFilename)
86 if profile.getPreference('sdshortnames') == 'True':
87 filename = sliceRun.getShortFilename(filename)
89 shutil.copy(exportFilename, os.path.join(profile.getPreference('sdpath'), filename))
91 self.GetParent().preview3d.ShowWarningPopup("Failed to copy file to SD card.")
93 self.GetParent().preview3d.ShowWarningPopup("Copy finished, safely remove SD card?", self.OnSafeRemove)
95 def OnSafeRemove(self):
96 if platform.system() == "Windows":
97 cmd = "%s %s>NUL" % (os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'EjectMedia.exe')), profile.getPreference('sdpath'))
99 cmd = "umount %s > /dev/null 2>&1" % (profile.getPreference('sdpath'))
101 self.GetParent().preview3d.ShowWarningPopup("Safe remove failed.")
103 self.GetParent().preview3d.ShowWarningPopup("You can now eject the card.")
105 def OnSliceDone(self, result):
106 self.progressGauge.Destroy()
107 self.abortButton.Destroy()
108 self.progressLog = result.progressLog
109 self.logButton = wx.Button(self, -1, "Show Log")
110 self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
111 self.Bind(wx.EVT_BUTTON, self.OnShowLog, self.logButton)
112 self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
113 self.sizer.Add(self.logButton, 0)
114 if result.returnCode == 0:
115 status = "Ready: Filament: %.2fm %.2fg" % (result.gcode.extrusionAmount / 1000, result.gcode.calculateWeight() * 1000)
116 status += " Print time: %02d:%02d" % (int(result.gcode.totalMoveTimeMinute / 60), int(result.gcode.totalMoveTimeMinute % 60))
117 cost = result.gcode.calculateCost()
119 status += " Cost: %s" % (cost)
120 self.statusText.SetLabel(status)
121 if exporer.hasExporer():
122 self.openFileLocationButton = wx.Button(self, -1, "Open file location")
123 self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton)
124 self.sizer.Add(self.openFileLocationButton, 0)
125 if len(profile.getSDcardDrives()) > 0:
126 self.copyToSDButton = wx.Button(self, -1, "Copy to SDCard")
127 self.Bind(wx.EVT_BUTTON, self.OnCopyToSD, self.copyToSDButton)
128 self.sizer.Add(self.copyToSDButton, 0)
129 self.showButton = wx.Button(self, -1, "Show result")
130 self.Bind(wx.EVT_BUTTON, self.OnShowGCode, self.showButton)
131 self.sizer.Add(self.showButton, 0)
133 self.statusText.SetLabel("Something went wrong during slicing!")
134 self.sizer.Add(self.abortButton, 0)
138 if self.mainWindow.preview3d.loadReModelFiles(self.filelist):
139 self.mainWindow.preview3d.setViewMode("GCode")
140 taskbar.setBusy(self.GetParent(), False)
142 def SetProgress(self, stepName, layer, maxLayer):
143 if self.prevStep != stepName:
144 self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep]
145 newTime = time.time()
146 #print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName
147 self.startTime = newTime
148 self.prevStep = stepName
150 progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000
151 self.progressGauge.SetValue(int(progresValue))
152 taskbar.setProgress(self.GetParent(), int(progresValue), self.progressGauge.GetRange())
153 self.statusText.SetLabel("Preparing: processing %s [%d/%d]" % (stepName, layer, maxLayer))
155 class WorkerThread(threading.Thread):
156 def __init__(self, notifyWindow, filelist, cmdList):
157 threading.Thread.__init__(self)
158 self.filelist = filelist
159 self.notifyWindow = notifyWindow
160 self.cmdList = cmdList
165 p = sliceRun.startSliceCommandProcess(self.cmdList[self.fileIdx])
166 line = p.stdout.readline()
167 self.progressLog = []
169 while(len(line) > 0):
171 if line[0:9] == "Progress[" and line[-1:] == "]":
172 progress = line[9:-1].split(":")
173 if len(progress) > 2:
174 maxValue = int(progress[2])
175 wx.CallAfter(self.notifyWindow.SetProgress, progress[0], int(progress[1]), maxValue)
177 self.progressLog.append(line)
178 wx.CallAfter(self.notifyWindow.statusText.SetLabel, line)
179 if self.notifyWindow.abort:
181 wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Aborted by user.")
183 line = p.stdout.readline()
184 self.returnCode = p.wait()
186 if self.fileIdx == len(self.cmdList):
187 if len(self.filelist) > 1:
188 self._stitchMultiExtruder()
189 gcodeFilename = sliceRun.getExportFilename(self.filelist[0])
190 gcodefile = open(gcodeFilename, "a")
191 for logLine in self.progressLog:
192 if logLine.startswith('Model error('):
193 gcodefile.write(';%s\n' % (logLine))
195 wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Running plugins")
196 ret = profile.runPostProcessingPlugins(gcodeFilename)
198 self.progressLog.append(ret)
199 self.gcode = gcodeInterpreter.gcode()
200 self.gcode.load(gcodeFilename)
201 profile.replaceGCodeTags(gcodeFilename, self.gcode)
202 wx.CallAfter(self.notifyWindow.OnSliceDone, self)
206 def _stitchMultiExtruder(self):
208 resultFile = open(sliceRun.getExportFilename(self.filelist[0]), "w")
209 resultFile.write(';TYPE:CUSTOM\n')
210 resultFile.write(profile.getAlterationFileContents('start.gcode'))
211 for filename in self.filelist:
212 if os.path.isfile(sliceRun.getExportFilename(filename, 'multi_extrude_tmp')):
213 files.append(open(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'), "r"))
218 resultFile.write('T%d\n' % (currentExtruder))
227 if line.startswith(';LAYER:'):
230 lastZ = float(re.search('Z([^\s]+)', line).group(1))
232 nextExtruder = files.index(f)
233 resultFile.write(';LAYER:%d\n' % (layerNr))
234 resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
235 if nextExtruder != currentExtruder:
236 resultFile.write(';TYPE:CUSTOM\n')
237 profile.setTempOverride('extruder', nextExtruder)
238 resultFile.write(profile.getAlterationFileContents('switchExtruder.gcode'))
239 profile.resetTempOverride()
240 currentExtruder = nextExtruder
242 resultFile.write(line)
246 for filename in self.filelist:
247 os.remove(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'))
248 resultFile.write(';TYPE:CUSTOM\n')
249 resultFile.write(profile.getAlterationFileContents('end.gcode'))
252 class LogWindow(wx.Frame):
253 def __init__(self, logText):
254 super(LogWindow, self).__init__(None, title="Slice log")
255 self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY)
256 self.SetSize((400,300))