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())
468 if ';{profile_string}' not in profile.getAlterationFile('end.gcode'):
469 profile.setAlterationFile('end.gcode', profile.getAlterationFile('end.gcode') + '\n;{profile_string}')
472 self.updateProfileToAllControls()
474 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)
477 def OnSaveProfile(self, e):
478 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
479 dlg.SetWildcard("ini files (*.ini)|*.ini")
480 if dlg.ShowModal() == wx.ID_OK:
481 profileFile = dlg.GetPath()
482 if not profileFile.lower().endswith('.ini'): #hack for linux, as for some reason the .ini is not appended.
483 profileFile += '.ini'
484 profile.saveProfile(profileFile)
487 def OnResetProfile(self, e):
488 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)
489 result = dlg.ShowModal() == wx.ID_YES
492 profile.resetProfile()
493 self.updateProfileToAllControls()
495 def OnSimpleSwitch(self, e):
496 profile.putPreference('startMode', 'Simple')
497 self.updateSliceMode()
499 def OnNormalSwitch(self, e):
500 profile.putPreference('startMode', 'Normal')
501 self.updateSliceMode()
503 def OnDefaultMarlinFirmware(self, e):
504 firmwareInstall.InstallFirmware()
506 def OnCustomFirmware(self, e):
507 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
508 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)
509 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
510 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
511 if dlg.ShowModal() == wx.ID_OK:
512 filename = dlg.GetPath()
514 if not(os.path.exists(filename)):
516 #For some reason my Ubuntu 10.10 crashes here.
517 firmwareInstall.InstallFirmware(filename)
519 def OnFirstRunWizard(self, e):
521 configWizard.configWizard()
523 self.reloadSettingPanels()
525 def OnSelectMachine(self, index):
526 profile.setActiveMachine(index)
527 self.reloadSettingPanels()
529 def OnBedLevelWizard(self, e):
530 configWizard.bedLevelWizard()
532 def OnHeadOffsetWizard(self, e):
533 configWizard.headOffsetWizard()
535 def OnExpertOpen(self, e):
536 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
540 def OnMinecraftImport(self, e):
541 mi = minecraftImport.minecraftImportWindow(self)
545 def OnPIDDebugger(self, e):
546 debugger = pidDebugger.debuggerWindow(self)
550 def onCopyProfileClipboard(self, e):
552 if not wx.TheClipboard.IsOpened():
553 wx.TheClipboard.Open()
554 clipData = wx.TextDataObject()
555 self.lastTriedClipboard = profile.getProfileString()
556 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
557 clipData.SetText(profileString)
558 wx.TheClipboard.SetData(clipData)
559 wx.TheClipboard.Close()
561 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
563 def OnCheckForUpdate(self, e):
564 newVersion = version.checkForNewerVersion()
565 if newVersion is not None:
566 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:
567 webbrowser.open(newVersion)
569 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
571 def OnAbout(self, e):
572 aboutBox = aboutWindow.aboutWindow()
576 def OnClose(self, e):
577 profile.saveProfile(profile.getDefaultProfilePath(), True)
579 # Save the window position, size & state from the preferences file
580 profile.putPreference('window_maximized', self.IsMaximized())
581 if not self.IsMaximized() and not self.IsIconized():
582 (posx, posy) = self.GetPosition()
583 profile.putPreference('window_pos_x', posx)
584 profile.putPreference('window_pos_y', posy)
585 (width, height) = self.GetSize()
586 profile.putPreference('window_width', width)
587 profile.putPreference('window_height', height)
589 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
590 isSimple = profile.getPreference('startMode') == 'Simple'
592 self.normalSashPos = self.splitter.GetSashPosition()
593 profile.putPreference('window_normal_sash', self.normalSashPos)
595 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
597 self.scene.OnPaint = lambda e : e
598 self.scene._engine.cleanup()
604 class normalSettingsPanel(configBase.configPanelBase):
605 "Main user interface window"
606 def __init__(self, parent, callback = None):
607 super(normalSettingsPanel, self).__init__(parent, callback)
610 self.nb = wx.Notebook(self)
611 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
612 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
614 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
615 self._addSettingsToPanels('basic', left, right)
616 self.SizeLabelWidths(left, right)
618 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
619 self._addSettingsToPanels('advanced', left, right)
620 self.SizeLabelWidths(left, right)
623 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
624 self.nb.AddPage(self.pluginPanel, _("Plugins"))
627 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
628 self.alterationPanel = None
630 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
631 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
633 self.Bind(wx.EVT_SIZE, self.OnSize)
635 self.nb.SetSize(self.GetSize())
636 self.UpdateSize(self.printPanel)
637 self.UpdateSize(self.advancedPanel)
639 def _addSettingsToPanels(self, category, left, right):
640 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
644 for title in profile.getSubCategoriesFor(category):
645 n += 1 + len(profile.getSettingsForCategory(category, title))
648 configBase.TitleRow(p, _(title))
649 for s in profile.getSettingsForCategory(category, title):
650 configBase.SettingRow(p, s.getName())
652 def SizeLabelWidths(self, left, right):
653 leftWidth = self.getLabelColumnWidth(left)
654 rightWidth = self.getLabelColumnWidth(right)
655 maxWidth = max(leftWidth, rightWidth)
656 self.setLabelColumnWidth(left, maxWidth)
657 self.setLabelColumnWidth(right, maxWidth)
660 # Make the size of the Notebook control the same size as this control
661 self.nb.SetSize(self.GetSize())
663 # Propegate the OnSize() event (just in case)
666 # Perform out resize magic
667 self.UpdateSize(self.printPanel)
668 self.UpdateSize(self.advancedPanel)
670 def UpdateSize(self, configPanel):
671 sizer = configPanel.GetSizer()
675 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
678 # if width(col1) > (best_width(col1) + best_width(col1)):
679 # switch to horizontal
682 col1 = configPanel.leftPanel
683 colSize1 = col1.GetSize()
684 colBestSize1 = col1.GetBestSize()
685 col2 = configPanel.rightPanel
686 colSize2 = col2.GetSize()
687 colBestSize2 = col2.GetBestSize()
689 orientation = sizer.GetOrientation()
691 if orientation == wx.HORIZONTAL:
692 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
694 sizer = wx.BoxSizer(wx.VERTICAL)
695 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
696 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
697 configPanel.SetSizer(sizer)
703 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
705 sizer = wx.BoxSizer(wx.HORIZONTAL)
706 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
707 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
708 configPanel.SetSizer(sizer)
714 def updateProfileToControls(self):
715 super(normalSettingsPanel, self).updateProfileToControls()
716 if self.alterationPanel is not None:
717 self.alterationPanel.updateProfileToControls()
718 self.pluginPanel.updateProfileToControls()