1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
9 from Cura.gui import configBase
10 from Cura.gui import expertConfig
11 from Cura.gui import alterationPanel
12 from Cura.gui import pluginPanel
13 from Cura.gui import preferencesDialog
14 from Cura.gui import configWizard
15 from Cura.gui import firmwareInstall
16 from Cura.gui import simpleMode
17 from Cura.gui import sceneView
18 from Cura.gui import aboutWindow
19 from Cura.gui.util import dropTarget
20 #from Cura.gui.tools import batchRun
21 from Cura.gui.tools import pidDebugger
22 from Cura.gui.tools import minecraftImport
23 from Cura.util import profile
24 from Cura.util import version
26 from Cura.util import meshLoader
28 class mainWindow(wx.Frame):
30 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
32 wx.EVT_CLOSE(self, self.OnClose)
34 # allow dropping any file, restrict later
35 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles))
37 # TODO: wxWidgets 2.9.4 has a bug when NSView does not register for dragged types when wx drop target is set. It was fixed in 2.9.5
38 if sys.platform.startswith('darwin'):
41 nswindow = objc.objc_object(c_void_p=self.MacGetTopLevelWindowRef())
42 view = nswindow.contentView()
43 view.registerForDraggedTypes_([u'NSFilenamesPboardType'])
47 self.normalModeOnlyItems = []
49 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
50 self.config = wx.FileConfig(appName="Cura",
51 localFilename=mruFile,
52 style=wx.CONFIG_USE_LOCAL_FILE)
54 self.ID_MRU_MODEL1, self.ID_MRU_MODEL2, self.ID_MRU_MODEL3, self.ID_MRU_MODEL4, self.ID_MRU_MODEL5, self.ID_MRU_MODEL6, self.ID_MRU_MODEL7, self.ID_MRU_MODEL8, self.ID_MRU_MODEL9, self.ID_MRU_MODEL10 = [wx.NewId() for line in xrange(10)]
55 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
56 self.config.SetPath("/ModelMRU")
57 self.modelFileHistory.Load(self.config)
59 self.ID_MRU_PROFILE1, self.ID_MRU_PROFILE2, self.ID_MRU_PROFILE3, self.ID_MRU_PROFILE4, self.ID_MRU_PROFILE5, self.ID_MRU_PROFILE6, self.ID_MRU_PROFILE7, self.ID_MRU_PROFILE8, self.ID_MRU_PROFILE9, self.ID_MRU_PROFILE10 = [wx.NewId() for line in xrange(10)]
60 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
61 self.config.SetPath("/ProfileMRU")
62 self.profileFileHistory.Load(self.config)
64 self.menubar = wx.MenuBar()
65 self.fileMenu = wx.Menu()
66 i = self.fileMenu.Append(-1, _("Load model file...\tCTRL+L"))
67 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
68 i = self.fileMenu.Append(-1, _("Save model...\tCTRL+S"))
69 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
70 i = self.fileMenu.Append(-1, _("Reload platform\tF5"))
71 self.Bind(wx.EVT_MENU, lambda e: self.scene.reloadScene(e), i)
72 i = self.fileMenu.Append(-1, _("Clear platform"))
73 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
75 self.fileMenu.AppendSeparator()
76 i = self.fileMenu.Append(-1, _("Print...\tCTRL+P"))
77 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnPrintButton(1), i)
78 i = self.fileMenu.Append(-1, _("Save GCode..."))
79 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
80 i = self.fileMenu.Append(-1, _("Show slice engine log..."))
81 self.Bind(wx.EVT_MENU, lambda e: self.scene._showEngineLog(), i)
83 self.fileMenu.AppendSeparator()
84 i = self.fileMenu.Append(-1, _("Open Profile..."))
85 self.normalModeOnlyItems.append(i)
86 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
87 i = self.fileMenu.Append(-1, _("Save Profile..."))
88 self.normalModeOnlyItems.append(i)
89 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
90 i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
91 self.normalModeOnlyItems.append(i)
92 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
93 self.fileMenu.AppendSeparator()
94 i = self.fileMenu.Append(-1, _("Reset Profile to default"))
95 self.normalModeOnlyItems.append(i)
96 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
98 self.fileMenu.AppendSeparator()
99 i = self.fileMenu.Append(-1, _("Preferences...\tCTRL+,"))
100 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
101 i = self.fileMenu.Append(-1, _("Machine settings..."))
102 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
103 self.fileMenu.AppendSeparator()
106 modelHistoryMenu = wx.Menu()
107 self.fileMenu.AppendMenu(wx.NewId(), '&' + _("Recent Model Files"), modelHistoryMenu)
108 self.modelFileHistory.UseMenu(modelHistoryMenu)
109 self.modelFileHistory.AddFilesToMenu()
110 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
113 profileHistoryMenu = wx.Menu()
114 self.fileMenu.AppendMenu(wx.NewId(), _("Recent Profile Files"), profileHistoryMenu)
115 self.profileFileHistory.UseMenu(profileHistoryMenu)
116 self.profileFileHistory.AddFilesToMenu()
117 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
119 self.fileMenu.AppendSeparator()
120 i = self.fileMenu.Append(wx.ID_EXIT, _("Quit"))
121 self.Bind(wx.EVT_MENU, self.OnQuit, i)
122 self.menubar.Append(self.fileMenu, '&' + _("File"))
124 toolsMenu = wx.Menu()
125 #i = toolsMenu.Append(-1, 'Batch run...')
126 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
127 #self.normalModeOnlyItems.append(i)
129 if minecraftImport.hasMinecraft():
130 i = toolsMenu.Append(-1, _("Minecraft map import..."))
131 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
133 if version.isDevVersion():
134 i = toolsMenu.Append(-1, _("PID Debugger..."))
135 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
137 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
138 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
140 toolsMenu.AppendSeparator()
141 self.allAtOnceItem = toolsMenu.Append(-1, _("Print all at once"), kind=wx.ITEM_RADIO)
142 self.Bind(wx.EVT_MENU, self.onOneAtATimeSwitch, self.allAtOnceItem)
143 self.oneAtATime = toolsMenu.Append(-1, _("Print one at a time"), kind=wx.ITEM_RADIO)
144 self.Bind(wx.EVT_MENU, self.onOneAtATimeSwitch, self.oneAtATime)
145 if profile.getPreference('oneAtATime') == 'True':
146 self.oneAtATime.Check(True)
148 self.allAtOnceItem.Check(True)
150 self.menubar.Append(toolsMenu, _("Tools"))
152 #Machine menu for machine configuration/tooling
153 self.machineMenu = wx.Menu()
154 self.updateMachineMenu()
156 self.menubar.Append(self.machineMenu, _("Machine"))
158 expertMenu = wx.Menu()
159 i = expertMenu.Append(-1, _("Switch to quickprint..."), kind=wx.ITEM_RADIO)
160 self.switchToQuickprintMenuItem = i
161 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
163 i = expertMenu.Append(-1, _("Switch to full settings..."), kind=wx.ITEM_RADIO)
164 self.switchToNormalMenuItem = i
165 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
166 expertMenu.AppendSeparator()
168 i = expertMenu.Append(-1, _("Open expert settings...\tCTRL+E"))
169 self.normalModeOnlyItems.append(i)
170 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
171 expertMenu.AppendSeparator()
172 i = expertMenu.Append(-1, _("Run first run wizard..."))
173 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
174 self.bedLevelWizardMenuItem = expertMenu.Append(-1, _("Run bed leveling wizard..."))
175 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, self.bedLevelWizardMenuItem)
176 self.headOffsetWizardMenuItem = expertMenu.Append(-1, _("Run head offset wizard..."))
177 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, self.headOffsetWizardMenuItem)
179 self.menubar.Append(expertMenu, _("Expert"))
182 i = helpMenu.Append(-1, _("Online documentation..."))
183 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
184 i = helpMenu.Append(-1, _("Report a problem..."))
185 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
186 i = helpMenu.Append(-1, _("Check for update..."))
187 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
188 i = helpMenu.Append(-1, _("Open YouMagine website..."))
189 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
190 i = helpMenu.Append(-1, _("About Cura..."))
191 self.Bind(wx.EVT_MENU, self.OnAbout, i)
192 self.menubar.Append(helpMenu, _("Help"))
193 self.SetMenuBar(self.menubar)
195 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
196 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
197 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
198 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
201 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
202 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
204 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
205 self.leftSizer.Add(self.simpleSettingsPanel, 1)
206 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
207 self.leftPane.SetSizer(self.leftSizer)
210 self.scene = sceneView.SceneView(self.rightPane)
212 #Main sizer, to position the preview window, buttons and tab control
213 sizer = wx.BoxSizer()
214 self.rightPane.SetSizer(sizer)
215 sizer.Add(self.scene, 1, flag=wx.EXPAND)
218 sizer = wx.BoxSizer(wx.VERTICAL)
220 sizer.Add(self.splitter, 1, wx.EXPAND)
224 self.updateProfileToAllControls()
226 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
228 self.simpleSettingsPanel.Show(False)
229 self.normalSettingsPanel.Show(False)
231 # Set default window size & position
232 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
235 #Timer set; used to check if profile is on the clipboard
236 self.timer = wx.Timer(self)
237 self.Bind(wx.EVT_TIMER, self.onTimer)
238 self.timer.Start(1000)
239 self.lastTriedClipboard = profile.getProfileString()
241 # Restore the window position, size & state from the preferences file
243 if profile.getPreference('window_maximized') == 'True':
246 posx = int(profile.getPreference('window_pos_x'))
247 posy = int(profile.getPreference('window_pos_y'))
248 width = int(profile.getPreference('window_width'))
249 height = int(profile.getPreference('window_height'))
250 if posx > 0 or posy > 0:
251 self.SetPosition((posx,posy))
252 if width > 0 and height > 0:
253 self.SetSize((width,height))
255 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
257 self.normalSashPos = 0
259 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
260 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
262 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
264 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
266 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
268 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
269 self.SetSize((800,600))
272 self.updateSliceMode()
273 self.scene.SetFocus()
275 def onTimer(self, e):
276 #Check if there is something in the clipboard
279 if not wx.TheClipboard.IsOpened():
280 if not wx.TheClipboard.Open():
282 do = wx.TextDataObject()
283 if wx.TheClipboard.GetData(do):
284 profileString = do.GetText()
285 wx.TheClipboard.Close()
287 startTag = "CURA_PROFILE_STRING:"
288 if startTag in profileString:
289 #print "Found correct syntax on clipboard"
290 profileString = profileString.replace("\n","").strip()
291 profileString = profileString[profileString.find(startTag)+len(startTag):]
292 if profileString != self.lastTriedClipboard:
294 self.lastTriedClipboard = profileString
295 profile.setProfileFromString(profileString)
296 self.scene.notification.message("Loaded new profile from clipboard.")
297 self.updateProfileToAllControls()
299 print "Unable to read from clipboard"
302 def updateSliceMode(self):
303 isSimple = profile.getPreference('startMode') == 'Simple'
305 self.normalSettingsPanel.Show(not isSimple)
306 self.simpleSettingsPanel.Show(isSimple)
307 self.leftPane.Layout()
309 for i in self.normalModeOnlyItems:
310 i.Enable(not isSimple)
312 self.switchToQuickprintMenuItem.Check()
314 self.switchToNormalMenuItem.Check()
316 # Set splitter sash position & size
318 # Save normal mode sash
319 self.normalSashPos = self.splitter.GetSashPosition()
321 # Change location of sash to width of quick mode pane
322 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
323 self.splitter.SetSashPosition(width, True)
326 self.splitter.SetSashSize(0)
328 self.splitter.SetSashPosition(self.normalSashPos, True)
330 self.splitter.SetSashSize(4)
331 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
332 if profile.getMachineSetting('machine_type') == 'ultimaker2':
333 self.bedLevelWizardMenuItem.Enable(False)
334 self.headOffsetWizardMenuItem.Enable(False)
335 if int(profile.getMachineSetting('extruder_amount')) < 2:
336 self.headOffsetWizardMenuItem.Enable(False)
337 self.scene.updateProfileToControls()
338 self.scene._scene.pushFree()
340 def onOneAtATimeSwitch(self, e):
341 profile.putPreference('oneAtATime', self.oneAtATime.IsChecked())
342 if self.oneAtATime.IsChecked() and profile.getMachineSettingFloat('extruder_head_size_height') < 1:
343 wx.MessageBox(_('For "One at a time" printing, you need to have entered the correct head size and gantry height in the machine settings'), _('One at a time warning'), wx.OK | wx.ICON_WARNING)
344 self.scene.updateProfileToControls()
345 self.scene._scene.pushFree()
346 self.scene.sceneUpdated()
348 def OnPreferences(self, e):
349 prefDialog = preferencesDialog.preferencesDialog(self)
353 wx.CallAfter(prefDialog.Show)
355 def OnMachineSettings(self, e):
356 prefDialog = preferencesDialog.machineSettingsDialog(self)
361 def OnDropFiles(self, files):
363 self.updateProfileToAllControls()
364 self.scene.loadFiles(files)
366 def OnModelMRU(self, e):
367 fileNum = e.GetId() - self.ID_MRU_MODEL1
368 path = self.modelFileHistory.GetHistoryFile(fileNum)
370 self.modelFileHistory.AddFileToHistory(path) # move up the list
371 self.config.SetPath("/ModelMRU")
372 self.modelFileHistory.Save(self.config)
375 profile.putPreference('lastFile', path)
377 self.scene.loadFiles(filelist)
379 def addToModelMRU(self, file):
380 self.modelFileHistory.AddFileToHistory(file)
381 self.config.SetPath("/ModelMRU")
382 self.modelFileHistory.Save(self.config)
385 def OnProfileMRU(self, e):
386 fileNum = e.GetId() - self.ID_MRU_PROFILE1
387 path = self.profileFileHistory.GetHistoryFile(fileNum)
389 self.profileFileHistory.AddFileToHistory(path) # move up the list
390 self.config.SetPath("/ProfileMRU")
391 self.profileFileHistory.Save(self.config)
394 profile.loadProfile(path)
395 self.updateProfileToAllControls()
397 def addToProfileMRU(self, file):
398 self.profileFileHistory.AddFileToHistory(file)
399 self.config.SetPath("/ProfileMRU")
400 self.profileFileHistory.Save(self.config)
403 def updateProfileToAllControls(self):
404 self.scene.updateProfileToControls()
405 self.normalSettingsPanel.updateProfileToControls()
406 self.simpleSettingsPanel.updateProfileToControls()
408 def reloadSettingPanels(self):
409 self.leftSizer.Detach(self.simpleSettingsPanel)
410 self.leftSizer.Detach(self.normalSettingsPanel)
411 self.simpleSettingsPanel.Destroy()
412 self.normalSettingsPanel.Destroy()
413 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
414 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
415 self.leftSizer.Add(self.simpleSettingsPanel, 1)
416 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
417 self.updateSliceMode()
418 self.updateProfileToAllControls()
420 def updateMachineMenu(self):
421 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
422 for item in self.machineMenu.GetMenuItems():
423 self.machineMenu.RemoveItem(item)
425 #Add a menu item for each machine configuration.
426 for n in xrange(0, profile.getMachineCount()):
427 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
428 if n == int(profile.getPreferenceFloat('active_machine')):
430 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
432 self.machineMenu.AppendSeparator()
434 i = self.machineMenu.Append(-1, _("Machine settings..."))
435 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
437 #Add tools for machines.
438 self.machineMenu.AppendSeparator()
440 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
441 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
443 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
444 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
446 def OnLoadProfile(self, e):
447 dlg=wx.FileDialog(self, _("Select profile file to load"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
448 dlg.SetWildcard("ini files (*.ini)|*.ini")
449 if dlg.ShowModal() == wx.ID_OK:
450 profileFile = dlg.GetPath()
451 profile.loadProfile(profileFile)
452 self.updateProfileToAllControls()
454 # Update the Profile MRU
455 self.addToProfileMRU(profileFile)
458 def OnLoadProfileFromGcode(self, e):
459 dlg=wx.FileDialog(self, _("Select gcode file to load profile from"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
460 dlg.SetWildcard("gcode files (*%s)|*%s;*%s" % (profile.getGCodeExtension(), profile.getGCodeExtension(), profile.getGCodeExtension()[0:2]))
461 if dlg.ShowModal() == wx.ID_OK:
462 gcodeFile = dlg.GetPath()
463 f = open(gcodeFile, 'r')
466 if line.startswith(';CURA_PROFILE_STRING:'):
467 profile.setProfileFromString(line[line.find(':')+1:].strip())
470 self.updateProfileToAllControls()
472 wx.MessageBox(_("No profile found in GCode file.\nThis feature only works with GCode files made by Cura 12.07 or newer."), _("Profile load error"), wx.OK | wx.ICON_INFORMATION)
475 def OnSaveProfile(self, e):
476 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
477 dlg.SetWildcard("ini files (*.ini)|*.ini")
478 if dlg.ShowModal() == wx.ID_OK:
479 profileFile = dlg.GetPath()
480 if platform.system() == 'Linux': #hack for linux, as for some reason the .ini is not appended.
481 profileFile += '.ini'
482 profile.saveProfile(profileFile)
485 def OnResetProfile(self, e):
486 dlg = wx.MessageDialog(self, _("This will reset all profile settings to defaults.\nUnless you have saved your current profile, all settings will be lost!\nDo you really want to reset?"), _("Profile reset"), wx.YES_NO | wx.ICON_QUESTION)
487 result = dlg.ShowModal() == wx.ID_YES
490 profile.resetProfile()
491 self.updateProfileToAllControls()
493 def OnSimpleSwitch(self, e):
494 profile.putPreference('startMode', 'Simple')
495 self.updateSliceMode()
497 def OnNormalSwitch(self, e):
498 profile.putPreference('startMode', 'Normal')
499 self.updateSliceMode()
501 def OnDefaultMarlinFirmware(self, e):
502 firmwareInstall.InstallFirmware()
504 def OnCustomFirmware(self, e):
505 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
506 wx.MessageBox(_("Warning: Installing a custom firmware does not guarantee that you machine will function correctly, and could damage your machine."), _("Firmware update"), wx.OK | wx.ICON_EXCLAMATION)
507 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
508 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
509 if dlg.ShowModal() == wx.ID_OK:
510 filename = dlg.GetPath()
511 if not(os.path.exists(filename)):
513 #For some reason my Ubuntu 10.10 crashes here.
514 firmwareInstall.InstallFirmware(filename)
516 def OnFirstRunWizard(self, e):
518 configWizard.configWizard()
520 self.reloadSettingPanels()
522 def OnSelectMachine(self, index):
523 profile.setActiveMachine(index)
524 self.reloadSettingPanels()
526 def OnBedLevelWizard(self, e):
527 configWizard.bedLevelWizard()
529 def OnHeadOffsetWizard(self, e):
530 configWizard.headOffsetWizard()
532 def OnExpertOpen(self, e):
533 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
537 def OnMinecraftImport(self, e):
538 mi = minecraftImport.minecraftImportWindow(self)
542 def OnPIDDebugger(self, e):
543 debugger = pidDebugger.debuggerWindow(self)
547 def onCopyProfileClipboard(self, e):
549 if not wx.TheClipboard.IsOpened():
550 wx.TheClipboard.Open()
551 clipData = wx.TextDataObject()
552 self.lastTriedClipboard = profile.getProfileString()
553 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
554 clipData.SetText(profileString)
555 wx.TheClipboard.SetData(clipData)
556 wx.TheClipboard.Close()
558 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
560 def OnCheckForUpdate(self, e):
561 newVersion = version.checkForNewerVersion()
562 if newVersion is not None:
563 if wx.MessageBox(_("A new version of Cura is available, would you like to download?"), _("New version available"), wx.YES_NO | wx.ICON_INFORMATION) == wx.YES:
564 webbrowser.open(newVersion)
566 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
568 def OnAbout(self, e):
569 aboutBox = aboutWindow.aboutWindow()
573 def OnClose(self, e):
574 profile.saveProfile(profile.getDefaultProfilePath(), True)
576 # Save the window position, size & state from the preferences file
577 profile.putPreference('window_maximized', self.IsMaximized())
578 if not self.IsMaximized() and not self.IsIconized():
579 (posx, posy) = self.GetPosition()
580 profile.putPreference('window_pos_x', posx)
581 profile.putPreference('window_pos_y', posy)
582 (width, height) = self.GetSize()
583 profile.putPreference('window_width', width)
584 profile.putPreference('window_height', height)
586 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
587 isSimple = profile.getPreference('startMode') == 'Simple'
589 self.normalSashPos = self.splitter.GetSashPosition()
590 profile.putPreference('window_normal_sash', self.normalSashPos)
592 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
594 self.scene.OnPaint = lambda e : e
595 self.scene._engine.cleanup()
601 class normalSettingsPanel(configBase.configPanelBase):
602 "Main user interface window"
603 def __init__(self, parent, callback = None):
604 super(normalSettingsPanel, self).__init__(parent, callback)
607 self.nb = wx.Notebook(self)
608 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
609 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
611 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
612 self._addSettingsToPanels('basic', left, right)
613 self.SizeLabelWidths(left, right)
615 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
616 self._addSettingsToPanels('advanced', left, right)
617 self.SizeLabelWidths(left, right)
620 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
621 self.nb.AddPage(self.pluginPanel, _("Plugins"))
624 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
625 self.alterationPanel = None
627 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
628 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
630 self.Bind(wx.EVT_SIZE, self.OnSize)
632 self.nb.SetSize(self.GetSize())
633 self.UpdateSize(self.printPanel)
634 self.UpdateSize(self.advancedPanel)
636 def _addSettingsToPanels(self, category, left, right):
637 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
641 for title in profile.getSubCategoriesFor(category):
642 n += 1 + len(profile.getSettingsForCategory(category, title))
645 configBase.TitleRow(p, _(title))
646 for s in profile.getSettingsForCategory(category, title):
647 configBase.SettingRow(p, s.getName())
649 def SizeLabelWidths(self, left, right):
650 leftWidth = self.getLabelColumnWidth(left)
651 rightWidth = self.getLabelColumnWidth(right)
652 maxWidth = max(leftWidth, rightWidth)
653 self.setLabelColumnWidth(left, maxWidth)
654 self.setLabelColumnWidth(right, maxWidth)
657 # Make the size of the Notebook control the same size as this control
658 self.nb.SetSize(self.GetSize())
660 # Propegate the OnSize() event (just in case)
663 # Perform out resize magic
664 self.UpdateSize(self.printPanel)
665 self.UpdateSize(self.advancedPanel)
667 def UpdateSize(self, configPanel):
668 sizer = configPanel.GetSizer()
672 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
675 # if width(col1) > (best_width(col1) + best_width(col1)):
676 # switch to horizontal
679 col1 = configPanel.leftPanel
680 colSize1 = col1.GetSize()
681 colBestSize1 = col1.GetBestSize()
682 col2 = configPanel.rightPanel
683 colSize2 = col2.GetSize()
684 colBestSize2 = col2.GetBestSize()
686 orientation = sizer.GetOrientation()
688 if orientation == wx.HORIZONTAL:
689 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
691 sizer = wx.BoxSizer(wx.VERTICAL)
692 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
693 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
694 configPanel.SetSizer(sizer)
700 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
702 sizer = wx.BoxSizer(wx.HORIZONTAL)
703 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
704 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
705 configPanel.SetSizer(sizer)
711 def updateProfileToControls(self):
712 super(normalSettingsPanel, self).updateProfileToControls()
713 if self.alterationPanel is not None:
714 self.alterationPanel.updateProfileToControls()
715 self.pluginPanel.updateProfileToControls()