chiark / gitweb /
Updated print window with statistics about the print. Filament used, and estimated...
[cura.git] / Cura / gui / printWindow.py
1 from __future__ import absolute_import\r
2 import __init__\r
3 \r
4 import wx, threading\r
5 \r
6 from gui import machineCom\r
7 from gui import icon\r
8 from util import gcodeInterpreter\r
9 \r
10 printWindowHandle = None\r
11 \r
12 def printFile(filename):\r
13         global printWindowHandle\r
14         if printWindowHandle == None:\r
15                 printWindowHandle = printWindow()\r
16         printWindowHandle.Show(True)\r
17         printWindowHandle.Raise()\r
18         printWindowHandle.LoadGCodeFile(filename)\r
19 \r
20 class printWindow(wx.Frame):\r
21         "Main user interface window"\r
22         def __init__(self):\r
23                 super(printWindow, self).__init__(None, -1, title='Printing')\r
24                 self.machineCom = None\r
25                 self.machineConnected = False\r
26                 self.thread = None\r
27                 self.gcode = None\r
28                 self.gcodeList = None\r
29                 self.printIdx = None\r
30                 self.bufferLineCount = 4\r
31                 self.sendCnt = 0\r
32 \r
33                 #self.SetIcon(icon.getMainIcon())\r
34                 \r
35                 self.SetSizer(wx.BoxSizer())\r
36                 self.panel = wx.Panel(self)\r
37                 self.GetSizer().Add(self.panel, 1, flag=wx.EXPAND)\r
38                 self.sizer = wx.GridBagSizer(2, 2)\r
39                 self.panel.SetSizer(self.sizer)\r
40                 \r
41                 sb = wx.StaticBox(self.panel, label="Statistics")\r
42                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)\r
43                 self.statsText = wx.StaticText(self.panel, -1, "Filament: #.##m #.##g\nPrint time: ##:##")\r
44                 boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)\r
45                 \r
46                 self.sizer.Add(boxsizer, pos=(0,0), span=(4,1), flag=wx.EXPAND)\r
47                 \r
48                 self.connectButton = wx.Button(self.panel, -1, 'Connect')\r
49                 self.loadButton = wx.Button(self.panel, -1, 'Load GCode')\r
50                 self.printButton = wx.Button(self.panel, -1, 'Print GCode')\r
51                 self.cancelButton = wx.Button(self.panel, -1, 'Cancel print')\r
52                 self.progress = wx.Gauge(self.panel, -1)\r
53                 self.sizer.Add(self.connectButton, pos=(0,1))\r
54                 self.sizer.Add(self.loadButton, pos=(1,1))\r
55                 self.sizer.Add(self.printButton, pos=(2,1))\r
56                 self.sizer.Add(self.cancelButton, pos=(3,1))\r
57                 self.sizer.Add(self.progress, pos=(4,0), span=(1,2), flag=wx.EXPAND)\r
58                 self.sizer.AddGrowableRow(3)\r
59                 self.sizer.AddGrowableCol(0)\r
60                 \r
61                 self.Bind(wx.EVT_CLOSE, self.OnClose)\r
62                 self.connectButton.Bind(wx.EVT_BUTTON, self.OnConnect)\r
63                 self.loadButton.Bind(wx.EVT_BUTTON, self.OnLoad)\r
64                 self.printButton.Bind(wx.EVT_BUTTON, self.OnPrint)\r
65                 self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)\r
66                 \r
67                 self.Layout()\r
68                 self.Fit()\r
69                 self.Centre()\r
70                 \r
71                 self.UpdateButtonStates()\r
72                 self.UpdateProgress()\r
73         \r
74         def UpdateButtonStates(self):\r
75                 self.connectButton.Enable(not self.machineConnected)\r
76                 self.loadButton.Enable(self.printIdx == None)\r
77                 self.printButton.Enable(self.machineConnected and self.gcodeList != None and self.printIdx == None)\r
78                 self.cancelButton.Enable(self.printIdx != None)\r
79         \r
80         def UpdateProgress(self):\r
81                 status = ""\r
82                 if self.gcode != None:\r
83                         status += "Filament: %.2fm %.2fg\n" % (self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)\r
84                         status += "Print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))\r
85                 if self.printIdx == None:\r
86                         self.progress.SetValue(0)\r
87                         if self.gcodeList != None:\r
88                                 status += 'Line: -/%d\n' % (len(self.gcodeList))\r
89                 else:\r
90                         self.progress.SetValue(self.printIdx)\r
91                         status += 'Line: %d/%d\n' % (self.printIdx, len(self.gcodeList))\r
92                 self.statsText.SetLabel(status)\r
93         \r
94         def OnConnect(self, e):\r
95                 if self.machineCom != None:\r
96                         self.machineCom.close()\r
97                         self.thread.join()\r
98                 self.machineCom = machineCom.MachineCom()\r
99                 self.thread = threading.Thread(target=self.PrinterMonitor)\r
100                 self.thread.start()\r
101                 self.UpdateButtonStates()\r
102         \r
103         def OnLoad(self, e):\r
104                 pass\r
105         \r
106         def OnPrint(self, e):\r
107                 if not self.machineConnected:\r
108                         return\r
109                 if self.gcodeList == None:\r
110                         return\r
111                 if self.printIdx != None:\r
112                         return\r
113                 self.printIdx = 1\r
114                 self.sendLine(0)\r
115                 self.sendCnt = self.bufferLineCount\r
116                 self.UpdateButtonStates()\r
117         \r
118         def OnCancel(self, e):\r
119                 self.printIdx = None\r
120                 self.UpdateButtonStates()\r
121         \r
122         def OnClose(self, e):\r
123                 global printWindowHandle\r
124                 printWindowHandle = None\r
125                 if self.machineCom != None:\r
126                         self.machineCom.close()\r
127                         self.thread.join()\r
128                 self.Destroy()\r
129 \r
130         def LoadGCodeFile(self, filename):\r
131                 gcodeList = ["M110"]\r
132                 for line in open(filename, 'r'):\r
133                         if ';' in line:\r
134                                 line = line[0:line.find(';')]\r
135                         line = line.strip()\r
136                         if len(line) > 0:\r
137                                 gcodeList.append(line)\r
138                 gcode = gcodeInterpreter.gcode()\r
139                 gcode.loadList(gcodeList)\r
140                 print "Loaded: %s (%d)" % (filename, len(gcodeList))\r
141                 self.progress.SetRange(len(gcodeList))\r
142                 self.gcode = gcode\r
143                 self.gcodeList = gcodeList\r
144                 self.UpdateButtonStates()\r
145                 self.UpdateProgress()\r
146 \r
147         def sendLine(self, lineNr):\r
148                 if lineNr >= len(self.gcodeList):\r
149                         return False\r
150                 checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (lineNr, self.gcodeList[lineNr])))\r
151                 self.machineCom.sendCommand("N%d%s*%d" % (lineNr, self.gcodeList[lineNr], checksum))\r
152                 return True\r
153 \r
154         def PrinterMonitor(self):\r
155                 skipCount = 0\r
156                 while True:\r
157                         line = self.machineCom.readline()\r
158                         if line == None:\r
159                                 self.machineConnected = False\r
160                                 wx.CallAfter(self.UpdateButtonStates)\r
161                                 return\r
162                         if self.machineConnected:\r
163                                 while self.sendCnt > 0:\r
164                                         self.sendLine(self.printIdx)\r
165                                         self.printIdx += 1\r
166                                         self.sendCnt -= 1\r
167                         elif line.startswith("start"):\r
168                                 self.machineConnected = True\r
169                                 wx.CallAfter(self.UpdateButtonStates)\r
170                         if self.printIdx != None:\r
171                                 if line.startswith("ok"):\r
172                                         if skipCount > 0:\r
173                                                 skipCount -= 1\r
174                                         else:\r
175                                                 if self.sendLine(self.printIdx):\r
176                                                         self.printIdx += 1\r
177                                                 wx.CallAfter(self.UpdateProgress)\r
178                                 elif "resend" in line.lower() or "rs" in line:\r
179                                         try:\r
180                                                 lineNr=int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])\r
181                                         except:\r
182                                                 if "rs" in line:\r
183                                                         lineNr=int(line.split()[1])\r
184                                         self.printIdx = lineNr\r
185                                         #we should actually resend the line here, but we also get an "ok" for each error from Marlin. And thus we'll resend on the OK.\r
186 \r