chiark / gitweb /
Small tooltip spelling update. fix an issue opening the save dialog on Mac.
[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                 self.menubar.Append(helpMenu, 'Help')
149                 self.SetMenuBar(self.menubar)
150
151                 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
152                 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
153                 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
154                 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
155
156                 ##Gui components##
157                 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
158                 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
159
160                 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
161                 self.leftSizer.Add(self.simpleSettingsPanel)
162                 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
163                 self.leftPane.SetSizer(self.leftSizer)
164                 
165                 #Preview window
166                 self.scene = sceneView.SceneView(self.rightPane)
167
168                 #Main sizer, to position the preview window, buttons and tab control
169                 sizer = wx.BoxSizer()
170                 self.rightPane.SetSizer(sizer)
171                 sizer.Add(self.scene, 1, flag=wx.EXPAND)
172
173                 # Main window sizer
174                 sizer = wx.BoxSizer(wx.VERTICAL)
175                 self.SetSizer(sizer)
176                 sizer.Add(self.splitter, 1, wx.EXPAND)
177                 sizer.Layout()
178                 self.sizer = sizer
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         def updateSliceMode(self):
225                 isSimple = profile.getPreference('startMode') == 'Simple'
226
227                 self.normalSettingsPanel.Show(not isSimple)
228                 self.simpleSettingsPanel.Show(isSimple)
229                 self.leftPane.Layout()
230
231                 for i in self.normalModeOnlyItems:
232                         i.Enable(not isSimple)
233                 self.switchToQuickprintMenuItem.Enable(not isSimple)
234                 self.switchToNormalMenuItem.Enable(isSimple)
235
236                 # Set splitter sash position & size
237                 if isSimple:
238                         # Save normal mode sash
239                         self.normalSashPos = self.splitter.GetSashPosition()
240                         
241                         # Change location of sash to width of quick mode pane 
242                         (width, height) = self.simpleSettingsPanel.GetSizer().GetSize() 
243                         self.splitter.SetSashPosition(width, True)
244                         
245                         # Disable sash
246                         self.splitter.SetSashSize(0)
247                 else:
248                         self.splitter.SetSashPosition(self.normalSashPos, True)
249                         # Enabled sash
250                         self.splitter.SetSashSize(4)
251                 self.scene.updateProfileToControls()
252                                                                 
253         def OnPreferences(self, e):
254                 prefDialog = preferencesDialog.preferencesDialog(self)
255                 prefDialog.Centre()
256                 prefDialog.Show()
257
258         def OnDropFiles(self, files):
259                 profile.setPluginConfig([])
260                 self.updateProfileToControls()
261                 self.scene.loadScene(files)
262
263         def OnModelMRU(self, e):
264                 fileNum = e.GetId() - self.ID_MRU_MODEL1
265                 path = self.modelFileHistory.GetHistoryFile(fileNum)
266                 # Update Model MRU
267                 self.modelFileHistory.AddFileToHistory(path)  # move up the list
268                 self.config.SetPath("/ModelMRU")
269                 self.modelFileHistory.Save(self.config)
270                 self.config.Flush()
271                 # Load Model
272                 filelist = [ path ]
273                 self.scene.loadScene(filelist)
274
275         def addToModelMRU(self, file):
276                 self.modelFileHistory.AddFileToHistory(file)
277                 self.config.SetPath("/ModelMRU")
278                 self.modelFileHistory.Save(self.config)
279                 self.config.Flush()
280         
281         def OnProfileMRU(self, e):
282                 fileNum = e.GetId() - self.ID_MRU_PROFILE1
283                 path = self.profileFileHistory.GetHistoryFile(fileNum)
284                 # Update Profile MRU
285                 self.profileFileHistory.AddFileToHistory(path)  # move up the list
286                 self.config.SetPath("/ProfileMRU")
287                 self.profileFileHistory.Save(self.config)
288                 self.config.Flush()
289                 # Load Profile  
290                 profile.loadProfile(path)
291                 self.updateProfileToControls()
292
293         def addToProfileMRU(self, file):
294                 self.profileFileHistory.AddFileToHistory(file)
295                 self.config.SetPath("/ProfileMRU")
296                 self.profileFileHistory.Save(self.config)
297                 self.config.Flush()                     
298
299         def updateProfileToControls(self):
300                 self.scene.updateProfileToControls()
301                 self.normalSettingsPanel.updateProfileToControls()
302                 self.simpleSettingsPanel.updateProfileToControls()
303
304         def OnLoadProfile(self, e):
305                 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)
306                 dlg.SetWildcard("ini files (*.ini)|*.ini")
307                 if dlg.ShowModal() == wx.ID_OK:
308                         profileFile = dlg.GetPath()
309                         profile.loadProfile(profileFile)
310                         self.updateProfileToControls()
311
312                         # Update the Profile MRU
313                         self.addToProfileMRU(profileFile)
314                 dlg.Destroy()
315
316         def OnLoadProfileFromGcode(self, e):
317                 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)
318                 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
319                 if dlg.ShowModal() == wx.ID_OK:
320                         gcodeFile = dlg.GetPath()
321                         f = open(gcodeFile, 'r')
322                         hasProfile = False
323                         for line in f:
324                                 if line.startswith(';CURA_PROFILE_STRING:'):
325                                         profile.loadProfileFromString(line[line.find(':')+1:].strip())
326                                         hasProfile = True
327                         if hasProfile:
328                                 self.updateProfileToControls()
329                         else:
330                                 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)
331                 dlg.Destroy()
332
333         def OnSaveProfile(self, e):
334                 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
335                 dlg.SetWildcard("ini files (*.ini)|*.ini")
336                 if dlg.ShowModal() == wx.ID_OK:
337                         profileFile = dlg.GetPath()
338                         profile.saveProfile(profileFile)
339                 dlg.Destroy()
340
341         def OnResetProfile(self, e):
342                 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)
343                 result = dlg.ShowModal() == wx.ID_YES
344                 dlg.Destroy()
345                 if result:
346                         profile.resetProfile()
347                         self.updateProfileToControls()
348
349         def OnBatchRun(self, e):
350                 br = batchRun.batchRunWindow(self)
351                 br.Centre()
352                 br.Show(True)
353
354         def OnSimpleSwitch(self, e):
355                 profile.putPreference('startMode', 'Simple')
356                 self.updateSliceMode()
357
358         def OnNormalSwitch(self, e):
359                 profile.putPreference('startMode', 'Normal')
360                 self.updateSliceMode()
361
362         def OnDefaultMarlinFirmware(self, e):
363                 firmwareInstall.InstallFirmware()
364
365         def OnCustomFirmware(self, e):
366                 if profile.getPreference('machine_type') == 'ultimaker':
367                         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)
368                 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
369                 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
370                 if dlg.ShowModal() == wx.ID_OK:
371                         filename = dlg.GetPath()
372                         if not(os.path.exists(filename)):
373                                 return
374                         #For some reason my Ubuntu 10.10 crashes here.
375                         firmwareInstall.InstallFirmware(filename)
376
377         def OnFirstRunWizard(self, e):
378                 configWizard.configWizard()
379                 self.updateProfileToControls()
380
381         def OnBedLevelWizard(self, e):
382                 configWizard.bedLevelWizard()
383
384         def OnHeadOffsetWizard(self, e):
385                 configWizard.headOffsetWizard()
386
387         def OnExpertOpen(self, e):
388                 ecw = expertConfig.expertConfigWindow()
389                 ecw.Centre()
390                 ecw.ShowModal()
391                 self.scene.sceneUpdated()
392
393         def OnMinecraftImport(self, e):
394                 mi = minecraftImport.minecraftImportWindow(self)
395                 mi.Centre()
396                 mi.Show(True)
397
398         def OnSuperformula(self, e):
399                 sf = superformula.superformulaWindow(self)
400                 #sf = superformula.superformulaEvolver(self)
401                 sf.Centre()
402                 sf.Show(True)
403
404         def OnCheckForUpdate(self, e):
405                 newVersion = version.checkForNewerVersion()
406                 if newVersion is not None:
407                         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:
408                                 webbrowser.open(newVersion)
409                 else:
410                         wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
411
412         def OnClose(self, e):
413                 profile.saveProfile(profile.getDefaultProfilePath())
414
415                 # Save the window position, size & state from the preferences file
416                 profile.putPreference('window_maximized', self.IsMaximized())
417                 if not self.IsMaximized() and not self.IsIconized():
418                         (posx, posy) = self.GetPosition()
419                         profile.putPreference('window_pos_x', posx)
420                         profile.putPreference('window_pos_y', posy)
421                         (width, height) = self.GetSize()
422                         profile.putPreference('window_width', width)
423                         profile.putPreference('window_height', height)                  
424                         
425                         # Save normal sash position.  If in normal mode (!simple mode), get last position of sash before saving it...
426                         isSimple = profile.getPreference('startMode') == 'Simple'
427                         if not isSimple:
428                                 self.normalSashPos = self.splitter.GetSashPosition()
429                         profile.putPreference('window_normal_sash', self.normalSashPos)
430
431                 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
432                 print "Closing down"
433                 self.scene.OnPaint = lambda e : e
434                 self.scene._slicer.cleanup()
435                 self.Destroy()
436
437         def OnQuit(self, e):
438                 self.Close()
439
440 class normalSettingsPanel(configBase.configPanelBase):
441         "Main user interface window"
442         def __init__(self, parent, callback = None):
443                 super(normalSettingsPanel, self).__init__(parent, callback)
444
445                 #Main tabs
446                 self.nb = wx.Notebook(self)
447                 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
448                 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
449
450                 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
451                 self._addSettingsToPanels('basic', left, right)
452                 self.SizeLabelWidths(left, right)
453                 
454                 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
455                 self._addSettingsToPanels('advanced', left, right)
456                 self.SizeLabelWidths(left, right)
457
458                 #Plugin page
459                 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
460                 if len(self.pluginPanel.pluginList) > 0:
461                         self.nb.AddPage(self.pluginPanel, "Plugins")
462                 else:
463                         self.pluginPanel.Show(False)
464
465                 #Alteration page
466                 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
467                 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
468
469                 self.Bind(wx.EVT_SIZE, self.OnSize)
470
471                 self.nb.SetSize(self.GetSize())
472                 self.UpdateSize(self.printPanel)
473                 self.UpdateSize(self.advancedPanel)
474
475         def _addSettingsToPanels(self, category, left, right):
476                 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
477
478                 p = left
479                 n = 0
480                 for title in profile.getSubCategoriesFor(category):
481                         n += 1 + len(profile.getSettingsForCategory(category, title))
482                         if n > count / 2:
483                                 p = right
484                         configBase.TitleRow(p, title)
485                         for s in profile.getSettingsForCategory(category, title):
486                                 if s.checkConditions():
487                                         configBase.SettingRow(p, s.getName())
488
489         def SizeLabelWidths(self, left, right):
490                 leftWidth = self.getLabelColumnWidth(left)
491                 rightWidth = self.getLabelColumnWidth(right)
492                 maxWidth = max(leftWidth, rightWidth)
493                 self.setLabelColumnWidth(left, maxWidth)
494                 self.setLabelColumnWidth(right, maxWidth)
495
496         def OnSize(self, e):
497                 # Make the size of the Notebook control the same size as this control
498                 self.nb.SetSize(self.GetSize())
499                 
500                 # Propegate the OnSize() event (just in case)
501                 e.Skip()
502                 
503                 # Perform out resize magic
504                 self.UpdateSize(self.printPanel)
505                 self.UpdateSize(self.advancedPanel)
506         
507         def UpdateSize(self, configPanel):
508                 sizer = configPanel.GetSizer()
509                 
510                 # Pseudocde
511                 # if horizontal:
512                 #     if width(col1) < best_width(col1) || width(col2) < best_width(col2):
513                 #         switch to vertical
514                 # else:
515                 #     if width(col1) > (best_width(col1) + best_width(col1)):
516                 #         switch to horizontal
517                 #
518                                 
519                 col1 = configPanel.leftPanel
520                 colSize1 = col1.GetSize()
521                 colBestSize1 = col1.GetBestSize()
522                 col2 = configPanel.rightPanel
523                 colSize2 = col2.GetSize()
524                 colBestSize2 = col2.GetBestSize()
525
526                 orientation = sizer.GetOrientation()
527                 
528                 if orientation == wx.HORIZONTAL:
529                         if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
530                                 configPanel.Freeze()
531                                 sizer = wx.BoxSizer(wx.VERTICAL)
532                                 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
533                                 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
534                                 configPanel.SetSizer(sizer)
535                                 #sizer.Layout()
536                                 configPanel.Layout()
537                                 self.Layout()
538                                 configPanel.Thaw()
539                 else:
540                         if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
541                                 configPanel.Freeze()
542                                 sizer = wx.BoxSizer(wx.HORIZONTAL)
543                                 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
544                                 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
545                                 configPanel.SetSizer(sizer)
546                                 #sizer.Layout()
547                                 configPanel.Layout()
548                                 self.Layout()
549                                 configPanel.Thaw()
550
551         def updateProfileToControls(self):
552                 super(normalSettingsPanel, self).updateProfileToControls()
553                 self.alterationPanel.updateProfileToControls()
554                 self.pluginPanel.updateProfileToControls()