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):
265 profile.setPluginConfig([])
266 self.updateProfileToControls()
267 self.scene.loadScene(files)
269 def OnModelMRU(self, e):
270 fileNum = e.GetId() - self.ID_MRU_MODEL1
271 path = self.modelFileHistory.GetHistoryFile(fileNum)
273 self.modelFileHistory.AddFileToHistory(path) # move up the list
274 self.config.SetPath("/ModelMRU")
275 self.modelFileHistory.Save(self.config)
279 self.scene.loadScene(filelist)
281 def addToModelMRU(self, file):
282 self.modelFileHistory.AddFileToHistory(file)
283 self.config.SetPath("/ModelMRU")
284 self.modelFileHistory.Save(self.config)
287 def OnProfileMRU(self, e):
288 fileNum = e.GetId() - self.ID_MRU_PROFILE1
289 path = self.profileFileHistory.GetHistoryFile(fileNum)
291 self.profileFileHistory.AddFileToHistory(path) # move up the list
292 self.config.SetPath("/ProfileMRU")
293 self.profileFileHistory.Save(self.config)
296 profile.loadProfile(path)
297 self.updateProfileToControls()
299 def addToProfileMRU(self, file):
300 self.profileFileHistory.AddFileToHistory(file)
301 self.config.SetPath("/ProfileMRU")
302 self.profileFileHistory.Save(self.config)
305 def updateProfileToControls(self):
306 self.scene.updateProfileToControls()
307 self.normalSettingsPanel.updateProfileToControls()
308 self.simpleSettingsPanel.updateProfileToControls()
310 def OnLoadProfile(self, e):
311 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)
312 dlg.SetWildcard("ini files (*.ini)|*.ini")
313 if dlg.ShowModal() == wx.ID_OK:
314 profileFile = dlg.GetPath()
315 profile.loadProfile(profileFile)
316 self.updateProfileToControls()
318 # Update the Profile MRU
319 self.addToProfileMRU(profileFile)
322 def OnLoadProfileFromGcode(self, e):
323 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)
324 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
325 if dlg.ShowModal() == wx.ID_OK:
326 gcodeFile = dlg.GetPath()
327 f = open(gcodeFile, 'r')
330 if line.startswith(';CURA_PROFILE_STRING:'):
331 profile.loadProfileFromString(line[line.find(':')+1:].strip())
334 self.updateProfileToControls()
336 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)
339 def OnSaveProfile(self, e):
340 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
341 dlg.SetWildcard("ini files (*.ini)|*.ini")
342 if dlg.ShowModal() == wx.ID_OK:
343 profileFile = dlg.GetPath()
344 profile.saveProfile(profileFile)
347 def OnResetProfile(self, e):
348 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)
349 result = dlg.ShowModal() == wx.ID_YES
352 profile.resetProfile()
353 self.updateProfileToControls()
355 def OnBatchRun(self, e):
356 br = batchRun.batchRunWindow(self)
360 def OnSimpleSwitch(self, e):
361 profile.putPreference('startMode', 'Simple')
362 self.updateSliceMode()
364 def OnNormalSwitch(self, e):
365 profile.putPreference('startMode', 'Normal')
366 self.updateSliceMode()
368 def OnDefaultMarlinFirmware(self, e):
369 firmwareInstall.InstallFirmware()
371 def OnCustomFirmware(self, e):
372 if profile.getPreference('machine_type') == 'ultimaker':
373 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)
374 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
375 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
376 if dlg.ShowModal() == wx.ID_OK:
377 filename = dlg.GetPath()
378 if not(os.path.exists(filename)):
380 #For some reason my Ubuntu 10.10 crashes here.
381 firmwareInstall.InstallFirmware(filename)
383 def OnFirstRunWizard(self, e):
384 configWizard.configWizard()
385 self.updateProfileToControls()
387 def OnBedLevelWizard(self, e):
388 configWizard.bedLevelWizard()
390 def OnHeadOffsetWizard(self, e):
391 configWizard.headOffsetWizard()
393 def OnExpertOpen(self, e):
394 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
398 def OnMinecraftImport(self, e):
399 mi = minecraftImport.minecraftImportWindow(self)
403 def OnSuperformula(self, e):
404 sf = superformula.superformulaWindow(self)
405 #sf = superformula.superformulaEvolver(self)
409 def OnCheckForUpdate(self, e):
410 newVersion = version.checkForNewerVersion()
411 if newVersion is not None:
412 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:
413 webbrowser.open(newVersion)
415 wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
417 def OnAbout(self, e):
418 info = wx.AboutDialogInfo()
420 info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.')
421 info.SetWebSite('http://software.ultimaker.com/')
422 info.SetCopyright('Copyright (C) David Braam')
424 This program is free software: you can redistribute it and/or modify
425 it under the terms of the GNU Affero General Public License as published by
426 the Free Software Foundation, either version 3 of the License, or
427 (at your option) any later version.
429 This program is distributed in the hope that it will be useful,
430 but WITHOUT ANY WARRANTY; without even the implied warranty of
431 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
432 GNU Affero General Public License for more details.
434 You should have received a copy of the GNU Affero General Public License
435 along with this program. If not, see <http://www.gnu.org/licenses/>.
439 def OnClose(self, e):
440 profile.saveProfile(profile.getDefaultProfilePath())
442 # Save the window position, size & state from the preferences file
443 profile.putPreference('window_maximized', self.IsMaximized())
444 if not self.IsMaximized() and not self.IsIconized():
445 (posx, posy) = self.GetPosition()
446 profile.putPreference('window_pos_x', posx)
447 profile.putPreference('window_pos_y', posy)
448 (width, height) = self.GetSize()
449 profile.putPreference('window_width', width)
450 profile.putPreference('window_height', height)
452 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
453 isSimple = profile.getPreference('startMode') == 'Simple'
455 self.normalSashPos = self.splitter.GetSashPosition()
456 profile.putPreference('window_normal_sash', self.normalSashPos)
458 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
460 self.scene.OnPaint = lambda e : e
461 self.scene._slicer.cleanup()
467 class normalSettingsPanel(configBase.configPanelBase):
468 "Main user interface window"
469 def __init__(self, parent, callback = None):
470 super(normalSettingsPanel, self).__init__(parent, callback)
473 self.nb = wx.Notebook(self)
474 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
475 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
477 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
478 self._addSettingsToPanels('basic', left, right)
479 self.SizeLabelWidths(left, right)
481 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
482 self._addSettingsToPanels('advanced', left, right)
483 self.SizeLabelWidths(left, right)
486 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
487 if len(self.pluginPanel.pluginList) > 0:
488 self.nb.AddPage(self.pluginPanel, "Plugins")
490 self.pluginPanel.Show(False)
493 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
494 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
496 self.Bind(wx.EVT_SIZE, self.OnSize)
498 self.nb.SetSize(self.GetSize())
499 self.UpdateSize(self.printPanel)
500 self.UpdateSize(self.advancedPanel)
502 def _addSettingsToPanels(self, category, left, right):
503 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
507 for title in profile.getSubCategoriesFor(category):
508 n += 1 + len(profile.getSettingsForCategory(category, title))
511 configBase.TitleRow(p, title)
512 for s in profile.getSettingsForCategory(category, title):
513 if s.checkConditions():
514 configBase.SettingRow(p, s.getName())
516 def SizeLabelWidths(self, left, right):
517 leftWidth = self.getLabelColumnWidth(left)
518 rightWidth = self.getLabelColumnWidth(right)
519 maxWidth = max(leftWidth, rightWidth)
520 self.setLabelColumnWidth(left, maxWidth)
521 self.setLabelColumnWidth(right, maxWidth)
524 # Make the size of the Notebook control the same size as this control
525 self.nb.SetSize(self.GetSize())
527 # Propegate the OnSize() event (just in case)
530 # Perform out resize magic
531 self.UpdateSize(self.printPanel)
532 self.UpdateSize(self.advancedPanel)
534 def UpdateSize(self, configPanel):
535 sizer = configPanel.GetSizer()
539 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
542 # if width(col1) > (best_width(col1) + best_width(col1)):
543 # switch to horizontal
546 col1 = configPanel.leftPanel
547 colSize1 = col1.GetSize()
548 colBestSize1 = col1.GetBestSize()
549 col2 = configPanel.rightPanel
550 colSize2 = col2.GetSize()
551 colBestSize2 = col2.GetBestSize()
553 orientation = sizer.GetOrientation()
555 if orientation == wx.HORIZONTAL:
556 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
558 sizer = wx.BoxSizer(wx.VERTICAL)
559 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
560 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
561 configPanel.SetSizer(sizer)
567 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
569 sizer = wx.BoxSizer(wx.HORIZONTAL)
570 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
571 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
572 configPanel.SetSizer(sizer)
578 def updateProfileToControls(self):
579 super(normalSettingsPanel, self).updateProfileToControls()
580 self.alterationPanel.updateProfileToControls()
581 self.pluginPanel.updateProfileToControls()