diff --git a/Cura/cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py b/Cura/cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py index f018e0c6..eb363a8c 100644 --- a/Cura/cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py +++ b/Cura/cura_sf/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py @@ -406,9 +406,10 @@ class CoolSkein: def setMultiplier(self, remainingOrbitTime): 'Set the feed and flow rate multiplier.' layerTimeActive = self.getLayerTimeActive() - self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive)) - - + if remainingOrbitTime + layerTimeActive > 0.00001: + self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive)) + else: + self.multiplier = 1.0 def main(): 'Display the cool dialog.' diff --git a/Cura/gui/gcodeTextArea.py b/Cura/gui/gcodeTextArea.py index e6d85655..6cb108a1 100644 --- a/Cura/gui/gcodeTextArea.py +++ b/Cura/gui/gcodeTextArea.py @@ -13,21 +13,86 @@ class GcodeTextArea(wx.stc.StyledTextCtrl): fontSize = wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize() fontName = wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL).GetFaceName() self.SetStyleBits(5) - self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%s,size:%d" % (fontName, fontSize)) - self.StyleSetSpec(1, "fore:#008000,face:%s,size:%d" % (fontName, fontSize)) + self.StyleSetSpec(0, "face:%s,size:%d" % (fontName, fontSize)) + self.StyleSetSpec(1, "fore:#008000,face:%s,size:%d" % (fontName, fontSize)) + self.IndicatorSetStyle(0, wx.stc.STC_INDIC_TT) + self.IndicatorSetForeground(0, "#0000FF") + self.IndicatorSetStyle(1, wx.stc.STC_INDIC_SQUIGGLE) + self.IndicatorSetForeground(1, "#FF0000") + + #GCodes and MCodes as supported by Marlin + #GCode 21 is not really supported by Marlin, but we still do not report it as error as it's often used. + self.supportedGCodes = [0,1,2,3,4,21,28,90,91,92] + self.supportedMCodes = [17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,42,80,81,82,83,84,85,92,104,105,106,107,109,114,115,117,119,140,190,201,202,203,204,205,206,220,221,240,301,302,303,400,500,501,502,503,999] def OnStyle(self, e): lineNr = self.LineFromPosition(self.GetEndStyled()) while self.PositionFromLine(lineNr) > -1: line = self.GetLine(lineNr) - self.StartStyling(self.PositionFromLine(lineNr), 31) - self.SetStyling(self.LineLength(lineNr), wx.stc.STC_STYLE_DEFAULT) + start = self.PositionFromLine(lineNr) + length = self.LineLength(lineNr) + self.StartStyling(start, 255) + self.SetStyling(length, 0) if ';' in line: pos = line.index(';') - self.StartStyling(self.PositionFromLine(lineNr) + pos, 31) - self.SetStyling(self.LineLength(lineNr) - pos, 1) + self.StartStyling(start + pos, 31) + self.SetStyling(length - pos, 1) + length = pos + + pos = 0 + while pos < length: + if line[pos] in " \t\n\r": + while pos < length and line[pos] in " \t\n\r": + pos += 1 + else: + end = pos + while end < length and not line[end] in " \t\n\r": + end += 1 + if self.checkGCodePart(line[pos:end], start + pos): + self.StartStyling(start + pos, 0x20) + self.SetStyling(end - pos, 0x20) + pos = end lineNr += 1 + def checkGCodePart(self, part, pos): + if len(part) < 2: + self.StartStyling(pos, 0x40) + self.SetStyling(1, 0x40) + return True + if not part[0] in "GMXYZFESTBPIDCJ": + self.StartStyling(pos, 0x40) + self.SetStyling(1, 0x40) + return True + if part[1] == '{': + if part[-1] != '}': + return True + tag = part[2:-1] + if not profile.isProfileSetting(tag) and not profile.isPreference(tag): + self.StartStyling(pos + 2, 0x40) + self.SetStyling(len(tag), 0x40) + return True + elif part[0] in "GM": + try: + code = int(part[1:]) + except (ValueError): + self.StartStyling(pos + 1, 0x40) + self.SetStyling(len(part) - 1, 0x40) + return True + if part[0] == 'G': + if not code in self.supportedGCodes: + return True + if part[0] == 'M': + if not code in self.supportedMCodes: + return True + else: + try: + float(part[1:]) + except (ValueError): + self.StartStyling(pos + 1, 0x40) + self.SetStyling(len(part) - 1, 0x40) + return True + return False + def GetValue(self): return self.GetText() diff --git a/Cura/gui/projectPlanner.py b/Cura/gui/projectPlanner.py index 9b664ce5..a198a76d 100644 --- a/Cura/gui/projectPlanner.py +++ b/Cura/gui/projectPlanner.py @@ -285,9 +285,7 @@ class projectPlanner(wx.Frame): return (maxX - minX) + (maxY - minY) def OnSlice(self, e): - oldProfile = profile.getGlobalProfileString() - - put = profile.putProfileSetting + put = profile.setTempOverride put('model_multiply_x', '1') put('model_multiply_y', '1') @@ -319,7 +317,7 @@ class projectPlanner(wx.Frame): actionList.append(action) #Restore the old profile. - profile.loadGlobalProfileFromString(oldProfile) + profile.resetTempOverride() dlg=wx.FileDialog(self, "Save project gcode file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE) dlg.SetWildcard("GCode file (*.gcode)|*.gcode") @@ -670,6 +668,7 @@ class ProjectSliceProgressWindow(wx.Frame): self.sizer.Add(self.statusText, (0,0), flag=wx.ALIGN_CENTER) self.sizer.Add(self.progressGauge, (1, 0), flag=wx.EXPAND) self.sizer.Add(self.progressGauge2, (2, 0), flag=wx.EXPAND) + self.sizer.Add(self.abortButton, (3,0), flag=wx.ALIGN_CENTER) self.sizer.AddGrowableCol(0) self.sizer.AddGrowableRow(0) @@ -702,7 +701,7 @@ class ProjectSliceProgressWindow(wx.Frame): def OnRun(self): resultFile = open(self.resultFilename, "w") - put = profile.putProfileSetting + put = profile.setTempOverride for action in self.actionList: p = subprocess.Popen(action.sliceCmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) line = p.stdout.readline() @@ -727,7 +726,6 @@ class ProjectSliceProgressWindow(wx.Frame): line = p.stdout.readline() self.returnCode = p.wait() - oldProfile = profile.getGlobalProfileString() put('machine_center_x', action.centerX - self.extruderOffset[action.extruder].x) put('machine_center_y', action.centerY - self.extruderOffset[action.extruder].y) put('clear_z', action.clearZ) @@ -743,7 +741,7 @@ class ProjectSliceProgressWindow(wx.Frame): resultFile.write(';TYPE:CUSTOM\n') resultFile.write(profile.getAlterationFileContents('nextobject.gcode')) resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action)) - profile.loadGlobalProfileFromString(oldProfile) + profile.resetTempOverride() f = open(action.filename[: action.filename.rfind('.')] + "_export.project_tmp", "r") data = f.read(4096) @@ -762,7 +760,7 @@ class ProjectSliceProgressWindow(wx.Frame): resultFile.close() self.abort = True sliceTime = time.time() - self.sliceStartTime - wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %d:%d' % (sliceTime / 60, sliceTime % 60)) + wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %02d:%02d' % (sliceTime / 60, sliceTime % 60)) wx.CallAfter(self.abortButton.SetLabel, 'Close') def main(): diff --git a/Cura/gui/sliceProgessPanel.py b/Cura/gui/sliceProgessPanel.py index 17fc7857..3fd0ad02 100644 --- a/Cura/gui/sliceProgessPanel.py +++ b/Cura/gui/sliceProgessPanel.py @@ -59,21 +59,20 @@ class sliceProgessPanel(wx.Panel): if profile.getPreference('save_profile') == 'True': profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini") cmdList = [] - oldProfile = profile.getGlobalProfileString() for filename in self.filelist: idx = self.filelist.index(filename) print filename, idx if idx > 0: - profile.putProfileSetting('fan_enabled', 'False') - profile.putProfileSetting('skirt_line_count', '0') - profile.putProfileSetting('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx))) - profile.putProfileSetting('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx))) - profile.putProfileSetting('alternative_center', self.filelist[0]) + profile.setTempOverride('fan_enabled', 'False') + profile.setTempOverride('skirt_line_count', '0') + profile.setTempOverride('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx))) + profile.setTempOverride('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx))) + profile.setTempOverride('alternative_center', self.filelist[0]) if len(self.filelist) > 1: - profile.putProfileSetting('add_start_end_gcode', 'False') - profile.putProfileSetting('gcode_extension', 'multi_extrude_tmp') + profile.setTempOverride('add_start_end_gcode', 'False') + profile.setTempOverride('gcode_extension', 'multi_extrude_tmp') cmdList.append(sliceRun.getSliceCommand(filename)) - profile.loadGlobalProfileFromString(oldProfile) + profile.resetTempOverride() self.thread = WorkerThread(self, filelist, cmdList) def OnAbort(self, e): @@ -188,7 +187,10 @@ class WorkerThread(threading.Thread): resultFile.write(';TYPE:CUSTOM\n') resultFile.write(profile.getAlterationFileContents('start.gcode')) for filename in self.filelist: - files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r")) + if os.path.isfile(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp'): + files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r")) + else: + return currentExtruder = 0 resultFile.write('T%d\n' % (currentExtruder)) diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 96e1eb35..686a8d8b 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -67,6 +67,9 @@ profileDefaultSettings = { 'add_start_end_gcode': 'True', 'gcode_extension': 'gcode', + 'alternative_center': '', + 'clear_z': '0.0', + 'extruder': '0', } alterationDefault = { ####################################################################################### @@ -153,6 +156,7 @@ preferencesDefaultSettings = { ## Profile and preferences functions ######################################################### +## Profile functions def getDefaultProfilePath(): return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini")) @@ -188,17 +192,31 @@ def getGlobalProfileString(): p = [] alt = [] + tempDone = [] if globalProfileParser.has_section('profile'): for key in globalProfileParser.options('profile'): - p.append(key + "=" + globalProfileParser.get('profile', key)) + if key in tempOverride: + p.append(key + "=" + unicode(tempOverride[key])) + tempDone.append(key) + else: + p.append(key + "=" + globalProfileParser.get('profile', key)) if globalProfileParser.has_section('alterations'): for key in globalProfileParser.options('alterations'): - alt.append(key + "=" + globalProfileParser.get('alterations', key)) + if key in tempOverride: + p.append(key + "=" + tempOverride[key]) + tempDone.append(key) + else: + alt.append(key + "=" + globalProfileParser.get('alterations', key)) + for key in tempOverride: + if key not in tempDone: + p.append(key + "=" + unicode(tempOverride[key])) ret = '\b'.join(p) + '\f' + '\b'.join(alt) ret = base64.b64encode(zlib.compress(ret, 9)) return ret def getProfileSetting(name): + if name in tempOverride: + return unicode(tempOverride[name]) #Check if we have a configuration file loaded, else load the default. if not globals().has_key('globalProfileParser'): loadGlobalProfile(getDefaultProfilePath()) @@ -230,6 +248,12 @@ def putProfileSetting(name, value): globalProfileParser.add_section('profile') globalProfileParser.set('profile', name, str(value)) +def isProfileSetting(name): + if name in profileDefaultSettings: + return True + return False + +## Preferences functions global globalPreferenceParser globalPreferenceParser = None @@ -239,11 +263,12 @@ def getPreferencePath(): def getPreferenceFloat(name): try: return float(eval(getPreference(name), {}, {})) - except (ValueError, SyntaxError): return 0.0 def getPreference(name): + if name in tempOverride: + return unicode(tempOverride[name]) global globalPreferenceParser if globalPreferenceParser == None: globalPreferenceParser = ConfigParser.ConfigParser() @@ -273,6 +298,18 @@ def putPreference(name, value): globalPreferenceParser.set('preference', name, unicode(value).encode("utf-8")) globalPreferenceParser.write(open(getPreferencePath(), 'w')) +def isPreference(name): + if name in preferencesDefaultSettings: + return True + return False + +## Temp overrides for multi-extruder slicing and the project planner. +tempOverride = {} +def setTempOverride(name, value): + tempOverride[name] = value +def resetTempOverride(): + tempOverride = {} + ######################################################### ## Utility functions to calculate common profile values ######################################################### @@ -316,7 +353,11 @@ def replaceTagMatch(m): tag = m.group(0)[1:-1] if tag in ['print_speed', 'retraction_speed', 'travel_speed', 'max_z_speed', 'bottom_layer_speed', 'cool_min_feedrate']: return str(getProfileSettingFloat(tag) * 60) - return str(getProfileSettingFloat(tag)) + if isProfileSetting(tag): + return str(getProfileSettingFloat(tag)) + if isPreference(tag): + return str(getProfileSettingFloat(tag)) + return tag ### Get aleration raw contents. (Used internally in Cura) def getAlterationFile(filename):