diff 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
line wrap: on
line diff
--- a/cagou/core/xmlui.py	Wed Mar 27 22:22:51 2019 +0100
+++ b/cagou/core/xmlui.py	Wed Mar 27 22:22:51 2019 +0100
@@ -257,15 +257,14 @@
 ## Containers ##
 
 
-class VerticalContainer(xmlui.VerticalContainer, ScrollView):
-    layout = properties.ObjectProperty(None)
+class VerticalContainer(xmlui.VerticalContainer, BoxLayout):
 
     def __init__(self, xmlui_parent):
         self.xmlui_parent = xmlui_parent
-        ScrollView.__init__(self)
+        BoxLayout.__init__(self)
 
     def _xmluiAppend(self, widget):
-        self.layout.add_widget(widget)
+        self.add_widget(widget)
 
 
 class PairsContainer(xmlui.PairsContainer, GridLayout):
@@ -301,7 +300,7 @@
         return tab
 
 
-class AdvancedListRow(GridLayout):
+class AdvancedListRow(BoxLayout):
     global_index = 0
     index = properties.ObjectProperty()
     selected = properties.BooleanProperty(False)
@@ -325,11 +324,11 @@
         return super(AdvancedListRow, self).on_touch_down(touch)
 
 
-class AdvancedListContainer(xmlui.AdvancedListContainer, GridLayout):
+class AdvancedListContainer(xmlui.AdvancedListContainer, BoxLayout):
 
     def __init__(self, xmlui_parent, columns, selectable='no'):
         self.xmlui_parent = xmlui_parent
-        GridLayout.__init__(self)
+        BoxLayout.__init__(self)
         self._columns = columns
         self.selectable = selectable != 'no'
         self._current_row = None
@@ -376,6 +375,7 @@
         """ Call callback with widget as only argument """
         self._xmlui_select_cb = callback
 
+
 ## Dialogs ##
 
 
@@ -498,15 +498,30 @@
 class FormButton(Button):
     pass
 
+class SubmitButton(FormButton):
+    pass
 
-class XMLUIPanel(xmlui.XMLUIPanel, BoxLayout):
+class CancelButton(FormButton):
+    pass
+
+class SaveButton(FormButton):
+    pass
+
+
+class XMLUIPanel(xmlui.XMLUIPanel, ScrollView):
     widget_factory = WidgetFactory()
+    layout = properties.ObjectProperty()
 
     def __init__(self, host, parsed_xml, title=None, flags=None, callback=None,
                  ignore=None, whitelist=None, profile=C.PROF_KEY_NONE):
-        BoxLayout.__init__(self)
+        ScrollView.__init__(self)
         self.close_cb = None
         self._post_treats = []  # list of callback to call after UI is constructed
+
+        # used to workaround touch issues when a ScrollView is used inside this
+        # one. This happens notably when a TabsContainer is used as main container
+        # (this is the case with settings).
+        self._skip_scroll_events = False
         xmlui.XMLUIPanel.__init__(self,
                                   host,
                                   parsed_xml,
@@ -516,11 +531,30 @@
                                   ignore=ignore,
                                   whitelist=whitelist,
                                   profile=profile)
+        self.bind(height=self.onHeight)
+
+    def on_touch_down(self, touch, after=False):
+        if self._skip_scroll_events:
+            return super(ScrollView, self).on_touch_down(touch)
+        else:
+            return super(XMLUIPanel, self).on_touch_down(touch)
+
+    def on_touch_up(self, touch, after=False):
+        if self._skip_scroll_events:
+            return super(ScrollView, self).on_touch_up(touch)
+        else:
+            return super(XMLUIPanel, self).on_touch_up(touch)
+
+    def on_touch_move(self, touch, after=False):
+        if self._skip_scroll_events:
+            return super(ScrollView, self).on_touch_move(touch)
+        else:
+            return super(XMLUIPanel, self).on_touch_move(touch)
 
     def setCloseCb(self, close_cb):
         self.close_cb = close_cb
 
-    def _xmluiClose(self):
+    def _xmluiClose(self, *__):
         if self.close_cb is not None:
             self.close_cb(self)
         else:
@@ -545,20 +579,34 @@
     def constructUI(self, parsed_dom):
         xmlui.XMLUIPanel.constructUI(self, parsed_dom, self._postTreatCb)
         if self.xmlui_title:
-            self.add_widget(Title(text=self.xmlui_title))
-        self.add_widget(self.main_cont)
+            self.layout.add_widget(Title(text=self.xmlui_title))
+        if isinstance(self.main_cont, TabsContainer):
+            # cf. comments above
+            self._skip_scroll_events = True
+        self.layout.add_widget(self.main_cont)
         if self.type == 'form':
-            submit_btn = FormButton(text=_(u"Submit"))
+            submit_btn = SubmitButton()
             submit_btn.bind(on_press=self.onFormSubmitted)
-            self.add_widget(submit_btn)
+            self.layout.add_widget(submit_btn)
             if not 'NO_CANCEL' in self.flags:
-                cancel_btn = FormButton(text=_(u"Cancel"))
+                cancel_btn = CancelButton(text=_(u"Cancel"))
                 cancel_btn.bind(on_press=self.onFormCancelled)
-                self.add_widget(cancel_btn)
+                self.layout.add_widget(cancel_btn)
         elif self.type == 'param':
-            self.save_btn = FormButton(text=_(u"Save"), disabled=True)
+            self.save_btn = SaveButton(text=_(u"Save"), disabled=True)
             self.save_btn.bind(on_press=self._saveButtonCb)
-            self.add_widget(self.save_btn)
+            self.layout.add_widget(self.save_btn)
+        elif self.type == 'window':
+            cancel_btn = CancelButton(text=_(u"Cancel"))
+            cancel_btn.bind(on_press=self._xmluiClose)
+            self.layout.add_widget(cancel_btn)
+
+    def onHeight(self, __, height):
+        if isinstance(self.main_cont, TabsContainer):
+            # when the main
+            other_children_height = sum([c.height for c in self.layout.children
+                                         if c is not self.main_cont])
+            self.main_cont.height = height - other_children_height
 
     def show(self, *args, **kwargs):
         if not self.user_action and not kwargs.get("force", False):