Printrun/pronterface.py

1552 lines
64 KiB
Python
Raw Permalink Normal View History

2013-05-30 14:31:49 +00:00
#!/usr/bin/env python2
2012-01-23 11:36:49 +00:00
# This file is part of the Printrun suite.
#
2012-01-23 11:36:49 +00:00
# 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.
#
2012-01-23 11:36:49 +00:00
# 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.
#
2012-01-23 11:36:49 +00:00
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
2011-08-06 23:45:52 +00:00
import os, Queue, re
from printrun.printrun_utils import install_locale
install_locale('pronterface')
2013-05-30 14:31:49 +00:00
import wxversion
wxversion.select("2.8")
2011-06-08 14:19:38 +00:00
try:
import wx
except:
2011-08-06 23:45:52 +00:00
print _("WX is not installed. This program requires WX to run.")
2011-06-08 14:19:38 +00:00
raise
2012-08-07 11:54:07 +00:00
import sys, glob, time, datetime, threading, traceback, cStringIO, subprocess
2013-05-18 15:18:20 +00:00
import shlex
from printrun.pronterface_widgets import *
from serial import SerialException
2012-08-08 07:38:48 +00:00
StringIO = cStringIO
2012-08-08 07:38:48 +00:00
winsize = (800, 500)
layerindex = 0
if os.name == "nt":
winsize = (800, 530)
2011-06-08 14:19:38 +00:00
try:
import _winreg
except:
pass
import printcore
from printrun.printrun_utils import pixmapfile, configfile
2012-09-05 11:09:38 +00:00
from printrun.gui import MainWindow
import pronsole
2013-05-15 17:42:38 +00:00
from pronsole import dosify
2013-05-16 13:05:28 +00:00
from printrun import gcoder
2011-06-08 22:02:00 +00:00
2012-08-02 16:26:56 +00:00
def parse_temperature_report(report, key):
if key in report:
return float(filter(lambda x: x.startswith(key), report.split())[0].split(":")[1].split("/")[0])
else:
return -1.0
2012-08-04 09:02:17 +00:00
def format_time(timestamp):
2012-08-07 11:54:07 +00:00
return datetime.datetime.fromtimestamp(timestamp).strftime("%H:%M:%S")
def format_duration(delta):
return str(datetime.timedelta(seconds = int(delta)))
2012-08-04 09:02:17 +00:00
class Tee(object):
def __init__(self, target):
self.stdout = sys.stdout
sys.stdout = self
2012-08-08 07:38:48 +00:00
self.target = target
def __del__(self):
sys.stdout = self.stdout
def write(self, data):
try:
self.target(data)
except:
pass
2013-01-23 16:11:08 +00:00
try:
data = data.encode("utf-8")
except:
pass
self.stdout.write(data)
def flush(self):
self.stdout.flush()
2011-06-08 22:02:00 +00:00
2012-09-05 11:09:38 +00:00
class PronterWindow(MainWindow, pronsole.pronsole):
2012-08-08 07:38:48 +00:00
def __init__(self, filename = None, size = winsize):
pronsole.pronsole.__init__(self)
self.settings.build_dimensions = '200x200x100+0+0+0+0+0+0' #default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed
self.settings.last_bed_temperature = 0.0
2011-06-29 21:32:24 +00:00
self.settings.last_file_path = ""
self.settings.last_temperature = 0.0
self.settings.preview_extrusion_width = 0.5
2011-08-07 20:00:13 +00:00
self.settings.preview_grid_step1 = 10.
self.settings.preview_grid_step2 = 50.
self.settings.bgcolor = "#FFFFFF"
self.pauseScript = "pause.gcode"
self.endScript = "end.gcode"
self.helpdict["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")
self.helpdict["last_bed_temperature"] = _("Last Set Temperature for the Heated Print Bed")
self.helpdict["last_file_path"] = _("Folder of last opened file")
self.helpdict["last_temperature"] = _("Last Temperature of the Hot End")
self.helpdict["preview_extrusion_width"] = _("Width of Extrusion in Preview (default: 0.5)")
self.helpdict["preview_grid_step1"] = _("Fine Grid Spacing (default: 10)")
self.helpdict["preview_grid_step2"] = _("Coarse Grid Spacing (default: 50)")
self.helpdict["bgcolor"] = _("Pronterface background color (default: #FFFFFF)")
2012-08-08 07:38:48 +00:00
self.filename = filename
2012-08-08 07:58:09 +00:00
os.putenv("UBUNTU_MENUPROXY", "0")
2012-09-05 11:09:38 +00:00
MainWindow.__init__(self, None, title = _("Printer Interface"), size = size);
2012-08-08 07:58:09 +00:00
self.SetIcon(wx.Icon(pixmapfile("P-face.ico"), wx.BITMAP_TYPE_ICO))
2012-08-08 07:38:48 +00:00
self.panel = wx.Panel(self,-1, size = size)
2012-08-08 07:38:48 +00:00
self.statuscheck = False
self.status_thread = None
2012-08-08 07:58:09 +00:00
self.capture_skip = {}
2012-08-08 07:38:48 +00:00
self.capture_skip_newline = False
self.tempreport = ""
self.monitor = 0
self.f = None
self.skeinp = None
self.monitor_interval = 3
self.current_pos = [0, 0, 0]
2012-08-08 07:38:48 +00:00
self.paused = False
2013-05-18 16:38:54 +00:00
self.sentlines = Queue.Queue(0)
2012-08-08 07:58:09 +00:00
self.cpbuttons = [
SpecialButton(_("Motors off"), ("M84"), (250, 250, 250), None, 0, _("Switch all motors off")),
SpecialButton(_("Check temp"), ("M105"), (225, 200, 200), (2, 5), (1, 1), _("Check current hotend temperature")),
SpecialButton(_("Extrude"), ("extrude"), (225, 200, 200), (4, 0), (1, 2), _("Advance extruder by set length")),
SpecialButton(_("Reverse"), ("reverse"), (225, 200, 200), (5, 0), (1, 2), _("Reverse extruder by set length")),
]
2012-08-08 07:58:09 +00:00
self.custombuttons = []
self.btndict = {}
self.parse_cmdline(sys.argv[1:])
2011-12-11 09:11:47 +00:00
self.build_dimensions_list = self.get_build_dimensions(self.settings.build_dimensions)
#initialize the code analyzer with the correct sizes. There must be a more general way to do so
2013-04-08 11:06:31 +00:00
# minimum = offset
self.p.analyzer.minX = self.build_dimensions_list[3]
self.p.analyzer.minY = self.build_dimensions_list[4]
self.p.analyzer.minZ = self.build_dimensions_list[5]
2013-04-08 11:06:31 +00:00
#max = offset + bedsize
self.p.analyzer.maxX = self.build_dimensions_list[3] + self.build_dimensions_list[0]
self.p.analyzer.maxY = self.build_dimensions_list[4] + self.build_dimensions_list[1]
self.p.analyzer.maxZ = self.build_dimensions_list[5] + self.build_dimensions_list[2]
self.p.analyzer.homeX = self.build_dimensions_list[6]
self.p.analyzer.homeY = self.build_dimensions_list[7]
self.p.analyzer.homeZ = self.build_dimensions_list[8]
#set feedrates in printcore for pause/resume
self.p.xy_feedrate = self.settings.xy_feedrate
self.p.z_feedrate = self.settings.z_feedrate
#make printcore aware of me
self.p.pronterface = self
self.panel.SetBackgroundColour(self.settings.bgcolor)
2012-08-08 07:58:09 +00:00
customdict = {}
try:
2012-08-08 07:58:09 +00:00
execfile(configfile("custombtn.txt"), customdict)
if len(customdict["btns"]):
if not len(self.custombuttons):
try:
self.custombuttons = customdict["btns"]
for n in xrange(len(self.custombuttons)):
2012-08-08 07:38:48 +00:00
self.cbutton_save(n, self.custombuttons[n])
2012-08-08 07:58:09 +00:00
os.rename("custombtn.txt", "custombtn.old")
rco = open("custombtn.txt", "w")
2011-08-06 23:45:52 +00:00
rco.write(_("# I moved all your custom buttons into .pronsolerc.\n# Please don't add them here any more.\n# Backup of your old buttons is in custombtn.old\n"))
rco.close()
2012-08-08 07:38:48 +00:00
except IOError, x:
print str(x)
else:
2011-08-06 23:45:52 +00:00
print _("Note!!! You have specified custom buttons in both custombtn.txt and .pronsolerc")
print _("Ignoring custombtn.txt. Remove all current buttons to revert to custombtn.txt")
except:
pass
2011-06-08 14:19:38 +00:00
self.popmenu()
2012-09-05 11:09:38 +00:00
self.createGui()
2012-08-08 07:38:48 +00:00
self.t = Tee(self.catchprint)
self.stdout = sys.stdout
self.skeining = 0
self.mini = False
self.p.sendcb = self.sentcb
self.p.startcb = self.startcb
self.p.endcb = self.endcb
self.starttime = 0
self.extra_print_time = 0
self.curlayer = 0
self.cur_button = None
self.predisconnect_mainqueue = None
self.predisconnect_queueindex = None
self.predisconnect_layer = None
2012-08-08 07:38:48 +00:00
self.hsetpoint = 0.0
self.bsetpoint = 0.0
if self.filename is not None:
2012-09-05 08:11:48 +00:00
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):
2012-08-08 07:38:48 +00:00
self.starttime = time.time()
2012-08-04 09:02:17 +00:00
print "Print Started at: " + format_time(self.starttime)
def endcb(self):
2012-08-08 07:58:09 +00:00
if self.p.queueindex == 0:
2012-08-07 11:54:07 +00:00
print_duration = int(time.time () - self.starttime + self.extra_print_time)
2013-05-16 20:50:28 +00:00
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)
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
self.p.runSmallScript(self.endScript)
param = self.settings.final_command
2012-08-07 08:58:28 +00:00
if not param:
return
2012-08-08 07:58:09 +00:00
pararray = [i.replace("$s", str(self.filename)).replace("$t", format_duration(print_duration)).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
2012-08-08 07:38:48 +00:00
self.finalp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
def online(self):
print _("Printer is now online.")
2012-02-26 01:08:57 +00:00
self.connectbtn.SetLabel(_("Disconnect"))
self.connectbtn.SetToolTip(wx.ToolTip("Disconnect from the printer"))
2012-08-08 07:38:48 +00:00
self.connectbtn.Bind(wx.EVT_BUTTON, self.disconnect)
2011-12-04 01:17:19 +00:00
for i in self.printerControls:
wx.CallAfter(i.Enable)
# Enable XYButtons and ZButtons
wx.CallAfter(self.xyb.enable)
wx.CallAfter(self.zb.enable)
if self.filename:
wx.CallAfter(self.printbtn.Enable)
def sentcb(self, line):
if "G1" in line:
if "Z" in line:
2011-06-22 11:40:27 +00:00
try:
layer = float(line.split("Z")[1].split()[0].split("*")[0])
if layer != self.curlayer:
self.curlayer = layer
self.gviz.hilight.clear()
self.gviz.hilightarcs.clear()
threading.Thread(target = wx.CallAfter, args = (self.gviz.setlayer, layer)).start()
2011-06-22 11:40:27 +00:00
except:
pass
try:
self.sentlines.put_nowait(line)
2013-05-18 16:38:54 +00:00
except Queue.Full:
pass
2012-08-08 07:38:48 +00:00
#threading.Thread(target = self.gviz.addgcode, args = (line, 1)).start()
#self.gwindow.p.addgcode(line, hilight = 1)
if "M104" in line or "M109" in line:
if "S" in line:
try:
temp = float(line.split("S")[1].split("*")[0])
2013-05-17 14:59:28 +00:00
if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp)
wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp)
except:
pass
try:
self.sentlines.put_nowait(line)
except:
pass
if "M140" in line:
if "S" in line:
try:
temp = float(line.split("S")[1].split("*")[0])
2013-05-17 14:59:28 +00:00
if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp)
wx.CallAfter(self.graph.SetBedTargetTemperature, temp)
except:
pass
try:
self.sentlines.put_nowait(line)
except:
pass
def do_extrude(self, l = ""):
try:
if not l.__class__ in (str, unicode) or not len(l):
l = str(self.edist.GetValue())
pronsole.pronsole.do_extrude(self, l)
except:
raise
def do_reverse(self, l = ""):
try:
if not l.__class__ in (str, unicode) or not len(l):
l = str(- float(self.edist.GetValue()))
2012-08-08 07:38:48 +00:00
pronsole.pronsole.do_extrude(self, l)
except:
pass
def setbedgui(self, f):
self.bsetpoint = f
2013-05-17 14:59:28 +00:00
if self.display_gauges: self.bedtgauge.SetTarget(int(f))
wx.CallAfter(self.graph.SetBedTargetTemperature, int(f))
2012-07-15 11:43:34 +00:00
if f>0:
wx.CallAfter(self.btemp.SetValue, str(f))
self.set("last_bed_temperature", str(f))
wx.CallAfter(self.setboff.SetBackgroundColour, None)
wx.CallAfter(self.setboff.SetForegroundColour, None)
wx.CallAfter(self.setbbtn.SetBackgroundColour, "#FFAA66")
wx.CallAfter(self.setbbtn.SetForegroundColour, "#660000")
wx.CallAfter(self.btemp.SetBackgroundColour, "#FFDABB")
2012-07-15 11:43:34 +00:00
else:
wx.CallAfter(self.setboff.SetBackgroundColour, "#0044CC")
wx.CallAfter(self.setboff.SetForegroundColour, "white")
wx.CallAfter(self.setbbtn.SetBackgroundColour, None)
wx.CallAfter(self.setbbtn.SetForegroundColour, None)
wx.CallAfter(self.btemp.SetBackgroundColour, "white")
2012-07-15 11:43:34 +00:00
wx.CallAfter(self.btemp.Refresh)
def sethotendgui(self, f):
self.hsetpoint = f
2013-05-17 14:59:28 +00:00
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))
self.set("last_temperature", str(f))
wx.CallAfter(self.settoff.SetBackgroundColour, None)
wx.CallAfter(self.settoff.SetForegroundColour, None)
wx.CallAfter(self.settbtn.SetBackgroundColour, "#FFAA66")
wx.CallAfter(self.settbtn.SetForegroundColour, "#660000")
wx.CallAfter(self.htemp.SetBackgroundColour, "#FFDABB")
2012-07-15 11:43:34 +00:00
else:
wx.CallAfter(self.settoff.SetBackgroundColour, "#0044CC")
wx.CallAfter(self.settoff.SetForegroundColour, "white")
wx.CallAfter(self.settbtn.SetBackgroundColour, None)
wx.CallAfter(self.settbtn.SetForegroundColour, None)
wx.CallAfter(self.htemp.SetBackgroundColour, "white")
2012-07-15 11:43:34 +00:00
wx.CallAfter(self.htemp.Refresh)
def do_settemp(self, l = ""):
2011-06-09 10:54:03 +00:00
try:
if not l.__class__ in (str, unicode) or not len(l):
l = str(self.htemp.GetValue().split()[0])
2012-08-08 07:58:09 +00:00
l = l.lower().replace(", ", ".")
2011-06-09 10:54:03 +00:00
for i in self.temps.keys():
l = l.replace(i, self.temps[i])
f = float(l)
if f >= 0:
2011-06-09 10:54:03 +00:00
if self.p.online:
self.p.send_now("M104 S"+l)
print _("Setting hotend temperature to %f degrees Celsius.") % f
2012-07-15 11:43:34 +00:00
self.sethotendgui(f)
2011-06-09 10:54:03 +00:00
else:
2011-08-06 23:45:52 +00:00
print _("Printer is not online.")
2011-06-09 10:54:03 +00:00
else:
2011-08-06 23:45:52 +00:00
print _("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
except Exception, x:
2012-08-04 19:51:07 +00:00
print _("You must enter a temperature. (%s)") % (repr(x),)
def do_bedtemp(self, l = ""):
2011-06-09 10:54:03 +00:00
try:
if not l.__class__ in (str, unicode) or not len(l):
l = str(self.btemp.GetValue().split()[0])
2012-08-08 07:58:09 +00:00
l = l.lower().replace(", ", ".")
2011-06-09 10:54:03 +00:00
for i in self.bedtemps.keys():
l = l.replace(i, self.bedtemps[i])
f = float(l)
if f >= 0:
2011-06-09 10:54:03 +00:00
if self.p.online:
self.p.send_now("M140 S"+l)
print _("Setting bed temperature to %f degrees Celsius.") % f
2012-07-15 11:43:34 +00:00
self.setbedgui(f)
2011-06-09 10:54:03 +00:00
else:
2011-08-06 23:45:52 +00:00
print _("Printer is not online.")
2011-06-09 10:54:03 +00:00
else:
2011-08-06 23:45:52 +00:00
print _("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
2012-08-04 19:51:07 +00:00
except Exception, x:
print _("You must enter a temperature. (%s)") % (repr(x),)
2011-07-26 14:34:55 +00:00
def end_macro(self):
pronsole.pronsole.end_macro(self)
self.update_macros_menu()
def delete_macro(self, macro_name):
pronsole.pronsole.delete_macro(self, macro_name)
2011-07-26 14:34:55 +00:00
self.update_macros_menu()
2012-08-08 07:38:48 +00:00
def start_macro(self, macro_name, old_macro_definition = ""):
if not self.processing_rc:
def cb(definition):
if len(definition.strip()) == 0:
if old_macro_definition != "":
dialog = wx.MessageDialog(self, _("Do you want to erase the macro?"), style = wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
if dialog.ShowModal() == wx.ID_YES:
2011-07-26 14:34:55 +00:00
self.delete_macro(macro_name)
return
2011-08-06 23:45:52 +00:00
print _("Cancelled.")
2011-07-26 14:34:55 +00:00
return
self.cur_macro_name = macro_name
self.cur_macro_def = definition
self.end_macro()
2012-09-05 15:30:28 +00:00
MacroEditor(macro_name, old_macro_definition, cb)
else:
pronsole.pronsole.start_macro(self, macro_name, old_macro_definition)
def catchprint(self, l):
if self.capture_skip_newline and len(l) and not len(l.strip("\n\r")):
self.capture_skip_newline = False
return
for pat in self.capture_skip.keys():
if self.capture_skip[pat] > 0 and pat.match(l):
self.capture_skip[pat] -= 1
self.capture_skip_newline = True
return
wx.CallAfter(self.addtexttolog,l);
2011-06-08 14:19:38 +00:00
def scanserial(self):
"""scan for available ports. return a list of device names."""
baselist = []
if os.name == "nt":
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:58:09 +00:00
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM")
i = 0
while True:
baselist += [_winreg.EnumValue(key, i)[1]]
i += 1
2011-06-08 14:19:38 +00:00
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
2012-09-05 08:10:05 +00:00
if self.p.online:
projectlayer.setframe(self,self.p).Show()
else:
print _("Printer is not online.")
2011-06-08 14:19:38 +00:00
def popmenu(self):
self.menustrip = wx.MenuBar()
# File menu
m = wx.Menu()
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.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"))
# Settings menu
m = wx.Menu()
self.macros_menu = wx.Menu()
m.AppendSubMenu(self.macros_menu, _("&Macros"))
self.Bind(wx.EVT_MENU, self.new_macro, self.macros_menu.Append(-1, _("<&New...>")))
2012-08-08 07:58:09 +00:00
self.Bind(wx.EVT_MENU, lambda *e:options(self), m.Append(-1, _("&Options"), _(" Options dialog")))
self.Bind(wx.EVT_MENU, lambda x: threading.Thread(target = lambda:self.do_skein("set")).start(), m.Append(-1, _("Slicing Settings"), _(" Adjust slicing settings")))
mItem = m.AppendCheckItem(-1, _("Debug G-code"),
_("Print all G-code sent to and received from the printer."))
m.Check(mItem.GetId(), self.p.loud)
self.Bind(wx.EVT_MENU, self.setloud, mItem)
2011-11-18 08:52:16 +00:00
#try:
# from SkeinforgeQuickEditDialog import SkeinforgeQuickEditDialog
# self.Bind(wx.EVT_MENU, lambda *e:SkeinforgeQuickEditDialog(self), m.Append(-1,_("SFACT Quick Settings"),_(" Quickly adjust SFACT settings for active profile")))
#except:
# pass
2011-09-06 19:26:37 +00:00
self.menustrip.Append(m, _("&Settings"))
2011-07-26 14:34:55 +00:00
self.update_macros_menu()
2011-06-08 14:19:38 +00:00
self.SetMenuBar(self.menustrip)
def doneediting(self, gcode):
f = open(self.filename, "w")
2011-08-06 13:28:25 +00:00
f.write("\n".join(gcode))
f.close()
wx.CallAfter(self.loadfile, None, self.filename)
def do_editgcode(self, e = None):
if self.filename is not None:
2012-09-05 15:30:28 +00:00
MacroEditor(self.filename, self.f, self.doneediting, 1)
def new_macro(self, e = None):
dialog = wx.Dialog(self, -1, _("Enter macro name"), size = (260, 85))
panel = wx.Panel(dialog, -1)
2011-07-26 14:34:55 +00:00
vbox = wx.BoxSizer(wx.VERTICAL)
wx.StaticText(panel, -1, _("Macro name:"), (8, 14))
2012-08-08 07:38:48 +00:00
dialog.namectrl = wx.TextCtrl(panel, -1, '', (110, 8), size = (130, 24), style = wx.TE_PROCESS_ENTER)
2011-07-26 14:34:55 +00:00
hbox = wx.BoxSizer(wx.HORIZONTAL)
okb = wx.Button(dialog, wx.ID_OK, _("Ok"), size = (60, 24))
dialog.Bind(wx.EVT_TEXT_ENTER, lambda e:dialog.EndModal(wx.ID_OK), dialog.namectrl)
#dialog.Bind(wx.EVT_BUTTON, lambda e:self.new_macro_named(dialog, e), okb)
2011-07-26 14:34:55 +00:00
hbox.Add(okb)
hbox.Add(wx.Button(dialog, wx.ID_CANCEL, _("Cancel"), size = (60, 24)))
2011-07-26 14:34:55 +00:00
vbox.Add(panel)
vbox.Add(hbox, 1, wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 10)
2011-07-26 14:34:55 +00:00
dialog.SetSizer(vbox)
dialog.Centre()
macro = ""
if dialog.ShowModal() == wx.ID_OK:
macro = dialog.namectrl.GetValue()
if macro != "":
wx.CallAfter(self.edit_macro, macro)
dialog.Destroy()
return macro
def edit_macro(self, macro):
if macro == "": return self.new_macro()
if self.macros.has_key(macro):
old_def = self.macros[macro]
2012-08-08 07:58:09 +00:00
elif len([c for c in macro.encode("ascii", "replace") if not c.isalnum() and c != "_"]):
print _("Macro name may contain only ASCII alphanumeric symbols and underscores")
return
2012-08-08 07:58:09 +00:00
elif hasattr(self.__class__, "do_"+macro):
print _("Name '%s' is being used by built-in command") % macro
return
else:
old_def = ""
2012-08-08 07:38:48 +00:00
self.start_macro(macro, old_def)
return macro
2011-07-26 14:34:55 +00:00
def update_macros_menu(self):
2012-08-08 07:58:09 +00:00
if not hasattr(self, "macros_menu"):
2011-07-26 14:34:55 +00:00
return # too early, menu not yet built
try:
while True:
item = self.macros_menu.FindItemByPosition(1)
if item is None: return
self.macros_menu.DeleteItem(item)
except:
pass
for macro in self.macros.keys():
self.Bind(wx.EVT_MENU, lambda x, m = macro: self.start_macro(m, self.macros[m]), self.macros_menu.Append(-1, macro))
2011-07-26 14:34:55 +00:00
2011-06-08 14:19:38 +00:00
def OnExit(self, event):
self.Close()
def rescanports(self, event = None):
scan = self.scanserial()
portslist = list(scan)
if self.settings.port != "" and self.settings.port not in portslist:
portslist += [self.settings.port]
2011-11-13 20:44:45 +00:00
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
2012-08-08 07:38:48 +00:00
def cbkey(self, e):
if e.GetKeyCode() == wx.WXK_UP:
if self.commandbox.histindex == len(self.commandbox.history):
self.commandbox.history+=[self.commandbox.GetValue()] #save current command
if len(self.commandbox.history):
2012-08-08 07:38:48 +00:00
self.commandbox.histindex = (self.commandbox.histindex-1)%len(self.commandbox.history)
self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex])
2012-08-08 07:38:48 +00:00
self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex]))
elif e.GetKeyCode() == wx.WXK_DOWN:
if self.commandbox.histindex == len(self.commandbox.history):
self.commandbox.history+=[self.commandbox.GetValue()] #save current command
if len(self.commandbox.history):
2012-08-08 07:38:48 +00:00
self.commandbox.histindex = (self.commandbox.histindex+1)%len(self.commandbox.history)
self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex])
2012-08-08 07:38:48 +00:00
self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex]))
else:
e.Skip()
2012-08-08 07:38:48 +00:00
def plate(self, e):
2011-11-18 08:52:16 +00:00
import plater
print "plate function activated"
2012-08-08 07:58:09 +00:00
plater.stlwin(size = (800, 580), callback = self.platecb, parent = self).Show()
2012-08-08 07:38:48 +00:00
def platecb(self, name):
2011-11-18 08:52:16 +00:00
print "plated: "+name
2012-08-08 07:38:48 +00:00
self.loadfile(None, name)
2012-08-08 07:38:48 +00:00
def sdmenu(self, e):
2011-11-18 08:52:16 +00:00
obj = e.GetEventObject()
2012-08-08 07:38:48 +00:00
popupmenu = wx.Menu()
item = popupmenu.Append(-1, _("SD Upload"))
if not self.f or not len(self.f):
item.Enable(False)
2012-08-08 07:38:48 +00:00
self.Bind(wx.EVT_MENU, self.upload, id = item.GetId())
item = popupmenu.Append(-1, _("SD Print"))
self.Bind(wx.EVT_MENU, self.sdprintfile, id = item.GetId())
2011-11-18 08:52:16 +00:00
self.panel.PopupMenu(popupmenu, obj.GetPosition())
2012-08-08 07:38:48 +00:00
def htemp_change(self, event):
if self.hsetpoint > 0:
self.do_settemp("")
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.htemp.SetInsertionPoint, 0)
2012-08-08 07:38:48 +00:00
def btemp_change(self, event):
if self.bsetpoint > 0:
self.do_bedtemp("")
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.btemp.SetInsertionPoint, 0)
2012-08-08 07:38:48 +00:00
def showwin(self, event):
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()
2012-08-08 07:38:48 +00:00
def setfeeds(self, e):
2011-06-29 21:31:57 +00:00
self.feedrates_changed = True
2011-06-09 16:44:57 +00:00
try:
2012-08-08 07:58:09 +00:00
self.settings._set("e_feedrate", self.efeedc.GetValue())
2011-06-09 16:44:57 +00:00
except:
pass
try:
2012-08-08 07:58:09 +00:00
self.settings._set("z_feedrate", self.zfeedc.GetValue())
2011-06-09 16:44:57 +00:00
except:
pass
try:
2012-08-08 07:58:09 +00:00
self.settings._set("xy_feedrate", self.xyfeedc.GetValue())
2011-06-09 16:44:57 +00:00
except:
pass
2012-08-08 07:38:48 +00:00
def toggleview(self, e):
if(self.mini):
2012-08-08 07:38:48 +00:00
self.mini = False
2012-09-05 11:09:38 +00:00
self.mainsizer.Fit(self)
2011-06-16 04:28:46 +00:00
#self.SetSize(winsize)
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.minibtn.SetLabel, _("Mini mode"))
else:
2012-08-08 07:38:48 +00:00
self.mini = True
2011-06-16 04:28:46 +00:00
self.uppersizer.Fit(self)
2011-06-16 04:28:46 +00:00
#self.SetSize(winssize)
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.minibtn.SetLabel, _("Full mode"))
2011-08-03 11:26:16 +00:00
def cbuttons_reload(self):
allcbs = []
2012-09-05 11:09:38 +00:00
ubs = self.uppersizer
2012-08-08 07:38:48 +00:00
cs = self.centersizer
#for item in ubs.GetChildren():
# if hasattr(item.GetWindow(),"custombutton"):
2012-08-08 07:38:48 +00:00
# allcbs += [(ubs, item.GetWindow())]
2011-08-03 11:26:16 +00:00
for item in cs.GetChildren():
if hasattr(item.GetWindow(),"custombutton"):
2012-08-08 07:38:48 +00:00
allcbs += [(cs, item.GetWindow())]
for sizer, button in allcbs:
2011-08-03 11:26:16 +00:00
#sizer.Remove(button)
button.Destroy()
2012-08-08 07:58:09 +00:00
self.custombuttonbuttons = []
2011-11-14 19:35:18 +00:00
newbuttonbuttonindex = len(self.custombuttons)
while newbuttonbuttonindex>0 and self.custombuttons[newbuttonbuttonindex-1] is None:
newbuttonbuttonindex -= 1
2011-09-30 14:41:18 +00:00
while len(self.custombuttons) < 13:
self.custombuttons.append(None)
2011-08-03 11:26:16 +00:00
for i in xrange(len(self.custombuttons)):
btndef = self.custombuttons[i]
try:
b = wx.Button(self.panel, -1, btndef.label, style = wx.BU_EXACTFIT)
b.SetToolTip(wx.ToolTip(_("Execute command: ")+btndef.command))
if btndef.background:
b.SetBackgroundColour(btndef.background)
2012-08-08 07:38:48 +00:00
rr, gg, bb = b.GetBackgroundColour().Get()
2011-08-03 11:26:16 +00:00
if 0.3*rr+0.59*gg+0.11*bb < 60:
b.SetForegroundColour("#ffffff")
except:
2011-11-14 19:35:18 +00:00
if i == newbuttonbuttonindex:
self.newbuttonbutton = b = wx.Button(self.panel, -1, "+", size = (19, 18), style = wx.BU_EXACTFIT)
2012-08-08 07:38:48 +00:00
#b.SetFont(wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
2011-11-14 19:35:18 +00:00
b.SetForegroundColour("#4444ff")
2011-11-14 19:43:16 +00:00
b.SetToolTip(wx.ToolTip(_("click to add new custom button")))
2012-08-08 07:38:48 +00:00
b.Bind(wx.EVT_BUTTON, self.cbutton_edit)
2011-11-14 19:35:18 +00:00
else:
2012-08-08 07:58:09 +00:00
b = wx.Button(self.panel,-1, ".", size = (1, 1))
#b = wx.StaticText(self.panel,-1, "", size = (72, 22), style = wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE) #+wx.SIMPLE_BORDER
b.Disable()
#continue
2012-08-08 07:38:48 +00:00
b.custombutton = i
b.properties = btndef
if btndef is not None:
2012-08-08 07:38:48 +00:00
b.Bind(wx.EVT_BUTTON, self.procbutton)
b.Bind(wx.EVT_MOUSE_EVENTS, self.editbutton)
2011-11-14 19:35:18 +00:00
#else:
2012-08-08 07:38:48 +00:00
# b.Bind(wx.EVT_BUTTON, lambda e:e.Skip())
2011-09-30 14:41:18 +00:00
self.custombuttonbuttons.append(b)
#if i<4:
# ubs.Add(b)
#else:
2012-08-08 07:58:09 +00:00
cs.Add(b, pos = ((i)/4, (i)%4))
2012-09-05 11:09:38 +00:00
self.mainsizer.Layout()
2011-08-03 11:26:16 +00:00
def help_button(self):
2011-08-06 23:45:52 +00:00
print _('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
2012-08-08 07:38:48 +00:00
def do_button(self, argstr):
2011-08-03 11:26:16 +00:00
def nextarg(rest):
2012-08-08 07:38:48 +00:00
rest = rest.lstrip()
2011-08-03 11:26:16 +00:00
if rest.startswith('"'):
return rest[1:].split('"',1)
2011-08-03 11:26:16 +00:00
else:
2012-08-08 07:38:48 +00:00
return rest.split(None, 1)
2011-08-03 11:26:16 +00:00
#try:
2012-08-08 07:38:48 +00:00
num, argstr = nextarg(argstr)
num = int(num)
title, argstr = nextarg(argstr)
colour = None
2011-08-03 11:26:16 +00:00
try:
2012-08-08 07:38:48 +00:00
c1, c2 = nextarg(argstr)
if c1 == "/c":
colour, argstr = nextarg(c2)
2011-08-03 11:26:16 +00:00
except:
pass
2012-08-08 07:38:48 +00:00
command = argstr.strip()
2011-08-03 11:26:16 +00:00
if num<0 or num>=64:
2011-08-06 23:45:52 +00:00
print _("Custom button number should be between 0 and 63")
2011-08-03 11:26:16 +00:00
return
while num >= len(self.custombuttons):
self.custombuttons.append(None)
self.custombuttons[num] = SpecialButton(title, command)
2011-08-03 11:26:16 +00:00
if colour is not None:
self.custombuttons[num].background = colour
2011-08-03 11:26:16 +00:00
if not self.processing_rc:
self.cbuttons_reload()
2012-08-08 07:38:48 +00:00
#except Exception, x:
2011-08-03 11:26:16 +00:00
# print "Bad syntax for button definition, see 'help button'"
# print x
2012-08-08 07:38:48 +00:00
def cbutton_save(self, n, bdef, new_n = None):
if new_n is None: new_n = n
2011-08-03 11:26:16 +00:00
if bdef is None or bdef == "":
self.save_in_rc(("button %d" % n),'')
elif bdef.background:
colour = bdef.background
2012-08-08 07:38:48 +00:00
if type(colour) not in (str, unicode):
2012-08-08 07:58:09 +00:00
#print type(colour), map(type, colour)
2012-08-08 07:38:48 +00:00
if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int):
colour = map(lambda x:x%256, colour)
colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX)
else:
colour = wx.Colour(colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX)
self.save_in_rc(("button %d" % n),'button %d "%s" /c "%s" %s' % (new_n, bdef.label, colour, bdef.command))
2011-08-03 11:26:16 +00:00
else:
self.save_in_rc(("button %d" % n),'button %d "%s" %s' % (new_n, bdef.label, bdef.command))
2011-08-03 11:26:16 +00:00
2012-08-08 07:38:48 +00:00
def cbutton_edit(self, e, button = None):
bedit = ButtonEdit(self)
2011-08-03 11:26:16 +00:00
if button is not None:
n = button.custombutton
2012-09-06 17:32:23 +00:00
bedit.name.SetValue(button.properties.label)
bedit.command.SetValue(button.properties.command)
if button.properties.background:
colour = button.properties.background
2012-08-08 07:38:48 +00:00
if type(colour) not in (str, unicode):
#print type(colour)
2012-08-08 07:38:48 +00:00
if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int):
colour = map(lambda x:x%256, colour)
colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX)
else:
colour = wx.Colour(colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX)
2011-08-03 11:26:16 +00:00
bedit.color.SetValue(colour)
else:
n = len(self.custombuttons)
2011-09-30 14:41:18 +00:00
while n>0 and self.custombuttons[n-1] is None:
n -= 1
2012-08-08 07:38:48 +00:00
if bedit.ShowModal() == wx.ID_OK:
if n == len(self.custombuttons):
2012-04-22 23:33:47 +00:00
self.custombuttons+=[None]
self.custombuttons[n]=SpecialButton(bedit.name.GetValue().strip(), bedit.command.GetValue().strip(), custom = True)
2012-04-22 23:33:47 +00:00
if bedit.color.GetValue().strip()!="":
self.custombuttons[n].background = bedit.color.GetValue()
2012-08-08 07:38:48 +00:00
self.cbutton_save(n, self.custombuttons[n])
2012-04-22 23:33:47 +00:00
bedit.Destroy()
self.cbuttons_reload()
2012-08-08 07:38:48 +00:00
def cbutton_remove(self, e, button):
2011-08-03 11:26:16 +00:00
n = button.custombutton
self.custombuttons[n]=None
2012-08-08 07:38:48 +00:00
self.cbutton_save(n, None)
2011-09-30 14:41:18 +00:00
#while len(self.custombuttons) and self.custombuttons[-1] is None:
# del self.custombuttons[-1]
2011-11-14 19:35:18 +00:00
wx.CallAfter(self.cbuttons_reload)
2012-08-08 07:38:48 +00:00
def cbutton_order(self, e, button, dir):
2011-08-03 11:26:16 +00:00
n = button.custombutton
if dir<0:
2012-08-08 07:38:48 +00:00
n = n-1
2011-08-03 11:26:16 +00:00
if n+1 >= len(self.custombuttons):
self.custombuttons+=[None] # pad
# swap
2012-08-08 07:58:09 +00:00
self.custombuttons[n], self.custombuttons[n+1] = self.custombuttons[n+1], self.custombuttons[n]
2012-08-08 07:38:48 +00:00
self.cbutton_save(n, self.custombuttons[n])
self.cbutton_save(n+1, self.custombuttons[n+1])
2011-09-30 14:41:18 +00:00
#if self.custombuttons[-1] is None:
# del self.custombuttons[-1]
2011-08-03 11:26:16 +00:00
self.cbuttons_reload()
2012-08-08 07:38:48 +00:00
def editbutton(self, e):
if e.IsCommandEvent() or e.ButtonUp(wx.MOUSE_BTN_RIGHT):
if e.IsCommandEvent():
2012-08-08 07:38:48 +00:00
pos = (0, 0)
else:
pos = e.GetPosition()
2011-08-03 11:26:16 +00:00
popupmenu = wx.Menu()
obj = e.GetEventObject()
2012-08-08 07:58:09 +00:00
if hasattr(obj, "custombutton"):
2012-08-08 07:38:48 +00:00
item = popupmenu.Append(-1, _("Edit custom button '%s'") % e.GetEventObject().GetLabelText())
2012-08-08 07:58:09 +00:00
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_edit(e, button), item)
2012-08-08 07:38:48 +00:00
item = popupmenu.Append(-1, _("Move left <<"))
2012-08-08 07:58:09 +00:00
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_order(e, button,-1), item)
2011-08-03 11:26:16 +00:00
if obj.custombutton == 0: item.Enable(False)
2012-08-08 07:38:48 +00:00
item = popupmenu.Append(-1, _("Move right >>"))
2012-08-08 07:58:09 +00:00
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_order(e, button, 1), item)
2011-08-03 11:26:16 +00:00
if obj.custombutton == 63: item.Enable(False)
pos = self.panel.ScreenToClient(e.GetEventObject().ClientToScreen(pos))
2012-08-08 07:38:48 +00:00
item = popupmenu.Append(-1, _("Remove custom button '%s'") % e.GetEventObject().GetLabelText())
2012-08-08 07:58:09 +00:00
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_remove(e, button), item)
2011-08-03 11:26:16 +00:00
else:
2012-08-08 07:38:48 +00:00
item = popupmenu.Append(-1, _("Add custom button"))
self.Bind(wx.EVT_MENU, self.cbutton_edit, item)
2011-08-03 11:26:16 +00:00
self.panel.PopupMenu(popupmenu, pos)
2011-09-30 14:41:18 +00:00
elif e.Dragging() and e.ButtonIsDown(wx.MOUSE_BTN_LEFT):
obj = e.GetEventObject()
scrpos = obj.ClientToScreen(e.GetPosition())
2012-08-08 07:58:09 +00:00
if not hasattr(self, "dragpos"):
self.dragpos = scrpos
e.Skip()
return
else:
2012-08-08 07:58:09 +00:00
dx, dy = self.dragpos[0]-scrpos[0], self.dragpos[1]-scrpos[1]
if dx*dx+dy*dy < 5*5: # threshold to detect dragging for jittery mice
e.Skip()
return
2012-08-08 07:58:09 +00:00
if not hasattr(self, "dragging"):
2011-09-30 14:41:18 +00:00
# init dragging of the custom button
2012-08-08 07:58:09 +00:00
if hasattr(obj, "custombutton") and obj.properties is not None:
#self.newbuttonbutton.SetLabel("")
2012-08-08 07:38:48 +00:00
#self.newbuttonbutton.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
#self.newbuttonbutton.SetForegroundColour("black")
#self.newbuttonbutton.SetSize(obj.GetSize())
2012-09-05 12:37:03 +00:00
#if self.uppersizer.GetItem(self.newbuttonbutton) is not None:
# self.uppersizer.SetItemMinSize(self.newbuttonbutton, obj.GetSize())
2012-09-05 11:09:38 +00:00
# self.mainsizer.Layout()
for b in self.custombuttonbuttons:
#if b.IsFrozen(): b.Thaw()
if b.properties is None:
b.Enable()
b.SetLabel("")
2012-08-08 07:38:48 +00:00
b.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
b.SetForegroundColour("black")
b.SetSize(obj.GetSize())
2012-09-05 12:37:03 +00:00
if self.uppersizer.GetItem(b) is not None:
self.uppersizer.SetItemMinSize(b, obj.GetSize())
2012-09-05 11:09:38 +00:00
self.mainsizer.Layout()
# b.SetStyle(wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE+wx.SIMPLE_BORDER)
2012-08-08 07:58:09 +00:00
self.dragging = wx.Button(self.panel,-1, obj.GetLabel(), style = wx.BU_EXACTFIT)
2011-09-30 14:41:18 +00:00
self.dragging.SetBackgroundColour(obj.GetBackgroundColour())
self.dragging.SetForegroundColour(obj.GetForegroundColour())
2011-09-30 14:41:18 +00:00
self.dragging.sourcebutton = obj
self.dragging.Raise()
self.dragging.Disable()
self.dragging.SetPosition(self.panel.ScreenToClient(scrpos))
self.last_drag_dest = obj
self.dragging.label = obj.s_label = obj.GetLabel()
self.dragging.bgc = obj.s_bgc = obj.GetBackgroundColour()
self.dragging.fgc = obj.s_fgc = obj.GetForegroundColour()
else:
2011-09-30 14:41:18 +00:00
# dragging in progress
self.dragging.SetPosition(self.panel.ScreenToClient(scrpos))
wx.CallAfter(self.dragging.Refresh)
btns = self.custombuttonbuttons
2011-09-30 14:41:18 +00:00
dst = None
src = self.dragging.sourcebutton
drg = self.dragging
for b in self.custombuttonbuttons:
if b.GetScreenRect().Contains(scrpos):
dst = b
break
#if dst is None and self.panel.GetScreenRect().Contains(scrpos):
# # try to check if it is after buttons at the end
2012-09-05 12:37:03 +00:00
# tspos = self.panel.ClientToScreen(self.uppersizer.GetPosition())
2011-09-30 14:41:18 +00:00
# bspos = self.panel.ClientToScreen(self.centersizer.GetPosition())
2012-09-05 12:37:03 +00:00
# tsrect = wx.Rect(*(tspos.Get()+self.uppersizer.GetSize().Get()))
2011-09-30 14:41:18 +00:00
# bsrect = wx.Rect(*(bspos.Get()+self.centersizer.GetSize().Get()))
# lbrect = btns[-1].GetScreenRect()
# p = scrpos.Get()
# if len(btns)<4 and tsrect.Contains(scrpos):
# if lbrect.GetRight() < p[0]:
# print "Right of last button on upper cb sizer"
# if bsrect.Contains(scrpos):
# if lbrect.GetBottom() < p[1]:
# print "Below last button on lower cb sizer"
# if lbrect.GetRight() < p[0] and lbrect.GetTop() <= p[1] and lbrect.GetBottom() >= p[1]:
# print "Right to last button on lower cb sizer"
if dst is not self.last_drag_dest:
if self.last_drag_dest is not None:
self.last_drag_dest.SetBackgroundColour(self.last_drag_dest.s_bgc)
self.last_drag_dest.SetForegroundColour(self.last_drag_dest.s_fgc)
2011-09-30 14:41:18 +00:00
self.last_drag_dest.SetLabel(self.last_drag_dest.s_label)
if dst is not None and dst is not src:
dst.s_bgc = dst.GetBackgroundColour()
dst.s_fgc = dst.GetForegroundColour()
2011-09-30 14:41:18 +00:00
dst.s_label = dst.GetLabel()
src.SetBackgroundColour(dst.GetBackgroundColour())
src.SetForegroundColour(dst.GetForegroundColour())
2011-09-30 14:41:18 +00:00
src.SetLabel(dst.GetLabel())
dst.SetBackgroundColour(drg.bgc)
dst.SetForegroundColour(drg.fgc)
2011-09-30 14:41:18 +00:00
dst.SetLabel(drg.label)
else:
src.SetBackgroundColour(drg.bgc)
src.SetForegroundColour(drg.fgc)
2011-09-30 14:41:18 +00:00
src.SetLabel(drg.label)
self.last_drag_dest = dst
2012-08-08 07:58:09 +00:00
elif hasattr(self, "dragging") and not e.ButtonIsDown(wx.MOUSE_BTN_LEFT):
2011-09-30 14:41:18 +00:00
# dragging finished
obj = e.GetEventObject()
scrpos = obj.ClientToScreen(e.GetPosition())
dst = None
src = self.dragging.sourcebutton
drg = self.dragging
for b in self.custombuttonbuttons:
if b.GetScreenRect().Contains(scrpos):
dst = b
break
if dst is not None:
src_i = src.custombutton
dst_i = dst.custombutton
2012-08-08 07:58:09 +00:00
self.custombuttons[src_i], self.custombuttons[dst_i] = self.custombuttons[dst_i], self.custombuttons[src_i]
2012-08-08 07:38:48 +00:00
self.cbutton_save(src_i, self.custombuttons[src_i])
self.cbutton_save(dst_i, self.custombuttons[dst_i])
2011-09-30 14:41:18 +00:00
while self.custombuttons[-1] is None:
del self.custombuttons[-1]
wx.CallAfter(self.dragging.Destroy)
del self.dragging
wx.CallAfter(self.cbuttons_reload)
del self.last_drag_dest
del self.dragpos
2011-08-03 11:26:16 +00:00
else:
2011-09-30 14:41:18 +00:00
e.Skip()
def homeButtonClicked(self, corner):
# When user clicks on the XY control, the Z control no longer gets spacebar/repeat signals
self.zb.clearRepeat()
if corner == 0: # upper-left
self.onecmd('home X')
elif corner == 1: # upper-right
self.onecmd('home Y')
elif corner == 2: # lower-right
self.onecmd('home Z')
elif corner == 3: # lower-left
self.onecmd('home')
else:
return
self.onecmd('M114')
2011-11-07 19:41:14 +00:00
def moveXY(self, x, y):
# When user clicks on the XY control, the Z control no longer gets spacebar/repeat signals
self.zb.clearRepeat()
2011-11-07 19:41:14 +00:00
if x != 0:
self.onecmd('move X %s' % x)
elif y != 0:
2011-11-07 19:41:14 +00:00
self.onecmd('move Y %s' % y)
else:
return
self.onecmd('M114')
2011-11-07 19:41:14 +00:00
def moveZ(self, z):
if z != 0:
self.onecmd('move Z %s' % z)
self.onecmd('M114')
# When user clicks on the Z control, the XY control no longer gets spacebar/repeat signals
self.xyb.clearRepeat()
def spacebarAction(self):
self.zb.repeatLast()
self.xyb.repeatLast()
2012-08-08 07:38:48 +00:00
def procbutton(self, e):
try:
if hasattr(e.GetEventObject(),"custombutton"):
2011-08-04 19:28:34 +00:00
if wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT):
return self.editbutton(e)
2012-08-08 07:38:48 +00:00
self.cur_button = e.GetEventObject().custombutton
2012-09-06 07:02:47 +00:00
self.onecmd(e.GetEventObject().properties.command)
2012-08-08 07:38:48 +00:00
self.cur_button = None
except:
2011-08-06 23:45:52 +00:00
print _("event object missing")
2012-08-08 07:38:48 +00:00
self.cur_button = None
raise
2012-08-08 07:38:48 +00:00
def kill(self, e):
2012-08-04 20:24:45 +00:00
self.statuscheck = False
if self.status_thread:
self.status_thread.join()
self.status_thread = None
2012-08-08 07:38:48 +00:00
self.p.recvcb = None
2011-06-08 14:19:38 +00:00
self.p.disconnect()
2012-08-08 07:58:09 +00:00
if hasattr(self, "feedrates_changed"):
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)
wx.CallAfter(self.gwindow.Destroy)
wx.CallAfter(self.Destroy)
2012-08-08 07:38:48 +00:00
def do_monitor(self, l = ""):
if l.strip()=="":
self.monitorbox.SetValue(not self.monitorbox.GetValue())
elif l.strip()=="off":
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.monitorbox.SetValue, False)
else:
try:
2012-08-08 07:38:48 +00:00
self.monitor_interval = float(l)
wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval>0)
except:
2011-08-06 23:45:52 +00:00
print _("Invalid period given.")
self.setmonitor(None)
if self.monitor:
2011-08-06 23:45:52 +00:00
print _("Monitoring printer.")
else:
2011-08-06 23:45:52 +00:00
print _("Done monitoring.")
2012-08-08 07:38:48 +00:00
def setmonitor(self, e):
self.monitor = self.monitorbox.GetValue()
if self.monitor:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.graph.StartPlotting, 1000)
else:
2012-05-04 04:40:19 +00:00
wx.CallAfter(self.graph.StopPlotting)
def addtexttolog(self,text):
try:
self.logbox.AppendText(text)
except:
print _("Attempted to write invalid text to console, which could be due to an invalid baudrate")
2012-09-05 08:11:48 +00:00
def setloud(self,e):
self.p.loud=e.IsChecked()
2012-09-05 08:10:05 +00:00
def sendline(self, e):
command = self.commandbox.GetValue()
if not len(command):
return
2012-09-05 08:10:05 +00:00
wx.CallAfter(self.addtexttolog, ">>>" + command + "\n");
2011-06-11 21:03:01 +00:00
self.onecmd(str(command))
2012-08-08 07:38:48 +00:00
self.commandbox.SetSelection(0, len(command))
2013-05-18 20:37:49 +00:00
self.commandbox.history.append(command)
2012-08-08 07:38:48 +00:00
self.commandbox.histindex = len(self.commandbox.history)
2012-08-08 07:38:48 +00:00
def clearOutput(self, e):
self.logbox.Clear()
2013-05-17 14:59:28 +00:00
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 update_pos(self, l):
bits = gcoder.m114_exp.findall(l)
x = None
y = None
z = None
for bit in bits:
if not x and bit.startswith("X"):
x = float(bit[1:].replace(":",""))
elif not y and bit.startswith("Y"):
y = float(bit[1:].replace(":",""))
elif not z and bit.startswith("Z"):
z = float(bit[1:].replace(":",""))
if x: self.current_pos[0] = x
if y: self.current_pos[1] = y
if z: self.current_pos[2] = z
2011-06-08 14:19:38 +00:00
def statuschecker(self):
while self.statuscheck:
string = ""
fractioncomplete = 0.0
if self.sdprinting:
fractioncomplete = float(self.percentdone / 100.0)
string += _(" SD printing:%04.2f %%") % (self.percentdone,)
if self.p.printing:
fractioncomplete = float(self.p.queueindex) / len(self.p.mainqueue)
string += _(" Printing: %04.2f%% |") % (100*float(self.p.queueindex)/len(self.p.mainqueue),)
string += _(" Line# %d of %d lines |" ) % (self.p.queueindex, len(self.p.mainqueue))
if fractioncomplete > 0.0:
secondselapsed = int(time.time() - self.starttime + self.extra_print_time)
secondsestimate = secondselapsed / fractioncomplete
secondsremain = secondsestimate - secondselapsed
2012-08-07 11:54:07 +00:00
string += _(" Est: %s of %s remaining | ") % (format_duration(secondsremain),
format_duration(secondsestimate))
string += _(" Z: %0.2f mm") % self.curlayer
wx.CallAfter(self.status.SetStatusText, string)
wx.CallAfter(self.gviz.Refresh)
if(self.monitor and self.p.online):
if self.sdprinting:
self.p.send_now("M27")
2012-08-08 07:58:09 +00:00
if not hasattr(self, "auto_monitor_pattern"):
self.auto_monitor_pattern = re.compile(r"(ok\s+)?T:[\d\.]+(\s+B:[\d\.]+)?(\s+@:[\d\.]+)?\s*")
self.capture_skip[self.auto_monitor_pattern] = self.capture_skip.setdefault(self.auto_monitor_pattern, 0) + 1
self.p.send_now("M105")
cur_time = time.time()
while time.time() < cur_time + self.monitor_interval:
if not self.statuscheck:
break
time.sleep(0.25)
while not self.sentlines.empty():
2013-05-18 16:38:54 +00:00
gc = self.sentlines.get_nowait()
wx.CallAfter(self.gviz.addgcode, gc, 1)
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Not connected to printer."))
2011-06-08 14:19:38 +00:00
def capture(self, func, *args, **kwargs):
2012-08-08 07:38:48 +00:00
stdout = sys.stdout
cout = None
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:38:48 +00:00
cout = self.cout
2011-06-08 14:19:38 +00:00
except:
pass
if cout is None:
2012-08-08 07:38:48 +00:00
cout = cStringIO.StringIO()
2012-08-08 07:38:48 +00:00
sys.stdout = cout
retval = None
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:38:48 +00:00
retval = func(*args,**kwargs)
2011-06-08 14:19:38 +00:00
except:
traceback.print_exc()
2012-08-08 07:38:48 +00:00
sys.stdout = stdout
2011-06-08 14:19:38 +00:00
return retval
2012-08-08 07:38:48 +00:00
def recvcb(self, l):
if "ok C:" in l:
self.posreport = l
self.update_pos()
if "ok T:" in l:
2012-08-08 07:38:48 +00:00
self.tempreport = l
2012-08-08 07:58:09 +00:00
wx.CallAfter(self.tempdisp.SetLabel, self.tempreport.strip().replace("ok ", ""))
2013-05-17 14:59:28 +00:00
self.update_tempdisplay()
2012-08-08 07:38:48 +00:00
tstring = l.rstrip()
2013-05-18 21:01:13 +00:00
if self.p.loud or (tstring not in ["ok", "wait"] and "ok T:" not in tstring and "ok C:" not in tstring):
2012-09-05 08:10:05 +00:00
wx.CallAfter(self.addtexttolog, tstring + "\n");
2013-05-18 21:01:13 +00:00
for listener in self.recvlisteners:
listener(l)
def listfiles(self, line, ignored = False):
2011-06-08 14:19:38 +00:00
if "Begin file list" in line:
2012-08-08 07:38:48 +00:00
self.listing = 1
2011-06-08 14:19:38 +00:00
elif "End file list" in line:
2012-08-08 07:38:48 +00:00
self.listing = 0
2011-06-08 14:19:38 +00:00
self.recvlisteners.remove(self.listfiles)
wx.CallAfter(self.filesloaded)
elif self.listing:
self.sdfiles.append(line.strip().lower())
2012-08-08 07:38:48 +00:00
def waitforsdresponse(self, l):
2011-06-08 14:19:38 +00:00
if "file.open failed" in l:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Opening file failed."))
2011-06-08 14:19:38 +00:00
self.recvlisteners.remove(self.waitforsdresponse)
return
if "File opened" in l:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, l)
2011-06-08 14:19:38 +00:00
if "File selected" in l:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Starting print"))
self.sdprinting = 1
self.p.send_now("M24")
self.startcb()
2011-06-08 14:19:38 +00:00
return
if "Done printing file" in l:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, l)
self.sdprinting = 0
2011-06-08 14:19:38 +00:00
self.recvlisteners.remove(self.waitforsdresponse)
self.endcb()
2011-06-08 14:19:38 +00:00
return
if "SD printing byte" in l:
#M27 handler
try:
2012-08-08 07:38:48 +00:00
resp = l.split()
vals = resp[-1].split("/")
self.percentdone = 100.0*int(vals[0])/int(vals[1])
2011-06-08 14:19:38 +00:00
except:
pass
2011-06-08 14:19:38 +00:00
def filesloaded(self):
2012-08-08 07:38:48 +00:00
dlg = wx.SingleChoiceDialog(self, _("Select the file to print"), _("Pick SD file"), self.sdfiles)
if(dlg.ShowModal() == wx.ID_OK):
target = dlg.GetStringSelection()
2011-06-08 14:19:38 +00:00
if len(target):
self.recvlisteners+=[self.waitforsdresponse]
self.p.send_now("M23 "+target.lower())
#print self.sdfiles
def getfiles(self):
if not self.p.online:
2012-08-08 07:58:09 +00:00
self.sdfiles = []
2011-06-08 14:19:38 +00:00
return
2012-08-08 07:38:48 +00:00
self.listing = 0
2012-08-08 07:58:09 +00:00
self.sdfiles = []
2011-06-08 14:19:38 +00:00
self.recvlisteners+=[self.listfiles]
self.p.send_now("M21")
2011-06-08 14:19:38 +00:00
self.p.send_now("M20")
2011-06-08 14:19:38 +00:00
def skein_func(self):
try:
param = self.expandcommand(self.settings.slicecommand).encode()
2012-08-08 07:58:09 +00:00
print "Slicing: ", param
pararray = [i.replace("$s", self.filename).replace("$o", self.filename.replace(".stl", "_export.gcode").replace(".STL", "_export.gcode")).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
#print pararray
2012-08-08 07:38:48 +00:00
self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
2011-11-18 08:52:16 +00:00
while True:
o = self.skeinp.stdout.read(1)
if o == '' and self.skeinp.poll() != None: break
sys.stdout.write(o)
self.skeinp.wait()
2012-08-08 07:38:48 +00:00
self.stopsf = 1
2011-06-08 14:19:38 +00:00
except:
print _("Failed to execute slicing software: ")
2012-08-08 07:38:48 +00:00
self.stopsf = 1
traceback.print_exc(file = sys.stdout)
2011-06-08 14:19:38 +00:00
def skein_monitor(self):
while(not self.stopsf):
try:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Slicing..."))#+self.cout.getvalue().split("\n")[-1])
2011-06-08 14:19:38 +00:00
except:
pass
time.sleep(0.1)
2012-08-08 07:38:48 +00:00
fn = self.filename
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:58:09 +00:00
self.filename = self.filename.replace(".stl", "_export.gcode").replace(".STL", "_export.gcode").replace(".obj", "_export.gcode").replace(".OBJ", "_export.gcode")
2012-08-08 07:38:48 +00:00
of = open(self.filename)
2012-08-08 07:58:09 +00:00
self.f = [i.replace("\n", "").replace("\r", "") for i in of]
of.close()
if self.p.online:
wx.CallAfter(self.printbtn.Enable)
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Loaded ")+self.filename+_(", %d lines") % (len(self.f),))
wx.CallAfter(self.pausebtn.Disable)
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
2012-08-08 07:38:48 +00:00
threading.Thread(target = self.loadviz).start()
2011-06-08 14:19:38 +00:00
except:
2012-08-08 07:38:48 +00:00
self.filename = fn
wx.CallAfter(self.loadbtn.SetLabel, _("Load File"))
self.skeining = 0
self.skeinp = None
2012-08-08 07:38:48 +00:00
def skein(self, filename):
wx.CallAfter(self.loadbtn.SetLabel, _("Cancel"))
2011-11-18 08:52:16 +00:00
print _("Slicing ") + filename
2012-08-08 07:38:48 +00:00
self.cout = StringIO.StringIO()
self.filename = filename
self.stopsf = 0
self.skeining = 1
threading.Thread(target = self.skein_func).start()
threading.Thread(target = self.skein_monitor).start()
def do_load(self,l):
2012-09-05 08:10:05 +00:00
if hasattr(self, 'skeining'):
self.loadfile(None, l)
else:
self._do_load(l)
2012-09-05 08:10:05 +00:00
def loadfile(self, event, filename = None):
2011-11-18 08:52:16 +00:00
if self.skeining and self.skeinp is not None:
self.skeinp.terminate()
return
2012-08-08 07:38:48 +00:00
basedir = self.settings.last_file_path
2011-06-29 21:32:24 +00:00
if not os.path.exists(basedir):
basedir = "."
try:
2012-08-08 07:38:48 +00:00
basedir = os.path.split(self.filename)[0]
2011-06-29 21:32:24 +00:00
except:
pass
2012-08-08 07:58:09 +00:00
dlg = wx.FileDialog(self, _("Open file to print"), basedir, style = wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard(_("OBJ, STL, and GCODE files (*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ)|*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ|All Files (*.*)|*.*"))
2011-08-06 13:28:25 +00:00
if(filename is not None or dlg.ShowModal() == wx.ID_OK):
if filename is not None:
2012-08-08 07:38:48 +00:00
name = filename
2011-08-06 13:28:25 +00:00
else:
2012-08-08 07:38:48 +00:00
name = dlg.GetPath()
2011-06-08 14:19:38 +00:00
if not(os.path.exists(name)):
2011-08-06 23:45:52 +00:00
self.status.SetStatusText(_("File not found!"))
2011-06-08 14:19:38 +00:00
return
2011-06-29 21:32:24 +00:00
path = os.path.split(name)[0]
if path != self.settings.last_file_path:
2012-08-08 07:58:09 +00:00
self.set("last_file_path", path)
if name.lower().endswith(".stl"):
2011-06-08 14:19:38 +00:00
self.skein(name)
elif name.lower().endswith(".obj"):
self.skein(name)
2011-06-08 14:19:38 +00:00
else:
2012-08-08 07:38:48 +00:00
self.filename = name
of = open(self.filename)
2012-08-08 07:58:09 +00:00
self.f = [i.replace("\n", "").replace("\r", "") for i in of]
2012-08-06 17:19:07 +00:00
of.close()
self.fgcode = gcoder.GCode(self.f)
self.status.SetStatusText(_("Loaded %s, %d lines") % (name, len(self.f)))
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
wx.CallAfter(self.pausebtn.Disable)
wx.CallAfter(self.recoverbtn.Disable)
if self.p.online:
wx.CallAfter(self.printbtn.Enable)
2012-08-08 07:38:48 +00:00
threading.Thread(target = self.loadviz).start()
2012-04-22 23:33:47 +00:00
2011-06-21 16:52:11 +00:00
def loadviz(self):
gcode = self.fgcode
gcode.measure()
print gcode.filament_length(), _("mm of filament used in this print\n")
2013-05-15 19:39:08 +00:00
print _("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (gcode.xmin, gcode.xmax, gcode.width)
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: %s") % gcode.estimate_duration()
2011-06-21 16:52:11 +00:00
self.gviz.clear()
self.gwindow.p.clear()
self.gviz.addfile(gcode)
self.gwindow.p.addfile(gcode)
2012-08-08 07:38:48 +00:00
self.gviz.showall = 1
2011-06-21 16:52:11 +00:00
wx.CallAfter(self.gviz.Refresh)
2012-08-08 07:38:48 +00:00
def printfile(self, event):
self.extra_print_time = 0
2011-06-10 18:34:04 +00:00
if self.paused:
2012-08-08 07:38:48 +00:00
self.p.paused = 0
self.paused = 0
self.on_startprint()
2011-06-10 18:34:04 +00:00
if self.sdprinting:
self.p.send_now("M26 S0")
self.p.send_now("M24")
return
2011-06-08 14:19:38 +00:00
if self.f is None or not len(self.f):
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.status.SetStatusText, _("No file loaded. Please use load first."))
2011-06-08 14:19:38 +00:00
return
if not self.p.online:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Not connected to printer."))
2011-06-08 14:19:38 +00:00
return
2011-07-09 14:07:17 +00:00
self.on_startprint()
2011-06-08 14:19:38 +00:00
self.p.startprint(self.f)
def on_startprint(self):
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
wx.CallAfter(self.pausebtn.Enable)
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.printbtn.SetLabel, _("Restart"))
2011-06-08 22:02:00 +00:00
def endupload(self):
self.p.send_now("M29 ")
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.status.SetStatusText, _("File upload complete"))
2011-06-08 22:02:00 +00:00
time.sleep(0.5)
2012-08-08 07:38:48 +00:00
self.p.clear = True
self.uploading = False
2012-08-08 07:38:48 +00:00
def uploadtrigger(self, l):
2011-06-08 22:02:00 +00:00
if "Writing to file" in l:
2012-08-08 07:38:48 +00:00
self.uploading = True
2011-06-08 22:02:00 +00:00
self.p.startprint(self.f)
2012-08-08 07:38:48 +00:00
self.p.endcb = self.endupload
2011-06-08 22:02:00 +00:00
self.recvlisteners.remove(self.uploadtrigger)
elif "open failed, File" in l:
self.recvlisteners.remove(self.uploadtrigger)
2012-08-08 07:38:48 +00:00
def upload(self, event):
if not self.f or not len(self.f):
2011-06-08 22:02:00 +00:00
return
if not self.p.online:
return
2012-08-08 07:38:48 +00:00
dlg = wx.TextEntryDialog(self, ("Enter a target filename in 8.3 format:"), _("Pick SD filename") ,dosify(self.filename))
if dlg.ShowModal() == wx.ID_OK:
2011-11-30 13:18:12 +00:00
self.p.send_now("M21")
2011-06-11 21:03:01 +00:00
self.p.send_now("M28 "+str(dlg.GetValue()))
2011-06-08 22:02:00 +00:00
self.recvlisteners+=[self.uploadtrigger]
2012-08-08 07:38:48 +00:00
def pause(self, event):
print _("Paused.")
2011-06-08 14:19:38 +00:00
if not self.paused:
if self.sdprinting:
self.p.send_now("M25")
else:
if(not self.p.printing):
#print "Not printing, cannot pause."
return
self.p.pause()
self.p.runSmallScript(self.pauseScript)
2012-08-08 07:38:48 +00:00
self.paused = True
#self.p.runSmallScript(self.pauseScript)
self.extra_print_time += int(time.time() - self.starttime)
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Resume"))
2011-06-08 14:19:38 +00:00
else:
2012-08-08 07:38:48 +00:00
self.paused = False
2011-06-08 14:19:38 +00:00
if self.sdprinting:
self.p.send_now("M24")
else:
self.p.resume()
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
2012-08-08 07:38:48 +00:00
def sdprintfile(self, event):
self.on_startprint()
2012-08-08 07:38:48 +00:00
threading.Thread(target = self.getfiles).start()
2012-08-08 07:38:48 +00:00
def connect(self, event):
print _("Connecting...")
2012-08-08 07:38:48 +00:00
port = None
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:38:48 +00:00
port = self.scanserial()[0]
2011-06-08 14:19:38 +00:00
except:
pass
if self.serialport.GetValue()!="":
2012-08-08 07:38:48 +00:00
port = str(self.serialport.GetValue())
baud = 115200
2011-06-08 14:19:38 +00:00
try:
2012-08-08 07:38:48 +00:00
baud = int(self.baud.GetValue())
2011-06-08 14:19:38 +00:00
except:
pass
2011-06-10 18:34:04 +00:00
if self.paused:
2012-08-08 07:38:48 +00:00
self.p.paused = 0
self.p.printing = 0
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
2012-08-08 07:38:48 +00:00
self.paused = 0
2011-06-10 18:34:04 +00:00
if self.sdprinting:
self.p.send_now("M26 S0")
try:
self.p.connect(port, baud)
except SerialException as e:
# Currently, there is no errno, but it should be there in the future
if e.errno == 2:
print _("Error: You are trying to connect to a non-exisiting port.")
elif e.errno == 8:
print _("Error: You don't have permission to open %s.") % port
print _("You might need to add yourself to the dialout group.")
else:
print e
2013-01-23 16:12:01 +00:00
# Kill the scope anyway
return
2012-08-08 07:38:48 +00:00
self.statuscheck = True
if port != self.settings.port:
2012-08-08 07:58:09 +00:00
self.set("port", port)
if baud != self.settings.baudrate:
2012-08-08 07:58:09 +00:00
self.set("baudrate", str(baud))
2012-08-04 20:24:45 +00:00
self.status_thread = threading.Thread(target = self.statuschecker)
self.status_thread.start()
if self.predisconnect_mainqueue:
self.recoverbtn.Enable()
def recover(self, event):
self.extra_print_time = 0
if not self.p.online:
2012-08-08 07:38:48 +00:00
wx.CallAfter(self.status.SetStatusText, _("Not connected to printer."))
return
# Reset Z
2012-08-06 21:25:01 +00:00
self.p.send_now("G92 Z%f" % self.predisconnect_layer)
# Home X and Y
self.p.send_now("G28 X Y")
self.on_startprint()
2012-08-06 21:25:01 +00:00
self.p.startprint(self.predisconnect_mainqueue, self.p.queueindex)
def store_predisconnect_state(self):
self.predisconnect_mainqueue = self.p.mainqueue
self.predisconnect_queueindex = self.p.queueindex
self.predisconnect_layer = self.curlayer
2012-08-08 07:38:48 +00:00
def disconnect(self, event):
print _("Disconnected.")
if self.p.printing or self.p.paused or self.paused:
self.store_predisconnect_state()
2011-06-08 14:19:38 +00:00
self.p.disconnect()
2012-08-04 20:24:45 +00:00
self.statuscheck = False
if self.status_thread:
self.status_thread.join()
self.status_thread = None
self.connectbtn.SetLabel(_("Connect"))
self.connectbtn.SetToolTip(wx.ToolTip("Connect to the printer"))
2012-08-08 07:38:48 +00:00
self.connectbtn.Bind(wx.EVT_BUTTON, self.connect)
2011-12-04 01:17:19 +00:00
2012-08-07 11:49:58 +00:00
wx.CallAfter(self.printbtn.Disable)
wx.CallAfter(self.pausebtn.Disable)
wx.CallAfter(self.recoverbtn.Disable)
for i in self.printerControls:
wx.CallAfter(i.Disable)
# Disable XYButtons and ZButtons
wx.CallAfter(self.xyb.disable)
wx.CallAfter(self.zb.disable)
2011-06-10 18:34:04 +00:00
if self.paused:
2012-08-08 07:38:48 +00:00
self.p.paused = 0
self.p.printing = 0
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
2012-08-08 07:38:48 +00:00
self.paused = 0
2011-06-10 18:34:04 +00:00
if self.sdprinting:
self.p.send_now("M26 S0")
2012-08-08 07:38:48 +00:00
def reset(self, event):
print _("Reset.")
2012-08-08 07:38:48 +00:00
dlg = wx.MessageDialog(self, _("Are you sure you want to reset the printer?"), _("Reset?"), wx.YES|wx.NO)
if dlg.ShowModal() == wx.ID_YES:
2011-06-08 14:19:38 +00:00
self.p.reset()
2012-07-15 11:43:34 +00:00
self.sethotendgui(0)
self.setbedgui(0)
2012-08-08 07:38:48 +00:00
self.p.printing = 0
wx.CallAfter(self.printbtn.SetLabel, _("Print"))
2011-06-10 18:34:04 +00:00
if self.paused:
2012-08-08 07:38:48 +00:00
self.p.paused = 0
2011-08-06 23:45:52 +00:00
wx.CallAfter(self.pausebtn.SetLabel, _("Pause"))
2012-08-08 07:38:48 +00:00
self.paused = 0
2012-08-08 07:38:48 +00:00
def get_build_dimensions(self, bdim):
2011-12-11 09:11:47 +00:00
import re
# a string containing up to six numbers delimited by almost anything
# first 0-3 numbers specify the build volume, no sign, always positive
# remaining 0-3 numbers specify the coordinates of the "southwest" corner of the build platform
# "XXX,YYY"
2011-12-11 09:11:47 +00:00
# "XXXxYYY+xxx-yyy"
# "XXX,YYY,ZZZ+xxx+yyy-zzz"
2011-12-11 09:11:47 +00:00
# etc
bdl = re.match(
"[^\d+-]*(\d+)?" + # X build size
"[^\d+-]*(\d+)?" + # Y build size
"[^\d+-]*(\d+)?" + # Z build size
"[^\d+-]*([+-]\d+)?" + # X corner coordinate
"[^\d+-]*([+-]\d+)?" + # Y corner coordinate
"[^\d+-]*([+-]\d+)?" + # Z corner coordinate
"[^\d+-]*([+-]\d+)?" + # X endstop
"[^\d+-]*([+-]\d+)?" + # Y endstop
"[^\d+-]*([+-]\d+)?" # Z endstop
2011-12-11 09:11:47 +00:00
,bdim).groups()
defaults = [200, 200, 100, 0, 0, 0, 0, 0, 0]
bdl_float = [float(value) if value else defaults[i] for i, value in enumerate(bdl)]
2011-12-11 09:11:47 +00:00
return bdl_float
2011-06-08 14:19:38 +00:00
if __name__ == '__main__':
app = wx.App(False)
main = PronterWindow()
main.Show()
2011-06-16 04:28:46 +00:00
try:
app.MainLoop()
except KeyboardInterrupt:
2011-06-16 04:28:46 +00:00
pass
del app