This commit is contained in:
yumoqing 2023-10-26 17:55:34 +08:00
parent 01442309d9
commit 9e2b5db1a6
23 changed files with 332 additions and 233 deletions

View File

@ -89,16 +89,6 @@ font_names = {
'title1':resource_find('Alimama_ShuHeiTi_Bold.ttf') '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': if platform == 'android':
from .widgetExt.phonebutton import PhoneButton from .widgetExt.phonebutton import PhoneButton
from .widgetExt.androidwebview import AWebView from .widgetExt.androidwebview import AWebView
@ -162,10 +152,12 @@ class SwipeBox(SwipeBehavior, Box):
class Text(Label): class Text(Label):
lang=StringProperty('') lang=StringProperty('')
otext = 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): 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) fontname = font_names.get(texttype)
self._i18n = i18n self._i18n = i18n
self.i18n = I18n() self.i18n = I18n()
@ -181,6 +173,8 @@ class Text(Label):
kwargs['text'] = kwargs.get('otext','') kwargs['text'] = kwargs.get('otext','')
super(Text, self).__init__(**kwargs) super(Text, self).__init__(**kwargs)
app.bind(font_size=self.reset_font_size)
# self.bind(texture_size=self.setter('size'))
if self._i18n: if self._i18n:
self.i18n.addI18nWidget(self) self.i18n.addI18nWidget(self)
if self.wrap: if self.wrap:
@ -190,6 +184,9 @@ class Text(Label):
if self.bgcolor: if self.bgcolor:
self.color = self.bgcolor self.color = self.bgcolor
def reset_font_size(self, app, fsize):
self.font_size = fsize * self.rate
def resize(self, *args): def resize(self, *args):
if not self.size_hint_y: if not self.size_hint_y:
ps = [0,0,0,0] ps = [0,0,0,0]

View File

@ -214,7 +214,14 @@ x = ClassX{klass_cnt}()
print_exc() print_exc()
if errback: if errback:
return errback(None,e) return errback(None,e)
return None return {
"widgettype":"Text",
"options":{
"text":f"{url=} error",
"wrap":True,
"halign":"left"
}
}
else: else:
config = getConfig() config = getConfig()
url = config.uihome + url url = config.uihome + url
@ -727,7 +734,7 @@ x = ClassX{klass_cnt}()
print('Block3: desc must be a dict object not None') print('Block3: desc must be a dict object not None')
return None return None
w = doit(desc) w = doit(desc)
print('widgetBuild():w=', w) # print('widgetBuild():w=', w)
return w return w
@classmethod @classmethod
@ -769,7 +776,7 @@ x = ClassX{klass_cnt}()
children = [i for i in from_widget.children] children = [i for i in from_widget.children]
if hasattr(from_widget, 'get_subwidgets'): if hasattr(from_widget, 'get_subwidgets'):
children = 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: for c in children:
ret = _find_widget(name, from_widget=c, dir=dir) ret = _find_widget(name, from_widget=c, dir=dir)
if ret: if ret:

View File

@ -12,6 +12,7 @@ from appPublic.folderUtils import ProgramPath
from appPublic.uniqueID import getID from appPublic.uniqueID import getID
from appPublic.rsawrap import RSA from appPublic.rsawrap import RSA
from kivy.properties import NumericProperty
from kivy.factory import Factory from kivy.factory import Factory
from kivy.metrics import sp,dp,mm from kivy.metrics import sp,dp,mm
from kivy.core.window import WindowBase, Window from kivy.core.window import WindowBase, Window
@ -48,6 +49,7 @@ signal.signal(signal.SIGINT, signal_handler)
class BlocksApp(App): class BlocksApp(App):
font_size = NumericProperty(24)
def get_rotation(self): def get_rotation(self):
return get_rotation() return get_rotation()
@ -78,7 +80,26 @@ class BlocksApp(App):
if isinstance(v,dict): if isinstance(v,dict):
register_css(k,v) 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): def build(self):
tl = Label(text='test')
self.font_size = tl.font_size
print('##################app_font_size=', self.font_size)
config = getConfig() config = getConfig()
self.workers = Workers(maxworkers=config.maxworkers or 80) self.workers = Workers(maxworkers=config.maxworkers or 80)
self.workers.start() self.workers.start()
@ -93,10 +114,10 @@ class BlocksApp(App):
self.default_params.update(config.default_params) self.default_params.update(config.default_params)
self.public_headers = { self.public_headers = {
"client_uuid":getID(),
"platform":self.platform "platform":self.platform
} }
# Window.borderless = True # Window.borderless = True
print('Window.dpi=', Window.dpi, 'Metrics.dpi=', Metrics.dpi)
Window.bind(on_request_close=self.on_close) Window.bind(on_request_close=self.on_close)
Window.bind(on_rotate=self.on_rotate) Window.bind(on_rotate=self.on_rotate)
Window.bind(size=self.device_info) Window.bind(size=self.device_info)

View File

@ -29,7 +29,7 @@ from kivy.graphics import Fbo, Color, Rectangle
from kivy.properties import NumericProperty, StringProperty, DictProperty from kivy.properties import NumericProperty, StringProperty, DictProperty
from .responsivelayout import VResponsiveLayout from .responsivelayout import VResponsiveLayout
from .toolbar import Toolbar from .toolbar import Toolbar
from .paging import Paging, RelatedLoader from .paging import RelatedLoader
from .utils import CSize, SUPER from .utils import CSize, SUPER
from .ready import WidgetReady from .ready import WidgetReady
from .baseWidget import VBox from .baseWidget import VBox

View File

@ -3,6 +3,12 @@ from kivy.logger import Logger
from kivy.uix.behaviors import TouchRippleButtonBehavior from kivy.uix.behaviors import TouchRippleButtonBehavior
from kivy.graphics import Color, Rectangle from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout 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.factory import Factory
from kivy.uix.image import AsyncImage from kivy.uix.image import AsyncImage
from kivy.properties import NumericProperty, DictProperty, \ from kivy.properties import NumericProperty, DictProperty, \
@ -395,6 +401,34 @@ def build_cmdbox_view(desc, rec=None):
x.setValue(vd) x.setValue(vd)
return x 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('checkbox', build_checkbox, build_checkbox)
UiFactory.register('cmdbox', build_cmdbox_view, build_cmdbox_view) UiFactory.register('cmdbox', build_cmdbox_view, build_cmdbox_view)
@ -409,3 +443,10 @@ r('ToggleText',ToggleText)
r('ToggleIconText',ToggleIconText) r('ToggleIconText',ToggleIconText)
r('ClickableImage',ClickableImage) r('ClickableImage',ClickableImage)
r('ToggleImage',ToggleImage) r('ToggleImage',ToggleImage)
r('PressableAnchorLayout',PressableAnchorLayout)
r('PressableBoxLayout',PressableBoxLayout)
r('PressableFloatLayout',PressableFloatLayout)
r('PressableRelativeLayout',PressableRelativeLayout)
r('PressableGridLayout',PressableGridLayout)
r('PressableScatterLayout',PressableScatterLayout)
r('PressableStackLayout',PressableStackLayout)

View File

@ -1,7 +1,12 @@
# container is ScrollView with a dataloader # container is ScrollView with a dataloader
from kivy.uix.scrollview import ScroppView import json
from kivy.properties import DictProperty, ListProperty, BooleanProperty from appPublic.myTE import MyTemplateEngine
from .paging import Paging, RelatedLoader 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): class LayoutBuildFailed(Exception):
def __init__(self, desc): def __init__(self, desc):
@ -13,7 +18,7 @@ class LayoutBuildFailed(Exception):
def __expr__(self): def __expr__(self):
return str(self) return str(self)
class Container(ScrollView): class Container(WidgetCSS, ScrollView):
""" """
"loader":{ "loader":{
"page":1, "page":1,
@ -24,43 +29,118 @@ class Container(ScrollView):
} }
}, },
""" """
idField = StringProperty('id')
loader = DictProperty({}) loader = DictProperty({})
data = ListProperty(None) data = ListProperty(None)
layout = DictProperty({}) layout = DictProperty({})
viewer = DictProperty({}) viewer = DictProperty({})
min_threhold = NumericProperty(0.01)
max_htrehold = NumericProperty(0.99)
extend_x = BooleanProperty(False) extend_x = BooleanProperty(False)
content = None content = None
def __init__(self, **kw): def __init__(self, **kw):
self.dataloader = None
self.engine = MyTemplateEngine('.')
self.id_widget = {}
super(Container, self).__init__(**kw) super(Container, self).__init__(**kw)
self.content = Blocks.widgetBuild(self.layout, self) self.content = Blocks().widgetBuild(self.layout)
if not self.content: if not self.content:
raise LayoutBuildFailed raise LayoutBuildFailed
if self.do_scroll_x: 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: if self.do_scroll_y:
self.content.bind(minimum_height=layout.setter('height')) self.content.bind(minimum_height=self.content.setter('height'))
super().add_widget(self.content) self.add_widget(self.content)
self.dataloader = RelatedLoader(target=self, **self.loader) self.viewer_tmpl = json.dumps(self.viewer)
self.dataloader.bind(on_deletepage=self.delete_page) self.bind(on_scroll_stop = self.on_scrollstop)
self.dataloader.bind(on_pageloaded=self.add_page) if self.data:
self.dataloader.bind(on_pageloaded=self.update_tailer_info) d = {
self.dataloader.bind(on_newbegin=self.clearRows) "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 print_info(self, *args):
def add_page(self, ): 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 clear_records(self, ):
def add_widget(self, w, index=0): def parse_viewer(self, rec):
return self.content.add_widget(w,index=index) return json.loads(self.engine.renders(self.viewer_tmpl, rec))
def remove_widget(self, w): def loadData(self, *args, **kw):
return self.content.remove_widget(w) kw['page'] = 1
self.dataloader.do_search(None,kw)
def clear_widgets(self):
return self.content.clear_widgets() def add_record(self, rec, tail=True):
desc = self.parse_viewer(rec)
def add_data(self, row_data): w = Blocks().widgetBuild(desc)
desc = self.transfer(row_data)
w = Blocks.widgetBuild(desc)
if w: 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()

View File

@ -1,3 +1,4 @@
import os
from kivy.uix.image import AsyncImage from kivy.uix.image import AsyncImage
from kivy.factory import Factory from kivy.factory import Factory
from kivy.properties import StringProperty from kivy.properties import StringProperty

View File

@ -1,11 +1,11 @@
import inspect import inspect
import asyncio import asyncio
from functools improt wraps from functools import wraps
def eventhandler(func): def eventhandler(func):
@wraps(func) @wraps(func)
def wrapper_func(*args, **kw): def wrapper_func(*args, **kw):
if inspect.inspect.iscoroutinefunction(func): if inspect.iscoroutinefunction(func):
return asyncio.gather(func(*args, **kw)) return asyncio.gather(func(*args, **kw))
return func(*args, **kw) return func(*args, **kw)
return wrapper_func return wrapper_func

View File

@ -58,9 +58,12 @@ class I18n:
if config.i18n_url: if config.i18n_url:
url = '%s%s' % (config.uihome, config.i18n_url) url = '%s%s' % (config.uihome, config.i18n_url)
hc = HttpClient() hc = HttpClient()
d = hc.get(url) try:
if isinstance(d, list): d = hc.get(url)
return d if isinstance(d, list):
return d
except:
pass
return [] return []
def loadI18n(self,lang): def loadI18n(self,lang):
@ -74,9 +77,12 @@ class I18n:
if config.i18n_url: if config.i18n_url:
url = '%s%s/%s' % (config.uihome, config.i18n_url, lang) url = '%s%s/%s' % (config.uihome, config.i18n_url, lang)
hc = HttpClient() hc = HttpClient()
d = hc.get(url) try:
print('i18n() %s get data=' % url, d, type(d)) d = hc.get(url)
self.kvlang[lang] = d print('i18n() %s get data=' % url, d, type(d))
self.kvlang[lang] = d
except:
pass
def __call__(self,msg,lang=None): def __call__(self,msg,lang=None):
if lang is None: if lang is None:

Binary file not shown.

BIN
kivyblocks/imgs/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
kivyblocks/imgs/delete.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

BIN
kivyblocks/imgs/deletex.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
kivyblocks/imgs/lensid.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -177,6 +177,8 @@ sub-widget's description file format
self.left_menu = Factory.Blocks().widgetBuild(left_menu) self.left_menu = Factory.Blocks().widgetBuild(left_menu)
self.sub_widgets = [] self.sub_widgets = []
VBox.__init__(self, **kw) 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, self.bar = HBox(size_hint_y=None,
csscls=bar_css, csscls=bar_css,
spacing=CSize(bar_size/6), spacing=CSize(bar_size/6),

View File

@ -17,28 +17,6 @@ from .dataloader import UrlDataLoader
from .dataloader import ListDataLoader from .dataloader import ListDataLoader
from .dataloader import RegisterFunctionDataLoader 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): class PageLoader(EventDispatcher):
def __init__(self,target=None, **options): def __init__(self,target=None, **options):
self.loading = False self.loading = False
@ -113,11 +91,11 @@ class PageLoader(EventDispatcher):
p += 1 p += 1
self.total_cnt = d['total'] self.total_cnt = d['total']
self.calculateTotalPage() self.calculateTotalPage()
d = { d.update( {
"page":self.curpage, "page":self.curpage,
"data":d['rows'],
"dir":self.dir, "dir":self.dir,
"data":d['rows'] })
}
self.dispatch('on_pageloaded',d) self.dispatch('on_pageloaded',d)
self.loading = False self.loading = False
@ -129,10 +107,10 @@ class PageLoader(EventDispatcher):
def loadNextPage(self): def loadNextPage(self):
if self.loading: if self.loading:
print('is loading, return') print('is loading, return')
return return -1
if self.total_page > 0 and self.curpage >=self.total_page: if self.total_page > 0 and self.curpage >=self.total_page:
return return -1
p = self.curpage + 1 p = self.curpage + 1
self.loadPage(p) self.loadPage(p)
@ -163,39 +141,18 @@ class PageLoader(EventDispatcher):
self.curpage = p self.curpage = p
self.loader.load() self.loader.load()
"""
{
adder,
remover
target,
locater,
dataurl,
params,
method,
filter
}
events:
'on_deletepage': erase
"""
class RelatedLoader(PageLoader): class RelatedLoader(PageLoader):
def __init__(self, **options): def __init__(self, **options):
super().__init__(**options) super().__init__(**options)
self.objectPages = {} self.objectPages = {}
self.totalObj = 0 self.totalObj = 0
self.MaxbufferPage = 3 self.MaxbufferPage = 3
self.locater = 1/self.MaxbufferPage self.buffered_pages = 0
if self.filter:
self.widget = self.filter
else:
self.widget = None
self.register_event_type('on_deletepage') self.register_event_type('on_deletepage')
def do_search(self,o,params): def do_search(self,o,params):
self.objectPages = {} self.objectPages = {}
self.totalObj = 0 self.totalObj = 0
self.MaxbufferPage = 3
self.locater = 1/self.MaxbufferPage
super().do_search(o, params) super().do_search(o, params)
def getLocater(self): def getLocater(self):
@ -216,13 +173,15 @@ class RelatedLoader(PageLoader):
self.calculateTotalPage() self.calculateTotalPage()
def doBufferMaintain(self): def doBufferMaintain(self):
siz = len(self.objectPages.keys()) siz = len([k for k in self.objectPages.keys()])
if siz >= self.MaxbufferPage: self.buffered_pages = siz
if siz > self.MaxbufferPage:
if self.dir == 'up': if self.dir == 'up':
p = max(self.objectPages.keys()) p = max(self.objectPages.keys())
else: else:
p = min(self.objectPages.keys()) p = min(self.objectPages.keys())
self.deleteBuffer(p) self.deleteBuffer(p)
self.buffered_pages = self.MaxbufferPage
def deleteBuffer(self,page): def deleteBuffer(self,page):
d = self.objectPages[page] d = self.objectPages[page]
@ -237,18 +196,25 @@ class RelatedLoader(PageLoader):
def show_page(self,o,data): def show_page(self,o,data):
if self.objectPages.get(self.curpage): if self.objectPages.get(self.curpage):
self.deleteBuffer(self.curpage) self.deleteBuffer(self.curpage)
else: self.bufferObjects(self.curpage, data['rows'])
self.doBufferMaintain() self.doBufferMaintain()
self.totalObj += len(data['rows']) 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) super().show_page(o,data)
def loadPreviousPage(self): def loadPreviousPage(self):
pages = self.objectPages.keys() pages = self.objectPages.keys()
if len(pages) < 1: if len(pages) < 1:
print('self.objectPages is null')
return return
page = min(pages) page = min(pages)
if page <= 1: if page <= 1:
print('page < 1')
return return
page -= 1 page -= 1
@ -257,68 +223,12 @@ class RelatedLoader(PageLoader):
def loadNextPage(self): def loadNextPage(self):
pages = self.objectPages.keys() pages = self.objectPages.keys()
if len(pages) == 0: if len(pages) == 0:
print('self.objectPages is null')
return return
page = max(pages) page = max(pages)
if page>=self.total_page: if page>=self.total_page:
print('page > total page')
return return
page += 1 page += 1
self.loadPage(page) 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)

View File

@ -8,6 +8,7 @@ import kivyblocks.clickable
import kivyblocks.multi_select import kivyblocks.multi_select
from .baseWidget import * from .baseWidget import *
from .container import Container
from .tree import Tree, TextTree, MenuTree, PopupMenu from .tree import Tree, TextTree, MenuTree, PopupMenu
from .toolbar import ToolPage, Toolbar from .toolbar import ToolPage, Toolbar
from .dg import DataGrid from .dg import DataGrid
@ -53,6 +54,7 @@ from .landscopehide import LandscopeHide
r = Factory.register r = Factory.register
# if kivy.platform in ['win','linux', 'macosx']: # if kivy.platform in ['win','linux', 'macosx']:
# r('ScreenWithMic', ScreenWithMic) # r('ScreenWithMic', ScreenWithMic)
r('Container', Container)
r('LandscopeHide', LandscopeHide) r('LandscopeHide', LandscopeHide)
r('VideoBehavior', VideoBehavior) r('VideoBehavior', VideoBehavior)
r('ModalBehavior', ModalBehavior) r('ModalBehavior', ModalBehavior)

View File

@ -6,8 +6,8 @@ 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 .utils import * from kivyblocks.utils import *
from .widget_css import WidgetCSS from kivyblocks.widget_css import WidgetCSS
class ScrollPanel(WidgetCSS, ScrollView): class ScrollPanel(WidgetCSS, ScrollView):
orientation = OptionProperty('vertical', \ orientation = OptionProperty('vertical', \

View File

@ -24,8 +24,8 @@ from appPublic.uniqueID import getID
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
from kivy.clock import Clock from kivy.clock import Clock
from kivy.factory import Factory from kivy.factory import Factory
from .utils import SUPER from kivyblocks.utils import SUPER
from .widget_css import WidgetCSS from kivyblocks.widget_css import WidgetCSS
class TabsPanel(WidgetCSS, TabbedPanel): class TabsPanel(WidgetCSS, TabbedPanel):
def __init__(self, tabs=[], **options): def __init__(self, tabs=[], **options):
@ -33,26 +33,44 @@ class TabsPanel(WidgetCSS, TabbedPanel):
SUPER(TabsPanel, self, options) SUPER(TabsPanel, self, options)
# TabbedPanel.__init__(self,**options) # TabbedPanel.__init__(self,**options)
# BGColorBehavior.__init__(self) # 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) Clock.schedule_once(self.add_tabs,0)
def newname(self): def add_tab(self,desc):
return getID() if not desc.get('name'):
desc['name'] = 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))
blocks = Factory.Blocks() blocks = Factory.Blocks()
blocks.bind(on_built=add) w = blocks.widgetBuild(desc['content'])
blocks.widgetBuild(desc) 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): def add_tabs(self,*args):
for d in self.tabs_list: for d in self.tabs_list:
name = d.get('name',self.newname()) self.add_tab(d)
text = d['text'] if self.def_tab:
desc = d['content'] self.switch_to(self.def_tab)
self.add_tab(name,text,desc) 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__': if __name__ == '__main__':
from kivy.app import App from kivy.app import App

View File

@ -221,6 +221,9 @@ class ToolPage(Box):
self.orientation = 'vertical' self.orientation = 'vertical'
else: else:
self.orientation = 'horizontal' 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: if not self.toolbar_size:
self.toolbar_size = self.img_size + self.text_size + 0.3 self.toolbar_size = self.img_size + self.text_size + 0.3
self.content_widgets = {} self.content_widgets = {}
@ -259,6 +262,7 @@ class ToolPage(Box):
def init(self): def init(self):
self.content_w = BoxLayout() self.content_w = BoxLayout()
self.curr_sub_content = None
self.content_w.widget_id = 'content' self.content_w.widget_id = 'content'
self.toolbar_w = Toolbar(**self.toolbar) self.toolbar_w = Toolbar(**self.toolbar)
if self.tool_at in ['top','left']: if self.tool_at in ['top','left']:
@ -300,24 +304,37 @@ class ToolPage(Box):
refresh = v.get('refresh', False) refresh = v.get('refresh', False)
# self.print_all() # self.print_all()
if self.current_sub_content:
self.dispatch('on_content_hide', self.current_sub_content)
w = self.content_widgets.get(name) w = self.content_widgets.get(name)
self.content_w.clear_widgets() self.content_w.clear_widgets()
if w and not refresh: if w and not refresh:
self.content_w.add_widget(w) self.content_w.add_widget(w)
return else:
url = v.get('url') w = None
if url: url = v.get('url')
w = self.build_widget(url) if url:
if w: w = self.build_widget(url)
self.content_widgets[name] = w if w:
self.content_w.add_widget(w) self.content_widgets[name] = w
return self.content_w.add_widget(w)
rfname = v.get('rfname') else:
if rfname: rfname = v.get('rfname')
rf = RegisterFunction() if rfname:
f = rf.get(rfname) rf = RegisterFunction()
if f: f = rf.get(rfname)
r = f() if f:
if isinstance(r,Widget): w = f()
self.content_w.add_widget(r) 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

View File

@ -158,12 +158,28 @@ class TreeNode(BoxLayout):
self.node_box1.width = width self.node_box1.width = width
for n in self.nodes: for n in self.nodes:
n.setMinWidth(width) 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): def buildContent(self):
pass pass
def addContent(self): def addContent(self):
self.buildContent() self.build_content()
self.node_box.add_widget(self.content) self.node_box.add_widget(self.content)
self.node_box.height = self.treeObj.rowheight self.node_box.height = self.treeObj.rowheight
self.node_box.width = self.trigger.width + \ self.node_box.width = self.trigger.width + \
@ -304,8 +320,7 @@ tree options
"single_expand", "single_expand",
"select_leaf_only", "select_leaf_only",
"bgcolor", "bgcolor",
"checkbox", "checkField",
"multplecheck",
"idField", "idField",
"textFiled", "textFiled",
"data" # array of {children:{},...} "data" # array of {children:{},...}
@ -313,7 +328,7 @@ tree options
""" """
class Tree(WidgetCSS, ScrollWidget): class Tree(WidgetCSS, ScrollWidget):
data = ListProperty([]) data = ListProperty([])
def __init__(self, def __init__(self,nodeKlass=TreeNode,
url=None, url=None,
params={}, params={},
single_expand=False, single_expand=False,
@ -322,13 +337,13 @@ class Tree(WidgetCSS, ScrollWidget):
normal_css="default", normal_css="default",
row_height=2, row_height=2,
selected_css="selected", selected_css="selected",
checkbox=False, checkField=None,
multiplecheck=False,
idField='id', idField='id',
textField='text', textField='text',
data=None, data=None,
**options): **options):
self.url = url self.url = url
self.nodeKlass = nodeKlass
self.params = params self.params = params
self.data = data self.data = data
self.single_expand=single_expand self.single_expand=single_expand
@ -338,8 +353,7 @@ class Tree(WidgetCSS, ScrollWidget):
self.bgcolor = bgcolor self.bgcolor = bgcolor
self.normal_css = normal_css self.normal_css = normal_css
self.selected_css = selected_css self.selected_css = selected_css
self.checkbox = checkbox self.checkFiled = checkField
self.multiplecheck = multiplecheck
self.idField = idField self.idField = idField
self.textField = textField self.textField = textField
print('options=',options) print('options=',options)
@ -351,6 +365,10 @@ class Tree(WidgetCSS, ScrollWidget):
self.buildTree() self.buildTree()
self.bind(size=self.onSize,pos=self.onSize) self.bind(size=self.onSize,pos=self.onSize)
self.register_event_type('on_press') 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): def on_press(self,*larg):
pass pass

View File

@ -194,8 +194,11 @@ def getWidgetById(w,id):
return w.ids.get(id) return w.ids.get(id)
def CSize(x,y=None,name=None): def CSize(x,y=None,name=None):
ks = KivySizes() app = App.get_running_app()
return ks.CSize(x,y=y,name=name) r = app.font_size
if not y:
return r * x
return r * x, r * y
def screenSize(): def screenSize():
ks = KivySizes() ks = KivySizes()

View File

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