From 5f0a2d3b6a7e3ba1feaf1d224be861f69f00162a Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 31 Dec 2021 16:05:24 +0800 Subject: [PATCH] bugfix --- kivyblocks/clickable.py | 25 +++++++-- kivyblocks/dg.pyx | 47 +---------------- kivyblocks/hirarchy.py | 73 +++++++++++++++++++++++++- kivyblocks/scrollpanel.py | 5 +- kivyblocks/uitype.py | 106 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+), 53 deletions(-) create mode 100644 kivyblocks/uitype.py diff --git a/kivyblocks/clickable.py b/kivyblocks/clickable.py index a31b263..2c30867 100644 --- a/kivyblocks/clickable.py +++ b/kivyblocks/clickable.py @@ -21,7 +21,7 @@ class TinyText(Text): self.on_texture_size(self, (1,1)) def on_texture_size(self, o, ts): - self._label.refresh() + self.texture_update() self.size = self.texture_size class ClickableBox(TouchRippleButtonBehavior, Box): @@ -48,24 +48,39 @@ class ClickableBox(TouchRippleButtonBehavior, Box): pass class ClickableText(ClickableBox): - text = StringProperty(' ') + text = StringProperty(None) fontsize = NumericProperty(1) def __init__(self, **kw): self.txt_w = None SUPER(ClickableText, self, kw) + self.create_text_widget() + + def create_text_widget(self): + if self.text is None: + return self.txt_w = TinyText(otext=self.text, i18n=True, font_size=CSize(self.fontsize)) + self.txt_w.font_size = CSize(self.fontsize) self.txt_w.bind(texture_size=self.reset_size) self.add_widget(self.txt_w) self.txt_w.size_hint = (None, None) self.txt_w.size = self.txt_w.texture_size + def on_fontsize(self, o, fs): + if self.txt_w: + self.txt_w.font_size = CSize(self.fontsize) + self.txt_w.texture_update() + def on_text(self, o, txt): + if self.text is None: + return + if not self.txt_w: + self.create_text_widget() + return if self.txt_w: self.txt_w.text = self.text - - + self.txt_w.texture_update() class ClickableIconText(ClickableText): source = StringProperty(None) @@ -139,6 +154,8 @@ class ToggleIconText(ToggleText): self.source = self.source_on if f else self.source_off def on_source(self, o, source): + if source is None: + return if self.img_w: self.img_w.source = self.source diff --git a/kivyblocks/dg.pyx b/kivyblocks/dg.pyx index 4d7f275..ac3c3f2 100644 --- a/kivyblocks/dg.pyx +++ b/kivyblocks/dg.pyx @@ -29,50 +29,7 @@ from .ready import WidgetReady from .toolbar import Toolbar from .bgcolorbehavior import BGColorBehavior from .widget_css import WidgetCSS - -def field_widget(desc, rec): - viewer = desc.get('viewer') - if viewer: - if not isinstance(viewer,str): - viewer = json.dumps(viewer) - rendered = string_template_render(viewer, rec) - dic = json.loads(rendered) - if dic is None: - return None - blocks = Factory.Blocks() - return blocks.widgetBuild(dic) - - uitype = desc.get('uitype', 'str') - if uitype is None: - uitype = desc.get('datatype') - if uitype in [ 'str' 'date', 'time', 'timestamp' ]: - return Text(text = str(desc['value']), - font_size=CSize(1),wrap=True, - halign='left', valign='middle' - ) - if uitype in [ 'long', 'int','integer' ]: - return Text(text=str(desc['value']), - font_size=CSize(1), wrap=True, - halign='right', valign='middle' - ) - if uitype == 'float': - f = '%%.0%df' % desc.get('dec',2) - return Text(text=f % float(desc['value']), - font_size=CSize(1), wrap=True, - halign='right', valign='middle' - ) - if uitype == 'code': - tf = desc.get('textField','text') - vf = desc.get('valueField','value') - v = rec.get(tf,rec.get(vf, ' ')) - return Text(text=v, font_size = CSize(1), wrap=True, - halign='right', valign='middle' - ) - return Text(text = str(desc['value']), - font_size=CSize(1),wrap=True, - halign='left', valign='middle' - ) - +from .uitype import build_view_widget class BLabel(ButtonBehavior, Text): def __init__(self, **kw): @@ -107,7 +64,7 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout): halign='left', valign='middle' ) else: - bl = field_widget(desc,self.row.row_data) + bl = build_view_widget(desc,self.row.row_data) if bl: self.add_widget(bl) diff --git a/kivyblocks/hirarchy.py b/kivyblocks/hirarchy.py index a700814..0f69c42 100644 --- a/kivyblocks/hirarchy.py +++ b/kivyblocks/hirarchy.py @@ -6,6 +6,7 @@ from kivy.properties import ListProperty, BooleanProperty, \ StringProperty, DictProperty, NumericProperty from kivy.uix.treeview import TreeView, TreeViewNode, TreeViewLabel from kivy.uix.boxlayout import BoxLayout +from kivy.uix.image import AsyncImage from .threadcall import HttpClient from .scrollpanel import ScrollPanel @@ -27,7 +28,8 @@ class TreeViewComplexNode(BoxLayout, TreeViewLabel): cb.bind(on_press=self.set_checked) self.add_widget(cb) if self.icon: - img = AsyncImage(source=self.icon) + img = AsyncImage(source=self.icon, size_hint=(None,None)) + img.size = CSize(1,1) self.add_widget(img) txt = Text(otext=self.otext, i18n=True) txt.texture_update() @@ -52,6 +54,7 @@ class Hirarchy(ScrollPanel): data = ListProperty(None) checkbox = BooleanProperty(False) icon = StringProperty(None) + single_expand = BooleanProperty(False) def __init__(self, **kw): self.register_event_type('on_selected') self.tree = TreeView(hide_root=True) @@ -68,9 +71,19 @@ class Hirarchy(ScrollPanel): def node_selected(self, o, v): self.dispatch('on_selected', o.selected_node) + def collapse_others(self, node): + for n in self.tree.iterate_open_nodes(node=node.parent_node): + if n != node and n !=node.parent_node and n.is_open: + self.tree.toggle_node(n) + def check_load_subnodes(self, treeview, node): + if self.single_expand: + self.collapse_others(node) if node.is_loaded: return + if not self.url: + node.is_loaded = True + return data = self.get_remote_data(node) for d in data: self.create_new_node(d, node) @@ -79,7 +92,7 @@ class Hirarchy(ScrollPanel): def create_new_node(self, data, node=None): n = TreeViewComplexNode(otext=data[self.textField], checkbox=self.checkbox, - icon=self.icon + icon=data.get('icon') or self.icon ) n.data = data n.width = self.tree.indent_start + \ @@ -97,6 +110,8 @@ class Hirarchy(ScrollPanel): n.is_loaded = True def get_remote_data(self, node=None): + if not self.url: + return hc = HttpClient() params = self.params.copy() if self.params else {} if node: @@ -115,4 +130,58 @@ class Hirarchy(ScrollPanel): for d in self.data: self.create_new_node(d) +class Menu(Hirarchy): + target = StringProperty(None) + def __init__(self, **kw): + self.target_w = None + super(Menu, self).__init__(**kw) + + def on_selected(self, node): + data = {} + dw = node.data.get('datawidget') + if dw: + data_widget = Factory.Blocks.getWidgetById(dw) + if data_widget: + vn = node.data.get('datamethod', 'getValue') + if hasattr(data_widget, vn): + f = getattr(data_widget, vn) + data = f() + if not isinstance(data, dict): + data = {} + + url = node.data.get('url') + target = Factory.Blocks.getWidgetById(node.data.get('target',self.target),self) + if url: + params = node.data.get('params',{}) + params.update(data) + blocks = Factory.Blocks() + desc = { + "widgettype":"urlwidget", + "options":{ + "url":url, + "params":params + } + } + w = blocks.widgetBuild(desc) + if w and target: + target.add_widget(w) + return + + rfname = node.data.get('rfname') + if rfname: + f = getRegisterFunctionByName(rfname) + if f: + f(self, **data) + return + + script = node.data.get('script') + if script: + target_name = node.data.get('target', self.target) + target = Factory.Blocks.getWidgetById(target_name, self) + data.update({'self':target}) + if target: + eval(script,data) + return + Factory.register('Hirarchy', Hirarchy) +Factory.register('Menu', Menu) diff --git a/kivyblocks/scrollpanel.py b/kivyblocks/scrollpanel.py index f659d66..1452ccb 100644 --- a/kivyblocks/scrollpanel.py +++ b/kivyblocks/scrollpanel.py @@ -6,9 +6,10 @@ from kivy.uix.widget import Widget from kivy.uix.boxlayout import BoxLayout from kivy.factory import Factory -from kivyblocks.utils import * +from .utils import * +from .widget_css import WidgetCSS -class ScrollPanel(ScrollView): +class ScrollPanel(WidgetCSS, ScrollView): orientation = OptionProperty('vertical', \ options=['vertical', 'horizontal']) bgcolor = ListProperty([0.2, 0.2, 0.2, 1]) diff --git a/kivyblocks/uitype.py b/kivyblocks/uitype.py new file mode 100644 index 0000000..00a8220 --- /dev/null +++ b/kivyblocks/uitype.py @@ -0,0 +1,106 @@ +#uitype.py +""" +each ui type need to provides a view widget and a input widget +to auto construct the form widget and record show widget. + +we use a register machinans to maintian the ui type information to build the view widget and input widget +""" + +from kivy.factory import Factory + +from appPublic.myTE import string_template_render + +view_widget_builders = { +} + +input_widget_builders = {} + +def view_register(uitype, f): + view_widget_builders.update({uitype:f}) + +def input_register(uitype, f): + input_widget_builders.update({uitype:f}) + +def get_input_builder(uitype): + return input_widget_builders.get(uitype, \ + input_widget_builders.get('str', None)) + +def get_view_builder(uitype): + return view_widget_builders.get(uitype, \ + view_widget_builders.get('str', None)) + +def build_view_widget(desc, rec = None): + if desc.get('viewer'): + if isinstance(viewer,dict): + viewer = json.dumps(viewer) + rendered = string_template_render(viewer, rec) + dic = json.loads(rendered) + if dic is None: + return None + w = Factory.Blocks().widgetBuild(dic) + return w + + f = get_view_builder(desc.get('uitype')) + return f(desc, rec) + +def build_input_widget(desc, rec=None): + f = get_input_builder(desc.get('uitype')) + return f(desc, rec) + +def get_value(desc, rec=None): + if rec: + return rec.get(desc['name']) + return desc.get('value', desc.get('defaultvalue', '')) + +def build_view_text_widget(desc, rec=None): + txt = get_value(desc, rec=rec) + return Factory.Text(text=str(txt), + font_size=CSize(1), + wrap=True, + halign='left', + valign='middle') + +view_register('str', build_view_text_widget) +view_register('date', build_view_text_widget) +view_register('time', build_view_text_widget) +view_register('timestamp', build_view_text_widget) + +def build_view_int_widget(desc, rec=None): + v = get_value(desc, rec=rec) + return Text(text=str(v), + font_size=CSize(1), + wrap=True, + halign='right', + valign='middle' + ) + +view_register('int', build_view_int_widget) +view_register('long', build_view_int_widget) +view_register('integer', build_view_int_widget) + +def build_view_float_widget(desc, rec=None): + v = get_value(desc, rec=rec) + f = '%%.0%df' % desc.get('dec',2) + return Text(text=f % float(v), + font_size=CSize(1), + wrap=True, + halign='right', + valign='middle' + ) + +view_register('float', build_view_float_widget) + +def build_view_code_widget(desc, rec=None): + tf = desc.get('textField','text') + vf = desc.get('valueField','value') + v = rec.get(tf,rec.get(vf, ' ')) + return Text(text=v, + font_size = CSize(1), + wrap=True, + halign='center', + valign='middle' + ) + +view_register('code', build_view_code_widget) + +