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.util import dropTarget
18 #from Cura.gui.tools import batchRun
19 from Cura.gui.tools import pidDebugger
20 from Cura.gui.tools import minecraftImport
21 from Cura.util import profile
22 from Cura.util import version
23 from Cura.util import meshLoader
25 class mainWindow(wx.Frame):
27 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
29 self.extruderCount = int(profile.getMachineSetting('extruder_amount'))
31 wx.EVT_CLOSE(self, self.OnClose)
33 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions() + ['.g', '.gcode', '.ini']))
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()
112 i = toolsMenu.Append(-1, _("Switch to quickprint..."))
113 self.switchToQuickprintMenuItem = i
114 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
116 i = toolsMenu.Append(-1, _("Switch to full settings..."))
117 self.switchToNormalMenuItem = i
118 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
120 #toolsMenu.AppendSeparator()
121 #i = toolsMenu.Append(-1, 'Batch run...')
122 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
123 #self.normalModeOnlyItems.append(i)
125 if minecraftImport.hasMinecraft():
126 i = toolsMenu.Append(-1, _("Minecraft import..."))
127 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
129 if version.isDevVersion():
130 i = toolsMenu.Append(-1, _("PID Debugger..."))
131 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
133 i = toolsMenu.Append(-1, _("Copy profile to clipboard"))
134 self.Bind(wx.EVT_MENU, self.onCopyProfileClipboard,i)
135 self.menubar.Append(toolsMenu, _("Tools"))
137 expertMenu = wx.Menu()
138 i = expertMenu.Append(-1, _("Open expert settings..."))
139 self.normalModeOnlyItems.append(i)
140 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
141 expertMenu.AppendSeparator()
142 if firmwareInstall.getDefaultFirmware() is not None:
143 i = expertMenu.Append(-1, _("Install default Marlin firmware"))
144 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
145 i = expertMenu.Append(-1, _("Install custom firmware"))
146 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
147 expertMenu.AppendSeparator()
148 i = expertMenu.Append(-1, _("Run first run wizard..."))
149 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
150 i = expertMenu.Append(-1, _("Run bed leveling wizard..."))
151 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
152 if self.extruderCount > 1:
153 i = expertMenu.Append(-1, _("Run head offset wizard..."))
154 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
156 i = expertMenu.Append(-1, _("Add new machine..."))
157 self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
159 self.menubar.Append(expertMenu, _("Expert"))
162 i = helpMenu.Append(-1, _("Online documentation..."))
163 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
164 i = helpMenu.Append(-1, _("Report a problem..."))
165 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
166 i = helpMenu.Append(-1, _("Check for update..."))
167 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
168 i = helpMenu.Append(-1, _("Open YouMagine website..."))
169 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://www.youmagine.com/'), i)
170 i = helpMenu.Append(-1, _("About Cura..."))
171 self.Bind(wx.EVT_MENU, self.OnAbout, i)
172 self.menubar.Append(helpMenu, _("Help"))
173 self.SetMenuBar(self.menubar)
175 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
176 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
177 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
178 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
181 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
182 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
184 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
185 self.leftSizer.Add(self.simpleSettingsPanel, 1)
186 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
187 self.leftPane.SetSizer(self.leftSizer)
190 self.scene = sceneView.SceneView(self.rightPane)
192 #Main sizer, to position the preview window, buttons and tab control
193 sizer = wx.BoxSizer()
194 self.rightPane.SetSizer(sizer)
195 sizer.Add(self.scene, 1, flag=wx.EXPAND)
198 sizer = wx.BoxSizer(wx.VERTICAL)
200 sizer.Add(self.splitter, 1, wx.EXPAND)
204 self.updateProfileToAllControls()
206 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
208 self.simpleSettingsPanel.Show(False)
209 self.normalSettingsPanel.Show(False)
211 # Set default window size & position
212 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
215 #Timer set; used to check if profile is on the clipboard
216 self.timer = wx.Timer(self)
217 self.Bind(wx.EVT_TIMER, self.onTimer)
218 self.timer.Start(1000)
219 self.lastTriedClipboard = profile.getProfileString()
221 # Restore the window position, size & state from the preferences file
223 if profile.getPreference('window_maximized') == 'True':
226 posx = int(profile.getPreference('window_pos_x'))
227 posy = int(profile.getPreference('window_pos_y'))
228 width = int(profile.getPreference('window_width'))
229 height = int(profile.getPreference('window_height'))
230 if posx > 0 or posy > 0:
231 self.SetPosition((posx,posy))
232 if width > 0 and height > 0:
233 self.SetSize((width,height))
235 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
237 self.normalSashPos = 0
239 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
240 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
242 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
244 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
246 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
248 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
249 self.SetSize((800,600))
252 self.updateSliceMode()
254 def onTimer(self, e):
255 #Check if there is something in the clipboard
258 if not wx.TheClipboard.IsOpened():
259 wx.TheClipboard.Open()
260 do = wx.TextDataObject()
261 if wx.TheClipboard.GetData(do):
262 profileString = do.GetText()
263 wx.TheClipboard.Close()
265 if "CURA_PROFILE_STRING:" in profileString:
266 #print "Found correct syntax on clipboard"
267 profileString = profileString.replace("\n","")
268 profileString = profileString.replace("CURA_PROFILE_STRING:", "")
269 if profileString != self.lastTriedClipboard:
270 self.lastTriedClipboard = profileString
271 profile.setProfileFromString(profileString)
272 print "changed profile"
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)
287 self.switchToQuickprintMenuItem.Enable(not isSimple)
288 self.switchToNormalMenuItem.Enable(isSimple)
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.scene.updateProfileToControls()
307 def OnPreferences(self, e):
308 prefDialog = preferencesDialog.preferencesDialog(self)
312 def OnMachineSettings(self, e):
313 prefDialog = preferencesDialog.machineSettingsDialog(self)
317 def OnDropFiles(self, files):
319 profile.setPluginConfig([])
320 self.updateProfileToAllControls()
321 self.scene.loadFiles(files)
323 def OnModelMRU(self, e):
324 fileNum = e.GetId() - self.ID_MRU_MODEL1
325 path = self.modelFileHistory.GetHistoryFile(fileNum)
327 self.modelFileHistory.AddFileToHistory(path) # move up the list
328 self.config.SetPath("/ModelMRU")
329 self.modelFileHistory.Save(self.config)
332 profile.putPreference('lastFile', path)
334 self.scene.loadFiles(filelist)
336 def addToModelMRU(self, file):
337 self.modelFileHistory.AddFileToHistory(file)
338 self.config.SetPath("/ModelMRU")
339 self.modelFileHistory.Save(self.config)
342 def OnProfileMRU(self, e):
343 fileNum = e.GetId() - self.ID_MRU_PROFILE1
344 path = self.profileFileHistory.GetHistoryFile(fileNum)
346 self.profileFileHistory.AddFileToHistory(path) # move up the list
347 self.config.SetPath("/ProfileMRU")
348 self.profileFileHistory.Save(self.config)
351 profile.loadProfile(path)
352 self.updateProfileToAllControls()
354 def addToProfileMRU(self, file):
355 self.profileFileHistory.AddFileToHistory(file)
356 self.config.SetPath("/ProfileMRU")
357 self.profileFileHistory.Save(self.config)
360 def updateProfileToAllControls(self):
361 self.scene.updateProfileToControls()
362 self.normalSettingsPanel.updateProfileToControls()
363 self.simpleSettingsPanel.updateProfileToControls()
365 def reloadSettingPanels(self):
366 self.leftSizer.Detach(self.simpleSettingsPanel)
367 self.leftSizer.Detach(self.normalSettingsPanel)
368 self.simpleSettingsPanel.Destroy()
369 self.normalSettingsPanel.Destroy()
370 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
371 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
372 self.leftSizer.Add(self.simpleSettingsPanel, 1)
373 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
374 self.updateSliceMode()
375 self.updateProfileToAllControls()
377 def OnLoadProfile(self, e):
378 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)
379 dlg.SetWildcard("ini files (*.ini)|*.ini")
380 if dlg.ShowModal() == wx.ID_OK:
381 profileFile = dlg.GetPath()
382 profile.loadProfile(profileFile)
383 self.updateProfileToAllControls()
385 # Update the Profile MRU
386 self.addToProfileMRU(profileFile)
389 def OnLoadProfileFromGcode(self, e):
390 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)
391 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
392 if dlg.ShowModal() == wx.ID_OK:
393 gcodeFile = dlg.GetPath()
394 f = open(gcodeFile, 'r')
397 if line.startswith(';CURA_PROFILE_STRING:'):
398 profile.setProfileFromString(line[line.find(':')+1:].strip())
401 self.updateProfileToAllControls()
403 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)
406 def OnSaveProfile(self, e):
407 dlg=wx.FileDialog(self, _("Select profile file to save"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
408 dlg.SetWildcard("ini files (*.ini)|*.ini")
409 if dlg.ShowModal() == wx.ID_OK:
410 profileFile = dlg.GetPath()
411 profile.saveProfile(profileFile)
414 def OnResetProfile(self, e):
415 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)
416 result = dlg.ShowModal() == wx.ID_YES
419 profile.resetProfile()
420 self.updateProfileToAllControls()
422 def OnSimpleSwitch(self, e):
423 profile.putPreference('startMode', 'Simple')
424 self.updateSliceMode()
426 def OnNormalSwitch(self, e):
427 profile.putPreference('startMode', 'Normal')
428 self.updateSliceMode()
430 def OnDefaultMarlinFirmware(self, e):
431 firmwareInstall.InstallFirmware()
433 def OnCustomFirmware(self, e):
434 if profile.getMachineSetting('machine_type').startswith('ultimaker'):
435 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)
436 dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
437 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
438 if dlg.ShowModal() == wx.ID_OK:
439 filename = dlg.GetPath()
440 if not(os.path.exists(filename)):
442 #For some reason my Ubuntu 10.10 crashes here.
443 firmwareInstall.InstallFirmware(filename)
445 def OnFirstRunWizard(self, e):
447 configWizard.configWizard()
449 self.reloadSettingPanels()
451 def OnAddNewMachine(self, e):
453 profile.setActiveMachine(profile.getMachineCount())
454 configWizard.configWizard(True)
456 self.reloadSettingPanels()
458 def OnBedLevelWizard(self, e):
459 configWizard.bedLevelWizard()
461 def OnHeadOffsetWizard(self, e):
462 configWizard.headOffsetWizard()
464 def OnExpertOpen(self, e):
465 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
469 def OnMinecraftImport(self, e):
470 mi = minecraftImport.minecraftImportWindow(self)
474 def OnPIDDebugger(self, e):
475 debugger = pidDebugger.debuggerWindow(self)
479 def onCopyProfileClipboard(self, e):
481 if not wx.TheClipboard.IsOpened():
482 wx.TheClipboard.Open()
483 clipData = wx.TextDataObject()
484 self.lastTriedClipboard = profile.getProfileString()
485 profileString = profile.insertNewlines("CURA_PROFILE_STRING:" + self.lastTriedClipboard)
486 clipData.SetText(profileString)
487 wx.TheClipboard.SetData(clipData)
488 wx.TheClipboard.Close()
490 print "Could not write to clipboard, unable to get ownership. Another program is using the clipboard."
492 def OnCheckForUpdate(self, e):
493 newVersion = version.checkForNewerVersion()
494 if newVersion is not None:
495 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:
496 webbrowser.open(newVersion)
498 wx.MessageBox(_("You are running the latest version of Cura!"), _("Awesome!"), wx.ICON_INFORMATION)
500 def OnAbout(self, e):
501 info = wx.AboutDialogInfo()
503 info.SetDescription(_("End solution for Open Source Fused Filament Fabrication 3D printing."))
504 info.SetWebSite('http://software.ultimaker.com/')
505 info.SetCopyright(_("Copyright (C) David Braam"))
507 This program is free software: you can redistribute it and/or modify
508 it under the terms of the GNU Affero General Public License as published by
509 the Free Software Foundation, either version 3 of the License, or
510 (at your option) any later version.
512 This program is distributed in the hope that it will be useful,
513 but WITHOUT ANY WARRANTY; without even the implied warranty of
514 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
515 GNU Affero General Public License for more details.
517 You should have received a copy of the GNU Affero General Public License
518 along with this program. If not, see <http://www.gnu.org/licenses/>.
522 def OnClose(self, e):
523 profile.saveProfile(profile.getDefaultProfilePath())
525 # Save the window position, size & state from the preferences file
526 profile.putPreference('window_maximized', self.IsMaximized())
527 if not self.IsMaximized() and not self.IsIconized():
528 (posx, posy) = self.GetPosition()
529 profile.putPreference('window_pos_x', posx)
530 profile.putPreference('window_pos_y', posy)
531 (width, height) = self.GetSize()
532 profile.putPreference('window_width', width)
533 profile.putPreference('window_height', height)
535 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
536 isSimple = profile.getPreference('startMode') == 'Simple'
538 self.normalSashPos = self.splitter.GetSashPosition()
539 profile.putPreference('window_normal_sash', self.normalSashPos)
541 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
543 self.scene.OnPaint = lambda e : e
544 self.scene._slicer.cleanup()
550 class normalSettingsPanel(configBase.configPanelBase):
551 "Main user interface window"
552 def __init__(self, parent, callback = None):
553 super(normalSettingsPanel, self).__init__(parent, callback)
556 self.nb = wx.Notebook(self)
557 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
558 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
560 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
561 self._addSettingsToPanels('basic', left, right)
562 self.SizeLabelWidths(left, right)
564 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
565 self._addSettingsToPanels('advanced', left, right)
566 self.SizeLabelWidths(left, right)
569 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
570 if len(self.pluginPanel.pluginList) > 0:
571 self.nb.AddPage(self.pluginPanel, _("Plugins"))
573 self.pluginPanel.Show(False)
576 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
577 self.alterationPanel = None
579 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
580 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
582 self.Bind(wx.EVT_SIZE, self.OnSize)
584 self.nb.SetSize(self.GetSize())
585 self.UpdateSize(self.printPanel)
586 self.UpdateSize(self.advancedPanel)
588 def _addSettingsToPanels(self, category, left, right):
589 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
593 for title in profile.getSubCategoriesFor(category):
594 n += 1 + len(profile.getSettingsForCategory(category, title))
597 configBase.TitleRow(p, title)
598 for s in profile.getSettingsForCategory(category, title):
599 configBase.SettingRow(p, s.getName())
601 def SizeLabelWidths(self, left, right):
602 leftWidth = self.getLabelColumnWidth(left)
603 rightWidth = self.getLabelColumnWidth(right)
604 maxWidth = max(leftWidth, rightWidth)
605 self.setLabelColumnWidth(left, maxWidth)
606 self.setLabelColumnWidth(right, maxWidth)
609 # Make the size of the Notebook control the same size as this control
610 self.nb.SetSize(self.GetSize())
612 # Propegate the OnSize() event (just in case)
615 # Perform out resize magic
616 self.UpdateSize(self.printPanel)
617 self.UpdateSize(self.advancedPanel)
619 def UpdateSize(self, configPanel):
620 sizer = configPanel.GetSizer()
624 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
627 # if width(col1) > (best_width(col1) + best_width(col1)):
628 # switch to horizontal
631 col1 = configPanel.leftPanel
632 colSize1 = col1.GetSize()
633 colBestSize1 = col1.GetBestSize()
634 col2 = configPanel.rightPanel
635 colSize2 = col2.GetSize()
636 colBestSize2 = col2.GetBestSize()
638 orientation = sizer.GetOrientation()
640 if orientation == wx.HORIZONTAL:
641 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
643 sizer = wx.BoxSizer(wx.VERTICAL)
644 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
645 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
646 configPanel.SetSizer(sizer)
652 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
654 sizer = wx.BoxSizer(wx.HORIZONTAL)
655 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
656 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
657 configPanel.SetSizer(sizer)
663 def updateProfileToControls(self):
664 super(normalSettingsPanel, self).updateProfileToControls()
665 if self.alterationPanel is not None:
666 self.alterationPanel.updateProfileToControls()
667 self.pluginPanel.updateProfileToControls()