chiark / gitweb /
Fix wxpython 2.8 bug for quickprint selection
[cura.git] / Cura / gui / simpleMode.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import wx
4 import ConfigParser as configparser
5 import os.path
6
7 from Cura.util import profile
8 from Cura.util import resources
9
10 class simpleModePanel(wx.Panel):
11         "Main user interface window for Quickprint mode"
12         def __init__(self, parent, callback):
13                 super(simpleModePanel, self).__init__(parent)
14                 self._callback = callback
15
16                 self._print_material_options = []
17                 self._print_profile_options = []
18                 self._print_other_options = []
19                 self._print_material_types = {}
20                 self._all_print_materials = []
21
22                 materials = resources.getSimpleModeMaterials()
23                 other_print_material_types = []
24                 for material in materials:
25                         if material.disabled:
26                                 continue
27                         if len(material.types) == 0:
28                                 other_print_material_types.append(material)
29                         else:
30                                 for type in material.types:
31                                         if self._print_material_types.has_key(type):
32                                                 self._print_material_types[type].append(material)
33                                         else:
34                                                 self._print_material_types[type] = [material]
35
36                 if len(self._print_material_types) == 0:
37                         self._print_material_types = None
38
39                 # Create material buttons
40                 self.printMaterialPanel = wx.Panel(self)
41                 selectedMaterial = None
42                 for material in materials:
43                         if material.disabled:
44                                 continue
45                         # Show radio buttons if there are no material types
46                         if self._print_material_types is None:
47                                 button = wx.RadioButton(self.printMaterialPanel, -1, material.name.replace('&', '&&'),
48                                                                                 style=wx.RB_GROUP if len(self._print_material_options) == 0 else 0)
49                                 button.profile = material
50                                 button.Bind(wx.EVT_RADIOBUTTON, self._materialSelected)
51                                 self._print_material_options.append(button)
52                         self._all_print_materials.append(material)
53                         if profile.getProfileSetting('simpleModeMaterial') == material.name:
54                                 selectedMaterial = material
55
56                 # Decide on the default selected material
57                 if selectedMaterial is None:
58                         for material in self._all_print_materials:
59                                 if material.default:
60                                         selectedMaterial = material
61                                         break
62
63                 if selectedMaterial is None and len(self._all_print_materials) > 0:
64                         selectedMaterial = self._all_print_materials[0]
65
66                 # Decide to show the panel or not
67                 if self._print_material_types is None and len(self._print_material_options) < 2:
68                         self.printMaterialPanel.Show(len(self._print_material_options) > 1 and \
69                                                                                  self._print_material_options[0].always_visible)
70
71                 # Create material types combobox
72                 self.printMaterialTypesPanel = wx.Panel(self)
73                 selectedMaterialType = None
74                 if self._print_material_types is not None:
75                         for material_type in self._print_material_types:
76                                 if profile.getProfileSetting('simpleModeMaterialType') == material_type and \
77                                    selectedMaterial in self._print_material_types[material_type]:
78                                         selectedMaterialType = material_type
79
80                         if selectedMaterialType is None:
81                                 if selectedMaterial is None or len(selectedMaterial.types) == 0:
82                                         selectedMaterialType = _("Others")
83                                 else:
84                                         selectedMaterialType = selectedMaterial.types[0]
85
86                 # Decide to show the material types or not
87                 if self._print_material_types is None:
88                         self.printMaterialTypesPanel.Show(False)
89
90                 self.printTypePanel = wx.Panel(self)
91
92                 sizer = wx.GridBagSizer()
93                 self.SetSizer(sizer)
94
95                 boxsizer = wx.BoxSizer(wx.VERTICAL)
96                 boxsizer.SetMinSize((80, 20))
97                 if self._print_material_types is None:
98                         self.materialTypeCombo = None
99                 else:
100                         choices = self._print_material_types.keys()
101                         choices.sort(key=lambda type: sum([mat.order for mat in self._print_material_types[type]]))
102                         # Now we can add Others, so it appears towards the end
103                         if len(other_print_material_types) > 0:
104                                 self._print_material_types[_("Others")] = other_print_material_types
105                                 choices.append(_("Others"))
106                         choices.append(_("All"))
107                         label = wx.StaticText(self.printMaterialTypesPanel, label=_("Material ease of use:"))
108                         self.materialTypeCombo = wx.ComboBox(self.printMaterialTypesPanel, -1, selectedMaterialType,
109                                                                                                  choices=choices, style=wx.CB_READONLY)
110                         self.materialTypeCombo.Bind(wx.EVT_COMBOBOX, self._materialTypeSelected)
111                         boxsizer.Add(label, flag=wx.EXPAND)
112                         boxsizer.Add(self.materialTypeCombo, border=5, flag=wx.BOTTOM|wx.TOP|wx.EXPAND)
113                 self.printMaterialTypesPanel.SetSizer(boxsizer)
114                 sizer.Add(self.printMaterialTypesPanel, (0,0), border=10, flag=wx.EXPAND|wx.RIGHT|wx.LEFT|wx.TOP)
115
116                 if self._print_material_types is None:
117                         sb = wx.StaticBox(self.printMaterialPanel, label=_("Material:"))
118                         boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
119                         boxsizer.SetMinSize((80, 20))
120                         for button in self._print_material_options:
121                                 # wxpython 2.8 gives a 13 pixel high radio/checkbutton but wxpython 3.0
122                                 # gives it a 25 pixels height, so we add a border to compensate for the ugliness
123                                 if button.GetBestSize()[1] < 20:
124                                         border = 5
125                                 else:
126                                         border = 0
127                                 boxsizer.Add(button, border=border, flag=wx.ALL)
128                         self.printMaterialPanel.SetSizer(wx.BoxSizer(wx.VERTICAL))
129                         self.printMaterialPanel.GetSizer().Add(boxsizer, flag=wx.EXPAND)
130                         self.materialCombo = None
131                 else:
132                         boxsizer = wx.BoxSizer(wx.VERTICAL)
133                         boxsizer.SetMinSize((80, 20))
134                         label = wx.StaticText(self.printMaterialPanel, label=_("Material:"))
135                         self.materialCombo = wx.ComboBox(self.printMaterialPanel, -1, selectedMaterial.name,
136                                                                                          choices=[], style=wx.CB_READONLY)
137                         self.materialCombo.Bind(wx.EVT_COMBOBOX, self._materialSelected)
138                         boxsizer.Add(label, flag=wx.EXPAND)
139                         boxsizer.Add(self.materialCombo, border=5, flag=wx.BOTTOM|wx.TOP|wx.EXPAND)
140                         self.printMaterialPanel.SetSizer(boxsizer)
141                 self.materialHyperlink = wx.HyperlinkCtrl(self.printMaterialPanel, -1, label=_('Material Information'), url='',
142                                                                                                   style=wx.HL_ALIGN_LEFT|wx.BORDER_NONE|wx.HL_CONTEXTMENU)
143                 self.materialHyperlink.Show(False)
144                 self.materialDescription = wx.StaticText(self.printMaterialPanel, -1, '')
145                 self.materialDescription.Show(False)
146                 boxsizer.Add(self.materialDescription, border=5, flag=wx.BOTTOM|wx.TOP|wx.EXPAND)
147                 boxsizer.Add(self.materialHyperlink, border=5, flag=wx.BOTTOM|wx.TOP|wx.EXPAND)
148                 sizer.Add(self.printMaterialPanel, (1,0), border=10, flag=wx.EXPAND|wx.RIGHT|wx.LEFT|wx.TOP)
149
150                 sb = wx.StaticBox(self.printTypePanel, label=_("Select a quickprint profile:"))
151                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
152                 boxsizer.SetMinSize((180, 20))
153                 self.printTypePanel.SetSizer(wx.BoxSizer(wx.VERTICAL))
154                 self.printTypePanel.GetSizer().Add(boxsizer, flag=wx.EXPAND)
155                 sizer.Add(self.printTypePanel, (2,0), border=10, flag=wx.EXPAND|wx.RIGHT|wx.LEFT|wx.TOP)
156
157
158                 self.printOptionsBox = wx.StaticBox(self, label=_("Other options:"))
159                 boxsizer = wx.StaticBoxSizer(self.printOptionsBox, wx.VERTICAL)
160                 boxsizer.SetMinSize((100, 20))
161                 sizer.Add(boxsizer, (3,0), border=10, flag=wx.EXPAND|wx.RIGHT|wx.LEFT|wx.TOP)
162                 self.printOptionsSizer = boxsizer
163
164                 if selectedMaterialType:
165                         self.materialTypeCombo.SetValue(selectedMaterialType)
166                         self._materialTypeSelected(None)
167                 if selectedMaterial:
168                         if self.materialCombo:
169                                 self.materialCombo.SetValue(selectedMaterial.name)
170                         else:
171                                 for button in self._print_material_options:
172                                         if button.profile == selectedMaterial:
173                                                 button.SetValue(True)
174                                                 break
175                 self._materialSelected(None)
176                 self.Layout()
177
178         def _materialTypeSelected(self, e):
179                 materialType = self.materialTypeCombo.GetValue()
180                 selection = self.materialTypeCombo.GetSelection()
181                 choices = []
182
183                 if selection >= len(self._print_material_types.keys()):
184                         materials = self._all_print_materials
185                         for material in materials:
186                                 choices.append(material.full_name)
187                 else:
188                         materials = self._print_material_types[materialType]
189                         for material in materials:
190                                 choices.append(material.name)
191
192                 # Decide on the default selected material
193                 selectedMaterial = None
194                 for material in materials:
195                         if material.default:
196                                 selectedMaterial = material
197                                 break
198
199                 if selectedMaterial is None and len(materials) > 0:
200                         selectedMaterial = materials[0]
201
202                 self.materialCombo.Clear()
203                 self.materialCombo.AppendItems(choices)
204                 if len(materials) == 0:
205                         self.printMaterialTypesPanel.Show(False)
206                 else:
207                         self.printMaterialTypesPanel.Show(True)
208                         self.materialCombo.SetValue(selectedMaterial.name)
209
210                 self.materialCombo.Layout()
211                 self.printMaterialPanel.Layout()
212                 self._materialSelected(e)
213
214         def _getSelectedMaterial(self):
215                 if self.materialCombo:
216                         materialType = self.materialTypeCombo.GetValue()
217                         selection = self.materialTypeCombo.GetSelection()
218
219                         if selection >= len(self._print_material_types.keys()):
220                                 materials = self._all_print_materials
221                         else:
222                                 materials = self._print_material_types[materialType]
223
224                         selection = self.materialCombo.GetSelection()
225
226                         # This is needed to avoid a wxpython 2.8 bug which returns -1
227                         # when the selection is made with SetValue
228                         if selection == -1:
229                                 material_name = self.materialCombo.GetValue()
230                                 for material in materials:
231                                         if material.name == material_name:
232                                                 return material
233
234                         return materials[selection]
235                 else:
236                         for button in self._print_material_options:
237                                 if button.GetValue():
238                                         return button.profile
239                         return None
240
241
242         def _materialSelected(self, e):
243                 material = self._getSelectedMaterial()
244
245                 # Delete profile options
246                 boxsizer = self.printTypePanel.GetSizer().GetItem(0).GetSizer()
247                 boxsizer.Clear(True)
248                 self._print_profile_options = []
249
250                 if material is None:
251                         self.printOptionsBox.Show(False)
252                         self.printTypePanel.Show(False)
253                         return
254                 self.printOptionsBox.Show(True)
255                 self.printTypePanel.Show(True)
256
257                 self.materialHyperlink.Show(material.url is not None)
258                 if material.url:
259                         self.materialHyperlink.SetURL(material.url)
260                 self.materialDescription.Show(material.description is not None)
261                 if material.description:
262                         self.materialDescription.SetLabel(material.description)
263
264                 # Add new profiles
265                 selectedProfile = None
266                 for print_profile in material.profiles:
267                         if print_profile.disabled:
268                                 continue
269                         button = wx.RadioButton(self.printTypePanel, -1, print_profile.name.replace('&', '&&'),
270                                                                         style=wx.RB_GROUP if len(self._print_profile_options) == 0 else 0)
271                         button.profile = print_profile
272                         self._print_profile_options.append(button)
273                         if profile.getProfileSetting('simpleModeProfile') == print_profile.name:
274                                 selectedProfile = button
275
276                 # Decide on the profile to be selected by default
277                 if selectedProfile is None:
278                         for button in self._print_profile_options:
279                                 if button.profile.default:
280                                         selectedProfile = button
281                                         break
282
283                 if selectedProfile is None and len(self._print_profile_options) > 0:
284                         selectedProfile = self._print_profile_options[0]
285
286                 # Decide if we show the profile panel or not
287                 if len(self._print_profile_options) < 2:
288                         self.printTypePanel.Show(len(self._print_profile_options) > 0 and \
289                                                                          self._print_profile_options[0].profile.always_visible)
290
291                 if selectedProfile:
292                         selectedProfile.SetValue(True)
293
294                 # Add profiles to the UI
295                 for button in self._print_profile_options:
296                         # wxpython 2.8 gives a 13 pixel high radio/checkbutton but wxpython 3.0
297                         # gives it a 25 pixels height, so we add a border to compensate for the ugliness
298                         if button.GetBestSize()[1] < 20:
299                                 border = 5
300                         else:
301                                 border = 0
302                         boxsizer.Add(button, border=border, flag=wx.ALL)
303                         button.Bind(wx.EVT_RADIOBUTTON, self._update)
304
305                 # Save current selected options
306                 selected_options = []
307                 deselected_options = []
308                 for button in self._print_other_options:
309                         if button.GetValue():
310                                 selected_options.append(button.profile.name)
311                         else:
312                                 deselected_options.append(button.profile.name)
313
314                 # Delete profile options
315                 boxsizer = self.printOptionsSizer
316                 boxsizer.Clear(True)
317                 self._print_other_options = []
318
319                 # Create new options
320                 for option in material.options:
321                         if option.disabled:
322                                 continue
323                         button = wx.CheckBox(self, -1, option.name.replace('&', '&&'))
324                         button.profile = option
325                         self._print_other_options.append(button)
326                         # Restore selection on similarly named options
327                         if option.name in selected_options or \
328                            ((not option.name in deselected_options) and option.default):
329                                 button.SetValue(True)
330
331                 # Decide if we show the profile panel or not
332                 # The always_visible doesn't make sense for options since they are checkboxes, and not radio buttons
333                 self.printOptionsBox.Show(len(self._print_other_options) > 0)
334
335                 # Add profiles to the UI
336                 for button in self._print_other_options:
337                         # wxpython 2.8 gives a 13 pixel high radio/checkbutton but wxpython 3.0
338                         # gives it a 25 pixels height, so we add a border to compensate for the ugliness
339                         if button.GetBestSize()[1] < 20:
340                                 border = 5
341                         else:
342                                 border = 0
343                         boxsizer.Add(button, border=border, flag=wx.ALL)
344                         button.Bind(wx.EVT_CHECKBOX, self._update)
345
346                 self.printTypePanel.Layout()
347                 self.Layout()
348                 self.GetParent().Fit()
349
350                 # Do not call the callback on the initial UI build
351                 if e is not None:
352                         self._update(e)
353
354         def _update(self, e):
355                 material = self._getSelectedMaterial()
356                 if material:
357                         profile.putProfileSetting('simpleModeMaterial', material.name)
358                 for button in self._print_profile_options:
359                         if button.GetValue():
360                                 profile.putProfileSetting('simpleModeProfile', button.profile.name)
361                 self._callback()
362
363         def getSettingOverrides(self):
364                 settings = {}
365                 for setting in profile.settingsList:
366                         if setting.isProfile() or setting.isAlteration():
367                                 settings[setting.getName()] = setting.getDefault()
368
369                 # Apply materials, profile, then options
370                 material = self._getSelectedMaterial()
371                 if material:
372                         settings.update(material.getProfileDict())
373                 for button in self._print_profile_options:
374                         if button.GetValue():
375                                 settings.update(button.profile.getProfileDict())
376                 for button in self._print_other_options:
377                         if button.GetValue():
378                                 settings.update(button.profile.getProfileDict())
379
380                 return settings
381
382         def updateProfileToControls(self):
383                 pass