chiark / gitweb /
Merge tag '15.01-RC1' into upstream
[cura.git] / Cura / gui / configBase.py
1 from __future__ import division
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
3
4 import wx, wx.lib.stattext, types
5 from wx.lib.agw import floatspin
6
7 from Cura.util import validators
8 from Cura.util import profile
9
10 class configPanelBase(wx.Panel):
11         "A base class for configuration dialogs. Handles creation of settings, and popups"
12         def __init__(self, parent, changeCallback = None):
13                 super(configPanelBase, self).__init__(parent)
14                 
15                 self.settingControlList = []
16
17                 self._callback = changeCallback
18         
19         def CreateConfigTab(self, nb, name):
20                 leftConfigPanel, rightConfigPanel, configPanel = self.CreateConfigPanel(nb)
21                 nb.AddPage(configPanel, name)
22                 return leftConfigPanel, rightConfigPanel
23         
24         def CreateConfigPanel(self, parent):
25                 configPanel = wx.Panel(parent)
26                 leftConfigPanel = wx.Panel(configPanel)
27                 rightConfigPanel = wx.Panel(configPanel)
28
29                 sizer = wx.GridBagSizer(2, 2)
30                 leftConfigPanel.SetSizer(sizer)
31                 sizer = wx.GridBagSizer(2, 2)
32                 rightConfigPanel.SetSizer(sizer)
33
34                 sizer = wx.BoxSizer(wx.HORIZONTAL)
35                 configPanel.SetSizer(sizer)
36                 sizer.Add(leftConfigPanel, border=35, flag=wx.RIGHT)
37                 sizer.Add(rightConfigPanel)
38                 leftConfigPanel.main = self
39                 rightConfigPanel.main = self
40                 return leftConfigPanel, rightConfigPanel, configPanel
41
42         def CreateDynamicConfigTab(self, nb, name):
43                 configPanel = wx.lib.scrolledpanel.ScrolledPanel(nb)    
44                 #configPanel = wx.Panel(nb);
45                 leftConfigPanel = wx.Panel(configPanel)
46                 rightConfigPanel = wx.Panel(configPanel)
47
48                 sizer = wx.GridBagSizer(2, 2)
49                 leftConfigPanel.SetSizer(sizer)
50                 #sizer.AddGrowableCol(1)
51
52                 sizer = wx.GridBagSizer(2, 2)
53                 rightConfigPanel.SetSizer(sizer)
54                 #sizer.AddGrowableCol(1)
55
56                 sizer = wx.BoxSizer(wx.HORIZONTAL)
57                 sizer.Add(leftConfigPanel, proportion=1, border=35, flag=wx.EXPAND)
58                 sizer.Add(rightConfigPanel, proportion=1, flag=wx.EXPAND)
59                 configPanel.SetSizer(sizer)
60
61                 configPanel.SetAutoLayout(1)
62                 configPanel.SetupScrolling(scroll_x=False, scroll_y=True)
63
64                 leftConfigPanel.main = self
65                 rightConfigPanel.main = self
66
67                 configPanel.leftPanel = leftConfigPanel
68                 configPanel.rightPanel = rightConfigPanel
69
70                 nb.AddPage(configPanel, name)
71
72                 return leftConfigPanel, rightConfigPanel, configPanel
73     
74         def updateProfileToControls(self):
75                 "Update the configuration wx controls to show the new configuration settings"
76                 for setting in self.settingControlList:
77                         setting.SetValue(setting.setting.getValue())
78                 self.Update()
79
80         def _validate(self):
81                 for setting in self.settingControlList:
82                         setting._validate()
83                 if self._callback is not None:
84                         self._callback()
85
86         def getLabelColumnWidth(self, panel):
87                 maxWidth = 0
88                 for child in panel.GetChildren():
89                         if isinstance(child, wx.lib.stattext.GenStaticText):
90                                 maxWidth = max(maxWidth, child.GetSize()[0])
91                 return maxWidth
92         
93         def setLabelColumnWidth(self, panel, width):
94                 for child in panel.GetChildren():
95                         if isinstance(child, wx.lib.stattext.GenStaticText):
96                                 size = child.GetSize()
97                                 size[0] = width
98                                 child.SetBestSize(size)
99         
100 class TitleRow(object):
101         def __init__(self, panel, name):
102                 "Add a title row to the configuration panel"
103                 sizer = panel.GetSizer()
104                 x = sizer.GetRows()
105                 self.title = wx.StaticText(panel, -1, name.replace('&', '&&'))
106                 self.title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
107                 sizer.Add(self.title, (x,0), (1,3), flag=wx.EXPAND|wx.TOP|wx.LEFT, border=10)
108                 sizer.Add(wx.StaticLine(panel), (x+1,0), (1,4), flag=wx.EXPAND|wx.LEFT,border=10)
109                 sizer.SetRows(x + 2)
110
111 class SettingRow(object):
112         def __init__(self, panel, configName, valueOverride = None, index = None):
113                 "Add a setting to the configuration panel"
114                 sizer = panel.GetSizer()
115                 x = sizer.GetRows()
116                 y = 0
117                 flag = 0
118                 has_expert_settings = False
119
120                 self.setting = profile.settingsDictionary[configName]
121                 self.settingIndex = index
122                 self.validationMsg = ''
123                 self.panel = panel
124
125                 self.label = wx.lib.stattext.GenStaticText(panel, -1, self.setting.getLabel())
126                 self.label.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
127
128                 #if self.setting.getType() is types.FloatType and False:
129                 #       digits = 0
130                 #       while 1 / pow(10, digits) > defaultValue:
131                 #               digits += 1
132                 #       self.ctrl = floatspin.FloatSpin(panel, -1, value=float(getSettingFunc(configName)), increment=defaultValue, digits=digits, min_val=0.0)
133                 #       self.ctrl.Bind(floatspin.EVT_FLOATSPIN, self.OnSettingChange)
134                 #       flag = wx.EXPAND
135                 if self.setting.getType() is types.BooleanType:
136                         self.ctrl = wx.CheckBox(panel, -1, style=wx.ALIGN_RIGHT)
137                         self.SetValue(self.setting.getValue(self.settingIndex))
138                         self.ctrl.Bind(wx.EVT_CHECKBOX, self.OnSettingChange)
139                 elif valueOverride is not None and valueOverride is wx.Colour:
140                         self.ctrl = wx.ColourPickerCtrl(panel, -1)
141                         self.SetValue(self.setting.getValue(self.settingIndex))
142                         self.ctrl.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnSettingChange)
143                 elif type(self.setting.getType()) is list or valueOverride is not None:
144                         value = self.setting.getValue(self.settingIndex)
145                         choices = self.setting.getType()
146                         if valueOverride is not None:
147                                 choices = valueOverride
148                         choices = choices[:]
149                         self._englishChoices = choices[:]
150                         if value not in choices and len(choices) > 0:
151                                 value = choices[0]
152                         for n in xrange(0, len(choices)):
153                                 choices[n] = _(choices[n])
154                         value = _(value)
155                         self.ctrl = wx.ComboBox(panel, -1, value, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY)
156                         self.ctrl.Bind(wx.EVT_COMBOBOX, self.OnSettingChange)
157                         self.ctrl.Bind(wx.EVT_LEFT_DOWN, self.OnMouseExit)
158                         flag = wx.EXPAND
159                 else:
160                         self.ctrl = wx.TextCtrl(panel, -1, self.setting.getValue(self.settingIndex))
161                         self.ctrl.Bind(wx.EVT_TEXT, self.OnSettingChange)
162                         flag = wx.EXPAND
163
164                 self.ctrl.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
165                 sizer.Add(self.label, (x,y), flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT,border=10)
166                 sizer.Add(self.ctrl, (x,y+1), flag=wx.ALIGN_CENTER_VERTICAL|flag)
167                 if self.setting.getExpertSubCategory() is not None:
168                         self._expert_button = wx.Button(panel, -1, '...', style=wx.BU_EXACTFIT)
169                         self._expert_button.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize() * 0.8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_NORMAL))
170                         self._expert_button.Bind(wx.EVT_BUTTON, self.OnExpertOpen)
171                         sizer.Add(self._expert_button, (x,y+2), flag=wx.ALIGN_CENTER_VERTICAL)
172                 sizer.SetRows(x+1)
173
174                 self.ctrl.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
175                 if isinstance(self.ctrl, floatspin.FloatSpin):
176                         self.ctrl.GetTextCtrl().Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
177                         self.defaultBGColour = self.ctrl.GetTextCtrl().GetBackgroundColour()
178                 else:
179                         self.defaultBGColour = self.ctrl.GetBackgroundColour()
180                 
181                 panel.main.settingControlList.append(self)
182
183         def OnMouseEnter(self, e):
184                 self.label.SetToolTipString(self.setting.getTooltip())
185                 self.ctrl.SetToolTipString(self.setting.getTooltip())
186
187         def OnMouseExit(self, e):
188                 self.label.SetToolTipString('')
189                 self.ctrl.SetToolTipString('')
190                 e.Skip()
191
192         def OnSettingChange(self, e):
193                 self.setting.setValue(self.GetValue(), self.settingIndex)
194                 self.panel.main._validate()
195
196         def OnExpertOpen(self, e):
197                 from Cura.gui import expertConfig
198
199                 expert_sub_category = self.setting.getExpertSubCategory()
200                 if type(expert_sub_category) is list:
201                         expert_sub_category = expert_sub_category[self.ctrl.GetSelection()]
202                 ecw = expertConfig.expertConfigWindow(self.panel.main._callback, expert_sub_category)
203                 ecw.Centre()
204                 ecw.Show()
205
206         def _validate(self):
207                 if type(self.setting.getExpertSubCategory()) is list:
208                         self._expert_button.Enable(self.setting.getExpertSubCategory()[self.ctrl.GetSelection()] is not None)
209                 result, msg = self.setting.validate()
210
211                 ctrl = self.ctrl
212                 if isinstance(ctrl, floatspin.FloatSpin):
213                         ctrl = ctrl.GetTextCtrl()
214                 if result == validators.ERROR:
215                         ctrl.SetBackgroundColour('Red')
216                 elif result == validators.WARNING:
217                         ctrl.SetBackgroundColour('Yellow')
218                 else:
219                         ctrl.SetBackgroundColour(self.defaultBGColour)
220                 ctrl.Refresh()
221
222                 self.validationMsg = msg
223
224         def GetValue(self):
225                 if isinstance(self.ctrl, wx.ColourPickerCtrl):
226                         return str(self.ctrl.GetColour().GetAsString(wx.C2S_HTML_SYNTAX))
227                 elif isinstance(self.ctrl, wx.ComboBox):
228                         value = unicode(self.ctrl.GetValue())
229                         for ret in self._englishChoices:
230                                 if _(ret) == value:
231                                         return ret
232                         return value
233                 else:
234                         return str(self.ctrl.GetValue())
235
236         def SetValue(self, value):
237                 if isinstance(self.ctrl, wx.CheckBox):
238                         self.ctrl.SetValue(str(value) == "True")
239                 elif isinstance(self.ctrl, wx.ColourPickerCtrl):
240                         self.ctrl.SetColour(value)
241                 elif isinstance(self.ctrl, floatspin.FloatSpin):
242                         try:
243                                 self.ctrl.SetValue(float(value))
244                         except ValueError:
245                                 pass
246                 elif isinstance(self.ctrl, wx.ComboBox):
247                         self.ctrl.SetValue(_(value))
248                 else:
249                         self.ctrl.SetValue(value)