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 i = expertMenu.Append(-1, _("Run bed leveling wizard..."))
152 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
153 if self.extruderCount > 1:
154 i = expertMenu.Append(-1, _("Run head offset wizard..."))
155 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
157 self.menubar.Append(expertMenu, _("Expert"))
160 i = helpMenu.Append(-1, _("Online documentation..."))
161 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
162 i = helpMenu.Append(-1, _("Report a problem..."))
163 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
164 i = helpMenu.Append(-1, _("Check for update..."))
165 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
166 i = helpMenu.Append(-1, _("Open YouMagine website..."))
167 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
168 i = helpMenu.Append(-1, _("About Cura..."))
169 self.Bind(wx.EVT_MENU, self.OnAbout, i)
170 self.menubar.Append(helpMenu, _("Help"))
171 self.SetMenuBar(self.menubar)
173 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
174 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
175 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
176 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
179 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
180 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
182 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
183 self.leftSizer.Add(self.simpleSettingsPanel, 1)
184 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
185 self.leftPane.SetSizer(self.leftSizer)
188 self.scene = sceneView.SceneView(self.rightPane)
190 #Main sizer, to position the preview window, buttons and tab control
191 sizer = wx.BoxSizer()
192 self.rightPane.SetSizer(sizer)
193 sizer.Add(self.scene, 1, flag=wx.EXPAND)
196 sizer = wx.BoxSizer(wx.VERTICAL)
198 sizer.Add(self.splitter, 1, wx.EXPAND)
202 self.updateProfileToAllControls()
204 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
206 self.simpleSettingsPanel.Show(False)
207 self.normalSettingsPanel.Show(False)
209 # Set default window size & position
210 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
213 #Timer set; used to check if profile is on the clipboard
214 self.timer = wx.Timer(self)
215 self.Bind(wx.EVT_TIMER, self.onTimer)
216 self.timer.Start(1000)
217 self.lastTriedClipboard = profile.getProfileString()
219 # Restore the window position, size & state from the preferences file
221 if profile.getPreference('window_maximized') == 'True':
224 posx = int(profile.getPreference('window_pos_x'))
225 posy = int(profile.getPreference('window_pos_y'))
226 width = int(profile.getPreference('window_width'))
227 height = int(profile.getPreference('window_height'))
228 if posx > 0 or posy > 0:
229 self.SetPosition((posx,posy))
230 if width > 0 and height > 0:
231 self.SetSize((width,height))
233 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
235 self.normalSashPos = 0
237 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
238 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
240 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
242 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
244 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
246 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
247 self.SetSize((800,600))
250 self.updateSliceMode()
252 def onTimer(self, e):
253 #Check if there is something in the clipboard
256 if not wx.TheClipboard.IsOpened():
257 wx.TheClipboard.Open()
258 do = wx.TextDataObject()
259 if wx.TheClipboard.GetData(do):
260 profileString = do.GetText()
261 wx.TheClipboard.Close()
263 startTag = "CURA_PROFILE_STRING:"
264 if startTag in profileString:
265 #print "Found correct syntax on clipboard"
266 profileString = profileString.replace("\n","").strip()
267 profileString = profileString[profileString.find(startTag)+len(startTag):]
268 if profileString != self.lastTriedClipboard:
270 self.lastTriedClipboard = profileString
271 profile.setProfileFromString(profileString)
272 self.scene.notification.message("Loaded new profile from clipboard.")
273 self.updateProfileToAllControls()
275 print "Unable to read from clipboard"
278 def updateSliceMode(self):
279 isSimple = profile.getPreference('startMode') == 'Simple'
281 self.normalSettingsPanel.Show(not isSimple)
282 self.simpleSettingsPanel.Show(isSimple)
283 self.leftPane.Layout()
285 for i in self.normalModeOnlyItems:
286 i.Enable(not isSimple)
288 self.switchToQuickprintMenuItem.Check()
290 self.switchToNormalMenuItem.Check()
292 # Set splitter sash position & size
294 # Save normal mode sash
295 self.normalSashPos = self.splitter.GetSashPosition()
297 # Change location of sash to width of quick mode pane
298 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
299 self.splitter.SetSashPosition(width, True)
302 self.splitter.SetSashSize(0)
304 self.splitter.SetSashPosition(self.normalSashPos, True)
306 self.splitter.SetSashSize(4)
307 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
308 self.scene.updateProfileToControls()
310 def OnPreferences(self, e):
311 prefDialog = preferencesDialog.preferencesDialog(self)
314 wx.CallAfter(prefDialog.Show)
316 def OnMachineSettings(self, e):
317 prefDialog = preferencesDialog.machineSettingsDialog(self)
321 def OnDropFiles(self, files):
323 profile.setPluginConfig([])
324 self.updateProfileToAllControls()
325 self.scene.loadFiles(files)
327 def OnModelMRU(self, e):
328 fileNum = e.GetId() - self.ID_MRU_MODEL1
329 path = self.modelFileHistory.GetHistoryFile(fileNum)
331 self.modelFileHistory.AddFileToHistory(path) # move up the list
332 self.config.SetPath("/ModelMRU")
333 self.modelFileHistory.Save(self.config)
336 profile.putPreference('lastFile', path)
338 self.scene.loadFiles(filelist)
340 def addToModelMRU(self, file):
341 self.modelFileHistory.AddFileToHistory(file)
342 self.config.SetPath("/ModelMRU")
343 self.modelFileHistory.Save(self.config)
346 def OnProfileMRU(self, e):
347 fileNum = e.GetId() - self.ID_MRU_PROFILE1
348 path = self.profileFileHistory.GetHistoryFile(fileNum)
350 self.profileFileHistory.AddFileToHistory(path) # move up the list
351 self.config.SetPath("/ProfileMRU")
352 self.profileFileHistory.Save(self.config)
355 profile.loadProfile(path)
356 self.updateProfileToAllControls()
358 def addToProfileMRU(self, file):
359 self.profileFileHistory.AddFileToHistory(file)
360 self.config.SetPath("/ProfileMRU")
361 self.profileFileHistory.Save(self.config)
364 def updateProfileToAllControls(self):
365 self.scene.updateProfileToControls()
366 self.normalSettingsPanel.updateProfileToControls()
367 self.simpleSettingsPanel.updateProfileToControls()
369 def reloadSettingPanels(self):
370 self.leftSizer.Detach(self.simpleSettingsPanel)
371 self.leftSizer.Detach(self.normalSettingsPanel)
372 self.simpleSettingsPanel.Destroy()
373 self.normalSettingsPanel.Destroy()
374 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
375 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
376 self.leftSizer.Add(self.simpleSettingsPanel, 1)
377 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
378 self.updateSliceMode()
379 self.updateProfileToAllControls()
381 def updateMachineMenu(self):
382 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
383 for item in self.machineMenu.GetMenuItems():
384 self.machineMenu.RemoveItem(item)
386 #Add a menu item for each machine configuration.
387 for n in xrange(0, profile.getMachineCount()):
388 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
389 if n == int(profile.getPreferenceFloat('active_machine')):
391 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
393 self.machineMenu.AppendSeparator()
394 i = self.machineMenu.Append(-1, _("Add new machine..."))
395 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
397 #Add tools for machines.
398 self.machineMenu.AppendSeparator()
399 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
400 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
402 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default Marlin firmware..."))
403 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
405 def OnLoadProfile(self, e):
406 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)
407 dlg.SetWildcard("ini files (*.ini)|*.ini")
408 if dlg.ShowModal() == wx.ID_OK:
409 profileFile = dlg.GetPath()
410 profile.loadProfile(profileFile)
411 self.updateProfileToAllControls()
413 # Update the Profile MRU
414 self.addToProfileMRU(profileFile)
417 def OnLoadProfileFromGcode(self, e):
418 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)
419 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
420 if dlg.ShowModal() == wx.ID_OK:
421 gcodeFile = dlg.GetPath()
422 f = open(gcodeFile, 'r')
425 if line.startswith(';CURA_PROFILE_STRING:'):
426 profile.setProfileFromString(line[line.find(':')+1:].strip())
429 self.updateProfileToAllControls()
431 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)
434 def OnSaveProfile(self, e):
435 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
436 dlg.SetWildcard("ini files (*.ini)|*.ini")
437 if dlg.ShowModal() == wx.ID_OK:
438 profileFile = dlg.GetPath()
439 profile.saveProfile(profileFile)
442 def OnResetProfile(self, e):
443 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)
444 result = dlg.ShowModal() == wx.ID_YES
447 profile.resetProfile()
448 self.updateProfileToAllControls()
450 def OnSimpleSwitch(self, e):
451 profile.putPreference('startMode', 'Simple')
452 self.updateSliceMode()
454 def OnNormalSwitch(self, e):
455 profile.putPreference('startMode', 'Normal')
456 self.updateSliceMode()
458 def OnDefaultMarlinFirmware(self, e):
459 firmwareInstall.InstallFirmware()
461 def OnCustomFirmware(self, e):
462 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
463 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)
464 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
465 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
466 if dlg.ShowModal() == wx.ID_OK:
467 filename = dlg.GetPath()
468 if not(os.path.exists(filename)):
470 #For some reason my Ubuntu 10.10 crashes here.
471 firmwareInstall.InstallFirmware(filename)
473 def OnFirstRunWizard(self, e):
475 configWizard.configWizard()
477 self.reloadSettingPanels()
479 def OnAddNewMachine(self, e):
481 profile.setActiveMachine(profile.getMachineCount())
482 configWizard.configWizard(True)
484 self.reloadSettingPanels()
485 self.updateMachineMenu()
487 def OnSelectMachine(self, index):
488 profile.setActiveMachine(index)
489 self.reloadSettingPanels()
491 def OnBedLevelWizard(self, e):
492 configWizard.bedLevelWizard()
494 def OnHeadOffsetWizard(self, e):
495 configWizard.headOffsetWizard()
497 def OnExpertOpen(self, e):
498 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
502 def OnMinecraftImport(self, e):
503 mi = minecraftImport.minecraftImportWindow(self)
507 def OnPIDDebugger(self, e):
508 debugger = pidDebugger.debuggerWindow(self)
512 def onCopyProfileClipboard(self, e):
514 if not wx.TheClipboard.IsOpened():
515 wx.TheClipboard.Open()
516 clipData = wx.TextDataObject()
517 self.lastTriedClipboard = profile.getProfileString()
518 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
519 clipData.SetText(profileString)
520 wx.TheClipboard.SetData(clipData)
521 wx.TheClipboard.Close()
523 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
525 def OnCheckForUpdate(self, e):
526 newVersion = version.checkForNewerVersion()
527 if newVersion is not None:
528 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:
529 webbrowser.open(newVersion)
531 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
533 def OnAbout(self, e):
534 aboutBox = aboutWindow.aboutWindow()
538 def OnClose(self, e):
539 profile.saveProfile(profile.getDefaultProfilePath())
541 # Save the window position, size & state from the preferences file
542 profile.putPreference('window_maximized', self.IsMaximized())
543 if not self.IsMaximized() and not self.IsIconized():
544 (posx, posy) = self.GetPosition()
545 profile.putPreference('window_pos_x', posx)
546 profile.putPreference('window_pos_y', posy)
547 (width, height) = self.GetSize()
548 profile.putPreference('window_width', width)
549 profile.putPreference('window_height', height)
551 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
552 isSimple = profile.getPreference('startMode') == 'Simple'
554 self.normalSashPos = self.splitter.GetSashPosition()
555 profile.putPreference('window_normal_sash', self.normalSashPos)
557 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
559 self.scene.OnPaint = lambda e : e
560 self.scene._slicer.cleanup()
566 class normalSettingsPanel(configBase.configPanelBase):
567 "Main user interface window"
568 def __init__(self, parent, callback = None):
569 super(normalSettingsPanel, self).__init__(parent, callback)
572 self.nb = wx.Notebook(self)
573 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
574 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
576 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
577 self._addSettingsToPanels('basic', left, right)
578 self.SizeLabelWidths(left, right)
580 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
581 self._addSettingsToPanels('advanced', left, right)
582 self.SizeLabelWidths(left, right)
585 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
586 self.nb.AddPage(self.pluginPanel, _("Plugins"))
589 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
590 self.alterationPanel = None
592 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
593 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
595 self.Bind(wx.EVT_SIZE, self.OnSize)
597 self.nb.SetSize(self.GetSize())
598 self.UpdateSize(self.printPanel)
599 self.UpdateSize(self.advancedPanel)
601 def _addSettingsToPanels(self, category, left, right):
602 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
606 for title in profile.getSubCategoriesFor(category):
607 n += 1 + len(profile.getSettingsForCategory(category, title))
610 configBase.TitleRow(p, _(title))
611 for s in profile.getSettingsForCategory(category, title):
612 configBase.SettingRow(p, s.getName())
614 def SizeLabelWidths(self, left, right):
615 leftWidth = self.getLabelColumnWidth(left)
616 rightWidth = self.getLabelColumnWidth(right)
617 maxWidth = max(leftWidth, rightWidth)
618 self.setLabelColumnWidth(left, maxWidth)
619 self.setLabelColumnWidth(right, maxWidth)
622 # Make the size of the Notebook control the same size as this control
623 self.nb.SetSize(self.GetSize())
625 # Propegate the OnSize() event (just in case)
628 # Perform out resize magic
629 self.UpdateSize(self.printPanel)
630 self.UpdateSize(self.advancedPanel)
632 def UpdateSize(self, configPanel):
633 sizer = configPanel.GetSizer()
637 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
640 # if width(col1) > (best_width(col1) + best_width(col1)):
641 # switch to horizontal
644 col1 = configPanel.leftPanel
645 colSize1 = col1.GetSize()
646 colBestSize1 = col1.GetBestSize()
647 col2 = configPanel.rightPanel
648 colSize2 = col2.GetSize()
649 colBestSize2 = col2.GetBestSize()
651 orientation = sizer.GetOrientation()
653 if orientation == wx.HORIZONTAL:
654 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
656 sizer = wx.BoxSizer(wx.VERTICAL)
657 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
658 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
659 configPanel.SetSizer(sizer)
665 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
667 sizer = wx.BoxSizer(wx.HORIZONTAL)
668 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
669 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
670 configPanel.SetSizer(sizer)
676 def updateProfileToControls(self):
677 super(normalSettingsPanel, self).updateProfileToControls()
678 if self.alterationPanel is not None:
679 self.alterationPanel.updateProfileToControls()
680 self.pluginPanel.updateProfileToControls()