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 wx.EVT_CLOSE(self, self.OnClose)
32 # allow dropping any file, restrict later
33 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles))
35 self.normalModeOnlyItems = []
37 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
38 self.config = wx.FileConfig(appName="Cura",
39 localFilename=mruFile,
40 style=wx.CONFIG_USE_LOCAL_FILE)
42 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)]
43 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
44 self.config.SetPath("/ModelMRU")
45 self.modelFileHistory.Load(self.config)
47 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)]
48 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
49 self.config.SetPath("/ProfileMRU")
50 self.profileFileHistory.Load(self.config)
52 self.menubar = wx.MenuBar()
53 self.fileMenu = wx.Menu()
54 i = self.fileMenu.Append(-1, _("Load model file...\tCTRL+L"))
55 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
56 i = self.fileMenu.Append(-1, _("Save model...\tCTRL+S"))
57 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
58 i = self.fileMenu.Append(-1, _("Clear platform"))
59 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
61 self.fileMenu.AppendSeparator()
62 i = self.fileMenu.Append(-1, _("Print...\tCTRL+P"))
63 self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
64 i = self.fileMenu.Append(-1, _("Save GCode..."))
65 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
66 i = self.fileMenu.Append(-1, _("Show slice engine log..."))
67 self.Bind(wx.EVT_MENU, lambda e: self.scene._showSliceLog(), i)
69 self.fileMenu.AppendSeparator()
70 i = self.fileMenu.Append(-1, _("Open Profile..."))
71 self.normalModeOnlyItems.append(i)
72 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
73 i = self.fileMenu.Append(-1, _("Save Profile..."))
74 self.normalModeOnlyItems.append(i)
75 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
76 i = self.fileMenu.Append(-1, _("Load Profile from GCode..."))
77 self.normalModeOnlyItems.append(i)
78 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
79 self.fileMenu.AppendSeparator()
80 i = self.fileMenu.Append(-1, _("Reset Profile to default"))
81 self.normalModeOnlyItems.append(i)
82 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
84 self.fileMenu.AppendSeparator()
85 i = self.fileMenu.Append(-1, _("Preferences...\tCTRL+,"))
86 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
87 i = self.fileMenu.Append(-1, _("Machine settings..."))
88 self.Bind(wx.EVT_MENU, self.OnMachineSettings, i)
89 self.fileMenu.AppendSeparator()
92 modelHistoryMenu = wx.Menu()
93 self.fileMenu.AppendMenu(wx.NewId(), '&' + _("Recent Model Files"), modelHistoryMenu)
94 self.modelFileHistory.UseMenu(modelHistoryMenu)
95 self.modelFileHistory.AddFilesToMenu()
96 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
99 profileHistoryMenu = wx.Menu()
100 self.fileMenu.AppendMenu(wx.NewId(), _("Recent Profile Files"), profileHistoryMenu)
101 self.profileFileHistory.UseMenu(profileHistoryMenu)
102 self.profileFileHistory.AddFilesToMenu()
103 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
105 self.fileMenu.AppendSeparator()
106 i = self.fileMenu.Append(wx.ID_EXIT, _("Quit"))
107 self.Bind(wx.EVT_MENU, self.OnQuit, i)
108 self.menubar.Append(self.fileMenu, '&' + _("File"))
110 toolsMenu = wx.Menu()
111 #i = toolsMenu.Append(-1, 'Batch run...')
112 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
113 #self.normalModeOnlyItems.append(i)
115 if minecraftImport.hasMinecraft():
116 i = toolsMenu.Append(-1, _("Minecraft map import..."))
117 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
119 if version.isDevVersion():
120 i = toolsMenu.Append(-1, _("PID Debugger..."))
121 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
123 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
124 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
125 self.menubar.Append(toolsMenu, _("Tools"))
127 #Machine menu for machine configuration/tooling
128 self.machineMenu = wx.Menu()
129 self.updateMachineMenu()
131 self.menubar.Append(self.machineMenu, _("Machine"))
133 expertMenu = wx.Menu()
134 i = expertMenu.Append(-1, _("Switch to quickprint..."), kind=wx.ITEM_RADIO)
135 self.switchToQuickprintMenuItem = i
136 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
138 i = expertMenu.Append(-1, _("Switch to full settings..."), kind=wx.ITEM_RADIO)
139 self.switchToNormalMenuItem = i
140 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
141 expertMenu.AppendSeparator()
143 i = expertMenu.Append(-1, _("Open expert settings...\tCTRL+E"))
144 self.normalModeOnlyItems.append(i)
145 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
146 expertMenu.AppendSeparator()
147 i = expertMenu.Append(-1, _("Run first run wizard..."))
148 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
149 self.bedLevelWizardMenuItem = expertMenu.Append(-1, _("Run bed leveling wizard..."))
150 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, self.bedLevelWizardMenuItem)
151 self.headOffsetWizardMenuItem = expertMenu.Append(-1, _("Run head offset wizard..."))
152 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, self.headOffsetWizardMenuItem)
154 self.menubar.Append(expertMenu, _("Expert"))
157 i = helpMenu.Append(-1, _("Online documentation..."))
158 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
159 i = helpMenu.Append(-1, _("Report a problem..."))
160 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
161 i = helpMenu.Append(-1, _("Check for update..."))
162 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
163 i = helpMenu.Append(-1, _("Open YouMagine website..."))
164 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
165 i = helpMenu.Append(-1, _("About Cura..."))
166 self.Bind(wx.EVT_MENU, self.OnAbout, i)
167 self.menubar.Append(helpMenu, _("Help"))
168 self.SetMenuBar(self.menubar)
170 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
171 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
172 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
173 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
176 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
177 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
179 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
180 self.leftSizer.Add(self.simpleSettingsPanel, 1)
181 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
182 self.leftPane.SetSizer(self.leftSizer)
185 self.scene = sceneView.SceneView(self.rightPane)
187 #Main sizer, to position the preview window, buttons and tab control
188 sizer = wx.BoxSizer()
189 self.rightPane.SetSizer(sizer)
190 sizer.Add(self.scene, 1, flag=wx.EXPAND)
193 sizer = wx.BoxSizer(wx.VERTICAL)
195 sizer.Add(self.splitter, 1, wx.EXPAND)
199 self.updateProfileToAllControls()
201 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
203 self.simpleSettingsPanel.Show(False)
204 self.normalSettingsPanel.Show(False)
206 # Set default window size & position
207 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
210 #Timer set; used to check if profile is on the clipboard
211 self.timer = wx.Timer(self)
212 self.Bind(wx.EVT_TIMER, self.onTimer)
213 self.timer.Start(1000)
214 self.lastTriedClipboard = profile.getProfileString()
216 # Restore the window position, size & state from the preferences file
218 if profile.getPreference('window_maximized') == 'True':
221 posx = int(profile.getPreference('window_pos_x'))
222 posy = int(profile.getPreference('window_pos_y'))
223 width = int(profile.getPreference('window_width'))
224 height = int(profile.getPreference('window_height'))
225 if posx > 0 or posy > 0:
226 self.SetPosition((posx,posy))
227 if width > 0 and height > 0:
228 self.SetSize((width,height))
230 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
232 self.normalSashPos = 0
234 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
235 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
237 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
239 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
241 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
243 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
244 self.SetSize((800,600))
247 self.updateSliceMode()
249 def onTimer(self, e):
250 #Check if there is something in the clipboard
253 if not wx.TheClipboard.IsOpened():
254 if not wx.TheClipboard.Open():
256 do = wx.TextDataObject()
257 if wx.TheClipboard.GetData(do):
258 profileString = do.GetText()
259 wx.TheClipboard.Close()
261 startTag = "CURA_PROFILE_STRING:"
262 if startTag in profileString:
263 #print "Found correct syntax on clipboard"
264 profileString = profileString.replace("\n","").strip()
265 profileString = profileString[profileString.find(startTag)+len(startTag):]
266 if profileString != self.lastTriedClipboard:
268 self.lastTriedClipboard = profileString
269 profile.setProfileFromString(profileString)
270 self.scene.notification.message("Loaded new profile from clipboard.")
271 self.updateProfileToAllControls()
273 print "Unable to read from clipboard"
276 def updateSliceMode(self):
277 isSimple = profile.getPreference('startMode') == 'Simple'
279 self.normalSettingsPanel.Show(not isSimple)
280 self.simpleSettingsPanel.Show(isSimple)
281 self.leftPane.Layout()
283 for i in self.normalModeOnlyItems:
284 i.Enable(not isSimple)
286 self.switchToQuickprintMenuItem.Check()
288 self.switchToNormalMenuItem.Check()
290 # Set splitter sash position & size
292 # Save normal mode sash
293 self.normalSashPos = self.splitter.GetSashPosition()
295 # Change location of sash to width of quick mode pane
296 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
297 self.splitter.SetSashPosition(width, True)
300 self.splitter.SetSashSize(0)
302 self.splitter.SetSashPosition(self.normalSashPos, True)
304 self.splitter.SetSashSize(4)
305 self.defaultFirmwareInstallMenuItem.Enable(firmwareInstall.getDefaultFirmware() is not None)
306 if profile.getMachineSetting('machine_type') == 'ultimaker2':
307 self.bedLevelWizardMenuItem.Enable(False)
308 self.headOffsetWizardMenuItem.Enable(False)
309 if int(profile.getMachineSetting('extruder_amount')) < 2:
310 self.headOffsetWizardMenuItem.Enable(False)
311 self.scene.updateProfileToControls()
313 def OnPreferences(self, e):
314 prefDialog = preferencesDialog.preferencesDialog(self)
317 wx.CallAfter(prefDialog.Show)
319 def OnMachineSettings(self, e):
320 prefDialog = preferencesDialog.machineSettingsDialog(self)
324 def OnDropFiles(self, files):
326 profile.setPluginConfig([])
327 self.updateProfileToAllControls()
328 self.scene.loadFiles(files)
330 def OnModelMRU(self, e):
331 fileNum = e.GetId() - self.ID_MRU_MODEL1
332 path = self.modelFileHistory.GetHistoryFile(fileNum)
334 self.modelFileHistory.AddFileToHistory(path) # move up the list
335 self.config.SetPath("/ModelMRU")
336 self.modelFileHistory.Save(self.config)
339 profile.putPreference('lastFile', path)
341 self.scene.loadFiles(filelist)
343 def addToModelMRU(self, file):
344 self.modelFileHistory.AddFileToHistory(file)
345 self.config.SetPath("/ModelMRU")
346 self.modelFileHistory.Save(self.config)
349 def OnProfileMRU(self, e):
350 fileNum = e.GetId() - self.ID_MRU_PROFILE1
351 path = self.profileFileHistory.GetHistoryFile(fileNum)
353 self.profileFileHistory.AddFileToHistory(path) # move up the list
354 self.config.SetPath("/ProfileMRU")
355 self.profileFileHistory.Save(self.config)
358 profile.loadProfile(path)
359 self.updateProfileToAllControls()
361 def addToProfileMRU(self, file):
362 self.profileFileHistory.AddFileToHistory(file)
363 self.config.SetPath("/ProfileMRU")
364 self.profileFileHistory.Save(self.config)
367 def updateProfileToAllControls(self):
368 self.scene.updateProfileToControls()
369 self.normalSettingsPanel.updateProfileToControls()
370 self.simpleSettingsPanel.updateProfileToControls()
372 def reloadSettingPanels(self):
373 self.leftSizer.Detach(self.simpleSettingsPanel)
374 self.leftSizer.Detach(self.normalSettingsPanel)
375 self.simpleSettingsPanel.Destroy()
376 self.normalSettingsPanel.Destroy()
377 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
378 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
379 self.leftSizer.Add(self.simpleSettingsPanel, 1)
380 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
381 self.updateSliceMode()
382 self.updateProfileToAllControls()
384 def updateMachineMenu(self):
385 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
386 for item in self.machineMenu.GetMenuItems():
387 self.machineMenu.RemoveItem(item)
389 #Add a menu item for each machine configuration.
390 for n in xrange(0, profile.getMachineCount()):
391 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
392 if n == int(profile.getPreferenceFloat('active_machine')):
394 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
396 self.machineMenu.AppendSeparator()
397 i = self.machineMenu.Append(-1, _("Add new machine..."))
398 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
400 #Add tools for machines.
401 self.machineMenu.AppendSeparator()
403 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
404 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
406 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
407 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
409 def OnLoadProfile(self, e):
410 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)
411 dlg.SetWildcard("ini files (*.ini)|*.ini")
412 if dlg.ShowModal() == wx.ID_OK:
413 profileFile = dlg.GetPath()
414 profile.loadProfile(profileFile)
415 self.updateProfileToAllControls()
417 # Update the Profile MRU
418 self.addToProfileMRU(profileFile)
421 def OnLoadProfileFromGcode(self, e):
422 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)
423 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
424 if dlg.ShowModal() == wx.ID_OK:
425 gcodeFile = dlg.GetPath()
426 f = open(gcodeFile, 'r')
429 if line.startswith(';CURA_PROFILE_STRING:'):
430 profile.setProfileFromString(line[line.find(':')+1:].strip())
433 self.updateProfileToAllControls()
435 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)
438 def OnSaveProfile(self, e):
439 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
440 dlg.SetWildcard("ini files (*.ini)|*.ini")
441 if dlg.ShowModal() == wx.ID_OK:
442 profileFile = dlg.GetPath()
443 profile.saveProfile(profileFile)
446 def OnResetProfile(self, e):
447 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)
448 result = dlg.ShowModal() == wx.ID_YES
451 profile.resetProfile()
452 self.updateProfileToAllControls()
454 def OnSimpleSwitch(self, e):
455 profile.putPreference('startMode', 'Simple')
456 self.updateSliceMode()
458 def OnNormalSwitch(self, e):
459 profile.putPreference('startMode', 'Normal')
460 self.updateSliceMode()
462 def OnDefaultMarlinFirmware(self, e):
463 firmwareInstall.InstallFirmware()
465 def OnCustomFirmware(self, e):
466 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
467 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)
468 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
469 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
470 if dlg.ShowModal() == wx.ID_OK:
471 filename = dlg.GetPath()
472 if not(os.path.exists(filename)):
474 #For some reason my Ubuntu 10.10 crashes here.
475 firmwareInstall.InstallFirmware(filename)
477 def OnFirstRunWizard(self, e):
479 configWizard.configWizard()
481 self.reloadSettingPanels()
483 def OnAddNewMachine(self, e):
485 profile.setActiveMachine(profile.getMachineCount())
486 configWizard.configWizard(True)
488 self.reloadSettingPanels()
489 self.updateMachineMenu()
491 def OnSelectMachine(self, index):
492 profile.setActiveMachine(index)
493 self.reloadSettingPanels()
495 def OnBedLevelWizard(self, e):
496 configWizard.bedLevelWizard()
498 def OnHeadOffsetWizard(self, e):
499 configWizard.headOffsetWizard()
501 def OnExpertOpen(self, e):
502 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
506 def OnMinecraftImport(self, e):
507 mi = minecraftImport.minecraftImportWindow(self)
511 def OnPIDDebugger(self, e):
512 debugger = pidDebugger.debuggerWindow(self)
516 def onCopyProfileClipboard(self, e):
518 if not wx.TheClipboard.IsOpened():
519 wx.TheClipboard.Open()
520 clipData = wx.TextDataObject()
521 self.lastTriedClipboard = profile.getProfileString()
522 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
523 clipData.SetText(profileString)
524 wx.TheClipboard.SetData(clipData)
525 wx.TheClipboard.Close()
527 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
529 def OnCheckForUpdate(self, e):
530 newVersion = version.checkForNewerVersion()
531 if newVersion is not None:
532 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:
533 webbrowser.open(newVersion)
535 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
537 def OnAbout(self, e):
538 aboutBox = aboutWindow.aboutWindow()
542 def OnClose(self, e):
543 profile.saveProfile(profile.getDefaultProfilePath())
545 # Save the window position, size & state from the preferences file
546 profile.putPreference('window_maximized', self.IsMaximized())
547 if not self.IsMaximized() and not self.IsIconized():
548 (posx, posy) = self.GetPosition()
549 profile.putPreference('window_pos_x', posx)
550 profile.putPreference('window_pos_y', posy)
551 (width, height) = self.GetSize()
552 profile.putPreference('window_width', width)
553 profile.putPreference('window_height', height)
555 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
556 isSimple = profile.getPreference('startMode') == 'Simple'
558 self.normalSashPos = self.splitter.GetSashPosition()
559 profile.putPreference('window_normal_sash', self.normalSashPos)
561 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
563 self.scene.OnPaint = lambda e : e
564 self.scene._slicer.cleanup()
570 class normalSettingsPanel(configBase.configPanelBase):
571 "Main user interface window"
572 def __init__(self, parent, callback = None):
573 super(normalSettingsPanel, self).__init__(parent, callback)
576 self.nb = wx.Notebook(self)
577 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
578 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
580 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
581 self._addSettingsToPanels('basic', left, right)
582 self.SizeLabelWidths(left, right)
584 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
585 self._addSettingsToPanels('advanced', left, right)
586 self.SizeLabelWidths(left, right)
589 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
590 self.nb.AddPage(self.pluginPanel, _("Plugins"))
593 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
594 self.alterationPanel = None
596 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
597 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
599 self.Bind(wx.EVT_SIZE, self.OnSize)
601 self.nb.SetSize(self.GetSize())
602 self.UpdateSize(self.printPanel)
603 self.UpdateSize(self.advancedPanel)
605 def _addSettingsToPanels(self, category, left, right):
606 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
610 for title in profile.getSubCategoriesFor(category):
611 n += 1 + len(profile.getSettingsForCategory(category, title))
614 configBase.TitleRow(p, _(title))
615 for s in profile.getSettingsForCategory(category, title):
616 configBase.SettingRow(p, s.getName())
618 def SizeLabelWidths(self, left, right):
619 leftWidth = self.getLabelColumnWidth(left)
620 rightWidth = self.getLabelColumnWidth(right)
621 maxWidth = max(leftWidth, rightWidth)
622 self.setLabelColumnWidth(left, maxWidth)
623 self.setLabelColumnWidth(right, maxWidth)
626 # Make the size of the Notebook control the same size as this control
627 self.nb.SetSize(self.GetSize())
629 # Propegate the OnSize() event (just in case)
632 # Perform out resize magic
633 self.UpdateSize(self.printPanel)
634 self.UpdateSize(self.advancedPanel)
636 def UpdateSize(self, configPanel):
637 sizer = configPanel.GetSizer()
641 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
644 # if width(col1) > (best_width(col1) + best_width(col1)):
645 # switch to horizontal
648 col1 = configPanel.leftPanel
649 colSize1 = col1.GetSize()
650 colBestSize1 = col1.GetBestSize()
651 col2 = configPanel.rightPanel
652 colSize2 = col2.GetSize()
653 colBestSize2 = col2.GetBestSize()
655 orientation = sizer.GetOrientation()
657 if orientation == wx.HORIZONTAL:
658 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
660 sizer = wx.BoxSizer(wx.VERTICAL)
661 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
662 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
663 configPanel.SetSizer(sizer)
669 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
671 sizer = wx.BoxSizer(wx.HORIZONTAL)
672 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
673 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
674 configPanel.SetSizer(sizer)
680 def updateProfileToControls(self):
681 super(normalSettingsPanel, self).updateProfileToControls()
682 if self.alterationPanel is not None:
683 self.alterationPanel.updateProfileToControls()
684 self.pluginPanel.updateProfileToControls()