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.util import dropTarget
18 #from Cura.gui.tools import batchRun
19 from Cura.gui.tools import pidDebugger
20 from Cura.gui.tools import minecraftImport
21 from Cura.util import profile
22 from Cura.util import version
23 from Cura.util import meshLoader
24 from Cura.util import resources
26 class mainWindow(wx.Frame):
28 super(mainWindow, self).__init__(None, title='Cura - ' + version.getVersion())
30 self.extruderCount = int(profile.getPreference('extruder_amount'))
32 wx.EVT_CLOSE(self, self.OnClose)
34 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions()))
36 self.normalModeOnlyItems = []
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)
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)
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)
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, 'Save model...\tCTRL+S')
58 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveModel(), i)
59 i = self.fileMenu.Append(-1, 'Clear platform')
60 self.Bind(wx.EVT_MENU, lambda e: self.scene.OnDeleteAll(e), i)
62 self.fileMenu.AppendSeparator()
63 i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
64 self.Bind(wx.EVT_MENU, lambda e: self.scene.showPrintWindow(), i)
65 i = self.fileMenu.Append(-1, 'Save GCode...')
66 self.Bind(wx.EVT_MENU, lambda e: self.scene.showSaveGCode(), i)
67 i = self.fileMenu.Append(-1, 'Show slice engine log...')
68 self.Bind(wx.EVT_MENU, lambda e: self.scene._showSliceLog(), i)
70 self.fileMenu.AppendSeparator()
71 i = self.fileMenu.Append(-1, 'Open Profile...')
72 self.normalModeOnlyItems.append(i)
73 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
74 i = self.fileMenu.Append(-1, 'Save Profile...')
75 self.normalModeOnlyItems.append(i)
76 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
77 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
78 self.normalModeOnlyItems.append(i)
79 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
80 self.fileMenu.AppendSeparator()
81 i = self.fileMenu.Append(-1, 'Reset Profile to default')
82 self.normalModeOnlyItems.append(i)
83 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
85 self.fileMenu.AppendSeparator()
86 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
87 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
88 self.fileMenu.AppendSeparator()
91 modelHistoryMenu = wx.Menu()
92 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
93 self.modelFileHistory.UseMenu(modelHistoryMenu)
94 self.modelFileHistory.AddFilesToMenu()
95 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
98 profileHistoryMenu = wx.Menu()
99 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
100 self.profileFileHistory.UseMenu(profileHistoryMenu)
101 self.profileFileHistory.AddFilesToMenu()
102 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
104 self.fileMenu.AppendSeparator()
105 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
106 self.Bind(wx.EVT_MENU, self.OnQuit, i)
107 self.menubar.Append(self.fileMenu, '&File')
109 toolsMenu = wx.Menu()
110 i = toolsMenu.Append(-1, 'Switch to quickprint...')
111 self.switchToQuickprintMenuItem = i
112 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
113 i = toolsMenu.Append(-1, 'Switch to full settings...')
114 self.switchToNormalMenuItem = i
115 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
116 toolsMenu.AppendSeparator()
117 #i = toolsMenu.Append(-1, 'Batch run...')
118 #self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
119 #self.normalModeOnlyItems.append(i)
120 if minecraftImport.hasMinecraft():
121 i = toolsMenu.Append(-1, 'Minecraft import...')
122 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
123 if version.isDevVersion():
124 i = toolsMenu.Append(-1, 'PID Debugger...')
125 self.Bind(wx.EVT_MENU, self.OnPIDDebugger, i)
126 self.menubar.Append(toolsMenu, 'Tools')
128 expertMenu = wx.Menu()
129 i = expertMenu.Append(-1, 'Open expert settings...')
130 self.normalModeOnlyItems.append(i)
131 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
132 expertMenu.AppendSeparator()
133 if firmwareInstall.getDefaultFirmware() is not None:
134 i = expertMenu.Append(-1, 'Install default Marlin firmware')
135 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
136 i = expertMenu.Append(-1, 'Install custom firmware')
137 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
138 expertMenu.AppendSeparator()
139 i = expertMenu.Append(-1, 'Run first run wizard...')
140 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
141 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
142 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
143 if self.extruderCount > 1:
144 i = expertMenu.Append(-1, 'Run head offset wizard...')
145 self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
146 self.menubar.Append(expertMenu, 'Expert')
149 i = helpMenu.Append(-1, 'Online documentation...')
150 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
151 i = helpMenu.Append(-1, 'Report a problem...')
152 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
153 i = helpMenu.Append(-1, 'Check for update...')
154 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
155 i = helpMenu.Append(-1, 'About Cura...')
156 self.Bind(wx.EVT_MENU, self.OnAbout, i)
157 self.menubar.Append(helpMenu, 'Help')
158 self.SetMenuBar(self.menubar)
160 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
161 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
162 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
163 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
166 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane, lambda : self.scene.sceneUpdated())
167 self.normalSettingsPanel = normalSettingsPanel(self.leftPane, lambda : self.scene.sceneUpdated())
169 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
170 self.leftSizer.Add(self.simpleSettingsPanel, 1)
171 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
172 self.leftPane.SetSizer(self.leftSizer)
175 self.scene = sceneView.SceneView(self.rightPane)
177 #Main sizer, to position the preview window, buttons and tab control
178 sizer = wx.BoxSizer()
179 self.rightPane.SetSizer(sizer)
180 sizer.Add(self.scene, 1, flag=wx.EXPAND)
183 sizer = wx.BoxSizer(wx.VERTICAL)
185 sizer.Add(self.splitter, 1, wx.EXPAND)
189 self.updateProfileToControls()
191 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
193 self.simpleSettingsPanel.Show(False)
194 self.normalSettingsPanel.Show(False)
196 # Set default window size & position
197 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
200 # Restore the window position, size & state from the preferences file
202 if profile.getPreference('window_maximized') == 'True':
205 posx = int(profile.getPreference('window_pos_x'))
206 posy = int(profile.getPreference('window_pos_y'))
207 width = int(profile.getPreference('window_width'))
208 height = int(profile.getPreference('window_height'))
209 if posx > 0 or posy > 0:
210 self.SetPosition((posx,posy))
211 if width > 0 and height > 0:
212 self.SetSize((width,height))
214 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
216 self.normalSashPos = 0
218 if self.normalSashPos < self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5:
219 self.normalSashPos = self.normalSettingsPanel.printPanel.GetBestSize()[0] + 5
221 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
223 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
225 if wx.Display.GetFromPoint((self.GetPositionTuple()[0] + self.GetSizeTuple()[1], self.GetPositionTuple()[1] + self.GetSizeTuple()[1])) < 0:
227 if wx.Display.GetFromPoint(self.GetPosition()) < 0:
228 self.SetSize((800,600))
231 self.updateSliceMode()
233 def updateSliceMode(self):
234 isSimple = profile.getPreference('startMode') == 'Simple'
236 self.normalSettingsPanel.Show(not isSimple)
237 self.simpleSettingsPanel.Show(isSimple)
238 self.leftPane.Layout()
240 for i in self.normalModeOnlyItems:
241 i.Enable(not isSimple)
242 self.switchToQuickprintMenuItem.Enable(not isSimple)
243 self.switchToNormalMenuItem.Enable(isSimple)
245 # Set splitter sash position & size
247 # Save normal mode sash
248 self.normalSashPos = self.splitter.GetSashPosition()
250 # Change location of sash to width of quick mode pane
251 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
252 self.splitter.SetSashPosition(width, True)
255 self.splitter.SetSashSize(0)
257 self.splitter.SetSashPosition(self.normalSashPos, True)
259 self.splitter.SetSashSize(4)
260 self.scene.updateProfileToControls()
262 def OnPreferences(self, e):
263 prefDialog = preferencesDialog.preferencesDialog(self)
267 def OnDropFiles(self, files):
269 profile.setPluginConfig([])
270 self.updateProfileToControls()
271 self.scene.loadScene(files)
273 def OnModelMRU(self, e):
274 fileNum = e.GetId() - self.ID_MRU_MODEL1
275 path = self.modelFileHistory.GetHistoryFile(fileNum)
277 self.modelFileHistory.AddFileToHistory(path) # move up the list
278 self.config.SetPath("/ModelMRU")
279 self.modelFileHistory.Save(self.config)
282 profile.putPreference('lastFile', path)
284 self.scene.loadScene(filelist)
286 def addToModelMRU(self, file):
287 self.modelFileHistory.AddFileToHistory(file)
288 self.config.SetPath("/ModelMRU")
289 self.modelFileHistory.Save(self.config)
292 def OnProfileMRU(self, e):
293 fileNum = e.GetId() - self.ID_MRU_PROFILE1
294 path = self.profileFileHistory.GetHistoryFile(fileNum)
296 self.profileFileHistory.AddFileToHistory(path) # move up the list
297 self.config.SetPath("/ProfileMRU")
298 self.profileFileHistory.Save(self.config)
301 profile.loadProfile(path)
302 self.updateProfileToControls()
304 def addToProfileMRU(self, file):
305 self.profileFileHistory.AddFileToHistory(file)
306 self.config.SetPath("/ProfileMRU")
307 self.profileFileHistory.Save(self.config)
310 def updateProfileToControls(self):
311 self.scene.updateProfileToControls()
312 self.normalSettingsPanel.updateProfileToControls()
313 self.simpleSettingsPanel.updateProfileToControls()
315 def OnLoadProfile(self, e):
316 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)
317 dlg.SetWildcard("ini files (*.ini)|*.ini")
318 if dlg.ShowModal() == wx.ID_OK:
319 profileFile = dlg.GetPath()
320 profile.loadProfile(profileFile)
321 self.updateProfileToControls()
323 # Update the Profile MRU
324 self.addToProfileMRU(profileFile)
327 def OnLoadProfileFromGcode(self, e):
328 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)
329 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
330 if dlg.ShowModal() == wx.ID_OK:
331 gcodeFile = dlg.GetPath()
332 f = open(gcodeFile, 'r')
335 if line.startswith(';CURA_PROFILE_STRING:'):
336 profile.loadProfileFromString(line[line.find(':')+1:].strip())
339 self.updateProfileToControls()
341 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)
344 def OnSaveProfile(self, e):
345 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
346 dlg.SetWildcard("ini files (*.ini)|*.ini")
347 if dlg.ShowModal() == wx.ID_OK:
348 profileFile = dlg.GetPath()
349 profile.saveProfile(profileFile)
352 def OnResetProfile(self, e):
353 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)
354 result = dlg.ShowModal() == wx.ID_YES
357 profile.resetProfile()
358 self.updateProfileToControls()
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').startswith('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 OnPIDDebugger(self, e):
404 debugger = pidDebugger.debuggerWindow(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 if profile.getPreference('gcode_flavor') == 'UltiGCode':
493 self.alterationPanel = None
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 if self.alterationPanel is not None:
583 self.alterationPanel.updateProfileToControls()
584 self.pluginPanel.updateProfileToControls()