1 from __future__ import absolute_import
7 from Cura.gui import configBase
8 from Cura.gui import expertConfig
9 from Cura.gui import preview3d
10 from Cura.gui import sliceProgressPanel
11 from Cura.gui import alterationPanel
12 from Cura.gui import pluginPanel
13 from Cura.gui import preferencesDialog
14 from Cura.gui import configWizard
15 from Cura.gui import firmwareInstall
16 from Cura.gui import printWindow
17 from Cura.gui import simpleMode
18 from Cura.gui import projectPlanner
19 from Cura.gui.tools import batchRun
20 from Cura.gui import flatSlicerWindow
21 from Cura.gui.util import dropTarget
22 from Cura.gui.tools import minecraftImport
23 from Cura.util import validators
24 from Cura.util import profile
25 from Cura.util import version
26 from Cura.util import sliceRun
27 from Cura.util import meshLoader
29 class mainWindow(wx.Frame):
31 super(mainWindow, self).__init__(None, title='Cura Steam Engine BETA - ' + version.getVersion())
33 self.extruderCount = int(profile.getPreference('extruder_amount'))
35 wx.EVT_CLOSE(self, self.OnClose)
37 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.supportedExtensions()))
39 self.normalModeOnlyItems = []
41 mruFile = os.path.join(profile.getBasePath(), 'mru_filelist.ini')
42 self.config = wx.FileConfig(appName="Cura",
43 localFilename=mruFile,
44 style=wx.CONFIG_USE_LOCAL_FILE)
46 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)]
47 self.modelFileHistory = wx.FileHistory(10, self.ID_MRU_MODEL1)
48 self.config.SetPath("/ModelMRU")
49 self.modelFileHistory.Load(self.config)
51 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)]
52 self.profileFileHistory = wx.FileHistory(10, self.ID_MRU_PROFILE1)
53 self.config.SetPath("/ProfileMRU")
54 self.profileFileHistory.Load(self.config)
56 self.menubar = wx.MenuBar()
57 self.fileMenu = wx.Menu()
58 i = self.fileMenu.Append(-1, 'Load model file...\tCTRL+L')
59 self.Bind(wx.EVT_MENU, lambda e: self._showModelLoadDialog(1), i)
60 i = self.fileMenu.Append(-1, 'Prepare print...\tCTRL+R')
61 self.Bind(wx.EVT_MENU, self.OnSlice, i)
62 i = self.fileMenu.Append(-1, 'Print...\tCTRL+P')
63 self.Bind(wx.EVT_MENU, self.OnPrint, i)
65 self.fileMenu.AppendSeparator()
66 i = self.fileMenu.Append(-1, 'Open Profile...')
67 self.normalModeOnlyItems.append(i)
68 self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
69 i = self.fileMenu.Append(-1, 'Save Profile...')
70 self.normalModeOnlyItems.append(i)
71 self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
72 i = self.fileMenu.Append(-1, 'Load Profile from GCode...')
73 self.normalModeOnlyItems.append(i)
74 self.Bind(wx.EVT_MENU, self.OnLoadProfileFromGcode, i)
75 self.fileMenu.AppendSeparator()
76 i = self.fileMenu.Append(-1, 'Reset Profile to default')
77 self.normalModeOnlyItems.append(i)
78 self.Bind(wx.EVT_MENU, self.OnResetProfile, i)
80 self.fileMenu.AppendSeparator()
81 i = self.fileMenu.Append(-1, 'Preferences...\tCTRL+,')
82 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
83 self.fileMenu.AppendSeparator()
86 modelHistoryMenu = wx.Menu()
87 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Model Files", modelHistoryMenu)
88 self.modelFileHistory.UseMenu(modelHistoryMenu)
89 self.modelFileHistory.AddFilesToMenu()
90 self.Bind(wx.EVT_MENU_RANGE, self.OnModelMRU, id=self.ID_MRU_MODEL1, id2=self.ID_MRU_MODEL10)
93 profileHistoryMenu = wx.Menu()
94 self.fileMenu.AppendMenu(wx.NewId(), "&Recent Profile Files", profileHistoryMenu)
95 self.profileFileHistory.UseMenu(profileHistoryMenu)
96 self.profileFileHistory.AddFilesToMenu()
97 self.Bind(wx.EVT_MENU_RANGE, self.OnProfileMRU, id=self.ID_MRU_PROFILE1, id2=self.ID_MRU_PROFILE10)
99 self.fileMenu.AppendSeparator()
100 i = self.fileMenu.Append(wx.ID_EXIT, 'Quit')
101 self.Bind(wx.EVT_MENU, self.OnQuit, i)
102 self.menubar.Append(self.fileMenu, '&File')
104 toolsMenu = wx.Menu()
105 i = toolsMenu.Append(-1, 'Switch to quickprint...')
106 self.switchToQuickprintMenuItem = i
107 self.Bind(wx.EVT_MENU, self.OnSimpleSwitch, i)
108 i = toolsMenu.Append(-1, 'Switch to full settings...')
109 self.switchToNormalMenuItem = i
110 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
111 toolsMenu.AppendSeparator()
112 i = toolsMenu.Append(-1, 'Project planner...')
113 self.Bind(wx.EVT_MENU, self.OnProjectPlanner, i)
114 self.normalModeOnlyItems.append(i)
115 i = toolsMenu.Append(-1, 'Batch run...')
116 self.Bind(wx.EVT_MENU, self.OnBatchRun, i)
117 self.normalModeOnlyItems.append(i)
118 # i = toolsMenu.Append(-1, 'Open SVG (2D) slicer...')
119 # self.Bind(wx.EVT_MENU, self.OnSVGSlicerOpen, i)
120 if minecraftImport.hasMinecraft():
121 i = toolsMenu.Append(-1, 'Minecraft import...')
122 self.Bind(wx.EVT_MENU, self.OnMinecraftImport, i)
123 self.menubar.Append(toolsMenu, 'Tools')
125 expertMenu = wx.Menu()
126 i = expertMenu.Append(-1, 'Open expert settings...')
127 self.normalModeOnlyItems.append(i)
128 self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
129 expertMenu.AppendSeparator()
130 if firmwareInstall.getDefaultFirmware() is not None:
131 i = expertMenu.Append(-1, 'Install default Marlin firmware')
132 self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
133 i = expertMenu.Append(-1, 'Install custom firmware')
134 self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
135 expertMenu.AppendSeparator()
136 i = expertMenu.Append(-1, 'Run first run wizard...')
137 self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
138 i = expertMenu.Append(-1, 'Run bed leveling wizard...')
139 self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
140 self.menubar.Append(expertMenu, 'Expert')
143 i = helpMenu.Append(-1, 'Online documentation...')
144 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('http://daid.github.com/Cura'), i)
145 i = helpMenu.Append(-1, 'Report a problem...')
146 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
147 i = helpMenu.Append(-1, 'Check for update...')
148 self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i)
149 self.menubar.Append(helpMenu, 'Help')
150 self.SetMenuBar(self.menubar)
152 if profile.getPreference('lastFile') != '':
153 self.filelist = profile.getPreference('lastFile').split(';')
154 self.SetTitle('Cura - %s - %s' % (version.getVersion(), self.filelist[-1]))
157 self.progressPanelList = []
159 self.splitter = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_LIVE_UPDATE)
160 self.leftPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
161 self.rightPane = wx.Panel(self.splitter, style=wx.BORDER_NONE)
162 self.splitter.Bind(wx.EVT_SPLITTER_DCLICK, lambda evt: evt.Veto())
165 self.simpleSettingsPanel = simpleMode.simpleModePanel(self.leftPane)
166 self.normalSettingsPanel = normalSettingsPanel(self.leftPane)
168 self.leftSizer = wx.BoxSizer(wx.VERTICAL)
169 self.leftSizer.Add(self.simpleSettingsPanel)
170 self.leftSizer.Add(self.normalSettingsPanel, 1, wx.EXPAND)
171 self.leftPane.SetSizer(self.leftSizer)
174 self.preview3d = preview3d.previewPanel(self.rightPane)
176 #Also bind double clicking the 3D preview to load an STL file.
177 #self.preview3d.glCanvas.Bind(wx.EVT_LEFT_DCLICK, lambda e: self._showModelLoadDialog(1), self.preview3d.glCanvas)
179 #Main sizer, to position the preview window, buttons and tab control
180 sizer = wx.BoxSizer()
181 self.rightPane.SetSizer(sizer)
182 sizer.Add(self.preview3d, 1, flag=wx.EXPAND)
185 sizer = wx.BoxSizer(wx.VERTICAL)
187 sizer.Add(self.splitter, 1, wx.EXPAND)
191 if len(self.filelist) > 0:
192 self.preview3d.loadModelFiles(self.filelist)
194 # Update the Model MRU
195 for idx in xrange(0, len(self.filelist)):
196 self.addToModelMRU(self.filelist[idx])
198 self.updateProfileToControls()
200 self.SetBackgroundColour(self.normalSettingsPanel.GetBackgroundColour())
202 self.simpleSettingsPanel.Show(False)
203 self.normalSettingsPanel.Show(False)
205 # Set default window size & position
206 self.SetSize((wx.Display().GetClientArea().GetWidth()/2,wx.Display().GetClientArea().GetHeight()/2))
209 # Restore the window position, size & state from the preferences file
210 self.normalSashPos = 320
212 if profile.getPreference('window_maximized') == 'True':
215 posx = int(profile.getPreference('window_pos_x'))
216 posy = int(profile.getPreference('window_pos_y'))
217 width = int(profile.getPreference('window_width'))
218 height = int(profile.getPreference('window_height'))
219 if posx > 0 or posy > 0:
220 self.SetPosition((posx,posy))
221 if width > 0 and height > 0:
222 self.SetSize((width,height))
224 self.normalSashPos = int(profile.getPreference('window_normal_sash'))
228 self.splitter.SplitVertically(self.leftPane, self.rightPane, self.normalSashPos)
230 self.updateSliceMode()
234 def updateSliceMode(self):
235 isSimple = profile.getPreference('startMode') == 'Simple'
237 self.normalSettingsPanel.Show(not isSimple)
238 self.simpleSettingsPanel.Show(isSimple)
239 self.leftPane.Layout()
241 for i in self.normalModeOnlyItems:
242 i.Enable(not isSimple)
243 self.switchToQuickprintMenuItem.Enable(not isSimple)
244 self.switchToNormalMenuItem.Enable(isSimple)
246 # Set splitter sash position & size
248 # Save normal mode sash
249 self.normalSashPos = self.splitter.GetSashPosition()
251 # Change location of sash to width of quick mode pane
252 (width, height) = self.simpleSettingsPanel.GetSizer().GetSize()
253 self.splitter.SetSashPosition(width, True)
256 self.splitter.SetSashSize(0)
258 self.splitter.SetSashPosition(self.normalSashPos, True)
261 self.splitter.SetSashSize(4)
263 def OnPreferences(self, e):
264 prefDialog = preferencesDialog.preferencesDialog(self)
266 prefDialog.Show(True)
268 def _showOpenDialog(self, title, wildcard = meshLoader.wildcardFilter()):
269 dlg=wx.FileDialog(self, title, os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
270 dlg.SetWildcard(wildcard)
271 if dlg.ShowModal() == wx.ID_OK:
272 filename = dlg.GetPath()
274 if not(os.path.exists(filename)):
276 profile.putPreference('lastFile', filename)
281 def _showModelLoadDialog(self, amount):
283 for i in xrange(0, amount):
284 filelist.append(self._showOpenDialog("Open file to print"))
285 if filelist[-1] == False:
287 self._loadModels(filelist)
289 def _loadModels(self, filelist):
290 self.filelist = filelist
291 self.SetTitle('Cura - %s - %s' % (version.getVersion(), filelist[-1]))
292 profile.putPreference('lastFile', ';'.join(self.filelist))
293 self.preview3d.loadModelFiles(self.filelist, True)
294 self.preview3d.setViewMode("Normal")
296 # Update the Model MRU
297 for idx in xrange(0, len(self.filelist)):
298 self.addToModelMRU(self.filelist[idx])
300 def OnDropFiles(self, files):
301 profile.putProfileSetting('model_matrix', '1,0,0,0,1,0,0,0,1')
302 profile.setPluginConfig([])
303 self.updateProfileToControls()
304 self._loadModels(files)
306 def OnLoadModel(self, e):
307 self._showModelLoadDialog(1)
309 def OnLoadModel2(self, e):
310 self._showModelLoadDialog(2)
312 def OnLoadModel3(self, e):
313 self._showModelLoadDialog(3)
315 def OnLoadModel4(self, e):
316 self._showModelLoadDialog(4)
318 def OnSlice(self, e):
319 if len(self.filelist) < 1:
320 wx.MessageBox('You need to load a file before you can prepare it.', 'Print error', wx.OK | wx.ICON_INFORMATION)
322 isSimple = profile.getPreference('startMode') == 'Simple'
324 #save the current profile so we can put it back latter
325 oldProfile = profile.getProfileString()
326 self.simpleSettingsPanel.setupSlice()
327 #Create a progress panel and add it to the window. The progress panel will start the Skein operation.
328 spp = sliceProgressPanel.sliceProgressPanel(self, self, self.filelist)
329 self.sizer.Add(spp, 0, flag=wx.EXPAND)
331 newSize = self.GetSize()
332 newSize.IncBy(0, spp.GetSize().GetHeight())
333 if newSize.GetWidth() < wx.GetDisplaySize()[0]:
334 self.SetSize(newSize)
335 self.progressPanelList.append(spp)
337 profile.loadProfileFromString(oldProfile)
339 def OnPrint(self, e):
340 if len(self.filelist) < 1:
341 wx.MessageBox('You need to load a file and prepare it before you can print.', 'Print error', wx.OK | wx.ICON_INFORMATION)
343 if not os.path.exists(sliceRun.getExportFilename(self.filelist[0])):
344 wx.MessageBox('You need to prepare a print before you can run the actual print.', 'Print error', wx.OK | wx.ICON_INFORMATION)
346 printWindow.printFile(sliceRun.getExportFilename(self.filelist[0]))
348 def OnModelMRU(self, e):
349 fileNum = e.GetId() - self.ID_MRU_MODEL1
350 path = self.modelFileHistory.GetHistoryFile(fileNum)
352 self.modelFileHistory.AddFileToHistory(path) # move up the list
353 self.config.SetPath("/ModelMRU")
354 self.modelFileHistory.Save(self.config)
358 self._loadModels(filelist)
360 def addToModelMRU(self, file):
361 self.modelFileHistory.AddFileToHistory(file)
362 self.config.SetPath("/ModelMRU")
363 self.modelFileHistory.Save(self.config)
366 def OnProfileMRU(self, e):
367 fileNum = e.GetId() - self.ID_MRU_PROFILE1
368 path = self.profileFileHistory.GetHistoryFile(fileNum)
370 self.profileFileHistory.AddFileToHistory(path) # move up the list
371 self.config.SetPath("/ProfileMRU")
372 self.profileFileHistory.Save(self.config)
375 profile.loadProfile(path)
376 self.updateProfileToControls()
378 def addToProfileMRU(self, file):
379 self.profileFileHistory.AddFileToHistory(file)
380 self.config.SetPath("/ProfileMRU")
381 self.profileFileHistory.Save(self.config)
384 def removeSliceProgress(self, spp):
385 self.progressPanelList.remove(spp)
386 newSize = self.GetSize()
387 newSize.IncBy(0, -spp.GetSize().GetHeight())
388 if newSize.GetWidth() < wx.GetDisplaySize()[0]:
389 self.SetSize(newSize)
391 self.sizer.Detach(spp)
394 def updateProfileToControls(self):
395 self.preview3d.updateProfileToControls()
396 self.normalSettingsPanel.updateProfileToControls()
397 self.simpleSettingsPanel.updateProfileToControls()
399 def OnLoadProfile(self, e):
400 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)
401 dlg.SetWildcard("ini files (*.ini)|*.ini")
402 if dlg.ShowModal() == wx.ID_OK:
403 profileFile = dlg.GetPath()
404 profile.loadProfile(profileFile)
405 self.updateProfileToControls()
407 # Update the Profile MRU
408 self.addToProfileMRU(profileFile)
411 def OnLoadProfileFromGcode(self, e):
412 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)
413 dlg.SetWildcard("gcode files (*.gcode)|*.gcode;*.g")
414 if dlg.ShowModal() == wx.ID_OK:
415 gcodeFile = dlg.GetPath()
416 f = open(gcodeFile, 'r')
419 if line.startswith(';CURA_PROFILE_STRING:'):
420 profile.loadProfileFromString(line[line.find(':')+1:].strip())
423 self.updateProfileToControls()
425 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)
428 def OnSaveProfile(self, e):
429 dlg=wx.FileDialog(self, "Select profile file to save", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
430 dlg.SetWildcard("ini files (*.ini)|*.ini")
431 if dlg.ShowModal() == wx.ID_OK:
432 profileFile = dlg.GetPath()
433 profile.saveProfile(profileFile)
436 def OnResetProfile(self, e):
437 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)
438 result = dlg.ShowModal() == wx.ID_YES
441 profile.resetProfile()
442 self.updateProfileToControls()
444 def OnBatchRun(self, e):
445 br = batchRun.batchRunWindow(self)
449 def OnSimpleSwitch(self, e):
450 profile.putPreference('startMode', 'Simple')
451 self.updateSliceMode()
453 def OnNormalSwitch(self, e):
454 profile.putPreference('startMode', 'Normal')
455 self.updateSliceMode()
457 def OnDefaultMarlinFirmware(self, e):
458 firmwareInstall.InstallFirmware()
460 def OnCustomFirmware(self, e):
461 if profile.getPreference('machine_type') == 'ultimaker':
462 wx.MessageBox('Warning: Installing a custom firmware does not garantee that you machine will function correctly, and could damage your machine.', 'Firmware update', wx.OK | wx.ICON_EXCLAMATION)
463 dlg=wx.FileDialog(self, "Open firmware to upload", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
464 dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
465 if dlg.ShowModal() == wx.ID_OK:
466 filename = dlg.GetPath()
467 if not(os.path.exists(filename)):
469 #For some reason my Ubuntu 10.10 crashes here.
470 firmwareInstall.InstallFirmware(filename)
472 def OnFirstRunWizard(self, e):
473 configWizard.configWizard()
474 self.updateProfileToControls()
476 def OnBedLevelWizard(self, e):
477 configWizard.bedLevelWizard()
479 def OnExpertOpen(self, e):
480 ecw = expertConfig.expertConfigWindow()
484 def OnProjectPlanner(self, e):
485 pp = projectPlanner.projectPlanner()
489 def OnMinecraftImport(self, e):
490 mi = minecraftImport.minecraftImportWindow(self)
494 def OnSVGSlicerOpen(self, e):
495 svgSlicer = flatSlicerWindow.flatSlicerWindow()
499 def OnCheckForUpdate(self, e):
500 newVersion = version.checkForNewerVersion()
501 if newVersion is not None:
502 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:
503 webbrowser.open(newVersion)
505 wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION)
507 def OnClose(self, e):
508 profile.saveProfile(profile.getDefaultProfilePath())
510 # Save the window position, size & state from the preferences file
511 profile.putPreference('window_maximized', self.IsMaximized())
512 if not self.IsMaximized() and not self.IsIconized():
513 (posx, posy) = self.GetPosition()
514 profile.putPreference('window_pos_x', posx)
515 profile.putPreference('window_pos_y', posy)
516 (width, height) = self.GetSize()
517 profile.putPreference('window_width', width)
518 profile.putPreference('window_height', height)
520 # Save normal sash position. If in normal mode (!simple mode), get last position of sash before saving it...
521 isSimple = profile.getPreference('startMode') == 'Simple'
523 self.normalSashPos = self.splitter.GetSashPosition()
524 profile.putPreference('window_normal_sash', self.normalSashPos)
526 #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which keeps wxWidgets from quiting.
527 self.preview3d.glCanvas.OnPaint = lambda e : e
533 class normalSettingsPanel(configBase.configPanelBase):
534 "Main user interface window"
535 def __init__(self, parent):
536 super(normalSettingsPanel, self).__init__(parent)
539 self.nb = wx.Notebook(self)
540 self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
541 self.GetSizer().Add(self.nb, 1, wx.EXPAND)
543 (left, right, self.printPanel) = self.CreateDynamicConfigTab(self.nb, 'Basic')
545 configBase.TitleRow(left, "Quality")
546 c = configBase.SettingRow(left, 'layer_height')
547 #validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 80.0 / 100.0), "Thicker layers then %.2fmm (80%% nozzle size) usually give bad results and are not recommended.")
548 c = configBase.SettingRow(left, 'wall_thickness')
549 #validators.wallThicknessValidator(c)
550 c = configBase.SettingRow(left, 'retraction_enable')
552 configBase.TitleRow(left, "Fill")
553 c = configBase.SettingRow(left, 'solid_layer_thickness')
554 c = configBase.SettingRow(left, 'fill_density')
556 configBase.TitleRow(right, "Speed && Temperature")
557 c = configBase.SettingRow(right, 'print_speed')
558 #validators.warningAbove(c, 150.0, "It is highly unlikely that your machine can achieve a printing speed above 150mm/s")
559 #validators.printSpeedValidator(c)
561 configBase.TitleRow(right, "Temperature")
562 c = configBase.SettingRow(right, 'print_temperature')
563 #validators.warningAbove(c, 260.0, "Temperatures above 260C could damage your machine, be careful!")
564 if int(profile.getPreference('extruder_amount')) > 1:
565 c = configBase.SettingRow(right, 'print_temperature2')
566 #validators.warningAbove(c, 260.0, "Temperatures above 260C could damage your machine, be careful!")
567 if int(profile.getPreference('extruder_amount')) > 2:
568 c = configBase.SettingRow(right, "3th nozzle temperature", 'print_temperature3', '0', 'Temperature used for printing with the 3th nozzle. Set at 0 to use the same temperature as for nozzle 1')
569 validators.warningAbove(c, 260.0, "Temperatures above 260C could damage your machine, be careful!")
570 if int(profile.getPreference('extruder_amount')) > 3:
571 c = configBase.SettingRow(right, "4th nozzle temperature", 'print_temperature4', '0', 'Temperature used for printing with the 4th nozzle. Set at 0 to use the same temperature as for nozzle 1')
572 validators.warningAbove(c, 260.0, "Temperatures above 260C could damage your machine, be careful!")
573 if profile.getPreference('has_heated_bed') == 'True':
574 c = configBase.SettingRow(right, "Bed temperature", 'print_bed_temperature', '0', 'Temperature used for the heated printer bed. Set at 0 to pre-heat yourself')
576 configBase.TitleRow(right, "Support structure")
577 c = configBase.SettingRow(right, 'support')
578 # c = configBase.SettingRow(right, "Add raft", 'enable_raft', False, 'A raft is a few layers of lines below the bottom of the object. It prevents warping. Full raft settings can be found in the expert settings.\nFor PLA this is usually not required. But if you print with ABS it is almost required.')
579 # if int(profile.getPreference('extruder_amount')) > 1:
580 # c = configBase.SettingRow(right, "Support dual extrusion", 'support_dual_extrusion', False, 'Print the support material with the 2nd extruder in a dual extrusion setup. The primary extruder will be used for normal material, while the second extruder is used to print support material.')
582 configBase.TitleRow(right, "Filament")
583 c = configBase.SettingRow(right, 'filament_diameter')
584 #validators.warningAbove(c, 3.5, "Are you sure your filament is that thick? Normal filament is around 3mm or 1.75mm.")
585 # if int(profile.getPreference('extruder_amount')) > 1:
586 # c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter2', '2.89', 'Diameter of your filament for the 2nd nozzle, as accurately as possible.\nIf you cannot measure this value you will have to calibrate it, a higher number means less extrusion, a smaller number generates more extrusion. Use 0 to use the same diameter as for nozzle 1.')
587 # validators.warningAbove(c, 3.5, "Are you sure your filament is that thick? Normal filament is around 3mm or 1.75mm.")
588 # if int(profile.getPreference('extruder_amount')) > 2:
589 # c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter3', '2.89', 'Diameter of your filament for the 3th nozzle, as accurately as possible.\nIf you cannot measure this value you will have to calibrate it, a higher number means less extrusion, a smaller number generates more extrusion. Use 0 to use the same diameter as for nozzle 1.')
590 # validators.warningAbove(c, 3.5, "Are you sure your filament is that thick? Normal filament is around 3mm or 1.75mm.")
591 # if int(profile.getPreference('extruder_amount')) > 3:
592 # c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter4', '2.89', 'Diameter of your filament for the 4th nozzle, as accurately as possible.\nIf you cannot measure this value you will have to calibrate it, a higher number means less extrusion, a smaller number generates more extrusion. Use 0 to use the same diameter as for nozzle 1.')
593 # validators.warningAbove(c, 3.5, "Are you sure your filament is that thick? Normal filament is around 3mm or 1.75mm.")
594 # c = configBase.SettingRow(right, "Packing Density", 'filament_density', '1.00', 'Packing density of your filament. This should be 1.00 for PLA and 0.85 for ABS')
596 self.SizeLabelWidths(left, right)
598 (left, right, self.advancedPanel) = self.CreateDynamicConfigTab(self.nb, 'Advanced')
600 configBase.TitleRow(left, "Machine size")
601 c = configBase.SettingRow(left, 'nozzle_size')
603 configBase.TitleRow(left, "Skirt")
604 c = configBase.SettingRow(left, 'skirt_line_count')
605 c = configBase.SettingRow(left, 'skirt_gap')
607 configBase.TitleRow(left, "Retraction")
608 # c = configBase.SettingRow(left, "Minimum travel (mm)", 'retraction_min_travel', '5.0', 'Minimum amount of travel needed for a retraction to happen at all. To make sure you do not get a lot of retractions in a small area')
609 c = configBase.SettingRow(left, 'retraction_speed')
610 c = configBase.SettingRow(left, 'retraction_amount')
611 # c = configBase.SettingRow(left, "Extra length on start (mm)", 'retraction_extra', '0.0', 'Extra extrusion amount when restarting after a retraction, to better "Prime" your extruder after retraction.')
613 configBase.TitleRow(right, "Speed")
614 c = configBase.SettingRow(right, 'travel_speed')
615 #validators.warningAbove(c, 300.0, "It is highly unlikely that your machine can achieve a travel speed above 300mm/s")
616 # c = configBase.SettingRow(right, "Max Z speed (mm/s)", 'max_z_speed', '1.0', 'Speed at which Z moves are done. When you Z axis is properly lubercated you can increase this for less Z blob.')
617 c = configBase.SettingRow(right, 'bottom_layer_speed')
619 # configBase.TitleRow(right, "Cool")
620 # c = configBase.SettingRow(right, "Minimal layer time (sec)", 'cool_min_layer_time', '10', 'Minimum time spend in a layer, gives the layer time to cool down before the next layer is put on top. If the layer will be placed down too fast the printer will slow down to make sure it has spend atleast this amount of seconds printing this layer.')
621 # c = configBase.SettingRow(right, "Enable cooling fan", 'fan_enabled', True, 'Enable the cooling fan during the print. The extra cooling from the cooling fan is essensial during faster prints.')
623 configBase.TitleRow(right, "Quality")
624 c = configBase.SettingRow(right, 'bottom_thickness')
625 #validators.validFloat(c, 0.0)
626 #validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 3.0 / 4.0), "A bottom layer of more then %.2fmm (3/4 nozzle size) usually give bad results and is not recommended.")
627 c = configBase.SettingRow(right, 'object_sink')
628 #validators.validFloat(c, 0.0)
629 # configBase.settingNotify(c, lambda : self.GetParent().GetParent().GetParent().preview3d.Refresh())
630 # c = configBase.SettingRow(right, "Duplicate outlines", 'enable_skin', False, 'Skin prints the outer lines of the prints twice, each time with half the thickness. This gives the illusion of a higher print quality.')
632 self.SizeLabelWidths(left, right)
635 self.pluginPanel = pluginPanel.pluginPanel(self.nb)
636 if len(self.pluginPanel.pluginList) > 0:
637 self.nb.AddPage(self.pluginPanel, "Plugins")
639 self.pluginPanel.Show(False)
642 self.alterationPanel = alterationPanel.alterationPanel(self.nb)
643 self.nb.AddPage(self.alterationPanel, "Start/End-GCode")
645 self.Bind(wx.EVT_SIZE, self.OnSize)
647 def SizeLabelWidths(self, left, right):
648 leftWidth = self.getLabelColumnWidth(left)
649 rightWidth = self.getLabelColumnWidth(right)
650 maxWidth = max(leftWidth, rightWidth)
651 self.setLabelColumnWidth(left, maxWidth)
652 self.setLabelColumnWidth(right, maxWidth)
655 # Make the size of the Notebook control the same size as this control
656 self.nb.SetSize(self.GetSize())
658 # Propegate the OnSize() event (just in case)
661 # Perform out resize magic
662 self.UpdateSize(self.printPanel)
663 self.UpdateSize(self.advancedPanel)
665 def UpdateSize(self, configPanel):
666 sizer = configPanel.GetSizer()
670 # if width(col1) < best_width(col1) || width(col2) < best_width(col2):
673 # if width(col1) > (best_width(col1) + best_width(col1)):
674 # switch to horizontal
677 col1 = configPanel.leftPanel
678 colSize1 = col1.GetSize()
679 colBestSize1 = col1.GetBestSize()
680 col2 = configPanel.rightPanel
681 colSize2 = col2.GetSize()
682 colBestSize2 = col2.GetBestSize()
684 orientation = sizer.GetOrientation()
686 if orientation == wx.HORIZONTAL:
687 if (colSize1[0] <= colBestSize1[0]) or (colSize2[0] <= colBestSize2[0]):
689 sizer = wx.BoxSizer(wx.VERTICAL)
690 sizer.Add(configPanel.leftPanel, flag=wx.EXPAND)
691 sizer.Add(configPanel.rightPanel, flag=wx.EXPAND)
692 configPanel.SetSizer(sizer)
698 if colSize1[0] > (colBestSize1[0] + colBestSize2[0]):
700 sizer = wx.BoxSizer(wx.HORIZONTAL)
701 sizer.Add(configPanel.leftPanel, proportion=1, border=35, flag=wx.EXPAND)
702 sizer.Add(configPanel.rightPanel, proportion=1, flag=wx.EXPAND)
703 configPanel.SetSizer(sizer)
709 def updateProfileToControls(self):
710 super(normalSettingsPanel, self).updateProfileToControls()
711 self.alterationPanel.updateProfileToControls()
712 self.pluginPanel.updateProfileToControls()