|
1 # This file is part of the Printrun suite. |
|
2 # |
|
3 # Printrun is free software: you can redistribute it and/or modify |
|
4 # it under the terms of the GNU General Public License as published by |
|
5 # the Free Software Foundation, either version 3 of the License, or |
|
6 # (at your option) any later version. |
|
7 # |
|
8 # Printrun is distributed in the hope that it will be useful, |
|
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 # GNU General Public License for more details. |
|
12 # |
|
13 # You should have received a copy of the GNU General Public License |
|
14 # along with Printrun. If not, see <http://www.gnu.org/licenses/>. |
|
15 # |
|
16 # Copyright 2017 Rock Storm <rockstorm@gmx.com> |
|
17 |
|
18 import wx |
|
19 from . import spoolmanager |
|
20 |
|
21 class SpoolManagerMainWindow(wx.Frame): |
|
22 """ |
|
23 Front-end for the Spool Manager. |
|
24 |
|
25 Main window which displays the currently loaded spools and the list of |
|
26 recorded ones with buttons to add, load, edit or delete them. |
|
27 """ |
|
28 |
|
29 def __init__(self, parent, spool_manager): |
|
30 wx.Frame.__init__(self, parent, |
|
31 title = "Spool Manager", |
|
32 style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) |
|
33 |
|
34 self.statusbar = self.CreateStatusBar() |
|
35 |
|
36 self.SetIcon(parent.GetIcon()) |
|
37 |
|
38 # Initiate the back-end |
|
39 self.spool_manager = spool_manager |
|
40 self.spool_manager.refresh() |
|
41 |
|
42 # Generate the dialogs showing the current spools |
|
43 self.current_spools_dialog = CurrentSpoolDialog(self, |
|
44 self.spool_manager) |
|
45 |
|
46 # Generate the list of recorded spools |
|
47 self.spool_list = SpoolListView(self, self.spool_manager) |
|
48 |
|
49 # Generate the buttons |
|
50 self.new_button = wx.Button(self, wx.ID_ADD) |
|
51 self.new_button.SetToolTip("Add a new spool") |
|
52 self.edit_button = wx.Button(self, wx.ID_EDIT) |
|
53 self.edit_button.SetToolTip("Edit the selected spool") |
|
54 self.delete_button = wx.Button(self, wx.ID_DELETE) |
|
55 self.delete_button.SetToolTip("Delete the selected spool") |
|
56 |
|
57 # "Program" the buttons |
|
58 self.new_button.Bind(wx.EVT_BUTTON, self.onClickAdd) |
|
59 self.edit_button.Bind(wx.EVT_BUTTON, self.onClickEdit) |
|
60 self.delete_button.Bind(wx.EVT_BUTTON, self.onClickDelete) |
|
61 |
|
62 # Layout |
|
63 ## Group the buttons |
|
64 self.button_sizer = wx.BoxSizer(wx.VERTICAL) |
|
65 self.button_sizer.Add(self.new_button, 1, |
|
66 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
67 self.button_sizer.Add(self.edit_button, 1, |
|
68 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
69 self.button_sizer.Add(self.delete_button, 1, |
|
70 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
71 |
|
72 ## Group the buttons with the spool list |
|
73 self.list_sizer = wx.BoxSizer(wx.HORIZONTAL) |
|
74 self.list_sizer.Add(self.spool_list, 1, wx.EXPAND) |
|
75 self.list_sizer.Add(self.button_sizer, 0, wx.ALIGN_CENTER) |
|
76 |
|
77 ## Layout the whole thing |
|
78 self.full_sizer = wx.BoxSizer(wx.VERTICAL) |
|
79 self.full_sizer.Add(self.current_spools_dialog, 0, wx.EXPAND) |
|
80 self.full_sizer.Add(self.list_sizer, 1, wx.ALL | wx.EXPAND, 10) |
|
81 |
|
82 self.SetSizerAndFit(self.full_sizer) |
|
83 |
|
84 def onClickAdd(self, event): |
|
85 """Open the window for customizing the new spool.""" |
|
86 SpoolManagerAddWindow(self).Show(True) |
|
87 |
|
88 def onClickLoad(self, event, extruder): |
|
89 """Load the selected spool to the correspondent extruder.""" |
|
90 |
|
91 # Check whether there is a spool selected |
|
92 spool_index = self.spool_list.GetFirstSelected() |
|
93 if spool_index == -1 : |
|
94 self.statusbar.SetStatusText( |
|
95 "Could not load the spool. No spool selected.") |
|
96 return 0 |
|
97 else: |
|
98 spool_name = self.spool_list.GetItemText(spool_index) |
|
99 self.statusbar.SetStatusText("") |
|
100 |
|
101 # If selected spool is already loaded, do nothing |
|
102 spool_extruder = self.spool_manager.isLoaded(spool_name) |
|
103 if spool_extruder > -1: |
|
104 self.statusbar.SetStatusText( |
|
105 "Spool '%s' is already loaded for Extruder %d." % |
|
106 (spool_name, spool_extruder)) |
|
107 return 0 |
|
108 |
|
109 # Load the selected spool and refresh the current spools dialog |
|
110 self.spool_manager.load(spool_name, extruder) |
|
111 self.current_spools_dialog.refreshDialog(self.spool_manager) |
|
112 self.statusbar.SetStatusText( |
|
113 "Loaded spool '%s' for Extruder %d." % (spool_name, extruder)) |
|
114 |
|
115 def onClickUnload(self, event, extruder): |
|
116 """Unload the spool from the correspondent extruder.""" |
|
117 |
|
118 spool_name = self.spool_manager.getSpoolName(extruder) |
|
119 if spool_name != None: |
|
120 self.spool_manager.unload(extruder) |
|
121 self.current_spools_dialog.refreshDialog(self.spool_manager) |
|
122 self.statusbar.SetStatusText( |
|
123 "Unloaded spool from Extruder %d." % extruder) |
|
124 else: |
|
125 self.statusbar.SetStatusText( |
|
126 "There is no spool loaded for Extruder %d." % extruder) |
|
127 |
|
128 def onClickEdit(self, event): |
|
129 """Open the window for editing the data of the selected spool.""" |
|
130 |
|
131 # Check whether there is a spool selected |
|
132 spool_index = self.spool_list.GetFirstSelected() |
|
133 if spool_index == -1 : |
|
134 self.statusbar.SetStatusText( |
|
135 "Could not edit the spool. No spool selected.") |
|
136 return 0 |
|
137 |
|
138 # Open the edit window |
|
139 spool_name = self.spool_list.GetItemText(spool_index) |
|
140 spool_length = self.spool_list.GetItemText(spool_index, 1) |
|
141 SpoolManagerEditWindow(self, spool_name, spool_length).Show(True) |
|
142 self.statusbar.SetStatusText("") |
|
143 |
|
144 def onClickDelete(self, event): |
|
145 """Delete the selected spool.""" |
|
146 |
|
147 # Get the selected spool |
|
148 spool_index = self.spool_list.GetFirstSelected() |
|
149 if spool_index == -1 : |
|
150 self.statusbar.SetStatusText( |
|
151 "Could not delete the spool. No spool selected.") |
|
152 return 0 |
|
153 else: |
|
154 spool_name = self.spool_list.GetItemText(spool_index) |
|
155 self.statusbar.SetStatusText("") |
|
156 |
|
157 # Ask confirmation for deleting |
|
158 delete_dialog = wx.MessageDialog(self, |
|
159 message = "Are you sure you want to delete the '%s' spool" % |
|
160 spool_name, |
|
161 caption = "Delete Spool", |
|
162 style = wx.YES_NO | wx.ICON_EXCLAMATION) |
|
163 |
|
164 if delete_dialog.ShowModal() == wx.ID_YES: |
|
165 # Remove spool |
|
166 self.spool_manager.remove(spool_name) |
|
167 self.spool_list.refreshList(self.spool_manager) |
|
168 self.current_spools_dialog.refreshDialog(self.spool_manager) |
|
169 self.statusbar.SetStatusText( |
|
170 "Deleted spool '%s'." % spool_name) |
|
171 |
|
172 |
|
173 class SpoolListView(wx.ListView): |
|
174 """ |
|
175 Custom wxListView object which visualizes the list of available spools. |
|
176 """ |
|
177 |
|
178 def __init__(self, parent, spool_manager): |
|
179 wx.ListView.__init__(self, parent, |
|
180 style = wx.LC_REPORT | wx.LC_SINGLE_SEL) |
|
181 self.InsertColumn(0, "Spool", width = wx.LIST_AUTOSIZE_USEHEADER) |
|
182 self.InsertColumn(1, "Filament", width = wx.LIST_AUTOSIZE_USEHEADER) |
|
183 self.populateList(spool_manager) |
|
184 |
|
185 # "Program" the layout |
|
186 self.Bind(wx.EVT_SIZE, self.onResizeList) |
|
187 |
|
188 def populateList(self, spool_manager): |
|
189 """Get the list of recorded spools from the Spool Manager.""" |
|
190 spool_list = spool_manager.getSpoolList() |
|
191 for i in range(len(spool_list)): |
|
192 self.Append(spool_list[i]) |
|
193 |
|
194 def refreshList(self, spool_manager): |
|
195 """Refresh the list by re-reading the Spool Manager list.""" |
|
196 self.DeleteAllItems() |
|
197 self.populateList(spool_manager) |
|
198 |
|
199 def onResizeList(self, event): |
|
200 list_size = self.GetSize() |
|
201 self.SetColumnWidth(1, -2) |
|
202 filament_column_width = self.GetColumnWidth(1) |
|
203 self.SetColumnWidth(col = 0, |
|
204 width = list_size.width - filament_column_width) |
|
205 event.Skip() |
|
206 |
|
207 |
|
208 class CurrentSpoolDialog(wx.Panel): |
|
209 """ |
|
210 Custom wxStaticText object to display the currently loaded spools and |
|
211 their remaining filament. |
|
212 """ |
|
213 |
|
214 def __init__(self, parent, spool_manager): |
|
215 wx.Panel.__init__(self, parent) |
|
216 self.parent = parent |
|
217 self.extruders = spool_manager.getExtruderCount() |
|
218 |
|
219 full_sizer = wx.BoxSizer(wx.VERTICAL) |
|
220 |
|
221 # Calculate the minimum size needed to properly display the |
|
222 # extruder information |
|
223 min_size = self.GetTextExtent(" Remaining filament: 0000000.00") |
|
224 |
|
225 # Generate a dialog for every extruder |
|
226 self.extruder_dialog = [] |
|
227 load_button = [] |
|
228 unload_button = [] |
|
229 button_sizer = [] |
|
230 dialog_sizer = [] |
|
231 for i in range(self.extruders): |
|
232 # Generate the dialog with the spool information |
|
233 self.extruder_dialog.append( |
|
234 wx.StaticText(self, style = wx.ST_ELLIPSIZE_END)) |
|
235 self.extruder_dialog[i].SetMinSize(wx.Size(min_size.width, -1)) |
|
236 |
|
237 # Generate the "load" and "unload" buttons |
|
238 load_button.append(wx.Button(self, label = "Load")) |
|
239 load_button[i].SetToolTip( |
|
240 "Load selected spool for Extruder %d" % i) |
|
241 unload_button.append(wx.Button(self, label = "Unload")) |
|
242 unload_button[i].SetToolTip( |
|
243 "Unload the spool for Extruder %d" % i) |
|
244 |
|
245 # "Program" the buttons |
|
246 load_button[i].Bind(wx.EVT_BUTTON, |
|
247 lambda event, extruder=i: parent.onClickLoad(event, extruder)) |
|
248 unload_button[i].Bind(wx.EVT_BUTTON, |
|
249 lambda event, extruder=i: parent.onClickUnload(event, extruder)) |
|
250 |
|
251 # Layout |
|
252 button_sizer.append(wx.BoxSizer(wx.VERTICAL)) |
|
253 button_sizer[i].Add(load_button[i], 0, |
|
254 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
255 button_sizer[i].Add(unload_button[i], 0, |
|
256 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
257 |
|
258 dialog_sizer.append(wx.BoxSizer(wx.HORIZONTAL)) |
|
259 dialog_sizer[i].Add(self.extruder_dialog[i], 1, wx.ALIGN_CENTER) |
|
260 dialog_sizer[i].AddSpacer(10) |
|
261 dialog_sizer[i].Add(button_sizer[i], 0, wx.EXPAND) |
|
262 |
|
263 full_sizer.Add(dialog_sizer[i], 0, wx.ALL | wx.EXPAND, 10) |
|
264 |
|
265 self.refreshDialog(spool_manager) |
|
266 |
|
267 self.SetSizerAndFit(full_sizer) |
|
268 |
|
269 |
|
270 def refreshDialog(self, spool_manager): |
|
271 """Retrieve the current spools from the Spool Manager.""" |
|
272 |
|
273 for i in range(self.extruders): |
|
274 spool_name = spool_manager.getSpoolName(i) |
|
275 spool_filament = spool_manager.getRemainingFilament(i) |
|
276 label = ("Spool for Extruder %d:\n" % i + |
|
277 " Name: %s\n" % spool_name + |
|
278 " Remaining filament: %.2f" % spool_filament) |
|
279 self.extruder_dialog[i].SetLabelText(label) |
|
280 |
|
281 |
|
282 # --------------------------------------------------------------------------- |
|
283 def checkOverwrite(parent, spool_name): |
|
284 """Ask the user whether or not to overwrite the existing spool.""" |
|
285 |
|
286 overwrite_dialog = wx.MessageDialog(parent, |
|
287 message = "A spool with the name '%s'' already exists." % |
|
288 spool_name + |
|
289 "Do you wish to overwrite it?", |
|
290 caption = "Overwrite", |
|
291 style = wx.YES_NO | wx.ICON_EXCLAMATION) |
|
292 |
|
293 if overwrite_dialog.ShowModal() == wx.ID_YES: |
|
294 return True |
|
295 else: |
|
296 return False |
|
297 |
|
298 def getFloat(parent, number): |
|
299 """ |
|
300 Check whether the input number is a float. Either return the number or |
|
301 return False. |
|
302 """ |
|
303 try: |
|
304 return float(number) |
|
305 except ValueError: |
|
306 parent.statusbar.SetStatusText("Unrecognized number: %s" % number) |
|
307 return False |
|
308 |
|
309 |
|
310 # --------------------------------------------------------------------------- |
|
311 class SpoolManagerAddWindow(wx.Frame): |
|
312 """Window for adding spools.""" |
|
313 |
|
314 def __init__(self, parent): |
|
315 |
|
316 wx.Frame.__init__(self, parent, |
|
317 title = "Add Spool", |
|
318 style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) |
|
319 |
|
320 self.statusbar = self.CreateStatusBar() |
|
321 |
|
322 self.parent = parent |
|
323 |
|
324 self.SetIcon(parent.GetIcon()) |
|
325 |
|
326 # Generate the dialogs |
|
327 self.name_dialog = LabeledTextCtrl(self, |
|
328 "Name", "Default Spool", "") |
|
329 self.diameter_dialog = LabeledTextCtrl(self, |
|
330 "Diameter", "1.75", "mm") |
|
331 self.diameter_dialog.SetToolTip( |
|
332 "Typically, either 1.75 mm or 2.85 mm (a.k.a '3')") |
|
333 self.weight_dialog = LabeledTextCtrl(self, |
|
334 "Weight", "1", "Kg") |
|
335 self.density_dialog = LabeledTextCtrl(self, |
|
336 "Density", "1.25", "g/cm^3") |
|
337 self.density_dialog.SetToolTip( |
|
338 "Typical densities are 1.25 g/cm^3 for PLA and 1.08 g/cm^3 for" + |
|
339 " ABS") |
|
340 self.length_dialog = LabeledTextCtrl(self, |
|
341 "Length", "332601.35", "mm") |
|
342 |
|
343 # "Program" the dialogs |
|
344 self.diameter_dialog.Bind(wx.EVT_TEXT, self.calculateLength) |
|
345 self.weight_dialog.Bind(wx.EVT_TEXT, self.calculateLength) |
|
346 self.density_dialog.Bind(wx.EVT_TEXT, self.calculateLength) |
|
347 self.length_dialog.Bind(wx.EVT_TEXT, self.calculateWeight) |
|
348 |
|
349 # Generate the bottom buttons |
|
350 self.add_button = wx.Button(self, wx.ID_ADD) |
|
351 self.cancel_button = wx.Button(self, wx.ID_CANCEL) |
|
352 |
|
353 # "Program" the bottom buttons |
|
354 self.add_button.Bind(wx.EVT_BUTTON, self.onClickAdd) |
|
355 self.cancel_button.Bind(wx.EVT_BUTTON, self.onClickCancel) |
|
356 |
|
357 # Layout |
|
358 ## Group the bottom buttons |
|
359 self.bottom_buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) |
|
360 self.bottom_buttons_sizer.Add(self.add_button, 0, wx.FIXED_MINSIZE) |
|
361 self.bottom_buttons_sizer.Add(self.cancel_button, 0, wx.FIXED_MINSIZE) |
|
362 |
|
363 ## Group the whole window |
|
364 self.full_sizer = wx.BoxSizer(wx.VERTICAL) |
|
365 self.full_sizer.Add(self.name_dialog, 0, |
|
366 wx.TOP | wx.BOTTOM | wx.EXPAND, 10) |
|
367 self.full_sizer.Add(self.diameter_dialog, 0, wx.EXPAND) |
|
368 self.full_sizer.Add(self.weight_dialog, 0, wx.EXPAND) |
|
369 self.full_sizer.Add(self.density_dialog, 0, wx.EXPAND) |
|
370 self.full_sizer.Add(self.length_dialog, 0, wx.EXPAND) |
|
371 self.full_sizer.Add(self.bottom_buttons_sizer, 0, |
|
372 wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 10) |
|
373 |
|
374 self.SetSizerAndFit(self.full_sizer) |
|
375 |
|
376 # Don't allow this window to be resized in height |
|
377 add_window_size = self.GetSize() |
|
378 self.SetMaxSize((-1, add_window_size.height)) |
|
379 |
|
380 def onClickAdd(self, event): |
|
381 """Add the new spool and close the window.""" |
|
382 |
|
383 spool_name = self.name_dialog.field.GetValue() |
|
384 spool_length = getFloat(self, self.length_dialog.field.GetValue()) |
|
385 |
|
386 # Check whether the length is actually a number |
|
387 if not spool_length: |
|
388 self.statusbar.SetStatusText( |
|
389 "ERROR: Unrecognized length: %s." % |
|
390 self.length_dialog.field.GetValue()) |
|
391 return -1 |
|
392 |
|
393 # The remaining filament should always be a positive number |
|
394 if not spool_length > 0: |
|
395 self.statusbar.SetStatusText( |
|
396 "ERROR: Length is zero or negative: %.2f." % spool_length) |
|
397 return -1 |
|
398 |
|
399 # Check whether the name is already used. If it is used, prompt the |
|
400 # user before overwriting it |
|
401 if self.parent.spool_manager.isListed(spool_name): |
|
402 if checkOverwrite(self, spool_name): |
|
403 # Remove the "will be overwritten" spool |
|
404 self.parent.spool_manager.remove(spool_name) |
|
405 else: |
|
406 return 0 |
|
407 |
|
408 # Add the new spool |
|
409 self.parent.spool_manager.add(spool_name, spool_length) |
|
410 self.parent.spool_list.refreshList(self.parent.spool_manager) |
|
411 self.parent.current_spools_dialog.refreshDialog( |
|
412 self.parent.spool_manager) |
|
413 self.parent.statusbar.SetStatusText( |
|
414 "Added new spool '%s'" % spool_name + |
|
415 " with %.2f mm of remaining filament." % spool_length) |
|
416 |
|
417 self.Close(True) |
|
418 |
|
419 def onClickCancel(self, event): |
|
420 """Do nothing and close the window.""" |
|
421 self.Close(True) |
|
422 self.parent.statusbar.SetStatusText("") |
|
423 |
|
424 def calculateLength(self, event): |
|
425 """ |
|
426 Calculate the length of the filament given the mass, diameter and |
|
427 density of the filament. Set the 'Length' field to this quantity. |
|
428 """ |
|
429 |
|
430 mass = getFloat(self, self.weight_dialog.field.GetValue()) |
|
431 diameter = getFloat(self, self.diameter_dialog.field.GetValue()) |
|
432 density = getFloat(self, self.density_dialog.field.GetValue()) |
|
433 if mass and diameter and density: |
|
434 pi = 3.14159265359 |
|
435 length = 4e6 * mass / pi / diameter**2 / density |
|
436 self.length_dialog.field.ChangeValue("%.2f" % length) |
|
437 self.statusbar.SetStatusText("") |
|
438 else: |
|
439 self.length_dialog.field.ChangeValue("---") |
|
440 |
|
441 def calculateWeight(self, event): |
|
442 """ |
|
443 Calculate the weight of the filament given the length, diameter and |
|
444 density of the filament. Set the 'Weight' field to this value. |
|
445 """ |
|
446 |
|
447 length = getFloat(self, self.length_dialog.field.GetValue()) |
|
448 diameter = getFloat(self, self.diameter_dialog.field.GetValue()) |
|
449 density = getFloat(self, self.density_dialog.field.GetValue()) |
|
450 if length and diameter and density: |
|
451 pi = 3.14159265359 |
|
452 mass = length * pi * diameter**2 * density / 4e6 |
|
453 self.weight_dialog.field.ChangeValue("%.2f" % mass) |
|
454 self.statusbar.SetStatusText("") |
|
455 else: |
|
456 self.weight_dialog.field.ChangeValue("---") |
|
457 |
|
458 |
|
459 class LabeledTextCtrl(wx.Panel): |
|
460 """ |
|
461 Group together a wxTextCtrl with a preceding and a subsequent wxStaticText. |
|
462 """ |
|
463 |
|
464 def __init__(self, parent, preceding_text, field_value, subsequent_text): |
|
465 wx.Panel.__init__(self, parent) |
|
466 self.pretext = wx.StaticText(self, label = preceding_text, |
|
467 style = wx.ALIGN_RIGHT) |
|
468 self.field = wx.TextCtrl(self, value = field_value) |
|
469 self.subtext = wx.StaticText(self, label = subsequent_text) |
|
470 |
|
471 # Layout the panel |
|
472 self.sizer = wx.BoxSizer(wx.HORIZONTAL) |
|
473 self.sizer.Add(self.pretext, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 10) |
|
474 self.sizer.SetItemMinSize(self.pretext, (80, -1)) |
|
475 self.sizer.Add(self.field, 1, wx.EXPAND) |
|
476 self.sizer.Add(self.subtext, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
|
477 self.sizer.SetItemMinSize(self.subtext, (50, -1)) |
|
478 |
|
479 self.SetSizerAndFit(self.sizer) |
|
480 |
|
481 |
|
482 # --------------------------------------------------------------------------- |
|
483 class SpoolManagerEditWindow(wx.Frame): |
|
484 """Window for editing the name or the length of a spool.""" |
|
485 |
|
486 def __init__(self, parent, spool_name, spool_length): |
|
487 |
|
488 wx.Frame.__init__(self, parent, |
|
489 title = "Edit Spool", |
|
490 style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) |
|
491 |
|
492 self.statusbar = self.CreateStatusBar() |
|
493 |
|
494 self.parent = parent |
|
495 |
|
496 self.SetIcon(parent.GetIcon()) |
|
497 |
|
498 self.old_spool_name = spool_name |
|
499 self.old_spool_length = getFloat(self, spool_length) |
|
500 |
|
501 # Set how many millimeters will the buttons add or subtract |
|
502 self.quantities = [-100.0, -50.0, -10.0, 10.0, 50.0, 100.0] |
|
503 |
|
504 # Generate the name field |
|
505 self.name_field = LabeledTextCtrl(self, |
|
506 "Name", self.old_spool_name, "") |
|
507 |
|
508 # Generate the length field and buttons |
|
509 self.length_title = wx.StaticText(self, label = "Remaining filament:") |
|
510 self.minus3_button = wx.Button(self, |
|
511 label = str(self.quantities[0]), style = wx.BU_EXACTFIT) |
|
512 self.minus2_button = wx.Button(self, |
|
513 label = str(self.quantities[1]), style = wx.BU_EXACTFIT) |
|
514 self.minus1_button = wx.Button(self, |
|
515 label = str(self.quantities[2]), style = wx.BU_EXACTFIT) |
|
516 self.length_field = wx.TextCtrl(self, |
|
517 value = str(self.old_spool_length)) |
|
518 self.plus1_button = wx.Button(self, |
|
519 label = "+" + str(self.quantities[3]), style = wx.BU_EXACTFIT) |
|
520 self.plus2_button = wx.Button(self, |
|
521 label = "+" + str(self.quantities[4]), style = wx.BU_EXACTFIT) |
|
522 self.plus3_button = wx.Button(self, |
|
523 label = "+" + str(self.quantities[5]), style = wx.BU_EXACTFIT) |
|
524 |
|
525 # "Program" the length buttons |
|
526 self.minus3_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
527 self.minus2_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
528 self.minus1_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
529 self.plus1_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
530 self.plus2_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
531 self.plus3_button.Bind(wx.EVT_BUTTON, self.changeLength) |
|
532 |
|
533 # Generate the bottom buttons |
|
534 self.save_button = wx.Button(self, wx.ID_SAVE) |
|
535 self.cancel_button = wx.Button(self, wx.ID_CANCEL) |
|
536 |
|
537 # "Program" the bottom buttons |
|
538 self.save_button.Bind(wx.EVT_BUTTON, self.onClickSave) |
|
539 self.cancel_button.Bind(wx.EVT_BUTTON, self.onClickCancel) |
|
540 |
|
541 # Layout |
|
542 ## Group the length field and its correspondent buttons |
|
543 self.length_sizer = wx.BoxSizer(wx.HORIZONTAL) |
|
544 self.length_sizer.Add(self.minus3_button, 0, |
|
545 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
546 self.length_sizer.Add(self.minus2_button, 0, |
|
547 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
548 self.length_sizer.Add(self.minus1_button, 0, |
|
549 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
550 self.length_sizer.Add(self.length_field, 1, wx.EXPAND) |
|
551 self.length_sizer.Add(self.plus1_button, 0, |
|
552 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
553 self.length_sizer.Add(self.plus2_button, 0, |
|
554 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
555 self.length_sizer.Add(self.plus3_button, 0, |
|
556 wx.FIXED_MINSIZE | wx.ALIGN_CENTER) |
|
557 |
|
558 ## Group the bottom buttons |
|
559 self.bottom_buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) |
|
560 self.bottom_buttons_sizer.Add(self.save_button, 0, wx.EXPAND) |
|
561 self.bottom_buttons_sizer.Add(self.cancel_button, 0, wx.EXPAND) |
|
562 |
|
563 ## Lay out the whole window |
|
564 self.full_sizer = wx.BoxSizer(wx.VERTICAL) |
|
565 self.full_sizer.Add(self.name_field, 0, wx.EXPAND) |
|
566 self.full_sizer.AddSpacer(10) |
|
567 self.full_sizer.Add(self.length_title, 0, |
|
568 wx.LEFT | wx.RIGHT | wx.EXPAND, 10) |
|
569 self.full_sizer.Add(self.length_sizer, 0, |
|
570 wx.LEFT | wx.RIGHT | wx.EXPAND, 10) |
|
571 self.full_sizer.AddSpacer(10) |
|
572 self.full_sizer.Add(self.bottom_buttons_sizer, 0, wx.ALIGN_CENTER) |
|
573 |
|
574 self.SetSizerAndFit(self.full_sizer) |
|
575 |
|
576 # Don't allow this window to be resized in height |
|
577 edit_window_size = self.GetSize() |
|
578 self.SetMaxSize((-1, edit_window_size.height)) |
|
579 |
|
580 def changeLength(self, event): |
|
581 new_length = getFloat(self, self.length_field.GetValue()) |
|
582 if new_length: |
|
583 new_length = new_length + float(event.GetEventObject().GetLabel()) |
|
584 self.length_field.ChangeValue("%.2f" % new_length) |
|
585 self.statusbar.SetStatusText("") |
|
586 |
|
587 def onClickSave(self, event): |
|
588 |
|
589 new_spool_name = self.name_field.field.GetValue() |
|
590 new_spool_length = getFloat(self, self.length_field.GetValue()) |
|
591 |
|
592 # Check whether the length is actually a number |
|
593 if not new_spool_length: |
|
594 self.statusbar.SetStatusText( |
|
595 "ERROR: Unrecognized length: %s." % |
|
596 self.length_field.GetValue()) |
|
597 return -1 |
|
598 |
|
599 if not new_spool_length > 0: |
|
600 self.statusbar.SetStatusText( |
|
601 "ERROR: Length is zero or negative: %.2f." % new_spool_length) |
|
602 return -1 |
|
603 |
|
604 # Check whether the "old" spool was loaded |
|
605 new_spool_extruder = self.parent.spool_manager.isLoaded( |
|
606 self.old_spool_name) |
|
607 |
|
608 # Check whether the name has changed |
|
609 if new_spool_name == self.old_spool_name: |
|
610 # Remove only the "old" spool |
|
611 self.parent.spool_manager.remove(self.old_spool_name) |
|
612 else: |
|
613 # Check whether the new name is already used |
|
614 if self.parent.spool_manager.isListed(new_spool_name): |
|
615 if checkOverwrite(self, new_spool_name): |
|
616 # Remove the "old" and the "will be overwritten" spools |
|
617 self.parent.spool_manager.remove(self.old_spool_name) |
|
618 self.parent.spool_manager.remove(new_spool_name) |
|
619 else: |
|
620 return 0 |
|
621 else: |
|
622 # Remove only the "old" spool |
|
623 self.parent.spool_manager.remove(self.old_spool_name) |
|
624 |
|
625 # Add "new" or edited spool |
|
626 self.parent.spool_manager.add(new_spool_name, new_spool_length) |
|
627 self.parent.spool_manager.load(new_spool_name, new_spool_extruder) |
|
628 self.parent.spool_list.refreshList(self.parent.spool_manager) |
|
629 self.parent.current_spools_dialog.refreshDialog( |
|
630 self.parent.spool_manager) |
|
631 self.parent.statusbar.SetStatusText( |
|
632 "Edited spool '%s'" % new_spool_name + |
|
633 " with %.2f mm of remaining filament." % new_spool_length) |
|
634 |
|
635 self.Close(True) |
|
636 |
|
637 def onClickCancel(self, event): |
|
638 self.Close(True) |
|
639 self.parent.statusbar.SetStatusText("") |