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)
318 wx.CallAfter(prefDialog.Show)
320 def OnMachineSettings(self, e):
321 prefDialog = preferencesDialog.machineSettingsDialog(self)
326 def OnDropFiles(self, files):
328 profile.setPluginConfig([])
329 self.updateProfileToAllControls()
330 self.scene.loadFiles(files)
332 def OnModelMRU(self, e):
333 fileNum = e.GetId() - self.ID_MRU_MODEL1
334 path = self.modelFileHistory.GetHistoryFile(fileNum)
336 self.modelFileHistory.AddFileToHistory(path) # move up the list
337 self.config.SetPath("/ModelMRU")
338 self.modelFileHistory.Save(self.config)
341 profile.putPreference('lastFile', path)
343 self.scene.loadFiles(filelist)
345 def addToModelMRU(self, file):
346 self.modelFileHistory.AddFileToHistory(file)
347 self.config.SetPath("/ModelMRU")
348 self.modelFileHistory.Save(self.config)
351 def OnProfileMRU(self, e):
352 fileNum = e.GetId() - self.ID_MRU_PROFILE1
353 path = self.profileFileHistory.GetHistoryFile(fileNum)
355 self.profileFileHistory.AddFileToHistory(path) # move up the list
356 self.config.SetPath("/ProfileMRU")
357 self.profileFileHistory.Save(self.config)
360 profile.loadProfile(path)
361 self.updateProfileToAllControls()
363 def addToProfileMRU(self, file):
364 self.profileFileHistory.AddFileToHistory(file)
365 self.config.SetPath("/ProfileMRU")
366 self.profileFileHistory.Save(self.config)
369 def updateProfileToAllControls(self):
370 self.scene.updateProfileToControls()
371 self.normalSettingsPanel.updateProfileToControls()
372 self.simpleSettingsPanel.updateProfileToControls()
374 def reloadSettingPanels(self):
375 self.leftSizer.Detach(self.simpleSettingsPanel)
376 self.leftSizer.Detach(self.normalSettingsPanel)
377 self.simpleSettingsPanel.Destroy()
378 self.normalSettingsPanel.Destroy()
379 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
380 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
381 self.leftSizer.Add(self.simpleSettingsPanel, 1)
382 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
383 self.updateSliceMode()
384 self.updateProfileToAllControls()
386 def updateMachineMenu(self):
387 #Remove all items so we can rebuild the menu. Inserting items seems to cause crashes, so this is the safest way.
388 for item in self.machineMenu.GetMenuItems():
389 self.machineMenu.RemoveItem(item)
391 #Add a menu item for each machine configuration.
392 for n in xrange(0, profile.getMachineCount()):
393 i = self.machineMenu.Append(n + 0x1000, profile.getMachineSetting('machine_name', n).title(), kind=wx.ITEM_RADIO)
394 if n == int(profile.getPreferenceFloat('active_machine')):
396 self.Bind(wx.EVT_MENU, lambda e: self.OnSelectMachine(e.GetId() - 0x1000), i)
398 self.machineMenu.AppendSeparator()
399 i = self.machineMenu.Append(-1, _("Add new machine..."))
400 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
402 #Add tools for machines.
403 self.machineMenu.AppendSeparator()
405 self.defaultFirmwareInstallMenuItem = self.machineMenu.Append(-1, _("Install default firmware..."))
406 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, self.defaultFirmwareInstallMenuItem)
408 i = self.machineMenu.Append(-1, _("Install custom firmware..."))
409 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
411 def OnLoadProfile(self, e):
412 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)
413 dlg.SetWildcard("ini files (*.ini)|*.ini")
414 if dlg.ShowModal() == wx.ID_OK:
415 profileFile = dlg.GetPath()
416 profile.loadProfile(profileFile)
417 self.updateProfileToAllControls()
419 # Update the Profile MRU
420 self.addToProfileMRU(profileFile)
423 def OnLoadProfileFromGcode(self, e):
424 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)
425 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
426 if dlg.ShowModal() == wx.ID_OK:
427 gcodeFile = dlg.GetPath()
428 f = open(gcodeFile, 'r')
431 if line.startswith(';CURA_PROFILE_STRING:'):
432 profile.setProfileFromString(line[line.find(':')+1:].strip())
435 self.updateProfileToAllControls()
437 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)
440 def OnSaveProfile(self, e):
441 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
442 dlg.SetWildcard("ini files (*.ini)|*.ini")
443 if dlg.ShowModal() == wx.ID_OK:
444 profileFile = dlg.GetPath()
445 profile.saveProfile(profileFile)
448 def OnResetProfile(self, e):
449 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)
450 result = dlg.ShowModal() == wx.ID_YES
453 profile.resetProfile()
454 self.updateProfileToAllControls()
456 def OnSimpleSwitch(self, e):
457 profile.putPreference('startMode', 'Simple')
458 self.updateSliceMode()
460 def OnNormalSwitch(self, e):
461 profile.putPreference('startMode', 'Normal')
462 self.updateSliceMode()
464 def OnDefaultMarlinFirmware(self, e):
465 firmwareInstall.InstallFirmware()
467 def OnCustomFirmware(self, e):
468 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
469 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)
470 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
471 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
472 if dlg.ShowModal() == wx.ID_OK:
473 filename = dlg.GetPath()
474 if not(os.path.exists(filename)):
476 #For some reason my Ubuntu 10.10 crashes here.
477 firmwareInstall.InstallFirmware(filename)
479 def OnFirstRunWizard(self, e):
481 configWizard.configWizard()
483 self.reloadSettingPanels()
485 def OnAddNewMachine(self, e):
487 profile.setActiveMachine(profile.getMachineCount())
488 configWizard.configWizard(True)
490 self.reloadSettingPanels()
491 self.updateMachineMenu()
493 def OnSelectMachine(self, index):
494 profile.setActiveMachine(index)
495 self.reloadSettingPanels()
497 def OnBedLevelWizard(self, e):
498 configWizard.bedLevelWizard()
500 def OnHeadOffsetWizard(self, e):
501 configWizard.headOffsetWizard()
503 def OnExpertOpen(self, e):
504 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
508 def OnMinecraftImport(self, e):
509 mi = minecraftImport.minecraftImportWindow(self)
513 def OnPIDDebugger(self, e):
514 debugger = pidDebugger.debuggerWindow(self)
518 def onCopyProfileClipboard(self, e):
520 if not wx.TheClipboard.IsOpened():
521 wx.TheClipboard.Open()
522 clipData = wx.TextDataObject()
523 self.lastTriedClipboard = profile.getProfileString()
524 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
525 clipData.SetText(profileString)
526 wx.TheClipboard.SetData(clipData)
527 wx.TheClipboard.Close()
529 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
531 def OnCheckForUpdate(self, e):
532 newVersion = version.checkForNewerVersion()
533 if newVersion is not None:
534 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:
535 webbrowser.open(newVersion)
537 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
539 def OnAbout(self, e):
540 aboutBox = aboutWindow.aboutWindow()
544 def OnClose(self, e):
545 profile.saveProfile(profile.getDefaultProfilePath())
547 # Save the window position, size & state from the preferences file
548 profile.putPreference('window_maximized', self.IsMaximized())
549 if not self.IsMaximized() and not self.IsIconized():
550 (posx, posy) = self.GetPosition()
551 profile.putPreference('window_pos_x', posx)
552 profile.putPreference('window_pos_y', posy)
553 (width, height) = self.GetSize()
554 profile.putPreference('window_width', width)
555 profile.putPreference('window_height', height)
557 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
558 isSimple = profile.getPreference('startMode') == 'Simple'
560 self.normalSashPos = self.splitter.GetSashPosition()
561 profile.putPreference('window_normal_sash', self.normalSashPos)
563 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
565 self.scene.OnPaint = lambda e : e
566 self.scene._slicer.cleanup()
572 class normalSettingsPanel(configBase.configPanelBase):
573 "Main user interface window"
574 def __init__(self, parent, callback = None):
575 super(normalSettingsPanel, self).__init__(parent, callback)
578 self.nb = wx.Notebook(self)
579 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
580 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
582 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
583 self._addSettingsToPanels('basic', left, right)
584 self.SizeLabelWidths(left, right)
586 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
587 self._addSettingsToPanels('advanced', left, right)
588 self.SizeLabelWidths(left, right)
591 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
592 self.nb.AddPage(self.pluginPanel, _("Plugins"))
595 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
596 self.alterationPanel = None
598 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
599 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
601 self.Bind(wx.EVT_SIZE, self.OnSize)
603 self.nb.SetSize(self.GetSize())
604 self.UpdateSize(self.printPanel)
605 self.UpdateSize(self.advancedPanel)
607 def _addSettingsToPanels(self, category, left, right):
608 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
612 for title in profile.getSubCategoriesFor(category):
613 n += 1 + len(profile.getSettingsForCategory(category, title))
616 configBase.TitleRow(p, _(title))
617 for s in profile.getSettingsForCategory(category, title):
618 configBase.SettingRow(p, s.getName())
620 def SizeLabelWidths(self, left, right):
621 leftWidth = self.getLabelColumnWidth(left)
622 rightWidth = self.getLabelColumnWidth(right)
623 maxWidth = max(leftWidth, rightWidth)
624 self.setLabelColumnWidth(left, maxWidth)
625 self.setLabelColumnWidth(right, maxWidth)
628 # Make the size of the Notebook control the same size as this control
629 self.nb.SetSize(self.GetSize())
631 # Propegate the OnSize() event (just in case)
634 # Perform out resize magic
635 self.UpdateSize(self.printPanel)
636 self.UpdateSize(self.advancedPanel)
638 def UpdateSize(self, configPanel):
639 sizer = configPanel.GetSizer()
643 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
646 # if width(col1) > (best_width(col1) + best_width(col1)):
647 # switch to horizontal
650 col1 = configPanel.leftPanel
651 colSize1 = col1.GetSize()
652 colBestSize1 = col1.GetBestSize()
653 col2 = configPanel.rightPanel
654 colSize2 = col2.GetSize()
655 colBestSize2 = col2.GetBestSize()
657 orientation = sizer.GetOrientation()
659 if orientation == wx.HORIZONTAL:
660 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
662 sizer = wx.BoxSizer(wx.VERTICAL)
663 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
664 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
665 configPanel.SetSizer(sizer)
671 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
673 sizer = wx.BoxSizer(wx.HORIZONTAL)
674 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
675 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
676 configPanel.SetSizer(sizer)
682 def updateProfileToControls(self):
683 super(normalSettingsPanel, self).updateProfileToControls()
684 if self.alterationPanel is not None:
685 self.alterationPanel.updateProfileToControls()
686 self.pluginPanel.updateProfileToControls()