1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
8 from Cura.gui import configBase
9 from Cura.gui import expertConfig
10 from Cura.gui import alterationPanel
11 from Cura.gui import pluginPanel
12 from Cura.gui import preferencesDialog
13 from Cura.gui import configWizard
14 from Cura.gui import firmwareInstall
15 from Cura.gui import simpleMode
16 from Cura.gui import sceneView
17 from Cura.gui import aboutWindow
18 from Cura.gui.util import dropTarget
19 #from Cura.gui.tools import batchRun
20 from Cura.gui.tools import pidDebugger
21 from Cura.gui.tools import minecraftImport
22 from Cura.util import profile
23 from Cura.util import version
24 from Cura.util import meshLoader
26 class mainWindow(wx.Frame):
28 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
30 self.extruderCount = int(profile.getMachineSetting('extruder_amount'))
32 wx.EVT_CLOSE(self, self.OnClose)
34 # allow dropping any file, restrict later
35 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles))
37 self.normalModeOnlyItems = []
39 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
40 self.config = wx.FileConfig(appName="Cura",
41 localFilename=mruFile,
42 style=wx.CONFIG_USE_LOCAL_FILE)
44 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)]
45 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
46 self.config.SetPath("/ModelMRU")
47 self.modelFileHistory.Load(self.config)
49 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)]
50 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
51 self.config.SetPath("/ProfileMRU")
52 self.profileFileHistory.Load(self.config)
54 self.menubar = wx.MenuBar()
55 self.fileMenu = wx.Menu()
56 i = self.fileMenu.Append(-1, _("Load model file...\tCTRL+L"))
57 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
58 i = self.fileMenu.Append(-1, _("Save model...\tCTRL+S"))
59 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
60 i = self.fileMenu.Append(-1, _("Clear platform"))
61 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
63 self.fileMenu.AppendSeparator()
64 i = self.fileMenu.Append(-1, _("Print...\tCTRL+P"))
65 self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
66 i = self.fileMenu.Append(-1, _("Save GCode..."))
67 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
68 i = self.fileMenu.Append(-1, _("Show slice engine log..."))
69 self.Bind(wx.EVT_MENU, lambda e: self.scene._showSliceLog(), i)
71 self.fileMenu.AppendSeparator()
72 i = self.fileMenu.Append(-1, _("Open Profile..."))
73 self.normalModeOnlyItems.append(i)
74 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
75 i = self.fileMenu.Append(-1, _("Save Profile..."))
76 self.normalModeOnlyItems.append(i)
77 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
78 i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
79 self.normalModeOnlyItems.append(i)
80 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
81 self.fileMenu.AppendSeparator()
82 i = self.fileMenu.Append(-1, _("Reset Profile to default"))
83 self.normalModeOnlyItems.append(i)
84 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
86 self.fileMenu.AppendSeparator()
87 i = self.fileMenu.Append(-1, _("Preferences...\tCTRL+,"))
88 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
89 i = self.fileMenu.Append(-1, _("Machine settings..."))
90 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
91 self.fileMenu.AppendSeparator()
94 modelHistoryMenu = wx.Menu()
95 self.fileMenu.AppendMenu(wx.NewId(), '&' + _("Recent Model Files"), modelHistoryMenu)
96 self.modelFileHistory.UseMenu(modelHistoryMenu)
97 self.modelFileHistory.AddFilesToMenu()
98 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
101 profileHistoryMenu = wx.Menu()
102 self.fileMenu.AppendMenu(wx.NewId(), _("Recent Profile Files"), profileHistoryMenu)
103 self.profileFileHistory.UseMenu(profileHistoryMenu)
104 self.profileFileHistory.AddFilesToMenu()
105 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
107 self.fileMenu.AppendSeparator()
108 i = self.fileMenu.Append(wx.ID_EXIT, _("Quit"))
109 self.Bind(wx.EVT_MENU, self.OnQuit, i)
110 self.menubar.Append(self.fileMenu, '&' + _("File"))
112 toolsMenu = wx.Menu()
113 #i = toolsMenu.Append(-1, 'Batch run...')
114 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
115 #self.normalModeOnlyItems.append(i)
117 if minecraftImport.hasMinecraft():
118 i = toolsMenu.Append(-1, _("Minecraft map import..."))
119 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
121 if version.isDevVersion():
122 i = toolsMenu.Append(-1, _("PID Debugger..."))
123 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
125 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
126 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
127 self.menubar.Append(toolsMenu, _("Tools"))
129 #Machine menu for machine configuration/tooling
130 self.machineMenu = wx.Menu()
131 self.updateMachineMenu()
133 self.menubar.Append(self.machineMenu, _("Machine"))
135 expertMenu = wx.Menu()
136 i = expertMenu.Append(-1, _("Switch to quickprint..."), kind=wx.ITEM_RADIO)
137 self.switchToQuickprintMenuItem = i
138 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
140 i = expertMenu.Append(-1, _("Switch to full settings..."), kind=wx.ITEM_RADIO)
141 self.switchToNormalMenuItem = i
142 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
143 expertMenu.AppendSeparator()
145 i = expertMenu.Append(-1, _("Open expert settings..."))
146 self.normalModeOnlyItems.append(i)
147 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
148 expertMenu.AppendSeparator()
149 i = expertMenu.Append(-1, _("Run first run wizard..."))
150 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
151 self.bedLevelWizardMenuItem = expertMenu.Append(-1, _("Run bed leveling wizard..."))
152 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, self.bedLevelWizardMenuItem)
153 if self.extruderCount > 1:
154 self.headOffsetWizardMenuItem = expertMenu.Append(-1, _("Run head offset wizard..."))
155 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, self.headOffsetWizardMenuItem)
157 self.headOffsetWizardMenuItem = None
159 self.menubar.Append(expertMenu, _("Expert"))
162 i = helpMenu.Append(-1, _("Online documentation..."))
163 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
164 i = helpMenu.Append(-1, _("Report a problem..."))
165 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
166 i = helpMenu.Append(-1, _("Check for update..."))
167 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
168 i = helpMenu.Append(-1, _("Open YouMagine website..."))
169 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
170 i = helpMenu.Append(-1, _("About Cura..."))
171 self.Bind(wx.EVT_MENU, self.OnAbout, i)
172 self.menubar.Append(helpMenu, _("Help"))
173 self.SetMenuBar(self.menubar)
175 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
176 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
177 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
178 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
181 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
182 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
184 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
185 self.leftSizer.Add(self.simpleSettingsPanel, 1)
186 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
187 self.leftPane.SetSizer(self.leftSizer)
190 self.scene = sceneView.SceneView(self.rightPane)
192 #Main sizer, to position the preview window, buttons and tab control
193 sizer = wx.BoxSizer()
194 self.rightPane.SetSizer(sizer)
195 sizer.Add(self.scene, 1, flag=wx.EXPAND)
198 sizer = wx.BoxSizer(wx.VERTICAL)
200 sizer.Add(self.splitter, 1, wx.EXPAND)
204 self.updateProfileToAllControls()
206 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
208 self.simpleSettingsPanel.Show(False)
209 self.normalSettingsPanel.Show(False)
211 # Set default window size & position
212 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
215 #Timer set; used to check if profile is on the clipboard
216 self.timer = wx.Timer(self)
217 self.Bind(wx.EVT_TIMER, self.onTimer)
218 self.timer.Start(1000)
219 self.lastTriedClipboard = profile.getProfileString()
221 # Restore the window position, size & state from the preferences file
223 if profile.getPreference('window_maximized') == 'True':
226 posx = int(profile.getPreference('window_pos_x'))
227 posy = int(profile.getPreference('window_pos_y'))
228 width = int(profile.getPreference('window_width'))
229 height = int(profile.getPreference('window_height'))
230 if posx > 0 or posy > 0:
231 self.SetPosition((posx,posy))
232 if width > 0 and height > 0:
233 self.SetSize((width,height))
235 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
237 self.normalSashPos = 0
239 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
240 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
242 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
244 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
246 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
248 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
249 self.SetSize((800,600))
252 self.updateSliceMode()
254 def onTimer(self, e):
255 #Check if there is something in the clipboard
258 if not wx.TheClipboard.IsOpened():
259 if not wx.TheClipboard.Open():
261 do = wx.TextDataObject()
262 if wx.TheClipboard.GetData(do):
263 profileString = do.GetText()
264 wx.TheClipboard.Close()
266 startTag = "CURA_PROFILE_STRING:"
267 if startTag in profileString:
268 #print "Found correct syntax on clipboard"
269 profileString = profileString.replace("\n","").strip()
270 profileString = profileString[profileString.find(startTag)+len(startTag):]
271 if profileString != self.lastTriedClipboard:
273 self.lastTriedClipboard = profileString
274 profile.setProfileFromString(profileString)
275 self.scene.notification.message("Loaded new profile from clipboard.")
276 self.updateProfileToAllControls()
278 print "Unable to read from clipboard"
281 def updateSliceMode(self):
282 isSimple = profile.getPreference('startMode') == 'Simple'
284 self.normalSettingsPanel.Show(not isSimple)
285 self.simpleSettingsPanel.Show(isSimple)
286 self.leftPane.Layout()
288 for i in self.normalModeOnlyItems:
289 i.Enable(not isSimple)
291 self.switchToQuickprintMenuItem.Check()
293 self.switchToNormalMenuItem.Check()
295 # Set splitter sash position & size
297 # Save normal mode sash
298 self.normalSashPos = self.splitter.GetSashPosition()
300 # Change location of sash to width of quick mode pane
301 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
302 self.splitter.SetSashPosition(width, True)
305 self.splitter.SetSashSize(0)
307 self.splitter.SetSashPosition(self.normalSashPos, True)
309 self.splitter.SetSashSize(4)
310 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
311 if profile.getMachineSetting('machine_type') == 'ultimaker2':
312 self.bedLevelWizardMenuItem.Enable(False)
313 if self.headOffsetWizardMenuItem is not None:
314 self.headOffsetWizardMenuItem.Enable(False)
315 self.scene.updateProfileToControls()
317 def OnPreferences(self, e):
318 prefDialog = preferencesDialog.preferencesDialog(self)
321 wx.CallAfter(prefDialog.Show)
323 def OnMachineSettings(self, e):
324 prefDialog = preferencesDialog.machineSettingsDialog(self)
328 def OnDropFiles(self, files):
330 profile.setPluginConfig([])
331 self.updateProfileToAllControls()
332 self.scene.loadFiles(files)
334 def OnModelMRU(self, e):
335 fileNum = e.GetId() - self.ID_MRU_MODEL1
336 path = self.modelFileHistory.GetHistoryFile(fileNum)
338 self.modelFileHistory.AddFileToHistory(path) # move up the list
339 self.config.SetPath("/ModelMRU")
340 self.modelFileHistory.Save(self.config)
343 profile.putPreference('lastFile', path)
345 self.scene.loadFiles(filelist)
347 def addToModelMRU(self, file):
348 self.modelFileHistory.AddFileToHistory(file)
349 self.config.SetPath("/ModelMRU")
350 self.modelFileHistory.Save(self.config)
353 def OnProfileMRU(self, e):
354 fileNum = e.GetId() - self.ID_MRU_PROFILE1
355 path = self.profileFileHistory.GetHistoryFile(fileNum)
357 self.profileFileHistory.AddFileToHistory(path) # move up the list
358 self.config.SetPath("/ProfileMRU")
359 self.profileFileHistory.Save(self.config)
362 profile.loadProfile(path)
363 self.updateProfileToAllControls()
365 def addToProfileMRU(self, file):
366 self.profileFileHistory.AddFileToHistory(file)
367 self.config.SetPath("/ProfileMRU")
368 self.profileFileHistory.Save(self.config)
371 def updateProfileToAllControls(self):
372 self.scene.updateProfileToControls()
373 self.normalSettingsPanel.updateProfileToControls()
374 self.simpleSettingsPanel.updateProfileToControls()
376 def reloadSettingPanels(self):
377 self.leftSizer.Detach(self.simpleSettingsPanel)
378 self.leftSizer.Detach(self.normalSettingsPanel)
379 self.simpleSettingsPanel.Destroy()
380 self.normalSettingsPanel.Destroy()
381 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
382 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
383 self.leftSizer.Add(self.simpleSettingsPanel, 1)
384 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
385 self.updateSliceMode()
386 self.updateProfileToAllControls()
388 def updateMachineMenu(self):
389 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
390 for item in self.machineMenu.GetMenuItems():
391 self.machineMenu.RemoveItem(item)
393 #Add a menu item for each machine configuration.
394 for n in xrange(0, profile.getMachineCount()):
395 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
396 if n == int(profile.getPreferenceFloat('active_machine')):
398 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
400 self.machineMenu.AppendSeparator()
401 i = self.machineMenu.Append(-1, _("Add new machine..."))
402 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
404 #Add tools for machines.
405 self.machineMenu.AppendSeparator()
407 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
408 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
410 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
411 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
413 def OnLoadProfile(self, e):
414 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)
415 dlg.SetWildcard("ini files (*.ini)|*.ini")
416 if dlg.ShowModal() == wx.ID_OK:
417 profileFile = dlg.GetPath()
418 profile.loadProfile(profileFile)
419 self.updateProfileToAllControls()
421 # Update the Profile MRU
422 self.addToProfileMRU(profileFile)
425 def OnLoadProfileFromGcode(self, e):
426 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)
427 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
428 if dlg.ShowModal() == wx.ID_OK:
429 gcodeFile = dlg.GetPath()
430 f = open(gcodeFile, 'r')
433 if line.startswith(';CURA_PROFILE_STRING:'):
434 profile.setProfileFromString(line[line.find(':')+1:].strip())
437 self.updateProfileToAllControls()
439 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)
442 def OnSaveProfile(self, e):
443 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
444 dlg.SetWildcard("ini files (*.ini)|*.ini")
445 if dlg.ShowModal() == wx.ID_OK:
446 profileFile = dlg.GetPath()
447 profile.saveProfile(profileFile)
450 def OnResetProfile(self, e):
451 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)
452 result = dlg.ShowModal() == wx.ID_YES
455 profile.resetProfile()
456 self.updateProfileToAllControls()
458 def OnSimpleSwitch(self, e):
459 profile.putPreference('startMode', 'Simple')
460 self.updateSliceMode()
462 def OnNormalSwitch(self, e):
463 profile.putPreference('startMode', 'Normal')
464 self.updateSliceMode()
466 def OnDefaultMarlinFirmware(self, e):
467 firmwareInstall.InstallFirmware()
469 def OnCustomFirmware(self, e):
470 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
471 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)
472 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
473 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
474 if dlg.ShowModal() == wx.ID_OK:
475 filename = dlg.GetPath()
476 if not(os.path.exists(filename)):
478 #For some reason my Ubuntu 10.10 crashes here.
479 firmwareInstall.InstallFirmware(filename)
481 def OnFirstRunWizard(self, e):
483 configWizard.configWizard()
485 self.reloadSettingPanels()
487 def OnAddNewMachine(self, e):
489 profile.setActiveMachine(profile.getMachineCount())
490 configWizard.configWizard(True)
492 self.reloadSettingPanels()
493 self.updateMachineMenu()
495 def OnSelectMachine(self, index):
496 profile.setActiveMachine(index)
497 self.reloadSettingPanels()
499 def OnBedLevelWizard(self, e):
500 configWizard.bedLevelWizard()
502 def OnHeadOffsetWizard(self, e):
503 configWizard.headOffsetWizard()
505 def OnExpertOpen(self, e):
506 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
510 def OnMinecraftImport(self, e):
511 mi = minecraftImport.minecraftImportWindow(self)
515 def OnPIDDebugger(self, e):
516 debugger = pidDebugger.debuggerWindow(self)
520 def onCopyProfileClipboard(self, e):
522 if not wx.TheClipboard.IsOpened():
523 wx.TheClipboard.Open()
524 clipData = wx.TextDataObject()
525 self.lastTriedClipboard = profile.getProfileString()
526 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
527 clipData.SetText(profileString)
528 wx.TheClipboard.SetData(clipData)
529 wx.TheClipboard.Close()
531 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
533 def OnCheckForUpdate(self, e):
534 newVersion = version.checkForNewerVersion()
535 if newVersion is not None:
536 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:
537 webbrowser.open(newVersion)
539 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
541 def OnAbout(self, e):
542 aboutBox = aboutWindow.aboutWindow()
546 def OnClose(self, e):
547 profile.saveProfile(profile.getDefaultProfilePath())
549 # Save the window position, size & state from the preferences file
550 profile.putPreference('window_maximized', self.IsMaximized())
551 if not self.IsMaximized() and not self.IsIconized():
552 (posx, posy) = self.GetPosition()
553 profile.putPreference('window_pos_x', posx)
554 profile.putPreference('window_pos_y', posy)
555 (width, height) = self.GetSize()
556 profile.putPreference('window_width', width)
557 profile.putPreference('window_height', height)
559 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
560 isSimple = profile.getPreference('startMode') == 'Simple'
562 self.normalSashPos = self.splitter.GetSashPosition()
563 profile.putPreference('window_normal_sash', self.normalSashPos)
565 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
567 self.scene.OnPaint = lambda e : e
568 self.scene._slicer.cleanup()
574 class normalSettingsPanel(configBase.configPanelBase):
575 "Main user interface window"
576 def __init__(self, parent, callback = None):
577 super(normalSettingsPanel, self).__init__(parent, callback)
580 self.nb = wx.Notebook(self)
581 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
582 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
584 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
585 self._addSettingsToPanels('basic', left, right)
586 self.SizeLabelWidths(left, right)
588 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
589 self._addSettingsToPanels('advanced', left, right)
590 self.SizeLabelWidths(left, right)
593 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
594 self.nb.AddPage(self.pluginPanel, _("Plugins"))
597 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
598 self.alterationPanel = None
600 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
601 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
603 self.Bind(wx.EVT_SIZE, self.OnSize)
605 self.nb.SetSize(self.GetSize())
606 self.UpdateSize(self.printPanel)
607 self.UpdateSize(self.advancedPanel)
609 def _addSettingsToPanels(self, category, left, right):
610 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
614 for title in profile.getSubCategoriesFor(category):
615 n += 1 + len(profile.getSettingsForCategory(category, title))
618 configBase.TitleRow(p, _(title))
619 for s in profile.getSettingsForCategory(category, title):
620 configBase.SettingRow(p, s.getName())
622 def SizeLabelWidths(self, left, right):
623 leftWidth = self.getLabelColumnWidth(left)
624 rightWidth = self.getLabelColumnWidth(right)
625 maxWidth = max(leftWidth, rightWidth)
626 self.setLabelColumnWidth(left, maxWidth)
627 self.setLabelColumnWidth(right, maxWidth)
630 # Make the size of the Notebook control the same size as this control
631 self.nb.SetSize(self.GetSize())
633 # Propegate the OnSize() event (just in case)
636 # Perform out resize magic
637 self.UpdateSize(self.printPanel)
638 self.UpdateSize(self.advancedPanel)
640 def UpdateSize(self, configPanel):
641 sizer = configPanel.GetSizer()
645 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
648 # if width(col1) > (best_width(col1) + best_width(col1)):
649 # switch to horizontal
652 col1 = configPanel.leftPanel
653 colSize1 = col1.GetSize()
654 colBestSize1 = col1.GetBestSize()
655 col2 = configPanel.rightPanel
656 colSize2 = col2.GetSize()
657 colBestSize2 = col2.GetBestSize()
659 orientation = sizer.GetOrientation()
661 if orientation == wx.HORIZONTAL:
662 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
664 sizer = wx.BoxSizer(wx.VERTICAL)
665 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
666 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
667 configPanel.SetSizer(sizer)
673 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
675 sizer = wx.BoxSizer(wx.HORIZONTAL)
676 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
677 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
678 configPanel.SetSizer(sizer)
684 def updateProfileToControls(self):
685 super(normalSettingsPanel, self).updateProfileToControls()
686 if self.alterationPanel is not None:
687 self.alterationPanel.updateProfileToControls()
688 self.pluginPanel.updateProfileToControls()