chiark / gitweb /
Merge branch 'master' into SteamEngine
[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.util import profile
20 from Cura.util import version
21 from Cura.util import meshLoader
22
23 class mainWindow(wx.Frame):
24         def __init__(self):
25                 super(mainWindow, self).__init__(None, title='Cura Steam Engine BETA - ' + version.getVersion())
26
27                 self.extruderCount = int(profile.getPreference('extruder_amount'))
28
29                 wx.EVT_CLOSE(self, self.OnClose)
30
31                 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.supportedExtensions()))
32
33                 self.normalModeOnlyItems = []
34
35                 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
36                 self.config = wx.FileConfig(appName="Cura", 
37                                                 localFilename=mruFile,
38                                                 style=wx.CONFIG_USE_LOCAL_FILE)
39                                                 
40                 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)]
41                 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
42                 self.config.SetPath("/ModelMRU")
43                 self.modelFileHistory.Load(self.config)
44
45                 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)]
46                 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
47                 self.config.SetPath("/ProfileMRU")
48                 self.profileFileHistory.Load(self.config)
49
50                 self.menubar = wx.MenuBar()
51                 self.fileMenu = wx.Menu()
52                 i = self.fileMenu.Append(-1, 'Load model file...\tCTRL+L')
53                 self.Bind(wx.EVT_MENU, lambda e: self.scene.ShowLoadModel(1), i)
54                 i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
55                 self.Bind(wx.EVT_MENU, lambda e: self.scene.ShowPrintWindow(), i)
56
57                 self.fileMenu.AppendSeparator()
58                 i = self.fileMenu.Append(-1, 'Open Profile...')
59                 self.normalModeOnlyItems.append(i)
60                 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
61                 i = self.fileMenu.Append(-1, 'Save Profile...')
62                 self.normalModeOnlyItems.append(i)
63                 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
64                 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
65                 self.normalModeOnlyItems.append(i)
66                 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
67                 self.fileMenu.AppendSeparator()
68                 i = self.fileMenu.Append(-1, 'Reset Profile to default')
69                 self.normalModeOnlyItems.append(i)
70                 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
71
72                 self.fileMenu.AppendSeparator()
73                 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
74                 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
75                 self.fileMenu.AppendSeparator()
76
77                 # Model MRU list
78                 modelHistoryMenu = wx.Menu()
79                 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
80                 self.modelFileHistory.UseMenu(modelHistoryMenu)
81                 self.modelFileHistory.AddFilesToMenu()
82                 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
83
84                 # Profle MRU list
85                 profileHistoryMenu = wx.Menu()
86                 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
87                 self.profileFileHistory.UseMenu(profileHistoryMenu)
88                 self.profileFileHistory.AddFilesToMenu()
89                 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
90                 
91                 self.fileMenu.AppendSeparator()
92                 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
93                 self.Bind(wx.EVT_MENU, self.OnQuit, i)
94                 self.menubar.Append(self.fileMenu, '&File')
95
96                 toolsMenu = wx.Menu()
97                 i = toolsMenu.Append(-1, 'Switch to quickprint...')
98                 self.switchToQuickprintMenuItem = i
99                 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
100                 i = toolsMenu.Append(-1, 'Switch to full settings...')
101                 self.switchToNormalMenuItem = i
102                 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
103                 toolsMenu.AppendSeparator()
104                 #i = toolsMenu.Append(-1, 'Batch run...')
105                 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
106                 #self.normalModeOnlyItems.append(i)
107                 if minecraftImport.hasMinecraft():
108                         i = toolsMenu.Append(-1, 'Minecraft import...')
109                         self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
110                 self.menubar.Append(toolsMenu, 'Tools')
111
112                 expertMenu = wx.Menu()
113                 i = expertMenu.Append(-1, 'Open expert settings...')
114                 self.normalModeOnlyItems.append(i)
115                 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
116                 expertMenu.AppendSeparator()
117                 if firmwareInstall.getDefaultFirmware() is not None:
118                         i = expertMenu.Append(-1, 'Install default Marlin firmware')
119                         self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
120                 i = expertMenu.Append(-1, 'Install custom firmware')
121                 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
122                 expertMenu.AppendSeparator()
123                 i = expertMenu.Append(-1, 'Run first run wizard...')
124                 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
125                 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
126                 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
127                 self.menubar.Append(expertMenu, 'Expert')
128
129                 helpMenu = wx.Menu()
130                 i = helpMenu.Append(-1, 'Online documentation...')
131                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
132                 i = helpMenu.Append(-1, 'Report a problem...')
133                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
134                 i = helpMenu.Append(-1, 'Check for update...')
135                 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
136                 self.menubar.Append(helpMenu, 'Help')
137                 self.SetMenuBar(self.menubar)
138
139                 if profile.getPreference('lastFile') != '':
140                         self.filelist = profile.getPreference('lastFile').split(';')
141                 else:
142                         self.filelist = []
143
144                 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
145                 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
146                 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
147                 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
148
149                 ##Gui components##
150                 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane)
151                 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
152
153                 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
154                 self.leftSizer.Add(self.simpleSettingsPanel)
155                 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
156                 self.leftPane.SetSizer(self.leftSizer)
157                 
158                 #Preview window
159                 self.scene = sceneView.SceneView(self.rightPane)
160
161                 #Main sizer, to position the preview window, buttons and tab control
162                 sizer = wx.BoxSizer()
163                 self.rightPane.SetSizer(sizer)
164                 sizer.Add(self.scene, 1, flag=wx.EXPAND)
165
166                 # Main window sizer
167                 sizer = wx.BoxSizer(wx.VERTICAL)
168                 self.SetSizer(sizer)
169                 sizer.Add(self.splitter, 1, wx.EXPAND)
170                 sizer.Layout()
171                 self.sizer = sizer
172
173                 if len(self.filelist) > 0:
174                         self.scene.loadScene(self.filelist)
175
176                         # Update the Model MRU
177                         for idx in xrange(0, len(self.filelist)):
178                                 self.addToModelMRU(self.filelist[idx])
179
180                 self.updateProfileToControls()
181
182                 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
183
184                 self.simpleSettingsPanel.Show(False)
185                 self.normalSettingsPanel.Show(False)
186
187                 # Set default window size & position
188                 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
189                 self.Centre()
190
191                 # Restore the window position, size & state from the preferences file
192                 try:
193                         if profile.getPreference('window_maximized') == 'True':
194                                 self.Maximize(True)
195                         else:
196                                 posx = int(profile.getPreference('window_pos_x'))
197                                 posy = int(profile.getPreference('window_pos_y'))
198                                 width = int(profile.getPreference('window_width'))
199                                 height = int(profile.getPreference('window_height'))
200                                 if posx > 0 or posy > 0:
201                                         self.SetPosition((posx,posy))
202                                 if width > 0 and height > 0:
203                                         self.SetSize((width,height))
204                                 
205                         self.normalSashPos = int(profile.getPreference('window_normal_sash'))
206                 except:
207                         self.normalSashPos = 0
208                         self.Maximize(True)
209                 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
210                         self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
211
212                 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
213
214                 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
215                         self.Centre()
216                 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
217                         self.Centre()
218                 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
219                         self.SetSize((800,600))
220                         self.Centre()
221
222                 self.updateSliceMode()
223
224                 self.Show(True)
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 OnExpertOpen(self, e):
387                 ecw = expertConfig.expertConfigWindow()
388                 ecw.Centre()
389                 ecw.ShowModal()
390                 self.scene.sceneUpdated()
391
392         def OnMinecraftImport(self, e):
393                 mi = minecraftImport.minecraftImportWindow(self)
394                 mi.Centre()
395                 mi.Show(True)
396
397         def OnCheckForUpdate(self, e):
398                 newVersion = version.checkForNewerVersion()
399                 if newVersion is not None:
400                         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:
401                                 webbrowser.open(newVersion)
402                 else:
403                         wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
404
405         def OnClose(self, e):
406                 profile.saveProfile(profile.getDefaultProfilePath())
407
408                 # Save the window position, size & state from the preferences file
409                 profile.putPreference('window_maximized', self.IsMaximized())
410                 if not self.IsMaximized() and not self.IsIconized():
411                         (posx, posy) = self.GetPosition()
412                         profile.putPreference('window_pos_x', posx)
413                         profile.putPreference('window_pos_y', posy)
414                         (width, height) = self.GetSize()
415                         profile.putPreference('window_width', width)
416                         profile.putPreference('window_height', height)                  
417                         
418                         # Save normal sash position.  If in normal mode (!simple mode), get last position of sash before saving it...
419                         isSimple = profile.getPreference('startMode') == 'Simple'
420                         if not isSimple:
421                                 self.normalSashPos = self.splitter.GetSashPosition()
422                         profile.putPreference('window_normal_sash', self.normalSashPos)
423
424                 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
425                 print "Closing down"
426                 self.scene.OnPaint = lambda e : e
427                 self.scene._slicer.cleanup()
428                 self.Destroy()
429
430         def OnQuit(self, e):
431                 self.Close()
432
433 class normalSettingsPanel(configBase.configPanelBase):
434         "Main user interface window"
435         def __init__(self, parent, callback = None):
436                 super(normalSettingsPanel, self).__init__(parent, callback)
437
438                 #Main tabs
439                 self.nb = wx.Notebook(self)
440                 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
441                 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
442
443                 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
444                 self._addSettingsToPanels('basic', left, right)
445                 self.SizeLabelWidths(left, right)
446                 
447                 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
448                 self._addSettingsToPanels('advanced', left, right)
449                 self.SizeLabelWidths(left, right)
450
451                 #Plugin page
452                 self.pluginPanel = pluginPanel.pluginPanel(self.nb)
453                 if len(self.pluginPanel.pluginList) > 0 and False:
454                         self.nb.AddPage(self.pluginPanel, "Plugins")
455                 else:
456                         self.pluginPanel.Show(False)
457
458                 #Alteration page
459                 self.alterationPanel = alterationPanel.alterationPanel(self.nb)
460                 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
461
462                 self.Bind(wx.EVT_SIZE, self.OnSize)
463
464                 self.nb.SetSize(self.GetSize())
465                 self.UpdateSize(self.printPanel)
466                 self.UpdateSize(self.advancedPanel)
467
468         def _addSettingsToPanels(self, category, left, right):
469                 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
470
471                 p = left
472                 n = 0
473                 for title in profile.getSubCategoriesFor(category):
474                         n += 1 + len(profile.getSettingsForCategory(category, title))
475                         if n > count / 2:
476                                 p = right
477                         configBase.TitleRow(p, title)
478                         for s in profile.getSettingsForCategory(category, title):
479                                 if s.checkConditions():
480                                         configBase.SettingRow(p, s.getName())
481
482         def SizeLabelWidths(self, left, right):
483                 leftWidth = self.getLabelColumnWidth(left)
484                 rightWidth = self.getLabelColumnWidth(right)
485                 maxWidth = max(leftWidth, rightWidth)
486                 self.setLabelColumnWidth(left, maxWidth)
487                 self.setLabelColumnWidth(right, maxWidth)
488
489         def OnSize(self, e):
490                 # Make the size of the Notebook control the same size as this control
491                 self.nb.SetSize(self.GetSize())
492                 
493                 # Propegate the OnSize() event (just in case)
494                 e.Skip()
495                 
496                 # Perform out resize magic
497                 self.UpdateSize(self.printPanel)
498                 self.UpdateSize(self.advancedPanel)
499         
500         def UpdateSize(self, configPanel):
501                 sizer = configPanel.GetSizer()
502                 
503                 # Pseudocde
504                 # if horizontal:
505                 #     if width(col1) < best_width(col1) || width(col2) < best_width(col2):
506                 #         switch to vertical
507                 # else:
508                 #     if width(col1) > (best_width(col1) + best_width(col1)):
509                 #         switch to horizontal
510                 #
511                                 
512                 col1 = configPanel.leftPanel
513                 colSize1 = col1.GetSize()
514                 colBestSize1 = col1.GetBestSize()
515                 col2 = configPanel.rightPanel
516                 colSize2 = col2.GetSize()
517                 colBestSize2 = col2.GetBestSize()
518
519                 orientation = sizer.GetOrientation()
520                 
521                 if orientation == wx.HORIZONTAL:
522                         if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
523                                 configPanel.Freeze()
524                                 sizer = wx.BoxSizer(wx.VERTICAL)
525                                 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
526                                 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
527                                 configPanel.SetSizer(sizer)
528                                 #sizer.Layout()
529                                 configPanel.Layout()
530                                 self.Layout()
531                                 configPanel.Thaw()
532                 else:
533                         if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
534                                 configPanel.Freeze()
535                                 sizer = wx.BoxSizer(wx.HORIZONTAL)
536                                 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
537                                 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
538                                 configPanel.SetSizer(sizer)
539                                 #sizer.Layout()
540                                 configPanel.Layout()
541                                 self.Layout()
542                                 configPanel.Thaw()
543
544         def updateProfileToControls(self):
545                 super(normalSettingsPanel, self).updateProfileToControls()
546                 self.alterationPanel.updateProfileToControls()
547                 self.pluginPanel.updateProfileToControls()