diff --git a/kivyblocks/clickable.py b/kivyblocks/clickable.py index 1ddadc8..0385ed3 100644 --- a/kivyblocks/clickable.py +++ b/kivyblocks/clickable.py @@ -22,7 +22,6 @@ class TinyText(Text): def on_texture_size(self, o, ts): self._label.refresh() self.size = self.texture_size - print('TinyText:texture_size=', self.texture_size, 'text=', self.text) class ClickableBox(TouchRippleButtonBehavior, Box): def __init__(self, @@ -32,6 +31,16 @@ class ClickableBox(TouchRippleButtonBehavior, Box): self.border_width = border_width # self.bind(minimum_height=self.setter('height')) # self.bind(minimum_width=self.setter('width')) + self.bind(children=self.reset_size) + + def reset_size(self, o, s): + self.size_hint = (None,None) + if self.orientation == 'horizontal': + self.height = max([c.height for c in self.children]) + self.width = sum([c.width for c in self.children]) + else: + self.height = sum([c.height for c in self.children]) + self.width = max([c.width for c in self.children]) def on_press(self,o=None): pass @@ -43,23 +52,15 @@ class ClickableText(ClickableBox): print('ClickableText begin inited') self.txt_w = None SUPER(ClickableText, self, kw) - self.txt_w = TinyText(text=self.text, + self.txt_w = TinyText(otext=self.text, i18n=True, 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 - #self.txt_w.bind(minimum_height=self.txt_w.setter('height')) - #self.txt_w.bind(minimum_width=self.txt_w.setter('width')) - print('ClickableText inited') - - def reset_size(self, o, s): - self.size_hint = (None,None) - self.size = self.txt_w.texture_size def on_text(self, o, txt): - print('on_text fired') if self.txt_w: self.txt_w.text = self.text @@ -73,22 +74,12 @@ class ClickableIconText(ClickableText): SUPER(ClickableIconText, self, kw) print('ClickableIconText inited') - def reset_size(self, o, s): - self.size_hint = (None,None) - if self.orientation == 'horizontal': - self.height = max(self.txt_w.texture_size[1], self.img_w.height) - self.width = self.txt_w.texture_size[0] + self.img_w.width - else: - self.height = self.txt_w.texture_size[1] + self.img_w.height - self.width = max(self.txt_w.texture_size[0], self.img_w.width) - - def on_source(self, o, source): if self.img_w: self.img_w.source = source return self.img_w = AsyncImage(source=self.source, **self.img_kw) - self.add_widget(self.img_w, index=-1) + self.add_widget(self.img_w, index=len(self.children)) class ToggleText(ClickableText): """ @@ -142,18 +133,8 @@ class ToggleIconText(ToggleText): SUPER(ToggleIconText, self, kw) self.source = self.source_off self.img_w = AsyncImage(source=self.source, **self.img_kw) - self.add_widget(self.img_w, index=-1) + self.add_widget(self.img_w, index=len(self.children)) - def reset_size(self, o, s): - self.size_hint = (None,None) - if self.orientation == 'horizontal': - self.height = max(self.txt_w.texture_size[1], self.img_w.height) - self.width = self.txt_w.texture_size[0] + self.img_w.width - else: - self.height = self.txt_w.texture_size[1] + self.img_w.height - self.width = max(self.txt_w.texture_size[0], self.img_w.width) - print(f'ToggleIconText:w,h={self.width},{self.height}') - def on_select_state(self, o, f): super(ToggleIconText, self).on_select_state(o,f) self.source = self.source_on if f else self.source_off @@ -168,12 +149,27 @@ class ClickableImage(ClickableBox): def __init__(self, **kw): self.img_w = None SUPER(ClickableImage, self, kw) - self.img_w = AsyncImage(source=self.source, **self.img_kw) - self.add_widget(self.img_w) + # self.img_w = AsyncImage(source=self.source, **self.img_kw) + # self.add_widget(self.img_w) def on_source(self, o, source): + if self.source is None: + self.source = blockImage('broken.png') + self.build_widget() + + def on_img_kw(self, o, img_kw): + self.build_widget() + + def build_widget(self): + if not self.source: + return + if not self.img_kw: + self.img_kw = {} + if self.img_w: - self.img_w.source = source + self.img_w.source = self.source + for k,v in self.img_kw.items(): + setattr(self.img_w, k,v) return self.img_w = AsyncImage(source=self.source, **self.img_kw) self.add_widget(self.img_w) @@ -204,8 +200,25 @@ class ToggleImage(ClickableImage): else: self.source = self.source_off +class CheckBox(ToggleImage): + otext = StringProperty(None) + def __init__(self, **kw): + SUPER(CheckBox, self, kw) + self.source_on = blockImage('checkbox-on.png') + self.source_off = blockImage('ceckbox-off.png') + if self.otext: + self.txt_w = TinyText(otext=self.otext, i18n=True) + self.add_widget(self.txt_w) + + def getValue(self): + return self.state() + + def setValue(self, v): + self.select_state = False if v else True + r = Factory.register r('TinyText', TinyText) +r('CheckBox', CheckBox) r('ClickableBox', ClickableBox) r('ClickableText',ClickableText) r('ClickableIconText',ClickableIconText) diff --git a/kivyblocks/dg.pyx b/kivyblocks/dg.pyx index 5e5c873..4d7f275 100644 --- a/kivyblocks/dg.pyx +++ b/kivyblocks/dg.pyx @@ -21,7 +21,7 @@ from appPublic.timecost import TimeCost from appPublic.uniqueID import getID from appPublic.myTE import string_template_render -from .utils import CSize, setSizeOptions, loading, loaded, absurl, alert +from .utils import CSize, setSizeOptions, loading, loaded, absurl, alert, SUPER from .baseWidget import Text, HBox, VBox from .scrollpanel import ScrollPanel from .paging import Paging, RelatedLoader @@ -166,7 +166,7 @@ class Row(BoxLayout): class Header(WidgetReady, ScrollPanel): def __init__(self,part,**kw): - super(Header, self).__init__(**kw) + SUPER(Header, self, kw) self.part = part self.init(1) self.bind(on_scroll_stop=self.part.datagrid.on_scrollstop) @@ -185,8 +185,8 @@ class Header(WidgetReady, ScrollPanel): class Body(WidgetReady, ScrollPanel): def __init__(self,part,**kw): self.part = part - kw.update({'spacing':self.part.datagrid.linewidth}) - super(Body, self).__init__(**kw) + SUPER(Body, self, kw) + self._inner.spacing = self.part.datagrid.linewidth self.size_hint=(1,1) self.idRow = {} self.bind(on_scroll_stop=self.part.datagrid.on_scrollstop) @@ -262,6 +262,11 @@ class DataGridPart(WidgetReady, BoxLayout): if not self.datagrid.noheader: self.header = Header(self,**kw) self.add_widget(self.header) + inner = { + "widgettype":"VBox", + "options":{ + } + } self.body = Body(self) self.add_widget(self.body) if not self.freeze_flag: @@ -522,6 +527,8 @@ class DataGrid(WidgetReady, BoxLayout): data['data'] = recs2 f = partial(self.add_page_delay,data) Clock.schedule_once(f, 0) + print('body=', self.normal_part.body.size, + 'inner=', self.normal_part.body._inner.size) def add_page_delay(self, data, *args): recs = data['data'] diff --git a/kivyblocks/form.py b/kivyblocks/form.py index 0926141..7af8278 100644 --- a/kivyblocks/form.py +++ b/kivyblocks/form.py @@ -241,8 +241,8 @@ class InputBox(BoxLayout): def defaultToolbar(): return { - "img_size":1.5, - "text_size":0.7, + "img_size_c":1.5, + "text_size_c":0.7, "tools":[ { "name":"__submit", @@ -320,18 +320,6 @@ class Form(WidgetCSS, WidgetReady, BoxLayout): self.fsc.org_box_width = self.width / self.options_cols if self.notoolbar: return - if self.toolbar_at in [ 'top', 'bottom' ]: - Logger.info('Form: height:tb:%d,ti:%d,fsc:%d, fm:%d', - self.toolbar.height, - self.toolbar.toggle_items.height, - self.fsc.height, self.height - ) - else: - Logger.info('Form: width:tb:%d,ti:%d,fsc:%d, fm:%d', - self.toolbar.width, - self.toolbar.toggle_items.width, - self.fsc.width, self.width - ) def init(self): if not self.notoolbar: @@ -359,11 +347,13 @@ class Form(WidgetCSS, WidgetReady, BoxLayout): if self.toolbar_at in ['top', 'bottom']: desc['orientation'] = 'horizontal' desc['size_hint_y'] = None - desc['height'] = CSize(desc['img_size'] + desc['text_size']) + desc['height'] = CSize(desc['img_size_c'] + \ + desc['text_size_c']) else: desc['orientation'] = 'vertical' desc['size_hint_x'] = None - desc['width'] = CSize(desc['img_size'] + desc['text_size']) + desc['width'] = CSize(desc['img_size_c'] + \ + desc['text_size_c']) self.toolbar = Toolbar(**desc) self.fsc = VResponsiveLayout( diff --git a/kivyblocks/scrollpanel.py b/kivyblocks/scrollpanel.py index b855004..f659d66 100644 --- a/kivyblocks/scrollpanel.py +++ b/kivyblocks/scrollpanel.py @@ -1,4 +1,5 @@ -from kivy.properties import NumericProperty, StringProperty, ListProperty +from kivy.properties import NumericProperty, StringProperty, \ + OptionProperty, ListProperty from kivy.uix.scrollview import ScrollView from kivy.effects.scroll import ScrollEffect from kivy.uix.widget import Widget @@ -8,38 +9,41 @@ from kivy.factory import Factory from kivyblocks.utils import * class ScrollPanel(ScrollView): - x_padding_c = NumericProperty(0) - y_padding_c = NumericProperty(0) + orientation = OptionProperty('vertical', \ + options=['vertical', 'horizontal']) bgcolor = ListProperty([0.2, 0.2, 0.2, 1]) + padding_c = NumericProperty(1) def __init__(self,inner=None, **kw): - print('ScrollPanel:kw=', kw) SUPER(ScrollPanel, self, kw) self.effect_cls = ScrollEffect if not inner: - kw = { - 'size_hint':(None,None), - 'bgcolor':self.bgcolor, - } - desc = { - "widgettype":"Box", - "options":kw - } - self._inner = Factory.Blocks().widgetBuild(desc) - if not self._inner: - print('desc=', desc) - raise Exception('widget build failed') - self._inner.padding = self._inner.spacing = \ - [CSize(self.x_padding_c), CSize(self.y_padding_c)] + self.create_default_inner() elif isinstance(inner, Widget): self._inner = inner else: self._inner = Factory.Blocks().widgetBuild(inner) + super(ScrollPanel,self).add_widget(self._inner) self._inner.bind( minimum_height=self._inner.setter('height')) self._inner.bind( minimum_width=self._inner.setter('width')) - super(ScrollPanel,self).add_widget(self._inner) + + def create_default_inner(self): + kw = { + 'size_hint':(None,None), + 'orientation':self.orientation + } + desc = { + "widgettype":"Box", + "options":kw + } + self._inner = Factory.Blocks().widgetBuild(desc) + self._inner.bgcolor = self.bgcolor + if not self._inner: + print('desc=', desc) + raise Exception('widget build failed') + self._inner.spacing = CSize(self.padding_c) def add_widget(self,widget,**kw): a = self._inner.add_widget(widget,**kw) diff --git a/kivyblocks/toolbar.py b/kivyblocks/toolbar.py index 8981890..5379638 100644 --- a/kivyblocks/toolbar.py +++ b/kivyblocks/toolbar.py @@ -10,7 +10,7 @@ from kivy.app import App from kivy.clock import Clock from kivy.factory import Factory from kivy.properties import StringProperty, DictProperty, \ - ListProperty, NumericProperty + OptionProperty, ListProperty, NumericProperty from appPublic.dictObject import DictObject from appPublic.registerfunction import RegisterFunction @@ -23,7 +23,7 @@ from .baseWidget import Text, Box from .scrollpanel import ScrollPanel from .toggleitems import ToggleItems -class ScrollToolbar(ScrollPanel): +class Toolbar(ScrollPanel): """ tool has the follow attributes { @@ -38,7 +38,6 @@ class ScrollToolbar(ScrollPanel): } toolbar has follow attributes { - "padding_c":x spacing "img_size_c":image height in charecter size "text_size_c": "toolbar_orient":"H" or "V" @@ -52,54 +51,44 @@ class ScrollToolbar(ScrollPanel): css_on = StringProperty('default') css_off = StringProperty('default') tools = ListProperty([]) - tool_orient = StringProperty('horizontal') - toolbar_orient = StringProperty('H') - padding_c = NumericProperty(1) + tool_orient = OptionProperty('horizontal', \ + options=['horizontal', 'vertical']) + toolbar_orient = OptionProperty('H', options=['H', 'V']) img_size_c = NumericProperty(2) text_size_c = NumericProperty(1) - def __init__(self, **kw): - SUPER(ScrollToolbar, self, kw) + self.w_dic = {} + SUPER(Toolbar, self, kw) self.register_event_type('on_press') + self.register_event_type('on_delete_tool') if self.toolbar_orient == 'H': self._inner.orientation = 'horizontal' else: self._inner.orientation = 'vertical' self.clear_widgets() - self.w_dic = {} for t in self.tools: self.add_tool(t) self.bar_width = 0 if self.toolbar_orient == 'H': self.do_scroll_y = False - self._inner.spacing = CSize(self.padding_c,0) else: self.do_scroll_x = False - self._inner.spacing = CSize(0, self.padding_c) def on_children_size(self, o, size): self.on_size(None, None) def on_size(self, o, size): - print('on_size=', size) if self.toolbar_orient == 'H': self.size_hint_x = 1 self.size_hint_y = None if len(self.w_dic.keys()) > 0: self.height = max([w.height for w in self.w_dic.keys()]) - self._inner.spacing = CSize(self.padding_c,0) else: self.size_hint_x = None self.size_hint_y = 1 if len(self.w_dic.keys()) > 0: self.width = max([w.width for w in self.w_dic.keys() ]) - self._inner.spacing = CSize(0, self.padding_c) - print('###size_hint=', - self.size_hint_x, - self.size_hint_y, - self.size_hint, - self.size) def add_tool(self, t): label = t.get('label', t.get('name', None)) @@ -108,6 +97,7 @@ class ScrollToolbar(ScrollPanel): ToggleIconText = Factory.ToggleIconText ToggleText = Factory.ToggleText ToggleImage = Factory.ToggleImage + ClickableImage = Factory.ClickableImage if label and source_on: w = ToggleIconText(css_on=self.css_on, css_off=self.css_off, @@ -142,6 +132,18 @@ class ScrollToolbar(ScrollPanel): } ) + print(w, 'children=', len(w.children)) + if t.get('deletable', False): + x = ClickableImage(source=blockImage('delete.png'), + img_kw={ + "size_hint":(None, None), + "size":CSize(1,1) + } + ) + x.data = (w, t) + x.bind(on_press=self.delete_tool) + w.add_widget(x) + if w: self.add_widget(w) self.w_dic[w] = t @@ -150,13 +152,20 @@ class ScrollToolbar(ScrollPanel): w.bind(on_press=self.tool_press) w.bind(minimum_width=w.setter('width')) w.bind(minimum_height=w.setter('height')) + print(w, 'children=', len(w.children)) - def del_tool(self, name): - m = [ x for x,y in self.w_dic.items() if y['name'] == name ] - for w in m: - self.remove(w) + def delete_tool(self, o): + w, t = o.data + self.del_tool(w) + self.dispatch('on_delete_tool', o.data) + + def on_delete_tool(self, o, d=None): + pass + + def del_tool(self, w): + self.remove_widget(w) self.w_dic = {k:v for k,v in self.w_dic.copy().items() \ - if k not in m } + if k != w } def on_press(self, o): pass @@ -187,7 +196,8 @@ class ToolPage(Box): } """ toolbar_size = NumericProperty(2) - tool_at = StringProperty('top') + tool_at = OptionProperty('top', \ + options=['top', 'bottom', 'left', 'right']) toolbar = DictProperty({}) def __init__(self, **kw): print('ToolPage:kw=',kw) @@ -202,16 +212,20 @@ class ToolPage(Box): self.content_w = None self.toolbar_w = None self.init() + self.toolbar_w.bind(on_delete_tool=self.delete_content_widget) name = self.toolbar['tools'][0]['name'] self.toolbar_w.select(name) + def delete_content_widget(self, o, d): + w, dic = d + self.del_tool(dic['name']) + def add_tool(self, tool): self.toolbar_w.add_tool(tool) def del_tool(self, name): - self.toolbar_w.del_tool(o) g = self.content_widgets.copy() - self.content_widgets = {k:v for k,v in g.items()} + self.content_widgets = {k:v for k,v in g.items() if k!=name} def on_size(self,obj,size): if self.content_w is None: @@ -226,7 +240,7 @@ class ToolPage(Box): def init(self): self.content_w = BoxLayout() self.content_w.widget_id = 'content' - self.toolbar_w = ScrollToolbar(**self.toolbar) + self.toolbar_w = Toolbar(**self.toolbar) if self.tool_at in ['top','left']: self.add_widget(self.toolbar_w) self.add_widget(self.content_w) @@ -264,7 +278,8 @@ class ToolPage(Box): def on_press_handle(self, o, v): name = v.get('name') refresh = v.get('refresh', False) - self.print_all() + # self.print_all() + w = self.content_widgets.get(name) self.content_w.clear_widgets() if w and not refresh: @@ -287,5 +302,3 @@ class ToolPage(Box): if isinstance(r,Widget): self.content_w.add_widget(r) -Factory.register('ScrollToolbar', ScrollToolbar) -Toolbar = ScrollToolbar