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.scene.updateProfileToControls()
309 def OnPreferences(self, e):
310 prefDialog = preferencesDialog.preferencesDialog(self)
313 wx.CallAfter(prefDialog.Show)
315 def OnMachineSettings(self, e):
316 prefDialog = preferencesDialog.machineSettingsDialog(self)
320 def OnDropFiles(self, files):
322 profile.setPluginConfig([])
323 self.updateProfileToAllControls()
324 self.scene.loadFiles(files)
326 def OnModelMRU(self, e):
327 fileNum = e.GetId() - self.ID_MRU_MODEL1
328 path = self.modelFileHistory.GetHistoryFile(fileNum)
330 self.modelFileHistory.AddFileToHistory(path) # move up the list
331 self.config.SetPath("/ModelMRU")
332 self.modelFileHistory.Save(self.config)
335 profile.putPreference('lastFile', path)
337 self.scene.loadFiles(filelist)
339 def addToModelMRU(self, file):
340 self.modelFileHistory.AddFileToHistory(file)
341 self.config.SetPath("/ModelMRU")
342 self.modelFileHistory.Save(self.config)
345 def OnProfileMRU(self, e):
346 fileNum = e.GetId() - self.ID_MRU_PROFILE1
347 path = self.profileFileHistory.GetHistoryFile(fileNum)
349 self.profileFileHistory.AddFileToHistory(path) # move up the list
350 self.config.SetPath("/ProfileMRU")
351 self.profileFileHistory.Save(self.config)
354 profile.loadProfile(path)
355 self.updateProfileToAllControls()
357 def addToProfileMRU(self, file):
358 self.profileFileHistory.AddFileToHistory(file)
359 self.config.SetPath("/ProfileMRU")
360 self.profileFileHistory.Save(self.config)
363 def updateProfileToAllControls(self):
364 self.scene.updateProfileToControls()
365 self.normalSettingsPanel.updateProfileToControls()
366 self.simpleSettingsPanel.updateProfileToControls()
368 def reloadSettingPanels(self):
369 self.leftSizer.Detach(self.simpleSettingsPanel)
370 self.leftSizer.Detach(self.normalSettingsPanel)
371 self.simpleSettingsPanel.Destroy()
372 self.normalSettingsPanel.Destroy()
373 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
374 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
375 self.leftSizer.Add(self.simpleSettingsPanel, 1)
376 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
377 self.updateSliceMode()
378 self.updateProfileToAllControls()
380 def updateMachineMenu(self):
381 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
382 for item in self.machineMenu.GetMenuItems():
383 self.machineMenu.RemoveItem(item)
385 #Add a menu item for each machine configuration.
386 for n in xrange(0, profile.getMachineCount()):
387 i = self.machineMenu.Append(n, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
388 if n == int(profile.getPreferenceFloat('active_machine')):
390 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId()), i)
392 self.machineMenu.AppendSeparator()
393 i = self.machineMenu.Append(-1, _("Add new machine..."))
394 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
396 #Add tools for machines.
397 self.machineMenu.AppendSeparator()
398 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
399 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
400 i = self.machineMenu.Append(-1, _("Install default Marlin firmware..."))
401 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
403 def OnLoadProfile(self, e):
404 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)
405 dlg.SetWildcard("ini files (*.ini)|*.ini")
406 if dlg.ShowModal() == wx.ID_OK:
407 profileFile = dlg.GetPath()
408 profile.loadProfile(profileFile)
409 self.updateProfileToAllControls()
411 # Update the Profile MRU
412 self.addToProfileMRU(profileFile)
415 def OnLoadProfileFromGcode(self, e):
416 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)
417 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
418 if dlg.ShowModal() == wx.ID_OK:
419 gcodeFile = dlg.GetPath()
420 f = open(gcodeFile, 'r')
423 if line.startswith(';CURA_PROFILE_STRING:'):
424 profile.setProfileFromString(line[line.find(':')+1:].strip())
427 self.updateProfileToAllControls()
429 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)
432 def OnSaveProfile(self, e):
433 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
434 dlg.SetWildcard("ini files (*.ini)|*.ini")
435 if dlg.ShowModal() == wx.ID_OK:
436 profileFile = dlg.GetPath()
437 profile.saveProfile(profileFile)
440 def OnResetProfile(self, e):
441 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)
442 result = dlg.ShowModal() == wx.ID_YES
445 profile.resetProfile()
446 self.updateProfileToAllControls()
448 def OnSimpleSwitch(self, e):
449 profile.putPreference('startMode', 'Simple')
450 self.updateSliceMode()
452 def OnNormalSwitch(self, e):
453 profile.putPreference('startMode', 'Normal')
454 self.updateSliceMode()
456 def OnDefaultMarlinFirmware(self, e):
457 firmwareInstall.InstallFirmware()
459 def OnCustomFirmware(self, e):
460 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
461 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)
462 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
463 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
464 if dlg.ShowModal() == wx.ID_OK:
465 filename = dlg.GetPath()
466 if not(os.path.exists(filename)):
468 #For some reason my Ubuntu 10.10 crashes here.
469 firmwareInstall.InstallFirmware(filename)
471 def OnFirstRunWizard(self, e):
473 configWizard.configWizard()
475 self.reloadSettingPanels()
477 def OnAddNewMachine(self, e):
479 profile.setActiveMachine(profile.getMachineCount())
480 configWizard.configWizard(True)
482 self.reloadSettingPanels()
483 self.updateMachineMenu()
485 def OnSelectMachine(self, index):
486 profile.setActiveMachine(index)
487 self.reloadSettingPanels()
489 def OnBedLevelWizard(self, e):
490 configWizard.bedLevelWizard()
492 def OnHeadOffsetWizard(self, e):
493 configWizard.headOffsetWizard()
495 def OnExpertOpen(self, e):
496 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
500 def OnMinecraftImport(self, e):
501 mi = minecraftImport.minecraftImportWindow(self)
505 def OnPIDDebugger(self, e):
506 debugger = pidDebugger.debuggerWindow(self)
510 def onCopyProfileClipboard(self, e):
512 if not wx.TheClipboard.IsOpened():
513 wx.TheClipboard.Open()
514 clipData = wx.TextDataObject()
515 self.lastTriedClipboard = profile.getProfileString()
516 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
517 clipData.SetText(profileString)
518 wx.TheClipboard.SetData(clipData)
519 wx.TheClipboard.Close()
521 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
523 def OnCheckForUpdate(self, e):
524 newVersion = version.checkForNewerVersion()
525 if newVersion is not None:
526 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:
527 webbrowser.open(newVersion)
529 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
531 def OnAbout(self, e):
532 aboutBox = aboutWindow.aboutWindow()
536 def OnClose(self, e):
537 profile.saveProfile(profile.getDefaultProfilePath())
539 # Save the window position, size & state from the preferences file
540 profile.putPreference('window_maximized', self.IsMaximized())
541 if not self.IsMaximized() and not self.IsIconized():
542 (posx, posy) = self.GetPosition()
543 profile.putPreference('window_pos_x', posx)
544 profile.putPreference('window_pos_y', posy)
545 (width, height) = self.GetSize()
546 profile.putPreference('window_width', width)
547 profile.putPreference('window_height', height)
549 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
550 isSimple = profile.getPreference('startMode') == 'Simple'
552 self.normalSashPos = self.splitter.GetSashPosition()
553 profile.putPreference('window_normal_sash', self.normalSashPos)
555 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
557 self.scene.OnPaint = lambda e : e
558 self.scene._slicer.cleanup()
564 class normalSettingsPanel(configBase.configPanelBase):
565 "Main user interface window"
566 def __init__(self, parent, callback = None):
567 super(normalSettingsPanel, self).__init__(parent, callback)
570 self.nb = wx.Notebook(self)
571 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
572 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
574 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
575 self._addSettingsToPanels('basic', left, right)
576 self.SizeLabelWidths(left, right)
578 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
579 self._addSettingsToPanels('advanced', left, right)
580 self.SizeLabelWidths(left, right)
583 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
584 self.nb.AddPage(self.pluginPanel, _("Plugins"))
587 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
588 self.alterationPanel = None
590 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
591 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
593 self.Bind(wx.EVT_SIZE, self.OnSize)
595 self.nb.SetSize(self.GetSize())
596 self.UpdateSize(self.printPanel)
597 self.UpdateSize(self.advancedPanel)
599 def _addSettingsToPanels(self, category, left, right):
600 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
604 for title in profile.getSubCategoriesFor(category):
605 n += 1 + len(profile.getSettingsForCategory(category, title))
608 configBase.TitleRow(p, _(title))
609 for s in profile.getSettingsForCategory(category, title):
610 configBase.SettingRow(p, s.getName())
612 def SizeLabelWidths(self, left, right):
613 leftWidth = self.getLabelColumnWidth(left)
614 rightWidth = self.getLabelColumnWidth(right)
615 maxWidth = max(leftWidth, rightWidth)
616 self.setLabelColumnWidth(left, maxWidth)
617 self.setLabelColumnWidth(right, maxWidth)
620 # Make the size of the Notebook control the same size as this control
621 self.nb.SetSize(self.GetSize())
623 # Propegate the OnSize() event (just in case)
626 # Perform out resize magic
627 self.UpdateSize(self.printPanel)
628 self.UpdateSize(self.advancedPanel)
630 def UpdateSize(self, configPanel):
631 sizer = configPanel.GetSizer()
635 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
638 # if width(col1) > (best_width(col1) + best_width(col1)):
639 # switch to horizontal
642 col1 = configPanel.leftPanel
643 colSize1 = col1.GetSize()
644 colBestSize1 = col1.GetBestSize()
645 col2 = configPanel.rightPanel
646 colSize2 = col2.GetSize()
647 colBestSize2 = col2.GetBestSize()
649 orientation = sizer.GetOrientation()
651 if orientation == wx.HORIZONTAL:
652 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
654 sizer = wx.BoxSizer(wx.VERTICAL)
655 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
656 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
657 configPanel.SetSizer(sizer)
663 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
665 sizer = wx.BoxSizer(wx.HORIZONTAL)
666 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
667 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
668 configPanel.SetSizer(sizer)
674 def updateProfileToControls(self):
675 super(normalSettingsPanel, self).updateProfileToControls()
676 if self.alterationPanel is not None:
677 self.alterationPanel.updateProfileToControls()
678 self.pluginPanel.updateProfileToControls()