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