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
25 from Cura.util import meshLoader
27 class mainWindow(wx.Frame):
29 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
31 wx.EVT_CLOSE(self, self.OnClose)
33 # allow dropping any file, restrict later
34 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles))
36 # 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
37 if sys.platform.startswith('darwin'):
40 nswindow = objc.objc_object(c_void_p=self.MacGetTopLevelWindowRef())
41 view = nswindow.contentView()
42 view.registerForDraggedTypes_([u'NSFilenamesPboardType'])
46 self.normalModeOnlyItems = []
48 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
49 self.config = wx.FileConfig(appName="Cura",
50 localFilename=mruFile,
51 style=wx.CONFIG_USE_LOCAL_FILE)
53 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)]
54 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
55 self.config.SetPath("/ModelMRU")
56 self.modelFileHistory.Load(self.config)
58 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)]
59 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
60 self.config.SetPath("/ProfileMRU")
61 self.profileFileHistory.Load(self.config)
63 self.menubar = wx.MenuBar()
64 self.fileMenu = wx.Menu()
65 i = self.fileMenu.Append(-1, _("Load model file...\tCTRL+L"))
66 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
67 i = self.fileMenu.Append(-1, _("Save model...\tCTRL+S"))
68 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
69 i = self.fileMenu.Append(-1, _("Reload platform\tF5"))
70 self.Bind(wx.EVT_MENU, lambda e: self.scene.reloadScene(e), i)
71 i = self.fileMenu.Append(-1, _("Clear platform"))
72 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
74 self.fileMenu.AppendSeparator()
75 i = self.fileMenu.Append(-1, _("Print...\tCTRL+P"))
76 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnPrintButton(1), i)
77 i = self.fileMenu.Append(-1, _("Save GCode..."))
78 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
79 i = self.fileMenu.Append(-1, _("Show slice engine log..."))
80 self.Bind(wx.EVT_MENU, lambda e: self.scene._showEngineLog(), i)
82 self.fileMenu.AppendSeparator()
83 i = self.fileMenu.Append(-1, _("Open Profile..."))
84 self.normalModeOnlyItems.append(i)
85 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
86 i = self.fileMenu.Append(-1, _("Save Profile..."))
87 self.normalModeOnlyItems.append(i)
88 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
89 i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
90 self.normalModeOnlyItems.append(i)
91 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
92 self.fileMenu.AppendSeparator()
93 i = self.fileMenu.Append(-1, _("Reset Profile to default"))
94 self.normalModeOnlyItems.append(i)
95 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
97 self.fileMenu.AppendSeparator()
98 i = self.fileMenu.Append(-1, _("Preferences...\tCTRL+,"))
99 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
100 i = self.fileMenu.Append(-1, _("Machine settings..."))
101 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
102 self.fileMenu.AppendSeparator()
105 modelHistoryMenu = wx.Menu()
106 self.fileMenu.AppendMenu(wx.NewId(), '&' + _("Recent Model Files"), modelHistoryMenu)
107 self.modelFileHistory.UseMenu(modelHistoryMenu)
108 self.modelFileHistory.AddFilesToMenu()
109 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
112 profileHistoryMenu = wx.Menu()
113 self.fileMenu.AppendMenu(wx.NewId(), _("Recent Profile Files"), profileHistoryMenu)
114 self.profileFileHistory.UseMenu(profileHistoryMenu)
115 self.profileFileHistory.AddFilesToMenu()
116 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
118 self.fileMenu.AppendSeparator()
119 i = self.fileMenu.Append(wx.ID_EXIT, _("Quit"))
120 self.Bind(wx.EVT_MENU, self.OnQuit, i)
121 self.menubar.Append(self.fileMenu, '&' + _("File"))
123 toolsMenu = wx.Menu()
124 #i = toolsMenu.Append(-1, 'Batch run...')
125 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
126 #self.normalModeOnlyItems.append(i)
128 if minecraftImport.hasMinecraft():
129 i = toolsMenu.Append(-1, _("Minecraft map import..."))
130 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
132 if version.isDevVersion():
133 i = toolsMenu.Append(-1, _("PID Debugger..."))
134 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
136 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
137 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
139 toolsMenu.AppendSeparator()
140 self.allAtOnceItem = toolsMenu.Append(-1, _("Print all at once"), kind=wx.ITEM_RADIO)
141 self.Bind(wx.EVT_MENU, self.onOneAtATimeSwitch, self.allAtOnceItem)
142 self.oneAtATime = toolsMenu.Append(-1, _("Print one at a time"), kind=wx.ITEM_RADIO)
143 self.Bind(wx.EVT_MENU, self.onOneAtATimeSwitch, self.oneAtATime)
144 if profile.getPreference('oneAtATime') == 'True':
145 self.oneAtATime.Check(True)
147 self.allAtOnceItem.Check(True)
149 self.menubar.Append(toolsMenu, _("Tools"))
151 #Machine menu for machine configuration/tooling
152 self.machineMenu = wx.Menu()
153 self.updateMachineMenu()
155 self.menubar.Append(self.machineMenu, _("Machine"))
157 expertMenu = wx.Menu()
158 i = expertMenu.Append(-1, _("Switch to quickprint..."), kind=wx.ITEM_RADIO)
159 self.switchToQuickprintMenuItem = i
160 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
162 i = expertMenu.Append(-1, _("Switch to full settings..."), kind=wx.ITEM_RADIO)
163 self.switchToNormalMenuItem = i
164 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
165 expertMenu.AppendSeparator()
167 i = expertMenu.Append(-1, _("Open expert settings...\tCTRL+E"))
168 self.normalModeOnlyItems.append(i)
169 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
170 expertMenu.AppendSeparator()
171 i = expertMenu.Append(-1, _("Run first run wizard..."))
172 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
173 self.bedLevelWizardMenuItem = expertMenu.Append(-1, _("Run bed leveling wizard..."))
174 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, self.bedLevelWizardMenuItem)
175 self.headOffsetWizardMenuItem = expertMenu.Append(-1, _("Run head offset wizard..."))
176 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, self.headOffsetWizardMenuItem)
178 self.menubar.Append(expertMenu, _("Expert"))
181 i = helpMenu.Append(-1, _("Online documentation..."))
182 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
183 i = helpMenu.Append(-1, _("Report a problem..."))
184 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
185 i = helpMenu.Append(-1, _("Check for update..."))
186 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
187 i = helpMenu.Append(-1, _("Open YouMagine website..."))
188 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
189 i = helpMenu.Append(-1, _("About Cura..."))
190 self.Bind(wx.EVT_MENU, self.OnAbout, i)
191 self.menubar.Append(helpMenu, _("Help"))
192 self.SetMenuBar(self.menubar)
194 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
195 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
196 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
197 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
200 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
201 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
203 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
204 self.leftSizer.Add(self.simpleSettingsPanel, 1)
205 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
206 self.leftPane.SetSizer(self.leftSizer)
209 self.scene = sceneView.SceneView(self.rightPane)
211 #Main sizer, to position the preview window, buttons and tab control
212 sizer = wx.BoxSizer()
213 self.rightPane.SetSizer(sizer)
214 sizer.Add(self.scene, 1, flag=wx.EXPAND)
217 sizer = wx.BoxSizer(wx.VERTICAL)
219 sizer.Add(self.splitter, 1, wx.EXPAND)
223 self.updateProfileToAllControls()
225 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
227 self.simpleSettingsPanel.Show(False)
228 self.normalSettingsPanel.Show(False)
230 # Set default window size & position
231 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
234 #Timer set; used to check if profile is on the clipboard
235 self.timer = wx.Timer(self)
236 self.Bind(wx.EVT_TIMER, self.onTimer)
237 self.timer.Start(1000)
238 self.lastTriedClipboard = profile.getProfileString()
240 # Restore the window position, size & state from the preferences file
242 if profile.getPreference('window_maximized') == 'True':
245 posx = int(profile.getPreference('window_pos_x'))
246 posy = int(profile.getPreference('window_pos_y'))
247 width = int(profile.getPreference('window_width'))
248 height = int(profile.getPreference('window_height'))
249 if posx > 0 or posy > 0:
250 self.SetPosition((posx,posy))
251 if width > 0 and height > 0:
252 self.SetSize((width,height))
254 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
256 self.normalSashPos = 0
258 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
259 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
261 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
263 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
265 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
267 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
268 self.SetSize((800,600))
271 self.updateSliceMode()
272 self.scene.SetFocus()
274 def onTimer(self, e):
275 #Check if there is something in the clipboard
278 if not wx.TheClipboard.IsOpened():
279 if not wx.TheClipboard.Open():
281 do = wx.TextDataObject()
282 if wx.TheClipboard.GetData(do):
283 profileString = do.GetText()
284 wx.TheClipboard.Close()
286 startTag = "CURA_PROFILE_STRING:"
287 if startTag in profileString:
288 #print "Found correct syntax on clipboard"
289 profileString = profileString.replace("\n","").strip()
290 profileString = profileString[profileString.find(startTag)+len(startTag):]
291 if profileString != self.lastTriedClipboard:
293 self.lastTriedClipboard = profileString
294 profile.setProfileFromString(profileString)
295 self.scene.notification.message("Loaded new profile from clipboard.")
296 self.updateProfileToAllControls()
298 print "Unable to read from clipboard"
301 def updateSliceMode(self):
302 isSimple = profile.getPreference('startMode') == 'Simple'
304 self.normalSettingsPanel.Show(not isSimple)
305 self.simpleSettingsPanel.Show(isSimple)
306 self.leftPane.Layout()
308 for i in self.normalModeOnlyItems:
309 i.Enable(not isSimple)
311 self.switchToQuickprintMenuItem.Check()
313 self.switchToNormalMenuItem.Check()
315 # Set splitter sash position & size
317 # Save normal mode sash
318 self.normalSashPos = self.splitter.GetSashPosition()
320 # Change location of sash to width of quick mode pane
321 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
322 self.splitter.SetSashPosition(width, True)
325 self.splitter.SetSashSize(0)
327 self.splitter.SetSashPosition(self.normalSashPos, True)
329 self.splitter.SetSashSize(4)
330 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
331 if profile.getMachineSetting('machine_type') == 'ultimaker2':
332 self.bedLevelWizardMenuItem.Enable(False)
333 self.headOffsetWizardMenuItem.Enable(False)
334 if int(profile.getMachineSetting('extruder_amount')) < 2:
335 self.headOffsetWizardMenuItem.Enable(False)
336 self.scene.updateProfileToControls()
337 self.scene._scene.pushFree()
339 def onOneAtATimeSwitch(self, e):
340 profile.putPreference('oneAtATime', self.oneAtATime.IsChecked())
341 if self.oneAtATime.IsChecked() and profile.getMachineSettingFloat('extruder_head_size_height') < 1:
342 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)
343 self.scene.updateProfileToControls()
344 self.scene._scene.pushFree()
345 self.scene.sceneUpdated()
347 def OnPreferences(self, e):
348 prefDialog = preferencesDialog.preferencesDialog(self)
352 wx.CallAfter(prefDialog.Show)
354 def OnMachineSettings(self, e):
355 prefDialog = preferencesDialog.machineSettingsDialog(self)
360 def OnDropFiles(self, files):
362 self.updateProfileToAllControls()
363 self.scene.loadFiles(files)
365 def OnModelMRU(self, e):
366 fileNum = e.GetId() - self.ID_MRU_MODEL1
367 path = self.modelFileHistory.GetHistoryFile(fileNum)
369 self.modelFileHistory.AddFileToHistory(path) # move up the list
370 self.config.SetPath("/ModelMRU")
371 self.modelFileHistory.Save(self.config)
374 profile.putPreference('lastFile', path)
376 self.scene.loadFiles(filelist)
378 def addToModelMRU(self, file):
379 self.modelFileHistory.AddFileToHistory(file)
380 self.config.SetPath("/ModelMRU")
381 self.modelFileHistory.Save(self.config)
384 def OnProfileMRU(self, e):
385 fileNum = e.GetId() - self.ID_MRU_PROFILE1
386 path = self.profileFileHistory.GetHistoryFile(fileNum)
388 self.profileFileHistory.AddFileToHistory(path) # move up the list
389 self.config.SetPath("/ProfileMRU")
390 self.profileFileHistory.Save(self.config)
393 profile.loadProfile(path)
394 self.updateProfileToAllControls()
396 def addToProfileMRU(self, file):
397 self.profileFileHistory.AddFileToHistory(file)
398 self.config.SetPath("/ProfileMRU")
399 self.profileFileHistory.Save(self.config)
402 def updateProfileToAllControls(self):
403 self.scene.updateProfileToControls()
404 self.normalSettingsPanel.updateProfileToControls()
405 self.simpleSettingsPanel.updateProfileToControls()
407 def reloadSettingPanels(self):
408 self.leftSizer.Detach(self.simpleSettingsPanel)
409 self.leftSizer.Detach(self.normalSettingsPanel)
410 self.simpleSettingsPanel.Destroy()
411 self.normalSettingsPanel.Destroy()
412 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
413 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
414 self.leftSizer.Add(self.simpleSettingsPanel, 1)
415 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
416 self.updateSliceMode()
417 self.updateProfileToAllControls()
419 def updateMachineMenu(self):
420 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
421 for item in self.machineMenu.GetMenuItems():
422 self.machineMenu.RemoveItem(item)
424 #Add a menu item for each machine configuration.
425 for n in xrange(0, profile.getMachineCount()):
426 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
427 if n == int(profile.getPreferenceFloat('active_machine')):
429 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
431 self.machineMenu.AppendSeparator()
433 i = self.machineMenu.Append(-1, _("Machine settings..."))
434 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
436 #Add tools for machines.
437 self.machineMenu.AppendSeparator()
439 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
440 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
442 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
443 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
445 def OnLoadProfile(self, e):
446 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)
447 dlg.SetWildcard("ini files (*.ini)|*.ini")
448 if dlg.ShowModal() == wx.ID_OK:
449 profileFile = dlg.GetPath()
450 profile.loadProfile(profileFile)
451 self.updateProfileToAllControls()
453 # Update the Profile MRU
454 self.addToProfileMRU(profileFile)
457 def OnLoadProfileFromGcode(self, e):
458 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)
459 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
460 if dlg.ShowModal() == wx.ID_OK:
461 gcodeFile = dlg.GetPath()
462 f = open(gcodeFile, 'r')
465 if line.startswith(';CURA_PROFILE_STRING:'):
466 profile.setProfileFromString(line[line.find(':')+1:].strip())
469 self.updateProfileToAllControls()
471 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)
474 def OnSaveProfile(self, e):
475 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
476 dlg.SetWildcard("ini files (*.ini)|*.ini")
477 if dlg.ShowModal() == wx.ID_OK:
478 profileFile = dlg.GetPath()
479 profile.saveProfile(profileFile)
482 def OnResetProfile(self, e):
483 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)
484 result = dlg.ShowModal() == wx.ID_YES
487 profile.resetProfile()
488 self.updateProfileToAllControls()
490 def OnSimpleSwitch(self, e):
491 profile.putPreference('startMode', 'Simple')
492 self.updateSliceMode()
494 def OnNormalSwitch(self, e):
495 profile.putPreference('startMode', 'Normal')
496 self.updateSliceMode()
498 def OnDefaultMarlinFirmware(self, e):
499 firmwareInstall.InstallFirmware()
501 def OnCustomFirmware(self, e):
502 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
503 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)
504 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
505 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
506 if dlg.ShowModal() == wx.ID_OK:
507 filename = dlg.GetPath()
508 if not(os.path.exists(filename)):
510 #For some reason my Ubuntu 10.10 crashes here.
511 firmwareInstall.InstallFirmware(filename)
513 def OnFirstRunWizard(self, e):
515 configWizard.configWizard()
517 self.reloadSettingPanels()
519 def OnSelectMachine(self, index):
520 profile.setActiveMachine(index)
521 self.reloadSettingPanels()
523 def OnBedLevelWizard(self, e):
524 configWizard.bedLevelWizard()
526 def OnHeadOffsetWizard(self, e):
527 configWizard.headOffsetWizard()
529 def OnExpertOpen(self, e):
530 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
534 def OnMinecraftImport(self, e):
535 mi = minecraftImport.minecraftImportWindow(self)
539 def OnPIDDebugger(self, e):
540 debugger = pidDebugger.debuggerWindow(self)
544 def onCopyProfileClipboard(self, e):
546 if not wx.TheClipboard.IsOpened():
547 wx.TheClipboard.Open()
548 clipData = wx.TextDataObject()
549 self.lastTriedClipboard = profile.getProfileString()
550 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
551 clipData.SetText(profileString)
552 wx.TheClipboard.SetData(clipData)
553 wx.TheClipboard.Close()
555 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
557 def OnCheckForUpdate(self, e):
558 newVersion = version.checkForNewerVersion()
559 if newVersion is not None:
560 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:
561 webbrowser.open(newVersion)
563 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
565 def OnAbout(self, e):
566 aboutBox = aboutWindow.aboutWindow()
570 def OnClose(self, e):
571 profile.saveProfile(profile.getDefaultProfilePath(), True)
573 # Save the window position, size & state from the preferences file
574 profile.putPreference('window_maximized', self.IsMaximized())
575 if not self.IsMaximized() and not self.IsIconized():
576 (posx, posy) = self.GetPosition()
577 profile.putPreference('window_pos_x', posx)
578 profile.putPreference('window_pos_y', posy)
579 (width, height) = self.GetSize()
580 profile.putPreference('window_width', width)
581 profile.putPreference('window_height', height)
583 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
584 isSimple = profile.getPreference('startMode') == 'Simple'
586 self.normalSashPos = self.splitter.GetSashPosition()
587 profile.putPreference('window_normal_sash', self.normalSashPos)
589 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
591 self.scene.OnPaint = lambda e : e
592 self.scene._engine.cleanup()
598 class normalSettingsPanel(configBase.configPanelBase):
599 "Main user interface window"
600 def __init__(self, parent, callback = None):
601 super(normalSettingsPanel, self).__init__(parent, callback)
604 self.nb = wx.Notebook(self)
605 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
606 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
608 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
609 self._addSettingsToPanels('basic', left, right)
610 self.SizeLabelWidths(left, right)
612 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
613 self._addSettingsToPanels('advanced', left, right)
614 self.SizeLabelWidths(left, right)
617 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
618 self.nb.AddPage(self.pluginPanel, _("Plugins"))
621 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
622 self.alterationPanel = None
624 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
625 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
627 self.Bind(wx.EVT_SIZE, self.OnSize)
629 self.nb.SetSize(self.GetSize())
630 self.UpdateSize(self.printPanel)
631 self.UpdateSize(self.advancedPanel)
633 def _addSettingsToPanels(self, category, left, right):
634 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
638 for title in profile.getSubCategoriesFor(category):
639 n += 1 + len(profile.getSettingsForCategory(category, title))
642 configBase.TitleRow(p, _(title))
643 for s in profile.getSettingsForCategory(category, title):
644 configBase.SettingRow(p, s.getName())
646 def SizeLabelWidths(self, left, right):
647 leftWidth = self.getLabelColumnWidth(left)
648 rightWidth = self.getLabelColumnWidth(right)
649 maxWidth = max(leftWidth, rightWidth)
650 self.setLabelColumnWidth(left, maxWidth)
651 self.setLabelColumnWidth(right, maxWidth)
654 # Make the size of the Notebook control the same size as this control
655 self.nb.SetSize(self.GetSize())
657 # Propegate the OnSize() event (just in case)
660 # Perform out resize magic
661 self.UpdateSize(self.printPanel)
662 self.UpdateSize(self.advancedPanel)
664 def UpdateSize(self, configPanel):
665 sizer = configPanel.GetSizer()
669 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
672 # if width(col1) > (best_width(col1) + best_width(col1)):
673 # switch to horizontal
676 col1 = configPanel.leftPanel
677 colSize1 = col1.GetSize()
678 colBestSize1 = col1.GetBestSize()
679 col2 = configPanel.rightPanel
680 colSize2 = col2.GetSize()
681 colBestSize2 = col2.GetBestSize()
683 orientation = sizer.GetOrientation()
685 if orientation == wx.HORIZONTAL:
686 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
688 sizer = wx.BoxSizer(wx.VERTICAL)
689 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
690 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
691 configPanel.SetSizer(sizer)
697 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
699 sizer = wx.BoxSizer(wx.HORIZONTAL)
700 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
701 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
702 configPanel.SetSizer(sizer)
708 def updateProfileToControls(self):
709 super(normalSettingsPanel, self).updateProfileToControls()
710 if self.alterationPanel is not None:
711 self.alterationPanel.updateProfileToControls()
712 self.pluginPanel.updateProfileToControls()