comparison cagou/core/xmlui.py @ 286:4772ba26623f

xmlui: many improvments: - use a white background to be coherent with the rest of the UI - cancel button is added on "window" XMLUIs - use color for submit/save buttons - VerticalContainer is not a ScrollView anymore, XMLUIPanel now has the main ScrollView - when a TabsContainer is used as main container, main XMLUIPanel ScrollView touch events are disabled, to improve user experience (Kivy doesn't support well ScrollView inside an other ScrollView) - use BoxLayout instead of GridLayout in AdvancedList*, as they use one row/col only - fixed DividerWidget line location - added margins in XMLUI panels - renamed Settings main class to CagouSettings, to avoid conflict with Kivy's Settings class (which is causing troubles with kv)
author Goffi <goffi@goffi.org>
date Wed, 27 Mar 2019 22:22:51 +0100
parents 1b835bcfa663
children b2727877bad4
comparison
equal deleted inserted replaced
285:3f7e227aab00 286:4772ba26623f
255 255
256 256
257 ## Containers ## 257 ## Containers ##
258 258
259 259
260 class VerticalContainer(xmlui.VerticalContainer, ScrollView): 260 class VerticalContainer(xmlui.VerticalContainer, BoxLayout):
261 layout = properties.ObjectProperty(None)
262 261
263 def __init__(self, xmlui_parent): 262 def __init__(self, xmlui_parent):
264 self.xmlui_parent = xmlui_parent 263 self.xmlui_parent = xmlui_parent
265 ScrollView.__init__(self) 264 BoxLayout.__init__(self)
266 265
267 def _xmluiAppend(self, widget): 266 def _xmluiAppend(self, widget):
268 self.layout.add_widget(widget) 267 self.add_widget(widget)
269 268
270 269
271 class PairsContainer(xmlui.PairsContainer, GridLayout): 270 class PairsContainer(xmlui.PairsContainer, GridLayout):
272 271
273 def __init__(self, xmlui_parent): 272 def __init__(self, xmlui_parent):
299 tab = TabsPanelContainer(text=label) 298 tab = TabsPanelContainer(text=label)
300 self.add_widget(tab) 299 self.add_widget(tab)
301 return tab 300 return tab
302 301
303 302
304 class AdvancedListRow(GridLayout): 303 class AdvancedListRow(BoxLayout):
305 global_index = 0 304 global_index = 0
306 index = properties.ObjectProperty() 305 index = properties.ObjectProperty()
307 selected = properties.BooleanProperty(False) 306 selected = properties.BooleanProperty(False)
308 307
309 def __init__(self, **kwargs): 308 def __init__(self, **kwargs):
323 self.selected = parent._xmluiToggleSelected(self) 322 self.selected = parent._xmluiToggleSelected(self)
324 323
325 return super(AdvancedListRow, self).on_touch_down(touch) 324 return super(AdvancedListRow, self).on_touch_down(touch)
326 325
327 326
328 class AdvancedListContainer(xmlui.AdvancedListContainer, GridLayout): 327 class AdvancedListContainer(xmlui.AdvancedListContainer, BoxLayout):
329 328
330 def __init__(self, xmlui_parent, columns, selectable='no'): 329 def __init__(self, xmlui_parent, columns, selectable='no'):
331 self.xmlui_parent = xmlui_parent 330 self.xmlui_parent = xmlui_parent
332 GridLayout.__init__(self) 331 BoxLayout.__init__(self)
333 self._columns = columns 332 self._columns = columns
334 self.selectable = selectable != 'no' 333 self.selectable = selectable != 'no'
335 self._current_row = None 334 self._current_row = None
336 self._selected = [] 335 self._selected = []
337 self._xmlui_select_cb = None 336 self._xmlui_select_cb = None
374 373
375 def _xmluiOnSelect(self, callback): 374 def _xmluiOnSelect(self, callback):
376 """ Call callback with widget as only argument """ 375 """ Call callback with widget as only argument """
377 self._xmlui_select_cb = callback 376 self._xmlui_select_cb = callback
378 377
378
379 ## Dialogs ## 379 ## Dialogs ##
380 380
381 381
382 class NoteDialog(xmlui.NoteDialog): 382 class NoteDialog(xmlui.NoteDialog):
383 383
496 496
497 497
498 class FormButton(Button): 498 class FormButton(Button):
499 pass 499 pass
500 500
501 501 class SubmitButton(FormButton):
502 class XMLUIPanel(xmlui.XMLUIPanel, BoxLayout): 502 pass
503
504 class CancelButton(FormButton):
505 pass
506
507 class SaveButton(FormButton):
508 pass
509
510
511 class XMLUIPanel(xmlui.XMLUIPanel, ScrollView):
503 widget_factory = WidgetFactory() 512 widget_factory = WidgetFactory()
513 layout = properties.ObjectProperty()
504 514
505 def __init__(self, host, parsed_xml, title=None, flags=None, callback=None, 515 def __init__(self, host, parsed_xml, title=None, flags=None, callback=None,
506 ignore=None, whitelist=None, profile=C.PROF_KEY_NONE): 516 ignore=None, whitelist=None, profile=C.PROF_KEY_NONE):
507 BoxLayout.__init__(self) 517 ScrollView.__init__(self)
508 self.close_cb = None 518 self.close_cb = None
509 self._post_treats = [] # list of callback to call after UI is constructed 519 self._post_treats = [] # list of callback to call after UI is constructed
520
521 # used to workaround touch issues when a ScrollView is used inside this
522 # one. This happens notably when a TabsContainer is used as main container
523 # (this is the case with settings).
524 self._skip_scroll_events = False
510 xmlui.XMLUIPanel.__init__(self, 525 xmlui.XMLUIPanel.__init__(self,
511 host, 526 host,
512 parsed_xml, 527 parsed_xml,
513 title=title, 528 title=title,
514 flags=flags, 529 flags=flags,
515 callback=callback, 530 callback=callback,
516 ignore=ignore, 531 ignore=ignore,
517 whitelist=whitelist, 532 whitelist=whitelist,
518 profile=profile) 533 profile=profile)
534 self.bind(height=self.onHeight)
535
536 def on_touch_down(self, touch, after=False):
537 if self._skip_scroll_events:
538 return super(ScrollView, self).on_touch_down(touch)
539 else:
540 return super(XMLUIPanel, self).on_touch_down(touch)
541
542 def on_touch_up(self, touch, after=False):
543 if self._skip_scroll_events:
544 return super(ScrollView, self).on_touch_up(touch)
545 else:
546 return super(XMLUIPanel, self).on_touch_up(touch)
547
548 def on_touch_move(self, touch, after=False):
549 if self._skip_scroll_events:
550 return super(ScrollView, self).on_touch_move(touch)
551 else:
552 return super(XMLUIPanel, self).on_touch_move(touch)
519 553
520 def setCloseCb(self, close_cb): 554 def setCloseCb(self, close_cb):
521 self.close_cb = close_cb 555 self.close_cb = close_cb
522 556
523 def _xmluiClose(self): 557 def _xmluiClose(self, *__):
524 if self.close_cb is not None: 558 if self.close_cb is not None:
525 self.close_cb(self) 559 self.close_cb(self)
526 else: 560 else:
527 G.host.closeUI() 561 G.host.closeUI()
528 562
543 self.onSaveParams(button) 577 self.onSaveParams(button)
544 578
545 def constructUI(self, parsed_dom): 579 def constructUI(self, parsed_dom):
546 xmlui.XMLUIPanel.constructUI(self, parsed_dom, self._postTreatCb) 580 xmlui.XMLUIPanel.constructUI(self, parsed_dom, self._postTreatCb)
547 if self.xmlui_title: 581 if self.xmlui_title:
548 self.add_widget(Title(text=self.xmlui_title)) 582 self.layout.add_widget(Title(text=self.xmlui_title))
549 self.add_widget(self.main_cont) 583 if isinstance(self.main_cont, TabsContainer):
584 # cf. comments above
585 self._skip_scroll_events = True
586 self.layout.add_widget(self.main_cont)
550 if self.type == 'form': 587 if self.type == 'form':
551 submit_btn = FormButton(text=_(u"Submit")) 588 submit_btn = SubmitButton()
552 submit_btn.bind(on_press=self.onFormSubmitted) 589 submit_btn.bind(on_press=self.onFormSubmitted)
553 self.add_widget(submit_btn) 590 self.layout.add_widget(submit_btn)
554 if not 'NO_CANCEL' in self.flags: 591 if not 'NO_CANCEL' in self.flags:
555 cancel_btn = FormButton(text=_(u"Cancel")) 592 cancel_btn = CancelButton(text=_(u"Cancel"))
556 cancel_btn.bind(on_press=self.onFormCancelled) 593 cancel_btn.bind(on_press=self.onFormCancelled)
557 self.add_widget(cancel_btn) 594 self.layout.add_widget(cancel_btn)
558 elif self.type == 'param': 595 elif self.type == 'param':
559 self.save_btn = FormButton(text=_(u"Save"), disabled=True) 596 self.save_btn = SaveButton(text=_(u"Save"), disabled=True)
560 self.save_btn.bind(on_press=self._saveButtonCb) 597 self.save_btn.bind(on_press=self._saveButtonCb)
561 self.add_widget(self.save_btn) 598 self.layout.add_widget(self.save_btn)
599 elif self.type == 'window':
600 cancel_btn = CancelButton(text=_(u"Cancel"))
601 cancel_btn.bind(on_press=self._xmluiClose)
602 self.layout.add_widget(cancel_btn)
603
604 def onHeight(self, __, height):
605 if isinstance(self.main_cont, TabsContainer):
606 # when the main
607 other_children_height = sum([c.height for c in self.layout.children
608 if c is not self.main_cont])
609 self.main_cont.height = height - other_children_height
562 610
563 def show(self, *args, **kwargs): 611 def show(self, *args, **kwargs):
564 if not self.user_action and not kwargs.get("force", False): 612 if not self.user_action and not kwargs.get("force", False):
565 G.host.addNotifUI(self) 613 G.host.addNotifUI(self)
566 else: 614 else: