chiark / gitweb /
Add an about box.
[cura.git] / Cura / gui / mainWindow.py
1 from __future__ import absolute_import
2
3 import wx
4 import os
5 import webbrowser
6
7 from Cura.gui import configBase
8 from Cura.gui import expertConfig
9 from Cura.gui import alterationPanel
10 from Cura.gui import pluginPanel
11 from Cura.gui import preferencesDialog
12 from Cura.gui import configWizard
13 from Cura.gui import firmwareInstall
14 from Cura.gui import simpleMode
15 from Cura.gui import sceneView
16 #from Cura.gui.tools import batchRun
17 from Cura.gui.util import dropTarget
18 from Cura.gui.tools import minecraftImport
19 from Cura.gui.tools import superformula
20 from Cura.util import profile
21 from Cura.util import version
22 from Cura.util import meshLoader
23
24 class mainWindow(wx.Frame):
25         def __init__(self):
26                 super(mainWindow, self).__init__(None, title='Cura Steam Engine BETA - ' + version.getVersion())
27
28                 self.extruderCount = int(profile.getPreference('extruder_amount'))
29
30                 wx.EVT_CLOSE(self, self.OnClose)
31
32                 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions()))
33
34                 self.normalModeOnlyItems = []
35
36                 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
37                 self.config = wx.FileConfig(appName="Cura", 
38                                                 localFilename=mruFile,
39                                                 style=wx.CONFIG_USE_LOCAL_FILE)
40                                                 
41                 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)]
42                 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
43                 self.config.SetPath("/ModelMRU")
44                 self.modelFileHistory.Load(self.config)
45
46                 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)]
47                 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
48                 self.config.SetPath("/ProfileMRU")
49                 self.profileFileHistory.Load(self.config)
50
51                 self.menubar = wx.MenuBar()
52                 self.fileMenu = wx.Menu()
53                 i = self.fileMenu.Append(-1, 'Load model file...\tCTRL+L')
54                 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
55                 i = self.fileMenu.Append(-1, 'Save model...\tCTRL+S')
56                 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
57
58                 self.fileMenu.AppendSeparator()
59                 i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
60                 self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
61                 i = self.fileMenu.Append(-1, 'Save GCode...')
62                 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
63
64                 self.fileMenu.AppendSeparator()
65                 i = self.fileMenu.Append(-1, 'Open Profile...')
66                 self.normalModeOnlyItems.append(i)
67                 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
68                 i = self.fileMenu.Append(-1, 'Save Profile...')
69                 self.normalModeOnlyItems.append(i)
70                 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
71                 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
72                 self.normalModeOnlyItems.append(i)
73                 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
74                 self.fileMenu.AppendSeparator()
75                 i = self.fileMenu.Append(-1, 'Reset Profile to default')
76                 self.normalModeOnlyItems.append(i)
77                 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
78
79                 self.fileMenu.AppendSeparator()
80                 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
81                 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
82                 self.fileMenu.AppendSeparator()
83
84                 # Model MRU list
85                 modelHistoryMenu = wx.Menu()
86                 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
87                 self.modelFileHistory.UseMenu(modelHistoryMenu)
88                 self.modelFileHistory.AddFilesToMenu()
89                 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
90
91                 # Profle MRU list
92                 profileHistoryMenu = wx.Menu()
93                 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
94                 self.profileFileHistory.UseMenu(profileHistoryMenu)
95                 self.profileFileHistory.AddFilesToMenu()
96                 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
97                 
98                 self.fileMenu.AppendSeparator()
99                 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
100                 self.Bind(wx.EVT_MENU, self.OnQuit, i)
101                 self.menubar.Append(self.fileMenu, '&File')
102
103                 toolsMenu = wx.Menu()
104                 i = toolsMenu.Append(-1, 'Switch to quickprint...')
105                 self.switchToQuickprintMenuItem = i
106                 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
107                 i = toolsMenu.Append(-1, 'Switch to full settings...')
108                 self.switchToNormalMenuItem = i
109                 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
110                 toolsMenu.AppendSeparator()
111                 #i = toolsMenu.Append(-1, 'Batch run...')
112                 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
113                 #self.normalModeOnlyItems.append(i)
114                 if minecraftImport.hasMinecraft():
115                         i = toolsMenu.Append(-1, 'Minecraft import...')
116                         self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
117                 i = toolsMenu.Append(-1, 'Super-shaper...')
118                 self.Bind(wx.EVT_MENU, self.OnSuperformula, i)
119                 self.menubar.Append(toolsMenu, 'Tools')
120
121                 expertMenu = wx.Menu()
122                 i = expertMenu.Append(-1, 'Open expert settings...')
123                 self.normalModeOnlyItems.append(i)
124                 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
125                 expertMenu.AppendSeparator()
126                 if firmwareInstall.getDefaultFirmware() is not None:
127                         i = expertMenu.Append(-1, 'Install default Marlin firmware')
128                         self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
129                 i = expertMenu.Append(-1, 'Install custom firmware')
130                 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
131                 expertMenu.AppendSeparator()
132                 i = expertMenu.Append(-1, 'Run first run wizard...')
133                 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
134                 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
135                 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
136                 if self.extruderCount > 1:
137                         i = expertMenu.Append(-1, 'Run head offset wizard...')
138                         self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
139                 self.menubar.Append(expertMenu, 'Expert')
140
141                 helpMenu = wx.Menu()
142                 i = helpMenu.Append(-1, 'Online documentation...')
143                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
144                 i = helpMenu.Append(-1, 'Report a problem...')
145                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
146                 i = helpMenu.Append(-1, 'Check for update...')
147                 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
148                 i = helpMenu.Append(-1, 'About Cura...')
149                 self.Bind(wx.EVT_MENU, self.OnAbout, i)
150                 self.menubar.Append(helpMenu, 'Help')
151                 self.SetMenuBar(self.menubar)
152
153                 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
154                 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
155                 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
156                 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
157
158                 ##Gui components##
159                 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
160                 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
161
162                 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
163                 self.leftSizer.Add(self.simpleSettingsPanel)
164                 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
165                 self.leftPane.SetSizer(self.leftSizer)
166                 
167                 #Preview window
168                 self.scene = sceneView.SceneView(self.rightPane)
169
170                 #Main sizer, to position the preview window, buttons and tab control
171                 sizer = wx.BoxSizer()
172                 self.rightPane.SetSizer(sizer)
173                 sizer.Add(self.scene, 1, flag=wx.EXPAND)
174
175                 # Main window sizer
176                 sizer = wx.BoxSizer(wx.VERTICAL)
177                 self.SetSizer(sizer)
178                 sizer.Add(self.splitter, 1, wx.EXPAND)
179                 sizer.Layout()
180                 self.sizer = sizer
181
182                 self.updateProfileToControls()
183
184                 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
185
186                 self.simpleSettingsPanel.Show(False)
187                 self.normalSettingsPanel.Show(False)
188
189                 # Set default window size & position
190                 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
191                 self.Centre()
192
193                 # Restore the window position, size & state from the preferences file
194                 try:
195                         if profile.getPreference('window_maximized') == 'True':
196                                 self.Maximize(True)
197                         else:
198                                 posx = int(profile.getPreference('window_pos_x'))
199                                 posy = int(profile.getPreference('window_pos_y'))
200                                 width = int(profile.getPreference('window_width'))
201                                 height = int(profile.getPreference('window_height'))
202                                 if posx > 0 or posy > 0:
203                                         self.SetPosition((posx,posy))
204                                 if width > 0 and height > 0:
205                                         self.SetSize((width,height))
206                                 
207                         self.normalSashPos = int(profile.getPreference('window_normal_sash'))
208                 except:
209                         self.normalSashPos = 0
210                         self.Maximize(True)
211                 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
212                         self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
213
214                 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
215
216                 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
217                         self.Centre()
218                 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
219                         self.Centre()
220                 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
221                         self.SetSize((800,600))
222                         self.Centre()
223
224                 self.updateSliceMode()
225
226         def updateSliceMode(self):
227                 isSimple = profile.getPreference('startMode') == 'Simple'
228
229                 self.normalSettingsPanel.Show(not isSimple)
230                 self.simpleSettingsPanel.Show(isSimple)
231                 self.leftPane.Layout()
232
233                 for i in self.normalModeOnlyItems:
234                         i.Enable(not isSimple)
235                 self.switchToQuickprintMenuItem.Enable(not isSimple)
236                 self.switchToNormalMenuItem.Enable(isSimple)
237
238                 # Set splitter sash position & size
239                 if isSimple:
240                         # Save normal mode sash
241                         self.normalSashPos = self.splitter.GetSashPosition()
242                         
243                         # Change location of sash to width of quick mode pane 
244                         (width, height) = self.simpleSettingsPanel.GetSizer().GetSize() 
245                         self.splitter.SetSashPosition(width, True)
246                         
247                         # Disable sash
248                         self.splitter.SetSashSize(0)
249                 else:
250                         self.splitter.SetSashPosition(self.normalSashPos, True)
251                         # Enabled sash
252                         self.splitter.SetSashSize(4)
253                 self.scene.updateProfileToControls()
254                                                                 
255         def OnPreferences(self, e):
256                 prefDialog = preferencesDialog.preferencesDialog(self)
257                 prefDialog.Centre()
258                 prefDialog.Show()
259
260         def OnDropFiles(self, files):
261                 profile.setPluginConfig([])
262                 self.updateProfileToControls()
263                 self.scene.loadScene(files)
264
265         def OnModelMRU(self, e):
266                 fileNum = e.GetId() - self.ID_MRU_MODEL1
267                 path = self.modelFileHistory.GetHistoryFile(fileNum)
268                 # Update Model MRU
269                 self.modelFileHistory.AddFileToHistory(path)  # move up the list
270                 self.config.SetPath("/ModelMRU")
271                 self.modelFileHistory.Save(self.config)
272                 self.config.Flush()
273                 # Load Model
274                 filelist = [ path ]
275                 self.scene.loadScene(filelist)
276
277         def addToModelMRU(self, file):
278                 self.modelFileHistory.AddFileToHistory(file)
279                 self.config.SetPath("/ModelMRU")
280                 self.modelFileHistory.Save(self.config)
281                 self.config.Flush()
282         
283         def OnProfileMRU(self, e):
284                 fileNum = e.GetId() - self.ID_MRU_PROFILE1
285                 path = self.profileFileHistory.GetHistoryFile(fileNum)
286                 # Update Profile MRU
287                 self.profileFileHistory.AddFileToHistory(path)  # move up the list
288                 self.config.SetPath("/ProfileMRU")
289                 self.profileFileHistory.Save(self.config)
290                 self.config.Flush()
291                 # Load Profile  
292                 profile.loadProfile(path)
293                 self.updateProfileToControls()
294
295         def addToProfileMRU(self, file):
296                 self.profileFileHistory.AddFileToHistory(file)
297                 self.config.SetPath("/ProfileMRU")
298                 self.profileFileHistory.Save(self.config)
299                 self.config.Flush()                     
300
301         def updateProfileToControls(self):
302                 self.scene.updateProfileToControls()
303                 self.normalSettingsPanel.updateProfileToControls()
304                 self.simpleSettingsPanel.updateProfileToControls()
305
306         def OnLoadProfile(self, e):
307                 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)
308                 dlg.SetWildcard("ini files (*.ini)|*.ini")
309                 if dlg.ShowModal() == wx.ID_OK:
310                         profileFile = dlg.GetPath()
311                         profile.loadProfile(profileFile)
312                         self.updateProfileToControls()
313
314                         # Update the Profile MRU
315                         self.addToProfileMRU(profileFile)
316                 dlg.Destroy()
317
318         def OnLoadProfileFromGcode(self, e):
319                 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)
320                 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
321                 if dlg.ShowModal() == wx.ID_OK:
322                         gcodeFile = dlg.GetPath()
323                         f = open(gcodeFile, 'r')
324                         hasProfile = False
325                         for line in f:
326                                 if line.startswith(';CURA_PROFILE_STRING:'):
327                                         profile.loadProfileFromString(line[line.find(':')+1:].strip())
328                                         hasProfile = True
329                         if hasProfile:
330                                 self.updateProfileToControls()
331                         else:
332                                 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)
333                 dlg.Destroy()
334
335         def OnSaveProfile(self, e):
336                 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
337                 dlg.SetWildcard("ini files (*.ini)|*.ini")
338                 if dlg.ShowModal() == wx.ID_OK:
339                         profileFile = dlg.GetPath()
340                         profile.saveProfile(profileFile)
341                 dlg.Destroy()
342
343         def OnResetProfile(self, e):
344                 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)
345                 result = dlg.ShowModal() == wx.ID_YES
346                 dlg.Destroy()
347                 if result:
348                         profile.resetProfile()
349                         self.updateProfileToControls()
350
351         def OnBatchRun(self, e):
352                 br = batchRun.batchRunWindow(self)
353                 br.Centre()
354                 br.Show(True)
355
356         def OnSimpleSwitch(self, e):
357                 profile.putPreference('startMode', 'Simple')
358                 self.updateSliceMode()
359
360         def OnNormalSwitch(self, e):
361                 profile.putPreference('startMode', 'Normal')
362                 self.updateSliceMode()
363
364         def OnDefaultMarlinFirmware(self, e):
365                 firmwareInstall.InstallFirmware()
366
367         def OnCustomFirmware(self, e):
368                 if profile.getPreference('machine_type') == 'ultimaker':
369                         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)
370                 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
371                 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
372                 if dlg.ShowModal() == wx.ID_OK:
373                         filename = dlg.GetPath()
374                         if not(os.path.exists(filename)):
375                                 return
376                         #For some reason my Ubuntu 10.10 crashes here.
377                         firmwareInstall.InstallFirmware(filename)
378
379         def OnFirstRunWizard(self, e):
380                 configWizard.configWizard()
381                 self.updateProfileToControls()
382
383         def OnBedLevelWizard(self, e):
384                 configWizard.bedLevelWizard()
385
386         def OnHeadOffsetWizard(self, e):
387                 configWizard.headOffsetWizard()
388
389         def OnExpertOpen(self, e):
390                 ecw = expertConfig.expertConfigWindow()
391                 ecw.Centre()
392                 ecw.ShowModal()
393                 self.scene.sceneUpdated()
394
395         def OnMinecraftImport(self, e):
396                 mi = minecraftImport.minecraftImportWindow(self)
397                 mi.Centre()
398                 mi.Show(True)
399
400         def OnSuperformula(self, e):
401                 sf = superformula.superformulaWindow(self)
402                 #sf = superformula.superformulaEvolver(self)
403                 sf.Centre()
404                 sf.Show(True)
405
406         def OnCheckForUpdate(self, e):
407                 newVersion = version.checkForNewerVersion()
408                 if newVersion is not None:
409                         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:
410                                 webbrowser.open(newVersion)
411                 else:
412                         wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
413
414         def OnAbout(self, e):
415                 info = wx.AboutDialogInfo()
416                 info.SetName('Cura')
417                 info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.')
418                 info.SetWebSite('http://software.ultimaker.com/')
419                 info.SetCopyright('Copyright (C) David Braam')
420                 info.SetLicence("""
421     This program is free software: you can redistribute it and/or modify
422     it under the terms of the GNU Affero General Public License as published by
423     the Free Software Foundation, either version 3 of the License, or
424     (at your option) any later version.
425
426     This program is distributed in the hope that it will be useful,
427     but WITHOUT ANY WARRANTY; without even the implied warranty of
428     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
429     GNU Affero General Public License for more details.
430
431     You should have received a copy of the GNU Affero General Public License
432     along with this program.  If not, see <http://www.gnu.org/licenses/>.
433 """)
434                 wx.AboutBox(info)
435
436         def OnClose(self, e):
437                 profile.saveProfile(profile.getDefaultProfilePath())
438
439                 # Save the window position, size & state from the preferences file
440                 profile.putPreference('window_maximized', self.IsMaximized())
441                 if not self.IsMaximized() and not self.IsIconized():
442                         (posx, posy) = self.GetPosition()
443                         profile.putPreference('window_pos_x', posx)
444                         profile.putPreference('window_pos_y', posy)
445                         (width, height) = self.GetSize()
446                         profile.putPreference('window_width', width)
447                         profile.putPreference('window_height', height)                  
448                         
449                         # Save normal sash position.  If in normal mode (!simple mode), get last position of sash before saving it...
450                         isSimple = profile.getPreference('startMode') == 'Simple'
451                         if not isSimple:
452                                 self.normalSashPos = self.splitter.GetSashPosition()
453                         profile.putPreference('window_normal_sash', self.normalSashPos)
454
455                 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
456                 print "Closing down"
457                 self.scene.OnPaint = lambda e : e
458                 self.scene._slicer.cleanup()
459                 self.Destroy()
460
461         def OnQuit(self, e):
462                 self.Close()
463
464 class normalSettingsPanel(configBase.configPanelBase):
465         "Main user interface window"
466         def __init__(self, parent, callback = None):
467                 super(normalSettingsPanel, self).__init__(parent, callback)
468
469                 #Main tabs
470                 self.nb = wx.Notebook(self)
471                 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
472                 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
473
474                 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
475                 self._addSettingsToPanels('basic', left, right)
476                 self.SizeLabelWidths(left, right)
477                 
478                 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
479                 self._addSettingsToPanels('advanced', left, right)
480                 self.SizeLabelWidths(left, right)
481
482                 #Plugin page
483                 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
484                 if len(self.pluginPanel.pluginList) > 0:
485                         self.nb.AddPage(self.pluginPanel, "Plugins")
486                 else:
487                         self.pluginPanel.Show(False)
488
489                 #Alteration page
490                 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
491                 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
492
493                 self.Bind(wx.EVT_SIZE, self.OnSize)
494
495                 self.nb.SetSize(self.GetSize())
496                 self.UpdateSize(self.printPanel)
497                 self.UpdateSize(self.advancedPanel)
498
499         def _addSettingsToPanels(self, category, left, right):
500                 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
501
502                 p = left
503                 n = 0
504                 for title in profile.getSubCategoriesFor(category):
505                         n += 1 + len(profile.getSettingsForCategory(category, title))
506                         if n > count / 2:
507                                 p = right
508                         configBase.TitleRow(p, title)
509                         for s in profile.getSettingsForCategory(category, title):
510                                 if s.checkConditions():
511                                         configBase.SettingRow(p, s.getName())
512
513         def SizeLabelWidths(self, left, right):
514                 leftWidth = self.getLabelColumnWidth(left)
515                 rightWidth = self.getLabelColumnWidth(right)
516                 maxWidth = max(leftWidth, rightWidth)
517                 self.setLabelColumnWidth(left, maxWidth)
518                 self.setLabelColumnWidth(right, maxWidth)
519
520         def OnSize(self, e):
521                 # Make the size of the Notebook control the same size as this control
522                 self.nb.SetSize(self.GetSize())
523                 
524                 # Propegate the OnSize() event (just in case)
525                 e.Skip()
526                 
527                 # Perform out resize magic
528                 self.UpdateSize(self.printPanel)
529                 self.UpdateSize(self.advancedPanel)
530         
531         def UpdateSize(self, configPanel):
532                 sizer = configPanel.GetSizer()
533                 
534                 # Pseudocde
535                 # if horizontal:
536                 #     if width(col1) < best_width(col1) || width(col2) < best_width(col2):
537                 #         switch to vertical
538                 # else:
539                 #     if width(col1) > (best_width(col1) + best_width(col1)):
540                 #         switch to horizontal
541                 #
542                                 
543                 col1 = configPanel.leftPanel
544                 colSize1 = col1.GetSize()
545                 colBestSize1 = col1.GetBestSize()
546                 col2 = configPanel.rightPanel
547                 colSize2 = col2.GetSize()
548                 colBestSize2 = col2.GetBestSize()
549
550                 orientation = sizer.GetOrientation()
551                 
552                 if orientation == wx.HORIZONTAL:
553                         if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
554                                 configPanel.Freeze()
555                                 sizer = wx.BoxSizer(wx.VERTICAL)
556                                 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
557                                 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
558                                 configPanel.SetSizer(sizer)
559                                 #sizer.Layout()
560                                 configPanel.Layout()
561                                 self.Layout()
562                                 configPanel.Thaw()
563                 else:
564                         if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
565                                 configPanel.Freeze()
566                                 sizer = wx.BoxSizer(wx.HORIZONTAL)
567                                 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
568                                 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
569                                 configPanel.SetSizer(sizer)
570                                 #sizer.Layout()
571                                 configPanel.Layout()
572                                 self.Layout()
573                                 configPanel.Thaw()
574
575         def updateProfileToControls(self):
576                 super(normalSettingsPanel, self).updateProfileToControls()
577                 self.alterationPanel.updateProfileToControls()
578                 self.pluginPanel.updateProfileToControls()