chiark / gitweb /
Testing of the new ImageButton widget
[cura.git] / Cura / gui / configWizard.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import os
4 import webbrowser
5 import threading
6 import time
7 import math
8
9 import wx
10 import wx.wizard
11
12 from Cura.gui import firmwareInstall
13 from Cura.gui import printWindow
14 from Cura.util import machineCom
15 from Cura.util import profile
16 from Cura.util import gcodeGenerator
17 from Cura.util import resources
18
19
20 class InfoBox(wx.Panel):
21         def __init__(self, parent):
22                 super(InfoBox, self).__init__(parent)
23                 self.SetBackgroundColour('#FFFF80')
24
25                 self.sizer = wx.GridBagSizer(5, 5)
26                 self.SetSizer(self.sizer)
27
28                 self.attentionBitmap = wx.Bitmap(resources.getPathForImage('attention.png'))
29                 self.errorBitmap = wx.Bitmap(resources.getPathForImage('error.png'))
30                 self.readyBitmap = wx.Bitmap(resources.getPathForImage('ready.png'))
31                 self.busyBitmap = [
32                         wx.Bitmap(resources.getPathForImage('busy-0.png')),
33                         wx.Bitmap(resources.getPathForImage('busy-1.png')),
34                         wx.Bitmap(resources.getPathForImage('busy-2.png')),
35                         wx.Bitmap(resources.getPathForImage('busy-3.png'))
36                 ]
37
38                 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
39                 self.text = wx.StaticText(self, -1, '')
40                 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
41                 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
42                 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
43                 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
44                 self.sizer.AddGrowableCol(1)
45
46                 self.extraInfoButton.Show(False)
47
48                 self.extraInfoUrl = ''
49                 self.busyState = None
50                 self.timer = wx.Timer(self)
51                 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
52                 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
53                 self.timer.Start(100)
54
55         def SetInfo(self, info):
56                 self.SetBackgroundColour('#FFFF80')
57                 self.text.SetLabel(info)
58                 self.extraInfoButton.Show(False)
59                 self.Refresh()
60
61         def SetError(self, info, extraInfoUrl):
62                 self.extraInfoUrl = extraInfoUrl
63                 self.SetBackgroundColour('#FF8080')
64                 self.text.SetLabel(info)
65                 self.extraInfoButton.Show(True)
66                 self.Layout()
67                 self.SetErrorIndicator()
68                 self.Refresh()
69
70         def SetAttention(self, info):
71                 self.SetBackgroundColour('#FFFF80')
72                 self.text.SetLabel(info)
73                 self.extraInfoButton.Show(False)
74                 self.SetAttentionIndicator()
75                 self.Layout()
76                 self.Refresh()
77
78         def SetBusy(self, info):
79                 self.SetInfo(info)
80                 self.SetBusyIndicator()
81
82         def SetBusyIndicator(self):
83                 self.busyState = 0
84                 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
85
86         def doExtraInfo(self, e):
87                 webbrowser.open(self.extraInfoUrl)
88
89         def doBusyUpdate(self, e):
90                 if self.busyState is None:
91                         return
92                 self.busyState += 1
93                 if self.busyState >= len(self.busyBitmap):
94                         self.busyState = 0
95                 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
96
97         def SetReadyIndicator(self):
98                 self.busyState = None
99                 self.bitmap.SetBitmap(self.readyBitmap)
100
101         def SetErrorIndicator(self):
102                 self.busyState = None
103                 self.bitmap.SetBitmap(self.errorBitmap)
104
105         def SetAttentionIndicator(self):
106                 self.busyState = None
107                 self.bitmap.SetBitmap(self.attentionBitmap)
108
109 class ImageButton(wx.Panel):
110         DefaultOverlay = wx.Bitmap(resources.getPathForImage('ImageButton_Overlay.png'))
111         IB_GROUP=1
112         __groups__ = {}
113         __last_group__ = None
114         def __init__(self, parent, label, bitmap, extra_label=None, overlay=DefaultOverlay, style=None):
115                 super(ImageButton, self).__init__(parent)
116
117                 if style is ImageButton.IB_GROUP:
118                         ImageButton.__last_group__ = self
119                         ImageButton.__groups__[self] = [self]
120                         self.group = self
121                 else:
122                         if ImageButton.__last_group__:
123                                 ImageButton.__groups__[ImageButton.__last_group__].append(self)
124                                 self.group = ImageButton.__last_group__
125                         else:
126                                 self.group = None
127                 self.sizer = wx.BoxSizer(wx.VERTICAL)
128                 self.SetSizer(self.sizer)
129                 self.bitmap = bitmap
130                 self.overlay = self.createOverlay(bitmap, overlay)
131                 self.text = wx.StaticText(self, -1, label)
132                 self.bmp = wx.StaticBitmap(self, -1, self.bitmap)
133                 if extra_label:
134                         self.extra_text = wx.StaticText(self, -1, extra_label)
135                 self.selected = False
136
137                 self.sizer.Add(self.text, 0, flag=wx.ALL|wx.ALIGN_CENTER, border=5)
138                 self.sizer.Add(self.bmp, 1, flag=wx.ALL|wx.ALIGN_CENTER|wx.EXPAND, border=5)
139                 if extra_label:
140                         self.sizer.Add(self.extra_text, 0, flag=wx.ALL|wx.ALIGN_CENTER, border=5)
141                 self.bmp.Bind(wx.EVT_LEFT_UP, self.OnLeftClick)
142
143         def __del__(self):
144                 if self.group:
145                         ImageButton.__groups__[self.group].remove(self)
146                         if self == self.group:
147                                 for ib in ImageButton.__groups__[self.group]:
148                                         ib.group = None
149                                 del ImageButton.__groups__[self.group]
150                                 if ImageButton.__last_group__ == self:
151                                         ImageButton.__last_group__ = None
152
153         def OnLeftClick(self, e):
154                 self.SetValue(True)
155
156         def GetValue(self):
157                 return self.selected
158
159         def SetValue(self, value):
160                 self.selected = bool(value)
161                 self.bmp.SetBitmap(self.overlay if self.GetValue() else self.bitmap)
162                 if self.selected and self.group:
163                         for ib in ImageButton.__groups__[self.group]:
164                                 if ib == self:
165                                         continue
166                                 ib.SetValue(False)
167
168         def createOverlay(self, bitmap, overlay):
169                 result = bitmap.GetSubBitmap(wx.Rect(0, 0, *bitmap.Size))
170                 (width, height) = bitmap.GetSize()
171                 overlay_image = wx.ImageFromBitmap(overlay)
172                 overlay_image = overlay_image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
173                 overlay_scaled = wx.BitmapFromImage(overlay_image)
174                 dc = wx.MemoryDC()
175                 dc.SelectObject(result)
176                 dc.DrawBitmap(overlay_scaled, 0, 0)
177                 dc.SelectObject(wx.NullBitmap)
178                 return result
179
180
181 class InfoPage(wx.wizard.WizardPageSimple):
182         def __init__(self, parent, title):
183                 wx.wizard.WizardPageSimple.__init__(self, parent)
184
185                 parent.GetPageAreaSizer().Add(self)
186                 sizer = wx.GridBagSizer(5, 5)
187                 self.sizer = sizer
188                 self.SetSizer(sizer)
189
190                 self.title = wx.StaticText(self, -1, title)
191                 font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
192                 self.title.SetFont(font)
193                 # HACK ALERT: For some reason, the StaticText keeps its same size as if
194                 # the font was not modified, this causes the text to wrap and to
195                 # get out of bounds of the widgets area and hide other widgets.
196                 # The only way I found for the widget to get its right size was to calculate
197                 # the new font's extent and set the min size on the widget
198                 dc = wx.ScreenDC()
199                 dc.SetFont(font)
200                 w,h = dc.GetTextExtent(title)
201                 self.title.SetMinSize((w, h))
202                 sizer.Add(self.title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
203                 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
204                 sizer.AddGrowableCol(1)
205
206                 self.rowNr = 2
207
208         def AddText(self, info):
209                 text = wx.StaticText(self, -1, info)
210                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
211                 self.rowNr += 1
212                 return text
213
214         def AddSeperator(self):
215                 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
216                 self.rowNr += 1
217
218         def AddHiddenSeperator(self):
219                 self.AddText("")
220
221         def AddInfoBox(self):
222                 infoBox = InfoBox(self)
223                 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
224                 self.rowNr += 1
225                 return infoBox
226
227         def AddRadioButton(self, label, style=0):
228                 radio = wx.RadioButton(self, -1, label, style=style)
229                 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
230                 self.rowNr += 1
231                 return radio
232
233         def AddCheckbox(self, label, checked=False):
234                 check = wx.CheckBox(self, -1)
235                 text = wx.StaticText(self, -1, label)
236                 check.SetValue(checked)
237                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
238                 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
239                 self.rowNr += 1
240                 return check
241
242         def AddButton(self, label):
243                 button = wx.Button(self, -1, label)
244                 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
245                 self.rowNr += 1
246                 return button
247
248         def AddDualButton(self, label1, label2):
249                 button1 = wx.Button(self, -1, label1)
250                 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
251                 button2 = wx.Button(self, -1, label2)
252                 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
253                 self.rowNr += 1
254                 return button1, button2
255
256         def AddTextCtrl(self, value):
257                 ret = wx.TextCtrl(self, -1, value)
258                 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
259                 self.rowNr += 1
260                 return ret
261
262         def AddLabelTextCtrl(self, info, value):
263                 text = wx.StaticText(self, -1, info)
264                 ret = wx.TextCtrl(self, -1, value)
265                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
266                 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
267                 self.rowNr += 1
268                 return ret
269
270         def AddTextCtrlButton(self, value, buttonText):
271                 text = wx.TextCtrl(self, -1, value)
272                 button = wx.Button(self, -1, buttonText)
273                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
274                 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
275                 self.rowNr += 1
276                 return text, button
277
278         def AddBitmap(self, bitmap):
279                 bitmap = wx.StaticBitmap(self, -1, bitmap)
280                 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
281                 self.rowNr += 1
282                 return bitmap
283
284         def AddPanel(self):
285                 panel = wx.Panel(self, -1)
286                 sizer = wx.GridBagSizer(2, 2)
287                 panel.SetSizer(sizer)
288                 self.GetSizer().Add(panel, pos=(self.rowNr, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND)
289                 self.rowNr += 1
290                 return panel
291
292         def AddCheckmark(self, label, bitmap):
293                 check = wx.StaticBitmap(self, -1, bitmap)
294                 text = wx.StaticText(self, -1, label)
295                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
296                 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
297                 self.rowNr += 1
298                 return check
299
300         def AddCombo(self, label, options):
301                 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
302                 text = wx.StaticText(self, -1, label)
303                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
304                 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
305                 self.rowNr += 1
306                 return combo
307
308         def AllowNext(self):
309                 return True
310
311         def AllowBack(self):
312                 return True
313
314         def StoreData(self):
315                 pass
316
317 class PrintrbotPage(InfoPage):
318         def __init__(self, parent):
319                 self._printer_info = [
320                         # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
321                         ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
322                         ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
323                         ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
324                         (":" + _("Older models"),),
325                         ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
326                         ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
327                         ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
328                         ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
329                         ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
330                         ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
331                         ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
332                         ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
333                         ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
334                         ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
335                         ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
336                         ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
337                         ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
338                 ]
339
340                 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
341                 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
342                 self.AddText(_("Select which Printrbot machine you have:"))
343                 self._items = []
344                 for printer in self._printer_info:
345                         if printer[0].startswith(":"):
346                                 self.AddSeperator()
347                                 self.AddText(printer[0][1:])
348                         else:
349                                 item = self.AddRadioButton(printer[0])
350                                 item.data = printer[1:]
351                                 self._items.append(item)
352
353         def StoreData(self):
354                 profile.putMachineSetting('machine_name', 'Printrbot ???')
355                 for item in self._items:
356                         if item.GetValue():
357                                 data = item.data
358                                 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
359                                 profile.putMachineSetting('machine_width', data[0])
360                                 profile.putMachineSetting('machine_depth', data[1])
361                                 profile.putMachineSetting('machine_height', data[2])
362                                 profile.putProfileSetting('nozzle_size', data[3])
363                                 profile.putProfileSetting('filament_diameter', data[4])
364                                 profile.putProfileSetting('print_temperature', data[5])
365                                 profile.putProfileSetting('print_speed', data[6])
366                                 profile.putProfileSetting('travel_speed', data[7])
367                                 profile.putProfileSetting('retraction_speed', data[8])
368                                 profile.putProfileSetting('retraction_amount', data[9])
369                                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
370                                 profile.putMachineSetting('has_heated_bed', 'False')
371                                 profile.putMachineSetting('machine_center_is_zero', 'False')
372                                 profile.putMachineSetting('extruder_head_size_min_x', '0')
373                                 profile.putMachineSetting('extruder_head_size_min_y', '0')
374                                 profile.putMachineSetting('extruder_head_size_max_x', '0')
375                                 profile.putMachineSetting('extruder_head_size_max_y', '0')
376                                 profile.putMachineSetting('extruder_head_size_height', '0')
377                                 if data[10]:
378                                         profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
379 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
380 ;Print time: {print_time}
381 ;Filament used: {filament_amount}m {filament_weight}g
382 ;Filament cost: {filament_cost}
383 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
384 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
385 G21        ;metric values
386 G90        ;absolute positioning
387 M82        ;set extruder to absolute mode
388 M107       ;start with the fan off
389 G28 X0 Y0  ;move X/Y to min endstops
390 G28 Z0     ;move Z to min endstops
391 G29        ;Run the auto bed leveling
392 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
393 G92 E0                  ;zero the extruded length
394 G1 F200 E3              ;extrude 3mm of feed stock
395 G92 E0                  ;zero the extruded length again
396 G1 F{travel_speed}
397 ;Put printing message on LCD screen
398 M117 Printing...
399 """)
400
401 class OtherMachineSelectPage(InfoPage):
402         def __init__(self, parent):
403                 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
404                 self.AddText(_("The following pre-defined machine profiles are available"))
405                 self.AddText(_("Note that these profiles are not guaranteed to give good results,\nor work at all. Extra tweaks might be required.\nIf you find issues with the predefined profiles,\nor want an extra profile.\nPlease report it at the github issue tracker."))
406                 self.options = []
407                 machines = resources.getDefaultMachineProfiles()
408                 machines.sort()
409                 for filename in machines:
410                         name = os.path.splitext(os.path.basename(filename))[0]
411                         item = self.AddRadioButton(name)
412                         item.filename = filename
413                         item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
414                         self.options.append(item)
415                 self.AddSeperator()
416                 item = self.AddRadioButton(_('Custom...'))
417                 item.SetValue(True)
418                 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
419
420         def OnProfileSelect(self, e):
421                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
422
423         def OnOtherSelect(self, e):
424                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
425
426         def StoreData(self):
427                 for option in self.options:
428                         if option.GetValue():
429                                 profile.loadProfile(option.filename)
430                                 profile.loadMachineSettings(option.filename)
431
432 class OtherMachineInfoPage(InfoPage):
433         def __init__(self, parent):
434                 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
435                 self.AddText(_("Cura is now ready to be used!"))
436
437 class CustomRepRapInfoPage(InfoPage):
438         def __init__(self, parent):
439                 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
440                 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
441                 self.AddText(_("Be sure to review the default profile before running it on your machine."))
442                 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
443                 self.AddSeperator()
444                 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
445                 self.AddSeperator()
446                 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
447                 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
448                 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
449                 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
450                 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
451                 self.heatedBed = self.AddCheckbox(_("Heated bed"))
452                 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
453
454         def StoreData(self):
455                 profile.putMachineSetting('machine_name', self.machineName.GetValue())
456                 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
457                 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
458                 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
459                 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
460                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
461                 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
462                 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
463                 profile.putMachineSetting('extruder_head_size_min_x', '0')
464                 profile.putMachineSetting('extruder_head_size_min_y', '0')
465                 profile.putMachineSetting('extruder_head_size_max_x', '0')
466                 profile.putMachineSetting('extruder_head_size_max_y', '0')
467                 profile.putMachineSetting('extruder_head_size_height', '0')
468                 profile.checkAndUpdateMachineName()
469
470 class MachineSelectPage(InfoPage):
471         def __init__(self, parent):
472                 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
473                 self.AddText(_("What kind of machine do you have:"))
474
475                 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
476                 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
477                 self.LulzbotMiniRadio.SetValue(True)
478                 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
479                 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
480                 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
481                 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
482                 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
483                 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
484                 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
485                 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
486                 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
487                 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
488                 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
489                 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
490                 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
491                 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
492                 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
493                 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
494                 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
495                 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
496
497         def OnUltimaker2Select(self, e):
498                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
499
500         def OnUltimakerSelect(self, e):
501                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
502
503         def OnUltimakerOPSelect(self, e):
504                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
505
506         def OnPrintrbotSelect(self, e):
507                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
508
509         def OnLulzbotSelect(self, e):
510                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotToolheadPage)
511
512         def OnTaz5Select(self, e):
513                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
514                 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotToolheadPage)
515
516         def OnOtherSelect(self, e):
517                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
518
519         def AllowNext(self):
520                 return True
521
522         def AllowBack(self):
523                 return False
524
525         def StoreData(self):
526                 profile.putProfileSetting('retraction_enable', 'True')
527                 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
528                         if self.Ultimaker2Radio.GetValue():
529                                 profile.putMachineSetting('machine_width', '230')
530                                 profile.putMachineSetting('machine_depth', '225')
531                                 profile.putMachineSetting('machine_height', '205')
532                                 profile.putMachineSetting('machine_name', 'ultimaker2')
533                                 profile.putMachineSetting('machine_type', 'ultimaker2')
534                                 profile.putMachineSetting('has_heated_bed', 'True')
535                         if self.Ultimaker2GoRadio.GetValue():
536                                 profile.putMachineSetting('machine_width', '120')
537                                 profile.putMachineSetting('machine_depth', '120')
538                                 profile.putMachineSetting('machine_height', '115')
539                                 profile.putMachineSetting('machine_name', 'ultimaker2go')
540                                 profile.putMachineSetting('machine_type', 'ultimaker2go')
541                                 profile.putMachineSetting('has_heated_bed', 'False')
542                         if self.Ultimaker2ExtRadio.GetValue():
543                                 profile.putMachineSetting('machine_width', '230')
544                                 profile.putMachineSetting('machine_depth', '225')
545                                 profile.putMachineSetting('machine_height', '315')
546                                 profile.putMachineSetting('machine_name', 'ultimaker2extended')
547                                 profile.putMachineSetting('machine_type', 'ultimaker2extended')
548                                 profile.putMachineSetting('has_heated_bed', 'False')
549                         profile.putMachineSetting('machine_center_is_zero', 'False')
550                         profile.putMachineSetting('gcode_flavor', 'UltiGCode')
551                         profile.putMachineSetting('extruder_head_size_min_x', '40.0')
552                         profile.putMachineSetting('extruder_head_size_min_y', '10.0')
553                         profile.putMachineSetting('extruder_head_size_max_x', '60.0')
554                         profile.putMachineSetting('extruder_head_size_max_y', '30.0')
555                         profile.putMachineSetting('extruder_head_size_height', '48.0')
556                         profile.putProfileSetting('nozzle_size', '0.4')
557                         profile.putProfileSetting('fan_full_height', '5.0')
558                         profile.putMachineSetting('extruder_offset_x1', '18.0')
559                         profile.putMachineSetting('extruder_offset_y1', '0.0')
560                 elif self.UltimakerRadio.GetValue():
561                         profile.putMachineSetting('machine_width', '205')
562                         profile.putMachineSetting('machine_depth', '205')
563                         profile.putMachineSetting('machine_height', '200')
564                         profile.putMachineSetting('machine_name', 'ultimaker original')
565                         profile.putMachineSetting('machine_type', 'ultimaker')
566                         profile.putMachineSetting('machine_center_is_zero', 'False')
567                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
568                         profile.putProfileSetting('nozzle_size', '0.4')
569                         profile.putMachineSetting('extruder_head_size_min_x', '75.0')
570                         profile.putMachineSetting('extruder_head_size_min_y', '18.0')
571                         profile.putMachineSetting('extruder_head_size_max_x', '18.0')
572                         profile.putMachineSetting('extruder_head_size_max_y', '35.0')
573                         profile.putMachineSetting('extruder_head_size_height', '55.0')
574                 elif self.UltimakerOPRadio.GetValue():
575                         profile.putMachineSetting('machine_width', '205')
576                         profile.putMachineSetting('machine_depth', '205')
577                         profile.putMachineSetting('machine_height', '200')
578                         profile.putMachineSetting('machine_name', 'ultimaker original+')
579                         profile.putMachineSetting('machine_type', 'ultimaker_plus')
580                         profile.putMachineSetting('machine_center_is_zero', 'False')
581                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
582                         profile.putProfileSetting('nozzle_size', '0.4')
583                         profile.putMachineSetting('extruder_head_size_min_x', '75.0')
584                         profile.putMachineSetting('extruder_head_size_min_y', '18.0')
585                         profile.putMachineSetting('extruder_head_size_max_x', '18.0')
586                         profile.putMachineSetting('extruder_head_size_max_y', '35.0')
587                         profile.putMachineSetting('extruder_head_size_height', '55.0')
588                         profile.putMachineSetting('has_heated_bed', 'True')
589                         profile.putMachineSetting('extruder_amount', '1')
590                         profile.putProfileSetting('retraction_enable', 'True')
591                 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
592                         if self.LulzbotTaz4Radio.GetValue():
593                                 profile.putMachineSetting('machine_width', '290')
594                                 profile.putMachineSetting('machine_depth', '275')
595                                 profile.putMachineSetting('machine_height', '250')
596                                 profile.putProfileSetting('nozzle_size', '0.35')
597                                 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
598                                 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
599                                 profile.putMachineSetting('serial_baud', '115200')
600                         elif self.LulzbotTaz5Radio.GetValue():
601                                 profile.putMachineSetting('machine_width', '290')
602                                 profile.putMachineSetting('machine_depth', '275')
603                                 profile.putMachineSetting('machine_height', '250')
604                                 profile.putMachineSetting('serial_baud', '115200')
605                                 # Machine type and name are set in the nozzle select page
606                         else:
607                                 profile.putMachineSetting('machine_width', '155')
608                                 profile.putMachineSetting('machine_depth', '155')
609                                 profile.putMachineSetting('machine_height', '163')
610                                 profile.putProfileSetting('nozzle_size', '0.5')
611                                 profile.putMachineSetting('machine_name', 'LulzBot Mini')
612                                 profile.putMachineSetting('machine_type', 'lulzbot_mini')
613                                 profile.putMachineSetting('serial_baud', '115200')
614                                 profile.putMachineSetting('extruder_head_size_min_x', '40')
615                                 profile.putMachineSetting('extruder_head_size_max_x', '75')
616                                 profile.putMachineSetting('extruder_head_size_min_y', '25')
617                                 profile.putMachineSetting('extruder_head_size_max_y', '55')
618                                 profile.putMachineSetting('extruder_head_size_height', '17')
619
620                         profile.putMachineSetting('machine_center_is_zero', 'False')
621                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
622                         profile.putMachineSetting('has_heated_bed', 'True')
623                         profile.putMachineSetting('extruder_head_size_min_x', '0.0')
624                         profile.putMachineSetting('extruder_head_size_min_y', '0.0')
625                         profile.putMachineSetting('extruder_head_size_max_x', '0.0')
626                         profile.putMachineSetting('extruder_head_size_max_y', '0.0')
627                         profile.putMachineSetting('extruder_head_size_height', '0.0')
628                         profile.putPreference('startMode', 'Simple')
629                 else:
630                         profile.putMachineSetting('machine_width', '80')
631                         profile.putMachineSetting('machine_depth', '80')
632                         profile.putMachineSetting('machine_height', '60')
633                         profile.putMachineSetting('machine_name', 'reprap')
634                         profile.putMachineSetting('machine_type', 'reprap')
635                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
636                         profile.putPreference('startMode', 'Normal')
637                         profile.putProfileSetting('nozzle_size', '0.5')
638                 profile.checkAndUpdateMachineName()
639                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
640
641 class SelectParts(InfoPage):
642         def __init__(self, parent):
643                 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
644                 self.AddText(_("To assist you in having better default settings for your Ultimaker\nCura would like to know which upgrades you have in your machine."))
645                 self.AddSeperator()
646                 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
647                 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
648                 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
649                 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
650                 self.AddSeperator()
651                 self.AddText(_("If you have an Ultimaker bought after october 2012 you will have the\nExtruder drive upgrade. If you do not have this upgrade,\nit is highly recommended to improve reliability."))
652                 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
653                 self.springExtruder.SetValue(True)
654
655         def StoreData(self):
656                 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
657                 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
658                         profile.putMachineSetting('has_heated_bed', 'True')
659                 else:
660                         profile.putMachineSetting('has_heated_bed', 'False')
661                 if self.dualExtrusion.GetValue():
662                         profile.putMachineSetting('extruder_amount', '2')
663                         profile.putMachineSetting('machine_depth', '195')
664                 else:
665                         profile.putMachineSetting('extruder_amount', '1')
666                 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
667                         profile.putProfileSetting('retraction_enable', 'True')
668                 else:
669                         profile.putProfileSetting('retraction_enable', 'False')
670
671
672 class UltimakerFirmwareUpgradePage(InfoPage):
673         def __init__(self, parent):
674                 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
675                 self.AddText(_("Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work."))
676                 self.AddHiddenSeperator()
677                 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
678                 self.AddHiddenSeperator()
679                 self.AddText(_("Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now."))
680                 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
681                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
682                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
683                 self.AddHiddenSeperator()
684                 if profile.getMachineSetting('machine_type') == 'ultimaker':
685                         self.AddText(_("Do not upgrade to this firmware if:"))
686                         self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
687                         self.AddText(_("* Build your own heated bed"))
688                         self.AddText(_("* Have other changes in the firmware"))
689 #               button = self.AddButton('Goto this page for a custom firmware')
690 #               button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
691
692         def AllowNext(self):
693                 return False
694
695         def OnUpgradeClick(self, e):
696                 if firmwareInstall.InstallFirmware():
697                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
698
699         def OnSkipClick(self, e):
700                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
701                 self.GetParent().ShowPage(self.GetNext())
702
703         def OnUrlClick(self, e):
704                 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
705
706 class UltimakerCheckupPage(InfoPage):
707         def __init__(self, parent):
708                 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
709
710                 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
711                 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
712                 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
713                 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
714                 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
715                 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
716                 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
717                 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
718                 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
719                 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
720
721                 self.AddText(
722                         _("It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional."))
723                 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
724                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
725                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
726                 self.AddSeperator()
727                 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
728                 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
729                 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
730                 self.AddSeperator()
731                 self.infoBox = self.AddInfoBox()
732                 self.machineState = self.AddText("")
733                 self.temperatureLabel = self.AddText("")
734                 self.errorLogButton = self.AddButton(_("Show error log"))
735                 self.errorLogButton.Show(False)
736                 self.AddSeperator()
737                 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
738                 self.comm = None
739                 self.xMinStop = False
740                 self.xMaxStop = False
741                 self.yMinStop = False
742                 self.yMaxStop = False
743                 self.zMinStop = False
744                 self.zMaxStop = False
745
746                 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
747
748         def __del__(self):
749                 if self.comm is not None:
750                         self.comm.close()
751
752         def AllowNext(self):
753                 self.endstopBitmap.Show(False)
754                 return False
755
756         def OnSkipClick(self, e):
757                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
758                 self.GetParent().ShowPage(self.GetNext())
759
760         def OnCheckClick(self, e=None):
761                 self.errorLogButton.Show(False)
762                 if self.comm is not None:
763                         self.comm.close()
764                         del self.comm
765                         self.comm = None
766                         wx.CallAfter(self.OnCheckClick)
767                         return
768                 self.infoBox.SetBusy(_("Connecting to machine."))
769                 self.commState.SetBitmap(self.unknownBitmap)
770                 self.tempState.SetBitmap(self.unknownBitmap)
771                 self.stopState.SetBitmap(self.unknownBitmap)
772                 self.checkupState = 0
773                 self.checkExtruderNr = 0
774                 self.comm = machineCom.MachineCom(callbackObject=self)
775
776         def OnErrorLog(self, e):
777                 printWindow.LogWindow('\n'.join(self.comm.getLog()))
778
779         def mcLog(self, message):
780                 pass
781
782         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
783                 if not self.comm.isOperational():
784                         return
785                 if self.checkupState == 0:
786                         self.tempCheckTimeout = 20
787                         if temp[self.checkExtruderNr] > 70:
788                                 self.checkupState = 1
789                                 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
790                                 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
791                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
792                         else:
793                                 self.startTemp = temp[self.checkExtruderNr]
794                                 self.checkupState = 2
795                                 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
796                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
797                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
798                 elif self.checkupState == 1:
799                         if temp[self.checkExtruderNr] < 60:
800                                 self.startTemp = temp[self.checkExtruderNr]
801                                 self.checkupState = 2
802                                 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
803                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
804                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
805                 elif self.checkupState == 2:
806                         #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
807                         if temp[self.checkExtruderNr] > self.startTemp + 40:
808                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
809                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
810                                 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
811                                         self.checkExtruderNr = 0
812                                         self.checkupState = 3
813                                         wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
814                                         wx.CallAfter(self.endstopBitmap.Show, True)
815                                         wx.CallAfter(self.Layout)
816                                         self.comm.sendCommand('M119')
817                                         wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
818                                 else:
819                                         self.checkupState = 0
820                                         self.checkExtruderNr += 1
821                         else:
822                                 self.tempCheckTimeout -= 1
823                                 if self.tempCheckTimeout < 1:
824                                         self.checkupState = -1
825                                         wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
826                                         wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
827                                         self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
828                                         self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
829                 elif self.checkupState >= 3 and self.checkupState < 10:
830                         self.comm.sendCommand('M119')
831                 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
832
833         def mcStateChange(self, state):
834                 if self.comm is None:
835                         return
836                 if self.comm.isOperational():
837                         wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
838                         wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
839                 elif self.comm.isError():
840                         wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
841                         wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
842                         wx.CallAfter(self.endstopBitmap.Show, False)
843                         wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
844                         wx.CallAfter(self.errorLogButton.Show, True)
845                         wx.CallAfter(self.Layout)
846                 else:
847                         wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
848
849         def mcMessage(self, message):
850                 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
851                         for data in message.split(' '):
852                                 if ':' in data:
853                                         tag, value = data.split(':', 1)
854                                         if tag == 'x_min':
855                                                 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
856                                         if tag == 'x_max':
857                                                 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
858                                         if tag == 'y_min':
859                                                 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
860                                         if tag == 'y_max':
861                                                 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
862                                         if tag == 'z_min':
863                                                 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
864                                         if tag == 'z_max':
865                                                 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
866                         if ':' in message:
867                                 tag, value = map(str.strip, message.split(':', 1))
868                                 if tag == 'x_min':
869                                         self.xMinStop = (value == 'H' or value == 'TRIGGERED')
870                                 if tag == 'x_max':
871                                         self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
872                                 if tag == 'y_min':
873                                         self.yMinStop = (value == 'H' or value == 'TRIGGERED')
874                                 if tag == 'y_max':
875                                         self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
876                                 if tag == 'z_min':
877                                         self.zMinStop = (value == 'H' or value == 'TRIGGERED')
878                                 if tag == 'z_max':
879                                         self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
880                         if 'z_max' in message:
881                                 self.comm.sendCommand('M119')
882
883                         if self.checkupState == 3:
884                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
885                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
886                                                 self.checkupState = 5
887                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
888                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
889                                         else:
890                                                 self.checkupState = 4
891                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
892                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
893                         elif self.checkupState == 4:
894                                 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
895                                         self.checkupState = 5
896                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
897                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
898                         elif self.checkupState == 5:
899                                 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
900                                         self.checkupState = 6
901                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
902                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
903                         elif self.checkupState == 6:
904                                 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
905                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
906                                                 self.checkupState = 8
907                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
908                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
909                                         else:
910                                                 self.checkupState = 7
911                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
912                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
913                         elif self.checkupState == 7:
914                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
915                                         self.checkupState = 8
916                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
917                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
918                         elif self.checkupState == 8:
919                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
920                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
921                                                 self.checkupState = 10
922                                                 self.comm.close()
923                                                 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
924                                                 wx.CallAfter(self.infoBox.SetReadyIndicator)
925                                                 wx.CallAfter(self.endstopBitmap.Show, False)
926                                                 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
927                                                 wx.CallAfter(self.OnSkipClick, None)
928                                         else:
929                                                 self.checkupState = 9
930                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
931                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
932                         elif self.checkupState == 9:
933                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
934                                         self.checkupState = 10
935                                         self.comm.close()
936                                         wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
937                                         wx.CallAfter(self.infoBox.SetReadyIndicator)
938                                         wx.CallAfter(self.endstopBitmap.Show, False)
939                                         wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
940                                         wx.CallAfter(self.OnSkipClick, None)
941
942         def mcProgress(self, lineNr):
943                 pass
944
945         def mcZChange(self, newZ):
946                 pass
947
948
949 class UltimakerCalibrationPage(InfoPage):
950         def __init__(self, parent):
951                 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
952
953                 self.AddText("Your Ultimaker requires some calibration.")
954                 self.AddText("This calibration is needed for a proper extrusion amount.")
955                 self.AddSeperator()
956                 self.AddText("The following values are needed:")
957                 self.AddText("* Diameter of filament")
958                 self.AddText("* Number of steps per mm of filament extrusion")
959                 self.AddSeperator()
960                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
961                 self.AddSeperator()
962                 self.AddText("First we need the diameter of your filament:")
963                 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
964                 self.AddText(
965                         "If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.")
966                 self.AddText("Note: This value can be changed later at any time.")
967
968         def StoreData(self):
969                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
970
971
972 class UltimakerCalibrateStepsPerEPage(InfoPage):
973         def __init__(self, parent):
974                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
975
976                 #if profile.getMachineSetting('steps_per_e') == '0':
977                 #       profile.putMachineSetting('steps_per_e', '865.888')
978
979                 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
980                 self.AddText(_("First remove any filament from your machine."))
981                 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
982                 self.AddText(_("We'll push the filament 100mm"))
983                 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
984                 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
985                 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
986                 self.AddText(_("This results in the following steps per E:"))
987                 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
988                 self.AddText(_("You can repeat these steps to get better calibration."))
989                 self.AddSeperator()
990                 self.AddText(
991                         _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
992                 self.heatButton = self.AddButton(_("Heatup for filament removal"))
993
994                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
995                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
996                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
997
998         def OnSaveLengthClick(self, e):
999                 currentEValue = float(self.stepsPerEInput.GetValue())
1000                 realExtrudeLength = float(self.lengthInput.GetValue())
1001                 newEValue = currentEValue * 100 / realExtrudeLength
1002                 self.stepsPerEInput.SetValue(str(newEValue))
1003                 self.lengthInput.SetValue("100")
1004
1005         def OnExtrudeClick(self, e):
1006                 t = threading.Thread(target=self.OnExtrudeRun)
1007                 t.daemon = True
1008                 t.start()
1009
1010         def OnExtrudeRun(self):
1011                 self.heatButton.Enable(False)
1012                 self.extrudeButton.Enable(False)
1013                 currentEValue = float(self.stepsPerEInput.GetValue())
1014                 self.comm = machineCom.MachineCom()
1015                 if not self.comm.isOpen():
1016                         wx.MessageBox(
1017                                 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1018                                 'Printer error', wx.OK | wx.ICON_INFORMATION)
1019                         self.heatButton.Enable(True)
1020                         self.extrudeButton.Enable(True)
1021                         return
1022                 while True:
1023                         line = self.comm.readline()
1024                         if line == '':
1025                                 return
1026                         if 'start' in line:
1027                                 break
1028                         #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1029                 time.sleep(3)
1030
1031                 self.sendGCommand('M302') #Disable cold extrusion protection
1032                 self.sendGCommand("M92 E%f" % (currentEValue))
1033                 self.sendGCommand("G92 E0")
1034                 self.sendGCommand("G1 E100 F600")
1035                 time.sleep(15)
1036                 self.comm.close()
1037                 self.extrudeButton.Enable()
1038                 self.heatButton.Enable()
1039
1040         def OnHeatClick(self, e):
1041                 t = threading.Thread(target=self.OnHeatRun)
1042                 t.daemon = True
1043                 t.start()
1044
1045         def OnHeatRun(self):
1046                 self.heatButton.Enable(False)
1047                 self.extrudeButton.Enable(False)
1048                 self.comm = machineCom.MachineCom()
1049                 if not self.comm.isOpen():
1050                         wx.MessageBox(
1051                                 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1052                                 'Printer error', wx.OK | wx.ICON_INFORMATION)
1053                         self.heatButton.Enable(True)
1054                         self.extrudeButton.Enable(True)
1055                         return
1056                 while True:
1057                         line = self.comm.readline()
1058                         if line == '':
1059                                 self.heatButton.Enable(True)
1060                                 self.extrudeButton.Enable(True)
1061                                 return
1062                         if 'start' in line:
1063                                 break
1064                         #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1065                 time.sleep(3)
1066
1067                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
1068                 wx.MessageBox(
1069                         'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
1070                         'Machine heatup', wx.OK | wx.ICON_INFORMATION)
1071                 self.sendGCommand('M104 S0')
1072                 time.sleep(1)
1073                 self.comm.close()
1074                 self.heatButton.Enable(True)
1075                 self.extrudeButton.Enable(True)
1076
1077         def sendGCommand(self, cmd):
1078                 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1079                 while True:
1080                         line = self.comm.readline()
1081                         if line == '':
1082                                 return
1083                         if line.startswith('ok'):
1084                                 break
1085
1086         def StoreData(self):
1087                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1088
1089 class Ultimaker2ReadyPage(InfoPage):
1090         def __init__(self, parent):
1091                 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1092                 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1093                 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1094                 self.AddSeperator()
1095
1096 class LulzbotReadyPage(InfoPage):
1097         def __init__(self, parent):
1098                 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1099                 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1100                 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1101                 self.AddSeperator()
1102                 self.AddText(_('For more information about using Cura with your LulzBot'))
1103                 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1104                 self.AddSeperator()
1105
1106 class LulzbotToolheadSelectPage(InfoPage):
1107         url='http://lulzbot.com/toolhead-identification'
1108
1109         def __init__(self, parent):
1110                 super(LulzbotToolheadSelectPage, self).__init__(parent, _("LulzBot Toolhead Selection"))
1111
1112                 self.mini_choices = [_('Standard'), _('Flexystruder')]
1113                 self.taz_choices = [_('Standard v1'),
1114                                            _('Standard v2 0.35 mm nozzle'), _('Standard v2 0.5 mm nozzle'),
1115                                            _('Flexystruder v1'), _('Flexystruder v2'),
1116                                            _('Dually v1'), _('Dually v2'),
1117                                            _('FlexyDually v1'), _('FlexyDually v2')]
1118                 self.description_map = {
1119                                 _('Standard'): _('This is the standard toolhead that comes with the Lulzbot Mini'),
1120                                 _('Flexystruder'): _('This is the Flexystruder for the Lulzbot Mini\nIt is used for printing Flexible materials'),
1121                                 _('Standard v1'): _('This is the standard toolhead that comes with the Lulzbot TAZ 1-2-3 and TAZ 4.\nIt uses the Budaschnozzle for the hotend'),
1122                                 _('Standard v2 0.35 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.35 mm nozzle'),
1123                                 _('Standard v2 0.5 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.5 mm nozzle'),
1124                                 _('Flexystruder v1'): _('It\'s the flexy!'),
1125                                 _('Flexystruder v2'): _('It\'s the flexy v2!'),
1126                                 _('Dually v1'): _('It\'s the dualy v1!'),
1127                                 _('Dually v2'): _('It\'s the dual v2!'),
1128                                 _('FlexyDually v1'): _('It\'s the flexy dually v1!'),
1129                                 _('FlexyDually v2'): _('It\'s the flexy dual v2!')
1130                 }
1131                 self.image_map = {
1132                                 _('Standard'): 'Lulzbot_Toolhead_Mini_Standard.jpg',
1133                                 _('Flexystruder'): 'Lulzbot_logo.png',
1134                                 _('Standard v1'): 'Lulzbot_logo.png',
1135                                 _('Standard v2 0.35 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1136                                 _('Standard v2 0.5 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1137                                 _('Flexystruder v1'): 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg',
1138                                 _('Flexystruder v2'): 'Lulzbot_logo.png',
1139                                 _('Dually v1'): 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg',
1140                                 _('Dually v2'): 'Lulzbot_logo.png',
1141                                 _('FlexyDually v1'): 'Lulzbot_logo.png',
1142                                 _('FlexyDually v2'): 'Lulzbot_logo.png'
1143                 }
1144                 self.AddBitmap(wx.Bitmap(resources.getPathForImage('LulzBot_logo.png')))
1145                 printer_name = profile.getMachineSetting('machine_type')
1146                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_SHOWN, self.OnPageShown)
1147
1148                 self.AddText(_('Please select your currently installed Tool Head'))
1149                 txt = self.AddText(_('It is important to select the correct Tool head for your printer.\n' +
1150                                                          'Flashing the wrong firmware on your printer can cause damage to your printer and to your toolhead\n' +
1151                                                          'If you are not sure which toolhead you have, please refer to this webpage for more information: '))
1152                 txt.SetForegroundColour(wx.RED)
1153                 button = self.AddButton(self.url)
1154                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1155
1156                 self.AddSeperator()
1157                 #self.combo = self.AddCombo(_('Currently installed Toolhead'), [''])
1158                 #self.combo.SetEditable(False)
1159                 #self.combo.Bind(wx.EVT_COMBOBOX, self.OnToolheadSelected)
1160                 #self.description = self.AddText('\n\n')
1161                 #self.description.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
1162                 #self.image = self.AddBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[self.mini_choices[0]])))
1163                 self.panel = self.AddPanel()
1164                 ib1 = ImageButton(self.panel, "Mini", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg')), "Some description", style=ImageButton.IB_GROUP)
1165                 ib2 = ImageButton(self.panel, "TAZ 4 ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Single_v2.jpg')), "Some description 2")
1166                 ib3 = ImageButton(self.panel, "TAZ 5 ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg')), "Some description 3")
1167                 ib4 = ImageButton(self.panel, "Others ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Dually_v1.jpg')), "Some description\n4")
1168                 self.panel.GetSizer().Add(ib1, pos=(0, 0), flag=wx.EXPAND)
1169                 self.panel.GetSizer().Add(ib2, pos=(0, 1), flag=wx.EXPAND)
1170                 self.panel.GetSizer().Add(ib3, pos=(1, 0), flag=wx.EXPAND)
1171                 self.panel.GetSizer().Add(ib4, pos=(1, 1), flag=wx.EXPAND)
1172
1173
1174         def OnPageShown(self, e):
1175                 printer_name = profile.getMachineSetting('machine_type')
1176                 if printer_name == 'lulzbot_mini':
1177                         choices = self.mini_choices
1178                         default = 0
1179                 else:
1180                         choices = self.taz_choices
1181                         if printer_name == 'lulzbot_TAZ_4':
1182                                 default = 0
1183                         elif printer_name == 'lulzbot_TAZ_5':
1184                                 default = 1
1185                         else:
1186                                 default = 2
1187
1188                 self.combo.Clear()
1189                 self.combo.AppendItems(choices)
1190                 self.combo.SetValue(choices[default])
1191                 self.OnToolheadSelected(e)
1192
1193         def OnUrlClick(self, e):
1194                 webbrowser.open(LulzbotToolheadSelectPage.url)
1195
1196         def OnToolheadSelected(self, e):
1197                 toolhead = self.combo.GetValue()
1198                 if self.description_map.has_key(toolhead):
1199                         self.image.SetBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[toolhead])))
1200                         self.description.SetLabel(self.description_map[toolhead])
1201                 else:
1202                         self.image.SetBitmap(wx.NullBitmap)
1203                         self.description.SetLabel('\n\n')
1204                 self.Layout()
1205                 self.Fit()
1206
1207
1208 class Taz5NozzleSelectPage(InfoPage):
1209         url='http://lulzbot.com/printer-identification'
1210
1211         def __init__(self, parent):
1212                 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1213                 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1214
1215                 self.AddText(_(' '))
1216                 self.AddText(_('Please select nozzle size:'))
1217                 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1218                 self.Nozzle35Radio.SetValue(True)
1219                 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1220                 self.AddText(_(' '))
1221                 self.AddSeperator()
1222
1223                 self.AddText(_('If you are not sure which nozzle size you have'))
1224                 self.AddText(_('please check this webpage: '))
1225                 button = self.AddButton(Taz5NozzleSelectPage.url)
1226                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1227
1228         def OnUrlClick(self, e):
1229                 webbrowser.open(Taz5NozzleSelectPage.url)
1230
1231         def StoreData(self):
1232                 if self.Nozzle35Radio.GetValue():
1233                         profile.putProfileSetting('nozzle_size', '0.35')
1234                         profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1235                         profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1236
1237                 else:
1238                         profile.putProfileSetting('nozzle_size', '0.5')
1239                         profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1240                         profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1241
1242 class ConfigWizard(wx.wizard.Wizard):
1243         def __init__(self, addNew = False):
1244                 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1245
1246                 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1247                 if addNew:
1248                         profile.setActiveMachine(profile.getMachineCount())
1249
1250                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1251                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1252                 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1253
1254                 self.machineSelectPage = MachineSelectPage(self)
1255                 self.ultimakerSelectParts = SelectParts(self)
1256                 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1257                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1258                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1259                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1260                 self.bedLevelPage = bedLevelWizardMain(self)
1261                 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1262                 self.printrbotSelectType = PrintrbotPage(self)
1263                 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1264                 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1265                 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1266
1267                 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1268                 self.lulzbotReadyPage = LulzbotReadyPage(self)
1269                 self.lulzbotToolheadPage = LulzbotToolheadSelectPage(self)
1270                 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1271
1272                 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1273                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1274                 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1275                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1276                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1277                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1278                 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1279                 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1280                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotToolheadPage)
1281                 wx.wizard.WizardPageSimple.Chain(self.lulzbotToolheadPage, self.lulzbotReadyPage)
1282
1283                 self.RunWizard(self.machineSelectPage)
1284                 self.Destroy()
1285
1286         def OnPageChanging(self, e):
1287                 e.GetPage().StoreData()
1288
1289         def OnPageChanged(self, e):
1290                 if e.GetPage().AllowNext():
1291                         self.FindWindowById(wx.ID_FORWARD).Enable()
1292                 else:
1293                         self.FindWindowById(wx.ID_FORWARD).Disable()
1294                 if e.GetPage().AllowBack():
1295                         self.FindWindowById(wx.ID_BACKWARD).Enable()
1296                 else:
1297                         self.FindWindowById(wx.ID_BACKWARD).Disable()
1298
1299         def OnCancel(self, e):
1300                 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1301                 profile.setActiveMachine(self._old_machine_index)
1302                 profile.removeMachine(new_machine_index)
1303
1304 class bedLevelWizardMain(InfoPage):
1305         def __init__(self, parent):
1306                 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1307
1308                 self.AddText(_('This wizard will help you in leveling your printer bed'))
1309                 self.AddSeperator()
1310                 self.AddText(_('It will do the following steps'))
1311                 self.AddText(_('* Move the printer head to each corner'))
1312                 self.AddText(_('  and let you adjust the height of the bed to the nozzle'))
1313                 self.AddText(_('* Print a line around the bed to check if it is level'))
1314                 self.AddSeperator()
1315
1316                 self.connectButton = self.AddButton(_('Connect to printer'))
1317                 self.comm = None
1318
1319                 self.infoBox = self.AddInfoBox()
1320                 self.resumeButton = self.AddButton(_('Resume'))
1321                 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1322                 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1323                 self.resumeButton.Enable(False)
1324
1325                 self.upButton.Enable(False)
1326                 self.downButton.Enable(False)
1327                 self.upButton2.Enable(False)
1328                 self.downButton2.Enable(False)
1329
1330                 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1331                 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1332                 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1333                 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1334                 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1335                 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1336
1337         def OnConnect(self, e = None):
1338                 if self.comm is not None:
1339                         self.comm.close()
1340                         del self.comm
1341                         self.comm = None
1342                         wx.CallAfter(self.OnConnect)
1343                         return
1344                 self.connectButton.Enable(False)
1345                 self.comm = machineCom.MachineCom(callbackObject=self)
1346                 self.infoBox.SetBusy(_('Connecting to machine.'))
1347                 self._wizardState = 0
1348
1349         def OnBedUp(self, e):
1350                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1351                 self.comm.sendCommand('G92 Z10')
1352                 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1353                 self.comm.sendCommand('M400')
1354
1355         def OnBedDown(self, e):
1356                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1357                 self.comm.sendCommand('G92 Z10')
1358                 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1359                 self.comm.sendCommand('M400')
1360
1361         def OnBedUp2(self, e):
1362                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1363                 self.comm.sendCommand('G92 Z10')
1364                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1365                 self.comm.sendCommand('M400')
1366
1367         def OnBedDown2(self, e):
1368                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1369                 self.comm.sendCommand('G92 Z10')
1370                 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1371                 self.comm.sendCommand('M400')
1372
1373         def AllowNext(self):
1374                 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1375                         wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1376                 return True
1377
1378         def OnResume(self, e):
1379                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1380                 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1381                 if self._wizardState == -1:
1382                         wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1383                         wx.CallAfter(self.upButton.Enable, False)
1384                         wx.CallAfter(self.downButton.Enable, False)
1385                         wx.CallAfter(self.upButton2.Enable, False)
1386                         wx.CallAfter(self.downButton2.Enable, False)
1387                         self.comm.sendCommand('M105')
1388                         self.comm.sendCommand('G28')
1389                         self._wizardState = 1
1390                 elif self._wizardState == 2:
1391                         if profile.getMachineSetting('has_heated_bed') == 'True':
1392                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1393                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1394                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1395                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1396                                 self.comm.sendCommand('M400')
1397                                 self._wizardState = 3
1398                         else:
1399                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1400                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1401                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1402                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1403                                 self.comm.sendCommand('M400')
1404                                 self._wizardState = 3
1405                 elif self._wizardState == 4:
1406                         if profile.getMachineSetting('has_heated_bed') == 'True':
1407                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1408                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1409                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1410                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1411                                 self.comm.sendCommand('M400')
1412                                 self._wizardState = 7
1413                         else:
1414                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1415                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1416                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1417                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1418                                 self.comm.sendCommand('M400')
1419                                 self._wizardState = 5
1420                 elif self._wizardState == 6:
1421                         wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1422                         self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1423                         self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1424                         self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1425                         self.comm.sendCommand('M400')
1426                         self._wizardState = 7
1427                 elif self._wizardState == 8:
1428                         wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1429                         self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1430                         self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1431                         self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1432                         self._wizardState = 9
1433                 elif self._wizardState == 10:
1434                         self._wizardState = 11
1435                         wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1436                         feedZ = profile.getProfileSettingFloat('print_speed') * 60
1437                         feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1438                         feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1439                         w = profile.getMachineSettingFloat('machine_width') - 10
1440                         d = profile.getMachineSettingFloat('machine_depth')
1441                         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1442                         filamentArea = math.pi * filamentRadius * filamentRadius
1443                         ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1444                         eValue = 0.0
1445
1446                         gcodeList = [
1447                                 'G1 Z2 F%d' % (feedZ),
1448                                 'G92 E0',
1449                                 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1450                                 'G1 Z0.3 F%d' % (feedZ)]
1451                         eValue += 5.0
1452                         gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1453
1454                         for i in xrange(0, 3):
1455                                 dist = 5.0 + 0.4 * float(i)
1456                                 eValue += (d - 2.0*dist) * ePerMM
1457                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1458                                 eValue += (w - 2.0*dist) * ePerMM
1459                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1460                                 eValue += (d - 2.0*dist) * ePerMM
1461                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1462                                 eValue += (w - 2.0*dist) * ePerMM
1463                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1464
1465                         gcodeList.append('M400')
1466                         self.comm.printGCode(gcodeList)
1467                 self.resumeButton.Enable(False)
1468
1469         def mcLog(self, message):
1470                 print 'Log:', message
1471
1472         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1473                 if self._wizardState == 1:
1474                         self._wizardState = 2
1475                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1476                         wx.CallAfter(self.resumeButton.Enable, True)
1477                 elif self._wizardState == 3:
1478                         self._wizardState = 4
1479                         if profile.getMachineSetting('has_heated_bed') == 'True':
1480                                 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1481                         else:
1482                                 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1483                         wx.CallAfter(self.resumeButton.Enable, True)
1484                 elif self._wizardState == 5:
1485                         self._wizardState = 6
1486                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1487                         wx.CallAfter(self.resumeButton.Enable, True)
1488                 elif self._wizardState == 7:
1489                         self._wizardState = 8
1490                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1491                         wx.CallAfter(self.resumeButton.Enable, True)
1492                 elif self._wizardState == 9:
1493                         if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1494                                 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1495                         else:
1496                                 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1497                                 wx.CallAfter(self.resumeButton.Enable, True)
1498                                 self._wizardState = 10
1499
1500         def mcStateChange(self, state):
1501                 if self.comm is None:
1502                         return
1503                 if self.comm.isOperational():
1504                         if self._wizardState == 0:
1505                                 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1506                                 wx.CallAfter(self.upButton.Enable, True)
1507                                 wx.CallAfter(self.downButton.Enable, True)
1508                                 wx.CallAfter(self.upButton2.Enable, True)
1509                                 wx.CallAfter(self.downButton2.Enable, True)
1510                                 wx.CallAfter(self.resumeButton.Enable, True)
1511                                 self._wizardState = -1
1512                         elif self._wizardState == 11 and not self.comm.isPrinting():
1513                                 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1514                                 self.comm.sendCommand('G92 E0')
1515                                 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1516                                 self.comm.sendCommand('M104 S0')
1517                                 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1518                                 wx.CallAfter(self.infoBox.SetReadyIndicator)
1519                                 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1520                                 wx.CallAfter(self.connectButton.Enable, True)
1521                                 self._wizardState = 12
1522                 elif self.comm.isError():
1523                         wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1524
1525         def mcMessage(self, message):
1526                 pass
1527
1528         def mcProgress(self, lineNr):
1529                 pass
1530
1531         def mcZChange(self, newZ):
1532                 pass
1533
1534 class headOffsetCalibrationPage(InfoPage):
1535         def __init__(self, parent):
1536                 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1537
1538                 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1539                 self.AddSeperator()
1540
1541                 self.connectButton = self.AddButton(_('Connect to printer'))
1542                 self.comm = None
1543
1544                 self.infoBox = self.AddInfoBox()
1545                 self.textEntry = self.AddTextCtrl('')
1546                 self.textEntry.Enable(False)
1547                 self.resumeButton = self.AddButton(_('Resume'))
1548                 self.resumeButton.Enable(False)
1549
1550                 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1551                 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1552
1553         def AllowBack(self):
1554                 return True
1555
1556         def OnConnect(self, e = None):
1557                 if self.comm is not None:
1558                         self.comm.close()
1559                         del self.comm
1560                         self.comm = None
1561                         wx.CallAfter(self.OnConnect)
1562                         return
1563                 self.connectButton.Enable(False)
1564                 self.comm = machineCom.MachineCom(callbackObject=self)
1565                 self.infoBox.SetBusy(_('Connecting to machine.'))
1566                 self._wizardState = 0
1567
1568         def OnResume(self, e):
1569                 if self._wizardState == 2:
1570                         self._wizardState = 3
1571                         wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1572
1573                         w = profile.getMachineSettingFloat('machine_width')
1574                         d = profile.getMachineSettingFloat('machine_depth')
1575
1576                         gcode = gcodeGenerator.gcodeGenerator()
1577                         gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1578                         gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1579                         gcode.addCmd('T0')
1580                         gcode.addPrime(15)
1581                         gcode.addCmd('T1')
1582                         gcode.addPrime(15)
1583
1584                         gcode.addCmd('T0')
1585                         gcode.addMove(w/2, 5)
1586                         gcode.addMove(z=0.2)
1587                         gcode.addPrime()
1588                         gcode.addExtrude(w/2, d-5.0)
1589                         gcode.addRetract()
1590                         gcode.addMove(5, d/2)
1591                         gcode.addPrime()
1592                         gcode.addExtrude(w-5.0, d/2)
1593                         gcode.addRetract(15)
1594
1595                         gcode.addCmd('T1')
1596                         gcode.addMove(w/2, 5)
1597                         gcode.addPrime()
1598                         gcode.addExtrude(w/2, d-5.0)
1599                         gcode.addRetract()
1600                         gcode.addMove(5, d/2)
1601                         gcode.addPrime()
1602                         gcode.addExtrude(w-5.0, d/2)
1603                         gcode.addRetract(15)
1604                         gcode.addCmd('T0')
1605
1606                         gcode.addMove(z=25)
1607                         gcode.addMove(0, 0)
1608                         gcode.addCmd('M400')
1609
1610                         self.comm.printGCode(gcode.list())
1611                         self.resumeButton.Enable(False)
1612                 elif self._wizardState == 4:
1613                         try:
1614                                 float(self.textEntry.GetValue())
1615                         except ValueError:
1616                                 return
1617                         profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1618                         self._wizardState = 5
1619                         self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1620                         self.textEntry.SetValue('0.0')
1621                         self.textEntry.Enable(True)
1622                 elif self._wizardState == 5:
1623                         try:
1624                                 float(self.textEntry.GetValue())
1625                         except ValueError:
1626                                 return
1627                         profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1628                         self._wizardState = 6
1629                         self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1630                         self.textEntry.SetValue('')
1631                         self.textEntry.Enable(False)
1632                         self.resumeButton.Enable(False)
1633
1634                         x = profile.getMachineSettingFloat('extruder_offset_x1')
1635                         y = profile.getMachineSettingFloat('extruder_offset_y1')
1636                         gcode = gcodeGenerator.gcodeGenerator()
1637                         gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1638                         gcode.setPrintSpeed(25)
1639                         gcode.addHome()
1640                         gcode.addCmd('T0')
1641                         gcode.addMove(50, 40, 0.2)
1642                         gcode.addPrime(15)
1643                         for n in xrange(0, 10):
1644                                 gcode.addExtrude(50 + n * 10, 150)
1645                                 gcode.addExtrude(50 + n * 10 + 5, 150)
1646                                 gcode.addExtrude(50 + n * 10 + 5, 40)
1647                                 gcode.addExtrude(50 + n * 10 + 10, 40)
1648                         gcode.addMove(40, 50)
1649                         for n in xrange(0, 10):
1650                                 gcode.addExtrude(150, 50 + n * 10)
1651                                 gcode.addExtrude(150, 50 + n * 10 + 5)
1652                                 gcode.addExtrude(40, 50 + n * 10 + 5)
1653                                 gcode.addExtrude(40, 50 + n * 10 + 10)
1654                         gcode.addRetract(15)
1655
1656                         gcode.addCmd('T1')
1657                         gcode.addMove(50 - x, 30 - y, 0.2)
1658                         gcode.addPrime(15)
1659                         for n in xrange(0, 10):
1660                                 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1661                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1662                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1663                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1664                         gcode.addMove(30 - x, 50 - y, 0.2)
1665                         for n in xrange(0, 10):
1666                                 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1667                                 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1668                                 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1669                                 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1670                         gcode.addRetract(15)
1671                         gcode.addMove(z=15)
1672                         gcode.addCmd('M400')
1673                         gcode.addCmd('M104 T0 S0')
1674                         gcode.addCmd('M104 T1 S0')
1675                         self.comm.printGCode(gcode.list())
1676                 elif self._wizardState == 7:
1677                         try:
1678                                 n = int(self.textEntry.GetValue()) - 1
1679                         except:
1680                                 return
1681                         x = profile.getMachineSettingFloat('extruder_offset_x1')
1682                         x += -1.0 + n * 0.1
1683                         profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1684                         self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1685                         self.textEntry.SetValue('10')
1686                         self._wizardState = 8
1687                 elif self._wizardState == 8:
1688                         try:
1689                                 n = int(self.textEntry.GetValue()) - 1
1690                         except:
1691                                 return
1692                         y = profile.getMachineSettingFloat('extruder_offset_y1')
1693                         y += -1.0 + n * 0.1
1694                         profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1695                         self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1696                         self.infoBox.SetReadyIndicator()
1697                         self._wizardState = 8
1698                         self.comm.close()
1699                         self.resumeButton.Enable(False)
1700
1701         def mcLog(self, message):
1702                 print 'Log:', message
1703
1704         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1705                 if self._wizardState == 1:
1706                         if temp[0] >= 210 and temp[1] >= 210:
1707                                 self._wizardState = 2
1708                                 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1709                                 wx.CallAfter(self.resumeButton.Enable, True)
1710                                 wx.CallAfter(self.resumeButton.SetFocus)
1711
1712         def mcStateChange(self, state):
1713                 if self.comm is None:
1714                         return
1715                 if self.comm.isOperational():
1716                         if self._wizardState == 0:
1717                                 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1718                                 self.comm.sendCommand('M105')
1719                                 self.comm.sendCommand('M104 S220 T0')
1720                                 self.comm.sendCommand('M104 S220 T1')
1721                                 self.comm.sendCommand('G28')
1722                                 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1723                                 self._wizardState = 1
1724                         if not self.comm.isPrinting():
1725                                 if self._wizardState == 3:
1726                                         self._wizardState = 4
1727                                         wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1728                                         wx.CallAfter(self.textEntry.SetValue, '0.0')
1729                                         wx.CallAfter(self.textEntry.Enable, True)
1730                                         wx.CallAfter(self.resumeButton.Enable, True)
1731                                         wx.CallAfter(self.resumeButton.SetFocus)
1732                                 elif self._wizardState == 6:
1733                                         self._wizardState = 7
1734                                         wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1735                                         wx.CallAfter(self.textEntry.SetValue, '10')
1736                                         wx.CallAfter(self.textEntry.Enable, True)
1737                                         wx.CallAfter(self.resumeButton.Enable, True)
1738                                         wx.CallAfter(self.resumeButton.SetFocus)
1739
1740                 elif self.comm.isError():
1741                         wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1742
1743         def mcMessage(self, message):
1744                 pass
1745
1746         def mcProgress(self, lineNr):
1747                 pass
1748
1749         def mcZChange(self, newZ):
1750                 pass
1751
1752 class bedLevelWizard(wx.wizard.Wizard):
1753         def __init__(self):
1754                 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1755
1756                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1757                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1758
1759                 self.mainPage = bedLevelWizardMain(self)
1760                 self.headOffsetCalibration = None
1761
1762                 self.RunWizard(self.mainPage)
1763                 self.Destroy()
1764
1765         def OnPageChanging(self, e):
1766                 e.GetPage().StoreData()
1767
1768         def OnPageChanged(self, e):
1769                 if e.GetPage().AllowNext():
1770                         self.FindWindowById(wx.ID_FORWARD).Enable()
1771                 else:
1772                         self.FindWindowById(wx.ID_FORWARD).Disable()
1773                 if e.GetPage().AllowBack():
1774                         self.FindWindowById(wx.ID_BACKWARD).Enable()
1775                 else:
1776                         self.FindWindowById(wx.ID_BACKWARD).Disable()
1777
1778 class headOffsetWizard(wx.wizard.Wizard):
1779         def __init__(self):
1780                 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1781
1782                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1783                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1784
1785                 self.mainPage = headOffsetCalibrationPage(self)
1786
1787                 self.RunWizard(self.mainPage)
1788                 self.Destroy()
1789
1790         def OnPageChanging(self, e):
1791                 e.GetPage().StoreData()
1792
1793         def OnPageChanged(self, e):
1794                 if e.GetPage().AllowNext():
1795                         self.FindWindowById(wx.ID_FORWARD).Enable()
1796                 else:
1797                         self.FindWindowById(wx.ID_FORWARD).Disable()
1798                 if e.GetPage().AllowBack():
1799                         self.FindWindowById(wx.ID_BACKWARD).Enable()
1800                 else:
1801                         self.FindWindowById(wx.ID_BACKWARD).Disable()