1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
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
20 class InfoBox(wx.Panel):
21 def __init__(self, parent):
22 super(InfoBox, self).__init__(parent)
23 self.SetBackgroundColour('#FFFF80')
25 self.sizer = wx.GridBagSizer(5, 5)
26 self.SetSizer(self.sizer)
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'))
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'))
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)
46 self.extraInfoButton.Show(False)
48 self.extraInfoUrl = ''
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)
55 def SetInfo(self, info):
56 self.SetBackgroundColour('#FFFF80')
57 self.text.SetLabel(info)
58 self.extraInfoButton.Show(False)
61 def SetError(self, info, extraInfoUrl):
62 self.extraInfoUrl = extraInfoUrl
63 self.SetBackgroundColour('#FF8080')
64 self.text.SetLabel(info)
65 self.extraInfoButton.Show(True)
67 self.SetErrorIndicator()
70 def SetAttention(self, info):
71 self.SetBackgroundColour('#FFFF80')
72 self.text.SetLabel(info)
73 self.extraInfoButton.Show(False)
74 self.SetAttentionIndicator()
78 def SetBusy(self, info):
80 self.SetBusyIndicator()
82 def SetBusyIndicator(self):
84 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
86 def doExtraInfo(self, e):
87 webbrowser.open(self.extraInfoUrl)
89 def doBusyUpdate(self, e):
90 if self.busyState is None:
93 if self.busyState >= len(self.busyBitmap):
95 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
97 def SetReadyIndicator(self):
99 self.bitmap.SetBitmap(self.readyBitmap)
101 def SetErrorIndicator(self):
102 self.busyState = None
103 self.bitmap.SetBitmap(self.errorBitmap)
105 def SetAttentionIndicator(self):
106 self.busyState = None
107 self.bitmap.SetBitmap(self.attentionBitmap)
110 class InfoPage(wx.wizard.WizardPageSimple):
111 def __init__(self, parent, title):
112 wx.wizard.WizardPageSimple.__init__(self, parent)
114 sizer = wx.GridBagSizer(5, 5)
118 title = wx.StaticText(self, -1, title)
119 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
120 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
121 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
122 sizer.AddGrowableCol(1)
126 def AddText(self, info):
127 text = wx.StaticText(self, -1, info)
128 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
132 def AddSeperator(self):
133 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
136 def AddHiddenSeperator(self):
139 def AddInfoBox(self):
140 infoBox = InfoBox(self)
141 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
145 def AddRadioButton(self, label, style=0):
146 radio = wx.RadioButton(self, -1, label, style=style)
147 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
151 def AddCheckbox(self, label, checked=False):
152 check = wx.CheckBox(self, -1)
153 text = wx.StaticText(self, -1, label)
154 check.SetValue(checked)
155 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
156 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
160 def AddButton(self, label):
161 button = wx.Button(self, -1, label)
162 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
166 def AddDualButton(self, label1, label2):
167 button1 = wx.Button(self, -1, label1)
168 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
169 button2 = wx.Button(self, -1, label2)
170 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
172 return button1, button2
174 def AddTextCtrl(self, value):
175 ret = wx.TextCtrl(self, -1, value)
176 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
180 def AddLabelTextCtrl(self, info, value):
181 text = wx.StaticText(self, -1, info)
182 ret = wx.TextCtrl(self, -1, value)
183 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
184 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
188 def AddTextCtrlButton(self, value, buttonText):
189 text = wx.TextCtrl(self, -1, value)
190 button = wx.Button(self, -1, buttonText)
191 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
192 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
196 def AddBitmap(self, bitmap):
197 bitmap = wx.StaticBitmap(self, -1, bitmap)
198 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
202 def AddCheckmark(self, label, bitmap):
203 check = wx.StaticBitmap(self, -1, bitmap)
204 text = wx.StaticText(self, -1, label)
205 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
206 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
210 def AddCombo(self, label, options):
211 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
212 text = wx.StaticText(self, -1, label)
213 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
214 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
227 class PrintrbotPage(InfoPage):
228 def __init__(self, parent):
229 self._printer_info = [
230 # X, Y, Z, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount
231 ("Simple Metal", 150, 150, 150, 1.75, 208, 40, 70, 30, 1),
232 ("Metal Plus", 250, 250, 250, 1.75, 208, 40, 70, 30, 1),
233 ("Simple Makers Kit", 100, 100, 100, 1.75, 208, 40, 70, 30, 1),
234 (":" + _("Older models"),),
235 ("Original", 130, 130, 130, 2.95, 208, 40, 70, 30, 1),
236 ("Simple Maker's Edition v1", 100, 100, 100, 1.75, 208, 40, 70, 30, 1),
237 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 1.75, 208, 40, 70, 30, 1),
238 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 1.75, 208, 40, 70, 30, 1),
239 ("Simple Maker's Edition v4 (Model 1405)", 100, 100, 100, 1.75, 208, 40, 70, 30, 1),
240 ("Jr v1", 150, 100, 80, 1.75, 208, 40, 70, 30, 1),
241 ("Jr v2", 150, 150, 150, 1.75, 208, 40, 70, 30, 1),
242 ("LC v2", 150, 150, 150, 1.75, 208, 40, 70, 30, 1),
243 ("Plus v2", 200, 200, 200, 1.75, 208, 40, 70, 30, 1),
244 ("Plus v2.1", 200, 200, 200, 1.75, 208, 40, 70, 30, 1),
245 ("Plus v2.2 (Model 1404/140422)", 250, 250, 250, 1.75, 208, 40, 70, 30, 1),
246 ("Plus v2.3 (Model 140501)", 250, 250, 250, 1.75, 208, 40, 70, 30, 1),
247 ("Plus v2.4 (Model 140507)", 250, 250, 250, 1.75, 208, 40, 70, 30, 1),
248 ("Go v2 Large", 609, 305, 305, 1.75, 208, 35, 70, 30, 1),
251 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
252 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
253 self.AddText(_("Select which Printrbot machine you have:"))
255 for printer in self._printer_info:
256 if printer[0].startswith(":"):
258 self.AddText(printer[0][1:])
260 item = self.AddRadioButton(printer[0])
261 item.data = printer[1:]
262 self._items.append(item)
265 profile.putMachineSetting('machine_name', 'Printrbot ???')
266 for item in self._items:
269 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
270 profile.putMachineSetting('machine_width', data[0])
271 profile.putMachineSetting('machine_depth', data[1])
272 profile.putMachineSetting('machine_height', data[2])
273 profile.putProfileSetting('nozzle_size', '0.5')
274 profile.putProfileSetting('filament_diameter', data[3])
275 profile.putProfileSetting('print_temperature', data[4])
276 profile.putProfileSetting('print_speed', data[5])
277 profile.putProfileSetting('travel_speed', data[6])
278 profile.putProfileSetting('retraction_speed', data[7])
279 profile.putProfileSetting('retraction_amount', data[8])
280 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
281 profile.putMachineSetting('has_heated_bed', 'False')
282 profile.putMachineSetting('machine_center_is_zero', 'False')
283 profile.putMachineSetting('extruder_head_size_min_x', '0')
284 profile.putMachineSetting('extruder_head_size_min_y', '0')
285 profile.putMachineSetting('extruder_head_size_max_x', '0')
286 profile.putMachineSetting('extruder_head_size_max_y', '0')
287 profile.putMachineSetting('extruder_head_size_height', '0')
289 class OtherMachineSelectPage(InfoPage):
290 def __init__(self, parent):
291 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
292 self.AddText(_("The following pre-defined machine profiles are available"))
293 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."))
295 machines = resources.getDefaultMachineProfiles()
297 for filename in machines:
298 name = os.path.splitext(os.path.basename(filename))[0]
299 item = self.AddRadioButton(name)
300 item.filename = filename
301 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
302 self.options.append(item)
304 item = self.AddRadioButton(_('Custom...'))
306 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
308 def OnProfileSelect(self, e):
309 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
311 def OnOtherSelect(self, e):
312 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
315 for option in self.options:
316 if option.GetValue():
317 profile.loadProfile(option.filename)
318 profile.loadMachineSettings(option.filename)
320 class OtherMachineInfoPage(InfoPage):
321 def __init__(self, parent):
322 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
323 self.AddText(_("Cura is now ready to be used!"))
325 class CustomRepRapInfoPage(InfoPage):
326 def __init__(self, parent):
327 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
328 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
329 self.AddText(_("Be sure to review the default profile before running it on your machine."))
330 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
332 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
334 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
335 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
336 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
337 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
338 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
339 self.heatedBed = self.AddCheckbox(_("Heated bed"))
340 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
343 profile.putMachineSetting('machine_name', self.machineName.GetValue())
344 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
345 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
346 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
347 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
348 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
349 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
350 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
351 profile.putMachineSetting('extruder_head_size_min_x', '0')
352 profile.putMachineSetting('extruder_head_size_min_y', '0')
353 profile.putMachineSetting('extruder_head_size_max_x', '0')
354 profile.putMachineSetting('extruder_head_size_max_y', '0')
355 profile.putMachineSetting('extruder_head_size_height', '0')
356 profile.checkAndUpdateMachineName()
358 class MachineSelectPage(InfoPage):
359 def __init__(self, parent):
360 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
361 self.AddText(_("What kind of machine do you have:"))
363 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
364 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
365 self.LulzbotMiniRadio.SetValue(True)
366 self.LulzbotTazRadio = self.AddRadioButton("LulzBot TAZ")
367 self.LulzbotTazRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
368 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
369 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
370 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
371 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
372 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
373 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
374 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
375 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
376 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
377 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
379 def OnUltimaker2Select(self, e):
380 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
382 def OnUltimakerSelect(self, e):
383 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
385 def OnUltimakerOPSelect(self, e):
386 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
388 def OnPrintrbotSelect(self, e):
389 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
391 def OnLulzbotSelect(self, e):
392 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
394 def OnOtherSelect(self, e):
395 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
398 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
402 profile.putProfileSetting('retraction_enable', 'True')
403 if self.Ultimaker2Radio.GetValue():
404 profile.putMachineSetting('machine_width', '230')
405 profile.putMachineSetting('machine_depth', '225')
406 profile.putMachineSetting('machine_height', '205')
407 profile.putMachineSetting('machine_name', 'ultimaker2')
408 profile.putMachineSetting('machine_type', 'ultimaker2')
409 profile.putMachineSetting('machine_center_is_zero', 'False')
410 profile.putMachineSetting('has_heated_bed', 'True')
411 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
412 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
413 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
414 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
415 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
416 profile.putMachineSetting('extruder_head_size_height', '48.0')
417 profile.putProfileSetting('nozzle_size', '0.4')
418 profile.putProfileSetting('fan_full_height', '5.0')
419 profile.putMachineSetting('extruder_offset_x1', '18.0')
420 profile.putMachineSetting('extruder_offset_y1', '0.0')
421 elif self.UltimakerRadio.GetValue():
422 profile.putMachineSetting('machine_width', '205')
423 profile.putMachineSetting('machine_depth', '205')
424 profile.putMachineSetting('machine_height', '200')
425 profile.putMachineSetting('machine_name', 'ultimaker original')
426 profile.putMachineSetting('machine_type', 'ultimaker')
427 profile.putMachineSetting('machine_center_is_zero', 'False')
428 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
429 profile.putProfileSetting('nozzle_size', '0.4')
430 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
431 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
432 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
433 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
434 profile.putMachineSetting('extruder_head_size_height', '55.0')
435 elif self.UltimakerOPRadio.GetValue():
436 profile.putMachineSetting('machine_width', '205')
437 profile.putMachineSetting('machine_depth', '205')
438 profile.putMachineSetting('machine_height', '200')
439 profile.putMachineSetting('machine_name', 'ultimaker original+')
440 profile.putMachineSetting('machine_type', 'ultimaker_plus')
441 profile.putMachineSetting('machine_center_is_zero', 'False')
442 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
443 profile.putProfileSetting('nozzle_size', '0.4')
444 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
445 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
446 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
447 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
448 profile.putMachineSetting('extruder_head_size_height', '55.0')
449 profile.putMachineSetting('has_heated_bed', 'True')
450 profile.putMachineSetting('extruder_amount', '1')
451 profile.putProfileSetting('retraction_enable', 'True')
452 elif self.LulzbotTazRadio.GetValue() or self.LulzbotMiniRadio.GetValue():
453 if self.LulzbotTazRadio.GetValue():
454 profile.putMachineSetting('machine_width', '298')
455 profile.putMachineSetting('machine_depth', '275')
456 profile.putMachineSetting('machine_height', '250')
457 profile.putProfileSetting('nozzle_size', '0.35')
458 profile.putMachineSetting('machine_name', 'LulzBot TAZ')
459 profile.putMachineSetting('machine_type', 'lulzbot_TAZ')
460 profile.putMachineSetting('serial_baud', '115200')
462 profile.putMachineSetting('machine_width', '155')
463 profile.putMachineSetting('machine_depth', '155')
464 profile.putMachineSetting('machine_height', '163')
465 profile.putProfileSetting('nozzle_size', '0.5')
466 profile.putMachineSetting('machine_name', 'LulzBot Mini')
467 profile.putMachineSetting('machine_type', 'lulzbot_mini')
468 profile.putMachineSetting('serial_baud', '115200')
469 profile.putMachineSetting('machine_center_is_zero', 'False')
470 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
471 profile.putMachineSetting('has_heated_bed', 'True')
472 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
473 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
474 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
475 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
476 profile.putMachineSetting('extruder_head_size_height', '0.0')
478 profile.putMachineSetting('machine_width', '80')
479 profile.putMachineSetting('machine_depth', '80')
480 profile.putMachineSetting('machine_height', '60')
481 profile.putMachineSetting('machine_name', 'reprap')
482 profile.putMachineSetting('machine_type', 'reprap')
483 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
484 profile.putPreference('startMode', 'Normal')
485 profile.putProfileSetting('nozzle_size', '0.5')
486 profile.checkAndUpdateMachineName()
487 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
489 class SelectParts(InfoPage):
490 def __init__(self, parent):
491 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
492 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."))
494 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
495 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
496 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
497 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
499 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."))
500 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
501 self.springExtruder.SetValue(True)
504 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
505 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
506 profile.putMachineSetting('has_heated_bed', 'True')
508 profile.putMachineSetting('has_heated_bed', 'False')
509 if self.dualExtrusion.GetValue():
510 profile.putMachineSetting('extruder_amount', '2')
511 profile.putMachineSetting('machine_depth', '195')
513 profile.putMachineSetting('extruder_amount', '1')
514 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
515 profile.putProfileSetting('retraction_enable', 'True')
517 profile.putProfileSetting('retraction_enable', 'False')
520 class UltimakerFirmwareUpgradePage(InfoPage):
521 def __init__(self, parent):
522 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
523 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."))
524 self.AddHiddenSeperator()
525 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
526 self.AddHiddenSeperator()
527 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."))
528 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
529 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
530 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
531 self.AddHiddenSeperator()
532 if profile.getMachineSetting('machine_type') == 'ultimaker':
533 self.AddText(_("Do not upgrade to this firmware if:"))
534 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
535 self.AddText(_("* Build your own heated bed"))
536 self.AddText(_("* Have other changes in the firmware"))
537 # button = self.AddButton('Goto this page for a custom firmware')
538 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
543 def OnUpgradeClick(self, e):
544 if firmwareInstall.InstallFirmware():
545 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
547 def OnSkipClick(self, e):
548 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
549 self.GetParent().ShowPage(self.GetNext())
551 def OnUrlClick(self, e):
552 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
554 class UltimakerCheckupPage(InfoPage):
555 def __init__(self, parent):
556 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
558 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
559 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
560 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
561 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
562 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
563 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
564 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
565 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
566 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
567 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
570 _("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."))
571 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
572 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
573 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
575 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
576 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
577 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
579 self.infoBox = self.AddInfoBox()
580 self.machineState = self.AddText("")
581 self.temperatureLabel = self.AddText("")
582 self.errorLogButton = self.AddButton(_("Show error log"))
583 self.errorLogButton.Show(False)
585 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
587 self.xMinStop = False
588 self.xMaxStop = False
589 self.yMinStop = False
590 self.yMaxStop = False
591 self.zMinStop = False
592 self.zMaxStop = False
594 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
597 if self.comm is not None:
601 self.endstopBitmap.Show(False)
604 def OnSkipClick(self, e):
605 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
606 self.GetParent().ShowPage(self.GetNext())
608 def OnCheckClick(self, e=None):
609 self.errorLogButton.Show(False)
610 if self.comm is not None:
614 wx.CallAfter(self.OnCheckClick)
616 self.infoBox.SetBusy(_("Connecting to machine."))
617 self.commState.SetBitmap(self.unknownBitmap)
618 self.tempState.SetBitmap(self.unknownBitmap)
619 self.stopState.SetBitmap(self.unknownBitmap)
620 self.checkupState = 0
621 self.checkExtruderNr = 0
622 self.comm = machineCom.MachineCom(callbackObject=self)
624 def OnErrorLog(self, e):
625 printWindow.LogWindow('\n'.join(self.comm.getLog()))
627 def mcLog(self, message):
630 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
631 if not self.comm.isOperational():
633 if self.checkupState == 0:
634 self.tempCheckTimeout = 20
635 if temp[self.checkExtruderNr] > 70:
636 self.checkupState = 1
637 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
638 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
639 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
641 self.startTemp = temp[self.checkExtruderNr]
642 self.checkupState = 2
643 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
644 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
645 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
646 elif self.checkupState == 1:
647 if temp[self.checkExtruderNr] < 60:
648 self.startTemp = temp[self.checkExtruderNr]
649 self.checkupState = 2
650 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
651 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
652 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
653 elif self.checkupState == 2:
654 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
655 if temp[self.checkExtruderNr] > self.startTemp + 40:
656 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
657 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
658 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
659 self.checkExtruderNr = 0
660 self.checkupState = 3
661 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
662 wx.CallAfter(self.endstopBitmap.Show, True)
663 wx.CallAfter(self.Layout)
664 self.comm.sendCommand('M119')
665 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
667 self.checkupState = 0
668 self.checkExtruderNr += 1
670 self.tempCheckTimeout -= 1
671 if self.tempCheckTimeout < 1:
672 self.checkupState = -1
673 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
674 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
675 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
676 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
677 elif self.checkupState >= 3 and self.checkupState < 10:
678 self.comm.sendCommand('M119')
679 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
681 def mcStateChange(self, state):
682 if self.comm is None:
684 if self.comm.isOperational():
685 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
686 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
687 elif self.comm.isError():
688 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
689 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
690 wx.CallAfter(self.endstopBitmap.Show, False)
691 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
692 wx.CallAfter(self.errorLogButton.Show, True)
693 wx.CallAfter(self.Layout)
695 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
697 def mcMessage(self, message):
698 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
699 for data in message.split(' '):
701 tag, value = data.split(':', 1)
703 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
705 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
707 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
709 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
711 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
713 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
715 tag, value = map(str.strip, message.split(':', 1))
717 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
719 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
721 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
723 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
725 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
727 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
728 if 'z_max' in message:
729 self.comm.sendCommand('M119')
731 if self.checkupState == 3:
732 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
733 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
734 self.checkupState = 5
735 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
736 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
738 self.checkupState = 4
739 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
740 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
741 elif self.checkupState == 4:
742 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
743 self.checkupState = 5
744 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
745 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
746 elif self.checkupState == 5:
747 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
748 self.checkupState = 6
749 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
750 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
751 elif self.checkupState == 6:
752 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
753 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
754 self.checkupState = 8
755 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
756 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
758 self.checkupState = 7
759 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
760 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
761 elif self.checkupState == 7:
762 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
763 self.checkupState = 8
764 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
765 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
766 elif self.checkupState == 8:
767 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
768 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
769 self.checkupState = 10
771 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
772 wx.CallAfter(self.infoBox.SetReadyIndicator)
773 wx.CallAfter(self.endstopBitmap.Show, False)
774 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
775 wx.CallAfter(self.OnSkipClick, None)
777 self.checkupState = 9
778 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
779 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
780 elif self.checkupState == 9:
781 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
782 self.checkupState = 10
784 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
785 wx.CallAfter(self.infoBox.SetReadyIndicator)
786 wx.CallAfter(self.endstopBitmap.Show, False)
787 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
788 wx.CallAfter(self.OnSkipClick, None)
790 def mcProgress(self, lineNr):
793 def mcZChange(self, newZ):
797 class UltimakerCalibrationPage(InfoPage):
798 def __init__(self, parent):
799 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
801 self.AddText("Your Ultimaker requires some calibration.")
802 self.AddText("This calibration is needed for a proper extrusion amount.")
804 self.AddText("The following values are needed:")
805 self.AddText("* Diameter of filament")
806 self.AddText("* Number of steps per mm of filament extrusion")
808 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
810 self.AddText("First we need the diameter of your filament:")
811 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
813 "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.")
814 self.AddText("Note: This value can be changed later at any time.")
817 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
820 class UltimakerCalibrateStepsPerEPage(InfoPage):
821 def __init__(self, parent):
822 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
824 #if profile.getMachineSetting('steps_per_e') == '0':
825 # profile.putMachineSetting('steps_per_e', '865.888')
827 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
828 self.AddText(_("First remove any filament from your machine."))
829 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
830 self.AddText(_("We'll push the filament 100mm"))
831 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
832 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
833 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
834 self.AddText(_("This results in the following steps per E:"))
835 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
836 self.AddText(_("You can repeat these steps to get better calibration."))
839 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
840 self.heatButton = self.AddButton(_("Heatup for filament removal"))
842 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
843 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
844 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
846 def OnSaveLengthClick(self, e):
847 currentEValue = float(self.stepsPerEInput.GetValue())
848 realExtrudeLength = float(self.lengthInput.GetValue())
849 newEValue = currentEValue * 100 / realExtrudeLength
850 self.stepsPerEInput.SetValue(str(newEValue))
851 self.lengthInput.SetValue("100")
853 def OnExtrudeClick(self, e):
854 t = threading.Thread(target=self.OnExtrudeRun)
858 def OnExtrudeRun(self):
859 self.heatButton.Enable(False)
860 self.extrudeButton.Enable(False)
861 currentEValue = float(self.stepsPerEInput.GetValue())
862 self.comm = machineCom.MachineCom()
863 if not self.comm.isOpen():
865 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
866 'Printer error', wx.OK | wx.ICON_INFORMATION)
867 self.heatButton.Enable(True)
868 self.extrudeButton.Enable(True)
871 line = self.comm.readline()
876 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
879 self.sendGCommand('M302') #Disable cold extrusion protection
880 self.sendGCommand("M92 E%f" % (currentEValue))
881 self.sendGCommand("G92 E0")
882 self.sendGCommand("G1 E100 F600")
885 self.extrudeButton.Enable()
886 self.heatButton.Enable()
888 def OnHeatClick(self, e):
889 t = threading.Thread(target=self.OnHeatRun)
894 self.heatButton.Enable(False)
895 self.extrudeButton.Enable(False)
896 self.comm = machineCom.MachineCom()
897 if not self.comm.isOpen():
899 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
900 'Printer error', wx.OK | wx.ICON_INFORMATION)
901 self.heatButton.Enable(True)
902 self.extrudeButton.Enable(True)
905 line = self.comm.readline()
907 self.heatButton.Enable(True)
908 self.extrudeButton.Enable(True)
912 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
915 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
917 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
918 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
919 self.sendGCommand('M104 S0')
922 self.heatButton.Enable(True)
923 self.extrudeButton.Enable(True)
925 def sendGCommand(self, cmd):
926 self.comm.sendCommand(cmd) #Disable cold extrusion protection
928 line = self.comm.readline()
931 if line.startswith('ok'):
935 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
937 class Ultimaker2ReadyPage(InfoPage):
938 def __init__(self, parent):
939 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
940 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
941 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
944 class LulzbotReadyPage(InfoPage):
945 def __init__(self, parent):
946 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
947 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
949 self.AddText(_('For more information about using Cura with your LulzBot'))
950 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
953 class ConfigWizard(wx.wizard.Wizard):
954 def __init__(self, addNew = False):
955 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
957 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
959 profile.setActiveMachine(profile.getMachineCount())
961 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
962 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
963 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
965 self.machineSelectPage = MachineSelectPage(self)
966 self.ultimakerSelectParts = SelectParts(self)
967 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
968 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
969 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
970 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
971 self.bedLevelPage = bedLevelWizardMain(self)
972 self.headOffsetCalibration = headOffsetCalibrationPage(self)
973 self.printrbotSelectType = PrintrbotPage(self)
974 self.otherMachineSelectPage = OtherMachineSelectPage(self)
975 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
976 self.otherMachineInfoPage = OtherMachineInfoPage(self)
978 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
979 self.lulzbotReadyPage = LulzbotReadyPage(self)
981 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
982 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
983 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
984 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
985 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
986 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
987 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
988 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
990 self.FitToPage(self.machineSelectPage)
991 self.GetPageAreaSizer().Add(self.machineSelectPage)
993 self.RunWizard(self.machineSelectPage)
996 def OnPageChanging(self, e):
997 e.GetPage().StoreData()
999 def OnPageChanged(self, e):
1000 if e.GetPage().AllowNext():
1001 self.FindWindowById(wx.ID_FORWARD).Enable()
1003 self.FindWindowById(wx.ID_FORWARD).Disable()
1004 if e.GetPage().AllowBack():
1005 self.FindWindowById(wx.ID_BACKWARD).Enable()
1007 self.FindWindowById(wx.ID_BACKWARD).Disable()
1009 def OnCancel(self, e):
1010 profile.setActiveMachine(self._old_machine_index)
1012 class bedLevelWizardMain(InfoPage):
1013 def __init__(self, parent):
1014 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1016 self.AddText(_('This wizard will help you in leveling your printer bed'))
1018 self.AddText(_('It will do the following steps'))
1019 self.AddText(_('* Move the printer head to each corner'))
1020 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1021 self.AddText(_('* Print a line around the bed to check if it is level'))
1024 self.connectButton = self.AddButton(_('Connect to printer'))
1027 self.infoBox = self.AddInfoBox()
1028 self.resumeButton = self.AddButton(_('Resume'))
1029 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1030 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1031 self.resumeButton.Enable(False)
1033 self.upButton.Enable(False)
1034 self.downButton.Enable(False)
1035 self.upButton2.Enable(False)
1036 self.downButton2.Enable(False)
1038 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1039 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1040 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1041 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1042 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1043 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1045 def OnConnect(self, e = None):
1046 if self.comm is not None:
1050 wx.CallAfter(self.OnConnect)
1052 self.connectButton.Enable(False)
1053 self.comm = machineCom.MachineCom(callbackObject=self)
1054 self.infoBox.SetBusy(_('Connecting to machine.'))
1055 self._wizardState = 0
1057 def OnBedUp(self, e):
1058 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1059 self.comm.sendCommand('G92 Z10')
1060 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1061 self.comm.sendCommand('M400')
1063 def OnBedDown(self, e):
1064 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1065 self.comm.sendCommand('G92 Z10')
1066 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1067 self.comm.sendCommand('M400')
1069 def OnBedUp2(self, e):
1070 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1071 self.comm.sendCommand('G92 Z10')
1072 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1073 self.comm.sendCommand('M400')
1075 def OnBedDown2(self, e):
1076 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1077 self.comm.sendCommand('G92 Z10')
1078 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1079 self.comm.sendCommand('M400')
1081 def AllowNext(self):
1082 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1083 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1086 def OnResume(self, e):
1087 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1088 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1089 if self._wizardState == -1:
1090 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1091 wx.CallAfter(self.upButton.Enable, False)
1092 wx.CallAfter(self.downButton.Enable, False)
1093 wx.CallAfter(self.upButton2.Enable, False)
1094 wx.CallAfter(self.downButton2.Enable, False)
1095 self.comm.sendCommand('M105')
1096 self.comm.sendCommand('G28')
1097 self._wizardState = 1
1098 elif self._wizardState == 2:
1099 if profile.getMachineSetting('has_heated_bed') == 'True':
1100 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1101 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1102 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1103 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1104 self.comm.sendCommand('M400')
1105 self._wizardState = 3
1107 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1108 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1109 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1110 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1111 self.comm.sendCommand('M400')
1112 self._wizardState = 3
1113 elif self._wizardState == 4:
1114 if profile.getMachineSetting('has_heated_bed') == 'True':
1115 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1116 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1117 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1118 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1119 self.comm.sendCommand('M400')
1120 self._wizardState = 7
1122 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1123 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1124 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1125 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1126 self.comm.sendCommand('M400')
1127 self._wizardState = 5
1128 elif self._wizardState == 6:
1129 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1130 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1131 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1132 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1133 self.comm.sendCommand('M400')
1134 self._wizardState = 7
1135 elif self._wizardState == 8:
1136 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1137 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1138 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1139 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1140 self._wizardState = 9
1141 elif self._wizardState == 10:
1142 self._wizardState = 11
1143 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1144 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1145 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1146 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1147 w = profile.getMachineSettingFloat('machine_width') - 10
1148 d = profile.getMachineSettingFloat('machine_depth')
1149 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1150 filamentArea = math.pi * filamentRadius * filamentRadius
1151 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1155 'G1 Z2 F%d' % (feedZ),
1157 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1158 'G1 Z0.3 F%d' % (feedZ)]
1160 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1162 for i in xrange(0, 3):
1163 dist = 5.0 + 0.4 * float(i)
1164 eValue += (d - 2.0*dist) * ePerMM
1165 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1166 eValue += (w - 2.0*dist) * ePerMM
1167 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1168 eValue += (d - 2.0*dist) * ePerMM
1169 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1170 eValue += (w - 2.0*dist) * ePerMM
1171 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1173 gcodeList.append('M400')
1174 self.comm.printGCode(gcodeList)
1175 self.resumeButton.Enable(False)
1177 def mcLog(self, message):
1178 print 'Log:', message
1180 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1181 if self._wizardState == 1:
1182 self._wizardState = 2
1183 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1184 wx.CallAfter(self.resumeButton.Enable, True)
1185 elif self._wizardState == 3:
1186 self._wizardState = 4
1187 if profile.getMachineSetting('has_heated_bed') == 'True':
1188 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1190 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1191 wx.CallAfter(self.resumeButton.Enable, True)
1192 elif self._wizardState == 5:
1193 self._wizardState = 6
1194 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1195 wx.CallAfter(self.resumeButton.Enable, True)
1196 elif self._wizardState == 7:
1197 self._wizardState = 8
1198 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1199 wx.CallAfter(self.resumeButton.Enable, True)
1200 elif self._wizardState == 9:
1201 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1202 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1204 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1205 wx.CallAfter(self.resumeButton.Enable, True)
1206 self._wizardState = 10
1208 def mcStateChange(self, state):
1209 if self.comm is None:
1211 if self.comm.isOperational():
1212 if self._wizardState == 0:
1213 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1214 wx.CallAfter(self.upButton.Enable, True)
1215 wx.CallAfter(self.downButton.Enable, True)
1216 wx.CallAfter(self.upButton2.Enable, True)
1217 wx.CallAfter(self.downButton2.Enable, True)
1218 wx.CallAfter(self.resumeButton.Enable, True)
1219 self._wizardState = -1
1220 elif self._wizardState == 11 and not self.comm.isPrinting():
1221 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1222 self.comm.sendCommand('G92 E0')
1223 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1224 self.comm.sendCommand('M104 S0')
1225 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1226 wx.CallAfter(self.infoBox.SetReadyIndicator)
1227 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1228 wx.CallAfter(self.connectButton.Enable, True)
1229 self._wizardState = 12
1230 elif self.comm.isError():
1231 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1233 def mcMessage(self, message):
1236 def mcProgress(self, lineNr):
1239 def mcZChange(self, newZ):
1242 class headOffsetCalibrationPage(InfoPage):
1243 def __init__(self, parent):
1244 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1246 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1249 self.connectButton = self.AddButton(_('Connect to printer'))
1252 self.infoBox = self.AddInfoBox()
1253 self.textEntry = self.AddTextCtrl('')
1254 self.textEntry.Enable(False)
1255 self.resumeButton = self.AddButton(_('Resume'))
1256 self.resumeButton.Enable(False)
1258 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1259 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1261 def AllowBack(self):
1264 def OnConnect(self, e = None):
1265 if self.comm is not None:
1269 wx.CallAfter(self.OnConnect)
1271 self.connectButton.Enable(False)
1272 self.comm = machineCom.MachineCom(callbackObject=self)
1273 self.infoBox.SetBusy(_('Connecting to machine.'))
1274 self._wizardState = 0
1276 def OnResume(self, e):
1277 if self._wizardState == 2:
1278 self._wizardState = 3
1279 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1281 w = profile.getMachineSettingFloat('machine_width')
1282 d = profile.getMachineSettingFloat('machine_depth')
1284 gcode = gcodeGenerator.gcodeGenerator()
1285 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1286 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1293 gcode.addMove(w/2, 5)
1294 gcode.addMove(z=0.2)
1296 gcode.addExtrude(w/2, d-5.0)
1298 gcode.addMove(5, d/2)
1300 gcode.addExtrude(w-5.0, d/2)
1301 gcode.addRetract(15)
1304 gcode.addMove(w/2, 5)
1306 gcode.addExtrude(w/2, d-5.0)
1308 gcode.addMove(5, d/2)
1310 gcode.addExtrude(w-5.0, d/2)
1311 gcode.addRetract(15)
1316 gcode.addCmd('M400')
1318 self.comm.printGCode(gcode.list())
1319 self.resumeButton.Enable(False)
1320 elif self._wizardState == 4:
1322 float(self.textEntry.GetValue())
1325 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1326 self._wizardState = 5
1327 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1328 self.textEntry.SetValue('0.0')
1329 self.textEntry.Enable(True)
1330 elif self._wizardState == 5:
1332 float(self.textEntry.GetValue())
1335 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1336 self._wizardState = 6
1337 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1338 self.textEntry.SetValue('')
1339 self.textEntry.Enable(False)
1340 self.resumeButton.Enable(False)
1342 x = profile.getMachineSettingFloat('extruder_offset_x1')
1343 y = profile.getMachineSettingFloat('extruder_offset_y1')
1344 gcode = gcodeGenerator.gcodeGenerator()
1345 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1346 gcode.setPrintSpeed(25)
1349 gcode.addMove(50, 40, 0.2)
1351 for n in xrange(0, 10):
1352 gcode.addExtrude(50 + n * 10, 150)
1353 gcode.addExtrude(50 + n * 10 + 5, 150)
1354 gcode.addExtrude(50 + n * 10 + 5, 40)
1355 gcode.addExtrude(50 + n * 10 + 10, 40)
1356 gcode.addMove(40, 50)
1357 for n in xrange(0, 10):
1358 gcode.addExtrude(150, 50 + n * 10)
1359 gcode.addExtrude(150, 50 + n * 10 + 5)
1360 gcode.addExtrude(40, 50 + n * 10 + 5)
1361 gcode.addExtrude(40, 50 + n * 10 + 10)
1362 gcode.addRetract(15)
1365 gcode.addMove(50 - x, 30 - y, 0.2)
1367 for n in xrange(0, 10):
1368 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1369 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1370 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1371 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1372 gcode.addMove(30 - x, 50 - y, 0.2)
1373 for n in xrange(0, 10):
1374 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1375 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1376 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1377 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1378 gcode.addRetract(15)
1380 gcode.addCmd('M400')
1381 gcode.addCmd('M104 T0 S0')
1382 gcode.addCmd('M104 T1 S0')
1383 self.comm.printGCode(gcode.list())
1384 elif self._wizardState == 7:
1386 n = int(self.textEntry.GetValue()) - 1
1389 x = profile.getMachineSettingFloat('extruder_offset_x1')
1391 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1392 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1393 self.textEntry.SetValue('10')
1394 self._wizardState = 8
1395 elif self._wizardState == 8:
1397 n = int(self.textEntry.GetValue()) - 1
1400 y = profile.getMachineSettingFloat('extruder_offset_y1')
1402 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1403 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1404 self.infoBox.SetReadyIndicator()
1405 self._wizardState = 8
1407 self.resumeButton.Enable(False)
1409 def mcLog(self, message):
1410 print 'Log:', message
1412 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1413 if self._wizardState == 1:
1414 if temp[0] >= 210 and temp[1] >= 210:
1415 self._wizardState = 2
1416 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1417 wx.CallAfter(self.resumeButton.Enable, True)
1418 wx.CallAfter(self.resumeButton.SetFocus)
1420 def mcStateChange(self, state):
1421 if self.comm is None:
1423 if self.comm.isOperational():
1424 if self._wizardState == 0:
1425 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1426 self.comm.sendCommand('M105')
1427 self.comm.sendCommand('M104 S220 T0')
1428 self.comm.sendCommand('M104 S220 T1')
1429 self.comm.sendCommand('G28')
1430 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1431 self._wizardState = 1
1432 if not self.comm.isPrinting():
1433 if self._wizardState == 3:
1434 self._wizardState = 4
1435 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1436 wx.CallAfter(self.textEntry.SetValue, '0.0')
1437 wx.CallAfter(self.textEntry.Enable, True)
1438 wx.CallAfter(self.resumeButton.Enable, True)
1439 wx.CallAfter(self.resumeButton.SetFocus)
1440 elif self._wizardState == 6:
1441 self._wizardState = 7
1442 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1443 wx.CallAfter(self.textEntry.SetValue, '10')
1444 wx.CallAfter(self.textEntry.Enable, True)
1445 wx.CallAfter(self.resumeButton.Enable, True)
1446 wx.CallAfter(self.resumeButton.SetFocus)
1448 elif self.comm.isError():
1449 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1451 def mcMessage(self, message):
1454 def mcProgress(self, lineNr):
1457 def mcZChange(self, newZ):
1460 class bedLevelWizard(wx.wizard.Wizard):
1462 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1464 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1465 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1467 self.mainPage = bedLevelWizardMain(self)
1468 self.headOffsetCalibration = None
1470 self.FitToPage(self.mainPage)
1471 self.GetPageAreaSizer().Add(self.mainPage)
1473 self.RunWizard(self.mainPage)
1476 def OnPageChanging(self, e):
1477 e.GetPage().StoreData()
1479 def OnPageChanged(self, e):
1480 if e.GetPage().AllowNext():
1481 self.FindWindowById(wx.ID_FORWARD).Enable()
1483 self.FindWindowById(wx.ID_FORWARD).Disable()
1484 if e.GetPage().AllowBack():
1485 self.FindWindowById(wx.ID_BACKWARD).Enable()
1487 self.FindWindowById(wx.ID_BACKWARD).Disable()
1489 class headOffsetWizard(wx.wizard.Wizard):
1491 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1493 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1494 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1496 self.mainPage = headOffsetCalibrationPage(self)
1498 self.FitToPage(self.mainPage)
1499 self.GetPageAreaSizer().Add(self.mainPage)
1501 self.RunWizard(self.mainPage)
1504 def OnPageChanging(self, e):
1505 e.GetPage().StoreData()
1507 def OnPageChanged(self, e):
1508 if e.GetPage().AllowNext():
1509 self.FindWindowById(wx.ID_FORWARD).Enable()
1511 self.FindWindowById(wx.ID_FORWARD).Disable()
1512 if e.GetPage().AllowBack():
1513 self.FindWindowById(wx.ID_BACKWARD).Enable()
1515 self.FindWindowById(wx.ID_BACKWARD).Disable()