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)
66 i = self.fileMenu.Append(-1, 'Show slice engine log...')
67 self.Bind(wx.EVT_MENU, lambda e: self.scene._showSliceLog(), i)
69 self.fileMenu.AppendSeparator()
70 i = self.fileMenu.Append(-1, 'Open Profile...')
71 self.normalModeOnlyItems.append(i)
72 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
73 i = self.fileMenu.Append(-1, 'Save Profile...')
74 self.normalModeOnlyItems.append(i)
75 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
76 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
77 self.normalModeOnlyItems.append(i)
78 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
79 self.fileMenu.AppendSeparator()
80 i = self.fileMenu.Append(-1, 'Reset Profile to default')
81 self.normalModeOnlyItems.append(i)
82 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
84 self.fileMenu.AppendSeparator()
85 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
86 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
87 self.fileMenu.AppendSeparator()
90 modelHistoryMenu = wx.Menu()
91 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
92 self.modelFileHistory.UseMenu(modelHistoryMenu)
93 self.modelFileHistory.AddFilesToMenu()
94 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
97 profileHistoryMenu = wx.Menu()
98 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
99 self.profileFileHistory.UseMenu(profileHistoryMenu)
100 self.profileFileHistory.AddFilesToMenu()
101 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
103 self.fileMenu.AppendSeparator()
104 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
105 self.Bind(wx.EVT_MENU, self.OnQuit, i)
106 self.menubar.Append(self.fileMenu, '&File')
108 toolsMenu = wx.Menu()
109 i = toolsMenu.Append(-1, 'Switch to quickprint...')
110 self.switchToQuickprintMenuItem = i
111 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
112 i = toolsMenu.Append(-1, 'Switch to full settings...')
113 self.switchToNormalMenuItem = i
114 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
115 toolsMenu.AppendSeparator()
116 #i = toolsMenu.Append(-1, 'Batch run...')
117 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
118 #self.normalModeOnlyItems.append(i)
119 if minecraftImport.hasMinecraft():
120 i = toolsMenu.Append(-1, 'Minecraft import...')
121 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
122 i = toolsMenu.Append(-1, 'Super-shaper...')
123 self.Bind(wx.EVT_MENU, self.OnSuperformula, i)
124 self.menubar.Append(toolsMenu, 'Tools')
126 expertMenu = wx.Menu()
127 i = expertMenu.Append(-1, 'Open expert settings...')
128 self.normalModeOnlyItems.append(i)
129 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
130 expertMenu.AppendSeparator()
131 if firmwareInstall.getDefaultFirmware() is not None:
132 i = expertMenu.Append(-1, 'Install default Marlin firmware')
133 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
134 i = expertMenu.Append(-1, 'Install custom firmware')
135 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
136 expertMenu.AppendSeparator()
137 i = expertMenu.Append(-1, 'Run first run wizard...')
138 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
139 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
140 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
141 if self.extruderCount > 1:
142 i = expertMenu.Append(-1, 'Run head offset wizard...')
143 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
144 self.menubar.Append(expertMenu, 'Expert')
147 i = helpMenu.Append(-1, 'Online documentation...')
148 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
149 i = helpMenu.Append(-1, 'Report a problem...')
150 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
151 i = helpMenu.Append(-1, 'Check for update...')
152 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
153 i = helpMenu.Append(-1, 'About Cura...')
154 self.Bind(wx.EVT_MENU, self.OnAbout, i)
155 self.menubar.Append(helpMenu, 'Help')
156 self.SetMenuBar(self.menubar)
158 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
159 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
160 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
161 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
164 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
165 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
167 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
168 self.leftSizer.Add(self.simpleSettingsPanel)
169 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
170 self.leftPane.SetSizer(self.leftSizer)
173 self.scene = sceneView.SceneView(self.rightPane)
175 #Main sizer, to position the preview window, buttons and tab control
176 sizer = wx.BoxSizer()
177 self.rightPane.SetSizer(sizer)
178 sizer.Add(self.scene, 1, flag=wx.EXPAND)
181 sizer = wx.BoxSizer(wx.VERTICAL)
183 sizer.Add(self.splitter, 1, wx.EXPAND)
187 self.updateProfileToControls()
189 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
191 self.simpleSettingsPanel.Show(False)
192 self.normalSettingsPanel.Show(False)
194 # Set default window size & position
195 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
198 # Restore the window position, size & state from the preferences file
200 if profile.getPreference('window_maximized') == 'True':
203 posx = int(profile.getPreference('window_pos_x'))
204 posy = int(profile.getPreference('window_pos_y'))
205 width = int(profile.getPreference('window_width'))
206 height = int(profile.getPreference('window_height'))
207 if posx > 0 or posy > 0:
208 self.SetPosition((posx,posy))
209 if width > 0 and height > 0:
210 self.SetSize((width,height))
212 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
214 self.normalSashPos = 0
216 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
217 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
219 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
221 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
223 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
225 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
226 self.SetSize((800,600))
229 self.updateSliceMode()
231 def updateSliceMode(self):
232 isSimple = profile.getPreference('startMode') == 'Simple'
234 self.normalSettingsPanel.Show(not isSimple)
235 self.simpleSettingsPanel.Show(isSimple)
236 self.leftPane.Layout()
238 for i in self.normalModeOnlyItems:
239 i.Enable(not isSimple)
240 self.switchToQuickprintMenuItem.Enable(not isSimple)
241 self.switchToNormalMenuItem.Enable(isSimple)
243 # Set splitter sash position & size
245 # Save normal mode sash
246 self.normalSashPos = self.splitter.GetSashPosition()
248 # Change location of sash to width of quick mode pane
249 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
250 self.splitter.SetSashPosition(width, True)
253 self.splitter.SetSashSize(0)
255 self.splitter.SetSashPosition(self.normalSashPos, True)
257 self.splitter.SetSashSize(4)
258 self.scene.updateProfileToControls()
260 def OnPreferences(self, e):
261 prefDialog = preferencesDialog.preferencesDialog(self)
265 def OnDropFiles(self, files):
267 profile.setPluginConfig([])
268 self.updateProfileToControls()
269 self.scene.loadScene(files)
271 def OnModelMRU(self, e):
272 fileNum = e.GetId() - self.ID_MRU_MODEL1
273 path = self.modelFileHistory.GetHistoryFile(fileNum)
275 self.modelFileHistory.AddFileToHistory(path) # move up the list
276 self.config.SetPath("/ModelMRU")
277 self.modelFileHistory.Save(self.config)
281 self.scene.loadScene(filelist)
283 def addToModelMRU(self, file):
284 self.modelFileHistory.AddFileToHistory(file)
285 self.config.SetPath("/ModelMRU")
286 self.modelFileHistory.Save(self.config)
289 def OnProfileMRU(self, e):
290 fileNum = e.GetId() - self.ID_MRU_PROFILE1
291 path = self.profileFileHistory.GetHistoryFile(fileNum)
293 self.profileFileHistory.AddFileToHistory(path) # move up the list
294 self.config.SetPath("/ProfileMRU")
295 self.profileFileHistory.Save(self.config)
298 profile.loadProfile(path)
299 self.updateProfileToControls()
301 def addToProfileMRU(self, file):
302 self.profileFileHistory.AddFileToHistory(file)
303 self.config.SetPath("/ProfileMRU")
304 self.profileFileHistory.Save(self.config)
307 def updateProfileToControls(self):
308 self.scene.updateProfileToControls()
309 self.normalSettingsPanel.updateProfileToControls()
310 self.simpleSettingsPanel.updateProfileToControls()
312 def OnLoadProfile(self, e):
313 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)
314 dlg.SetWildcard("ini files (*.ini)|*.ini")
315 if dlg.ShowModal() == wx.ID_OK:
316 profileFile = dlg.GetPath()
317 profile.loadProfile(profileFile)
318 self.updateProfileToControls()
320 # Update the Profile MRU
321 self.addToProfileMRU(profileFile)
324 def OnLoadProfileFromGcode(self, e):
325 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)
326 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
327 if dlg.ShowModal() == wx.ID_OK:
328 gcodeFile = dlg.GetPath()
329 f = open(gcodeFile, 'r')
332 if line.startswith(';CURA_PROFILE_STRING:'):
333 profile.loadProfileFromString(line[line.find(':')+1:].strip())
336 self.updateProfileToControls()
338 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)
341 def OnSaveProfile(self, e):
342 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
343 dlg.SetWildcard("ini files (*.ini)|*.ini")
344 if dlg.ShowModal() == wx.ID_OK:
345 profileFile = dlg.GetPath()
346 profile.saveProfile(profileFile)
349 def OnResetProfile(self, e):
350 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)
351 result = dlg.ShowModal() == wx.ID_YES
354 profile.resetProfile()
355 self.updateProfileToControls()
357 def OnBatchRun(self, e):
358 br = batchRun.batchRunWindow(self)
362 def OnSimpleSwitch(self, e):
363 profile.putPreference('startMode', 'Simple')
364 self.updateSliceMode()
366 def OnNormalSwitch(self, e):
367 profile.putPreference('startMode', 'Normal')
368 self.updateSliceMode()
370 def OnDefaultMarlinFirmware(self, e):
371 firmwareInstall.InstallFirmware()
373 def OnCustomFirmware(self, e):
374 if profile.getPreference('machine_type') == 'ultimaker':
375 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)
376 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
377 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
378 if dlg.ShowModal() == wx.ID_OK:
379 filename = dlg.GetPath()
380 if not(os.path.exists(filename)):
382 #For some reason my Ubuntu 10.10 crashes here.
383 firmwareInstall.InstallFirmware(filename)
385 def OnFirstRunWizard(self, e):
386 configWizard.configWizard()
387 self.updateProfileToControls()
389 def OnBedLevelWizard(self, e):
390 configWizard.bedLevelWizard()
392 def OnHeadOffsetWizard(self, e):
393 configWizard.headOffsetWizard()
395 def OnExpertOpen(self, e):
396 ecw = expertConfig.expertConfigWindow(lambda : self.scene.sceneUpdated())
400 def OnMinecraftImport(self, e):
401 mi = minecraftImport.minecraftImportWindow(self)
405 def OnSuperformula(self, e):
406 sf = superformula.superformulaWindow(self)
407 #sf = superformula.superformulaEvolver(self)
411 def OnCheckForUpdate(self, e):
412 newVersion = version.checkForNewerVersion()
413 if newVersion is not None:
414 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:
415 webbrowser.open(newVersion)
417 wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
419 def OnAbout(self, e):
420 info = wx.AboutDialogInfo()
422 info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.')
423 info.SetWebSite('http://software.ultimaker.com/')
424 info.SetCopyright('Copyright (C) David Braam')
426 This program is free software: you can redistribute it and/or modify
427 it under the terms of the GNU Affero General Public License as published by
428 the Free Software Foundation, either version 3 of the License, or
429 (at your option) any later version.
431 This program is distributed in the hope that it will be useful,
432 but WITHOUT ANY WARRANTY; without even the implied warranty of
433 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
434 GNU Affero General Public License for more details.
436 You should have received a copy of the GNU Affero General Public License
437 along with this program. If not, see <http://www.gnu.org/licenses/>.
441 def OnClose(self, e):
442 profile.saveProfile(profile.getDefaultProfilePath())
444 # Save the window position, size & state from the preferences file
445 profile.putPreference('window_maximized', self.IsMaximized())
446 if not self.IsMaximized() and not self.IsIconized():
447 (posx, posy) = self.GetPosition()
448 profile.putPreference('window_pos_x', posx)
449 profile.putPreference('window_pos_y', posy)
450 (width, height) = self.GetSize()
451 profile.putPreference('window_width', width)
452 profile.putPreference('window_height', height)
454 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
455 isSimple = profile.getPreference('startMode') == 'Simple'
457 self.normalSashPos = self.splitter.GetSashPosition()
458 profile.putPreference('window_normal_sash', self.normalSashPos)
460 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
462 self.scene.OnPaint = lambda e : e
463 self.scene._slicer.cleanup()
469 class normalSettingsPanel(configBase.configPanelBase):
470 "Main user interface window"
471 def __init__(self, parent, callback = None):
472 super(normalSettingsPanel, self).__init__(parent, callback)
475 self.nb = wx.Notebook(self)
476 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
477 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
479 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
480 self._addSettingsToPanels('basic', left, right)
481 self.SizeLabelWidths(left, right)
483 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
484 self._addSettingsToPanels('advanced', left, right)
485 self.SizeLabelWidths(left, right)
488 self.pluginPanel = pluginPanel.pluginPanel(self.nb, callback)
489 if len(self.pluginPanel.pluginList) > 0:
490 self.nb.AddPage(self.pluginPanel, "Plugins")
492 self.pluginPanel.Show(False)
495 self.alterationPanel = alterationPanel.alterationPanel(self.nb, callback)
496 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
498 self.Bind(wx.EVT_SIZE, self.OnSize)
500 self.nb.SetSize(self.GetSize())
501 self.UpdateSize(self.printPanel)
502 self.UpdateSize(self.advancedPanel)
504 def _addSettingsToPanels(self, category, left, right):
505 count = len(profile.getSubCategoriesFor(category)) + len(profile.getSettingsForCategory(category))
509 for title in profile.getSubCategoriesFor(category):
510 n += 1 + len(profile.getSettingsForCategory(category, title))
513 configBase.TitleRow(p, title)
514 for s in profile.getSettingsForCategory(category, title):
515 if s.checkConditions():
516 configBase.SettingRow(p, s.getName())
518 def SizeLabelWidths(self, left, right):
519 leftWidth = self.getLabelColumnWidth(left)
520 rightWidth = self.getLabelColumnWidth(right)
521 maxWidth = max(leftWidth, rightWidth)
522 self.setLabelColumnWidth(left, maxWidth)
523 self.setLabelColumnWidth(right, maxWidth)
526 # Make the size of the Notebook control the same size as this control
527 self.nb.SetSize(self.GetSize())
529 # Propegate the OnSize() event (just in case)
532 # Perform out resize magic
533 self.UpdateSize(self.printPanel)
534 self.UpdateSize(self.advancedPanel)
536 def UpdateSize(self, configPanel):
537 sizer = configPanel.GetSizer()
541 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
544 # if width(col1) > (best_width(col1) + best_width(col1)):
545 # switch to horizontal
548 col1 = configPanel.leftPanel
549 colSize1 = col1.GetSize()
550 colBestSize1 = col1.GetBestSize()
551 col2 = configPanel.rightPanel
552 colSize2 = col2.GetSize()
553 colBestSize2 = col2.GetBestSize()
555 orientation = sizer.GetOrientation()
557 if orientation == wx.HORIZONTAL:
558 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
560 sizer = wx.BoxSizer(wx.VERTICAL)
561 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
562 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
563 configPanel.SetSizer(sizer)
569 if max(colSize1[0], colSize2[0]) > (colBestSize1[0] + colBestSize2[0]):
571 sizer = wx.BoxSizer(wx.HORIZONTAL)
572 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
573 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
574 configPanel.SetSizer(sizer)
580 def updateProfileToControls(self):
581 super(normalSettingsPanel, self).updateProfileToControls()
582 self.alterationPanel.updateProfileToControls()
583 self.pluginPanel.updateProfileToControls()