1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
8 from Cura.gui import configBase
9 from Cura.gui import expertConfig
10 from Cura.gui import alterationPanel
11 from Cura.gui import pluginPanel
12 from Cura.gui import preferencesDialog
13 from Cura.gui import configWizard
14 from Cura.gui import firmwareInstall
15 from Cura.gui import simpleMode
16 from Cura.gui import sceneView
17 #from Cura.gui.tools import batchRun
18 from Cura.gui.util import dropTarget
19 from Cura.gui.tools import minecraftImport
20 from Cura.gui.tools import superformula
21 from Cura.util import profile
22 from Cura.util import version
23 from Cura.util import meshLoader
25 class mainWindow(wx.Frame):
27 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
29 self.extruderCount = int(profile.getPreference('extruder_amount'))
31 wx.EVT_CLOSE(self, self.OnClose)
33 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions()))
35 self.normalModeOnlyItems = []
37 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
38 self.config = wx.FileConfig(appName="Cura",
39 localFilename=mruFile,
40 style=wx.CONFIG_USE_LOCAL_FILE)
42 self.ID_MRU_MODEL1, self.ID_MRU_MODEL2, self.ID_MRU_MODEL3, self.ID_MRU_MODEL4, self.ID_MRU_MODEL5, self.ID_MRU_MODEL6, self.ID_MRU_MODEL7, self.ID_MRU_MODEL8, self.ID_MRU_MODEL9, self.ID_MRU_MODEL10 = [wx.NewId() for line in xrange(10)]
43 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
44 self.config.SetPath("/ModelMRU")
45 self.modelFileHistory.Load(self.config)
47 self.ID_MRU_PROFILE1, self.ID_MRU_PROFILE2, self.ID_MRU_PROFILE3, self.ID_MRU_PROFILE4, self.ID_MRU_PROFILE5, self.ID_MRU_PROFILE6, self.ID_MRU_PROFILE7, self.ID_MRU_PROFILE8, self.ID_MRU_PROFILE9, self.ID_MRU_PROFILE10 = [wx.NewId() for line in xrange(10)]
48 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
49 self.config.SetPath("/ProfileMRU")
50 self.profileFileHistory.Load(self.config)
52 self.menubar = wx.MenuBar()
53 self.fileMenu = wx.Menu()
54 i = self.fileMenu.Append(-1, 'Load model file...\tCTRL+L')
55 self.Bind(wx.EVT_MENU, lambda e: self.scene.showLoadModel(), i)
56 i = self.fileMenu.Append(-1, 'Save model...\tCTRL+S')
57 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
58 i = self.fileMenu.Append(-1, 'Clear platform')
59 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
61 self.fileMenu.AppendSeparator()
62 i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
63 self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
64 i = self.fileMenu.Append(-1, 'Save GCode...')
65 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
67 self.fileMenu.AppendSeparator()
68 i = self.fileMenu.Append(-1, 'Open Profile...')
69 self.normalModeOnlyItems.append(i)
70 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
71 i = self.fileMenu.Append(-1, 'Save Profile...')
72 self.normalModeOnlyItems.append(i)
73 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
74 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
75 self.normalModeOnlyItems.append(i)
76 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
77 self.fileMenu.AppendSeparator()
78 i = self.fileMenu.Append(-1, 'Reset Profile to default')
79 self.normalModeOnlyItems.append(i)
80 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
82 self.fileMenu.AppendSeparator()
83 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
84 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
85 self.fileMenu.AppendSeparator()
88 modelHistoryMenu = wx.Menu()
89 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
90 self.modelFileHistory.UseMenu(modelHistoryMenu)
91 self.modelFileHistory.AddFilesToMenu()
92 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
95 profileHistoryMenu = wx.Menu()
96 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
97 self.profileFileHistory.UseMenu(profileHistoryMenu)
98 self.profileFileHistory.AddFilesToMenu()
99 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
101 self.fileMenu.AppendSeparator()
102 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
103 self.Bind(wx.EVT_MENU, self.OnQuit, i)
104 self.menubar.Append(self.fileMenu, '&File')
106 toolsMenu = wx.Menu()
107 i = toolsMenu.Append(-1, 'Switch to quickprint...')
108 self.switchToQuickprintMenuItem = i
109 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
110 i = toolsMenu.Append(-1, 'Switch to full settings...')
111 self.switchToNormalMenuItem = i
112 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
113 toolsMenu.AppendSeparator()
114 #i = toolsMenu.Append(-1, 'Batch run...')
115 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
116 #self.normalModeOnlyItems.append(i)
117 if minecraftImport.hasMinecraft():
118 i = toolsMenu.Append(-1, 'Minecraft import...')
119 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
120 i = toolsMenu.Append(-1, 'Super-shaper...')
121 self.Bind(wx.EVT_MENU, self.OnSuperformula, i)
122 self.menubar.Append(toolsMenu, 'Tools')
124 expertMenu = wx.Menu()
125 i = expertMenu.Append(-1, 'Open expert settings...')
126 self.normalModeOnlyItems.append(i)
127 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
128 expertMenu.AppendSeparator()
129 if firmwareInstall.getDefaultFirmware() is not None:
130 i = expertMenu.Append(-1, 'Install default Marlin firmware')
131 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
132 i = expertMenu.Append(-1, 'Install custom firmware')
133 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
134 expertMenu.AppendSeparator()
135 i = expertMenu.Append(-1, 'Run first run wizard...')
136 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
137 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
138 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
139 if self.extruderCount > 1:
140 i = expertMenu.Append(-1, 'Run head offset wizard...')
141 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
142 self.menubar.Append(expertMenu, 'Expert')
145 i = helpMenu.Append(-1, 'Online documentation...')
146 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
147 i = helpMenu.Append(-1, 'Report a problem...')
148 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
149 i = helpMenu.Append(-1, 'Check for update...')
150 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
151 i = helpMenu.Append(-1, 'About Cura...')
152 self.Bind(wx.EVT_MENU, self.OnAbout, i)
153 self.menubar.Append(helpMenu, 'Help')
154 self.SetMenuBar(self.menubar)
156 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
157 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
158 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
159 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
162 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
163 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
165 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
166 self.leftSizer.Add(self.simpleSettingsPanel)
167 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
168 self.leftPane.SetSizer(self.leftSizer)
171 self.scene = sceneView.SceneView(self.rightPane)
173 #Main sizer, to position the preview window, buttons and tab control
174 sizer = wx.BoxSizer()
175 self.rightPane.SetSizer(sizer)
176 sizer.Add(self.scene, 1, flag=wx.EXPAND)
179 sizer = wx.BoxSizer(wx.VERTICAL)
181 sizer.Add(self.splitter, 1, wx.EXPAND)
185 self.updateProfileToControls()
187 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
189 self.simpleSettingsPanel.Show(False)
190 self.normalSettingsPanel.Show(False)
192 # Set default window size & position
193 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
196 # Restore the window position, size & state from the preferences file
198 if profile.getPreference('window_maximized') == 'True':
201 posx = int(profile.getPreference('window_pos_x'))
202 posy = int(profile.getPreference('window_pos_y'))
203 width = int(profile.getPreference('window_width'))
204 height = int(profile.getPreference('window_height'))
205 if posx > 0 or posy > 0:
206 self.SetPosition((posx,posy))
207 if width > 0 and height > 0:
208 self.SetSize((width,height))
210 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
212 self.normalSashPos = 0
214 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
215 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
217 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
219 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
221 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
223 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
224 self.SetSize((800,600))
227 self.updateSliceMode()
229 def updateSliceMode(self):
230 isSimple = profile.getPreference('startMode') == 'Simple'
232 self.normalSettingsPanel.Show(not isSimple)
233 self.simpleSettingsPanel.Show(isSimple)
234 self.leftPane.Layout()
236 for i in self.normalModeOnlyItems:
237 i.Enable(not isSimple)
238 self.switchToQuickprintMenuItem.Enable(not isSimple)
239 self.switchToNormalMenuItem.Enable(isSimple)
241 # Set splitter sash position & size
243 # Save normal mode sash
244 self.normalSashPos = self.splitter.GetSashPosition()
246 # Change location of sash to width of quick mode pane
247 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
248 self.splitter.SetSashPosition(width, True)
251 self.splitter.SetSashSize(0)
253 self.splitter.SetSashPosition(self.normalSashPos, True)
255 self.splitter.SetSashSize(4)
256 self.scene.updateProfileToControls()
258 def OnPreferences(self, e):
259 prefDialog = preferencesDialog.preferencesDialog(self)
263 def OnDropFiles(self, files):
264 profile.setPluginConfig([])
265 self.updateProfileToControls()
266 self.scene.loadScene(files)
268 def OnModelMRU(self, e):
269 fileNum = e.GetId() - self.ID_MRU_MODEL1
270 path = self.modelFileHistory.GetHistoryFile(fileNum)
272 self.modelFileHistory.AddFileToHistory(path) # move up the list
273 self.config.SetPath("/ModelMRU")
274 self.modelFileHistory.Save(self.config)
278 self.scene.loadScene(filelist)
280 def addToModelMRU(self, file):
281 self.modelFileHistory.AddFileToHistory(file)
282 self.config.SetPath("/ModelMRU")
283 self.modelFileHistory.Save(self.config)
286 def OnProfileMRU(self, e):
287 fileNum = e.GetId() - self.ID_MRU_PROFILE1
288 path = self.profileFileHistory.GetHistoryFile(fileNum)
290 self.profileFileHistory.AddFileToHistory(path) # move up the list
291 self.config.SetPath("/ProfileMRU")
292 self.profileFileHistory.Save(self.config)
295 profile.loadProfile(path)
296 self.updateProfileToControls()
298 def addToProfileMRU(self, file):
299 self.profileFileHistory.AddFileToHistory(file)
300 self.config.SetPath("/ProfileMRU")
301 self.profileFileHistory.Save(self.config)
304 def updateProfileToControls(self):
305 self.scene.updateProfileToControls()
306 self.normalSettingsPanel.updateProfileToControls()
307 self.simpleSettingsPanel.updateProfileToControls()
309 def OnLoadProfile(self, e):
310 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)
311 dlg.SetWildcard("ini files (*.ini)|*.ini")
312 if dlg.ShowModal() == wx.ID_OK:
313 profileFile = dlg.GetPath()
314 profile.loadProfile(profileFile)
315 self.updateProfileToControls()
317 # Update the Profile MRU
318 self.addToProfileMRU(profileFile)
321 def OnLoadProfileFromGcode(self, e):
322 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)
323 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
324 if dlg.ShowModal() == wx.ID_OK:
325 gcodeFile = dlg.GetPath()
326 f = open(gcodeFile, 'r')
329 if line.startswith(';CURA_PROFILE_STRING:'):
330 profile.loadProfileFromString(line[line.find(':')+1:].strip())
333 self.updateProfileToControls()
335 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)
338 def OnSaveProfile(self, e):
339 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
340 dlg.SetWildcard("ini files (*.ini)|*.ini")
341 if dlg.ShowModal() == wx.ID_OK:
342 profileFile = dlg.GetPath()
343 profile.saveProfile(profileFile)
346 def OnResetProfile(self, e):
347 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)
348 result = dlg.ShowModal() == wx.ID_YES
351 profile.resetProfile()
352 self.updateProfileToControls()
354 def OnBatchRun(self, e):
355 br = batchRun.batchRunWindow(self)
359 def OnSimpleSwitch(self, e):
360 profile.putPreference('startMode', 'Simple')
361 self.updateSliceMode()
363 def OnNormalSwitch(self, e):
364 profile.putPreference('startMode', 'Normal')
365 self.updateSliceMode()
367 def OnDefaultMarlinFirmware(self, e):
368 firmwareInstall.InstallFirmware()
370 def OnCustomFirmware(self, e):
371 if profile.getPreference('machine_type') == 'ultimaker':
372 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)
373 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
374 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
375 if dlg.ShowModal() == wx.ID_OK:
376 filename = dlg.GetPath()
377 if not(os.path.exists(filename)):
379 #For some reason my Ubuntu 10.10 crashes here.
380 firmwareInstall.InstallFirmware(filename)
382 def OnFirstRunWizard(self, e):
383 configWizard.configWizard()
384 self.updateProfileToControls()
386 def OnBedLevelWizard(self, e):
387 configWizard.bedLevelWizard()
389 def OnHeadOffsetWizard(self, e):
390 configWizard.headOffsetWizard()
392 def OnExpertOpen(self, e):
393 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
397 def OnMinecraftImport(self, e):
398 mi = minecraftImport.minecraftImportWindow(self)
402 def OnSuperformula(self, e):
403 sf = superformula.superformulaWindow(self)
404 #sf = superformula.superformulaEvolver(self)
408 def OnCheckForUpdate(self, e):
409 newVersion = version.checkForNewerVersion()
410 if newVersion is not None:
411 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:
412 webbrowser.open(newVersion)
414 wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
416 def OnAbout(self, e):
417 info = wx.AboutDialogInfo()
419 info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.')
420 info.SetWebSite('http://software.ultimaker.com/')
421 info.SetCopyright('Copyright (C) David Braam')
423 This program is free software: you can redistribute it and/or modify
424 it under the terms of the GNU Affero General Public License as published by
425 the Free Software Foundation, either version 3 of the License, or
426 (at your option) any later version.
428 This program is distributed in the hope that it will be useful,
429 but WITHOUT ANY WARRANTY; without even the implied warranty of
430 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
431 GNU Affero General Public License for more details.
433 You should have received a copy of the GNU Affero General Public License
434 along with this program. If not, see <http://www.gnu.org/licenses/>.
438 def OnClose(self, e):
439 profile.saveProfile(profile.getDefaultProfilePath())
441 # Save the window position, size & state from the preferences file
442 profile.putPreference('window_maximized', self.IsMaximized())
443 if not self.IsMaximized() and not self.IsIconized():
444 (posx, posy) = self.GetPosition()
445 profile.putPreference('window_pos_x', posx)
446 profile.putPreference('window_pos_y', posy)
447 (width, height) = self.GetSize()
448 profile.putPreference('window_width', width)
449 profile.putPreference('window_height', height)
451 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
452 isSimple = profile.getPreference('startMode') == 'Simple'
454 self.normalSashPos = self.splitter.GetSashPosition()
455 profile.putPreference('window_normal_sash', self.normalSashPos)
457 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
459 self.scene.OnPaint = lambda e : e
460 self.scene._slicer.cleanup()
466 class normalSettingsPanel(configBase.configPanelBase):
467 "Main user interface window"
468 def __init__(self, parent, callback = None):
469 super(normalSettingsPanel, self).__init__(parent, callback)
472 self.nb = wx.Notebook(self)
473 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
474 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
476 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
477 self._addSettingsToPanels('basic', left, right)
478 self.SizeLabelWidths(left, right)
480 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
481 self._addSettingsToPanels('advanced', left, right)
482 self.SizeLabelWidths(left, right)
485 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
486 if len(self.pluginPanel.pluginList) > 0:
487 self.nb.AddPage(self.pluginPanel, "Plugins")
489 self.pluginPanel.Show(False)
492 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
493 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
495 self.Bind(wx.EVT_SIZE, self.OnSize)
497 self.nb.SetSize(self.GetSize())
498 self.UpdateSize(self.printPanel)
499 self.UpdateSize(self.advancedPanel)
501 def _addSettingsToPanels(self, category, left, right):
502 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
506 for title in profile.getSubCategoriesFor(category):
507 n += 1 + len(profile.getSettingsForCategory(category, title))
510 configBase.TitleRow(p, title)
511 for s in profile.getSettingsForCategory(category, title):
512 if s.checkConditions():
513 configBase.SettingRow(p, s.getName())
515 def SizeLabelWidths(self, left, right):
516 leftWidth = self.getLabelColumnWidth(left)
517 rightWidth = self.getLabelColumnWidth(right)
518 maxWidth = max(leftWidth, rightWidth)
519 self.setLabelColumnWidth(left, maxWidth)
520 self.setLabelColumnWidth(right, maxWidth)
523 # Make the size of the Notebook control the same size as this control
524 self.nb.SetSize(self.GetSize())
526 # Propegate the OnSize() event (just in case)
529 # Perform out resize magic
530 self.UpdateSize(self.printPanel)
531 self.UpdateSize(self.advancedPanel)
533 def UpdateSize(self, configPanel):
534 sizer = configPanel.GetSizer()
538 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
541 # if width(col1) > (best_width(col1) + best_width(col1)):
542 # switch to horizontal
545 col1 = configPanel.leftPanel
546 colSize1 = col1.GetSize()
547 colBestSize1 = col1.GetBestSize()
548 col2 = configPanel.rightPanel
549 colSize2 = col2.GetSize()
550 colBestSize2 = col2.GetBestSize()
552 orientation = sizer.GetOrientation()
554 if orientation == wx.HORIZONTAL:
555 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
557 sizer = wx.BoxSizer(wx.VERTICAL)
558 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
559 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
560 configPanel.SetSizer(sizer)
566 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
568 sizer = wx.BoxSizer(wx.HORIZONTAL)
569 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
570 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
571 configPanel.SetSizer(sizer)
577 def updateProfileToControls(self):
578 super(normalSettingsPanel, self).updateProfileToControls()
579 self.alterationPanel.updateProfileToControls()
580 self.pluginPanel.updateProfileToControls()