diff --git a/.gitignore b/.gitignore index 6ade96c..0c68aa2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.swp *.bak uploads +.DS_Store diff --git a/README.md b/README.md index 1d735c3..998ec60 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,19 @@ You can run Printrun directly from source, as there are no packages available ye `sudo apt-get install python-serial python-wxgtk2.8 python-pyglet` -### Fedora 15 and newer +### Fedora 17 and newer -You can run Printrun directly from source, as there are no packages available yet. Fetch and install the dependencies using +You can install Printrun from official packages. Install the whole package using + +`sudo yum install printrun` + +Or get only apps you need by + +`sudo yum install pronsole` or `pronterface` or `plater` + +Adding `--enablerepo updates-testing` option to `yum` might give you newer packages (but also not very tested). + +You can also run Printrun directly from source, if the packages are too old for you anyway, or you have Fedora 15 or 16. Fetch and install the dependencies using `sudo yum install pyserial wxpython pyglet` diff --git a/printcore.py b/printcore.py index 0849ee5..47a779c 100755 --- a/printcore.py +++ b/printcore.py @@ -461,12 +461,12 @@ if __name__ == '__main__': try: if statusreport: p.loud = False - sys.stdout.write("Progress: 00.0%") + sys.stdout.write("Progress: 00.0%\r") sys.stdout.flush() while p.printing: time.sleep(1) if statusreport: - sys.stdout.write("%02.1f%%\r" % (100 * float(p.queueindex) / len(p.mainqueue),) ) + sys.stdout.write("Progress: %02.1f%%\r" % (100 * float(p.queueindex) / len(p.mainqueue),) ) sys.stdout.flush() p.disconnect() sys.exit(0) diff --git a/printrun/bufferedcanvas.py b/printrun/bufferedcanvas.py index 85ad019..3e7049b 100644 --- a/printrun/bufferedcanvas.py +++ b/printrun/bufferedcanvas.py @@ -77,7 +77,7 @@ class BufferedCanvas(wx.Panel): ## General methods ## - def draw(self, dc): + def draw(self, dc, w, h): """ Stub: called when the canvas needs to be re-drawn. """ diff --git a/printrun/gcoder.py b/printrun/gcoder.py index 7062467..fffded9 100755 --- a/printrun/gcoder.py +++ b/printrun/gcoder.py @@ -47,10 +47,13 @@ class Line(object): if ";" in self.raw: self.raw = self.raw.split(";")[0].rstrip() self.split_raw = self.raw.split(" ") - self.command = self.split_raw[0].upper() + self.command = self.split_raw[0].upper() if not self.split_raw[0].startswith("n") else self.split_raw[1] self.is_move = self.command in ["G0", "G1"] def parse_coordinates(self, imperial): + # Not a G-line, we don't want to parse its arguments + if not self.command[0] == "G": + return if imperial: for bit in self.split_raw: code = bit[0] diff --git a/printrun/graph.py b/printrun/graph.py index daff989..bb426fc 100644 --- a/printrun/graph.py +++ b/printrun/graph.py @@ -23,14 +23,13 @@ class Graph(BufferedCanvas): '''A class to show a Graph with Pronterface.''' def __init__(self, parent, id, pos = wx.DefaultPosition, - size = wx.DefaultSize, style = 0): + size = wx.Size(150, 80), style = 0): # Forcing a no full repaint to stop flickering style = style | wx.NO_FULL_REPAINT_ON_RESIZE #call super function - #super(Graph, self).__init__(parent, id, pos, size, style) - BufferedCanvas.__init__(self, parent, id) + super(Graph, self).__init__(parent, id, pos, size, style) + #BufferedCanvas.__init__(self, parent, id) - self.SetSize(wx.Size(150, 80)) self.extruder0temps = [0] self.extruder0targettemps = [0] @@ -80,8 +79,7 @@ class Graph(BufferedCanvas): #b = gc.CreateLinearGradientBrush(0, 0, w, h, col1, col2) gc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 4)) - #gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(245, 245, 255, 252)))) - #gc.SetBrush(b) + gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(0, 0, 0, 0)))) gc.DrawRectangle(0, 0, self.width, self.height) #gc.SetBrush(wx.Brush(wx.Colour(245, 245, 255, 52))) diff --git a/printrun/gui.py b/printrun/gui.py index 123a8d4..b042c00 100644 --- a/printrun/gui.py +++ b/printrun/gui.py @@ -26,6 +26,7 @@ from printrun import gviz from printrun.xybuttons import XYButtons from printrun.zbuttons import ZButtons from printrun.graph import Graph +from printrun.pronterface_widgets import TempGauge def make_button(parent, label, callback, tooltip, container = None, size = wx.DefaultSize, style = 0): button = wx.Button(parent, -1, label, style = style, size = size) @@ -56,9 +57,9 @@ class LeftPane(wx.GridBagSizer): def __init__(self, root): super(LeftPane, self).__init__() llts = wx.BoxSizer(wx.HORIZONTAL) - self.Add(llts, pos = (0, 0), span = (1, 9)) + self.Add(llts, pos = (0, 0), span = (1, 6)) self.xyzsizer = XYZControlsSizer(root) - self.Add(self.xyzsizer, pos = (1, 0), span = (1, 8), flag = wx.ALIGN_CENTER) + self.Add(self.xyzsizer, pos = (1, 0), span = (1, 6), flag = wx.ALIGN_CENTER) for i in root.cpbuttons: btn = make_button(root.panel, i.label, root.procbutton, i.tooltip, style = wx.BU_EXACTFIT) @@ -84,7 +85,7 @@ class LeftPane(wx.GridBagSizer): root.monitorbox = wx.CheckBox(root.panel,-1, _("Watch")) root.monitorbox.SetToolTip(wx.ToolTip("Monitor Temperatures in Graph")) - self.Add(root.monitorbox, pos = (2, 6)) + self.Add(root.monitorbox, pos = (3, 5)) root.monitorbox.Bind(wx.EVT_CHECKBOX, root.setmonitor) self.Add(wx.StaticText(root.panel,-1, _("Heat:")), pos = (2, 0), span = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) @@ -164,9 +165,31 @@ class LeftPane(wx.GridBagSizer): root.zfeedc.SetBackgroundColour((180, 255, 180)) root.zfeedc.SetForegroundColour("black") + if root.display_gauges: + root.hottgauge = TempGauge(root.panel, size = (-1, 24), title = _("Heater:"), maxval = 300) + self.Add(root.hottgauge, pos = (6, 0), span = (1, 6), flag = wx.EXPAND) + root.bedtgauge = TempGauge(root.panel, size = (-1, 24), title = _("Bed:"), maxval = 150) + self.Add(root.bedtgauge, pos = (7, 0), span = (1, 6), flag = wx.EXPAND) + def hotendgauge_scroll_setpoint(e): + rot = e.GetWheelRotation() + if rot > 0: + root.do_settemp(str(root.hsetpoint + 1)) + elif rot < 0: + root.do_settemp(str(max(0, root.hsetpoint - 1))) + def bedgauge_scroll_setpoint(e): + rot = e.GetWheelRotation() + if rot > 0: + root.do_settemp(str(root.bsetpoint + 1)) + elif rot < 0: + root.do_settemp(str(max(0, root.bsetpoint - 1))) + root.hottgauge.Bind(wx.EVT_MOUSEWHEEL, hotendgauge_scroll_setpoint) + root.bedtgauge.Bind(wx.EVT_MOUSEWHEEL, bedgauge_scroll_setpoint) + self.Add(root.tempdisp, pos = (8, 0), span = (1, 6)) + else: + self.Add(root.tempdisp, pos = (6, 0), span = (1, 6)) + root.graph = Graph(root.panel, wx.ID_ANY) - self.Add(root.graph, pos = (3, 5), span = (3, 3)) - self.Add(root.tempdisp, pos = (6, 0), span = (1, 9)) + self.Add(root.graph, pos = (4, 5), span = (2, 1)) class VizPane(wx.BoxSizer): @@ -199,6 +222,7 @@ class LogPane(wx.BoxSizer): super(LogPane, self).__init__(wx.VERTICAL) root.lowerrsizer = self root.logbox = wx.TextCtrl(root.panel, style = wx.TE_MULTILINE, size = (350,-1)) + root.logbox.SetMinSize((100,-1)) root.logbox.SetEditable(0) self.Add(root.logbox, 1, wx.EXPAND) lbrs = wx.BoxSizer(wx.HORIZONTAL) @@ -223,7 +247,7 @@ class MainToolbar(wx.BoxSizer): root.serialport = wx.ComboBox(root.panel, -1, choices = root.scanserial(), - style = wx.CB_DROPDOWN, size = (150, 25)) + style = wx.CB_DROPDOWN, size = (-1, 25)) root.serialport.SetToolTip(wx.ToolTip("Select Port Printer is connected to")) root.rescanports() self.Add(root.serialport) @@ -263,10 +287,10 @@ class MainWindow(wx.Frame): self.mainsizer = wx.BoxSizer(wx.VERTICAL) self.uppersizer = MainToolbar(self) self.lowersizer = wx.BoxSizer(wx.HORIZONTAL) - self.lowersizer.Add(LeftPane(self)) + self.lowersizer.Add(LeftPane(self), 0) self.lowersizer.Add(VizPane(self), 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL) - self.lowersizer.Add(LogPane(self), 0, wx.EXPAND) - self.mainsizer.Add(self.uppersizer) + self.lowersizer.Add(LogPane(self), 1, wx.EXPAND) + self.mainsizer.Add(self.uppersizer, 0) self.mainsizer.Add(self.lowersizer, 1, wx.EXPAND) self.panel.SetSizer(self.mainsizer) self.status = self.CreateStatusBar() @@ -276,6 +300,12 @@ class MainWindow(wx.Frame): self.mainsizer.Layout() self.mainsizer.Fit(self) + # This prevents resizing below a reasonnable value + # We sum the lowersizer (left pane / viz / log) min size + # the toolbar height and the statusbar/menubar sizes + minsize = self.lowersizer.GetMinSize() # lower pane + minsize[1] += self.uppersizer.GetMinSize()[1] # toolbar height + self.SetMinSize(self.ClientToWindowSize(minsize)) # client to window # disable all printer controls until we connect to a printer self.pausebtn.Disable() diff --git a/printrun/gviz.py b/printrun/gviz.py index 11dac18..d52ec93 100755 --- a/printrun/gviz.py +++ b/printrun/gviz.py @@ -44,8 +44,8 @@ class window(wx.Frame): vbox.Add(self.p, 1, wx.EXPAND) panel.SetSizer(vbox) self.SetMinSize(self.ClientToWindowSize(vbox.GetMinSize())) - self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(200, 200, 1.2), id = 1) - self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(200, 200, 1/1.2), id = 2) + self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(-1, -1, 1.2), id = 1) + self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(-1, -1, 1/1.2), id = 2) self.Bind(wx.EVT_TOOL, lambda x:self.p.layerup(), id = 3) self.Bind(wx.EVT_TOOL, lambda x:self.p.layerdown(), id = 4) self.Bind(wx.EVT_TOOL, self.resetview, id = 5) @@ -123,6 +123,17 @@ class window(wx.Frame): elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1/1.2) class gviz(wx.Panel): + + # Mark canvas as dirty when setting showall + _showall = 0 + def _get_showall(self): + return self._showall + def _set_showall(self, showall): + if showall != self._showall: + self.dirty = 1 + self._showall = showall + showall = property(_get_showall, _set_showall) + def __init__(self, parent, size = (200, 200), build_dimensions = [200, 200, 100, 0, 0, 0], grid = (10, 50), extrusion_width = 0.5): wx.Panel.__init__(self, parent, -1, size = size) self.SetMinSize((150, 150)) @@ -202,18 +213,18 @@ class gviz(wx.Panel): pass def resize(self, event): - oldwidth, oldheight = max(1.0, self.size[0]), max(1.0, self.size[1]) - oldside = min(oldwidth, oldheight) - newwidth, newheight = self.GetClientSizeTuple() - newwidth, newheight = [max(1.0, newwidth), max(1.0, newheight)] - newside = min(newwidth, newheight) + oldside = max(1.0, min(self.size)) + self.size = self.GetClientSizeTuple() + newside = max(1.0, min(self.size)) + self.basescale = 2*[min(float(self.size[0])/self.build_dimensions[0], + float(self.size[1])/self.build_dimensions[1])] zoomratio = float(newside) / oldside - print newwidth, newheight - print zoomratio - self.size = self.GetClientSize() wx.CallAfter(self.zoom, 0, 0, zoomratio) def zoom(self, x, y, factor): + if x == -1 and y == -1: + side = min(self.size) + x = y = side / 2 self.scale = [s * factor for s in self.scale] self.translate = [ x - (x-self.translate[0]) * factor, @@ -291,14 +302,18 @@ class gviz(wx.Panel): def paint(self, event): dc = wx.PaintDC(self) if self.dirty: - self.repaint() self.dirty = 0 + self.repaint() dc.DrawBitmap(self.blitmap, 0, 0) def addfile(self, gcode): self.clear() self.add_parsed_gcodes(gcode.lines) + # FIXME : there's code duplication going on there, we should factor it (but + # the reason addgcode is not factored as a add_parsed_gcodes([gline]) is + # because when loading a file there's no hilight, so it simply lets us not + # do the if hilight: all the time for nothing when loading a lot of lines def add_parsed_gcodes(self, lines): def _y(y): return self.build_dimensions[1] - (y - self.build_dimensions[4]) @@ -312,10 +327,19 @@ class gviz(wx.Panel): target = self.lastpos[:] target[5] = 0.0 target[6] = 0.0 - if gline.x != None: target[0] = gline.x - if gline.y != None: target[1] = gline.y - if gline.z != None: target[2] = gline.z - if gline.e != None: target[3] = gline.e + if gline.relative: + if gline.x != None: target[0] += gline.x + if gline.y != None: target[1] += gline.y + if gline.z != None: target[2] += gline.z + else: + if gline.x != None: target[0] = gline.x + if gline.y != None: target[1] = gline.y + if gline.z != None: target[2] = gline.z + if gline.e != None: + if gline.relative_e: + target[3] += gline.e + else: + target[3] = gline.e if gline.f != None: target[4] = gline.f if gline.i != None: target[5] = gline.i if gline.j != None: target[6] = gline.j @@ -330,100 +354,88 @@ class gviz(wx.Panel): start_pos = self.lastpos[:] if gline.command in ["G0", "G1"]: - line = [ _x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]) ] - self.lines[z].append(line) + self.lines[z].append((_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]))) self.pens[z].append(self.mainpen if target[3] != self.lastpos[3] else self.travelpen) - self.lastpos = target - self.dirty = 1 - - if gline.command in ["G2", "G3"]: + elif gline.command in ["G2", "G3"]: + # startpos, endpos, arc center arc = [_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]), - _x(start_pos[0] + target[5]), _y(start_pos[1] + target[6]) ] # center + _x(start_pos[0] + target[5]), _y(start_pos[1] + target[6])] # FIXME : verify this works : why not reverse endpoints 4, 5 if gline.command == "G2": # clockwise, reverse endpoints arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1] self.arcs[z].append(arc) self.arcpens[z].append(self.arcpen) - self.lastpos = target - self.dirty = 1 + + self.lastpos = target + self.dirty = 1 + self.Refresh() def addgcode(self, gcode = "M105", hilight = 0): gcode = gcode.split("*")[0] gcode = gcode.split(";")[0] - gcode = gcode.lower().strip().split() + gcode = gcode.lower().strip() if not gcode: return - if gcode[0][0] == 'n': # not sure what this check is for ? - gcode.pop(0) - - def _readgcode(): - target = self.lastpos[:] - target[5]=0.0 - target[6]=0.0 - if hilight: - target = self.hilightpos[:] - for i in gcode: - if i[0]=="x": - target[0]=float(i[1:]) - elif i[0]=="y": - target[1]=float(i[1:]) - elif i[0]=="z": - target[2]=float(i[1:]) - elif i[0]=="e": - target[3]=float(i[1:]) - elif i[0]=="f": - target[4]=float(i[1:]) - elif i[0]=="i": - target[5]=float(i[1:]) - elif i[0]=="j": - target[6]=float(i[1:]) - if not hilight: - if not target[2] in self.lines.keys(): - self.lines[target[2]]=[] - self.pens[target[2]]=[] - self.arcs[target[2]]=[] - self.arcpens[target[2]]=[] - self.layers+=[target[2]] - return target + gline = gcoder.Line(gcode) + gline.parse_coordinates(False) def _y(y): - return self.build_dimensions[1]-(y-self.build_dimensions[4]) + return self.build_dimensions[1] - (y - self.build_dimensions[4]) def _x(x): - return x-self.build_dimensions[3] + return x - self.build_dimensions[3] start_pos = self.hilightpos[:] if hilight else self.lastpos[:] - if gcode[0] in [ "g0", "g1" ]: - target = _readgcode() - line = [ _x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]) ] - if not hilight: - self.lines[ target[2] ] += [line] - self.pens[ target[2] ] += [self.mainpen if target[3] != self.lastpos[3] else self.travelpen] - self.lastpos = target - else: - self.hilight += [line] - self.hilightpos = target - self.dirty = 1 + if gline.command not in ["G0", "G1", "G2", "G3"]: + return + + target = self.hilightpos[:] if hilight else self.lastpos[:] + target[5] = 0.0 + target[6] = 0.0 + if gline.x != None: target[0] = gline.x + if gline.y != None: target[1] = gline.y + if gline.z != None: target[2] = gline.z + if gline.e != None: target[3] = gline.e + if gline.f != None: target[4] = gline.f + if gline.i != None: target[5] = gline.i + if gline.j != None: target[6] = gline.j - if gcode[0] in [ "g2", "g3" ]: - target = _readgcode() - arc = [] - arc += [ _x(start_pos[0]), _y(start_pos[1]) ] - arc += [ _x(target[0]), _y(target[1]) ] - arc += [ _x(start_pos[0] + target[5]), _y(start_pos[1] + target[6]) ] # center - if gcode[0] == "g2": # clockwise, reverse endpoints + z = target[2] + if not hilight and z not in self.layers: + self.lines[z] = [] + self.pens[z] = [] + self.arcs[z] = [] + self.arcpens[z] = [] + self.layers.append(z) + + if gline.command in ["G0", "G1"]: + line = [_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1])] + if not hilight: + self.lines[z].append((_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]))) + self.pens[z].append(self.mainpen if target[3] != self.lastpos[3] else self.travelpen) + else: + self.hilight.append(line) + elif gline.command in ["G2", "G3"]: + # startpos, endpos, arc center + arc = [_x(start_pos[0]), _y(start_pos[1]), + _x(target[0]), _y(target[1]), + _x(start_pos[0] + target[5]), _y(start_pos[1] + target[6])] + if gline.command == "G2": # clockwise, reverse endpoints arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1] - if not hilight: - self.arcs[ target[2] ] += [arc] - self.arcpens[ target[2] ] += [self.arcpen] - self.lastpos = target + self.arcs[z].append(arc) + self.arcpens[z].append(self.arcpen) else: - self.hilightarcs += [arc] - self.hilightpos = target - self.dirty = 1 + self.hilightarcs.append(arc) + + if not hilight: + self.lastpos = target + else: + self.hilightpos = target + self.dirty = 1 + self.Refresh() if __name__ == '__main__': import sys diff --git a/printrun/pronterface_widgets.py b/printrun/pronterface_widgets.py index 5b3fd36..a40c682 100644 --- a/printrun/pronterface_widgets.py +++ b/printrun/pronterface_widgets.py @@ -211,6 +211,113 @@ class ButtonEdit(wx.Dialog): if self.name.GetValue()=="": self.name.SetValue(macro) +class TempGauge(wx.Panel): + + def __init__(self, parent, size = (200, 22), title = "", maxval = 240, gaugeColour = None): + wx.Panel.__init__(self, parent,-1, size = size) + self.Bind(wx.EVT_PAINT, self.paint) + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + self.width, self.height = size + self.title = title + self.max = maxval + self.gaugeColour = gaugeColour + self.value = 0 + self.setpoint = 0 + self.recalc() + + def recalc(self): + mmax = max(int(self.setpoint*1.05), self.max) + self.scale = float(self.width-2)/float(mmax) + self.ypt = max(16, int(self.scale*max(self.setpoint, self.max/6))) + + def SetValue(self, value): + self.value = value + wx.CallAfter(self.Refresh) + + def SetTarget(self, value): + self.setpoint = value + wx.CallAfter(self.Refresh) + + def interpolatedColour(self, val, vmin, vmid, vmax, cmin, cmid, cmax): + if val < vmin: return cmin + if val > vmax: return cmax + if val <= vmid: + lo, hi, val, valhi = cmin, cmid, val-vmin, vmid-vmin + else: + lo, hi, val, valhi = cmid, cmax, val-vmid, vmax-vmid + vv = float(val)/valhi + rgb = lo.Red()+(hi.Red()-lo.Red())*vv, lo.Green()+(hi.Green()-lo.Green())*vv, lo.Blue()+(hi.Blue()-lo.Blue())*vv + rgb = map(lambda x:x*0.8, rgb) + return wx.Colour(*map(int, rgb)) + + def paint(self, ev): + self.width, self.height = self.GetClientSizeTuple() + self.recalc() + x0, y0, x1, y1, xE, yE = 1, 1, self.ypt+1, 1, self.width+1-2, 20 + dc = wx.PaintDC(self) + dc.SetBackground(wx.Brush((255, 255, 255))) + dc.Clear() + cold, medium, hot = wx.Colour(0, 167, 223), wx.Colour(239, 233, 119), wx.Colour(210, 50.100) + gauge1, gauge2 = wx.Colour(255, 255, 210), (self.gaugeColour or wx.Colour(234, 82, 0)) + shadow1, shadow2 = wx.Colour(110, 110, 110), wx.Colour(255, 255, 255) + gc = wx.GraphicsContext.Create(dc) + # draw shadow first + # corners + gc.SetBrush(gc.CreateRadialGradientBrush(xE-7, 9, xE-7, 9, 8, shadow1, shadow2)) + gc.DrawRectangle(xE-7, 1, 8, 8) + gc.SetBrush(gc.CreateRadialGradientBrush(xE-7, 17, xE-7, 17, 8, shadow1, shadow2)) + gc.DrawRectangle(xE-7, 17, 8, 8) + gc.SetBrush(gc.CreateRadialGradientBrush(x0+6, 17, x0+6, 17, 8, shadow1, shadow2)) + gc.DrawRectangle(0, 17, x0+6, 8) + # edges + gc.SetBrush(gc.CreateLinearGradientBrush(xE-6, 0, xE+1, 0, shadow1, shadow2)) + gc.DrawRectangle(xE-7, 9, 8, 8) + gc.SetBrush(gc.CreateLinearGradientBrush(x0, yE-2, x0, yE+5, shadow1, shadow2)) + gc.DrawRectangle(x0+6, yE-2, xE-12, 7) + # draw gauge background + gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0, x1+1, y1, cold, medium)) + gc.DrawRoundedRectangle(x0, y0, x1+4, yE, 6) + gc.SetBrush(gc.CreateLinearGradientBrush(x1-2, y1, xE, y1, medium, hot)) + gc.DrawRoundedRectangle(x1-2, y1, xE-x1, yE, 6) + # draw gauge + width = 12 + w1 = y0+9-width/2 + w2 = w1+width + value = x0+max(10, min(self.width+1-2, int(self.value*self.scale))) + #gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0+3, x0, y0+15, gauge1, gauge2)) + #gc.SetBrush(gc.CreateLinearGradientBrush(0, 3, 0, 15, wx.Colour(255, 255, 255), wx.Colour(255, 90, 32))) + gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0+3, x0, y0+15, gauge1, self.interpolatedColour(value, x0, x1, xE, cold, medium, hot))) + val_path = gc.CreatePath() + val_path.MoveToPoint(x0, w1) + val_path.AddLineToPoint(value, w1) + val_path.AddLineToPoint(value+2, w1+width/4) + val_path.AddLineToPoint(value+2, w2-width/4) + val_path.AddLineToPoint(value, w2) + #val_path.AddLineToPoint(value-4, 10) + val_path.AddLineToPoint(x0, w2) + gc.DrawPath(val_path) + # draw setpoint markers + setpoint = x0+max(10, int(self.setpoint*self.scale)) + gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(0, 0, 0)))) + setp_path = gc.CreatePath() + setp_path.MoveToPoint(setpoint-4, y0) + setp_path.AddLineToPoint(setpoint+4, y0) + setp_path.AddLineToPoint(setpoint, y0+5) + setp_path.MoveToPoint(setpoint-4, yE) + setp_path.AddLineToPoint(setpoint+4, yE) + setp_path.AddLineToPoint(setpoint, yE-5) + gc.DrawPath(setp_path) + # draw readout + text = u"T\u00B0 %u/%u"%(self.value, self.setpoint) + #gc.SetFont(gc.CreateFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE)) + #gc.DrawText(text, 29,-2) + gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE)) + gc.DrawText(self.title, x0+19, y0+4) + gc.DrawText(text, x0+119, y0+4) + gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))) + gc.DrawText(self.title, x0+18, y0+3) + gc.DrawText(text, x0+118, y0+3) + class SpecialButton(object): label = None diff --git a/printrun/xybuttons.py b/printrun/xybuttons.py index 0f6865e..3be412f 100644 --- a/printrun/xybuttons.py +++ b/printrun/xybuttons.py @@ -60,8 +60,7 @@ class XYButtons(BufferedCanvas): self.bgcolor.SetFromName(bgcolor) self.bgcolormask = wx.Colour(self.bgcolor.Red(), self.bgcolor.Green(), self.bgcolor.Blue(), 128) - BufferedCanvas.__init__(self, parent, ID) - self.SetSize(self.bg_bmp.GetSize()) + BufferedCanvas.__init__(self, parent, ID, size=self.bg_bmp.GetSize()) # Set up mouse and keyboard event capture self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) diff --git a/printrun/zbuttons.py b/printrun/zbuttons.py index 1b79f40..101d1a4 100644 --- a/printrun/zbuttons.py +++ b/printrun/zbuttons.py @@ -46,9 +46,7 @@ class ZButtons(BufferedCanvas): self.bgcolor.SetFromName(bgcolor) self.bgcolormask = wx.Colour(self.bgcolor.Red(), self.bgcolor.Green(), self.bgcolor.Blue(), 128) - BufferedCanvas.__init__(self, parent, ID) - - self.SetSize(wx.Size(59, 244)) + BufferedCanvas.__init__(self, parent, ID, size=wx.Size(59, 244)) # Set up mouse and keyboard event capture self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) diff --git a/pronsole.py b/pronsole.py index dfa93d7..96ca97c 100755 --- a/pronsole.py +++ b/pronsole.py @@ -1207,12 +1207,12 @@ class pronsole(cmd.Cmd): self.log("home e - set extruder position to zero (Using G92)") self.log("home xyze - homes all axes and zeroes the extruder (Using G28 and G92)") - def parse_cmdline(self, args): - parser = argparse.ArgumentParser(description = 'Printrun 3D printer interface') + def add_cmdline_arguments(self, parser): parser.add_argument('-c','--conf','--config', help = _("load this file on startup instead of .pronsolerc ; you may chain config files, if so settings auto-save will use the last specified file"), action = "append", default = []) parser.add_argument('-e','--execute', help = _("executes command after configuration/.pronsolerc is loaded ; macros/settings from these commands are not autosaved"), action = "append", default = []) parser.add_argument('filename', nargs='?', help = _("file to load")) - args = parser.parse_args() + + def process_cmdline_arguments(self, args): for config in args.conf: self.load_rc(config) if not self.rc_loaded: @@ -1224,6 +1224,12 @@ class pronsole(cmd.Cmd): if args.filename: self.do_load(args.filename) + def parse_cmdline(self, args): + parser = argparse.ArgumentParser(description = 'Printrun 3D printer interface') + self.add_cmdline_arguments(parser) + args = parser.parse_args() + self.process_cmdline_arguments(args) + # We replace this function, defined in cmd.py . # It's default behavior with reagrds to Ctr-C # and Ctr-D doesn't make much sense... diff --git a/pronterface.py b/pronterface.py index 4c377bf..9770e00 100755 --- a/pronterface.py +++ b/pronterface.py @@ -198,15 +198,23 @@ class PronterWindow(MainWindow, pronsole.pronsole): if self.filename is not None: self.do_load(self.filename) + def add_cmdline_arguments(self, parser): + pronsole.pronsole.add_cmdline_arguments(self, parser) + parser.add_argument('-g','--gauges', help = _("display graphical temperature gauges in addition to the temperatures graph"), action = "store_true") + + def process_cmdline_arguments(self, args): + pronsole.pronsole.process_cmdline_arguments(self, args) + self.display_gauges = args.gauges + def startcb(self): self.starttime = time.time() print "Print Started at: " + format_time(self.starttime) def endcb(self): if self.p.queueindex == 0: - print "Print ended at: " + format_time(time.time()) print_duration = int(time.time () - self.starttime + self.extra_print_time) - print "and took: " + format_duration(print_duration) + print _("Print ended at: %(end_time)s and took %(duration)s") % {"end_time": format_time(time.time()), + "duration": format_duration(print_duration)} wx.CallAfter(self.pausebtn.Disable) wx.CallAfter(self.printbtn.SetLabel, _("Print")) @@ -239,7 +247,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): if "G1" in line: if "Z" in line: try: - layer = float(line.split("Z")[1].split()[0]) + layer = float(line.split("Z")[1].split()[0].split("*")[0]) if layer != self.curlayer: self.curlayer = layer self.gviz.hilight = [] @@ -256,6 +264,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): if "S" in line: try: temp = float(line.split("S")[1].split("*")[0]) + if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp) wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp) except: pass @@ -267,6 +276,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): if "S" in line: try: temp = float(line.split("S")[1].split("*")[0]) + if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp) wx.CallAfter(self.graph.SetBedTargetTemperature, temp) except: pass @@ -293,6 +303,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): def setbedgui(self, f): self.bsetpoint = f + if self.display_gauges: self.bedtgauge.SetTarget(int(f)) wx.CallAfter(self.graph.SetBedTargetTemperature, int(f)) if f>0: wx.CallAfter(self.btemp.SetValue, str(f)) @@ -312,6 +323,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): def sethotendgui(self, f): self.hsetpoint = f + if self.display_gauges: self.hottgauge.SetTarget(int(f)) wx.CallAfter(self.graph.SetExtruder0TargetTemperature, int(f)) if f > 0: wx.CallAfter(self.htemp.SetValue, str(f)) @@ -591,7 +603,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): wx.CallAfter(self.btemp.SetInsertionPoint, 0) def showwin(self, event): - if(self.f is not None): + if self.f is not None: self.gwindow.Show(True) self.gwindow.SetToolTip(wx.ToolTip("Mousewheel zooms the display\nShift / Mousewheel scrolls layers")) self.gwindow.Raise() @@ -1015,8 +1027,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): try: self.logbox.AppendText(text) except: - print "attempted to write invalid text to console" - pass + print _("Attempted to write invalid text to console, which could be due to an invalid baudrate") def setloud(self,e): self.p.loud=e.IsChecked() @@ -1034,15 +1045,22 @@ class PronterWindow(MainWindow, pronsole.pronsole): def clearOutput(self, e): self.logbox.Clear() + def update_tempdisplay(self): + try: + hotend_temp = parse_temperature_report(self.tempreport, "T:") + wx.CallAfter(self.graph.SetExtruder0Temperature, hotend_temp) + if self.display_gauges: wx.CallAfter(self.hottgauge.SetValue, hotend_temp) + bed_temp = parse_temperature_report(self.tempreport, "B:") + wx.CallAfter(self.graph.SetBedTemperature, bed_temp) + if self.display_gauges: wx.CallAfter(self.bedtgauge.SetValue, bed_temp) + except: + traceback.print_exc() + def statuschecker(self): while self.statuscheck: string = "" wx.CallAfter(self.tempdisp.SetLabel, self.tempreport.strip().replace("ok ", "")) - try: - wx.CallAfter(self.graph.SetExtruder0Temperature, parse_temperature_report(self.tempreport, "T:")) - wx.CallAfter(self.graph.SetBedTemperature, parse_temperature_report(self.tempreport, "B:")) - except: - pass + self.update_tempdisplay() fractioncomplete = 0.0 if self.sdprinting: fractioncomplete = float(self.percentdone / 100.0) @@ -1103,11 +1121,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): if "T:" in l: self.tempreport = l wx.CallAfter(self.tempdisp.SetLabel, self.tempreport.strip().replace("ok ", "")) - try: - wx.CallAfter(self.graph.SetExtruder0Temperature, parse_temperature_report(self.tempreport, "T:")) - wx.CallAfter(self.graph.SetBedTemperature, parse_temperature_report(self.tempreport, "B:")) - except: - traceback.print_exc() + self.update_tempdisplay() tstring = l.rstrip() #print tstring if (tstring!="ok") and (tstring!="wait") and ("ok T:" not in tstring) and (not self.p.loud): @@ -1286,15 +1300,10 @@ class PronterWindow(MainWindow, pronsole.pronsole): print _("the print goes from %f mm to %f mm in Y\nand is %f mm wide\n") % (gcode.ymin, gcode.ymax, gcode.depth) print _("the print goes from %f mm to %f mm in Z\nand is %f mm high\n") % (gcode.zmin, gcode.zmax, gcode.height) print _("Estimated duration (pessimistic): "), gcode.estimate_duration() - #import time - #t0 = time.time() self.gviz.clear() self.gwindow.p.clear() - self.gviz.addfile(self.f) - #print "generated 2d view in %f s"%(time.time()-t0) - #t0 = time.time() - self.gwindow.p.addfile(self.f) - #print "generated 3d view in %f s"%(time.time()-t0) + self.gviz.addfile(gcode) + self.gwindow.p.addfile(gcode) self.gviz.showall = 1 wx.CallAfter(self.gviz.Refresh) @@ -1516,5 +1525,5 @@ if __name__ == '__main__': main.Show() try: app.MainLoop() - except: + except KeyboardInterrupt: pass