This commit is contained in:
yumoqing 2021-12-31 16:05:24 +08:00
parent 0de5b5b0ac
commit 5f0a2d3b6a
5 changed files with 203 additions and 53 deletions

View File

@ -21,7 +21,7 @@ class TinyText(Text):
self.on_texture_size(self, (1,1)) self.on_texture_size(self, (1,1))
def on_texture_size(self, o, ts): def on_texture_size(self, o, ts):
self._label.refresh() self.texture_update()
self.size = self.texture_size self.size = self.texture_size
class ClickableBox(TouchRippleButtonBehavior, Box): class ClickableBox(TouchRippleButtonBehavior, Box):
@ -48,24 +48,39 @@ class ClickableBox(TouchRippleButtonBehavior, Box):
pass pass
class ClickableText(ClickableBox): class ClickableText(ClickableBox):
text = StringProperty(' ') text = StringProperty(None)
fontsize = NumericProperty(1) fontsize = NumericProperty(1)
def __init__(self, **kw): def __init__(self, **kw):
self.txt_w = None self.txt_w = None
SUPER(ClickableText, self, kw) 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, self.txt_w = TinyText(otext=self.text,
i18n=True, i18n=True,
font_size=CSize(self.fontsize)) font_size=CSize(self.fontsize))
self.txt_w.font_size = CSize(self.fontsize)
self.txt_w.bind(texture_size=self.reset_size) self.txt_w.bind(texture_size=self.reset_size)
self.add_widget(self.txt_w) self.add_widget(self.txt_w)
self.txt_w.size_hint = (None, None) self.txt_w.size_hint = (None, None)
self.txt_w.size = self.txt_w.texture_size 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): 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: if self.txt_w:
self.txt_w.text = self.text self.txt_w.text = self.text
self.txt_w.texture_update()
class ClickableIconText(ClickableText): class ClickableIconText(ClickableText):
source = StringProperty(None) source = StringProperty(None)
@ -139,6 +154,8 @@ class ToggleIconText(ToggleText):
self.source = self.source_on if f else self.source_off self.source = self.source_on if f else self.source_off
def on_source(self, o, source): def on_source(self, o, source):
if source is None:
return
if self.img_w: if self.img_w:
self.img_w.source = self.source self.img_w.source = self.source

View File

@ -29,50 +29,7 @@ from .ready import WidgetReady
from .toolbar import Toolbar from .toolbar import Toolbar
from .bgcolorbehavior import BGColorBehavior from .bgcolorbehavior import BGColorBehavior
from .widget_css import WidgetCSS from .widget_css import WidgetCSS
from .uitype import build_view_widget
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'
)
class BLabel(ButtonBehavior, Text): class BLabel(ButtonBehavior, Text):
def __init__(self, **kw): def __init__(self, **kw):
@ -107,7 +64,7 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
halign='left', valign='middle' halign='left', valign='middle'
) )
else: else:
bl = field_widget(desc,self.row.row_data) bl = build_view_widget(desc,self.row.row_data)
if bl: if bl:
self.add_widget(bl) self.add_widget(bl)

View File

@ -6,6 +6,7 @@ from kivy.properties import ListProperty, BooleanProperty, \
StringProperty, DictProperty, NumericProperty StringProperty, DictProperty, NumericProperty
from kivy.uix.treeview import TreeView, TreeViewNode, TreeViewLabel from kivy.uix.treeview import TreeView, TreeViewNode, TreeViewLabel
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import AsyncImage
from .threadcall import HttpClient from .threadcall import HttpClient
from .scrollpanel import ScrollPanel from .scrollpanel import ScrollPanel
@ -27,7 +28,8 @@ class TreeViewComplexNode(BoxLayout, TreeViewLabel):
cb.bind(on_press=self.set_checked) cb.bind(on_press=self.set_checked)
self.add_widget(cb) self.add_widget(cb)
if self.icon: 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) self.add_widget(img)
txt = Text(otext=self.otext, i18n=True) txt = Text(otext=self.otext, i18n=True)
txt.texture_update() txt.texture_update()
@ -52,6 +54,7 @@ class Hirarchy(ScrollPanel):
data = ListProperty(None) data = ListProperty(None)
checkbox = BooleanProperty(False) checkbox = BooleanProperty(False)
icon = StringProperty(None) icon = StringProperty(None)
single_expand = BooleanProperty(False)
def __init__(self, **kw): def __init__(self, **kw):
self.register_event_type('on_selected') self.register_event_type('on_selected')
self.tree = TreeView(hide_root=True) self.tree = TreeView(hide_root=True)
@ -68,9 +71,19 @@ class Hirarchy(ScrollPanel):
def node_selected(self, o, v): def node_selected(self, o, v):
self.dispatch('on_selected', o.selected_node) 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): def check_load_subnodes(self, treeview, node):
if self.single_expand:
self.collapse_others(node)
if node.is_loaded: if node.is_loaded:
return return
if not self.url:
node.is_loaded = True
return
data = self.get_remote_data(node) data = self.get_remote_data(node)
for d in data: for d in data:
self.create_new_node(d, node) self.create_new_node(d, node)
@ -79,7 +92,7 @@ class Hirarchy(ScrollPanel):
def create_new_node(self, data, node=None): def create_new_node(self, data, node=None):
n = TreeViewComplexNode(otext=data[self.textField], n = TreeViewComplexNode(otext=data[self.textField],
checkbox=self.checkbox, checkbox=self.checkbox,
icon=self.icon icon=data.get('icon') or self.icon
) )
n.data = data n.data = data
n.width = self.tree.indent_start + \ n.width = self.tree.indent_start + \
@ -97,6 +110,8 @@ class Hirarchy(ScrollPanel):
n.is_loaded = True n.is_loaded = True
def get_remote_data(self, node=None): def get_remote_data(self, node=None):
if not self.url:
return
hc = HttpClient() hc = HttpClient()
params = self.params.copy() if self.params else {} params = self.params.copy() if self.params else {}
if node: if node:
@ -115,4 +130,58 @@ class Hirarchy(ScrollPanel):
for d in self.data: for d in self.data:
self.create_new_node(d) 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('Hirarchy', Hirarchy)
Factory.register('Menu', Menu)

View File

@ -6,9 +6,10 @@ from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.factory import Factory 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', \ orientation = OptionProperty('vertical', \
options=['vertical', 'horizontal']) options=['vertical', 'horizontal'])
bgcolor = ListProperty([0.2, 0.2, 0.2, 1]) bgcolor = ListProperty([0.2, 0.2, 0.2, 1])

106
kivyblocks/uitype.py Normal file
View File

@ -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)