chiark / gitweb /
Add drag&drop support to quickprint.
[cura.git] / Cura / gui / simpleMode.py
1 from __future__ import absolute_import
2 import __init__
3
4 import wx, os, platform, types, webbrowser
5
6 from gui import configBase
7 from gui import preview3d
8 from gui import sliceProgessPanel
9 from gui import preferencesDialog
10 from gui import configWizard
11 from gui import firmwareInstall
12 from gui import dropTarget
13 from gui import printWindow
14 from gui import icon
15 from util import validators
16 from util import profile
17 from util import version
18 from util import sliceRun
19 from util import meshLoader
20
21 class simpleModeWindow(configBase.configWindowBase):
22         "Main user interface window for Quickprint mode"
23         def __init__(self):
24                 super(simpleModeWindow, self).__init__(title='Cura - Quickprint - ' + version.getVersion())
25                 
26                 wx.EVT_CLOSE(self, self.OnClose)
27                 #self.SetIcon(icon.getMainIcon())
28
29                 self.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.supportedExtensions()))
30                 
31                 menubar = wx.MenuBar()
32                 fileMenu = wx.Menu()
33                 i = fileMenu.Append(-1, 'Load model file...')
34                 self.Bind(wx.EVT_MENU, self.OnLoadModel, i)
35                 fileMenu.AppendSeparator()
36                 i = fileMenu.Append(-1, 'Preferences...')
37                 self.Bind(wx.EVT_MENU, self.OnPreferences, i)
38                 fileMenu.AppendSeparator()
39                 i = fileMenu.Append(wx.ID_EXIT, 'Quit')
40                 self.Bind(wx.EVT_MENU, self.OnQuit, i)
41                 menubar.Append(fileMenu, '&File')
42                 
43                 toolsMenu = wx.Menu()
44                 i = toolsMenu.Append(-1, 'Switch to Normal mode...')
45                 self.Bind(wx.EVT_MENU, self.OnNormalSwitch, i)
46                 menubar.Append(toolsMenu, 'Normal mode')
47                 
48                 helpMenu = wx.Menu()
49                 i = helpMenu.Append(-1, 'Online documentation...')
50                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://daid.github.com/Cura'), i)
51                 i = helpMenu.Append(-1, 'Report a problem...')
52                 self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i)
53                 menubar.Append(helpMenu, 'Help')
54                 self.SetMenuBar(menubar)
55                 
56                 if profile.getPreference('lastFile') != '':
57                         self.filelist = profile.getPreference('lastFile').split(';')
58                         self.SetTitle(self.filelist[-1] + ' - Cura - ' + version.getVersion())
59                 else:
60                         self.filelist = []
61                 self.progressPanelList = []
62
63                 #Preview window
64                 self.preview3d = preview3d.previewPanel(self)
65
66                 configPanel = wx.Panel(self)
67                 self.printTypeNormal = wx.RadioButton(configPanel, -1, 'Normal quality print', style=wx.RB_GROUP)
68                 self.printTypeLow = wx.RadioButton(configPanel, -1, 'Fast low quality print')
69                 self.printTypeHigh = wx.RadioButton(configPanel, -1, 'High quality print')
70                 self.printTypeJoris = wx.RadioButton(configPanel, -1, 'Thin walled cup or vase')
71
72                 self.printMaterialPLA = wx.RadioButton(configPanel, -1, 'PLA', style=wx.RB_GROUP)
73                 self.printMaterialABS = wx.RadioButton(configPanel, -1, 'ABS')
74                 self.printMaterialDiameter = wx.TextCtrl(configPanel, -1, profile.getProfileSetting('filament_diameter'))
75                 
76                 self.printSupport = wx.CheckBox(configPanel, -1, 'Print support structure')
77                 
78                 sizer = wx.GridBagSizer()
79                 configPanel.SetSizer(sizer)
80
81                 sb = wx.StaticBox(configPanel, label="Select a print type:")
82                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
83                 boxsizer.Add(self.printTypeNormal)
84                 boxsizer.Add(self.printTypeLow)
85                 boxsizer.Add(self.printTypeHigh)
86                 boxsizer.Add(self.printTypeJoris)
87                 sizer.Add(boxsizer, (0,0), flag=wx.EXPAND)
88
89                 sb = wx.StaticBox(configPanel, label="Material:")
90                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
91                 boxsizer.Add(self.printMaterialPLA)
92                 boxsizer.Add(self.printMaterialABS)
93                 boxsizer.Add(wx.StaticText(configPanel, -1, 'Diameter:'))
94                 boxsizer.Add(self.printMaterialDiameter)
95                 sizer.Add(boxsizer, (1,0), flag=wx.EXPAND)
96
97                 sb = wx.StaticBox(configPanel, label="Other:")
98                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
99                 boxsizer.Add(self.printSupport)
100                 sizer.Add(boxsizer, (2,0), flag=wx.EXPAND)
101
102                 # load and slice buttons.
103                 loadButton = wx.Button(self, -1, 'Load Model')
104                 sliceButton = wx.Button(self, -1, 'Prepare print')
105                 printButton = wx.Button(self, -1, 'Print')
106                 self.Bind(wx.EVT_BUTTON, self.OnLoadModel, loadButton)
107                 self.Bind(wx.EVT_BUTTON, self.OnSlice, sliceButton)
108                 self.Bind(wx.EVT_BUTTON, self.OnPrint, printButton)
109                 #Also bind double clicking the 3D preview to load an STL file.
110                 self.preview3d.glCanvas.Bind(wx.EVT_LEFT_DCLICK, self.OnLoadModel, self.preview3d.glCanvas)
111
112                 #Main sizer, to position the preview window, buttons and tab control
113                 sizer = wx.GridBagSizer()
114                 self.SetSizer(sizer)
115                 sizer.Add(configPanel, (0,0), span=(1,1), flag=wx.EXPAND)
116                 sizer.Add(self.preview3d, (0,1), span=(1,3), flag=wx.EXPAND)
117                 sizer.AddGrowableCol(2)
118                 sizer.AddGrowableRow(0)
119                 sizer.Add(loadButton, (1,1), flag=wx.RIGHT, border=5)
120                 sizer.Add(sliceButton, (1,2), flag=wx.RIGHT, border=5)
121                 sizer.Add(printButton, (1,3), flag=wx.RIGHT, border=5)
122                 self.sizer = sizer
123
124                 if len(self.filelist) > 0:
125                         self.preview3d.loadModelFiles(self.filelist)
126
127                 self.updateProfileToControls()
128
129                 self.Fit()
130                 self.SetMinSize(self.GetSize())
131                 self.Centre()
132                 self.Show(True)
133         
134         def OnPreferences(self, e):
135                 prefDialog = preferencesDialog.preferencesDialog(self)
136                 prefDialog.Centre()
137                 prefDialog.Show(True)
138
139         def OnLoadModel(self, e):
140                 dlg=wx.FileDialog(self, "Open file to print", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
141                 dlg.SetWildcard(meshLoader.wildcardFilter())
142                 if dlg.ShowModal() == wx.ID_OK:
143                         self.filelist = [dlg.GetPath()]
144                         profile.putPreference('lastFile', ';'.join(self.filelist))
145                         self.preview3d.loadModelFiles(self.filelist, True)
146                         self.preview3d.setViewMode("Normal")
147                 dlg.Destroy()
148
149         def OnDropFiles(self, filenames):
150                 self.filelist = filenames
151                 profile.putPreference('lastFile', ';'.join(self.filelist))
152                 self.preview3d.loadModelFiles(self.filelist, True)
153                 self.preview3d.setViewMode("Normal")
154         
155         def OnSlice(self, e):
156                 if len(self.filelist) < 1:
157                         wx.MessageBox('You need to load a file before you can prepare it.', 'Print error', wx.OK | wx.ICON_INFORMATION)
158                         return
159                 #save the current profile so we can put it back latter
160                 oldProfile = profile.getGlobalProfileString()
161                 
162                 put = profile.putProfileSetting
163                 get = profile.getProfileSetting
164
165                 put('layer_height', '0.2')
166                 put('wall_thickness', '0.8')
167                 put('solid_layer_thickness', '0.6')
168                 put('fill_density', '20')
169                 put('skirt_line_count', '1')
170                 put('skirt_gap', '6.0')
171                 put('print_speed', '50')
172                 put('print_temperature', '220')
173                 put('support', 'None')
174                 #put('machine_center_x', '100')
175                 #put('machine_center_y', '100')
176                 put('retraction_enable', 'False')
177                 put('retraction_min_travel', '5.0')
178                 put('retraction_speed', '40.0')
179                 put('retraction_amount', '4.5')
180                 put('retraction_extra', '0.0')
181                 put('travel_speed', '150')
182                 put('max_z_speed', '3.0')
183                 put('bottom_layer_speed', '25')
184                 put('cool_min_layer_time', '10')
185                 put('fan_enabled', 'True')
186                 put('fan_layer', '1')
187                 put('fan_speed', '100')
188                 #put('model_scale', '1.0')
189                 #put('flip_x', 'False')
190                 #put('flip_y', 'False')
191                 #put('flip_z', 'False')
192                 #put('model_rotate_base', '0')
193                 #put('model_multiply_x', '1')
194                 #put('model_multiply_y', '1')
195                 put('extra_base_wall_thickness', '0.0')
196                 put('sequence', 'Loops > Perimeter > Infill')
197                 put('force_first_layer_sequence', 'True')
198                 put('infill_type', 'Line')
199                 put('solid_top', 'True')
200                 put('fill_overlap', '15')
201                 put('support_rate', '50')
202                 put('support_distance', '0.5')
203                 put('joris', 'False')
204                 put('cool_min_feedrate', '5')
205                 put('bridge_speed', '100')
206                 put('raft_margin', '5')
207                 put('raft_base_material_amount', '100')
208                 put('raft_interface_material_amount', '100')
209                 put('bottom_thickness', '0.0')
210
211                 if self.printSupport.GetValue():
212                         put('support', 'Exterior Only')
213
214                 nozzle_size = float(get('nozzle_size'))
215                 if self.printTypeNormal.GetValue():
216                         put('wall_thickness', nozzle_size * 2.0)
217                         put('layer_height', '0.2')
218                         put('fill_density', '20')
219                 elif self.printTypeLow.GetValue():
220                         put('wall_thickness', nozzle_size * 1.4)
221                         put('layer_height', '0.25')
222                         put('fill_density', '10')
223                         put('print_speed', '80')
224                         put('cool_min_layer_time', '3')
225                         put('bottom_layer_speed', '40')
226                 elif self.printTypeHigh.GetValue():
227                         put('wall_thickness', nozzle_size * 2.0)
228                         put('layer_height', '0.1')
229                         put('fill_density', '30')
230                         put('bottom_layer_speed', '15')
231                         put('bottom_thickness', '0.2')
232                 elif self.printTypeJoris.GetValue():
233                         put('wall_thickness', nozzle_size * 1.5)
234                         put('layer_height', '0.3')
235                         put('solid_layer_thickness', '0.9')
236                         put('fill_density', '0')
237                         put('joris', 'True')
238                         put('extra_base_wall_thickness', '15.0')
239                         put('sequence', 'Infill > Loops > Perimeter')
240                         put('force_first_layer_sequence', 'False')
241                         put('solid_top', 'False')
242                         put('support', 'None')
243                         put('cool_min_layer_time', '3')
244
245                 put('filament_diameter', self.printMaterialDiameter.GetValue())
246                 if self.printMaterialPLA.GetValue():
247                         put('filament_density', '1.00')
248                         put('enable_raft', 'False')
249                         put('skirt_line_count', '1')
250                 if self.printMaterialABS.GetValue():
251                         put('filament_density', '0.85')
252                         put('enable_raft', 'True')
253                         put('skirt_line_count', '0')
254                         put('fan_layer', '1')
255                         put('bottom_thickness', '0.0')
256                         put('print_temperature', '260')
257                 
258                 #Create a progress panel and add it to the window. The progress panel will start the Skein operation.
259                 spp = sliceProgessPanel.sliceProgessPanel(self, self, self.filelist)
260                 self.sizer.Add(spp, (len(self.progressPanelList)+2,0), span=(1,4), flag=wx.EXPAND)
261                 self.sizer.Layout()
262                 newSize = self.GetSize();
263                 newSize.IncBy(0, spp.GetSize().GetHeight())
264                 self.SetSize(newSize)
265                 self.progressPanelList.append(spp)
266                 
267                 #Restore the old profile.
268                 profile.loadGlobalProfileFromString(oldProfile)
269         
270         def OnPrint(self, e):
271                 if len(self.filelist) < 1:
272                         wx.MessageBox('You need to load a file and prepare it before you can print.', 'Print error', wx.OK | wx.ICON_INFORMATION)
273                         return
274                 if not os.path.exists(sliceRun.getExportFilename(self.filelist[0])):
275                         wx.MessageBox('You need to prepare the file before you can print.', 'Print error', wx.OK | wx.ICON_INFORMATION)
276                         return
277                 printWindow.printFile(sliceRun.getExportFilename(self.filelist[0]))
278
279         def OnNormalSwitch(self, e):
280                 from gui import mainWindow
281                 profile.putPreference('startMode', 'Normal')
282                 mainWindow.mainWindow()
283                 self.Close()
284
285         def removeSliceProgress(self, spp):
286                 self.progressPanelList.remove(spp)
287                 newSize = self.GetSize();
288                 newSize.IncBy(0, -spp.GetSize().GetHeight())
289                 self.SetSize(newSize)
290                 self.sizer.Remove(spp)
291                 spp.Destroy()
292                 for spp in self.progressPanelList:
293                         self.sizer.Remove(spp)
294                 i = 2
295                 for spp in self.progressPanelList:
296                         self.sizer.Add(spp, (i,0), span=(1,4), flag=wx.EXPAND)
297                         i += 1
298                 self.sizer.Layout()
299
300         def OnQuit(self, e):
301                 self.Close()
302         
303         def OnClose(self, e):
304                 self.Destroy()
305
306         def updateProfileToControls(self):
307                 super(simpleModeWindow, self).updateProfileToControls()
308                 self.preview3d.updateProfileToControls()
309