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()
114 i = toolsMenu.Append(-1, _("Switch to quickprint..."))
115 self.switchToQuickprintMenuItem = i
116 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
118 i = toolsMenu.Append(-1, _("Switch to full settings..."))
119 self.switchToNormalMenuItem = i
120 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
122 #toolsMenu.AppendSeparator()
123 #i = toolsMenu.Append(-1, 'Batch run...')
124 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
125 #self.normalModeOnlyItems.append(i)
127 if minecraftImport.hasMinecraft():
128 i = toolsMenu.Append(-1, _("Minecraft map import..."))
129 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
131 if version.isDevVersion():
132 i = toolsMenu.Append(-1, _("PID Debugger..."))
133 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
135 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
136 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
137 self.menubar.Append(toolsMenu, _("Tools"))
139 #Machine menu for machine configuration/tooling
140 self.machineMenu = wx.Menu()
141 self.updateMachineMenu()
143 self.menubar.Append(self.machineMenu, _("Machine"))
145 expertMenu = wx.Menu()
146 i = expertMenu.Append(-1, _("Open expert settings..."))
147 self.normalModeOnlyItems.append(i)
148 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
149 expertMenu.AppendSeparator()
150 i = expertMenu.Append(-1, _("Run first run wizard..."))
151 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
152 i = expertMenu.Append(-1, _("Run bed leveling wizard..."))
153 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
154 if self.extruderCount > 1:
155 i = expertMenu.Append(-1, _("Run head offset wizard..."))
156 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
158 self.menubar.Append(expertMenu, _("Expert"))
161 i = helpMenu.Append(-1, _("Online documentation..."))
162 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
163 i = helpMenu.Append(-1, _("Report a problem..."))
164 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
165 i = helpMenu.Append(-1, _("Check for update..."))
166 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
167 i = helpMenu.Append(-1, _("Open YouMagine website..."))
168 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
169 i = helpMenu.Append(-1, _("About Cura..."))
170 self.Bind(wx.EVT_MENU, self.OnAbout, i)
171 self.menubar.Append(helpMenu, _("Help"))
172 self.SetMenuBar(self.menubar)
174 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
175 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
176 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
177 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
180 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
181 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
183 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
184 self.leftSizer.Add(self.simpleSettingsPanel, 1)
185 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
186 self.leftPane.SetSizer(self.leftSizer)
189 self.scene = sceneView.SceneView(self.rightPane)
191 #Main sizer, to position the preview window, buttons and tab control
192 sizer = wx.BoxSizer()
193 self.rightPane.SetSizer(sizer)
194 sizer.Add(self.scene, 1, flag=wx.EXPAND)
197 sizer = wx.BoxSizer(wx.VERTICAL)
199 sizer.Add(self.splitter, 1, wx.EXPAND)
203 self.updateProfileToAllControls()
205 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
207 self.simpleSettingsPanel.Show(False)
208 self.normalSettingsPanel.Show(False)
210 # Set default window size & position
211 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
214 #Timer set; used to check if profile is on the clipboard
215 self.timer = wx.Timer(self)
216 self.Bind(wx.EVT_TIMER, self.onTimer)
217 self.timer.Start(1000)
218 self.lastTriedClipboard = profile.getProfileString()
220 # Restore the window position, size & state from the preferences file
222 if profile.getPreference('window_maximized') == 'True':
225 posx = int(profile.getPreference('window_pos_x'))
226 posy = int(profile.getPreference('window_pos_y'))
227 width = int(profile.getPreference('window_width'))
228 height = int(profile.getPreference('window_height'))
229 if posx > 0 or posy > 0:
230 self.SetPosition((posx,posy))
231 if width > 0 and height > 0:
232 self.SetSize((width,height))
234 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
236 self.normalSashPos = 0
238 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
239 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
241 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
243 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
245 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
247 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
248 self.SetSize((800,600))
251 self.updateSliceMode()
253 def onTimer(self, e):
254 #Check if there is something in the clipboard
257 if not wx.TheClipboard.IsOpened():
258 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)
288 self.switchToQuickprintMenuItem.Enable(not isSimple)
289 self.switchToNormalMenuItem.Enable(isSimple)
291 # Set splitter sash position & size
293 # Save normal mode sash
294 self.normalSashPos = self.splitter.GetSashPosition()
296 # Change location of sash to width of quick mode pane
297 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
298 self.splitter.SetSashPosition(width, True)
301 self.splitter.SetSashSize(0)
303 self.splitter.SetSashPosition(self.normalSashPos, True)
305 self.splitter.SetSashSize(4)
306 self.scene.updateProfileToControls()
308 def OnPreferences(self, e):
309 prefDialog = preferencesDialog.preferencesDialog(self)
312 wx.CallAfter(prefDialog.Show)
314 def OnMachineSettings(self, e):
315 prefDialog = preferencesDialog.machineSettingsDialog(self)
319 def OnDropFiles(self, files):
321 profile.setPluginConfig([])
322 self.updateProfileToAllControls()
323 self.scene.loadFiles(files)
325 def OnModelMRU(self, e):
326 fileNum = e.GetId() - self.ID_MRU_MODEL1
327 path = self.modelFileHistory.GetHistoryFile(fileNum)
329 self.modelFileHistory.AddFileToHistory(path) # move up the list
330 self.config.SetPath("/ModelMRU")
331 self.modelFileHistory.Save(self.config)
334 profile.putPreference('lastFile', path)
336 self.scene.loadFiles(filelist)
338 def addToModelMRU(self, file):
339 self.modelFileHistory.AddFileToHistory(file)
340 self.config.SetPath("/ModelMRU")
341 self.modelFileHistory.Save(self.config)
344 def OnProfileMRU(self, e):
345 fileNum = e.GetId() - self.ID_MRU_PROFILE1
346 path = self.profileFileHistory.GetHistoryFile(fileNum)
348 self.profileFileHistory.AddFileToHistory(path) # move up the list
349 self.config.SetPath("/ProfileMRU")
350 self.profileFileHistory.Save(self.config)
353 profile.loadProfile(path)
354 self.updateProfileToAllControls()
356 def addToProfileMRU(self, file):
357 self.profileFileHistory.AddFileToHistory(file)
358 self.config.SetPath("/ProfileMRU")
359 self.profileFileHistory.Save(self.config)
362 def updateProfileToAllControls(self):
363 self.scene.updateProfileToControls()
364 self.normalSettingsPanel.updateProfileToControls()
365 self.simpleSettingsPanel.updateProfileToControls()
367 def reloadSettingPanels(self):
368 self.leftSizer.Detach(self.simpleSettingsPanel)
369 self.leftSizer.Detach(self.normalSettingsPanel)
370 self.simpleSettingsPanel.Destroy()
371 self.normalSettingsPanel.Destroy()
372 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
373 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
374 self.leftSizer.Add(self.simpleSettingsPanel, 1)
375 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
376 self.updateSliceMode()
377 self.updateProfileToAllControls()
379 def updateMachineMenu(self):
380 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
381 for item in self.machineMenu.GetMenuItems():
382 self.machineMenu.RemoveItem(item)
384 #Add a menu item for each machine configuration.
385 for n in xrange(0, profile.getMachineCount()):
386 i = self.machineMenu.Append(n, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
387 if n == int(profile.getPreferenceFloat('active_machine')):
389 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId()), i)
391 self.machineMenu.AppendSeparator()
392 i = self.machineMenu.Append(-1, _("Add new machine..."))
393 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
395 #Add tools for machines.
396 self.machineMenu.AppendSeparator()
397 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
398 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
399 i = self.machineMenu.Append(-1, _("Install default Marlin firmware..."))
400 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
402 def OnLoadProfile(self, e):
403 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)
404 dlg.SetWildcard("ini files (*.ini)|*.ini")
405 if dlg.ShowModal() == wx.ID_OK:
406 profileFile = dlg.GetPath()
407 profile.loadProfile(profileFile)
408 self.updateProfileToAllControls()
410 # Update the Profile MRU
411 self.addToProfileMRU(profileFile)
414 def OnLoadProfileFromGcode(self, e):
415 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)
416 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
417 if dlg.ShowModal() == wx.ID_OK:
418 gcodeFile = dlg.GetPath()
419 f = open(gcodeFile, 'r')
422 if line.startswith(';CURA_PROFILE_STRING:'):
423 profile.setProfileFromString(line[line.find(':')+1:].strip())
426 self.updateProfileToAllControls()
428 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)
431 def OnSaveProfile(self, e):
432 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
433 dlg.SetWildcard("ini files (*.ini)|*.ini")
434 if dlg.ShowModal() == wx.ID_OK:
435 profileFile = dlg.GetPath()
436 profile.saveProfile(profileFile)
439 def OnResetProfile(self, e):
440 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)
441 result = dlg.ShowModal() == wx.ID_YES
444 profile.resetProfile()
445 self.updateProfileToAllControls()
447 def OnSimpleSwitch(self, e):
448 profile.putPreference('startMode', 'Simple')
449 self.updateSliceMode()
451 def OnNormalSwitch(self, e):
452 profile.putPreference('startMode', 'Normal')
453 self.updateSliceMode()
455 def OnDefaultMarlinFirmware(self, e):
456 firmwareInstall.InstallFirmware()
458 def OnCustomFirmware(self, e):
459 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
460 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)
461 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
462 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
463 if dlg.ShowModal() == wx.ID_OK:
464 filename = dlg.GetPath()
465 if not(os.path.exists(filename)):
467 #For some reason my Ubuntu 10.10 crashes here.
468 firmwareInstall.InstallFirmware(filename)
470 def OnFirstRunWizard(self, e):
472 configWizard.configWizard()
474 self.reloadSettingPanels()
476 def OnAddNewMachine(self, e):
478 profile.setActiveMachine(profile.getMachineCount())
479 configWizard.configWizard(True)
481 self.reloadSettingPanels()
482 self.updateMachineMenu()
484 def OnSelectMachine(self, index):
485 profile.setActiveMachine(index)
486 self.reloadSettingPanels()
488 def OnBedLevelWizard(self, e):
489 configWizard.bedLevelWizard()
491 def OnHeadOffsetWizard(self, e):
492 configWizard.headOffsetWizard()
494 def OnExpertOpen(self, e):
495 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
499 def OnMinecraftImport(self, e):
500 mi = minecraftImport.minecraftImportWindow(self)
504 def OnPIDDebugger(self, e):
505 debugger = pidDebugger.debuggerWindow(self)
509 def onCopyProfileClipboard(self, e):
511 if not wx.TheClipboard.IsOpened():
512 wx.TheClipboard.Open()
513 clipData = wx.TextDataObject()
514 self.lastTriedClipboard = profile.getProfileString()
515 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
516 clipData.SetText(profileString)
517 wx.TheClipboard.SetData(clipData)
518 wx.TheClipboard.Close()
520 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
522 def OnCheckForUpdate(self, e):
523 newVersion = version.checkForNewerVersion()
524 if newVersion is not None:
525 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:
526 webbrowser.open(newVersion)
528 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
530 def OnAbout(self, e):
531 aboutBox = aboutWindow.aboutWindow()
535 def OnClose(self, e):
536 profile.saveProfile(profile.getDefaultProfilePath())
538 # Save the window position, size & state from the preferences file
539 profile.putPreference('window_maximized', self.IsMaximized())
540 if not self.IsMaximized() and not self.IsIconized():
541 (posx, posy) = self.GetPosition()
542 profile.putPreference('window_pos_x', posx)
543 profile.putPreference('window_pos_y', posy)
544 (width, height) = self.GetSize()
545 profile.putPreference('window_width', width)
546 profile.putPreference('window_height', height)
548 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
549 isSimple = profile.getPreference('startMode') == 'Simple'
551 self.normalSashPos = self.splitter.GetSashPosition()
552 profile.putPreference('window_normal_sash', self.normalSashPos)
554 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
556 self.scene.OnPaint = lambda e : e
557 self.scene._slicer.cleanup()
563 class normalSettingsPanel(configBase.configPanelBase):
564 "Main user interface window"
565 def __init__(self, parent, callback = None):
566 super(normalSettingsPanel, self).__init__(parent, callback)
569 self.nb = wx.Notebook(self)
570 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
571 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
573 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
574 self._addSettingsToPanels('basic', left, right)
575 self.SizeLabelWidths(left, right)
577 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
578 self._addSettingsToPanels('advanced', left, right)
579 self.SizeLabelWidths(left, right)
582 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
583 if len(self.pluginPanel.pluginList) > 0:
584 self.nb.AddPage(self.pluginPanel, _("Plugins"))
586 self.pluginPanel.Show(False)
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()