chiark / gitweb /
Add more missing translations
[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
110 class InfoPage(wx.wizard.WizardPageSimple):
111         def __init__(self, parent, title):
112                 wx.wizard.WizardPageSimple.__init__(self, parent)
113
114                 sizer = wx.GridBagSizer(5, 5)
115                 self.sizer = sizer
116                 self.SetSizer(sizer)
117
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)
123
124                 self.rowNr = 2
125
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)
129                 self.rowNr += 1
130                 return text
131
132         def AddSeperator(self):
133                 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
134                 self.rowNr += 1
135
136         def AddHiddenSeperator(self):
137                 self.AddText("")
138
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)
142                 self.rowNr += 1
143                 return infoBox
144
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)
148                 self.rowNr += 1
149                 return radio
150
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)
157                 self.rowNr += 1
158                 return check
159
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)
163                 self.rowNr += 1
164                 return button
165
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))
171                 self.rowNr += 1
172                 return button1, button2
173
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)
177                 self.rowNr += 1
178                 return ret
179
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)
185                 self.rowNr += 1
186                 return ret
187
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)
193                 self.rowNr += 1
194                 return text, button
195
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)
199                 self.rowNr += 1
200                 return bitmap
201
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)
207                 self.rowNr += 1
208                 return check
209
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)
215                 self.rowNr += 1
216                 return combo
217
218         def AllowNext(self):
219                 return True
220
221         def AllowBack(self):
222                 return True
223
224         def StoreData(self):
225                 pass
226
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                         "Original": (130, 130, 130, 2.95, 208, 40, 70, 30, 1),
232                         "Simple Maker's Edition v1": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
233                         "Simple Maker's Edition v2 (2013 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
234                         "Simple Maker's Edition v3 (2014 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
235                         "Simple Maker's Edition v4 (Model 1405)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
236                         "Simple Metal": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
237                         "Jr v1": (150, 100, 80, 1.75, 208, 40, 70, 30, 1),
238                         "Jr v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
239                         "LC v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
240                         "Plus v2": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
241                         "Plus v2.1": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
242                         "Plus v2.2 (Model 1404/140422)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
243                         "Plus v2.3 (Model 140501)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
244                         "Plus v2.4 (Model 140507)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
245                 }
246
247                 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
248                 self.AddText(_("Select which Printrbot machine you have:"))
249                 keys = self._printer_info.keys()
250                 keys.sort()
251                 self._items = []
252                 for name in keys:
253                         item = self.AddRadioButton(name)
254                         item.data = self._printer_info[name]
255                         self._items.append(item)
256
257         def StoreData(self):
258                 profile.putMachineSetting('machine_name', 'Printrbot ???')
259                 for item in self._items:
260                         if item.GetValue():
261                                 data = item.data
262                                 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
263                                 profile.putMachineSetting('machine_width', data[0])
264                                 profile.putMachineSetting('machine_depth', data[1])
265                                 profile.putMachineSetting('machine_height', data[2])
266                                 profile.putProfileSetting('nozzle_size', '0.5')
267                                 profile.putProfileSetting('filament_diameter', data[3])
268                                 profile.putProfileSetting('print_temperature', data[4])
269                                 profile.putProfileSetting('print_speed', data[5])
270                                 profile.putProfileSetting('travel_speed', data[6])
271                                 profile.putProfileSetting('retraction_speed', data[7])
272                                 profile.putProfileSetting('retraction_amount', data[8])
273                                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
274                                 profile.putMachineSetting('has_heated_bed', 'False')
275                                 profile.putMachineSetting('machine_center_is_zero', 'False')
276                                 profile.putMachineSetting('extruder_head_size_min_x', '0')
277                                 profile.putMachineSetting('extruder_head_size_min_y', '0')
278                                 profile.putMachineSetting('extruder_head_size_max_x', '0')
279                                 profile.putMachineSetting('extruder_head_size_max_y', '0')
280                                 profile.putMachineSetting('extruder_head_size_height', '0')
281
282 class OtherMachineSelectPage(InfoPage):
283         def __init__(self, parent):
284                 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
285                 self.AddText(_("The following pre-defined machine profiles are available"))
286                 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."))
287                 self.options = []
288                 machines = resources.getDefaultMachineProfiles()
289                 machines.sort()
290                 for filename in machines:
291                         name = os.path.splitext(os.path.basename(filename))[0]
292                         item = self.AddRadioButton(name)
293                         item.filename = filename
294                         item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
295                         self.options.append(item)
296                 self.AddSeperator()
297                 item = self.AddRadioButton(_('Custom...'))
298                 item.SetValue(True)
299                 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
300
301         def OnProfileSelect(self, e):
302                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
303
304         def OnOtherSelect(self, e):
305                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
306
307         def StoreData(self):
308                 for option in self.options:
309                         if option.GetValue():
310                                 profile.loadProfile(option.filename)
311                                 profile.loadMachineSettings(option.filename)
312
313 class OtherMachineInfoPage(InfoPage):
314         def __init__(self, parent):
315                 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
316                 self.AddText(_("Cura is now ready to be used!"))
317
318 class CustomRepRapInfoPage(InfoPage):
319         def __init__(self, parent):
320                 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
321                 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
322                 self.AddText(_("Be sure to review the default profile before running it on your machine."))
323                 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
324                 self.AddSeperator()
325                 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
326                 self.AddSeperator()
327                 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
328                 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
329                 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
330                 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
331                 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
332                 self.heatedBed = self.AddCheckbox(_("Heated bed"))
333                 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
334
335         def StoreData(self):
336                 profile.putMachineSetting('machine_name', self.machineName.GetValue())
337                 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
338                 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
339                 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
340                 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
341                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
342                 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
343                 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
344                 profile.putMachineSetting('extruder_head_size_min_x', '0')
345                 profile.putMachineSetting('extruder_head_size_min_y', '0')
346                 profile.putMachineSetting('extruder_head_size_max_x', '0')
347                 profile.putMachineSetting('extruder_head_size_max_y', '0')
348                 profile.putMachineSetting('extruder_head_size_height', '0')
349                 profile.checkAndUpdateMachineName()
350
351 class MachineSelectPage(InfoPage):
352         def __init__(self, parent):
353                 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
354                 self.AddText(_("What kind of machine do you have:"))
355
356                 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
357                 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
358                 self.LulzbotMiniRadio.SetValue(True)
359                 self.LulzbotTazRadio = self.AddRadioButton("LulzBot TAZ")
360                 self.LulzbotTazRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
361                 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
362                 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
363                 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
364                 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
365                 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
366                 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
367                 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
368                 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
369                 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
370                 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
371
372         def OnUltimaker2Select(self, e):
373                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
374
375         def OnUltimakerSelect(self, e):
376                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
377
378         def OnUltimakerOPSelect(self, e):
379                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
380
381         def OnPrintrbotSelect(self, e):
382                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
383
384         def OnLulzbotSelect(self, e):
385                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
386
387         def OnOtherSelect(self, e):
388                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
389
390         def AllowNext(self):
391                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
392                 return True
393
394         def StoreData(self):
395                 profile.putProfileSetting('retraction_enable', 'True')
396                 if self.Ultimaker2Radio.GetValue():
397                         profile.putMachineSetting('machine_width', '230')
398                         profile.putMachineSetting('machine_depth', '225')
399                         profile.putMachineSetting('machine_height', '205')
400                         profile.putMachineSetting('machine_name', 'ultimaker2')
401                         profile.putMachineSetting('machine_type', 'ultimaker2')
402                         profile.putMachineSetting('machine_center_is_zero', 'False')
403                         profile.putMachineSetting('has_heated_bed', 'True')
404                         profile.putMachineSetting('gcode_flavor', 'UltiGCode')
405                         profile.putMachineSetting('extruder_head_size_min_x', '40.0')
406                         profile.putMachineSetting('extruder_head_size_min_y', '10.0')
407                         profile.putMachineSetting('extruder_head_size_max_x', '60.0')
408                         profile.putMachineSetting('extruder_head_size_max_y', '30.0')
409                         profile.putMachineSetting('extruder_head_size_height', '48.0')
410                         profile.putProfileSetting('nozzle_size', '0.4')
411                         profile.putProfileSetting('fan_full_height', '5.0')
412                         profile.putMachineSetting('extruder_offset_x1', '18.0')
413                         profile.putMachineSetting('extruder_offset_y1', '0.0')
414                 elif self.UltimakerRadio.GetValue():
415                         profile.putMachineSetting('machine_width', '205')
416                         profile.putMachineSetting('machine_depth', '205')
417                         profile.putMachineSetting('machine_height', '200')
418                         profile.putMachineSetting('machine_name', 'ultimaker original')
419                         profile.putMachineSetting('machine_type', 'ultimaker')
420                         profile.putMachineSetting('machine_center_is_zero', 'False')
421                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
422                         profile.putProfileSetting('nozzle_size', '0.4')
423                         profile.putMachineSetting('extruder_head_size_min_x', '75.0')
424                         profile.putMachineSetting('extruder_head_size_min_y', '18.0')
425                         profile.putMachineSetting('extruder_head_size_max_x', '18.0')
426                         profile.putMachineSetting('extruder_head_size_max_y', '35.0')
427                         profile.putMachineSetting('extruder_head_size_height', '55.0')
428                 elif self.UltimakerOPRadio.GetValue():
429                         profile.putMachineSetting('machine_width', '205')
430                         profile.putMachineSetting('machine_depth', '205')
431                         profile.putMachineSetting('machine_height', '200')
432                         profile.putMachineSetting('machine_name', 'ultimaker original+')
433                         profile.putMachineSetting('machine_type', 'ultimaker_plus')
434                         profile.putMachineSetting('machine_center_is_zero', 'False')
435                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
436                         profile.putProfileSetting('nozzle_size', '0.4')
437                         profile.putMachineSetting('extruder_head_size_min_x', '75.0')
438                         profile.putMachineSetting('extruder_head_size_min_y', '18.0')
439                         profile.putMachineSetting('extruder_head_size_max_x', '18.0')
440                         profile.putMachineSetting('extruder_head_size_max_y', '35.0')
441                         profile.putMachineSetting('extruder_head_size_height', '55.0')
442                         profile.putMachineSetting('has_heated_bed', 'True')
443                         profile.putMachineSetting('extruder_amount', '1')
444                         profile.putProfileSetting('retraction_enable', 'True')
445                 elif self.LulzbotTazRadio.GetValue() or self.LulzbotMiniRadio.GetValue():
446                         if self.LulzbotTazRadio.GetValue():
447                                 profile.putMachineSetting('machine_width', '298')
448                                 profile.putMachineSetting('machine_depth', '275')
449                                 profile.putMachineSetting('machine_height', '250')
450                                 profile.putProfileSetting('nozzle_size', '0.35')
451                                 profile.putMachineSetting('machine_name', 'LulzBot TAZ')
452                                 profile.putMachineSetting('machine_type', 'lulzbot_TAZ')
453                                 profile.putMachineSetting('serial_baud', '115200')
454                         else:
455                                 profile.putMachineSetting('machine_width', '155')
456                                 profile.putMachineSetting('machine_depth', '155')
457                                 profile.putMachineSetting('machine_height', '163')
458                                 profile.putProfileSetting('nozzle_size', '0.5')
459                                 profile.putMachineSetting('machine_name', 'LulzBot Mini')
460                                 profile.putMachineSetting('machine_type', 'lulzbot_mini')
461                                 profile.putMachineSetting('serial_baud', '115200')
462                         profile.putMachineSetting('machine_center_is_zero', 'False')
463                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
464                         profile.putMachineSetting('has_heated_bed', 'True')
465                         profile.putMachineSetting('extruder_head_size_min_x', '0.0')
466                         profile.putMachineSetting('extruder_head_size_min_y', '0.0')
467                         profile.putMachineSetting('extruder_head_size_max_x', '0.0')
468                         profile.putMachineSetting('extruder_head_size_max_y', '0.0')
469                         profile.putMachineSetting('extruder_head_size_height', '0.0')
470                 else:
471                         profile.putMachineSetting('machine_width', '80')
472                         profile.putMachineSetting('machine_depth', '80')
473                         profile.putMachineSetting('machine_height', '60')
474                         profile.putMachineSetting('machine_name', 'reprap')
475                         profile.putMachineSetting('machine_type', 'reprap')
476                         profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
477                         profile.putPreference('startMode', 'Normal')
478                         profile.putProfileSetting('nozzle_size', '0.5')
479                 profile.checkAndUpdateMachineName()
480                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
481
482 class SelectParts(InfoPage):
483         def __init__(self, parent):
484                 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
485                 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."))
486                 self.AddSeperator()
487                 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
488                 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
489                 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
490                 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
491                 self.AddSeperator()
492                 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."))
493                 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
494                 self.springExtruder.SetValue(True)
495
496         def StoreData(self):
497                 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
498                 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
499                         profile.putMachineSetting('has_heated_bed', 'True')
500                 else:
501                         profile.putMachineSetting('has_heated_bed', 'False')
502                 if self.dualExtrusion.GetValue():
503                         profile.putMachineSetting('extruder_amount', '2')
504                         profile.putMachineSetting('machine_depth', '195')
505                 else:
506                         profile.putMachineSetting('extruder_amount', '1')
507                 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
508                         profile.putProfileSetting('retraction_enable', 'True')
509                 else:
510                         profile.putProfileSetting('retraction_enable', 'False')
511
512
513 class UltimakerFirmwareUpgradePage(InfoPage):
514         def __init__(self, parent):
515                 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
516                 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."))
517                 self.AddHiddenSeperator()
518                 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
519                 self.AddHiddenSeperator()
520                 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."))
521                 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
522                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
523                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
524                 self.AddHiddenSeperator()
525                 if profile.getMachineSetting('machine_type') == 'ultimaker':
526                         self.AddText(_("Do not upgrade to this firmware if:"))
527                         self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
528                         self.AddText(_("* Build your own heated bed"))
529                         self.AddText(_("* Have other changes in the firmware"))
530 #               button = self.AddButton('Goto this page for a custom firmware')
531 #               button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
532
533         def AllowNext(self):
534                 return False
535
536         def OnUpgradeClick(self, e):
537                 if firmwareInstall.InstallFirmware():
538                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
539
540         def OnSkipClick(self, e):
541                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
542                 self.GetParent().ShowPage(self.GetNext())
543
544         def OnUrlClick(self, e):
545                 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
546
547 class UltimakerCheckupPage(InfoPage):
548         def __init__(self, parent):
549                 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
550
551                 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
552                 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
553                 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
554                 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
555                 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
556                 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
557                 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
558                 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
559                 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
560                 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
561
562                 self.AddText(
563                         _("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."))
564                 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
565                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
566                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
567                 self.AddSeperator()
568                 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
569                 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
570                 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
571                 self.AddSeperator()
572                 self.infoBox = self.AddInfoBox()
573                 self.machineState = self.AddText("")
574                 self.temperatureLabel = self.AddText("")
575                 self.errorLogButton = self.AddButton(_("Show error log"))
576                 self.errorLogButton.Show(False)
577                 self.AddSeperator()
578                 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
579                 self.comm = None
580                 self.xMinStop = False
581                 self.xMaxStop = False
582                 self.yMinStop = False
583                 self.yMaxStop = False
584                 self.zMinStop = False
585                 self.zMaxStop = False
586
587                 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
588
589         def __del__(self):
590                 if self.comm is not None:
591                         self.comm.close()
592
593         def AllowNext(self):
594                 self.endstopBitmap.Show(False)
595                 return False
596
597         def OnSkipClick(self, e):
598                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
599                 self.GetParent().ShowPage(self.GetNext())
600
601         def OnCheckClick(self, e=None):
602                 self.errorLogButton.Show(False)
603                 if self.comm is not None:
604                         self.comm.close()
605                         del self.comm
606                         self.comm = None
607                         wx.CallAfter(self.OnCheckClick)
608                         return
609                 self.infoBox.SetBusy(_("Connecting to machine."))
610                 self.commState.SetBitmap(self.unknownBitmap)
611                 self.tempState.SetBitmap(self.unknownBitmap)
612                 self.stopState.SetBitmap(self.unknownBitmap)
613                 self.checkupState = 0
614                 self.checkExtruderNr = 0
615                 self.comm = machineCom.MachineCom(callbackObject=self)
616
617         def OnErrorLog(self, e):
618                 printWindow.LogWindow('\n'.join(self.comm.getLog()))
619
620         def mcLog(self, message):
621                 pass
622
623         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
624                 if not self.comm.isOperational():
625                         return
626                 if self.checkupState == 0:
627                         self.tempCheckTimeout = 20
628                         if temp[self.checkExtruderNr] > 70:
629                                 self.checkupState = 1
630                                 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
631                                 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
632                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
633                         else:
634                                 self.startTemp = temp[self.checkExtruderNr]
635                                 self.checkupState = 2
636                                 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
637                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
638                                 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
639                 elif self.checkupState == 1:
640                         if temp[self.checkExtruderNr] < 60:
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 == 2:
647                         #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
648                         if temp[self.checkExtruderNr] > self.startTemp + 40:
649                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
650                                 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
651                                 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
652                                         self.checkExtruderNr = 0
653                                         self.checkupState = 3
654                                         wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
655                                         wx.CallAfter(self.endstopBitmap.Show, True)
656                                         wx.CallAfter(self.Layout)
657                                         self.comm.sendCommand('M119')
658                                         wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
659                                 else:
660                                         self.checkupState = 0
661                                         self.checkExtruderNr += 1
662                         else:
663                                 self.tempCheckTimeout -= 1
664                                 if self.tempCheckTimeout < 1:
665                                         self.checkupState = -1
666                                         wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
667                                         wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
668                                         self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
669                                         self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
670                 elif self.checkupState >= 3 and self.checkupState < 10:
671                         self.comm.sendCommand('M119')
672                 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
673
674         def mcStateChange(self, state):
675                 if self.comm is None:
676                         return
677                 if self.comm.isOperational():
678                         wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
679                         wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
680                 elif self.comm.isError():
681                         wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
682                         wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
683                         wx.CallAfter(self.endstopBitmap.Show, False)
684                         wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
685                         wx.CallAfter(self.errorLogButton.Show, True)
686                         wx.CallAfter(self.Layout)
687                 else:
688                         wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
689
690         def mcMessage(self, message):
691                 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
692                         for data in message.split(' '):
693                                 if ':' in data:
694                                         tag, value = data.split(':', 1)
695                                         if tag == 'x_min':
696                                                 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
697                                         if tag == 'x_max':
698                                                 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
699                                         if tag == 'y_min':
700                                                 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
701                                         if tag == 'y_max':
702                                                 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
703                                         if tag == 'z_min':
704                                                 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
705                                         if tag == 'z_max':
706                                                 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
707                         if ':' in message:
708                                 tag, value = map(str.strip, message.split(':', 1))
709                                 if tag == 'x_min':
710                                         self.xMinStop = (value == 'H' or value == 'TRIGGERED')
711                                 if tag == 'x_max':
712                                         self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
713                                 if tag == 'y_min':
714                                         self.yMinStop = (value == 'H' or value == 'TRIGGERED')
715                                 if tag == 'y_max':
716                                         self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
717                                 if tag == 'z_min':
718                                         self.zMinStop = (value == 'H' or value == 'TRIGGERED')
719                                 if tag == 'z_max':
720                                         self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
721                         if 'z_max' in message:
722                                 self.comm.sendCommand('M119')
723
724                         if self.checkupState == 3:
725                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
726                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
727                                                 self.checkupState = 5
728                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
729                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
730                                         else:
731                                                 self.checkupState = 4
732                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
733                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
734                         elif self.checkupState == 4:
735                                 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
736                                         self.checkupState = 5
737                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
738                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
739                         elif self.checkupState == 5:
740                                 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
741                                         self.checkupState = 6
742                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
743                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
744                         elif self.checkupState == 6:
745                                 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
746                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
747                                                 self.checkupState = 8
748                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
749                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
750                                         else:
751                                                 self.checkupState = 7
752                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
753                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
754                         elif self.checkupState == 7:
755                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
756                                         self.checkupState = 8
757                                         wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
758                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
759                         elif self.checkupState == 8:
760                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
761                                         if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
762                                                 self.checkupState = 10
763                                                 self.comm.close()
764                                                 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
765                                                 wx.CallAfter(self.infoBox.SetReadyIndicator)
766                                                 wx.CallAfter(self.endstopBitmap.Show, False)
767                                                 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
768                                                 wx.CallAfter(self.OnSkipClick, None)
769                                         else:
770                                                 self.checkupState = 9
771                                                 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
772                                                 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
773                         elif self.checkupState == 9:
774                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
775                                         self.checkupState = 10
776                                         self.comm.close()
777                                         wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
778                                         wx.CallAfter(self.infoBox.SetReadyIndicator)
779                                         wx.CallAfter(self.endstopBitmap.Show, False)
780                                         wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
781                                         wx.CallAfter(self.OnSkipClick, None)
782
783         def mcProgress(self, lineNr):
784                 pass
785
786         def mcZChange(self, newZ):
787                 pass
788
789
790 class UltimakerCalibrationPage(InfoPage):
791         def __init__(self, parent):
792                 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
793
794                 self.AddText("Your Ultimaker requires some calibration.")
795                 self.AddText("This calibration is needed for a proper extrusion amount.")
796                 self.AddSeperator()
797                 self.AddText("The following values are needed:")
798                 self.AddText("* Diameter of filament")
799                 self.AddText("* Number of steps per mm of filament extrusion")
800                 self.AddSeperator()
801                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
802                 self.AddSeperator()
803                 self.AddText("First we need the diameter of your filament:")
804                 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
805                 self.AddText(
806                         "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.")
807                 self.AddText("Note: This value can be changed later at any time.")
808
809         def StoreData(self):
810                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
811
812
813 class UltimakerCalibrateStepsPerEPage(InfoPage):
814         def __init__(self, parent):
815                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
816
817                 #if profile.getMachineSetting('steps_per_e') == '0':
818                 #       profile.putMachineSetting('steps_per_e', '865.888')
819
820                 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
821                 self.AddText(_("First remove any filament from your machine."))
822                 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
823                 self.AddText(_("We'll push the filament 100mm"))
824                 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
825                 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
826                 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
827                 self.AddText(_("This results in the following steps per E:"))
828                 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
829                 self.AddText(_("You can repeat these steps to get better calibration."))
830                 self.AddSeperator()
831                 self.AddText(
832                         _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
833                 self.heatButton = self.AddButton(_("Heatup for filament removal"))
834
835                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
836                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
837                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
838
839         def OnSaveLengthClick(self, e):
840                 currentEValue = float(self.stepsPerEInput.GetValue())
841                 realExtrudeLength = float(self.lengthInput.GetValue())
842                 newEValue = currentEValue * 100 / realExtrudeLength
843                 self.stepsPerEInput.SetValue(str(newEValue))
844                 self.lengthInput.SetValue("100")
845
846         def OnExtrudeClick(self, e):
847                 t = threading.Thread(target=self.OnExtrudeRun)
848                 t.daemon = True
849                 t.start()
850
851         def OnExtrudeRun(self):
852                 self.heatButton.Enable(False)
853                 self.extrudeButton.Enable(False)
854                 currentEValue = float(self.stepsPerEInput.GetValue())
855                 self.comm = machineCom.MachineCom()
856                 if not self.comm.isOpen():
857                         wx.MessageBox(
858                                 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
859                                 'Printer error', wx.OK | wx.ICON_INFORMATION)
860                         self.heatButton.Enable(True)
861                         self.extrudeButton.Enable(True)
862                         return
863                 while True:
864                         line = self.comm.readline()
865                         if line == '':
866                                 return
867                         if 'start' in line:
868                                 break
869                         #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
870                 time.sleep(3)
871
872                 self.sendGCommand('M302') #Disable cold extrusion protection
873                 self.sendGCommand("M92 E%f" % (currentEValue))
874                 self.sendGCommand("G92 E0")
875                 self.sendGCommand("G1 E100 F600")
876                 time.sleep(15)
877                 self.comm.close()
878                 self.extrudeButton.Enable()
879                 self.heatButton.Enable()
880
881         def OnHeatClick(self, e):
882                 t = threading.Thread(target=self.OnHeatRun)
883                 t.daemon = True
884                 t.start()
885
886         def OnHeatRun(self):
887                 self.heatButton.Enable(False)
888                 self.extrudeButton.Enable(False)
889                 self.comm = machineCom.MachineCom()
890                 if not self.comm.isOpen():
891                         wx.MessageBox(
892                                 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
893                                 'Printer error', wx.OK | wx.ICON_INFORMATION)
894                         self.heatButton.Enable(True)
895                         self.extrudeButton.Enable(True)
896                         return
897                 while True:
898                         line = self.comm.readline()
899                         if line == '':
900                                 self.heatButton.Enable(True)
901                                 self.extrudeButton.Enable(True)
902                                 return
903                         if 'start' in line:
904                                 break
905                         #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
906                 time.sleep(3)
907
908                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
909                 wx.MessageBox(
910                         'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
911                         'Machine heatup', wx.OK | wx.ICON_INFORMATION)
912                 self.sendGCommand('M104 S0')
913                 time.sleep(1)
914                 self.comm.close()
915                 self.heatButton.Enable(True)
916                 self.extrudeButton.Enable(True)
917
918         def sendGCommand(self, cmd):
919                 self.comm.sendCommand(cmd) #Disable cold extrusion protection
920                 while True:
921                         line = self.comm.readline()
922                         if line == '':
923                                 return
924                         if line.startswith('ok'):
925                                 break
926
927         def StoreData(self):
928                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
929
930 class Ultimaker2ReadyPage(InfoPage):
931         def __init__(self, parent):
932                 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
933                 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
934                 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
935                 self.AddSeperator()
936
937 class LulzbotReadyPage(InfoPage):
938         def __init__(self, parent):
939                 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
940                 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
941                 self.AddSeperator()
942                 self.AddText(_('For more information about using Cura with your LulzBot'))
943                 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
944                 self.AddSeperator()
945
946 class configWizard(wx.wizard.Wizard):
947         def __init__(self, addNew = False):
948                 super(configWizard, self).__init__(None, -1, _("Configuration Wizard"))
949
950                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
951                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
952
953                 self.machineSelectPage = MachineSelectPage(self)
954                 self.ultimakerSelectParts = SelectParts(self)
955                 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
956                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
957                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
958                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
959                 self.bedLevelPage = bedLevelWizardMain(self)
960                 self.headOffsetCalibration = headOffsetCalibrationPage(self)
961                 self.printrbotSelectType = PrintrbotPage(self)
962                 self.otherMachineSelectPage = OtherMachineSelectPage(self)
963                 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
964                 self.otherMachineInfoPage = OtherMachineInfoPage(self)
965
966                 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
967                 self.lulzbotReadyPage = LulzbotReadyPage(self)
968
969                 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
970                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
971                 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
972                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
973                 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
974                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
975                 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
976                 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
977
978                 self.FitToPage(self.machineSelectPage)
979                 self.GetPageAreaSizer().Add(self.machineSelectPage)
980
981                 self.RunWizard(self.machineSelectPage)
982                 self.Destroy()
983
984         def OnPageChanging(self, e):
985                 e.GetPage().StoreData()
986
987         def OnPageChanged(self, e):
988                 if e.GetPage().AllowNext():
989                         self.FindWindowById(wx.ID_FORWARD).Enable()
990                 else:
991                         self.FindWindowById(wx.ID_FORWARD).Disable()
992                 if e.GetPage().AllowBack():
993                         self.FindWindowById(wx.ID_BACKWARD).Enable()
994                 else:
995                         self.FindWindowById(wx.ID_BACKWARD).Disable()
996
997 class bedLevelWizardMain(InfoPage):
998         def __init__(self, parent):
999                 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1000
1001                 self.AddText(_('This wizard will help you in leveling your printer bed'))
1002                 self.AddSeperator()
1003                 self.AddText(_('It will do the following steps'))
1004                 self.AddText(_('* Move the printer head to each corner'))
1005                 self.AddText(_('  and let you adjust the height of the bed to the nozzle'))
1006                 self.AddText(_('* Print a line around the bed to check if it is level'))
1007                 self.AddSeperator()
1008
1009                 self.connectButton = self.AddButton(_('Connect to printer'))
1010                 self.comm = None
1011
1012                 self.infoBox = self.AddInfoBox()
1013                 self.resumeButton = self.AddButton(_('Resume'))
1014                 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1015                 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1016                 self.resumeButton.Enable(False)
1017
1018                 self.upButton.Enable(False)
1019                 self.downButton.Enable(False)
1020                 self.upButton2.Enable(False)
1021                 self.downButton2.Enable(False)
1022
1023                 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1024                 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1025                 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1026                 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1027                 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1028                 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1029
1030         def OnConnect(self, e = None):
1031                 if self.comm is not None:
1032                         self.comm.close()
1033                         del self.comm
1034                         self.comm = None
1035                         wx.CallAfter(self.OnConnect)
1036                         return
1037                 self.connectButton.Enable(False)
1038                 self.comm = machineCom.MachineCom(callbackObject=self)
1039                 self.infoBox.SetBusy(_('Connecting to machine.'))
1040                 self._wizardState = 0
1041
1042         def OnBedUp(self, e):
1043                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1044                 self.comm.sendCommand('G92 Z10')
1045                 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1046                 self.comm.sendCommand('M400')
1047
1048         def OnBedDown(self, e):
1049                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1050                 self.comm.sendCommand('G92 Z10')
1051                 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1052                 self.comm.sendCommand('M400')
1053
1054         def OnBedUp2(self, e):
1055                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1056                 self.comm.sendCommand('G92 Z10')
1057                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1058                 self.comm.sendCommand('M400')
1059
1060         def OnBedDown2(self, e):
1061                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1062                 self.comm.sendCommand('G92 Z10')
1063                 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1064                 self.comm.sendCommand('M400')
1065
1066         def AllowNext(self):
1067                 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1068                         wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1069                 return True
1070
1071         def OnResume(self, e):
1072                 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1073                 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1074                 if self._wizardState == -1:
1075                         wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1076                         wx.CallAfter(self.upButton.Enable, False)
1077                         wx.CallAfter(self.downButton.Enable, False)
1078                         wx.CallAfter(self.upButton2.Enable, False)
1079                         wx.CallAfter(self.downButton2.Enable, False)
1080                         self.comm.sendCommand('M105')
1081                         self.comm.sendCommand('G28')
1082                         self._wizardState = 1
1083                 elif self._wizardState == 2:
1084                         if profile.getMachineSetting('has_heated_bed') == 'True':
1085                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1086                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1087                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1088                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1089                                 self.comm.sendCommand('M400')
1090                                 self._wizardState = 3
1091                         else:
1092                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1093                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1094                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1095                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1096                                 self.comm.sendCommand('M400')
1097                                 self._wizardState = 3
1098                 elif self._wizardState == 4:
1099                         if profile.getMachineSetting('has_heated_bed') == 'True':
1100                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1101                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1102                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1103                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1104                                 self.comm.sendCommand('M400')
1105                                 self._wizardState = 7
1106                         else:
1107                                 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1108                                 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1109                                 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1110                                 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1111                                 self.comm.sendCommand('M400')
1112                                 self._wizardState = 5
1113                 elif self._wizardState == 6:
1114                         wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1115                         self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1116                         self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1117                         self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1118                         self.comm.sendCommand('M400')
1119                         self._wizardState = 7
1120                 elif self._wizardState == 8:
1121                         wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1122                         self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1123                         self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1124                         self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1125                         self._wizardState = 9
1126                 elif self._wizardState == 10:
1127                         self._wizardState = 11
1128                         wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1129                         feedZ = profile.getProfileSettingFloat('print_speed') * 60
1130                         feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1131                         feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1132                         w = profile.getMachineSettingFloat('machine_width') - 10
1133                         d = profile.getMachineSettingFloat('machine_depth')
1134                         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1135                         filamentArea = math.pi * filamentRadius * filamentRadius
1136                         ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1137                         eValue = 0.0
1138
1139                         gcodeList = [
1140                                 'G1 Z2 F%d' % (feedZ),
1141                                 'G92 E0',
1142                                 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1143                                 'G1 Z0.3 F%d' % (feedZ)]
1144                         eValue += 5.0
1145                         gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1146
1147                         for i in xrange(0, 3):
1148                                 dist = 5.0 + 0.4 * float(i)
1149                                 eValue += (d - 2.0*dist) * ePerMM
1150                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1151                                 eValue += (w - 2.0*dist) * ePerMM
1152                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1153                                 eValue += (d - 2.0*dist) * ePerMM
1154                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1155                                 eValue += (w - 2.0*dist) * ePerMM
1156                                 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1157
1158                         gcodeList.append('M400')
1159                         self.comm.printGCode(gcodeList)
1160                 self.resumeButton.Enable(False)
1161
1162         def mcLog(self, message):
1163                 print 'Log:', message
1164
1165         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1166                 if self._wizardState == 1:
1167                         self._wizardState = 2
1168                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1169                         wx.CallAfter(self.resumeButton.Enable, True)
1170                 elif self._wizardState == 3:
1171                         self._wizardState = 4
1172                         if profile.getMachineSetting('has_heated_bed') == 'True':
1173                                 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1174                         else:
1175                                 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1176                         wx.CallAfter(self.resumeButton.Enable, True)
1177                 elif self._wizardState == 5:
1178                         self._wizardState = 6
1179                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1180                         wx.CallAfter(self.resumeButton.Enable, True)
1181                 elif self._wizardState == 7:
1182                         self._wizardState = 8
1183                         wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1184                         wx.CallAfter(self.resumeButton.Enable, True)
1185                 elif self._wizardState == 9:
1186                         if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1187                                 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1188                         else:
1189                                 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1190                                 wx.CallAfter(self.resumeButton.Enable, True)
1191                                 self._wizardState = 10
1192
1193         def mcStateChange(self, state):
1194                 if self.comm is None:
1195                         return
1196                 if self.comm.isOperational():
1197                         if self._wizardState == 0:
1198                                 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1199                                 wx.CallAfter(self.upButton.Enable, True)
1200                                 wx.CallAfter(self.downButton.Enable, True)
1201                                 wx.CallAfter(self.upButton2.Enable, True)
1202                                 wx.CallAfter(self.downButton2.Enable, True)
1203                                 wx.CallAfter(self.resumeButton.Enable, True)
1204                                 self._wizardState = -1
1205                         elif self._wizardState == 11 and not self.comm.isPrinting():
1206                                 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1207                                 self.comm.sendCommand('G92 E0')
1208                                 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1209                                 self.comm.sendCommand('M104 S0')
1210                                 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1211                                 wx.CallAfter(self.infoBox.SetReadyIndicator)
1212                                 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1213                                 wx.CallAfter(self.connectButton.Enable, True)
1214                                 self._wizardState = 12
1215                 elif self.comm.isError():
1216                         wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1217
1218         def mcMessage(self, message):
1219                 pass
1220
1221         def mcProgress(self, lineNr):
1222                 pass
1223
1224         def mcZChange(self, newZ):
1225                 pass
1226
1227 class headOffsetCalibrationPage(InfoPage):
1228         def __init__(self, parent):
1229                 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1230
1231                 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1232                 self.AddSeperator()
1233
1234                 self.connectButton = self.AddButton(_('Connect to printer'))
1235                 self.comm = None
1236
1237                 self.infoBox = self.AddInfoBox()
1238                 self.textEntry = self.AddTextCtrl('')
1239                 self.textEntry.Enable(False)
1240                 self.resumeButton = self.AddButton(_('Resume'))
1241                 self.resumeButton.Enable(False)
1242
1243                 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1244                 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1245
1246         def AllowBack(self):
1247                 return True
1248
1249         def OnConnect(self, e = None):
1250                 if self.comm is not None:
1251                         self.comm.close()
1252                         del self.comm
1253                         self.comm = None
1254                         wx.CallAfter(self.OnConnect)
1255                         return
1256                 self.connectButton.Enable(False)
1257                 self.comm = machineCom.MachineCom(callbackObject=self)
1258                 self.infoBox.SetBusy(_('Connecting to machine.'))
1259                 self._wizardState = 0
1260
1261         def OnResume(self, e):
1262                 if self._wizardState == 2:
1263                         self._wizardState = 3
1264                         wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1265
1266                         w = profile.getMachineSettingFloat('machine_width')
1267                         d = profile.getMachineSettingFloat('machine_depth')
1268
1269                         gcode = gcodeGenerator.gcodeGenerator()
1270                         gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1271                         gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1272                         gcode.addCmd('T0')
1273                         gcode.addPrime(15)
1274                         gcode.addCmd('T1')
1275                         gcode.addPrime(15)
1276
1277                         gcode.addCmd('T0')
1278                         gcode.addMove(w/2, 5)
1279                         gcode.addMove(z=0.2)
1280                         gcode.addPrime()
1281                         gcode.addExtrude(w/2, d-5.0)
1282                         gcode.addRetract()
1283                         gcode.addMove(5, d/2)
1284                         gcode.addPrime()
1285                         gcode.addExtrude(w-5.0, d/2)
1286                         gcode.addRetract(15)
1287
1288                         gcode.addCmd('T1')
1289                         gcode.addMove(w/2, 5)
1290                         gcode.addPrime()
1291                         gcode.addExtrude(w/2, d-5.0)
1292                         gcode.addRetract()
1293                         gcode.addMove(5, d/2)
1294                         gcode.addPrime()
1295                         gcode.addExtrude(w-5.0, d/2)
1296                         gcode.addRetract(15)
1297                         gcode.addCmd('T0')
1298
1299                         gcode.addMove(z=25)
1300                         gcode.addMove(0, 0)
1301                         gcode.addCmd('M400')
1302
1303                         self.comm.printGCode(gcode.list())
1304                         self.resumeButton.Enable(False)
1305                 elif self._wizardState == 4:
1306                         try:
1307                                 float(self.textEntry.GetValue())
1308                         except ValueError:
1309                                 return
1310                         profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1311                         self._wizardState = 5
1312                         self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1313                         self.textEntry.SetValue('0.0')
1314                         self.textEntry.Enable(True)
1315                 elif self._wizardState == 5:
1316                         try:
1317                                 float(self.textEntry.GetValue())
1318                         except ValueError:
1319                                 return
1320                         profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1321                         self._wizardState = 6
1322                         self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1323                         self.textEntry.SetValue('')
1324                         self.textEntry.Enable(False)
1325                         self.resumeButton.Enable(False)
1326
1327                         x = profile.getMachineSettingFloat('extruder_offset_x1')
1328                         y = profile.getMachineSettingFloat('extruder_offset_y1')
1329                         gcode = gcodeGenerator.gcodeGenerator()
1330                         gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1331                         gcode.setPrintSpeed(25)
1332                         gcode.addHome()
1333                         gcode.addCmd('T0')
1334                         gcode.addMove(50, 40, 0.2)
1335                         gcode.addPrime(15)
1336                         for n in xrange(0, 10):
1337                                 gcode.addExtrude(50 + n * 10, 150)
1338                                 gcode.addExtrude(50 + n * 10 + 5, 150)
1339                                 gcode.addExtrude(50 + n * 10 + 5, 40)
1340                                 gcode.addExtrude(50 + n * 10 + 10, 40)
1341                         gcode.addMove(40, 50)
1342                         for n in xrange(0, 10):
1343                                 gcode.addExtrude(150, 50 + n * 10)
1344                                 gcode.addExtrude(150, 50 + n * 10 + 5)
1345                                 gcode.addExtrude(40, 50 + n * 10 + 5)
1346                                 gcode.addExtrude(40, 50 + n * 10 + 10)
1347                         gcode.addRetract(15)
1348
1349                         gcode.addCmd('T1')
1350                         gcode.addMove(50 - x, 30 - y, 0.2)
1351                         gcode.addPrime(15)
1352                         for n in xrange(0, 10):
1353                                 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1354                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1355                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1356                                 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1357                         gcode.addMove(30 - x, 50 - y, 0.2)
1358                         for n in xrange(0, 10):
1359                                 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1360                                 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1361                                 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1362                                 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1363                         gcode.addRetract(15)
1364                         gcode.addMove(z=15)
1365                         gcode.addCmd('M400')
1366                         gcode.addCmd('M104 T0 S0')
1367                         gcode.addCmd('M104 T1 S0')
1368                         self.comm.printGCode(gcode.list())
1369                 elif self._wizardState == 7:
1370                         try:
1371                                 n = int(self.textEntry.GetValue()) - 1
1372                         except:
1373                                 return
1374                         x = profile.getMachineSettingFloat('extruder_offset_x1')
1375                         x += -1.0 + n * 0.1
1376                         profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1377                         self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1378                         self.textEntry.SetValue('10')
1379                         self._wizardState = 8
1380                 elif self._wizardState == 8:
1381                         try:
1382                                 n = int(self.textEntry.GetValue()) - 1
1383                         except:
1384                                 return
1385                         y = profile.getMachineSettingFloat('extruder_offset_y1')
1386                         y += -1.0 + n * 0.1
1387                         profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1388                         self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1389                         self.infoBox.SetReadyIndicator()
1390                         self._wizardState = 8
1391                         self.comm.close()
1392                         self.resumeButton.Enable(False)
1393
1394         def mcLog(self, message):
1395                 print 'Log:', message
1396
1397         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1398                 if self._wizardState == 1:
1399                         if temp[0] >= 210 and temp[1] >= 210:
1400                                 self._wizardState = 2
1401                                 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1402                                 wx.CallAfter(self.resumeButton.Enable, True)
1403                                 wx.CallAfter(self.resumeButton.SetFocus)
1404
1405         def mcStateChange(self, state):
1406                 if self.comm is None:
1407                         return
1408                 if self.comm.isOperational():
1409                         if self._wizardState == 0:
1410                                 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1411                                 self.comm.sendCommand('M105')
1412                                 self.comm.sendCommand('M104 S220 T0')
1413                                 self.comm.sendCommand('M104 S220 T1')
1414                                 self.comm.sendCommand('G28')
1415                                 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1416                                 self._wizardState = 1
1417                         if not self.comm.isPrinting():
1418                                 if self._wizardState == 3:
1419                                         self._wizardState = 4
1420                                         wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1421                                         wx.CallAfter(self.textEntry.SetValue, '0.0')
1422                                         wx.CallAfter(self.textEntry.Enable, True)
1423                                         wx.CallAfter(self.resumeButton.Enable, True)
1424                                         wx.CallAfter(self.resumeButton.SetFocus)
1425                                 elif self._wizardState == 6:
1426                                         self._wizardState = 7
1427                                         wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1428                                         wx.CallAfter(self.textEntry.SetValue, '10')
1429                                         wx.CallAfter(self.textEntry.Enable, True)
1430                                         wx.CallAfter(self.resumeButton.Enable, True)
1431                                         wx.CallAfter(self.resumeButton.SetFocus)
1432
1433                 elif self.comm.isError():
1434                         wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1435
1436         def mcMessage(self, message):
1437                 pass
1438
1439         def mcProgress(self, lineNr):
1440                 pass
1441
1442         def mcZChange(self, newZ):
1443                 pass
1444
1445 class bedLevelWizard(wx.wizard.Wizard):
1446         def __init__(self):
1447                 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1448
1449                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1450                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1451
1452                 self.mainPage = bedLevelWizardMain(self)
1453                 self.headOffsetCalibration = None
1454
1455                 self.FitToPage(self.mainPage)
1456                 self.GetPageAreaSizer().Add(self.mainPage)
1457
1458                 self.RunWizard(self.mainPage)
1459                 self.Destroy()
1460
1461         def OnPageChanging(self, e):
1462                 e.GetPage().StoreData()
1463
1464         def OnPageChanged(self, e):
1465                 if e.GetPage().AllowNext():
1466                         self.FindWindowById(wx.ID_FORWARD).Enable()
1467                 else:
1468                         self.FindWindowById(wx.ID_FORWARD).Disable()
1469                 if e.GetPage().AllowBack():
1470                         self.FindWindowById(wx.ID_BACKWARD).Enable()
1471                 else:
1472                         self.FindWindowById(wx.ID_BACKWARD).Disable()
1473
1474 class headOffsetWizard(wx.wizard.Wizard):
1475         def __init__(self):
1476                 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1477
1478                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1479                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1480
1481                 self.mainPage = headOffsetCalibrationPage(self)
1482
1483                 self.FitToPage(self.mainPage)
1484                 self.GetPageAreaSizer().Add(self.mainPage)
1485
1486                 self.RunWizard(self.mainPage)
1487                 self.Destroy()
1488
1489         def OnPageChanging(self, e):
1490                 e.GetPage().StoreData()
1491
1492         def OnPageChanged(self, e):
1493                 if e.GetPage().AllowNext():
1494                         self.FindWindowById(wx.ID_FORWARD).Enable()
1495                 else:
1496                         self.FindWindowById(wx.ID_FORWARD).Disable()
1497                 if e.GetPage().AllowBack():
1498                         self.FindWindowById(wx.ID_BACKWARD).Enable()
1499                 else:
1500                         self.FindWindowById(wx.ID_BACKWARD).Disable()