diff --git a/kivyblocks/baseWidget.py b/kivyblocks/baseWidget.py index 210801a..9a4fece 100755 --- a/kivyblocks/baseWidget.py +++ b/kivyblocks/baseWidget.py @@ -89,16 +89,6 @@ font_names = { 'title1':resource_find('Alimama_ShuHeiTi_Bold.ttf') } -font_sizes = { - 'text':CSize(1), - 'title6':CSize(1.1), - 'title5':CSize(1.3), - 'title4':CSize(1.5), - 'title3':CSize(1.7), - 'title2':CSize(1.9), - 'title1':CSize(2.1) -} - if platform == 'android': from .widgetExt.phonebutton import PhoneButton from .widgetExt.androidwebview import AWebView @@ -162,10 +152,12 @@ class SwipeBox(SwipeBehavior, Box): class Text(Label): lang=StringProperty('') otext = StringProperty('') - def __init__(self,i18n=False, texttype='text', wrap=False, + def __init__(self,i18n=False, texttype='text', wrap=False, rate=1, fgcolor=None, **kw): - fontsize = font_sizes.get(texttype) + app = App.get_running_app() + self.rate = 1 + fontsize = app.get_font_size(texttype) * self.rate fontname = font_names.get(texttype) self._i18n = i18n self.i18n = I18n() @@ -181,6 +173,8 @@ class Text(Label): kwargs['text'] = kwargs.get('otext','') super(Text, self).__init__(**kwargs) + app.bind(font_size=self.reset_font_size) + # self.bind(texture_size=self.setter('size')) if self._i18n: self.i18n.addI18nWidget(self) if self.wrap: @@ -190,6 +184,9 @@ class Text(Label): if self.bgcolor: self.color = self.bgcolor + def reset_font_size(self, app, fsize): + self.font_size = fsize * self.rate + def resize(self, *args): if not self.size_hint_y: ps = [0,0,0,0] diff --git a/kivyblocks/blocks.py b/kivyblocks/blocks.py index 92a6f24..e813659 100755 --- a/kivyblocks/blocks.py +++ b/kivyblocks/blocks.py @@ -214,7 +214,14 @@ x = ClassX{klass_cnt}() print_exc() if errback: return errback(None,e) - return None + return { + "widgettype":"Text", + "options":{ + "text":f"{url=} error", + "wrap":True, + "halign":"left" + } + } else: config = getConfig() url = config.uihome + url @@ -727,7 +734,7 @@ x = ClassX{klass_cnt}() print('Block3: desc must be a dict object not None') return None w = doit(desc) - print('widgetBuild():w=', w) + # print('widgetBuild():w=', w) return w @classmethod @@ -769,7 +776,7 @@ x = ClassX{klass_cnt}() children = [i for i in from_widget.children] if hasattr(from_widget, 'get_subwidgets'): children = from_widget.get_subwidgets() - Logger.info('children=%s', str(children)) + # Logger.info('children=%s', str(children)) for c in children: ret = _find_widget(name, from_widget=c, dir=dir) if ret: diff --git a/kivyblocks/blocksapp.py b/kivyblocks/blocksapp.py index 9de0825..3965f07 100755 --- a/kivyblocks/blocksapp.py +++ b/kivyblocks/blocksapp.py @@ -12,6 +12,7 @@ from appPublic.folderUtils import ProgramPath from appPublic.uniqueID import getID from appPublic.rsawrap import RSA +from kivy.properties import NumericProperty from kivy.factory import Factory from kivy.metrics import sp,dp,mm from kivy.core.window import WindowBase, Window @@ -48,6 +49,7 @@ signal.signal(signal.SIGINT, signal_handler) class BlocksApp(App): + font_size = NumericProperty(24) def get_rotation(self): return get_rotation() @@ -78,7 +80,26 @@ class BlocksApp(App): if isinstance(v,dict): register_css(k,v) + def set_fontsize(self, x): + self.font_size = x + + def get_font_size(self, ttype='text'): + text_fontrates = { + 'text':1, + 'title6':1.1, + 'title5':1.3, + 'title4':1.5, + 'title3':1.7, + 'title2':1.9, + 'title1':2.1 + } + v = text_fontrates.get(ttype, 'text') + return v * self.font_size + def build(self): + tl = Label(text='test') + self.font_size = tl.font_size + print('##################app_font_size=', self.font_size) config = getConfig() self.workers = Workers(maxworkers=config.maxworkers or 80) self.workers.start() @@ -93,10 +114,10 @@ class BlocksApp(App): self.default_params.update(config.default_params) self.public_headers = { + "client_uuid":getID(), "platform":self.platform } # Window.borderless = True - print('Window.dpi=', Window.dpi, 'Metrics.dpi=', Metrics.dpi) Window.bind(on_request_close=self.on_close) Window.bind(on_rotate=self.on_rotate) Window.bind(size=self.device_info) diff --git a/kivyblocks/boxViewer.py b/kivyblocks/boxViewer.py index a6be19c..cec3d22 100755 --- a/kivyblocks/boxViewer.py +++ b/kivyblocks/boxViewer.py @@ -29,7 +29,7 @@ from kivy.graphics import Fbo, Color, Rectangle from kivy.properties import NumericProperty, StringProperty, DictProperty from .responsivelayout import VResponsiveLayout from .toolbar import Toolbar -from .paging import Paging, RelatedLoader +from .paging import RelatedLoader from .utils import CSize, SUPER from .ready import WidgetReady from .baseWidget import VBox diff --git a/kivyblocks/clickable.py b/kivyblocks/clickable.py index e9bf4c7..7256d97 100755 --- a/kivyblocks/clickable.py +++ b/kivyblocks/clickable.py @@ -3,6 +3,12 @@ from kivy.logger import Logger from kivy.uix.behaviors import TouchRippleButtonBehavior from kivy.graphics import Color, Rectangle from kivy.uix.boxlayout import BoxLayout +from kivy.uix.anchorlayout import AnchorLayout +from kivy.uix.floatlayout import FloatLayout +from kivy.uix.relativelayout import RelativeLayout +from kivy.uix.gridlayout import GridLayout +from kivy.uix.scatterlayout import ScatterLayout +from kivy.uix.stacklayout import StackLayout from kivy.factory import Factory from kivy.uix.image import AsyncImage from kivy.properties import NumericProperty, DictProperty, \ @@ -395,6 +401,34 @@ def build_cmdbox_view(desc, rec=None): x.setValue(vd) return x +class PressableAnchorLayout(TouchRippleButtonBehavior, AnchorLayout): + def on_press(self, o=None, d=None): + pass + +class PressableBoxLayout(TouchRippleButtonBehavior, BoxLayout): + def on_press(self, o=None, d=None): + pass + +class PressableFloatLayout(TouchRippleButtonBehavior, FloatLayout): + def on_press(self, o=None, d=None): + pass + +class PressableRelativeLayout(TouchRippleButtonBehavior, RelativeLayout): + def on_press(self, o=None, d=None): + pass + +class PressableGridLayout(TouchRippleButtonBehavior, GridLayout): + def on_press(self, o=None, d=None): + pass + +class PressableScatterLayout(TouchRippleButtonBehavior, ScatterLayout): + def on_press(self, o=None, d=None): + pass + +class PressableStackLayout(TouchRippleButtonBehavior, StackLayout): + def on_press(self, o=None, d=None): + pass + UiFactory.register('checkbox', build_checkbox, build_checkbox) UiFactory.register('cmdbox', build_cmdbox_view, build_cmdbox_view) @@ -409,3 +443,10 @@ r('ToggleText',ToggleText) r('ToggleIconText',ToggleIconText) r('ClickableImage',ClickableImage) r('ToggleImage',ToggleImage) +r('PressableAnchorLayout',PressableAnchorLayout) +r('PressableBoxLayout',PressableBoxLayout) +r('PressableFloatLayout',PressableFloatLayout) +r('PressableRelativeLayout',PressableRelativeLayout) +r('PressableGridLayout',PressableGridLayout) +r('PressableScatterLayout',PressableScatterLayout) +r('PressableStackLayout',PressableStackLayout) diff --git a/kivyblocks/container.py b/kivyblocks/container.py index a41228c..70b2c9d 100644 --- a/kivyblocks/container.py +++ b/kivyblocks/container.py @@ -1,7 +1,12 @@ # container is ScrollView with a dataloader -from kivy.uix.scrollview import ScroppView -from kivy.properties import DictProperty, ListProperty, BooleanProperty -from .paging import Paging, RelatedLoader +import json +from appPublic.myTE import MyTemplateEngine +from kivy.uix.scrollview import ScrollView +from kivy.properties import DictProperty, ListProperty, BooleanProperty, StringProperty, NumericProperty +from kivy.clock import Clock +from kivyblocks.blocks import Blocks +from kivyblocks.paging import RelatedLoader +from kivyblocks.widget_css import WidgetCSS class LayoutBuildFailed(Exception): def __init__(self, desc): @@ -13,7 +18,7 @@ class LayoutBuildFailed(Exception): def __expr__(self): return str(self) -class Container(ScrollView): +class Container(WidgetCSS, ScrollView): """ "loader":{ "page":1, @@ -24,43 +29,118 @@ class Container(ScrollView): } }, """ + idField = StringProperty('id') loader = DictProperty({}) data = ListProperty(None) layout = DictProperty({}) viewer = DictProperty({}) + min_threhold = NumericProperty(0.01) + max_htrehold = NumericProperty(0.99) extend_x = BooleanProperty(False) content = None def __init__(self, **kw): + self.dataloader = None + self.engine = MyTemplateEngine('.') + self.id_widget = {} super(Container, self).__init__(**kw) - self.content = Blocks.widgetBuild(self.layout, self) + self.content = Blocks().widgetBuild(self.layout) if not self.content: raise LayoutBuildFailed if self.do_scroll_x: - self.content.bind(minimum_height=layout.setter('width')) + self.content.bind(minimum_width=self.content.setter('width')) if self.do_scroll_y: - self.content.bind(minimum_height=layout.setter('height')) - super().add_widget(self.content) - self.dataloader = RelatedLoader(target=self, **self.loader) - self.dataloader.bind(on_deletepage=self.delete_page) - self.dataloader.bind(on_pageloaded=self.add_page) - self.dataloader.bind(on_pageloaded=self.update_tailer_info) - self.dataloader.bind(on_newbegin=self.clearRows) + self.content.bind(minimum_height=self.content.setter('height')) + self.add_widget(self.content) + self.viewer_tmpl = json.dumps(self.viewer) + self.bind(on_scroll_stop = self.on_scrollstop) + if self.data: + d = { + "dir":"down", + "rows":self.data, + "total":len(self.data) + } + self.add_page(d) + + if self.loader: + self.dataloader = RelatedLoader(target=self, **self.loader) + self.dataloader.bind(on_deletepage=self.delete_page) + self.dataloader.bind(on_pageloaded=self.add_page) + self.dataloader.bind(on_newbegin=self.clear_records) + Clock.schedule_once(self.loadData, 0.5) - def delete_page(self, ): - def add_page(self, ): - def clear_records(self, ): + def print_info(self, *args): + print(f"{self.scroll_distance=}, {self.scroll_timeout=}, {self.do_scroll_x=} {self.do_scroll_y=}, {self.scroll_x=}, {self.scroll_y=}, {self.content.size=}") - def add_widget(self, w, index=0): - return self.content.add_widget(w,index=index) - - def remove_widget(self, w): - return self.content.remove_widget(w) - - def clear_widgets(self): - return self.content.clear_widgets() - - def add_data(self, row_data): - desc = self.transfer(row_data) - w = Blocks.widgetBuild(desc) + def parse_viewer(self, rec): + return json.loads(self.engine.renders(self.viewer_tmpl, rec)) + + def loadData(self, *args, **kw): + kw['page'] = 1 + self.dataloader.do_search(None,kw) + + def add_record(self, rec, tail=True): + desc = self.parse_viewer(rec) + w = Blocks().widgetBuild(desc) if w: - self.add_widget(w) + idx = 0 + if not tail: + idx = -1 + id = rec.get(self.idField) + self.id_widget[id] = w + self.content.add_widget(w, index=idx) + else: + print(f'create widget error {self.viewer_tmpl=}, {rec=}') + + def delete_record(self, rec): + id = rec.get(self.idField) + w = self.id_widget.get(id) + if w: + self.content.remove_widget(w) + del self.id_widget[id] + + def delete_page(self, o, d): + # print(f'delete_page():{o=}, {d=}') + for r in d: + self.delete_record(r) + + def add_page(self, o, d): + # print(f'add_page():{o=},{d=}') + dir = d.get('dir', 'down') + recs = d.get('data', []) + tail = True + if dir != 'down': + tail = False + recs.reverse() + + for r in recs: + self.add_record(r, tail=tail) + if self.extend_x: + self.scroll_x = d['locator'] + else: + self.scroll_y = d['locator'] + + def clear_records(self, o): + # print(f'clear_records():{o=}') + self.content.clear_widgets() + self.id_Widget = {} + + def on_scrollstop(self, o, d=None): + if self.dataloader is None: + return + if self.extend_x: + if self.scroll_x < self.min_threhold: + self.dataloader.loadNextPage() + if self.scroll_x > self.max_htrehold: + self.dataloader.loadPreviousPage() + print('return here ...') + return + if self.dataloader.loading: + print('loading is True') + return + if self.scroll_y < self.min_threhold: + print('load next page ...') + self.dataloader.loadNextPage() + if self.scroll_y > self.max_htrehold: + print('load previous page ...') + self.dataloader.loadPreviousPage() + diff --git a/kivyblocks/defaultimage.py b/kivyblocks/defaultimage.py index ef2354d..8b1008a 100755 --- a/kivyblocks/defaultimage.py +++ b/kivyblocks/defaultimage.py @@ -1,3 +1,4 @@ +import os from kivy.uix.image import AsyncImage from kivy.factory import Factory from kivy.properties import StringProperty diff --git a/kivyblocks/eventhandler.py b/kivyblocks/eventhandler.py index 9f07f54..37dc6c8 100644 --- a/kivyblocks/eventhandler.py +++ b/kivyblocks/eventhandler.py @@ -1,11 +1,11 @@ import inspect import asyncio -from functools improt wraps +from functools import wraps def eventhandler(func): @wraps(func) def wrapper_func(*args, **kw): - if inspect.inspect.iscoroutinefunction(func): + if inspect.iscoroutinefunction(func): return asyncio.gather(func(*args, **kw)) return func(*args, **kw) return wrapper_func diff --git a/kivyblocks/i18n.py b/kivyblocks/i18n.py index 5ad2fc5..1b35731 100755 --- a/kivyblocks/i18n.py +++ b/kivyblocks/i18n.py @@ -58,9 +58,12 @@ class I18n: if config.i18n_url: url = '%s%s' % (config.uihome, config.i18n_url) hc = HttpClient() - d = hc.get(url) - if isinstance(d, list): - return d + try: + d = hc.get(url) + if isinstance(d, list): + return d + except: + pass return [] def loadI18n(self,lang): @@ -74,9 +77,12 @@ class I18n: if config.i18n_url: url = '%s%s/%s' % (config.uihome, config.i18n_url, lang) hc = HttpClient() - d = hc.get(url) - print('i18n() %s get data=' % url, d, type(d)) - self.kvlang[lang] = d + try: + d = hc.get(url) + print('i18n() %s get data=' % url, d, type(d)) + self.kvlang[lang] = d + except: + pass def __call__(self,msg,lang=None): if lang is None: diff --git a/kivyblocks/imgs/.DS_Store b/kivyblocks/imgs/.DS_Store index 90b7b93..7f6403d 100755 Binary files a/kivyblocks/imgs/.DS_Store and b/kivyblocks/imgs/.DS_Store differ diff --git a/kivyblocks/imgs/add.png b/kivyblocks/imgs/add.png new file mode 100644 index 0000000..92c7aa4 Binary files /dev/null and b/kivyblocks/imgs/add.png differ diff --git a/kivyblocks/imgs/delete.png b/kivyblocks/imgs/delete.png old mode 100755 new mode 100644 index 4f1f30a..fd447fb Binary files a/kivyblocks/imgs/delete.png and b/kivyblocks/imgs/delete.png differ diff --git a/kivyblocks/imgs/deletex.png b/kivyblocks/imgs/deletex.png new file mode 100755 index 0000000..4f1f30a Binary files /dev/null and b/kivyblocks/imgs/deletex.png differ diff --git a/kivyblocks/imgs/lensid.png b/kivyblocks/imgs/lensid.png new file mode 100755 index 0000000..3a0e0c7 Binary files /dev/null and b/kivyblocks/imgs/lensid.png differ diff --git a/kivyblocks/pagepanel.py b/kivyblocks/pagepanel.py index 93c4aa5..a151474 100755 --- a/kivyblocks/pagepanel.py +++ b/kivyblocks/pagepanel.py @@ -177,6 +177,8 @@ sub-widget's description file format self.left_menu = Factory.Blocks().widgetBuild(left_menu) self.sub_widgets = [] VBox.__init__(self, **kw) + app = App.get_running_app() + print('========================barsize=', CSize(bar_size), bar_size, app.font_size) self.bar = HBox(size_hint_y=None, csscls=bar_css, spacing=CSize(bar_size/6), diff --git a/kivyblocks/paging.py b/kivyblocks/paging.py index 49af829..f6f395a 100755 --- a/kivyblocks/paging.py +++ b/kivyblocks/paging.py @@ -17,28 +17,6 @@ from .dataloader import UrlDataLoader from .dataloader import ListDataLoader from .dataloader import RegisterFunctionDataLoader -class PagingButton(Button): - def __init__(self, **kw): - super().__init__(**kw) - self.size_hint = (None,None) - self.size = CSize(2,1.8) - self.font_size = CSize(1) - -""" -{ - dataurl - params - method - locater - filter -} - -PageLoader load data in a page size once. -it fires two type of event -'on_newbegin':fire when start a new parameters loading series -'on_pageloaded':fire when a page data loads success -""" - class PageLoader(EventDispatcher): def __init__(self,target=None, **options): self.loading = False @@ -113,11 +91,11 @@ class PageLoader(EventDispatcher): p += 1 self.total_cnt = d['total'] self.calculateTotalPage() - d = { + d.update( { "page":self.curpage, + "data":d['rows'], "dir":self.dir, - "data":d['rows'] - } + }) self.dispatch('on_pageloaded',d) self.loading = False @@ -129,10 +107,10 @@ class PageLoader(EventDispatcher): def loadNextPage(self): if self.loading: print('is loading, return') - return + return -1 if self.total_page > 0 and self.curpage >=self.total_page: - return + return -1 p = self.curpage + 1 self.loadPage(p) @@ -163,39 +141,18 @@ class PageLoader(EventDispatcher): self.curpage = p self.loader.load() -""" -{ - adder, - remover - target, - locater, - dataurl, - params, - method, - filter -} -events: -'on_deletepage': erase - -""" class RelatedLoader(PageLoader): def __init__(self, **options): super().__init__(**options) self.objectPages = {} self.totalObj = 0 self.MaxbufferPage = 3 - self.locater = 1/self.MaxbufferPage - if self.filter: - self.widget = self.filter - else: - self.widget = None + self.buffered_pages = 0 self.register_event_type('on_deletepage') def do_search(self,o,params): self.objectPages = {} self.totalObj = 0 - self.MaxbufferPage = 3 - self.locater = 1/self.MaxbufferPage super().do_search(o, params) def getLocater(self): @@ -216,13 +173,15 @@ class RelatedLoader(PageLoader): self.calculateTotalPage() def doBufferMaintain(self): - siz = len(self.objectPages.keys()) - if siz >= self.MaxbufferPage: + siz = len([k for k in self.objectPages.keys()]) + self.buffered_pages = siz + if siz > self.MaxbufferPage: if self.dir == 'up': p = max(self.objectPages.keys()) else: p = min(self.objectPages.keys()) self.deleteBuffer(p) + self.buffered_pages = self.MaxbufferPage def deleteBuffer(self,page): d = self.objectPages[page] @@ -237,18 +196,25 @@ class RelatedLoader(PageLoader): def show_page(self,o,data): if self.objectPages.get(self.curpage): self.deleteBuffer(self.curpage) - else: - self.doBufferMaintain() + self.bufferObjects(self.curpage, data['rows']) + self.doBufferMaintain() self.totalObj += len(data['rows']) + if self.dir == 'down': + data['locator'] = 1/self.buffered_pages + else: + data['locator'] = 1 - 1/self.buffered_pages + super().show_page(o,data) def loadPreviousPage(self): pages = self.objectPages.keys() if len(pages) < 1: + print('self.objectPages is null') return page = min(pages) if page <= 1: + print('page < 1') return page -= 1 @@ -257,68 +223,12 @@ class RelatedLoader(PageLoader): def loadNextPage(self): pages = self.objectPages.keys() if len(pages) == 0: + print('self.objectPages is null') return page = max(pages) if page>=self.total_page: + print('page > total page') return page += 1 self.loadPage(page) -""" -{ - adder, - clearer - target, - dataurl - params, - method -} -""" -class Paging(PageLoader): - def __init__(self,**options): - PageLoader.__init__(self,**options) - self.target = options.get('target') - self.init() - - def init(self): - kwargs = {} - kwargs['size_hint_y'] = None - kwargs['height'] = CSize(2) - kwargs['orientation'] = 'horizontal' - kwargs['spacing'] = CSize(1) - self.widget = BoxLayout(**kwargs) - self.b_f = PagingButton(text="|<") - self.b_p = PagingButton(text="<") - self.b_n = PagingButton(text=">") - self.b_l = PagingButton(text=">|") - self.b_f.bind(on_press=self.loadFirstPage) - self.b_p.bind(on_press=self.loadPreviousPage) - self.b_n.bind(on_press=self.loadNextPage) - self.b_l.bind(on_press=self.loadLastPage) - self.widget.add_widget(self.b_f) - self.widget.add_widget(self.b_p) - self.widget.add_widget(self.b_n) - self.widget.add_widget(self.b_l) - if self.filter: - self.widget.add_widget(self.filter) - - def loadFirstPage(self,o=None): - if self.curpage == 1: - return - self.loadPage(1) - - def loadPreviousPage(self,o=None): - if self.curpage < 2: - return - self.loadPage(self.curpage-1) - - def loadNextPage(self,o=None): - if self.curpage >= self.total_page: - return - self.loadPage(self.curpage+1) - - def loadLastPage(self,o=None): - if self.curpage >= self.total_page: - return - self.loadPage(self.total_page) - diff --git a/kivyblocks/register.py b/kivyblocks/register.py index 77c8d61..9f1c87c 100755 --- a/kivyblocks/register.py +++ b/kivyblocks/register.py @@ -8,6 +8,7 @@ import kivyblocks.clickable import kivyblocks.multi_select from .baseWidget import * +from .container import Container from .tree import Tree, TextTree, MenuTree, PopupMenu from .toolbar import ToolPage, Toolbar from .dg import DataGrid @@ -53,6 +54,7 @@ from .landscopehide import LandscopeHide r = Factory.register # if kivy.platform in ['win','linux', 'macosx']: # r('ScreenWithMic', ScreenWithMic) +r('Container', Container) r('LandscopeHide', LandscopeHide) r('VideoBehavior', VideoBehavior) r('ModalBehavior', ModalBehavior) diff --git a/kivyblocks/scrollpanel.py b/kivyblocks/scrollpanel.py index fb3ab08..b8f2aab 100755 --- a/kivyblocks/scrollpanel.py +++ b/kivyblocks/scrollpanel.py @@ -6,8 +6,8 @@ from kivy.uix.widget import Widget from kivy.uix.boxlayout import BoxLayout from kivy.factory import Factory -from .utils import * -from .widget_css import WidgetCSS +from kivyblocks.utils import * +from kivyblocks.widget_css import WidgetCSS class ScrollPanel(WidgetCSS, ScrollView): orientation = OptionProperty('vertical', \ diff --git a/kivyblocks/tab.py b/kivyblocks/tab.py index 46f0054..d31520b 100755 --- a/kivyblocks/tab.py +++ b/kivyblocks/tab.py @@ -24,8 +24,8 @@ from appPublic.uniqueID import getID from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem from kivy.clock import Clock from kivy.factory import Factory -from .utils import SUPER -from .widget_css import WidgetCSS +from kivyblocks.utils import SUPER +from kivyblocks.widget_css import WidgetCSS class TabsPanel(WidgetCSS, TabbedPanel): def __init__(self, tabs=[], **options): @@ -33,26 +33,44 @@ class TabsPanel(WidgetCSS, TabbedPanel): SUPER(TabsPanel, self, options) # TabbedPanel.__init__(self,**options) # BGColorBehavior.__init__(self) + self.old_content = None + self.def_tab = None + self.register_event_type('on_content_show') + self.register_event_type('on_content_hide') Clock.schedule_once(self.add_tabs,0) - def newname(self): - return getID() - - def add_tab(self,name,text,desc): - def add(o,w): - if not hasattr(w,'widget_id'): - w.widget_id = name - self.add_widget(TabbedPanelItem(text=text,content=w)) + def add_tab(self,desc): + if not desc.get('name'): + desc['name'] = getID() blocks = Factory.Blocks() - blocks.bind(on_built=add) - blocks.widgetBuild(desc) + w = blocks.widgetBuild(desc['content']) + if w is None: + return + if not hasattr(w,'widget_id'): + w.widget_id = desc['name'] + item = TabbedPanelItem(text=desc['text'],content=w) + if desc.get('isdefault', False): + self.def_tab = item + self.add_widget(item) def add_tabs(self,*args): for d in self.tabs_list: - name = d.get('name',self.newname()) - text = d['text'] - desc = d['content'] - self.add_tab(name,text,desc) + self.add_tab(d) + if self.def_tab: + self.switch_to(self.def_tab) + self.bind(current_tab = self.content_changed) + + def content_changed(self, o, v=None): + if self.old_content: + self.dispatch('on_content_hide', self.old_content) + self.old_content = self.current_tab.content + self.dispatch('on_content_show', self.old_content) + + def on_content_show(self, *args): + print('content show', args) + + def on_content_hide(self, *args): + print('content hide', args) if __name__ == '__main__': from kivy.app import App diff --git a/kivyblocks/toolbar.py b/kivyblocks/toolbar.py index 1e248d5..389d4f9 100755 --- a/kivyblocks/toolbar.py +++ b/kivyblocks/toolbar.py @@ -221,6 +221,9 @@ class ToolPage(Box): self.orientation = 'vertical' else: self.orientation = 'horizontal' + self.current_sub_content = None + self.register_event_type('on_content_show') + self.register_event_type('on_content_hide') if not self.toolbar_size: self.toolbar_size = self.img_size + self.text_size + 0.3 self.content_widgets = {} @@ -259,6 +262,7 @@ class ToolPage(Box): def init(self): self.content_w = BoxLayout() + self.curr_sub_content = None self.content_w.widget_id = 'content' self.toolbar_w = Toolbar(**self.toolbar) if self.tool_at in ['top','left']: @@ -300,24 +304,37 @@ class ToolPage(Box): refresh = v.get('refresh', False) # self.print_all() + if self.current_sub_content: + self.dispatch('on_content_hide', self.current_sub_content) + w = self.content_widgets.get(name) self.content_w.clear_widgets() if w and not refresh: self.content_w.add_widget(w) - return - url = v.get('url') - if url: - w = self.build_widget(url) - if w: - self.content_widgets[name] = w - self.content_w.add_widget(w) - return - rfname = v.get('rfname') - if rfname: - rf = RegisterFunction() - f = rf.get(rfname) - if f: - r = f() - if isinstance(r,Widget): - self.content_w.add_widget(r) + else: + w = None + url = v.get('url') + if url: + w = self.build_widget(url) + if w: + self.content_widgets[name] = w + self.content_w.add_widget(w) + else: + rfname = v.get('rfname') + if rfname: + rf = RegisterFunction() + f = rf.get(rfname) + if f: + w = f() + if isinstance(w,Widget): + self.content_widgets[name] = w + self.content_w.add_widget(w) + if w: + self.current_sub_content = w + self.dispatch('on_content_show', w) + def on_content_show(self, content): + pass + + def on_content_hide(self, content): + pass diff --git a/kivyblocks/tree.py b/kivyblocks/tree.py index c185943..cd7f061 100755 --- a/kivyblocks/tree.py +++ b/kivyblocks/tree.py @@ -158,12 +158,28 @@ class TreeNode(BoxLayout): self.node_box1.width = width for n in self.nodes: n.setMinWidth(width) + def build_content(self): + self.buildContent() + x = self.content + cf = self.treeObj.checkField + if cf: + self.content = HBox(size_hint_y=None, + height=self.treeObj.rowHeight) + self.checkbox_w = CheckBox(active=self.data.get(cf, False) + self.content.add_widget(self.checkbox_w) + self.content.add_widget(x) + self.checkbox_w.bind(active=self.on_checkbox_active) + def on_checkbox_active(self, o, v): + cf = self.treeObj.checkField + self.data[cf] = v + self.treeObj.node_checkbox_changed(self) + def buildContent(self): pass def addContent(self): - self.buildContent() + self.build_content() self.node_box.add_widget(self.content) self.node_box.height = self.treeObj.rowheight self.node_box.width = self.trigger.width + \ @@ -304,8 +320,7 @@ tree options "single_expand", "select_leaf_only", "bgcolor", - "checkbox", - "multplecheck", + "checkField", "idField", "textFiled", "data" # array of {children:{},...} @@ -313,7 +328,7 @@ tree options """ class Tree(WidgetCSS, ScrollWidget): data = ListProperty([]) - def __init__(self, + def __init__(self,nodeKlass=TreeNode, url=None, params={}, single_expand=False, @@ -322,13 +337,13 @@ class Tree(WidgetCSS, ScrollWidget): normal_css="default", row_height=2, selected_css="selected", - checkbox=False, - multiplecheck=False, + checkField=None, idField='id', textField='text', data=None, **options): self.url = url + self.nodeKlass = nodeKlass self.params = params self.data = data self.single_expand=single_expand @@ -338,8 +353,7 @@ class Tree(WidgetCSS, ScrollWidget): self.bgcolor = bgcolor self.normal_css = normal_css self.selected_css = selected_css - self.checkbox = checkbox - self.multiplecheck = multiplecheck + self.checkFiled = checkField self.idField = idField self.textField = textField print('options=',options) @@ -351,6 +365,10 @@ class Tree(WidgetCSS, ScrollWidget): self.buildTree() self.bind(size=self.onSize,pos=self.onSize) self.register_event_type('on_press') + self.register_event_type('on_checked') + + def node_checkbox_changed(self, node): + self.dispatch('on_checked', node.data) def on_press(self,*larg): pass diff --git a/kivyblocks/utils.py b/kivyblocks/utils.py index b6e932f..608200b 100755 --- a/kivyblocks/utils.py +++ b/kivyblocks/utils.py @@ -194,8 +194,11 @@ def getWidgetById(w,id): return w.ids.get(id) def CSize(x,y=None,name=None): - ks = KivySizes() - return ks.CSize(x,y=y,name=name) + app = App.get_running_app() + r = app.font_size + if not y: + return r * x + return r * x, r * y def screenSize(): ks = KivySizes() diff --git a/kivyblocks/widgetExt/tree.py b/kivyblocks/widgetExt/tree.py deleted file mode 100755 index 44f3a81..0000000 --- a/kivyblocks/widgetExt/tree.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -tree description json format: -{ - "url":a http(s) url for get data, - "checkbox":boolean, show a checkbox before text - "data":if undefined url,use data to construct the tree - "params":parameters attached to the http(s) request via url - "headers":headers need to set for the http request via url - "height":widget 's height - "width":widget's width -} - -data structure : -{ - "id":identified field, - "widgettype":widget type, - ...other data... - "__children__":[ - ] -} -""" -from .scrollwidget import ScrollWidget -from kivy.uix.treeview import TreeView -