Commit 2337cb12 authored by D1plo1d's avatar D1plo1d

Merge branch 'experimental' of github.com:kliment/Printrun into experimental

parents 313a51f3 b91265ee
......@@ -74,6 +74,7 @@ class printcore():
self.tempcb = None #impl (wholeline)
self.recvcb = None #impl (wholeline)
self.sendcb = None #impl (wholeline)
self.preprintsendcb = None #impl (wholeline)
self.printsendcb = None #impl (wholeline)
self.layerchangecb = None #impl (wholeline)
self.errorcb = None #impl (wholeline)
......@@ -414,7 +415,9 @@ class printcore():
if self.startcb:
#callback for printing started
try: self.startcb(resuming)
except: pass
except:
print "Print start callback failed with:"
traceback.print_exc(file = sys.stdout)
while self.printing and self.printer and self.online:
self._sendnext()
self.sentlines = {}
......@@ -423,10 +426,12 @@ class printcore():
if self.endcb:
#callback for printing done
try: self.endcb()
except: pass
except:
print "Print end callback failed with:"
traceback.print_exc(file = sys.stdout)
except:
print "Print thread died due to the following error:"
traceback.print_exc()
traceback.print_exc(file = sys.stdout)
finally:
self.print_thread = None
self._start_sender()
......@@ -460,16 +465,23 @@ class printcore():
return
if self.printing and self.queueindex < len(self.mainqueue):
(layer, line) = self.mainqueue.idxs(self.queueindex)
gline = self.mainqueue.all_layers[layer].lines[line]
gline = self.mainqueue.all_layers[layer][line]
if self.layerchangecb and self.queueindex > 0:
(prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1)
if prev_layer != layer:
try: self.layerchangecb(layer)
except: traceback.print_exc()
if self.preprintsendcb:
gline = self.preprintsendcb(gline)
if gline == None:
self.queueindex += 1
self.clear = True
return
tline = gline.raw
if tline.lstrip().startswith(";@"): # check for host command
self.processHostCommand(tline)
self.queueindex += 1
self.clear = True
return
tline = tline.split(";")[0]
......
......@@ -69,8 +69,9 @@ class GCodeAnalyzer():
def Analyze(self, gcode):
gline = gcoder.Line(gcode)
split_raw = gcoder.split(gline)
if gline.command.startswith(";@"): return # code is a host command
gline.parse_coordinates(self.imperial)
gcoder.parse_coordinates(gline, split_raw, self.imperial)
code_g = int(gline.command[1:]) if gline.command.startswith("G") else None
code_m = int(gline.command[1:]) if gline.command.startswith("M") else None
......
# This file is part of the Printrun suite.
#
# Printrun is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Printrun is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx
from printrun import gviz
from printrun_utils import imagefile, install_locale
install_locale('pronterface')
class ExcluderWindow(gviz.GvizWindow):
def __init__(self, excluder, *args, **kwargs):
super(ExcluderWindow, self).__init__(*args, **kwargs)
self.SetTitle(_("Part excluder: draw rectangles where print instructions should be ignored"))
self.toolbar.AddLabelTool(128, " " + _("Reset selection"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset selection"), longHelp = "")
self.Bind(wx.EVT_TOOL, self.reset_selection, id = 128)
self.parent = excluder
self.p.paint_overlay = self.paint_selection
self.p.layerup()
def real_to_gcode(self, x, y):
return (x + self.p.build_dimensions[3],
self.p.build_dimensions[4] + self.p.build_dimensions[1] - y)
def gcode_to_real(self, x, y):
return (x - self.p.build_dimensions[3],
self.p.build_dimensions[1] - (y - self.p.build_dimensions[4]))
def mouse(self, event):
if event.ButtonUp(wx.MOUSE_BTN_LEFT) or event.ButtonUp(wx.MOUSE_BTN_RIGHT):
self.initpos = None
elif event.Dragging() and event.RightIsDown():
e = event.GetPositionTuple()
if not self.initpos or not hasattr(self, "basetrans"):
self.initpos = e
self.basetrans = self.p.translate
self.p.translate = [self.basetrans[0] + (e[0] - self.initpos[0]),
self.basetrans[1] + (e[1] - self.initpos[1])]
self.p.dirty = 1
wx.CallAfter(self.p.Refresh)
elif event.Dragging() and event.LeftIsDown():
x, y = event.GetPositionTuple()
if not hasattr(self, "basetrans"):
self.basetrans = self.p.translate
x = (x - self.basetrans[0]) / self.p.scale[0]
y = (y - self.basetrans[1]) / self.p.scale[1]
x, y = self.real_to_gcode(x, y)
if not self.initpos:
self.initpos = (x, y)
self.basetrans = self.p.translate
self.parent.rectangles.append((0, 0, 0, 0))
else:
pos = (x, y)
x0 = min(self.initpos[0], pos[0])
y0 = min(self.initpos[1], pos[1])
x1 = max(self.initpos[0], pos[0])
y1 = max(self.initpos[1], pos[1])
self.parent.rectangles[-1] = (x0, y0, x1, y1)
wx.CallAfter(self.p.Refresh)
else:
event.Skip()
def _line_scaler(self, orig):
x0, y0 = self.gcode_to_real(orig[0], orig[1])
x0 = self.p.scale[0]*x0 + self.p.translate[0]
y0 = self.p.scale[1]*y0 + self.p.translate[1]
x1, y1 = self.gcode_to_real(orig[2], orig[3])
x1 = self.p.scale[0]*x1 + self.p.translate[0]
y1 = self.p.scale[1]*y1 + self.p.translate[1]
width = max(x0, x1) - min(x0, x1) + 1
height = max(y0, y1) - min(y0, y1) + 1
return (min(x0, x1), min(y0, y1), width, height,)
def paint_selection(self, dc):
dc = wx.GCDC(dc)
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleList([self._line_scaler(rect) for rect in self.parent.rectangles],
None, wx.Brush((200, 200, 200, 150)))
def reset_selection(self, event):
self.parent.rectangles = []
wx.CallAfter(self.p.Refresh)
class Excluder(object):
def __init__(self):
self.rectangles = []
self.window = None
def pop_window(self, gcode, *args, **kwargs):
if not self.window:
self.window = ExcluderWindow(self, *args, **kwargs)
self.window.p.addfile(gcode)
self.window.p.layerup()
self.window.Bind(wx.EVT_CLOSE, self.close_window)
self.window.Show()
else:
self.window.Show()
self.window.Raise()
def close_window(self, event = None):
if self.window:
self.window.Destroy()
self.window = None
if __name__ == '__main__':
import sys
gcode = gcoder.GCode(open(sys.argv[1]))
app = wx.App(False)
ex = Excluder()
ex.pop_window(gcode)
app.MainLoop()
......@@ -20,66 +20,67 @@ import math
import datetime
from array import array
gcode_parsed_args = ["x", "y", "e", "f", "z", "p", "i", "j", "s"]
gcode_exp = re.compile("\([^\(\)]*\)|;.*|[/\*].*\n|[a-z][-+]?[0-9]*\.?[0-9]*")
m114_exp = re.compile("\([^\(\)]*\)|[/\*].*\n|[A-Z]:?[-+]?[0-9]*\.?[0-9]*")
gcode_parsed_args = ["x", "y", "e", "f", "z", "i", "j"]
gcode_parsed_nonargs = ["g", "t", "m", "n"]
to_parse = "".join(gcode_parsed_args + gcode_parsed_nonargs)
gcode_exp = re.compile("\([^\(\)]*\)|;.*|[/\*].*\n|([%s])([-+]?[0-9]*\.?[0-9]*)" % to_parse)
m114_exp = re.compile("\([^\(\)]*\)|[/\*].*\n|([XYZ]):?([-+]?[0-9]*\.?[0-9]*)")
specific_exp = "(?:\([^\(\)]*\))|(?:;.*)|(?:[/\*].*\n)|(%s[-+]?[0-9]*\.?[0-9]*)"
move_gcodes = ["G0", "G1", "G2", "G3"]
class PyLine(object):
__slots__ = ('x','y','z','e','f','i','j','s','p',
__slots__ = ('x','y','z','e','f','i','j',
'raw','split_raw',
'command','is_move',
'relative','relative_e',
'current_x', 'current_y', 'current_z', 'extruding', 'current_tool',
'gcview_end_vertex')
def __init__(self, l):
self.raw = l
def __getattr__(self, name):
return None
try:
import gcoder_line
LineBase = gcoder_line.GLine
Line = gcoder_line.GLine
except ImportError:
LineBase = PyLine
class Line(LineBase):
__slots__ = ()
def __init__(self, l):
super(Line, self).__init__()
self.raw = l
self.split_raw = gcode_exp.findall(self.raw.lower())
self.command = self.split_raw[0].upper() if not self.split_raw[0].startswith("n") else self.split_raw[1].upper()
self.is_move = self.command in move_gcodes
def parse_coordinates(self, imperial = False, force = False):
# Not a G-line, we don't want to parse its arguments
if not force and not self.command[0] == "G":
return
if imperial:
for bit in self.split_raw:
code = bit[0]
if code in gcode_parsed_args and len(bit) > 1:
setattr(self, code, 25.4*float(bit[1:]))
else:
for bit in self.split_raw:
code = bit[0]
if code in gcode_parsed_args and len(bit) > 1:
setattr(self, code, float(bit[1:]))
del self.split_raw
def __repr__(self):
return self.raw
class Layer(object):
Line = PyLine
def find_specific_code(line, code):
exp = specific_exp % code
bits = [bit for bit in re.findall(exp, line.raw) if bit]
if not bits: return None
else: return float(bits[0][1:])
def S(line):
return find_specific_code(line, "S")
def P(line):
return find_specific_code(line, "P")
def split(line):
split_raw = gcode_exp.findall(line.raw.lower())
command = split_raw[0] if split_raw[0][0] != "n" else split_raw[1]
line.command = command[0].upper() + command[1]
line.is_move = line.command in move_gcodes
return split_raw
def parse_coordinates(line, split_raw, imperial = False, force = False):
# Not a G-line, we don't want to parse its arguments
if not force and line.command[0] != "G":
return
unit_factor = 25.4 if imperial else 1
for bit in split_raw:
code = bit[0]
if code not in gcode_parsed_nonargs and bit[1]:
setattr(line, code, unit_factor*float(bit[1]))
lines = None
duration = None
class Layer(list):
def __init__(self, lines):
self.lines = lines
__slots__ = ("duration")
def _preprocess(self, current_x, current_y, current_z):
xmin = float("inf")
......@@ -91,7 +92,7 @@ class Layer(object):
relative = False
relative_e = False
for line in self.lines:
for line in self:
if not line.is_move and line.command != "G92":
continue
if line.is_move:
......@@ -178,9 +179,9 @@ class GCode(object):
self.lines.append(gline)
self._preprocess_lines([gline])
self._preprocess_extrusion([gline])
self.append_layer.lines.append(gline)
self.append_layer.append(gline)
self.layer_idxs.append(self.append_layer_id)
self.line_idxs.append(len(self.append_layer.lines))
self.line_idxs.append(len(self.append_layer))
return gline
def _preprocess_lines(self, lines = None):
......@@ -192,6 +193,9 @@ class GCode(object):
relative_e = self.relative_e
current_tool = self.current_tool
for line in lines:
split_raw = split(line)
if not line.command:
continue
if line.is_move:
line.relative = relative
line.relative_e = relative_e
......@@ -213,7 +217,7 @@ class GCode(object):
elif line.command[0] == "T":
current_tool = int(line.command[1:])
if line.command[0] == "G":
line.parse_coordinates(imperial)
parse_coordinates(line, split_raw, imperial)
self.imperial = imperial
self.relative = relative
self.relative_e = relative_e
......@@ -283,7 +287,7 @@ class GCode(object):
if cur_lines:
all_layers.append(Layer(cur_lines))
old_lines = layers.pop(prev_z, [])
old_lines = layers.get(prev_z, [])
old_lines += cur_lines
layers[prev_z] = old_lines
......@@ -359,7 +363,7 @@ class GCode(object):
# get device caps from firmware: max speed, acceleration/axis (including extruder)
# calculate the maximum move duration accounting for above ;)
for layer in self.all_layers:
for line in layer.lines:
for line in layer:
if line.command not in ["G1", "G0", "G4"]:
continue
if line.command == "G4":
......@@ -407,7 +411,8 @@ def main():
if len(sys.argv) < 2:
print "usage: %s filename.gcode" % sys.argv[0]
return
print "Line object size:", sys.getsizeof(Line("G0 X0"))
gcode = GCode(open(sys.argv[1]))
print "Dimensions:"
......
--- printrun/gcoder_line.c 2013-06-15 16:08:53.260081109 +0200
+++ printrun/gcoder_line.c 2013-06-15 16:08:57.083439793 +0200
@@ -3945,2 +3945,4 @@ static int __Pyx_InitGlobals(void) {
+#include "gcoder_line_extra.h"
+
#if PY_MAJOR_VERSION < 3
@@ -4032,2 +4034,7 @@ PyMODINIT_FUNC PyInit_gcoder_line(void)
/*--- Execution code ---*/
+ nysets_heapdefs[0].type = &__pyx_type_8printrun_11gcoder_line_GLine;
+ if (PyDict_SetItemString(__pyx_d,
+ "_NyHeapDefs_",
+ PyCObject_FromVoidPtrAndDesc(&nysets_heapdefs, "NyHeapDef[] v1.0", 0)) < 0)
+{__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
......@@ -36,20 +36,18 @@ cdef enum BitPos:
pos_f = 1 << 4
pos_i = 1 << 5
pos_j = 1 << 6
pos_s = 1 << 7
pos_p = 1 << 8
pos_is_move = 1 << 9
pos_relative = 1 << 10
pos_relative_e = 1 << 11
pos_extruding = 1 << 12
pos_current_x = 1 << 13
pos_current_y = 1 << 14
pos_current_z = 1 << 15
pos_current_tool = 1 << 16
pos_raw = 1 << 17
pos_split_raw = 1 << 18
pos_command = 1 << 19
pos_gcview_end_vertex = 1 << 20
pos_is_move = 1 << 7
pos_relative = 1 << 8
pos_relative_e = 1 << 9
pos_extruding = 1 << 10
pos_current_x = 1 << 11
pos_current_y = 1 << 12
pos_current_z = 1 << 13
pos_current_tool = 1 << 14
pos_raw = 1 << 15
pos_command = 1 << 16
pos_gcview_end_vertex = 1 << 17
# WARNING: don't use bits 24 to 31 as we store current_tool there
cdef inline uint32_t has_var(uint32_t status, uint32_t pos):
return status & pos
......@@ -60,16 +58,14 @@ cdef inline uint32_t set_has_var(uint32_t status, uint32_t pos):
cdef inline uint32_t unset_has_var(uint32_t status, uint32_t pos):
return status & ~pos
cdef class GLine(object):
cdef class GLine:
cdef char* _raw
cdef char* _command
cdef object _split_raw
cdef float _x, _y, _z, _e, _f, _i, _j, _s, _p
cdef float _x, _y, _z, _e, _f, _i, _j
cdef float _current_x, _current_y, _current_z
cdef uint32_t _gcview_end_vertex
cdef uint32_t _status
cdef char _current_tool
__slots__ = ()
......@@ -78,6 +74,9 @@ cdef class GLine(object):
self._raw = NULL
self._command = NULL
def __init__(self, line):
self.raw = line
def __dealloc__(self):
if self._raw != NULL: free(self._raw)
if self._command != NULL: free(self._command)
......@@ -131,20 +130,6 @@ cdef class GLine(object):
def __set__(self, value):
self._j = value
self._status = set_has_var(self._status, pos_j)
property s:
def __get__(self):
if has_var(self._status, pos_s): return self._s
else: return None
def __set__(self, value):
self._s = value
self._status = set_has_var(self._status, pos_s)
property p:
def __get__(self):
if has_var(self._status, pos_p): return self._p
else: return None
def __set__(self, value):
self._p = value
self._status = set_has_var(self._status, pos_p)
property is_move:
def __get__(self):
if has_var(self._status, pos_is_move): return True
......@@ -196,10 +181,10 @@ cdef class GLine(object):
self._status = set_has_var(self._status, pos_current_z)
property current_tool:
def __get__(self):
if has_var(self._status, pos_current_tool): return self._current_tool
if has_var(self._status, pos_current_tool): return self._status >> 24
else: return None
def __set__(self, value):
self._current_tool = value
self._status = (self._status & ((1 << 24) - 1)) | (value << 24)
self._status = set_has_var(self._status, pos_current_tool)
property gcview_end_vertex:
def __get__(self):
......@@ -208,20 +193,13 @@ cdef class GLine(object):
def __set__(self, value):
self._gcview_end_vertex = value
self._status = set_has_var(self._status, pos_gcview_end_vertex)
property split_raw:
def __get__(self):
if has_var(self._status, pos_split_raw): return self._split_raw
else: return None
def __set__(self, value):
self._split_raw = value
self._status = set_has_var(self._status, pos_split_raw)
def __del__(self):
self._split_raw = None
property raw:
def __get__(self):
if has_var(self._status, pos_raw): return self._raw
else: return None
def __set__(self, value):
# WARNING: memory leak could happen here, as we don't do the following :
# if self._raw != NULL: free(self._raw)
self._raw = copy_string(value)
self._status = set_has_var(self._status, pos_raw)
property command:
......@@ -229,5 +207,7 @@ cdef class GLine(object):
if has_var(self._status, pos_command): return self._command
else: return None
def __set__(self, value):
# WARNING: memory leak could happen here, as we don't do the following :
# if self._command != NULL: free(self._command)
self._command = copy_string(value)
self._status = set_has_var(self._status, pos_command)
typedef int (*NyHeapDef_SizeGetter) (PyObject *obj);
typedef struct {
int flags; /* As yet, only 0 */
PyTypeObject *type; /* The type it regards */
NyHeapDef_SizeGetter size;
void *traverse;
void *relate;
void *resv3, *resv4, *resv5; /* Reserved for future bin. comp. */
} NyHeapDef;
int gline_size(struct __pyx_obj_8printrun_11gcoder_line_GLine *gline) {
int size = __pyx_type_8printrun_11gcoder_line_GLine.tp_basicsize;
if (gline->_raw != NULL)
size += strlen(gline->_raw) + 1;
if (gline->_command != NULL)
size += strlen(gline->_command) + 1;
return size;
}
static NyHeapDef nysets_heapdefs[] = {
{0, 0, (NyHeapDef_SizeGetter) gline_size},
};
/*
nysets_heapdefs[0].type = &__pyx_type_8printrun_11gcoder_line_GLine;
if (PyDict_SetItemString(__pyx_d,
"_NyHeapDefs_",
PyCObject_FromVoidPtrAndDesc(&nysets_heapdefs, "NyHeapDef[] v1.0", 0)) < 0)
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
*/
......@@ -34,6 +34,8 @@ from .libtatlin import actors
class wxGLPanel(wx.Panel):
'''A simple class for using OpenGL with wxPython.'''
orthographic = True
def __init__(self, parent, id, pos = wx.DefaultPosition,
size = wx.DefaultSize, style = 0):
# Forcing a no full repaint to stop flickering
......@@ -63,11 +65,11 @@ class wxGLPanel(wx.Panel):
def processSizeEvent(self, event):
'''Process the resize event.'''
size = self.GetClientSize()
self.winsize = (size.width, size.height)
self.width, self.height = size.width, size.height
if (wx.VERSION > (2,9) and self.canvas.IsShownOnScreen()) or self.canvas.GetContext():
# Make sure the frame is shown before calling SetCurrent.
size = self.GetClientSize()
self.winsize = (size.width, size.height)
self.width, self.height = size.width, size.height
self.canvas.SetCurrent(self.context)
self.OnReshape(size.width, size.height)
self.canvas.Refresh(False)
......@@ -97,11 +99,9 @@ class wxGLPanel(wx.Panel):
def OnInitGL(self):
'''Initialize OpenGL for use in the window.'''
#create a pyglet context for this panel
self.mvmat = (GLdouble * 16)()
self.pygletcontext = gl.Context(gl.current_context)
self.pygletcontext.canvas = self
self.pygletcontext.set_current()
self.dist = 1000
#normal gl init
glClearColor(0.98, 0.98, 0.78, 1)
glClearDepth(1.0) # set depth value to 1
......@@ -121,12 +121,15 @@ class wxGLPanel(wx.Panel):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60., width / float(height), .1, 1000.)
if self.orthographic:
glOrtho(-width / 2, width / 2, -height / 2, height / 2, 0.1, 3 * self.dist)
else:
gluPerspective(60., float(width) / height, 10.0, 3 * self.dist)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(*self.transv)
glMultMatrixd(build_rotmatrix(self.basequat))
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
if self.orthographic:
ratio = 0.9 * float(min(self.width, self.height)) / self.dist
glScalef(ratio, ratio, 1)
# Wrap text to the width of the window
if self.GLinitialized:
......@@ -250,7 +253,6 @@ class GcodeViewPanel(wxGLPanel):
self.dist = max(build_dimensions[0], build_dimensions[1])
else:
self.dist = 200
self.transv = [0, 0, -self.dist]
self.basequat = [0, 0, 0, 1]
self.mousepos = [0, 0]
......@@ -267,12 +269,11 @@ class GcodeViewPanel(wxGLPanel):
def draw_objects(self):
'''called in the middle of ondraw after the buffer has been cleared'''
self.create_objects()
glLoadIdentity()
glMultMatrixd(self.mvmat)
glPushMatrix()
glTranslatef(-self.parent.platform.width/2, -self.parent.platform.depth/2, 0)
glTranslatef(0, 0, -self.dist) # Move back
glMultMatrixd(build_rotmatrix(self.basequat)) # Rotate according to trackball
glTranslatef(-self.parent.platform.width/2, -self.parent.platform.depth/2, 0) # Move origin to bottom left of platform
for obj in self.parent.objects:
if not obj.model or not obj.model.loaded or not obj.model.initialized:
......@@ -290,6 +291,35 @@ class GcodeViewPanel(wxGLPanel):
if self.parent.clickcb:
self.parent.clickcb(event)
def handle_rotation(self, event):
if self.initpos == None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1x = float(p1[0]) / (sz[0] / 2) - 1
p1y = 1 - float(p1[1]) / (sz[1] / 2)
p2x = float(p2[0]) / (sz[0] / 2) - 1
p2y = 1 - float(p2[1]) / (sz[1] / 2)
quat = trackball(p1x, p1y, p2x, p2y, self.dist / 250.0)
self.basequat = mulquat(self.basequat, quat)
self.initpos = p2
def handle_translation(self, event):
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
if self.orthographic:
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
glTranslatef(x2 - x1, y2 - y1, 0)
else:
glTranslatef(p2[0] - p1[0], -(p2[1] - p1[1]), 0)
self.initpos = p2
def move(self, event):
"""react to mouse actions:
no mouse: show red mousedrop
......@@ -301,56 +331,13 @@ class GcodeViewPanel(wxGLPanel):
event.Skip()
return
if event.Dragging() and event.LeftIsDown():
if self.initpos == None:
self.initpos = event.GetPositionTuple()
else:
#print self.initpos
p1 = self.initpos
self.initpos = None
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1x = (float(p1[0]) - sz[0] / 2) / (sz[0] / 2)
p1y = -(float(p1[1]) - sz[1] / 2) / (sz[1] / 2)
p2x = (float(p2[0]) - sz[0] / 2) / (sz[0] / 2)
p2y = -(float(p2[1]) - sz[1] / 2) / (sz[1] / 2)
#print p1x, p1y, p2x, p2y
quat = trackball(p1x, p1y, p2x, p2y, -self.transv[2] / 250.0)
self.basequat = mulquat(self.basequat, quat)
mat = build_rotmatrix(self.basequat)
glLoadIdentity()
glTranslatef(*self.transv)
glMultMatrixd(mat)
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
self.handle_rotation(event)
elif event.Dragging() and event.RightIsDown():
self.handle_translation(event)
elif event.ButtonUp(wx.MOUSE_BTN_LEFT):
if self.initpos is not None:
self.initpos = None
self.initpos = None
elif event.ButtonUp(wx.MOUSE_BTN_RIGHT):
if self.initpos is not None:
self.initpos = None
elif event.Dragging() and event.RightIsDown():
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1 = list(p1) + [0]
p2 = list(p2) + [0]
p1[1] *= -1
p2[1] *= -1
sz = list(sz) + [1]
sz[0] *= 2
sz[1] *= 2
self.transv = map(lambda x, y, z, c: c - self.dist * (x - y) / z, p1, p2, sz, self.transv)
glLoadIdentity()
glTranslatef(*self.transv)
glMultMatrixd(build_rotmatrix(self.basequat))
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
self.initpos = None
self.initpos = None
else:
event.Skip()
return
......@@ -362,7 +349,10 @@ class GcodeViewPanel(wxGLPanel):
return
max_layers = self.parent.model.max_layers
current_layer = self.parent.model.num_layers_to_draw
new_layer = min(max_layers, current_layer + 1)
# accept going up to max_layers + 1
# max_layers means visualizing the last layer differently,
# max_layers + 1 means visualizing all layers with the same color
new_layer = min(max_layers + 1, current_layer + 1)
self.parent.model.num_layers_to_draw = new_layer
wx.CallAfter(self.Refresh)
......@@ -374,13 +364,15 @@ class GcodeViewPanel(wxGLPanel):
self.parent.model.num_layers_to_draw = new_layer
wx.CallAfter(self.Refresh)
def zoom(self, dist):
self.transv[2] += dist
def zoom(self, factor, to = None):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(*self.transv)
glMultMatrixd(build_rotmatrix(self.basequat))
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
if to:
delta_x = to[0]
delta_y = to[1]
glTranslatef(delta_x, delta_y, 0)
glScalef(factor, factor, 1)
if to:
glTranslatef(-delta_x, -delta_y, 0)
wx.CallAfter(self.Refresh)
def wheel(self, event):
......@@ -388,40 +380,60 @@ class GcodeViewPanel(wxGLPanel):
without shift: set max layer
with shift: zoom viewport
"""
z = event.GetWheelRotation()
dist = 10
delta = event.GetWheelRotation()
factor = 1.05
if event.ShiftDown():
if not self.parent.model:
return
if z > 0:
if delta > 0:
self.layerup()
else:
self.layerdown()
return
if z > 0:
self.zoom(dist)
x, y = event.GetPositionTuple()
x, y, _ = self.mouse_to_3d(x, y)
if delta > 0:
self.zoom(factor, (x, y))
else:
self.zoom(-dist)
self.zoom(1/factor, (x, y))
def mouse_to_3d(self, x, y):
x = float(x)
y = self.height - float(y)
# The following could work if we were not initially scaling to zoom on the bed
#if self.orthographic:
# return (x - self.width / 2, y - self.height / 2, 0)
pmat = (GLdouble * 16)()
mvmat = (GLdouble * 16)()
viewport = (GLint * 4)()
px = (GLdouble)()
py = (GLdouble)()
pz = (GLdouble)()
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_PROJECTION_MATRIX, pmat)
glGetDoublev(GL_MODELVIEW_MATRIX, mvmat)
gluUnProject(x, y, 1.0, mvmat, pmat, viewport, px, py, pz)
return (px.value, py.value, pz.value)
def keypress(self, event):
"""gets keypress events and moves/rotates acive shape"""
keycode = event.GetKeyCode()
step = 10
step = 1.1
if event.ControlDown():
step = 3
step = 1.05
kup = [85, 315] # Up keys
kdo = [68, 317] # Down Keys
kzi = [wx.WXK_PAGEDOWN, 388, 316, 61] # Zoom In Keys
kzo = [wx.WXK_PAGEUP, 390, 314, 45] # Zoom Out Keys
x = event.GetKeyCode()
if x in kup:
key = event.GetKeyCode()
if key in kup:
self.layerup()
if x in kdo:
if key in kdo:
self.layerdown()
if x in kzi:
self.zoom(step)
if x in kzo:
self.zoom(-step)
x, y, _ = self.mouse_to_3d(self.width / 2, self.height / 2)
if key in kzi:
self.zoom(step, (x, y))
if key in kzo:
self.zoom(1 / step, (x, y))
event.Skip()
wx.CallAfter(self.Refresh)
......
......@@ -266,7 +266,7 @@ class VizPane(wx.BoxSizer):
print "Falling back to 2D view, and here is the backtrace:"
traceback.print_exc()
if use2dview:
root.gviz = gviz.gviz(parentpanel, (300, 300),
root.gviz = gviz.Gviz(parentpanel, (300, 300),
build_dimensions = root.build_dimensions_list,
grid = (root.settings.preview_grid_step1, root.settings.preview_grid_step2),
extrusion_width = root.settings.preview_extrusion_width,
......@@ -288,7 +288,7 @@ class VizPane(wx.BoxSizer):
print "Falling back to 2D view, and here is the backtrace:"
traceback.print_exc()
if not use3dview:
root.gwindow = gviz.window([],
root.gwindow = gviz.GvizWindow(
build_dimensions = root.build_dimensions_list,
grid = (root.settings.preview_grid_step1, root.settings.preview_grid_step2),
extrusion_width = root.settings.preview_extrusion_width,
......
......@@ -18,31 +18,33 @@ from collections import deque
import wx, time
from printrun import gcoder
from printrun_utils import imagefile
from printrun_utils import imagefile, install_locale
install_locale('pronterface')
ID_ABOUT = 101
ID_EXIT = 110
class window(wx.Frame):
def __init__(self, f, size = (600, 600), build_dimensions = [200, 200, 100, 0, 0, 0], grid = (10, 50), extrusion_width = 0.5, bgcolor = "#000000"):
wx.Frame.__init__(self, None, title = "Gcode view, shift to move view, mousewheel to set layer", size = size)
class GvizWindow(wx.Frame):
def __init__(self, f = None, size = (600, 600), build_dimensions = [200, 200, 100, 0, 0, 0], grid = (10, 50), extrusion_width = 0.5, bgcolor = "#000000"):
wx.Frame.__init__(self, None, title = _("Gcode view, shift to move view, mousewheel to set layer"), size = size)
self.CreateStatusBar(1);
self.SetStatusText("Layer number and Z position show here when you scroll");
self.SetStatusText(_("Layer number and Z position show here when you scroll"))
panel = wx.Panel(self, -1)
self.p = gviz(panel, size = size, build_dimensions = build_dimensions, grid = grid, extrusion_width = extrusion_width, bgcolor = bgcolor, realparent = self)
self.p = Gviz(panel, size = size, build_dimensions = build_dimensions, grid = grid, extrusion_width = extrusion_width, bgcolor = bgcolor, realparent = self)
vbox = wx.BoxSizer(wx.VERTICAL)
toolbar = wx.ToolBar(panel, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER)
toolbar.AddSimpleTool(1, wx.Image(imagefile('zoom_in.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Zoom In [+]', '')
toolbar.AddSimpleTool(2, wx.Image(imagefile('zoom_out.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Zoom Out [-]', '')
toolbar = wx.ToolBar(panel, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_HORZ_TEXT)
toolbar.AddSimpleTool(1, wx.Image(imagefile('zoom_in.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom In [+]"), '')
toolbar.AddSimpleTool(2, wx.Image(imagefile('zoom_out.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom Out [-]"), '')
toolbar.AddSeparator()
toolbar.AddSimpleTool(3, wx.Image(imagefile('arrow_up.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Move Up a Layer [U]', '')
toolbar.AddSimpleTool(4, wx.Image(imagefile('arrow_down.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Move Down a Layer [D]', '')
toolbar.AddSimpleTool(5, wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Reset view', '')
toolbar.AddSimpleTool(3, wx.Image(imagefile('arrow_up.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Up a Layer [U]"), '')
toolbar.AddSimpleTool(4, wx.Image(imagefile('arrow_down.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Down a Layer [D]"), '')
toolbar.AddLabelTool(5, " " + _("Reset view"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset view"), longHelp = '')
toolbar.AddSeparator()
#toolbar.AddSimpleTool(6, wx.Image(imagefile('inject.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Insert Code at start of this layer', '')
#toolbar.AddSimpleTool(6, wx.Image(imagefile('inject.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Insert Code at start of this layer"), '')
toolbar.Realize()
self.toolbar = toolbar
vbox.Add(toolbar, 0, border = 5)
vbox.Add(self.p, 1, wx.EXPAND)
panel.SetSizer(vbox)
......@@ -54,7 +56,7 @@ class window(wx.Frame):
self.Bind(wx.EVT_TOOL, self.resetview, id = 5)
#self.Bind(wx.EVT_TOOL, lambda x:self.p.inject(), id = 6)
self.initpos = [0, 0]
self.initpos = None
self.p.Bind(wx.EVT_KEY_DOWN, self.key)
self.Bind(wx.EVT_KEY_DOWN, self.key)
self.p.Bind(wx.EVT_MOUSEWHEEL, self.zoom)
......@@ -75,12 +77,12 @@ class window(wx.Frame):
self.p.zoom(0, 0, 1.0)
def mouse(self, event):
if event.ButtonUp(wx.MOUSE_BTN_LEFT):
if event.ButtonUp(wx.MOUSE_BTN_LEFT) or event.ButtonUp(wx.MOUSE_BTN_RIGHT):
if self.initpos is not None:
self.initpos = None
elif event.Dragging():
e = event.GetPositionTuple()
if self.initpos is None or not hasattr(self, "basetrans"):
if self.initpos is None:
self.initpos = e
self.basetrans = self.p.translate
self.p.translate = [self.basetrans[0] + (e[0] - self.initpos[0]),
......@@ -116,7 +118,7 @@ class window(wx.Frame):
if z > 0: self.p.zoom(event.GetX(), event.GetY(), 1.2)
elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1/1.2)
class gviz(wx.Panel):
class Gviz(wx.Panel):
# Mark canvas as dirty when setting showall
_showall = 0
......@@ -168,6 +170,7 @@ class gviz(wx.Panel):
self.bgcolor = wx.Colour()
self.bgcolor.SetFromName(bgcolor)
self.blitmap = wx.EmptyBitmap(self.GetClientSize()[0], self.GetClientSize()[1], -1)
self.paint_overlay = None
def inject(self):
#import pdb; pdb.set_trace()
......@@ -198,14 +201,14 @@ class gviz(wx.Panel):
def layerup(self):
if self.layerindex + 1 < len(self.layers):
self.layerindex += 1
self.parent.SetStatusText("Layer %d - Going Up - Z = %.03f mm" % (self.layerindex + 1, self.layers[self.layerindex]), 0)
self.parent.SetStatusText(_("Layer %d - Going Up - Z = %.03f mm") % (self.layerindex + 1, self.layers[self.layerindex]), 0)
self.dirty = 1
wx.CallAfter(self.Refresh)
def layerdown(self):
if self.layerindex > 0:
self.layerindex -= 1
self.parent.SetStatusText("Layer %d - Going Down - Z = %.03f mm" % (self.layerindex + 1, self.layers[self.layerindex]), 0)
self.parent.SetStatusText(_("Layer %d - Going Down - Z = %.03f mm") % (self.layerindex + 1, self.layers[self.layerindex]), 0)
self.dirty = 1
wx.CallAfter(self.Refresh)
......@@ -337,6 +340,8 @@ class gviz(wx.Panel):
dc.SetBackground(wx.Brush(self.bgcolor))
dc.Clear()
dc.DrawBitmap(self.blitmap, self.translate[0], self.translate[1])
if self.paint_overlay:
self.paint_overlay(dc)
def addfile(self, gcode):
self.clear()
......@@ -474,6 +479,6 @@ class gviz(wx.Panel):
if __name__ == '__main__':
import sys
app = wx.App(False)
main = window(open(sys.argv[1]))
main = GvizWindow(open(sys.argv[1]))
main.Show()
app.MainLoop()
......@@ -241,6 +241,7 @@ class GcodeModel(Model):
color_tool0 = (1.0, 0.0, 0.0, 0.6)
color_tool1 = (0.0, 0.0, 1.0, 0.6)
color_printed = (0.2, 0.75, 0, 0.6)
color_current = (0.6, 0.3, 0, 1)
use_vbos = True
loaded = False
......@@ -256,7 +257,7 @@ class GcodeModel(Model):
prev_pos = (0, 0, 0)
for layer_idx, layer in enumerate(model_data.all_layers):
for gline in layer.lines:
for gline in layer:
if not gline.is_move:
continue
vertex_list.append(prev_pos)
......@@ -337,33 +338,56 @@ class GcodeModel(Model):
else:
glVertexPointer(3, GL_FLOAT, 0, self.vertex_buffer.ptr)
if mode_2d:
glScale(1.0, 1.0, 0.0) # discard z coordinates
start = self.layer_stops[self.num_layers_to_draw - 1]
end = self.layer_stops[self.num_layers_to_draw] - start
else: # 3d
start = 0
end = self.layer_stops[self.num_layers_to_draw]
self.vertex_color_buffer.bind()
if has_vbo:
glColorPointer(4, GL_FLOAT, 0, None)
else:
glColorPointer(4, GL_FLOAT, 0, self.vertex_color_buffer.ptr)
start = 0
if self.num_layers_to_draw <= self.max_layers:
end_prev_layer = self.layer_stops[self.num_layers_to_draw - 1]
else:
end_prev_layer = -1
end = self.layer_stops[min(self.num_layers_to_draw, self.max_layers)]
glDisableClientState(GL_COLOR_ARRAY)
glColor4f(*self.color_printed)
printed_end = min(self.printed_until, end)
if start < printed_end:
glDrawArrays(GL_LINES, start, printed_end)
# Draw printed stuff until end or end_prev_layer
cur_end = min(self.printed_until, end)
if end_prev_layer >= 0:
cur_end = min(cur_end, end_prev_layer)
if cur_end >= 0:
glDrawArrays(GL_LINES, start, cur_end)
glEnableClientState(GL_COLOR_ARRAY)
self.vertex_color_buffer.bind()
if has_vbo:
glColorPointer(4, GL_FLOAT, 0, None)
else:
glColorPointer(4, GL_FLOAT, 0, self.vertex_color_buffer.ptr)
# Draw nonprinted stuff until end_prev_layer
start = max(cur_end, 0)
if end_prev_layer >= start:
glDrawArrays(GL_LINES, start, end_prev_layer - start)
cur_end = end_prev_layer
glDisableClientState(GL_COLOR_ARRAY)
glColor4f(*self.color_current)
# Draw current layer
orig_linewidth = (GLfloat)()
glGetFloatv(GL_LINE_WIDTH, orig_linewidth)
glLineWidth(2.0)
if end_prev_layer >= 0 and end > end_prev_layer:
glDrawArrays(GL_LINES, end_prev_layer, end - end_prev_layer)
glLineWidth(orig_linewidth)
glEnableClientState(GL_COLOR_ARRAY)
# Draw non printed stuff until end (if not ending at a given layer)
start = max(self.printed_until, 0)
end = end - start
if start >= 0 and end > 0:
if end_prev_layer < 0 and end > 0:
glDrawArrays(GL_LINES, start, end)
self.vertex_buffer.unbind()
......
......@@ -77,7 +77,7 @@ class RemainingTimeEstimator(object):
if self.previous_layers_estimate > 0 and printtime > 0:
self.drift = printtime / self.previous_layers_estimate
self.current_layer_estimate = self.gcode.all_layers[layer].duration
self.current_layer_lines = len(self.gcode.all_layers[layer].lines)
self.current_layer_lines = len(self.gcode.all_layers[layer])
self.remaining_layers_estimate -= self.current_layer_estimate
self.last_idx = -1
self.last_estimate = None
......
......@@ -462,7 +462,7 @@ class pronsole(cmd.Cmd):
pass
for g in ['/dev/ttyUSB*', '/dev/ttyACM*', "/dev/tty.*", "/dev/cu.*", "/dev/rfcomm*"]:
baselist+=glob.glob(g)
baselist += glob.glob(g)
return filter(self._bluetoothSerialFilter, baselist)
def _bluetoothSerialFilter(self, serial):
......@@ -1369,7 +1369,7 @@ class pronsole(cmd.Cmd):
self.log(_("Loading sliced file."))
self.do_load(l[0].replace(".stl", "_export.gcode"))
except Exception, e:
self.logError(_("Skeinforge execution failed: %s") % e)
self.logError(_("Slicing failed: %s") % e)
def complete_skein(self, text, line, begidx, endidx):
s = line.split()
......
......@@ -45,6 +45,7 @@ if os.name == "nt":
import printcore
from printrun.printrun_utils import pixmapfile, configfile
from printrun.gui import MainWindow
from printrun.excluder import Excluder
import pronsole
from pronsole import dosify, wxSetting, HiddenSetting, StringSetting, SpinSetting, FloatSpinSetting, BooleanSetting, StaticTextSetting
from printrun import gcoder
......@@ -175,6 +176,15 @@ class ComboSetting(wxSetting):
return self.widget
class PronterWindow(MainWindow, pronsole.pronsole):
_fgcode = None
def _get_fgcode(self):
return self._fgcode
def _set_fgcode(self, value):
self._fgcode = value
self.excluder = None
fgcode = property(_get_fgcode, _set_fgcode)
def __init__(self, filename = None, size = winsize):
pronsole.pronsole.__init__(self)
#default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed and endstops at 0, 0 and 0
......@@ -182,6 +192,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
monitorsetting.hidden = True
self.settings._add(monitorsetting)
self.settings._add(BuildDimensionsSetting("build_dimensions", "200x200x100+0+0+0+0+0+0", _("Build dimensions"), _("Dimensions of Build Platform\n & optional offset of origin\n & optional switch position\n\nExamples:\n XXXxYYY\n XXX,YYY,ZZZ\n XXXxYYYxZZZ+OffX+OffY+OffZ\nXXXxYYYxZZZ+OffX+OffY+OffZ+HomeX+HomeY+HomeZ"), "Printer"))
self.settings._add(BooleanSetting("clamp_jogging", False, _("Clamp manual moves"), _("Prevent manual moves from leaving the specified build dimensions"), "Printer"))
self.settings._add(StringSetting("bgcolor", "#FFFFFF", _("Background color"), _("Pronterface background color"), "UI"))
self.settings._add(ComboSetting("uimode", "Standard", ["Standard", "Compact", "Tabbed"], _("Interface mode"), _("Standard interface is a one-page, three columns layout with controls/visualization/log\nCompact mode is a one-page, two columns layout with controls + log/visualization\nTabbed mode is a two-pages mode, where the first page shows controls and the second one shows visualization and log."), "UI"))
self.settings._add(BooleanSetting("viz3d", False, _("Enable 3D viewer"), _("Use 3D visualization instead of 2D layered visualization"), "UI"))
......@@ -217,6 +228,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.userm105 = 0
self.monitor = 0
self.fgcode = None
self.excluder = None
self.skeinp = None
self.monitor_interval = 3
self.current_pos = [0, 0, 0]
......@@ -291,6 +303,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.skeining = 0
self.mini = False
self.p.sendcb = self.sentcb
self.p.preprintsendcb = self.preprintsendcb
self.p.printsendcb = self.printsentcb
self.p.layerchangecb = self.layer_change_cb
self.p.startcb = self.startcb
......@@ -367,7 +380,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def sentcb(self, line):
gline = gcoder.Line(line)
gline.parse_coordinates(imperial = False)
split_raw = gcoder.split(gline)
gcoder.parse_coordinates(gline, split_raw, imperial = False)
if gline.is_move:
if gline.z != None:
layer = gline.z
......@@ -376,21 +390,36 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.gviz.clearhilights()
wx.CallAfter(self.gviz.setlayer, layer)
elif gline.command in ["M104", "M109"]:
gline.parse_coordinates(imperial = False, force = True)
if gline.s != None:
temp = gline.s
gcoder.parse_coordinates(gline, split_raw, imperial = False, force = True)
gline_s = gcoder.S(gline)
if gline_s != None:
temp = gline_s
if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp)
elif gline.command == "M140":
gline.parse_coordinates(imperial = False, force = True)
if gline.s != None:
temp = gline.s
gline.parse_coordinates(gline, split_raw, imperial = False, force = True)
gline_s = gcoder.S(gline)
if gline_s != None:
temp = gline_s
if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, temp)
else:
return
self.sentlines.put_nowait(line)
def preprintsendcb(self, gline):
if not gline.is_move or not self.excluder or not self.excluder.rectangles:
return gline
if gline.x == None and gline.y == None:
return gline
for (x0, y0, x1, y1) in self.excluder.rectangles:
if x0 <= gline.current_x <= x1 and y0 <= gline.current_y <= y1:
if gline.e != None and not gline.relative_e:
return gcoder.Line("G92 E%.5f" % gline.e)
else:
return None
return gline
def printsentcb(self, gline):
if gline.is_move and hasattr(self.gwindow, "set_current_gline"):
wx.CallAfter(self.gwindow.set_current_gline, gline)
......@@ -530,24 +559,18 @@ class PronterWindow(MainWindow, pronsole.pronsole):
return
wx.CallAfter(self.addtexttolog,l);
def scanserial(self):
"""scan for available ports. return a list of device names."""
baselist = []
if os.name == "nt":
try:
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM")
i = 0
while True:
baselist += [_winreg.EnumValue(key, i)[1]]
i += 1
except:
pass
return baselist+glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') + glob.glob("/dev/tty.*") + glob.glob("/dev/cu.*") + glob.glob("/dev/rfcomm*")
def project(self,event):
from printrun import projectlayer
projectlayer.SettingsFrame(self, self.p).Show()
def exclude(self, event):
if not self.fgcode:
wx.CallAfter(self.statusbar.SetStatusText, _("No file loaded. Please use load first."))
return
if not self.excluder:
self.excluder = Excluder()
self.excluder.pop_window(self.fgcode, bgcolor = self.settings.bgcolor)
def popmenu(self):
self.menustrip = wx.MenuBar()
# File menu
......@@ -555,6 +578,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.Bind(wx.EVT_MENU, self.loadfile, m.Append(-1, _("&Open..."), _(" Opens file")))
self.Bind(wx.EVT_MENU, self.do_editgcode, m.Append(-1, _("&Edit..."), _(" Edit open file")))
self.Bind(wx.EVT_MENU, self.clearOutput, m.Append(-1, _("Clear console"), _(" Clear output console")))
self.Bind(wx.EVT_MENU, self.exclude, m.Append(-1, _("Excluder"), _(" Exclude parts of the bed from being printed")))
self.Bind(wx.EVT_MENU, self.project, m.Append(-1, _("Projector"), _(" Project slices")))
self.Bind(wx.EVT_MENU, self.OnExit, m.Append(wx.ID_EXIT, _("E&xit"), _(" Closes the Window")))
self.menustrip.Append(m, _("&File"))
......@@ -647,19 +671,16 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.Close()
def rescanports(self, event = None):
scan = self.scanserial()
portslist = list(scan)
scanned = self.scanserial()
portslist = list(scanned)
if self.settings.port != "" and self.settings.port not in portslist:
portslist += [self.settings.port]
portslist.append(self.settings.port)
self.serialport.Clear()
self.serialport.AppendItems(portslist)
try:
if os.path.exists(self.settings.port) or self.settings.port in scan:
self.serialport.SetValue(self.settings.port)
elif len(portslist) > 0:
self.serialport.SetValue(portslist[0])
except:
pass
if os.path.exists(self.settings.port) or self.settings.port in scanned:
self.serialport.SetValue(self.settings.port)
elif portslist:
self.serialport.SetValue(portslist[0])
def cbkey(self, e):
if e.GetKeyCode() == wx.WXK_UP:
......@@ -1062,12 +1083,25 @@ class PronterWindow(MainWindow, pronsole.pronsole):
return
self.p.send_now('M114')
def clamped_move_message(self):
print _("Manual move outside of the build volume prevented (see the \"Clamp manual moves\" option).")
def moveXY(self, x, y):
# When user clicks on the XY control, the Z control no longer gets spacebar/repeat signals
self.zb.clearRepeat()
if x != 0:
if self.settings.clamp_jogging:
new_x = self.current_pos[0] + x
if new_x < self.build_dimensions_list[3] or new_x > self.build_dimensions_list[0] + self.build_dimensions_list[3]:
self.clamped_move_message()
return
self.onecmd('move X %s' % x)
elif y != 0:
if self.settings.clamp_jogging:
new_y = self.current_pos[1] + y
if new_y < self.build_dimensions_list[4] or new_y > self.build_dimensions_list[1] + self.build_dimensions_list[4]:
self.clamped_move_message()
return
self.onecmd('move Y %s' % y)
else:
return
......@@ -1075,6 +1109,11 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def moveZ(self, z):
if z != 0:
if self.settings.clamp_jogging:
new_z = self.current_pos[2] + z
if new_z < self.build_dimensions_list[5] or new_z > self.build_dimensions_list[2] + self.build_dimensions_list[5]:
self.clamped_move_message()
return
self.onecmd('move Z %s' % z)
self.p.send_now('M114')
# When user clicks on the Z control, the XY control no longer gets spacebar/repeat signals
......@@ -1116,6 +1155,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.save_in_rc("set xy_feedrate", "set xy_feedrate %d" % self.settings.xy_feedrate)
self.save_in_rc("set z_feedrate", "set z_feedrate %d" % self.settings.z_feedrate)
self.save_in_rc("set e_feedrate", "set e_feedrate %d" % self.settings.e_feedrate)
if self.excluder:
self.excluder.close_window()
wx.CallAfter(self.gwindow.Destroy)
wx.CallAfter(self.Destroy)
......@@ -1193,12 +1234,13 @@ class PronterWindow(MainWindow, pronsole.pronsole):
y = None
z = None
for bit in bits:
if x is None and bit.startswith("X"):
x = float(bit[1:].replace(":",""))
elif y is None and bit.startswith("Y"):
y = float(bit[1:].replace(":",""))
elif z is None and bit.startswith("Z"):
z = float(bit[1:].replace(":",""))
if not bit[0]: continue
if x is None and bit[0] == "X":
x = float(bit[1])
elif y is None and bit[0] == "Y":
y = float(bit[1])
elif z is None and bit[0] == "Z":
z = float(bit[1])
if x is not None: self.current_pos[0] = x
if y is not None: self.current_pos[1] = y
if z is not None: self.current_pos[2] = z
......@@ -1568,17 +1610,18 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def connect(self, event = None):
print _("Connecting...")
port = None
try:
port = self.scanserial()[0]
except:
pass
if self.serialport.GetValue()!="":
if self.serialport.GetValue():
port = str(self.serialport.GetValue())
else:
scanned = self.scanserial()
if scanned:
port = scanned[0]
baud = 115200
try:
baud = int(self.baud.GetValue())
except:
pass
print _("Could not parse baud rate: ")
traceback.print_exc(file = sys.stdout)
if self.paused:
self.p.paused = 0
self.p.printing = 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment