Mercurial > libervia-desktop-kivy
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) |