This commit is contained in:
yumoqing 2020-04-24 18:35:30 +08:00
parent 97372e8ad2
commit e11a398439
17 changed files with 645 additions and 297 deletions

View File

@ -1,4 +1,6 @@
import sys import sys
from traceback import print_exc
from kivy.app import App
from kivy.utils import platform from kivy.utils import platform
from kivy.uix.button import Button, ButtonBehavior from kivy.uix.button import Button, ButtonBehavior
from kivy.uix.accordion import Accordion,AccordionItem from kivy.uix.accordion import Accordion,AccordionItem
@ -46,6 +48,7 @@ from kivy.uix.codeinput import CodeInput
from kivy.graphics import Color, Rectangle from kivy.graphics import Color, Rectangle
from kivy.properties import ListProperty from kivy.properties import ListProperty
from kivycalendar import DatePicker from kivycalendar import DatePicker
from kivy.factory import Factory
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
@ -57,52 +60,66 @@ from .widgetExt.inputext import FloatInput,IntegerInput, \
from .widgetExt.messager import Messager from .widgetExt.messager import Messager
from .charts.bar import Bar from .charts.bar import Bar
from .bgcolorbehavior import BGColorBehavior from .bgcolorbehavior import BGColorBehavior
from .utils import NeedLogin, InsufficientPrivilege, HTTPError
from .login import LoginForm
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
class Text(BGColorBehavior, Label):
def __init__(self,bgcolor=[],fgcolor=[],color_level=-1,**kw):
self.options = DictObject(**kw)
kwargs = kw.copy()
Label.__init__(self,**kwargs)
BGColorBehavior.__init__(self,bgcolor=bgcolor,
fgcolor=fgcolor,
color_level=color_level)
class PressableImage(ButtonBehavior,AsyncImage): class PressableImage(ButtonBehavior,AsyncImage):
def on_press(self): def on_press(self):
pass pass
class Text(BGColorBehavior, Label):
def __init__(self,bgcolor=[0,0,0,1],**kw):
self.options = DictObject(**kw)
kwargs = kw.copy()
if kwargs.get('bgColor'):
self.bgColor = kwargs['bgColor']
del kwargs['bgColor']
Label.__init__(self,**kwargs)
BGColorBehavior.__init__(self,bgcolor=bgcolor)
class PressableLabel(ButtonBehavior, Text): class PressableLabel(ButtonBehavior, Text):
def on_press(self): def on_press(self):
pass pass
class HTTPDataHandler(EventDispatcher): class HTTPDataHandler(EventDispatcher):
def __init__(self, url,method='GET',params={},headers={}): def __init__(self, url,method='GET',params={},
EventDispatcher.__init__() headers={},
self.opts = opts files={}
):
EventDispatcher.__init__(self)
self.url = url self.url = url
self.method = method self.method = method
self.params = params self.params = params
self.headers = headers self.headers = headers
self.files=files
self.hc = App.get_running_app().hc self.hc = App.get_running_app().hc
self.register_event_type('on_sucess') self.register_event_type('on_success')
self.register_event_type('on_error') self.register_event_type('on_error')
def on_success(self,o,v): def on_success(self,v):
pass pass
def on_error(self,o,e): def on_error(self,e):
pass pass
def onSuccess(self,o,v): def onSuccess(self,o,v):
self.dispatch('on_sucess',v) print(__file__,'onSuccess():v=',v)
self.dispatch('on_success',v)
def onError(self,o,e): def onError(self,o,e):
if isinstance(e,NeedLogin):
lf = LoginForm()
lf.bind(on_setupuser=self.redo)
lf.open()
return
self.dispatch('on_error',e) self.dispatch('on_error',e)
print_exc()
print('[****][*********] onError Called',e)
def redo(self,o,v=None):
self.handle()
def handle(self,params={},headers={}): def handle(self,params={},headers={}):
p = self.params p = self.params

View File

@ -1,27 +1,87 @@
from kivy.logger import Logger from kivy.logger import Logger
from kivy.graphics import Color, Rectangle from kivy.graphics import Color, Rectangle
from kivy.properties import ListProperty from kivy.properties import ListProperty
from .color_definitions import getColors
_logcnt = 0 _logcnt = 0
class BGColorBehavior(object): class BGColorBehavior(object):
bgcolor = ListProperty([]) def __init__(self, bgcolor=[],fgcolor=[], color_level=-1,**kwargs):
def __init__(self, bgcolor=[0,0,0,1],**kwargs): self.color_level = color_level
self.bgcolor = bgcolor self.bgcolor = bgcolor
self.fgcolor = fgcolor
self.normal_bgcolor = bgcolor
self.normal_fgcolor = fgcolor
self.selected_bgcolor = bgcolor
self.selected_fgcolor = fgcolor
self.useOwnColor = False
self.useOwnBG = False
self.useOwnFG = False
if color_level != -1:
fg,bg= getColors(color_level)
self.fgcolor = fg
self.bgcolor = bg
self.normal_bgcolor = bg
self.normal_fgcolor = fg
fg,bg= getColors(color_level,selected=True)
self.selected_bgcolor = bg
self.selected_fgcolor = fg
self.useOwnColor = True
else:
if bgcolor != [] and fgcolor != []:
self.useOwnColor = True
elif bgcolor != []:
self.useOwnBG = True
elif fgcolor != []:
self.useOwnFG = True
if self.fgcolor!=[]:
self.color = self.fgcolor
self.bind(size=self.onSize_bgcolor_behavior, self.bind(size=self.onSize_bgcolor_behavior,
pos=self.onSize_bgcolor_behavior) pos=self.onSize_bgcolor_behavior)
self.bind(parent=self.useAcestorColor)
self.on_bgcolor() self.on_bgcolor()
def useAcestorColor(self,o,v=None):
if self.useOwnColor:
return
p = self.parent
cnt = 0
while p:
if isinstance(p,BGColorBehavior):
break
p = p.parent
cnt += 1
if cnt > 100:
return
if not self.useOwnBG and p:
self.bgcolor = p.bgcolor
self.on_bgcolor()
if not self.useOwnFG and p:
self.fgcolor = p.bgcolor
self.color = self.fgcolor
def onSize_bgcolor_behavior(self,o,v=None): def onSize_bgcolor_behavior(self,o,v=None):
if not hasattr(self,'rect'): if not hasattr(self,'rect'):
self.on_bgcolor() self.on_bgcolor()
else: else:
self.rect.pos = o.pos self.rect.pos = self.pos
self.rect.size = o.size self.rect.size = self.size
def on_bgcolor(self,o=None,v=None): def on_bgcolor(self,o=None,v=None):
if self.bgcolor == []:
return
if self.canvas: if self.canvas:
with self.canvas.before: with self.canvas.before:
Color(*self.bgcolor) Color(*self.bgcolor)
self.rect = Rectangle(pos=self.pos, self.rect = Rectangle(pos=self.pos,
size=self.size) size=self.size)
def selected(self):
self.bgcolor = self.selected_bgcolor
Logger.info('selected:color=%s',self.bgcolor)
self.on_bgcolor()
def unselected(self):
self.bgcolor = self.normal_bgcolor
Logger.info('unselected:color=%s',self.bgcolor)
self.on_bgcolor()

View File

@ -10,6 +10,7 @@ from appPublic.dictExt import dictExtend
from appPublic.folderUtils import ProgramPath from appPublic.folderUtils import ProgramPath
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
from appPublic.Singleton import SingletonDecorator from appPublic.Singleton import SingletonDecorator
from appPublic.datamapping import keyMapping
from kivy.config import Config from kivy.config import Config
from kivy.metrics import sp,dp,mm from kivy.metrics import sp,dp,mm
@ -17,14 +18,11 @@ from kivy.core.window import WindowBase
from kivy.properties import BooleanProperty from kivy.properties import BooleanProperty
from kivy.uix.widget import Widget from kivy.uix.widget import Widget
from kivy.app import App from kivy.app import App
from kivy.factory import Factory
from .baseWidget import * from .baseWidget import *
from .widgetExt import Messager
from .externalwidgetmanager import ExternalWidgetManager
from .threadcall import HttpClient
from .toolbar import * from .toolbar import *
from .dg import DataGrid from .dg import DataGrid
from .utils import * from .utils import *
from .ready import WidgetReady
from .serverImageViewer import ServerImageViewer from .serverImageViewer import ServerImageViewer
from .vplayer import VPlayer from .vplayer import VPlayer
from .form import InputBox, Form, StrSearchForm from .form import InputBox, Form, StrSearchForm
@ -113,10 +111,12 @@ def registerWidget(name,widget):
globals()[name] = widget globals()[name] = widget
class Blocks: class Blocks(EventDispatcher):
registedWidgets = {}
def __init__(self): def __init__(self):
EventDispatcher.__init__(self)
self.action_id = 0 self.action_id = 0
self.register_event_type('on_built')
self.register_event_type('on_failed')
def register_widget(self,name,widget): def register_widget(self,name,widget):
globals()[name] = widget globals()[name] = widget
@ -140,8 +140,6 @@ class Blocks:
raise Exception('None Function') raise Exception('None Function')
func =partial(f,widget) func =partial(f,widget)
return func return func
setattr(widget,fname,f)
return getattr(widget,fname)
def eval(self,s,l): def eval(self,s,l):
g = {} g = {}
@ -163,23 +161,22 @@ class Blocks:
return eval(s,g,l) return eval(s,g,l)
def getUrlData(self,kw,parenturl=None): def getUrlData(self,url,method='GET',params={}, files={},
url = kw.get('url') callback=None,
method = kw.get('method','GET') errback=None,**kw):
params = kw.get('params',{})
if url is None:
print('kw=',kw)
raise ArgumentError('url','getUrlData() miss a url argument')
url = absurl(url,parenturl)
if url.startswith('file://'): if url.startswith('file://'):
filename = url[7:] filename = url[7:]
print(filename) print(filename)
with codecs.open(filename,'r','utf-8') as f: with codecs.open(filename,'r','utf-8') as f:
b = f.read() b = f.read()
dic = json.loads(b) dic = json.loads(b)
callback(None,dic)
else: else:
dic = App.get_running_app().hc(url,method=method,params=params) h = HTTPDataHandler(url,method=method,params=params,
return dic, url files=files)
h.bind(on_success=callback)
h.bind(on_error=errback)
h.handle()
def strValueExpr(self,s:str,localnamespace:dict={}): def strValueExpr(self,s:str,localnamespace:dict={}):
if not s.startswith('py::'): if not s.startswith('py::'):
@ -239,7 +236,6 @@ class Blocks:
def __build(self,desc:dict,ancestor=None): def __build(self,desc:dict,ancestor=None):
def checkReady(w,o): def checkReady(w,o):
print('checkReady():w=',w,'o=',o)
w.children_ready[o] = True w.children_ready[o] = True
if all(w.children_ready.values()): if all(w.children_ready.values()):
w.ready = True w.ready = True
@ -250,8 +246,10 @@ class Blocks:
widgetClass = desc['widgettype'] widgetClass = desc['widgettype']
opts = desc.get('options',{}) opts = desc.get('options',{})
klass = globals().get(widgetClass) try:
if not klass: klass = Factory.get(widgetClass)
except Exception as e:
print('Error:',widgetClass,'not registered')
raise NotExistsObject(widgetClass) raise NotExistsObject(widgetClass)
widget = klass(**opts) widget = klass(**opts)
if desc.get('parenturl'): if desc.get('parenturl'):
@ -270,23 +268,34 @@ class Blocks:
widget.build_desc = desc widget.build_desc = desc
self.build_rest(widget,desc,ancestor) self.build_rest(widget,desc,ancestor)
# f = partial(self.build_rest,widget,desc,ancestor)
# event = Clock.schedule_once(f,0)
return widget return widget
def build_rest(self, widget,desc,ancestor,t=None): def build_rest(self, widget,desc,ancestor,t=None):
for sw in desc.get('subwidgets',[]): bcnt = 0
w = self.widgetBuild(sw, ancestor=ancestor) btotal = len(desc.get('subwidgets',[]))
if w is None: def doit(self,widget,bcnt,btotal,desc,o,w):
continue bcnt += 1
w.parenturl = widget.parenturl w.parenturl = widget.parenturl
widget.add_widget(w) widget.add_widget(w)
if hasattr(widget,'addChild'): if hasattr(widget,'addChild'):
widget.addChild(w) widget.addChild(w)
for b in desc.get('binds',[]): if bcnt >= btotal:
self.buildBind(widget,b) for b in desc.get('binds',[]):
if hasattr(widget, 'built'): self.buildBind(widget,b)
widget.built()
def doerr(o,e):
raise e
f = partial(doit,self,widget,bcnt,btotal,desc)
for sw in desc.get('subwidgets',[]):
b = Blocks()
b.bind(on_built=f)
b.bind(on_failed=doerr)
w = b.widgetBuild(sw, ancestor=ancestor)
if btotal == 0:
for b in desc.get('binds',[]):
self.buildBind(widget,b)
def buildBind(self,widget,desc): def buildBind(self,widget,desc):
wid = desc.get('wid','self') wid = desc.get('wid','self')
@ -309,7 +318,7 @@ class Blocks:
return self.scriptAction(widget, desc) return self.scriptAction(widget, desc)
if acttype == 'method': if acttype == 'method':
return self.methodAction(widget, desc) return self.methodAction(widget, desc)
alert(msg="actiontype invalid",title=acttype) alert("actiontype(%s) invalid" % acttype,title='error')
def blocksAction(widget,desc): def blocksAction(widget,desc):
target = self.getWidgetByIdPath(widget, desc.get('target','self')) target = self.getWidgetByIdPath(widget, desc.get('target','self'))
@ -319,13 +328,18 @@ class Blocks:
p = opts.get('options',{}) p = opts.get('options',{})
p.update(d) p.update(d)
opts['options'] = p opts['options'] = p
x = self.widgetBuild(opts,ancestor=widget) def doit(target,add_mode,o,w):
if x is None: if add_mode == 'replace':
alert(str(opts), title='widugetBuild error') target.clear_widgets()
return target.add_widget(w)
if add_mode == 'replace':
target.clear_widgets() def doerr(o,e):
target.add_widget(x) raise e
b = Blocks()
b.bind(on_built=partial(doit,target,add_mode))
b.bind(on_failed=doerr)
b.widgetBuild(opts,ancestor=widget)
def urlwidgetAction(self,widget,desc): def urlwidgetAction(self,widget,desc):
target = self.getWidgetByIdPath(widget, desc.get('target','self')) target = self.getWidgetByIdPath(widget, desc.get('target','self'))
@ -339,12 +353,19 @@ class Blocks:
'widgettype' : 'urlwidget' 'widgettype' : 'urlwidget'
} }
d['options'] = opts d['options'] = opts
x = self.widgetBuild(d,ancestor=widget)
if x is None: def doit(target,add_mode,o,w):
return if add_mode == 'replace':
if add_mode == 'replace': target.clear_widgets()
target.clear_widgets() target.add_widget(w)
target.add_widget(x)
def doerr(o,e):
raise e
b = Blocks()
b.bind(on_built=partial(doit,target,add_mode))
b.bind(on_failed=doerr)
b.widgetBuild(d,ancestor=widget)
def getActionData(self,widget,desc): def getActionData(self,widget,desc):
data = {} data = {}
@ -352,6 +373,8 @@ class Blocks:
dwidget = self.getWidgetByIdPath(widget, dwidget = self.getWidgetByIdPath(widget,
desc.get('datawidget')) desc.get('datawidget'))
data = dwidget.getData() data = dwidget.getData()
if desc.get('keymapping'):
data = keyMapping(data, desc.get('keymapping'))
return data return data
def registedfunctionAction(self, widget, desc): def registedfunctionAction(self, widget, desc):
@ -361,7 +384,7 @@ class Blocks:
params = desc.get(params,{}) params = desc.get(params,{})
d = self.getActionData(widget,desc) d = self.getActionData(widget,desc)
params.update(d) params.update(d)
func(params) func(**params)
def scriptAction(self, widget, desc): def scriptAction(self, widget, desc):
script = desc.get('script') script = desc.get('script')
@ -400,28 +423,44 @@ class Blocks:
] ]
} }
""" """
def doit(desc):
desc = self.valueExpr(desc)
try:
widget = self.__build(desc,ancestor=ancestor)
self.dispatch('on_built',widget)
print('widgetBuild():&&&&&&&&&&&&&&&&&',widget)
except Exception as e:
print('&&&&&&&&&&&&&&&&&',e)
doerr(None,e)
print('&&&&&&&&&&&&&&&&&',e)
return
def doerr(o,e):
self.dispatch('on_failed',e)
name = desc['widgettype'] name = desc['widgettype']
if name == 'urlwidget': if name == 'urlwidget':
opts = desc.get('options') opts = desc.get('options')
parenturl = None parenturl = None
url=''
if ancestor: if ancestor:
parenturl = ancestor.parenturl parenturl = ancestor.parenturl
desc, parenturl = self.getUrlData(opts,parenturl) try:
if not isinstance(desc,dict): url = absurl(opts.get('url'),parenturl)
print("getUrlData() return error data",opts,parenturl) except Exception as e:
# alert(str(desc) + 'format error',title='widgetBuild()') self.dispatch('on_failed',e)
return None
desc = self.valueExpr(desc)
desc['parenturl'] = parenturl
try: def cb(o,d):
widget = self.__build(desc,ancestor=ancestor) try:
return widget d['parenturl'] = url
except: doit(d)
print('widgetBuild() Error',desc) except Exception as e:
print_exc() doerr(None,e)
alert(str(desc))
return None del opts['url']
self.getUrlData(url,callback=cb,errback=doerr,**opts)
return
doit(desc)
def getWidgetByIdPath(self,widget,path): def getWidgetByIdPath(self,widget,path):
ids = path.split('/') ids = path.split('/')
@ -438,3 +477,10 @@ class Blocks:
raise WidgetNotFoundById(id) raise WidgetNotFoundById(id)
return widget return widget
def on_built(self,v=None):
return
def on_failed(self,e=None):
return
Factory.register('Blocks',Blocks)

View File

@ -15,7 +15,10 @@ BoxViewer options:
} }
} }
""" """
from traceback import print_exc
from functools import partial
from kivy.app import App from kivy.app import App
from kivy.factory import Factory
from kivy.utils import platform from kivy.utils import platform
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from .responsivelayout import VResponsiveLayout from .responsivelayout import VResponsiveLayout
@ -38,16 +41,11 @@ class BoxViewer(BoxLayout):
if options.get('toolbar'): if options.get('toolbar'):
self.toolbar = Toolbar(options['toolbar']) self.toolbar = Toolbar(options['toolbar'])
lopts = options['dataloader'].copy() lopts = options['dataloader'].copy()
lopts['options']['adder'] = self.showObject self.dataloader = RelatedLoader(target=self,**lopts['options'])
lopts['options']['remover'] = self.viewContainer.remove_widget self.dataloader.bind(on_deletepage=self.deleteWidgets)
lopts['options']['clearer'] = self.viewContainer.clear_widgets self.dataloader.bind(on_pageloaded=self.addPageWidgets)
lopts['options']['target'] = self self.dataloader.bind(on_newbegin=self.deleteAllWidgets)
lopts['options']['locater'] = self.locater
LClass = RelatedLoader
if lopts['widgettype'] == 'paging':
LClass = Paging
self.dataloader = LClass(**lopts['options'])
if self.toolbar: if self.toolbar:
self.add_widget(self.toolbar) self.add_widget(self.toolbar)
if self.dataloader.widget: if self.dataloader.widget:
@ -58,6 +56,30 @@ class BoxViewer(BoxLayout):
pos=self.resetCols) pos=self.resetCols)
self.viewContainer.bind(on_scroll_stop=self.on_scroll_stop) self.viewContainer.bind(on_scroll_stop=self.on_scroll_stop)
def deleteAllWidgets(self,o):
self.viewContainer.clear_widgets()
def addPageWidgets(self,o,data):
widgets = []
recs = data['data']
dir = data['dir']
idx = 0
if dir == 'up':
recs.reverse()
idx = -1
print('addPageWidgets(),begin')
for r in recs:
self.showObject(widgets, r, index=idx)
print('addPageWidgets(),widgets=',len(widgets))
self.dataloader.bufferObjects(widgets)
x = self.dataloader.getLocater()
self.locater(x)
def deleteWidgets(self,o,data):
for w in data:
self.viewContainer.remove_widget(w)
def on_selected(self, o, v=None): def on_selected(self, o, v=None):
print('BoxViewer(): on_selected fired....') print('BoxViewer(): on_selected fired....')
@ -77,20 +99,29 @@ class BoxViewer(BoxLayout):
self.dataloader.loadPage(1) self.dataloader.loadPage(1)
self.initflag = True self.initflag = True
def showObject(self, rec,**kw): def showObject(self, holders, rec,index=0):
blocks = App.get_running_app().blocks def doit(self,holders,idx,o,w):
print('showObject()...doit(),w=',w,o)
w.bind(on_press=self.select_record)
self.viewContainer.add_widget(w,index=idx)
holders.append(w)
def doerr(o,e):
print_exc()
print('showObject(),error=',e)
raise e
options = self.options['viewer'].copy() options = self.options['viewer'].copy()
options['options']['record'] = rec options['options']['record'] = rec
options['options']['ancestor'] = self options['options']['ancestor'] = self
options['options']['size_hint'] = None,None options['options']['size_hint'] = None,None
options['options']['width'] = self.box_width options['options']['width'] = self.box_width
options['options']['height'] = self.box_height options['options']['height'] = self.box_height
w = blocks.widgetBuild(options, ancestor=self) blocks = Factory.Blocks()
if w is None: blocks.bind(on_built=partial(doit,self,holders,index))
return None blocks.bind(on_failed=doerr)
w.bind(on_press=self.select_record) print('showObject():********here***********')
self.viewContainer.add_widget(w,**kw) blocks.widgetBuild(options, ancestor=self)
return w print('showObject():********end ***********')
def on_scroll_stop(self,o,v=None): def on_scroll_stop(self,o,v=None):
if o.scroll_y <= 0.001: if o.scroll_y <= 0.001:

View File

@ -46,6 +46,10 @@ form options
""" """
uitypes = { uitypes = {
"str":{
"orientation":"horizontal",
"wclass":StrInput,
},
"string":{ "string":{
"orientation":"horizontal", "orientation":"horizontal",
"wclass":StrInput, "wclass":StrInput,
@ -54,6 +58,10 @@ uitypes = {
"orientation":"horizontal", "orientation":"horizontal",
"wclass":Password, "wclass":Password,
}, },
"int":{
"orientation":"horizontal",
"wclass":IntegerInput,
},
"number":{ "number":{
"orientation":"horizontal", "orientation":"horizontal",
"wclass":IntegerInput, "wclass":IntegerInput,
@ -87,7 +95,7 @@ uitypes = {
"wclass":StrInput, "wclass":StrInput,
"options":{ "options":{
"multiline":True, "multiline":True,
"height":CSize(9), "height":9,
} }
}, },
"teleno":{ "teleno":{
@ -111,9 +119,12 @@ class InputBox(BoxLayout):
self.labelwidth = self.form.options['labelwidth'] self.labelwidth = self.form.options['labelwidth']
kwargs = { kwargs = {
"orientation":orientation, "orientation":orientation,
"size_hint_y":None,
"height":height
} }
if height<=1:
kwargs['size_hint_y'] = height
else:
kwargs['size_hint_y'] = None
kwargs['height'] = CSize(height)
if width <= 1: if width <= 1:
kwargs['size_hint_x'] = width kwargs['size_hint_x'] = width
else: else:
@ -121,7 +132,7 @@ class InputBox(BoxLayout):
kwargs['width'] = CSize(width) kwargs['width'] = CSize(width)
super().__init__(**kwargs) super().__init__(**kwargs)
self.initflag = False self.initflag = False
self.bind(on_size=self.setSize, self.bind(size=self.setSize,
pos=self.setSize) pos=self.setSize)
self.register_event_type("on_datainput") self.register_event_type("on_datainput")
self.register_event_type("on_ready") self.register_event_type("on_ready")
@ -169,8 +180,8 @@ class InputBox(BoxLayout):
options = self.uidef.get('options',{}).copy() options = self.uidef.get('options',{}).copy()
options.update(self.options.get('uiparams',{})) options.update(self.options.get('uiparams',{}))
options['allow_copy'] = True options['allow_copy'] = True
options['size_hint_y'] = None options['width'] = 1
options['height'] = CSize(3) options['height'] = 2.5
if self.options.get('tip'): if self.options.get('tip'):
options['hint_text'] = i18n(self.options.get('tip')) options['hint_text'] = i18n(self.options.get('tip'))
@ -217,6 +228,12 @@ class InputBox(BoxLayout):
def getValue(self): def getValue(self):
return {self.options.get('name'):self.input_widget.getValue()} return {self.options.get('name'):self.input_widget.getValue()}
def disable(self,*args,**kwargs):
self.input_widget.disabled = True
def enable(self,*args,**kwargs):
self.input_widget.disabled = False
def defaultToolbar(): def defaultToolbar():
return { return {
"img_size":2, "img_size":2,
@ -241,23 +258,18 @@ class Form(BGColorBehavior, BoxLayout):
self.options = options self.options = options
BoxLayout.__init__(self, orientation='vertical') BoxLayout.__init__(self, orientation='vertical')
self.color_level = self.options.get('color_level', 0) self.color_level = self.options.get('color_level', 0)
textcolor, bgcolor = getColors(self.color_level) BGColorBehavior.__init__(self,color_level=self.color_level)
BGColorBehavior.__init__(self,bgcolor=bgcolor)
self.widget_ids = {} self.widget_ids = {}
self.readiedInput = 0 self.readiedInput = 0
self.cols = self.options_cols = self.options.get('cols',1) self.cols = self.options_cols = self.options.get('cols',1)
if isHandHold() and Window.width < Window.height: if isHandHold() and Window.width < Window.height:
self.cols = 1 self.cols = 1
self.inputwidth = Window.width / self.cols self.inputwidth = Window.width / self.cols
self.inputheight = CSize(self.options.get('inputheight',3)) self.inputheight = self.options.get('inputheight',3)
self.initflag = False self.init()
self.register_event_type('on_submit') self.register_event_type('on_submit')
self.bind(size=self.on_size,
pos=self.on_size)
def init(self): def init(self):
if self.initflag:
return
self.toolbar = Toolbar(ancestor=self,**self.options.get('toolbar',defaultToolbar())) self.toolbar = Toolbar(ancestor=self,**self.options.get('toolbar',defaultToolbar()))
self.fsc = VResponsiveLayout( self.fsc = VResponsiveLayout(
self.inputwidth, self.inputwidth,
@ -279,7 +291,6 @@ class Form(BGColorBehavior, BoxLayout):
wid = blocks.getWidgetByIdPath(self,'__clear') wid = blocks.getWidgetByIdPath(self,'__clear')
# wid = self.widget_ids['__clear'] # wid = self.widget_ids['__clear']
wid.bind(on_press=self.on_clear_button) wid.bind(on_press=self.on_clear_button)
self.initflag = True
def makeInputLink(self,o,v=None): def makeInputLink(self,o,v=None):
self.readiedInput += 1 self.readiedInput += 1
@ -323,10 +334,6 @@ class Form(BGColorBehavior, BoxLayout):
for fw in self.fieldWidgets: for fw in self.fieldWidgets:
fw.clear() fw.clear()
def on_size(self,o, v=None):
self.init()
textcolor, self.bgcolor = getColors(self.color_level)
class StrSearchForm(BoxLayout): class StrSearchForm(BoxLayout):
def __init__(self,img_url=None,**options): def __init__(self,img_url=None,**options):
self.name = options.get('name','search_string') self.name = options.get('name','search_string')

View File

@ -28,6 +28,8 @@ class I18n:
if lang is None: if lang is None:
lang = self.lang lang = self.lang
d = self.kvlang.get(lang,{}) d = self.kvlang.get(lang,{})
if d is None:
return msg
return d.get(msg,msg) return d.get(msg,msg)
def changeLang(self,lang): def changeLang(self,lang):

View File

@ -41,18 +41,15 @@ class KivySizes:
return self.unitedSize(x,y=y,name=name) return self.unitedSize(x,y=y,name=name)
def getScreenSize(self): def getScreenSize(self):
#root = App.get_running_app().root
#return root.width, root.height
return Window.width, Window.height return Window.width, Window.height
def getWindowPhysicalSize(self,w): def getWindowPhysicalSize(self):
h_phy = float(w.height) / mm(1) h_phy = float(Window.height) / mm(1)
w_phy = float(w.width) / mm(1) w_phy = float(Window.width) / mm(1)
return w_phy, h_phy return w_phy, h_phy
def getScreenPhysicalSize(self): def getScreenPhysicalSize(self):
return self.getWindowPhysicalSize(App.get_running_app().root) return self.getWindowPhysicalSize()
return self.getWindowPhysicalSize(Window)
def isHandHold(self): def isHandHold(self):
return min(self.getScreenPhysicalSize()) <= 75.0 return min(self.getScreenPhysicalSize()) <= 75.0

View File

@ -1,4 +1,6 @@
from traceback import print_exc
from kivy.logger import Logger from kivy.logger import Logger
from kivy.factory import Factory
from kivy.app import App from kivy.app import App
from kivy.core.window import Window from kivy.core.window import Window
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
@ -35,21 +37,14 @@ class LoginForm(Popup):
def __init__(self): def __init__(self):
super().__init__(size_hint=(0.8,0.8)) super().__init__(size_hint=(0.8,0.8))
self.title = 'login' self.title = 'login'
self.initflag = False self.buildContent(None,None)
self.bind(size=self.buildContent, self.register_event_type('on_setupuser')
pos=self.buildContent)
def on_setupuser(self,o=None):
return
def buildContent(self,o,size): def buildContent(self,o,size):
print('build Content. ....') self.content = Factory.Form(**logformdesc['options'])
if self.initflag:
return
print('build Content ....... ....')
self.initflag = True
app = App.get_running_app()
try:
self.content = app.blocks.widgetBuild(logformdesc)
except Exception as e:
Logger.info('login: Error %s', e)
self.content.bind(on_submit=self.on_submit) self.content.bind(on_submit=self.on_submit)
def on_submit(self,o,userinfo): def on_submit(self,o,userinfo):
@ -61,10 +56,7 @@ class LoginForm(Popup):
if userinfo.get('passwd',False): if userinfo.get('passwd',False):
userinfo['authmethod'] = 'password' userinfo['authmethod'] = 'password'
authinfo = app.serverinfo.encode(userinfo) authinfo = app.serverinfo.encode(userinfo)
config = getConfig() self.dispatch('on_setupuser')
login_url = '%s%s' % (config.uihome, config.login_url)
x = app.hc.get(login_url)
print('login return=', x, login_url, authinfo)
def on_cancel(self,o,v): def on_cancel(self,o,v):
print('login() on_cancel fired .....') print('login() on_cancel fired .....')

75
kivyblocks/newwidget.py Normal file
View File

@ -0,0 +1,75 @@
from kivy.logger import Logger
from kivy.graphics import Color, Rectangle
from kivy.properties import ListProperty, NumericProperty
from kivy.factory import Factory
from kivy.uix.widget import Widget
from .color_definitions import getColors
class NewWidget(Widget):
bgcolor = ListProperty([])
fcolor = ListProperty([])
color_level = NumericProperty(-1)
def __init__(self, color_level=-1,bgcolor=[],fcolor=[],**kwargs):
super().__init__(**kwargs)
self.bgcolor = bgcolor
self.fcolor = fcolor
self.color_level = color_level
self.initColors()
self.bind(size=self.onSize_bgcolor_behavior,
pos=self.onSize_bgcolor_behavior)
def initColors(self):
if self.color_level != -1:
fcolor, bgcolor = getColors(self.color_level)
if self.bgcolor == []:
self.bgcolor = bgcolor
if self.fcolor == []:
self.fcolor = fcolor
def getParentColorLevel(self):
if not self.parent:
self.fcolor, self.bgcolor = getColors(self.color_level):
def on_color_level(self,o,v=None):
if bgcolor != [] and fcolor != []:
return
if color_level != -1:
fcolor, bgcolor = getColors(self.color_level)
if self.bgcolor == []:
self.bgcolor = bgcolor
if self.fcolor == []:
self.fcolor = fcolor
def on_fcolor(self,o,v=None):
self.color = self.fcolor
def on_parent(self,o,v=None):
if self.color_level != -1:
self.fcolor, self.bgcolor = getColors(self.color_level)
if self.color_level == -1:
self.setColorsFromAncestor()
def onSize_bgcolor_behavior(self,o,v=None):
if not hasattr(self,'rect'):
self.on_bgcolor()
else:
self.rect.pos = o.pos
self.rect.size = o.size
def on_bgcolor(self,o=None,v=None):
if self.bgcolor == []:
return
if self.canvas:
with self.canvas.before:
Color(*self.bgcolor)
self.rect = Rectangle(pos=self.pos,
size=self.size)
try:
Factory.unregister('Widget')
except:
pass
Factory.register('Widget',cls=NewWidget)

View File

@ -2,6 +2,7 @@ import traceback
import math import math
from kivy.logger import Logger from kivy.logger import Logger
from kivy.event import EventDispatcher
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button from kivy.uix.button import Button
from kivy.clock import Clock from kivy.clock import Clock
@ -9,7 +10,7 @@ from kivy.app import App
from functools import partial from functools import partial
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
from .baseWidget import Text from .baseWidget import Text, HTTPDataHandler
from .utils import CSize, absurl, alert from .utils import CSize, absurl, alert
from .form import StrSearchForm from .form import StrSearchForm
@ -28,37 +29,22 @@ class PagingButton(Button):
locater locater
filter 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 HttpLoader: class PageLoader(EventDispatcher):
def __init__(self, url, method, params,page_rows=60): def __init__(self,target=None, **options):
self.page_rows = page_rows
self.url = url
self.method = method
self.params = params
def setParams(self,params, url=None, page_rows=60):
self.params = params
if url is not None:
self.url = url
self.page_rows = page_rows
def load(self, callback, errback=None):
hc = App.get_running_app().hc
x = hc(self.url,
method=self.method,
params=self.params,
callback=callback,
errback=errback)
class PageLoader:
def __init__(self, **options):
self.loading = False self.loading = False
self.target = target
self.options = options
self.filter = None self.filter = None
if options.get('filter'): if options.get('filter'):
self.filter = StrSearchForm(**options['filter']) self.filter = StrSearchForm(**options['filter'])
self.filter.bind(on_submit=self.do_search) self.filter.bind(on_submit=self.do_search)
self.params = options.get('params',{}) self.params = options.get('params',{})
self.method = options.get('method','GET') self.method = options.get('method','GET')
self.url = options.get('dataurl') self.url = options.get('dataurl')
@ -66,14 +52,34 @@ class PageLoader:
self.total_cnt = 0 self.total_cnt = 0
self.total_page = 0 self.total_page = 0
self.curpage = 0 self.curpage = 0
Logger.info('kivyblocks: method=%s,type=%s',str(self.method),type(self.method)) self.dir = 'down'
self.loader = HttpLoader(self.url, self.method, self.params ) self.register_event_type('on_newbegin')
self.register_event_type('on_pageloaded')
def getLocater(self):
x = 1 / self.MaxbufferPage
if self.dir != 'down':
x = 1 - x
print('getLocater(),x=%f,dir=%s,self.curpage=%d' % (x,self.dir,self.curpage))
return x
def on_newbegin(self):
pass
def on_pageloaded(self,d):
"""
d={
page:
data:[]
dir:'up' or 'down'
}
"""
pass
def do_search(self,o,params): def do_search(self,o,params):
print('PageLoader().do_search(), on_submit handle....',params) print('PageLoader().do_search(), on_submit handle....',params)
self.clearer() self.dispatch('on_newbegin')
self.params.update(params) self.params.update(params)
self.loader.setParams(self.params)
self.loadPage(1) self.loadPage(1)
def calculateTotalPage(self): def calculateTotalPage(self):
@ -94,22 +100,20 @@ class PageLoader:
self.curpage = 1 self.curpage = 1
self.loadPage(self.curpage) self.loadPage(self.curpage)
def setDir(self):
pages = self.objectPages.keys()
if len(pages)==0:
self.dir = 'down'
return
if self.curpage >= max(self.objectPages.keys()):
self.dir = 'down'
else:
self.dir = 'up'
def show_page(self,o,d): def show_page(self,o,d):
p = (self.curpage - 1) * self.page_rows + 1 p = (self.curpage - 1) * self.page_rows + 1
for r in d['rows']: for r in d['rows']:
r['__posInSet__'] = p r['__posInSet__'] = p
p += 1 p += 1
self.total_cnt = d['total']
self.calculateTotalPage()
d = {
"page":self.curpage,
"dir":self.dir,
"data":d['rows']
}
self.dispatch('on_pageloaded',d)
def httperror(self,o,e): def httperror(self,o,e):
traceback.print_exc() traceback.print_exc()
alert(str(e),title='alert') alert(str(e),title='alert')
@ -117,6 +121,12 @@ class PageLoader:
def loadPage(self,p): def loadPage(self,p):
if not self.url: if not self.url:
raise Exception('dataurl must be present:options=%s' % str(options)) raise Exception('dataurl must be present:options=%s' % str(options))
if self.curpage > p:
self.dir = 'up'
elif self.curpage == p:
self.dir = 'reload'
else:
self.dir = 'down'
self.curpage = p self.curpage = p
self.loading = True self.loading = True
params = self.params.copy() params = self.params.copy()
@ -124,9 +134,11 @@ class PageLoader:
"page":self.curpage, "page":self.curpage,
"rows":self.page_rows "rows":self.page_rows
}) })
url = absurl(self.url,self.target.parenturl) realurl = absurl(self.url,self.target.parenturl)
self.loader.setParams(params,url=url) loader = HTTPDataHandler(realurl,params=params)
self.loader.load(self.show_page,self.httperror) loader.bind(on_success=self.show_page)
loader.bind(on_failed=self.httperror)
loader.handle()
""" """
{ {
@ -139,22 +151,25 @@ class PageLoader:
method, method,
filter filter
} }
events:
'on_bufferraise': erase
""" """
class RelatedLoader(PageLoader): class RelatedLoader(PageLoader):
def __init__(self, **options): def __init__(self, **options):
super().__init__(**options) super().__init__(**options)
self.adder = options.get('adder')
self.locater = options.get('locater',None)
self.remover = options.get('remover')
self.clearer = options.get('clearer')
self.target = options.get('target')
self.objectPages = {} self.objectPages = {}
self.totalObj = 0 self.totalObj = 0
self.MaxbufferPage = 3 self.MaxbufferPage = 3
self.locater = 1/self.MaxbufferPage
if self.filter: if self.filter:
self.widget = self.filter self.widget = self.filter
else: else:
self.widget = None self.widget = None
self.register_event_type('on_deletepage')
def on_deletepage(self,d):
pass
def setPageRows(self,row_cnt): def setPageRows(self,row_cnt):
if self.total_cnt != 0: if self.total_cnt != 0:
@ -171,42 +186,21 @@ class RelatedLoader(PageLoader):
self.deleteBuffer(p) self.deleteBuffer(p)
def deleteBuffer(self,page): def deleteBuffer(self,page):
for w in self.objectPages[page]: d = self.objectPages[page]
self.remover(w) self.dispatch('on_deletepage',d)
self.totalObj -= len(self.objectPages[page]) self.totalObj -= len(self.objectPages[page])
del self.objectPages[page] del self.objectPages[page]
def bufferObjects(self,objects):
self.objectPages[self.curpage] = objects
def show_page(self,o,data): def show_page(self,o,data):
super().show_page(o,data)
if self.objectPages.get(self.curpage): if self.objectPages.get(self.curpage):
self.deleteBuffer(self.curpage) self.deleteBuffer(self.curpage)
else: else:
self.setDir()
self.doBufferMaintain() self.doBufferMaintain()
self.total_cnt = data['total'] self.totalObj += len(data['rows'])
self.calculateTotalPage() super().show_page(o,data)
widgets = []
rows = data['rows']
if self.dir == 'up':
rows.reverse()
for r in rows:
if self.dir == 'up':
w = self.adder(r,index=self.totalObj)
else:
w = self.adder(r)
widgets.append(w)
self.totalObj += 1
self.objectPages[self.curpage] = widgets
pages = len(self.objectPages.keys())
loc = 1.0 / float(pages)
if self.locater:
if pages == 1:
self.locater(1)
elif self.dir == 'up':
self.locater(1 - loc)
else:
self.locater(loc)
self.loading = False self.loading = False
print('buffer pages=',len(self.objectPages.keys()),'pages=',self.objectPages.keys()) print('buffer pages=',len(self.objectPages.keys()),'pages=',self.objectPages.keys())
@ -218,12 +212,12 @@ class RelatedLoader(PageLoader):
if len(pages) < 1: if len(pages) < 1:
return return
self.curpage = min(pages) page = min(pages)
if self.curpage <= 1: if page <= 1:
return return
self.curpage -= 1 page -= 1
self.loadPage(self.curpage) self.loadPage(page)
def loadNextPage(self): def loadNextPage(self):
if self.loading: if self.loading:
@ -231,11 +225,11 @@ class RelatedLoader(PageLoader):
pages = self.objectPages.keys() pages = self.objectPages.keys()
if len(pages) == 0: if len(pages) == 0:
return return
self.curpage = max(pages) page = max(pages)
if self.curpage>=self.total_page: if page>=self.total_page:
return return
self.curpage += 1 page += 1
self.loadPage(self.curpage) self.loadPage(page)
""" """
{ {

41
kivyblocks/register.py Normal file
View File

@ -0,0 +1,41 @@
from kivy.utils import platform
from .baseWidget import *
from .tree import Tree, TextTree, PopupMenu
from .toolbar import ToolPage, Toolbar
from .dg import DataGrid
from .vplayer import VPlayer
from .form import Form, StrSearchForm
from .boxViewer import BoxViewer
from .pagescontainer import PageContainer
r = Factory.register
r('PageContainer', PageContainer)
r('BoxViewer', BoxViewer)
r('Form', Form)
r('StrSearchForm', StrSearchForm)
r('VPlayer', VPlayer)
r('DataGrid', DataGrid)
r('Toolbar', Toolbar)
r('ToolPage',ToolPage)
r('HTTPDataHandler',HTTPDataHandler)
r('Text',Text)
r('ScrollWidget',ScrollWidget)
r('BinStateImage',BinStateImage)
r('JsonCodeInput',JsonCodeInput)
r('FloatInput',FloatInput)
r('IntegerInput',IntegerInput)
r('StrInput',StrInput)
r('SelectInput',SelectInput)
r('BoolInput',BoolInput)
r('AmountInput',AmountInput)
r('Messager',Messager)
r('Bar',Bar)
r('LoginForm',LoginForm)
r('PressableImage', PressableImage)
r('PressableLabel', PressableLabel)
r('Tree',Tree)
r('TextTree',TextTree)
r('PopupMenu',PopupMenu)
if platform == 'android':
r('PhoneButton',PhoneButton)
r('AWebView',AWebView)

35
kivyblocks/tab.py Normal file
View File

@ -0,0 +1,35 @@
"""
{
"widgettype":"BLKTabbedPanel",
"tab_pos":"top_left",
"color_level":0,
"width",
"height",
"size_hint",
"tabs":[
{
"text":"tab1",
"content":{
"widgettype":"urlwidegt",
"url":"reggtY",
}
},
{
}
]
}
"""
class BLKTabItem(BGColorBehavior, TabbedPanelItem):
def __init__(self,parent,color_level=0,text="",content={}):
self.parent=parent
self.color_level = color_level
class BLKTabedPanel(BGColorBehavior, TabbedPanel):
def __init__(self,color_level=0, tabs=[], **kwargs):
self.tabs_desc = tabs
self.color_level = color_level
TabbedPanel.__init__(**kwargs)
BGColorBehavior.__init__(self)
class

View File

@ -6,9 +6,7 @@ from kivy.event import EventDispatcher
from kivy.clock import Clock from kivy.clock import Clock
from kivy.app import App from kivy.app import App
from .login import LoginForm from .login import LoginForm
from .utils import NeedLogin, InsufficientPrivilege, HTTPError
class NeedLogin(Exception):
pass
class ThreadCall(Thread,EventDispatcher): class ThreadCall(Thread,EventDispatcher):
def __init__(self,target, args=(), kwargs={}): def __init__(self,target, args=(), kwargs={}):
@ -95,7 +93,11 @@ class HttpClient:
app = App.get_running_app() app = App.get_running_app()
domain = self.url2domain(url) domain = self.url2domain(url)
sessionid = hostsessions.get(domain,None) sessionid = hostsessions.get(domain,None)
print('hostsessions=', hostsessions, 'sessionid=',sessionid, 'domain=',domain) print('hostsessions=', hostsessions,
'sessionid=',sessionid,
'domain=',domain,
'url=',url
)
if sessionid: if sessionid:
headers.update({'session':sessionid}) headers.update({'session':sessionid})
elif app.getAuthHeader(): elif app.getAuthHeader():
@ -128,10 +130,16 @@ class HttpClient:
except: except:
return resp.text return resp.text
if resp.status_code == 401: if resp.status_code == 401:
print('NeedLogin:',url)
raise NeedLogin raise NeedLogin
print('Error', url, method, params, resp.status_code,type(resp.status_code)) if resp.status_code == 403:
raise Exception('error:%s' % url) raise InsufficientPrivilege
print('Error', url, method,
params, resp.status_code,
type(resp.status_code))
raise HTTPError(resp.status_code)
def __call__(self,url,method="GET",params={},headers={},files={},callback=None,errback=None): def __call__(self,url,method="GET",params={},headers={},files={},callback=None,errback=None):
def cb(t,resp): def cb(t,resp):
@ -142,10 +150,8 @@ class HttpClient:
resp = self.webcall(url, method=method, resp = self.webcall(url, method=method,
params=params, files=files, headers=headers) params=params, files=files, headers=headers)
return cb(None,resp) return cb(None,resp)
except NeedLogin as e: except Exception as e:
lf = LoginForm() raise e
lf.open()
return None
except Exception as e: except Exception as e:
if errback is not None: if errback is not None:
errback(e) errback(e)

View File

@ -42,7 +42,7 @@ class Tool(ButtonBehavior, BGColorBehavior, BoxLayout):
ButtonBehavior.__init__(self) ButtonBehavior.__init__(self)
BoxLayout.__init__(self, BoxLayout.__init__(self,
size_hint_y=None) size_hint_y=None)
BGColorBehavior.__init__(self) BGColorBehavior.__init__(self,color_level=ancestor.color_level)
self.bl = BoxLayout(orientation='vertical', self.bl = BoxLayout(orientation='vertical',
size_hint_y=None) size_hint_y=None)
self.add_widget(self.bl) self.add_widget(self.bl)
@ -62,7 +62,8 @@ class Tool(ButtonBehavior, BGColorBehavior, BoxLayout):
tsize = CSize(self.opts.text_size) tsize = CSize(self.opts.text_size)
label = self.opts.label or self.opts.name label = self.opts.label or self.opts.name
self.lbl = I18nText(otext=label, self.lbl = I18nText(color_level=self.ancestor.color_level,
otext=label,
font_size=int(tsize), font_size=int(tsize),
text_size=(CSize(len(label)), tsize), text_size=(CSize(len(label)), tsize),
height=tsize, height=tsize,
@ -71,24 +72,21 @@ class Tool(ButtonBehavior, BGColorBehavior, BoxLayout):
) )
self.bl.add_widget(self.lbl) self.bl.add_widget(self.lbl)
self.height = (size + tsize)*1.1 self.height = (size + tsize)*1.1
self.lbl.color, self.bgcolor = getColors(self.ancestor.color_level,
selected=False)
self.lbl.bgcolor = self.bgcolor
def on_size(self,obj,size): def on_size(self,obj,size):
Logger.info('toolbar: Tool() on_size fired') Logger.info('toolbar: Tool() on_size fired')
self.lbl.color, self.bgcolor = getColors(self.ancestor.color_level, #self.lbl.color, self.bgcolor = getColors(self.ancestor.color_level,
selected=False) # selected=False)
self.lbl.bgcolor = self.bgcolor #self.lbl.bgcolor = self.bgcolor
def on_press(self): def on_press(self):
print('Tool(). pressed ...............') print('Tool(). pressed ...............')
def setActive(self,flag): def setActive(self,flag):
text_color, self.bgcolor = getColors(self.ancestor.color_level, if flag:
selected=flag) self.selected()
self.lbl.bgcolor = self.bgcolor else:
self.lbl.color = text_color self.unselected()
""" """
@ -106,11 +104,15 @@ toolbar options
] ]
} }
""" """
class Toolbar(GridLayout): class Toolbar(BGColorBehavior, GridLayout):
def __init__(self, ancestor=None,**opts): def __init__(self, ancestor=None,**opts):
self.opts = DictObject(**opts) self.opts = DictObject(**opts)
self.tool_widgets={} self.tool_widgets={}
super().__init__(cols = len(self.opts.tools)) GridLayout.__init__(self,cols = len(self.opts.tools))
color_level = 0
if isinstance(ancestor, BGColorBehavior):
color_level = ancestor.color_level + 1
BGColorBehavior.__init__(self,color_level=color_level)
self.size_hint = (1,None) self.size_hint = (1,None)
first = True first = True
for opt in self.opts.tools: for opt in self.opts.tools:
@ -175,9 +177,9 @@ class ToolPage(BGColorBehavior, BoxLayout):
orient = 'vertical' orient = 'vertical'
else: else:
orient = 'horizontal' orient = 'horizontal'
color_level=self.opts.color_level or 0
BoxLayout.__init__(self,orientation=orient) BoxLayout.__init__(self,orientation=orient)
BGColorBehavior.__init__(self) BGColorBehavior.__init__(self,color_level=color_level)
self.content = None self.content = None
self.toolbar = None self.toolbar = None
self.init() self.init()
@ -190,7 +192,6 @@ class ToolPage(BGColorBehavior, BoxLayout):
self.toolbar.width = x self.toolbar.width = x
self.content.width = x self.content.width = x
self.content.height = y - self.toolbar.height self.content.height = y - self.toolbar.height
self.color, self.bgcolor = getColors(self.color_level)
def showPage(self,obj): def showPage(self,obj):
self._show_page(obj.opts) self._show_page(obj.opts)
@ -211,8 +212,6 @@ class ToolPage(BGColorBehavior, BoxLayout):
t.img_src = absurl(t.img_src,parenturl) t.img_src = absurl(t.img_src,parenturl)
opts = self.opts opts = self.opts
self.color_level = self.opts.color_level or 0
self.color, self.bgcolor = getColors(self.color_level)
self.toolbar = Toolbar(ancestor=self, **self.opts) self.toolbar = Toolbar(ancestor=self, **self.opts)
if self.opts.tool_at in ['top','left']: if self.opts.tool_at in ['top','left']:
self.add_widget(self.toolbar) self.add_widget(self.toolbar)

View File

@ -285,7 +285,7 @@ class Tree(BGColorBehavior, ScrollWidget):
def __init__(self,**options): def __init__(self,**options):
self.color_level = options.get('color_level',0) self.color_level = options.get('color_level',0)
ScrollWidget.__init__(self) ScrollWidget.__init__(self)
BGColorBehavior.__init__(self) BGColorBehavior.__init__(self,color_level=self.color_level)
self.options = DictObject(**options) self.options = DictObject(**options)
self.nodes = [] self.nodes = []
self.initflag = False self.initflag = False
@ -377,21 +377,16 @@ class Tree(BGColorBehavior, ScrollWidget):
self.nodes = [ i for i in self.nodes if i != node ] self.nodes = [ i for i in self.nodes if i != node ]
class TextContent(PressableLabel): class TextContent(PressableLabel):
def __init__(self,level=0,**options): def __init__(self,color_level=0,**options):
PressableLabel.__init__(self,**options) PressableLabel.__init__(self,color_level=color_level,**options)
def selected(self):
pass
def unselected(self):
pass
class TextTreeNode(TreeNode): class TextTreeNode(TreeNode):
def buildContent(self): def buildContent(self):
txt = self.data.get(self.treeObj.options.textField, txt = self.data.get(self.treeObj.options.textField,
self.data.get(self.treeObj.options.idField,'defaulttext')) self.data.get(self.treeObj.options.idField,'defaulttext'))
self.content = TextContent( text=txt, self.content = TextContent(color_level=self.treeObj.color_level,
text=txt,
size_hint=(None,None), size_hint=(None,None),
font_size=CSize(1), font_size=CSize(1),
text_size=CSize(len(txt)-1,1), text_size=CSize(len(txt)-1,1),
@ -412,18 +407,12 @@ class TextTreeNode(TreeNode):
self.treeObj.select_row(self) self.treeObj.select_row(self)
def selected(self): def selected(self):
Logger.info('content selected ........') if hasattr(self.content,'selected'):
color, bgcolor = getColors(self.treeObj.color_level, self.content.selected()
selected=True)
self.content.bgcolor = bgcolor
self.content.color = color
def unselected(self): def unselected(self):
Logger.info('content unselected ........') if hasattr(self.content,'unselected'):
color, bgcolor = getColors(self.treeObj.color_level, self.content.unselected()
selected=False)
self.content.bgcolor = bgcolor
self.content.color = color
class TextTree(Tree): class TextTree(Tree):
def __init__(self,**options): def __init__(self,**options):

View File

@ -1,4 +1,5 @@
import os import os
from traceback import print_exc
from kivy.app import App from kivy.app import App
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
@ -11,6 +12,23 @@ from appPublic.dictObject import DictObject
from .kivysize import KivySizes from .kivysize import KivySizes
class NeedLogin(Exception):
pass
class InsufficientPrivilege(Exception):
pass
class HTTPError(Exception):
def __init__(self,resp_code):
self.resp_code = resp_code
Exception.__init__(self)
def __expr__(self):
return f'Exception:return code={self.resp_code}'
def __str__(self):
return f'Exception:return code={self.resp_code}'
alert_widget= None alert_widget= None
def blockImage(name): def blockImage(name):
@ -81,6 +99,9 @@ def alert(text,title='alert'):
x = x + ':hh' x = x + ':hh'
alert_widget.title = str(title) + x alert_widget.title = str(title) + x
alert_widget.open() alert_widget.open()
print('************')
print_exc()
print('************')
def StrConvert(s): def StrConvert(s):
if not s.startswith('py::'): if not s.startswith('py::'):

View File

@ -47,21 +47,31 @@ class StrInput(TextInput):
kv = {} kv = {}
a = { a = {
"allow_copy":True, "allow_copy":True,
"font_size":1, "password":False,
"multiline":False, "multiline":False,
"halign":"left", "halign":"left",
"hint_text":"", "hint_text":"",
"size_hint_y":None,
"width":20,
"height":2.5
} }
if kv.get('tip'): if kv.get('tip'):
a['hint_text'] = kv['tip'] a['hint_text'] = kv['tip']
a.update(kv) # a.update(kv)
a['width'] = CSize(kv.get('width',20)) w = kv.get('width',20)
a['height'] = CSize(kv.get('height',2.5)) h = kv.get('height',2.5)
if w <= 1:
a['size_hint_x'] = w
else:
a['size_hint_x'] = None
a['width'] = CSize(w)
if h <= 1:
a['size_hint_y'] = h
else:
a['size_hint_y'] = None
a['height'] = CSize(h)
a['font_size'] = CSize(kv.get('font_size',1)) a['font_size'] = CSize(kv.get('font_size',1))
a['password'] = kv.get('password',False)
a['multiline'] = kv.get('multiline',False)
Logger.info('TextInput:a=%s,h=%d,w=%d,CSize(1)=%d',a,h,w,CSize(1))
super(StrInput,self).__init__(**a) super(StrInput,self).__init__(**a)
self.old_value = None self.old_value = None
self.register_event_type('on_changed') self.register_event_type('on_changed')
@ -149,13 +159,16 @@ class MyDropDown(DropDown):
def __init__(self,**kw): def __init__(self,**kw):
super(MyDropDown,self).__init__() super(MyDropDown,self).__init__()
self.options = kw self.options = kw
self.textField = kw.get('textField',None) self.textField = kw.get('textField','text')
self.valueField = kw.get('valueField',None) self.valueField = kw.get('valueField','value')
if kw.get('url') is not None: self.loadSelectItems()
self.url = kw.get('url')
def loadSelectItems(self):
if self.options.get('url') is not None:
self.url = self.options.get('url')
self.setDataByUrl(self.url) self.setDataByUrl(self.url)
else: else:
self.si_data = kw.get('data') self.si_data = self.options.get('data')
self.setData(self.si_data) self.setData(self.si_data)
self.bind(on_select=lambda instance, x: self.selectfunc(x)) self.bind(on_select=lambda instance, x: self.selectfunc(x))
@ -179,12 +192,23 @@ class MyDropDown(DropDown):
def setData(self,data): def setData(self,data):
self.si_data = data self.si_data = data
self.clear_widgets() self.clear_widgets()
w = self.options.get('width',10)
h = self.options.get('height',2.5)
a = {}
if w <= 1:
a['size_hint_x'] = w
else:
a['size_hint_x'] = None
a['width'] = CSize(w)
if h <= 1:
a['size_hint_y'] = h
else:
a['size_hint_y'] = None
a['height'] = CSize(h)
a['font_size'] = CSize(self.options.get('font_size',1))
for d in data: for d in data:
dd = (d[self.valueField],d[self.textField]) dd = (d[self.valueField],d[self.textField])
b = Button(text=d[self.textField],font_size=CSize(1), b = Button(text=d[self.textField],**a)
size_hint=(None,None),
width=CSize(10),
height=CSize(2.5))
setattr(b,'kw_data',dd) setattr(b,'kw_data',dd)
b.bind(on_release=lambda btn: self.select(btn.kw_data)) b.bind(on_release=lambda btn: self.select(btn.kw_data))
self.add_widget(b) self.add_widget(b)
@ -205,10 +229,22 @@ class MyDropDown(DropDown):
class SelectInput(BoxLayout): class SelectInput(BoxLayout):
def __init__(self,**kw): def __init__(self,**kw):
a={}
w = kw.get('width',10)
h = kw.get('height',2.5)
if w <= 1:
a['size_hint_x'] = w
else:
a['size_hint_x'] = None
a['width'] = CSize(w)
if h <= 1:
a['size_hint_y'] = h
else:
a['size_hint_y'] = None
a['height'] = h
super(SelectInput,self).__init__(orientation='horizontal',\ super(SelectInput,self).__init__(orientation='horizontal',\
size_hint=(None,None), **a)
width=CSize(kw.get('width',10)),
height=CSize(kw.get('height',2.5)))
self.tinp = StrInput(size_hint_y=None,height=kw.get('height',2.5)) self.tinp = StrInput(size_hint_y=None,height=kw.get('height',2.5))
self.tinp.readonly = True self.tinp.readonly = True
newkw = {} newkw = {}