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 if not wx.TheClipboard.Open():
259 do = wx.TextDataObject()
260 if wx.TheClipboard.GetData(do):
261 profileString = do.GetText()
262 wx.TheClipboard.Close()
264 startTag = "CURA_PROFILE_STRING:"
265 if startTag in profileString:
266 #print "Found correct syntax on clipboard"
267 profileString = profileString.replace("\n","").strip()
268 profileString = profileString[profileString.find(startTag)+len(startTag):]
269 if profileString != self.lastTriedClipboard:
271 self.lastTriedClipboard = profileString
272 profile.setProfileFromString(profileString)
273 self.scene.notification.message("Loaded new profile from clipboard.")
274 self.updateProfileToAllControls()
276 print "Unable to read from clipboard"
279 def updateSliceMode(self):
280 isSimple = profile.getPreference('startMode') == 'Simple'
282 self.normalSettingsPanel.Show(not isSimple)
283 self.simpleSettingsPanel.Show(isSimple)
284 self.leftPane.Layout()
286 for i in self.normalModeOnlyItems:
287 i.Enable(not isSimple)
289 self.switchToQuickprintMenuItem.Check()
291 self.switchToNormalMenuItem.Check()
293 # Set splitter sash position & size
295 # Save normal mode sash
296 self.normalSashPos = self.splitter.GetSashPosition()
298 # Change location of sash to width of quick mode pane
299 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
300 self.splitter.SetSashPosition(width, True)
303 self.splitter.SetSashSize(0)
305 self.splitter.SetSashPosition(self.normalSashPos, True)
307 self.splitter.SetSashSize(4)
308 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
309 self.scene.updateProfileToControls()
311 def OnPreferences(self, e):
312 prefDialog = preferencesDialog.preferencesDialog(self)
315 wx.CallAfter(prefDialog.Show)
317 def OnMachineSettings(self, e):
318 prefDialog = preferencesDialog.machineSettingsDialog(self)
322 def OnDropFiles(self, files):
324 profile.setPluginConfig([])
325 self.updateProfileToAllControls()
326 self.scene.loadFiles(files)
328 def OnModelMRU(self, e):
329 fileNum = e.GetId() - self.ID_MRU_MODEL1
330 path = self.modelFileHistory.GetHistoryFile(fileNum)
332 self.modelFileHistory.AddFileToHistory(path) # move up the list
333 self.config.SetPath("/ModelMRU")
334 self.modelFileHistory.Save(self.config)
337 profile.putPreference('lastFile', path)
339 self.scene.loadFiles(filelist)
341 def addToModelMRU(self, file):
342 self.modelFileHistory.AddFileToHistory(file)
343 self.config.SetPath("/ModelMRU")
344 self.modelFileHistory.Save(self.config)
347 def OnProfileMRU(self, e):
348 fileNum = e.GetId() - self.ID_MRU_PROFILE1
349 path = self.profileFileHistory.GetHistoryFile(fileNum)
351 self.profileFileHistory.AddFileToHistory(path) # move up the list
352 self.config.SetPath("/ProfileMRU")
353 self.profileFileHistory.Save(self.config)
356 profile.loadProfile(path)
357 self.updateProfileToAllControls()
359 def addToProfileMRU(self, file):
360 self.profileFileHistory.AddFileToHistory(file)
361 self.config.SetPath("/ProfileMRU")
362 self.profileFileHistory.Save(self.config)
365 def updateProfileToAllControls(self):
366 self.scene.updateProfileToControls()
367 self.normalSettingsPanel.updateProfileToControls()
368 self.simpleSettingsPanel.updateProfileToControls()
370 def reloadSettingPanels(self):
371 self.leftSizer.Detach(self.simpleSettingsPanel)
372 self.leftSizer.Detach(self.normalSettingsPanel)
373 self.simpleSettingsPanel.Destroy()
374 self.normalSettingsPanel.Destroy()
375 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
376 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
377 self.leftSizer.Add(self.simpleSettingsPanel, 1)
378 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
379 self.updateSliceMode()
380 self.updateProfileToAllControls()
382 def updateMachineMenu(self):
383 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
384 for item in self.machineMenu.GetMenuItems():
385 self.machineMenu.RemoveItem(item)
387 #Add a menu item for each machine configuration.
388 for n in xrange(0, profile.getMachineCount()):
389 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
390 if n == int(profile.getPreferenceFloat('active_machine')):
392 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
394 self.machineMenu.AppendSeparator()
395 i = self.machineMenu.Append(-1, _("Add new machine..."))
396 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
398 #Add tools for machines.
399 self.machineMenu.AppendSeparator()
401 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
402 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
404 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
405 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
407 def OnLoadProfile(self, e):
408 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)
409 dlg.SetWildcard("ini files (*.ini)|*.ini")
410 if dlg.ShowModal() == wx.ID_OK:
411 profileFile = dlg.GetPath()
412 profile.loadProfile(profileFile)
413 self.updateProfileToAllControls()
415 # Update the Profile MRU
416 self.addToProfileMRU(profileFile)
419 def OnLoadProfileFromGcode(self, e):
420 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)
421 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
422 if dlg.ShowModal() == wx.ID_OK:
423 gcodeFile = dlg.GetPath()
424 f = open(gcodeFile, 'r')
427 if line.startswith(';CURA_PROFILE_STRING:'):
428 profile.setProfileFromString(line[line.find(':')+1:].strip())
431 self.updateProfileToAllControls()
433 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)
436 def OnSaveProfile(self, e):
437 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
438 dlg.SetWildcard("ini files (*.ini)|*.ini")
439 if dlg.ShowModal() == wx.ID_OK:
440 profileFile = dlg.GetPath()
441 profile.saveProfile(profileFile)
444 def OnResetProfile(self, e):
445 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)
446 result = dlg.ShowModal() == wx.ID_YES
449 profile.resetProfile()
450 self.updateProfileToAllControls()
452 def OnSimpleSwitch(self, e):
453 profile.putPreference('startMode', 'Simple')
454 self.updateSliceMode()
456 def OnNormalSwitch(self, e):
457 profile.putPreference('startMode', 'Normal')
458 self.updateSliceMode()
460 def OnDefaultMarlinFirmware(self, e):
461 firmwareInstall.InstallFirmware()
463 def OnCustomFirmware(self, e):
464 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
465 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)
466 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
467 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
468 if dlg.ShowModal() == wx.ID_OK:
469 filename = dlg.GetPath()
470 if not(os.path.exists(filename)):
472 #For some reason my Ubuntu 10.10 crashes here.
473 firmwareInstall.InstallFirmware(filename)
475 def OnFirstRunWizard(self, e):
477 configWizard.configWizard()
479 self.reloadSettingPanels()
481 def OnAddNewMachine(self, e):
483 profile.setActiveMachine(profile.getMachineCount())
484 configWizard.configWizard(True)
486 self.reloadSettingPanels()
487 self.updateMachineMenu()
489 def OnSelectMachine(self, index):
490 profile.setActiveMachine(index)
491 self.reloadSettingPanels()
493 def OnBedLevelWizard(self, e):
494 configWizard.bedLevelWizard()
496 def OnHeadOffsetWizard(self, e):
497 configWizard.headOffsetWizard()
499 def OnExpertOpen(self, e):
500 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
504 def OnMinecraftImport(self, e):
505 mi = minecraftImport.minecraftImportWindow(self)
509 def OnPIDDebugger(self, e):
510 debugger = pidDebugger.debuggerWindow(self)
514 def onCopyProfileClipboard(self, e):
516 if not wx.TheClipboard.IsOpened():
517 wx.TheClipboard.Open()
518 clipData = wx.TextDataObject()
519 self.lastTriedClipboard = profile.getProfileString()
520 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
521 clipData.SetText(profileString)
522 wx.TheClipboard.SetData(clipData)
523 wx.TheClipboard.Close()
525 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
527 def OnCheckForUpdate(self, e):
528 newVersion = version.checkForNewerVersion()
529 if newVersion is not None:
530 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:
531 webbrowser.open(newVersion)
533 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
535 def OnAbout(self, e):
536 aboutBox = aboutWindow.aboutWindow()
540 def OnClose(self, e):
541 profile.saveProfile(profile.getDefaultProfilePath())
543 # Save the window position, size & state from the preferences file
544 profile.putPreference('window_maximized', self.IsMaximized())
545 if not self.IsMaximized() and not self.IsIconized():
546 (posx, posy) = self.GetPosition()
547 profile.putPreference('window_pos_x', posx)
548 profile.putPreference('window_pos_y', posy)
549 (width, height) = self.GetSize()
550 profile.putPreference('window_width', width)
551 profile.putPreference('window_height', height)
553 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
554 isSimple = profile.getPreference('startMode') == 'Simple'
556 self.normalSashPos = self.splitter.GetSashPosition()
557 profile.putPreference('window_normal_sash', self.normalSashPos)
559 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
561 self.scene.OnPaint = lambda e : e
562 self.scene._slicer.cleanup()
568 class normalSettingsPanel(configBase.configPanelBase):
569 "Main user interface window"
570 def __init__(self, parent, callback = None):
571 super(normalSettingsPanel, self).__init__(parent, callback)
574 self.nb = wx.Notebook(self)
575 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
576 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
578 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
579 self._addSettingsToPanels('basic', left, right)
580 self.SizeLabelWidths(left, right)
582 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
583 self._addSettingsToPanels('advanced', left, right)
584 self.SizeLabelWidths(left, right)
587 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
588 self.nb.AddPage(self.pluginPanel, _("Plugins"))
591 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
592 self.alterationPanel = None
594 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
595 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
597 self.Bind(wx.EVT_SIZE, self.OnSize)
599 self.nb.SetSize(self.GetSize())
600 self.UpdateSize(self.printPanel)
601 self.UpdateSize(self.advancedPanel)
603 def _addSettingsToPanels(self, category, left, right):
604 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
608 for title in profile.getSubCategoriesFor(category):
609 n += 1 + len(profile.getSettingsForCategory(category, title))
612 configBase.TitleRow(p, _(title))
613 for s in profile.getSettingsForCategory(category, title):
614 configBase.SettingRow(p, s.getName())
616 def SizeLabelWidths(self, left, right):
617 leftWidth = self.getLabelColumnWidth(left)
618 rightWidth = self.getLabelColumnWidth(right)
619 maxWidth = max(leftWidth, rightWidth)
620 self.setLabelColumnWidth(left, maxWidth)
621 self.setLabelColumnWidth(right, maxWidth)
624 # Make the size of the Notebook control the same size as this control
625 self.nb.SetSize(self.GetSize())
627 # Propegate the OnSize() event (just in case)
630 # Perform out resize magic
631 self.UpdateSize(self.printPanel)
632 self.UpdateSize(self.advancedPanel)
634 def UpdateSize(self, configPanel):
635 sizer = configPanel.GetSizer()
639 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
642 # if width(col1) > (best_width(col1) + best_width(col1)):
643 # switch to horizontal
646 col1 = configPanel.leftPanel
647 colSize1 = col1.GetSize()
648 colBestSize1 = col1.GetBestSize()
649 col2 = configPanel.rightPanel
650 colSize2 = col2.GetSize()
651 colBestSize2 = col2.GetBestSize()
653 orientation = sizer.GetOrientation()
655 if orientation == wx.HORIZONTAL:
656 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
658 sizer = wx.BoxSizer(wx.VERTICAL)
659 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
660 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
661 configPanel.SetSizer(sizer)
667 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
669 sizer = wx.BoxSizer(wx.HORIZONTAL)
670 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
671 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
672 configPanel.SetSizer(sizer)
678 def updateProfileToControls(self):
679 super(normalSettingsPanel, self).updateProfileToControls()
680 if self.alterationPanel is not None:
681 self.alterationPanel.updateProfileToControls()
682 self.pluginPanel.updateProfileToControls()