comparison src/cagou/core/xmlui.py @ 69:a9c6b089070d

xmlui: improvments to prepare parameters: - added missing implementation: JidsListWidget (just a simple ListWidget for now), IntWidget, TabsContainer - _xmluiOnChange implemented for StringWidget, PasswordWidget, IntWidget and BoolWidget - added post treatment handling, as it is needed to adjust TabsContainer height - a "save" button is added on params
author Goffi <goffi@goffi.org>
date Sun, 18 Dec 2016 10:24:29 +0100
parents b0011c6dc7dc
children 8c9fe2c5aacc
comparison
equal deleted inserted replaced
68:4a1e1012337e 69:a9c6b089070d
22 from sat.core.log import getLogger 22 from sat.core.log import getLogger
23 log = getLogger(__name__) 23 log = getLogger(__name__)
24 from sat_frontends.tools import xmlui 24 from sat_frontends.tools import xmlui
25 from kivy.uix.scrollview import ScrollView 25 from kivy.uix.scrollview import ScrollView
26 from kivy.uix.gridlayout import GridLayout 26 from kivy.uix.gridlayout import GridLayout
27 from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
27 from kivy.uix.textinput import TextInput 28 from kivy.uix.textinput import TextInput
28 from kivy.uix.label import Label 29 from kivy.uix.label import Label
29 from kivy.uix.button import Button 30 from kivy.uix.button import Button
30 from kivy.uix.togglebutton import ToggleButton 31 from kivy.uix.togglebutton import ToggleButton
31 from kivy.uix.widget import Widget 32 from kivy.uix.widget import Widget
36 37
37 38
38 ## Widgets ## 39 ## Widgets ##
39 40
40 41
42 class TextInputOnChange(object):
43
44 def __init__(self):
45 self._xmlui_onchange_cb = None
46 self._got_focus = False
47
48 def _xmluiOnChange(self, callback):
49 self._xmlui_onchange_cb = callback
50
51 def on_focus(self, instance, focus):
52 # we need to wait for first focus, else initial value
53 # will trigger a on_text
54 if not self._got_focus and focus:
55 self._got_focus = True
56
57 def on_text(self, instance, new_text):
58 log.debug("on_text: %s" % new_text)
59 if self._xmlui_onchange_cb is not None and self._got_focus:
60 self._xmlui_onchange_cb(self)
61
62
41 class EmptyWidget(xmlui.EmptyWidget, Widget): 63 class EmptyWidget(xmlui.EmptyWidget, Widget):
42 64
43 def __init__(self, _xmlui_parent): 65 def __init__(self, _xmlui_parent):
44 Widget.__init__(self) 66 Widget.__init__(self)
45 67
56 78
57 class JidWidget(xmlui.JidWidget, TextWidget): 79 class JidWidget(xmlui.JidWidget, TextWidget):
58 pass 80 pass
59 81
60 82
61 class StringWidget(xmlui.StringWidget, TextInput): 83 class StringWidget(xmlui.StringWidget, TextInput, TextInputOnChange):
62 84
63 def __init__(self, xmlui_parent, value, read_only=False): 85 def __init__(self, xmlui_parent, value, read_only=False):
64 TextInput.__init__(self, text=value, multiline=False) 86 TextInput.__init__(self, text=value, multiline=False)
87 TextInputOnChange.__init__(self)
65 self.readonly = read_only 88 self.readonly = read_only
66 89
67 def _xmluiSetValue(self, value): 90 def _xmluiSetValue(self, value):
68 self.text = value 91 self.text = value
69 92
192 215
193 def _xmluiOnChange(self, callback): 216 def _xmluiOnChange(self, callback):
194 self._on_change = callback 217 self._on_change = callback
195 218
196 219
197 class PasswordWidget(xmlui.PasswordWidget, TextInput): 220 class JidsListWidget(ListWidget):
221 # TODO: real list dedicated to jids
222
223 def __init__(self, _xmlui_parent, jids, flags):
224 ListWidget.__init__(self, _xmlui_parent, [(j,j) for j in jids], [], flags)
225
226
227 class PasswordWidget(xmlui.PasswordWidget, TextInput, TextInputOnChange):
198 228
199 def __init__(self, _xmlui_parent, value, read_only=False): 229 def __init__(self, _xmlui_parent, value, read_only=False):
200 TextInput.__init__(self, password=True, multiline=False, 230 TextInput.__init__(self, password=True, multiline=False,
201 text=value, readonly=read_only, size=(100,25), size_hint=(1,None)) 231 text=value, readonly=read_only, size=(100,25), size_hint=(1,None))
232 TextInputOnChange.__init__(self)
202 233
203 def _xmluiSetValue(self, value): 234 def _xmluiSetValue(self, value):
204 self.text = value 235 self.text = value
205 236
206 def _xmluiGetValue(self): 237 def _xmluiGetValue(self):
218 self.active = value 249 self.active = value
219 250
220 def _xmluiGetValue(self): 251 def _xmluiGetValue(self):
221 return self.active 252 return self.active
222 253
254 def _xmluiOnChange(self, callback):
255 self.bind(active=lambda instance, value: callback(instance))
256
257
258 class IntWidget(xmlui.IntWidget, TextInput, TextInputOnChange):
259
260 def __init__(self, _xmlui_parent, value, read_only=False):
261 TextInput.__init__(self, text=value, input_filter='int', multiline=False)
262 TextInputOnChange.__init__(self)
263 if read_only:
264 self.disabled = True
265
266 def _xmluiSetValue(self, value):
267 self.text = value
268
269 def _xmluiGetValue(self):
270 return self.text
271
223 272
224 ## Containers ## 273 ## Containers ##
225 274
226 275
227 class VerticalContainer(xmlui.VerticalContainer, GridLayout): 276 class VerticalContainer(xmlui.VerticalContainer, GridLayout):
228 277
229 def __init__(self, xmlui_parent): 278 def __init__(self, xmlui_parent):
279 self.xmlui_parent = xmlui_parent
230 GridLayout.__init__(self) 280 GridLayout.__init__(self)
231 281
232 def _xmluiAppend(self, widget): 282 def _xmluiAppend(self, widget):
233 self.add_widget(widget) 283 self.add_widget(widget)
234 284
235 285
236 class PairsContainer(xmlui.PairsContainer, GridLayout): 286 class PairsContainer(xmlui.PairsContainer, GridLayout):
237 287
238 def __init__(self, xmlui_parent): 288 def __init__(self, xmlui_parent):
289 self.xmlui_parent = xmlui_parent
239 GridLayout.__init__(self) 290 GridLayout.__init__(self)
240 291
241 def _xmluiAppend(self, widget): 292 def _xmluiAppend(self, widget):
242 self.add_widget(widget) 293 self.add_widget(widget)
294
295
296 class TabsPanelContainer(TabbedPanelItem):
297
298 def _xmluiAppend(self, widget):
299 self.add_widget(widget)
300
301
302 class TabsContainer(xmlui.TabsContainer, TabbedPanel):
303
304 def __init__(self, xmlui_parent):
305 self.xmlui_parent = xmlui_parent
306 xmlui_panel = xmlui_parent
307 while not isinstance(xmlui_panel, XMLUIPanel):
308 xmlui_panel = xmlui_panel.xmlui_parent
309 xmlui_panel.addPostTreat(self._postTreat)
310 TabbedPanel.__init__(self, do_default_tab=False)
311
312 def _xmluiAddTab(self, label, selected):
313 tab = TabsPanelContainer(text=label)
314 self.add_widget(tab)
315 return tab
316
317 def _postTreat(self):
318 """bind minimum height of tabs' content so self.height is adapted"""
319 # we need to do this in postTreat because contents exists after UI construction
320 for t in self.tab_list:
321 t.content.bind(minimum_height=self._updateHeight)
322
323 def _updateHeight(self, instance, height):
324 """Called after UI is constructed (so height can be calculated)"""
325 # needed because TabbedPanel doesn't have a minimum_height property
326 self.height = max([t.content.minimum_height for t in self.tab_list]) + self.tab_height + 5
243 327
244 328
245 class AdvancedListRow(GridLayout): 329 class AdvancedListRow(GridLayout):
246 global_index = 0 330 global_index = 0
247 index = properties.ObjectProperty() 331 index = properties.ObjectProperty()
266 return super(AdvancedListRow, self).on_touch_down(touch) 350 return super(AdvancedListRow, self).on_touch_down(touch)
267 351
268 352
269 class AdvancedListContainer(xmlui.AdvancedListContainer, GridLayout): 353 class AdvancedListContainer(xmlui.AdvancedListContainer, GridLayout):
270 354
271 def __init__(self, _xmlui_parent, columns, selectable='no'): 355 def __init__(self, xmlui_parent, columns, selectable='no'):
356 self.xmlui_parent = xmlui_parent
272 GridLayout.__init__(self) 357 GridLayout.__init__(self)
273 self._columns = columns 358 self._columns = columns
274 self.selectable = selectable != 'no' 359 self.selectable = selectable != 'no'
275 self._current_row = None 360 self._current_row = None
276 self._selected = [] 361 self._selected = []
363 448
364 def __init__(self, host, parsed_xml, title=None, flags=None, callback=None, profile=C.PROF_KEY_NONE): 449 def __init__(self, host, parsed_xml, title=None, flags=None, callback=None, profile=C.PROF_KEY_NONE):
365 ScrollView.__init__(self) 450 ScrollView.__init__(self)
366 self.close_cb = None 451 self.close_cb = None
367 self._grid = XMLUIPanelGrid() 452 self._grid = XMLUIPanelGrid()
453 self._post_treats = [] # list of callback to call after UI is constructed
368 ScrollView.add_widget(self, self._grid) 454 ScrollView.add_widget(self, self._grid)
369 xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags, callback, profile) 455 xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags, callback, profile)
370 456
371 def add_widget(self, wid): 457 def add_widget(self, wid):
372 self._grid.add_widget(wid) 458 self._grid.add_widget(wid)
378 if self.close_cb is not None: 464 if self.close_cb is not None:
379 self.close_cb(self) 465 self.close_cb(self)
380 else: 466 else:
381 G.host.closeUI() 467 G.host.closeUI()
382 468
469 def addPostTreat(self, callback):
470 self._post_treats.append(callback)
471
472 def _postTreatCb(self):
473 for cb in self._post_treats:
474 cb()
475 del self._post_treats
476
383 def constructUI(self, parsed_dom): 477 def constructUI(self, parsed_dom):
384 xmlui.XMLUIPanel.constructUI(self, parsed_dom) 478 xmlui.XMLUIPanel.constructUI(self, parsed_dom, self._postTreatCb)
385 if self.xmlui_title: 479 if self.xmlui_title:
386 self.add_widget(Title(text=self.xmlui_title)) 480 self.add_widget(Title(text=self.xmlui_title))
387 self.add_widget(self.main_cont) 481 self.add_widget(self.main_cont)
388 if self.type == 'form': 482 if self.type == 'form':
389 submit_btn = FormButton(text=_(u"Submit")) 483 submit_btn = FormButton(text=_(u"Submit"))
391 self.add_widget(submit_btn) 485 self.add_widget(submit_btn)
392 if not 'NO_CANCEL' in self.flags: 486 if not 'NO_CANCEL' in self.flags:
393 cancel_btn = FormButton(text=_(u"Cancel")) 487 cancel_btn = FormButton(text=_(u"Cancel"))
394 cancel_btn.bind(on_press=self.onFormCancelled) 488 cancel_btn.bind(on_press=self.onFormCancelled)
395 self.add_widget(cancel_btn) 489 self.add_widget(cancel_btn)
490 elif self.type == 'param':
491 save_btn = FormButton(text=_(u"Save"))
492 save_btn.bind(on_press=self.onSaveParams)
493 self.add_widget(save_btn)
396 self.add_widget(Widget()) # to have elements on the top 494 self.add_widget(Widget()) # to have elements on the top
397 495
398 def show(self, *args, **kwargs): 496 def show(self, *args, **kwargs):
399 if not self.user_action and not kwargs.get("force", False): 497 if not self.user_action and not kwargs.get("force", False):
400 G.host.addNotifUI(self) 498 G.host.addNotifUI(self)