This commit is contained in:
yumoqing 2022-01-13 00:08:38 +08:00
parent 17bd95f52a
commit 804027cfb6
4 changed files with 6704 additions and 4625 deletions

View File

@ -33,6 +33,7 @@ from .utils import *
from .pagescontainer import PageContainer from .pagescontainer import PageContainer
from .blocks import Blocks from .blocks import Blocks
from .theming import ThemeManager from .theming import ThemeManager
from .widget_css import register_css
from appPublic.rsa import RSA from appPublic.rsa import RSA
if platform == 'android': if platform == 'android':
from jnius import autoclass from jnius import autoclass
@ -85,19 +86,6 @@ def getAuthHeader():
print('serverinfo authCode not found') print('serverinfo authCode not found')
return {} return {}
kivyblocks_css_keys = [
"height_nm",
"width_nm",
"height_cm",
"width_cm",
"bgcolor",
"fgcolor",
"radius",
"spacing",
"padding",
"border"
]
class BlocksApp(App): class BlocksApp(App):
def get_rotation(self): def get_rotation(self):
return get_rotation() return get_rotation()
@ -116,9 +104,6 @@ class BlocksApp(App):
d = hc.get(self.realurl(config.css.css_url)) d = hc.get(self.realurl(config.css.css_url))
self.buildCsses(d) self.buildCsses(d)
def get_css(self, cssname):
return self.csses.get(cssname, 'default')
def on_rotate(self,*largs): def on_rotate(self,*largs):
self.current_rotation = Window.rotation self.current_rotation = Window.rotation
Logger.info('BlocksApp:on_rotate(), largs=%s', Logger.info('BlocksApp:on_rotate(), largs=%s',
@ -127,14 +112,7 @@ class BlocksApp(App):
def buildCsses(self, dic): def buildCsses(self, dic):
for k,v in dic.items(): for k,v in dic.items():
if isinstance(v,dict): if isinstance(v,dict):
self.csses[k] = \ register_css(k,v)
{x:y for x,y in v.items() if x in kivyblocks_css_keys}
def get_csses(self):
return self.csses
def get_css(self, name):
return self.csses.get(name,self.csses.get('default',{}))
def build(self): def build(self):
self.platform = platform self.platform = platform

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,8 @@ from kivy.uix.label import Label
from kivy.graphics import Fbo from kivy.graphics import Fbo
from kivy.uix.button import ButtonBehavior from kivy.uix.button import ButtonBehavior
from kivy.clock import Clock from kivy.clock import Clock
from kivy.properties import BooleanProperty, StringProperty from kivy.properties import BooleanProperty, StringProperty, \
OptionProperty, DictProperty, NumericProperty, ListProperty
from kivy.properties import ListProperty from kivy.properties import ListProperty
from kivy.graphics import Color, Rectangle from kivy.graphics import Color, Rectangle
from kivy.app import App from kivy.app import App
@ -21,7 +22,7 @@ from appPublic.timecost import TimeCost
from appPublic.uniqueID import getID from appPublic.uniqueID import getID
from appPublic.myTE import string_template_render from appPublic.myTE import string_template_render
from .utils import CSize, setSizeOptions, loading, loaded, absurl, alert, SUPER from .utils import *
from .baseWidget import Text, HBox, VBox from .baseWidget import Text, HBox, VBox
from .scrollpanel import ScrollPanel from .scrollpanel import ScrollPanel
from .paging import Paging, RelatedLoader from .paging import Paging, RelatedLoader
@ -38,6 +39,9 @@ class BLabel(ButtonBehavior, Text):
self.csscls = 'dummy' self.csscls = 'dummy'
class Cell(ButtonBehavior, WidgetCSS, BoxLayout): class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
colume_name = StringProperty(None)
cell_type = OptionProperty('data', \
options=['data', 'header'])
def __init__(self,row,desc, **kw): def __init__(self,row,desc, **kw):
""" """
desc:{ desc:{
@ -50,28 +54,26 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
""" """
self.desc = desc self.desc = desc
self.row = row self.row = row
csscls=self.row.part.datagrid.body_css
if self.row.header:
csscls=self.row.part.datagrid.header_css
super().__init__(size_hint=(None,None), super().__init__(size_hint=(None,None),
width = self.desc['width'], width = self.desc['width'],
height = self.row.part.datagrid.rowHeight(), height = self.row.part.datagrid.rowHeight()
csscls=csscls
) )
self.csscls=self.row.part.datagrid.row_normal_css
if self.row.header:
self.csscls=self.row.part.datagrid.header_css
if desc['header']: if desc['header']:
bl = Text(i18n=True, text=str(desc['value']), bl = Text(i18n=True, text=str(desc['value']),
font_size=CSize(1),wrap=True, font_size=CSize(1),wrap=True,
halign='left', valign='middle' halign='left', valign='middle'
) )
self.cell_type = 'header'
else: else:
self.cell_type = 'data'
bl = build_view_widget(desc,self.row.row_data) bl = build_view_widget(desc,self.row.row_data)
self.colume_name = desc['name']
if bl: if bl:
self.add_widget(bl) self.add_widget(bl)
def on_press(self,o=None):
if not self.row.header:
self.row.selected()
class Row(BoxLayout): class Row(BoxLayout):
def __init__(self,part, rowdesc,header=False,data=None, **kw): def __init__(self,part, rowdesc,header=False,data=None, **kw):
""" """
@ -99,6 +101,8 @@ class Row(BoxLayout):
self.height = self.part.datagrid.rowHeight() self.height = self.part.datagrid.rowHeight()
self.init(0) self.init(0)
def on_row_press(self, *args):
pass
def init(self,t): def init(self,t):
w = 0 w = 0
@ -107,28 +111,33 @@ class Row(BoxLayout):
c['header'] = self.header c['header'] = self.header
cell = Cell(self,c) cell = Cell(self,c)
self.add_widget(cell) self.add_widget(cell)
cell.bind(on_press=self.part.datagrid.cell_pressed)
w += cell.width w += cell.width
self.size_hint = None,None self.size_hint = None,None
self.width = w + self.linewidth * (len(self.rowdesc)+1) self.width = w + self.linewidth * (len(self.rowdesc)+1)
def selected(self): def unselected(self):
if not hasattr(self,'row_data'): self.select(False)
return # header
print('row selected',self.row_id, self.row_data)
self.part.datagrid.row_selected = True def selected(self):
self.part.datagrid.select_rowid = self.row_id self.select(True)
self.part.datagrid.select_row = self
self.part.datagrid.dispatch('on_selected',self) def select(self, flag):
for c in self.children:
if flag:
c.csscls = self.part.datagrid.row_selected_css
else:
c.csscls = self.part.datagrid.row_normal_css
class Header(WidgetReady, ScrollPanel): class Header(WidgetReady, ScrollPanel):
def __init__(self,part,**kw): def __init__(self,part,**kw):
SUPER(Header, self, kw) SUPER(Header, self, kw)
self.part = part self.part = part
self.init(1) self.init(1)
self.bind(on_scroll_stop=self.part.datagrid.on_scrollstop) self.bind(on_scroll_stop=self.part.datagrid.scrollstop)
if self.part.freeze_flag: if self.part.freeze_flag:
self.bar_width = 0 self.bar_width = 0
self.bar_width = 0
def init(self,t): def init(self,t):
rd = [ f.copy() for f in self.part.rowdesc ] rd = [ f.copy() for f in self.part.rowdesc ]
@ -146,7 +155,7 @@ class Body(WidgetReady, ScrollPanel):
self._inner.spacing = self.part.datagrid.linewidth self._inner.spacing = self.part.datagrid.linewidth
self.size_hint=(1,1) self.size_hint=(1,1)
self.idRow = {} self.idRow = {}
self.bind(on_scroll_stop=self.part.datagrid.on_scrollstop) self.bind(on_scroll_stop=self.part.datagrid.scrollstop)
if self.part.freeze_flag: if self.part.freeze_flag:
self.bar_width = 0 self.bar_width = 0
@ -176,6 +185,9 @@ class Body(WidgetReady, ScrollPanel):
def getRowHeight(self): def getRowHeight(self):
return self.part.datagrid.rowHeight() return self.part.datagrid.rowHeight()
def get_row_by_id(self, rowid):
return self.idRow.get(rowid)
class DataGridPart(WidgetReady, BoxLayout): class DataGridPart(WidgetReady, BoxLayout):
def __init__(self,dg, freeze_flag, fields): def __init__(self,dg, freeze_flag, fields):
self.datagrid = dg self.datagrid = dg
@ -246,7 +258,7 @@ class DataGridPart(WidgetReady, BoxLayout):
self.body.height = self.height self.body.height = self.height
class DataGrid(WidgetReady, BoxLayout): class DataGrid(VBox):
""" """
DataGrid data format: DataGrid data format:
{ {
@ -297,46 +309,44 @@ class DataGrid(WidgetReady, BoxLayout):
} }
""" """
row_selected = BooleanProperty(False) row_selected = BooleanProperty(False)
row_normal_css = StringProperty('default')
row_selected_css = StringProperty('default')
header_css = StringProperty('default')
body_css = StringProperty('default')
row_height = NumericProperty(2)
noheader = BooleanProperty(False)
linewidth = NumericProperty(1)
toolbar = DictProperty(None)
dataloader = DictProperty(None)
fields = ListProperty(None)
tailer = ListProperty(None)
def __init__(self,**options): def __init__(self,**options):
options['orientation'] = 'vertical'
BoxLayout.__init__(self, orientation='vertical')
WidgetReady.__init__(self)
self.select_rowid = None self.select_rowid = None
self.options = options
self.rowheight = None self.rowheight = None
self.on_sizeTask = None self.on_sizeTask = None
self.selected_rowid = None self.selected_rowid = None
self.show_rows = 0 self.show_rows = 0
self.toolbar = None self._toolbar = None
self.freeze_part = None self.freeze_part = None
self.normal_part = None self.normal_part = None
self.page_rows = self.options.get('page_rows', 60) SUPER(DataGrid, self, options)
self.params = self.options.get('params',{})
self.total_cnt = 0
self.max_row = 0
self.row_height = self.options.get('row_height',2)
self.header_css = self.options.get('header_css','default')
self.noheader = self.options.get('noheader',False)
self.body_css = self.options.get('body_css', 'default')
self.linewidth = self.options.get('linewidth',1)
self.curpage = 0
self.loading = False
self.freeze_fields = self.getPartFields(freeze_flag=True) self.freeze_fields = self.getPartFields(freeze_flag=True)
self.normal_fields = self.getPartFields(freeze_flag=False) self.normal_fields = self.getPartFields(freeze_flag=False)
ldr_desc = options.get('dataloader') if not self.dataloader:
if not ldr_desc:
raise Exception('DataGrid need a DataLoader') raise Exception('DataGrid need a DataLoader')
self.dataloader = RelatedLoader(target=self, **ldr_desc) self._dataloader = RelatedLoader(target=self, **self.dataloader)
self.dataloader.bind(on_deletepage=self.delete_page) self._dataloader.bind(on_deletepage=self.delete_page)
self.dataloader.bind(on_pageloaded=self.add_page) self._dataloader.bind(on_pageloaded=self.add_page)
self.dataloader.bind(on_pageloaded=self.update_tailer_info) self._dataloader.bind(on_pageloaded=self.update_tailer_info)
self.dataloader.bind(on_newbegin=self.clearRows) self._dataloader.bind(on_newbegin=self.clearRows)
self.register_event_type('on_selected') self.register_event_type('on_selected')
self.register_event_type('on_scrollstop') self.register_event_type('on_rowpress')
self.register_event_type('on_cellpress')
self.register_event_type('on_headerpress')
self.createDataGridPart() self.createDataGridPart()
self.createToolbar() self.createToolbar()
if self.toolbar: if self._toolbar:
self.add_widget(self.toolbar) self.add_widget(self._toolbar)
b = BoxLayout(orientation='horizontal') b = BoxLayout(orientation='horizontal')
if self.freeze_part: if self.freeze_part:
@ -344,9 +354,49 @@ class DataGrid(WidgetReady, BoxLayout):
if self.normal_part: if self.normal_part:
b.add_widget(self.normal_part) b.add_widget(self.normal_part)
self.add_widget(b) self.add_widget(b)
if self.options.get('tailer'): if self.tailer:
self.tailer_widgets = {} self.tailer_widgets = {}
self.build_tailer(self.options.get('tailer')) self.build_tailer(self.tailer)
def on_rowpress(self, *args):
print('on_rowpress fire, args=', args)
def on_cellpress(self, *args):
print('on_cesspress fire, args=', args)
def on_headerpress(self, *args):
print('on_headerpress fire, args=', args)
def cell_pressed(self, o):
if o.cell_type == 'header':
self.dispatch('on_headerpress', o.colume_name)
return
row = o.row
if self.selected_rowid:
self.unselect_row(self.selected_rowid)
self.selected_rowid = row.row_id
self.select_row(row.row_id)
self.dispatch('on_cellpress', o)
self.dispatch('on_rowpress', row)
self.dispatch('on_selected', row)
def unselect_row(self, row_id):
if self.freeze_part:
row = self.freeze_part.body.get_row_by_id(row_id)
row.unselected()
row = self.normal_part.body.get_row_by_id(row_id)
row.unselected()
def select_row(self, row_id):
if self.freeze_part:
row = self.freeze_part.body.get_row_by_id(row_id)
row.selected()
row = self.normal_part.body.get_row_by_id(row_id)
row.selected()
def on_ready(self, *args):
self.loadData()
def build_tailer(self, tailer_desc): def build_tailer(self, tailer_desc):
kw = tailer_desc.get('options', {}) kw = tailer_desc.get('options', {})
@ -387,8 +437,8 @@ class DataGrid(WidgetReady, BoxLayout):
return Factory.Blocks().widgetBuild(desc) return Factory.Blocks().widgetBuild(desc)
def loader_info(self, n): def loader_info(self, n):
if hasattr(self.dataloader, n): if hasattr(self._dataloader, n):
txt=getattr(self.dataloader, n, 0) txt=getattr(self._dataloader, n, 0)
if txt is None: if txt is None:
txt = '0' txt = '0'
txt = str(txt) txt = str(txt)
@ -399,7 +449,7 @@ class DataGrid(WidgetReady, BoxLayout):
if self.freeze_part: if self.freeze_part:
self.freeze_part.body.scroll_y = pos self.freeze_part.body.scroll_y = pos
def on_scrollstop(self,o,v=None): def scrollstop(self,o,v=None):
if not self.noheader and o == self.normal_part.header: if not self.noheader and o == self.normal_part.header:
self.normal_part.body.scroll_x = o.scroll_x self.normal_part.body.scroll_x = o.scroll_x
return return
@ -412,13 +462,9 @@ class DataGrid(WidgetReady, BoxLayout):
self.normal_part.body.scroll_y = o.scroll_y self.normal_part.body.scroll_y = o.scroll_y
if o.scroll_y <= 0.01: if o.scroll_y <= 0.01:
print('loading next page...', self.dataloader.curpage) self._dataloader.loadNextPage()
self.loading = True
self.dataloader.loadNextPage()
if o.scroll_y >= 0.99: if o.scroll_y >= 0.99:
print('loading previous page...', self.dataloader.curpage) self._dataloader.loadPreviousPage()
self.loading = True
self.dataloader.loadPreviousPage()
def getValue(self): def getValue(self):
if not self.select_rowid: if not self.select_rowid:
@ -430,7 +476,6 @@ class DataGrid(WidgetReady, BoxLayout):
if self.freeze_part: if self.freeze_part:
d.update(self.freeze_part.body.getRowData(rowid)) d.update(self.freeze_part.body.getRowData(rowid))
d.update(self.normal_part.body.getRowData(rowid)) d.update(self.normal_part.body.getRowData(rowid))
print('getValue() return=',d)
return DictObject(**d) return DictObject(**d)
def bodyOnSize(self,o,s): def bodyOnSize(self,o,s):
@ -445,7 +490,7 @@ class DataGrid(WidgetReady, BoxLayout):
def calculateShowRows(self,t): def calculateShowRows(self,t):
self.getShowRows() self.getShowRows()
self.dataloader.setPageRows(self.show_rows * 2) self._dataloader.setPageRows(self.show_rows * 2)
def getShowRows(self): def getShowRows(self):
if self.show_rows == 0: if self.show_rows == 0:
@ -454,7 +499,6 @@ class DataGrid(WidgetReady, BoxLayout):
return self.show_rows * 2 return self.show_rows * 2
def clearRows(self, *args): def clearRows(self, *args):
print('dg.py:clearRows() called')
if self.freeze_part: if self.freeze_part:
self.freeze_part.body.clearRows() self.freeze_part.body.clearRows()
self.normal_part.body.clearRows() self.normal_part.body.clearRows()
@ -504,13 +548,11 @@ class DataGrid(WidgetReady, BoxLayout):
with self.canvas: with self.canvas:
self._fbo_rect = Rectangle(size=self.size, self._fbo_rect = Rectangle(size=self.size,
texture=self._fbo.texture) texture=self._fbo.texture)
self.dataloader.bufferObjects(page,ids) self._dataloader.bufferObjects(page,ids)
x = self.dataloader.getLocater() x = self._dataloader.getLocater()
self.locater(x) self.locater(x)
self.loading = False
def delete_page(self,o,data): def delete_page(self,o,data):
print('dg.py:delete_page() called')
for id in data: for id in data:
self.delRow(id) self.delRow(id)
@ -528,17 +570,16 @@ class DataGrid(WidgetReady, BoxLayout):
self.normal_part.body.delRowById(id) self.normal_part.body.delRowById(id)
def createToolbar(self): def createToolbar(self):
if 'toolbar' in self.options.keys(): if self.toolbar:
tb = self.options['toolbar'] self._toolbar = Toolbar(**self.toolbar)
self.toolbar = Toolbar(**tb)
def on_selected(self,row): def on_selected(self,row):
print("DataGrid():on_selected fire") print("DataGrid():on_selected fire")
def loadData(self,*args, **kwargs): def loadData(self,*args, **kwargs):
print('args=', args, 'kwargs=',kwargs)
kwargs['page'] = 1 kwargs['page'] = 1
self.dataloader.do_search(None,kwargs) self.selected_rowid = None
self._dataloader.do_search(None,kwargs)
def createDataGridPart(self): def createDataGridPart(self):
self.freeze_part = None self.freeze_part = None
@ -550,7 +591,7 @@ class DataGrid(WidgetReady, BoxLayout):
def getPartFields(self,freeze_flag:bool=False) -> list: def getPartFields(self,freeze_flag:bool=False) -> list:
fs = [] fs = []
for f in self.options['fields']: for f in self.fields:
if freeze_flag: if freeze_flag:
if f.get('freeze',False): if f.get('freeze',False):
fs.append(f) fs.append(f)

View File

@ -5,10 +5,38 @@ from kivy.uix.textinput import TextInput
from kivy.uix.button import Button from kivy.uix.button import Button
from kivy.uix.label import Label from kivy.uix.label import Label
from kivyblocks.utils import CSize from kivyblocks.utils import CSize
from kivy.app import App
from .colorcalc import * from .colorcalc import *
csses = {
"default":{
"bgcolor":[0.35,0.35,0.35,1],
"fgcolor":[0.85,0.85,0.85,1]
}
}
csskeys=[
"height_nm",
"width_nm",
"height_c",
"width_c",
"fgcolor_s",
"bgcolor_s",
"bgcolor",
"fgcolor",
"csscls",
"radius",
"height",
"width",
]
def register_css(cssname, cssdic):
dic = {k:v for k,v in cssdic.items() if k in csskeys }
csses.update({cssname:dic})
def get_css(cssname,default='default'):
return csses.get(cssname, csses.get(default))
class WidgetCSS(object): class WidgetCSS(object):
height_nm = NumericProperty(None) height_nm = NumericProperty(None)
width_nm = NumericProperty(None) width_nm = NumericProperty(None)
@ -61,10 +89,8 @@ class WidgetCSS(object):
def set_css(self, css_str): def set_css(self, css_str):
css = {} css = {}
app = App.get_running_app()
for css_name in css_str.split(' '): for css_name in css_str.split(' '):
css.update(app.get_css(css_name)) css.update(get_css(css_name))
# Logger.info('WidgetCSS:set_css():%s',css.keys())
for k,v in css.items(): for k,v in css.items():
setattr(self,k,v) setattr(self,k,v)