chiark / gitweb /
Merge pull request #349 from smorloc/master
[cura.git] / Cura / gui / configBase.py
1 from __future__ import absolute_import
2 from __future__ import division
3
4 import platform
5 import wx, wx.lib.stattext, types
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):
13                 super(configPanelBase, self).__init__(parent)
14                 
15                 self.settingControlList = []
16                 
17                 #Create the popup window
18                 self.popup = wx.PopupWindow(self, flags=wx.BORDER_SIMPLE)
19                 self.popup.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK))
20                 self.popup.setting = None
21                 self.popup.text = wx.StaticText(self.popup, -1, '');
22                 self.popup.sizer = wx.BoxSizer()
23                 self.popup.sizer.Add(self.popup.text, flag=wx.EXPAND|wx.ALL, border=1)
24                 self.popup.SetSizer(self.popup.sizer)
25         
26         def CreateConfigTab(self, nb, name):
27                 leftConfigPanel, rightConfigPanel, configPanel = self.CreateConfigPanel(nb)
28                 nb.AddPage(configPanel, name)
29                 return leftConfigPanel, rightConfigPanel
30         
31         def CreateConfigPanel(self, parent):
32                 configPanel = wx.Panel(parent);
33                 leftConfigPanel = wx.Panel(configPanel)
34                 rightConfigPanel = wx.Panel(configPanel)
35
36                 sizer = wx.GridBagSizer(2, 2)
37                 leftConfigPanel.SetSizer(sizer)
38                 sizer = wx.GridBagSizer(2, 2)
39                 rightConfigPanel.SetSizer(sizer)
40
41                 sizer = wx.BoxSizer(wx.HORIZONTAL)
42                 configPanel.SetSizer(sizer)
43                 sizer.Add(leftConfigPanel, border=35, flag=wx.RIGHT)
44                 sizer.Add(rightConfigPanel)
45                 leftConfigPanel.main = self
46                 rightConfigPanel.main = self
47                 return leftConfigPanel, rightConfigPanel, configPanel
48
49         def CreateDynamicConfigTab(self, nb, name):
50                 configPanel = wx.lib.scrolledpanel.ScrolledPanel(nb)    
51                 #configPanel = wx.Panel(nb);
52                 leftConfigPanel = wx.Panel(configPanel)
53                 rightConfigPanel = wx.Panel(configPanel)
54
55                 sizer = wx.GridBagSizer(2, 2)
56                 leftConfigPanel.SetSizer(sizer)
57                 sizer.AddGrowableCol(1)
58
59                 sizer = wx.GridBagSizer(2, 2)
60                 rightConfigPanel.SetSizer(sizer)
61                 sizer.AddGrowableCol(1)
62
63                 sizer = wx.BoxSizer(wx.HORIZONTAL)
64                 sizer.Add(leftConfigPanel, proportion=1, border=35, flag=wx.EXPAND)
65                 sizer.Add(rightConfigPanel, proportion=1, flag=wx.EXPAND)
66                 configPanel.SetSizer(sizer)
67
68                 configPanel.SetAutoLayout(1)
69                 configPanel.SetupScrolling(scroll_x=False, scroll_y=True)
70
71                 leftConfigPanel.main = self
72                 rightConfigPanel.main = self
73
74                 configPanel.leftPanel = leftConfigPanel
75                 configPanel.rightPanel = rightConfigPanel
76
77                 nb.AddPage(configPanel, name)
78
79                 return leftConfigPanel, rightConfigPanel, configPanel
80
81         def OnPopupDisplay(self, setting):
82                 self.popup.setting = setting
83                 self.UpdatePopup(setting)
84                 self.popup.Show(True)
85                 
86         def OnPopupHide(self, e):
87                 self.popup.Show(False)
88         
89         def UpdatePopup(self, setting):
90                 if self.popup.setting == setting:
91                         if setting.validationMsg != '':
92                                 self.popup.text.SetLabel(setting.validationMsg + '\n\n' + setting.helpText)
93                         else:
94                                 self.popup.text.SetLabel(setting.helpText)
95                         self.popup.text.Wrap(350)
96                         self.popup.Fit()
97                         x, y = setting.ctrl.ClientToScreenXY(0, 0)
98                         sx, sy = setting.ctrl.GetSizeTuple()
99                         #if platform.system() == "Windows":
100                         #       for some reason, under windows, the popup is relative to the main window... in some cases. (Wierd ass bug)
101                         #       wx, wy = self.ClientToScreenXY(0, 0)
102                         #       x -= wx
103                         #       y -= wy
104                         self.popup.SetPosition((x, y+sy))
105         
106         def updateProfileToControls(self):
107                 "Update the configuration wx controls to show the new configuration settings"
108                 for setting in self.settingControlList:
109                         if setting.type == 'profile':
110                                 setting.SetValue(profile.getProfileSetting(setting.configName))
111                         else:
112                                 setting.SetValue(profile.getPreference(setting.configName))
113                 self.Update()
114
115         def getLabelColumnWidth(self, panel):
116                 maxWidth = 0
117                 for child in panel.GetChildren():
118                         if isinstance(child, wx.lib.stattext.GenStaticText):
119                                 maxWidth = max(maxWidth, child.GetSize()[0])
120                 return maxWidth
121         
122         def setLabelColumnWidth(self, panel, width):
123                 for child in panel.GetChildren():
124                         if isinstance(child, wx.lib.stattext.GenStaticText):
125                                 size = child.GetSize()
126                                 size[0] = width
127                                 child.SetBestSize(size)
128         
129 class TitleRow():
130         def __init__(self, panel, name):
131                 "Add a title row to the configuration panel"
132                 sizer = panel.GetSizer()
133                 x = sizer.GetRows()
134                 self.title = wx.StaticText(panel, -1, name)
135                 self.title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
136                 sizer.Add(self.title, (x,0), (1,3), flag=wx.EXPAND|wx.TOP|wx.LEFT, border=10)
137                 sizer.Add(wx.StaticLine(panel), (x+1,0), (1,3), flag=wx.EXPAND|wx.LEFT,border=10)
138                 sizer.SetRows(x + 2)
139
140 class SettingRow():
141         def __init__(self, panel, label, configName, defaultValue = '', helpText = 'Help: TODO', type = 'profile'):
142                 "Add a setting to the configuration panel"
143                 sizer = panel.GetSizer()
144                 x = sizer.GetRows()
145                 y = 0
146                 flag = 0
147                 
148                 self.validators = []
149                 self.validationMsg = ''
150                 self.helpText = helpText
151                 self.configName = configName
152                 self.panel = panel
153                 self.type = type
154
155                 self.label = wx.lib.stattext.GenStaticText(panel, -1, label)
156                 self.label.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
157                 self.label.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseExit)
158
159                 getSettingFunc = profile.getPreference
160                 if self.type == 'profile':
161                         getSettingFunc = profile.getProfileSetting
162                 if isinstance(defaultValue, types.StringTypes):
163                         self.ctrl = wx.TextCtrl(panel, -1, getSettingFunc(configName))
164                         self.ctrl.Bind(wx.EVT_TEXT, self.OnSettingChange)
165                         flag = wx.EXPAND
166                 elif isinstance(defaultValue, types.BooleanType):
167                         self.ctrl = wx.CheckBox(panel, -1, style=wx.ALIGN_RIGHT)
168                         self.SetValue(getSettingFunc(configName))
169                         self.ctrl.Bind(wx.EVT_CHECKBOX, self.OnSettingChange)
170                 elif isinstance(defaultValue, wx.Colour):
171                         self.ctrl = wx.ColourPickerCtrl(panel, -1)
172                         self.SetValue(getSettingFunc(configName))
173                         self.ctrl.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnSettingChange)
174                 else:
175                         self.ctrl = wx.ComboBox(panel, -1, getSettingFunc(configName), choices=defaultValue, style=wx.CB_DROPDOWN|wx.CB_READONLY)
176                         self.ctrl.Bind(wx.EVT_COMBOBOX, self.OnSettingChange)
177                         self.ctrl.Bind(wx.EVT_LEFT_DOWN, self.OnMouseExit)
178                         flag = wx.EXPAND
179
180                 # Set the minimum size of control to something other than the humungous default
181                 minSize = self.ctrl.GetMinSize()
182                 
183                 ##if platform.system() == "Darwin":
184                 ##      # Under MacOS, it appears that the minSize is used for the actual size, so give the field a bit more room...
185                 ##      minSize[0] = 150
186                 ##else:
187                 ##      minSize[0] = 50
188                 ##self.ctrl.SetMinSize(minSize)
189                 
190                 sizer.Add(self.label, (x,y), flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT,border=10)
191                 sizer.Add(self.ctrl, (x,y+1), flag=wx.ALIGN_BOTTOM|flag)
192                 sizer.SetRows(x+1)
193
194                 self.ctrl.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
195                 self.ctrl.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseExit)
196                 
197                 self.defaultBGColour = self.ctrl.GetBackgroundColour()
198                 
199                 panel.main.settingControlList.append(self)
200
201         def OnMouseEnter(self, e):
202                 self.panel.main.OnPopupDisplay(self)
203
204         def OnMouseExit(self, e):
205                 self.panel.main.OnPopupHide(self)
206                 e.Skip()
207
208         def OnSettingChange(self, e):
209                 if self.type == 'profile':
210                         profile.putProfileSetting(self.configName, self.GetValue())
211                 else:
212                         profile.putPreference(self.configName, self.GetValue())
213                 result = validators.SUCCESS
214                 msgs = []
215                 for validator in self.validators:
216                         res, err = validator.validate()
217                         if res == validators.ERROR:
218                                 result = res
219                         elif res == validators.WARNING and result != validators.ERROR:
220                                 result = res
221                         if res != validators.SUCCESS:
222                                 msgs.append(err)
223                 if result == validators.ERROR:
224                         self.ctrl.SetBackgroundColour('Red')
225                 elif result == validators.WARNING:
226                         self.ctrl.SetBackgroundColour('Yellow')
227                 else:
228                         self.ctrl.SetBackgroundColour(self.defaultBGColour)
229                 self.ctrl.Refresh()
230
231                 self.validationMsg = '\n'.join(msgs)
232                 self.panel.main.UpdatePopup(self)
233
234         def GetValue(self):
235                 if isinstance(self.ctrl, wx.ColourPickerCtrl):
236                         return str(self.ctrl.GetColour().GetAsString(wx.C2S_HTML_SYNTAX))
237                 else:
238                         return str(self.ctrl.GetValue())
239
240         def SetValue(self, value):
241                 if isinstance(self.ctrl, wx.CheckBox):
242                         self.ctrl.SetValue(str(value) == "True")
243                 elif isinstance(self.ctrl, wx.ColourPickerCtrl):
244                         self.ctrl.SetColour(value)
245                 else:
246                         self.ctrl.SetValue(value)
247
248 #Settings notify works as a validator, but instead of validating anything, it calls another function, which can use the value.
249 # A bit hacky, bit it works.
250 class settingNotify():
251         def __init__(self, setting, func):
252                 self.setting = setting
253                 self.setting.validators.append(self)
254                 self.func = func
255         
256         def validate(self):
257                 self.func()
258                 return validators.SUCCESS, ''
259