# HG changeset patch # User Goffi # Date 1482053069 -3600 # Node ID a9c6b089070d55126c28b28f81644115c6aee29c # Parent 4a1e1012337e2ca2f2ab7d2a331a1c49ccc7280c 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 diff -r 4a1e1012337e -r a9c6b089070d src/cagou/core/xmlui.py --- a/src/cagou/core/xmlui.py Sat Dec 17 14:34:45 2016 +0100 +++ b/src/cagou/core/xmlui.py Sun Dec 18 10:24:29 2016 +0100 @@ -24,6 +24,7 @@ from sat_frontends.tools import xmlui from kivy.uix.scrollview import ScrollView from kivy.uix.gridlayout import GridLayout +from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem from kivy.uix.textinput import TextInput from kivy.uix.label import Label from kivy.uix.button import Button @@ -38,6 +39,27 @@ ## Widgets ## +class TextInputOnChange(object): + + def __init__(self): + self._xmlui_onchange_cb = None + self._got_focus = False + + def _xmluiOnChange(self, callback): + self._xmlui_onchange_cb = callback + + def on_focus(self, instance, focus): + # we need to wait for first focus, else initial value + # will trigger a on_text + if not self._got_focus and focus: + self._got_focus = True + + def on_text(self, instance, new_text): + log.debug("on_text: %s" % new_text) + if self._xmlui_onchange_cb is not None and self._got_focus: + self._xmlui_onchange_cb(self) + + class EmptyWidget(xmlui.EmptyWidget, Widget): def __init__(self, _xmlui_parent): @@ -58,10 +80,11 @@ pass -class StringWidget(xmlui.StringWidget, TextInput): +class StringWidget(xmlui.StringWidget, TextInput, TextInputOnChange): def __init__(self, xmlui_parent, value, read_only=False): TextInput.__init__(self, text=value, multiline=False) + TextInputOnChange.__init__(self) self.readonly = read_only def _xmluiSetValue(self, value): @@ -194,11 +217,19 @@ self._on_change = callback -class PasswordWidget(xmlui.PasswordWidget, TextInput): +class JidsListWidget(ListWidget): + # TODO: real list dedicated to jids + + def __init__(self, _xmlui_parent, jids, flags): + ListWidget.__init__(self, _xmlui_parent, [(j,j) for j in jids], [], flags) + + +class PasswordWidget(xmlui.PasswordWidget, TextInput, TextInputOnChange): def __init__(self, _xmlui_parent, value, read_only=False): TextInput.__init__(self, password=True, multiline=False, text=value, readonly=read_only, size=(100,25), size_hint=(1,None)) + TextInputOnChange.__init__(self) def _xmluiSetValue(self, value): self.text = value @@ -220,6 +251,24 @@ def _xmluiGetValue(self): return self.active + def _xmluiOnChange(self, callback): + self.bind(active=lambda instance, value: callback(instance)) + + +class IntWidget(xmlui.IntWidget, TextInput, TextInputOnChange): + + def __init__(self, _xmlui_parent, value, read_only=False): + TextInput.__init__(self, text=value, input_filter='int', multiline=False) + TextInputOnChange.__init__(self) + if read_only: + self.disabled = True + + def _xmluiSetValue(self, value): + self.text = value + + def _xmluiGetValue(self): + return self.text + ## Containers ## @@ -227,6 +276,7 @@ class VerticalContainer(xmlui.VerticalContainer, GridLayout): def __init__(self, xmlui_parent): + self.xmlui_parent = xmlui_parent GridLayout.__init__(self) def _xmluiAppend(self, widget): @@ -236,12 +286,46 @@ class PairsContainer(xmlui.PairsContainer, GridLayout): def __init__(self, xmlui_parent): + self.xmlui_parent = xmlui_parent GridLayout.__init__(self) def _xmluiAppend(self, widget): self.add_widget(widget) +class TabsPanelContainer(TabbedPanelItem): + + def _xmluiAppend(self, widget): + self.add_widget(widget) + + +class TabsContainer(xmlui.TabsContainer, TabbedPanel): + + def __init__(self, xmlui_parent): + self.xmlui_parent = xmlui_parent + xmlui_panel = xmlui_parent + while not isinstance(xmlui_panel, XMLUIPanel): + xmlui_panel = xmlui_panel.xmlui_parent + xmlui_panel.addPostTreat(self._postTreat) + TabbedPanel.__init__(self, do_default_tab=False) + + def _xmluiAddTab(self, label, selected): + tab = TabsPanelContainer(text=label) + self.add_widget(tab) + return tab + + def _postTreat(self): + """bind minimum height of tabs' content so self.height is adapted""" + # we need to do this in postTreat because contents exists after UI construction + for t in self.tab_list: + t.content.bind(minimum_height=self._updateHeight) + + def _updateHeight(self, instance, height): + """Called after UI is constructed (so height can be calculated)""" + # needed because TabbedPanel doesn't have a minimum_height property + self.height = max([t.content.minimum_height for t in self.tab_list]) + self.tab_height + 5 + + class AdvancedListRow(GridLayout): global_index = 0 index = properties.ObjectProperty() @@ -268,7 +352,8 @@ class AdvancedListContainer(xmlui.AdvancedListContainer, GridLayout): - def __init__(self, _xmlui_parent, columns, selectable='no'): + def __init__(self, xmlui_parent, columns, selectable='no'): + self.xmlui_parent = xmlui_parent GridLayout.__init__(self) self._columns = columns self.selectable = selectable != 'no' @@ -365,6 +450,7 @@ ScrollView.__init__(self) self.close_cb = None self._grid = XMLUIPanelGrid() + self._post_treats = [] # list of callback to call after UI is constructed ScrollView.add_widget(self, self._grid) xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags, callback, profile) @@ -380,8 +466,16 @@ else: G.host.closeUI() + def addPostTreat(self, callback): + self._post_treats.append(callback) + + def _postTreatCb(self): + for cb in self._post_treats: + cb() + del self._post_treats + def constructUI(self, parsed_dom): - xmlui.XMLUIPanel.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) @@ -393,6 +487,10 @@ cancel_btn = FormButton(text=_(u"Cancel")) cancel_btn.bind(on_press=self.onFormCancelled) self.add_widget(cancel_btn) + elif self.type == 'param': + save_btn = FormButton(text=_(u"Save")) + save_btn.bind(on_press=self.onSaveParams) + self.add_widget(save_btn) self.add_widget(Widget()) # to have elements on the top def show(self, *args, **kwargs): diff -r 4a1e1012337e -r a9c6b089070d src/cagou/kv/xmlui.kv --- a/src/cagou/kv/xmlui.kv Sat Dec 17 14:34:45 2016 +0100 +++ b/src/cagou/kv/xmlui.kv Sun Dec 18 10:24:29 2016 +0100 @@ -78,6 +78,10 @@ size_hint: 1, None height: self.minimum_height +: + size_hint: 1, None + height: 100 + : size_hint: 1, None height: dp(button_height)