This commit is contained in:
yumoqing 2022-11-14 17:07:42 +08:00
parent 1352d23245
commit 9b6084e15d
11 changed files with 335 additions and 230 deletions

View File

@ -2,8 +2,8 @@ from kivy.logger import Logger
from kivy.graphics import Color, Rectangle, RoundedRectangle from kivy.graphics import Color, Rectangle, RoundedRectangle
from kivy.properties import ListProperty, NumericProperty from kivy.properties import ListProperty, NumericProperty
from .color_definitions import getColors from .color_definitions import getColors
from .mixin import register_mixin
_logcnt = 0
class BGColorBehavior(object): class BGColorBehavior(object):
color_level=NumericProperty(0) color_level=NumericProperty(0)
radius = ListProperty([]) radius = ListProperty([])
@ -65,3 +65,5 @@ class BGColorBehavior(object):
self.bgcolor = self.normal_bgcolor self.bgcolor = self.normal_bgcolor
self.color = self.fgcolor = self.normal_fgcolor self.color = self.fgcolor = self.normal_fgcolor
self.on_bgcolor() self.on_bgcolor()
register_mixin('BGColorBehavior', BGColorBehavior)

View File

@ -103,6 +103,7 @@ def registerWidget(name:str,widget):
globals()[name] = widget globals()[name] = widget
klass_cnt = 0
class Blocks(EventDispatcher): class Blocks(EventDispatcher):
def __init__(self): def __init__(self):
EventDispatcher.__init__(self) EventDispatcher.__init__(self)
@ -113,6 +114,47 @@ class Blocks(EventDispatcher):
config = getConfig() config = getConfig()
self.script = Script() self.script = Script()
def klassBuild(self, klass_name, options):
global klass_cnt
exclude_mixin = filter_mixin(options)
mixins = get_mixins(options)
klasses = [
{
'name':klass_name,
'klass':Factory.get(klass_name),
'opts':exclude_mixin
}
]
if mixins == {}:
return Factory.get(klass_name)(**options)
env = globals().copy()
lenv = {}
for n, d, in mixins.items():
klasses.append({
'name':n,
'klass':Factory.get(n),
'opts':d
})
print('mixins=', mixins)
env['klasses'] = klasses
ids = [ i for i in range(len(klasses))]
ids.reverse()
klasslist = ','.join([f'klasses[{i}]["klass"]' for i in ids])
code = f"""class ClassX{klass_cnt}({klasslist}):
def __init__(self):
for i in range(len(klasses)):
print(klasses[i]['opts'])
klasses[i]['klass'].__init__(self, **klasses[i]['opts'])
x = ClassX{klass_cnt}()
"""
print(code)
exec(code, env, lenv)
w = lenv.get('x', None)
klass_cnt += 1
return w
def set(self, k:str, v): def set(self, k:str, v):
self.env[k] = v self.env[k] = v
@ -243,19 +285,17 @@ class Blocks(EventDispatcher):
if not widgetClass: if not widgetClass:
Logger.info("Block: w_build(), desc invalid", desc) Logger.info("Block: w_build(), desc invalid", desc)
raise Exception(desc) raise Exception(desc)
widgetClass = desc['widgettype']
opts_org = self.valueExpr(desc.get('options',{}).copy()) opts_org = self.valueExpr(desc.get('options',{}).copy())
opts = filter_mixin(opts_org)
bopts = get_mixins(opts_org)
widget = None widget = None
try: try:
"""
klass = Factory.get(widgetClass) klass = Factory.get(widgetClass)
widget = klass(**opts) widget = klass(**opts)
mixin_behaviors(widget, bopts) """
widget = self.klassBuild(widgetClass, opts_org)
except Exception as e: except Exception as e:
print('Error:',widgetClass,'contructon error') print('Error:',widgetClass,'construction error')
print_exc() print_exc()
raise NotExistsObject(widgetClass) raise NotExistsObject(widgetClass)
@ -314,7 +354,7 @@ class Blocks(EventDispatcher):
kw = self.valueExpr(sw.copy(), kw = self.valueExpr(sw.copy(),
localnamespace={'self':widget}) localnamespace={'self':widget})
w = b.widgetBuild(kw) w = b.widgetBuild(kw)
if w: if w and not w.parent:
widget.add_widget(w) widget.add_widget(w)
@ -684,7 +724,9 @@ class Blocks(EventDispatcher):
if widgettype is None: if widgettype is None:
print('Block3: desc must be a dict object not None') print('Block3: desc must be a dict object not None')
return None return None
return doit(desc) w = doit(desc)
print('widgetBuild():w=', w)
return w
@classmethod @classmethod
def findWidget(self, id:str, from_widget:Widget=None) -> Widget: def findWidget(self, id:str, from_widget:Widget=None) -> Widget:

View File

@ -1,27 +1,62 @@
from kivy.factory import Factory
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.behaviors import CodeNavigationBehavior
from kivy.uix.behaviors import CompoundSelectionBehavior
from kivy.uix.behaviors import CoverBehavior
from kivy.uix.behaviors import DragBehavior
from kivy.uix.behaviors import EmacsBehavior
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.uix.behaviors import TouchRippleBehavior
from kivy.uix.behaviors import TouchRippleButtonBehavior
from kivy.factory import Factory from kivy.factory import Factory
_mix_ins = {} _mix_ins = {}
# def on_press(inst, *args):
# pass
# ButtonBehavior.on_press = on_press
def filter_mixin(kwargs): def filter_mixin(kwargs):
return {k:v for k, v in kwargs.items() if not k.endswith('behavior')} return {k:v for k, v in kwargs.items() if not k.endswith('Behavior')}
def get_mixins(kwargs): def get_mixins(kwargs):
return {k:v for k, v in kwargs.items() if k.endswith('behavior')} return {k:v for k, v in kwargs.items() if k.endswith('Behavior')}
def register_mixin(name, klass): def register_mixin(name, klass):
_mix_ins[name] = klass _mix_ins[name] = klass
Factory.register(name, klass)
def mix_other(inst, other): def mix_other(inst, other):
for k,v in other.__dict__.items(): excluded = ['__class__', '__dict__', '__weakref__']
setattr(inst, k, v) keys = [ k for k in dir(other) if k not in excluded ]
for k in keys:
if not hasattr(inst, k):
setattr(inst, k, getattr(other, k))
def mixin_behaviors(inst, kwargs): def mixin_behaviors(inst, kwargs):
behaviors_kw = get_mixins(kwargs) behaviors_kw = get_mixins(kwargs)
for name, dic in behaviors_kw.items(): for name, dic in behaviors_kw.items():
klass = _mix_ins.get(name) klass = _mix_ins.get(name)
if klass: if klass:
other = Factory.Blocks().widgetBuild(dic) mix_other(klass, inst.__class__)
desc = {
"widgettype":name,
"options":dic
}
other = Factory.Blocks().widgetBuild(desc)
if other: if other:
mix_other(inst, other) mix_other(inst, other)
register_mixin('ButtonBehavior', ButtonBehavior)
register_mixin('CodeNavigationBehavior', CodeNavigationBehavior)
register_mixin('CompoundSelectionBehavior', CompoundSelectionBehavior)
register_mixin('CoverBehavior', CoverBehavior)
register_mixin('DragBehavior', DragBehavior)
register_mixin('EmacsBehavior', EmacsBehavior)
register_mixin('FocusBehavior', FocusBehavior)
register_mixin('ToggleButtonBehavior', ToggleButtonBehavior)
register_mixin('TouchRippleBehavior', TouchRippleBehavior)
register_mixin('TouchRippleButtonBehavior', TouchRippleButtonBehavior)

View File

@ -1,10 +1,9 @@
from kivy.core.window import Window
from kivy.properties import DictProperty, BooleanProperty, \ from kivy.properties import DictProperty, BooleanProperty, \
StringProperty, OptionProperty, \ StringProperty, OptionProperty, \
NumericProperty NumericProperty
from mixin import register_mixin
class ModalBehavior(object): class ModalBehavior(object):
auto_open = BooleanProperty(True) auto_open = BooleanProperty(True)
auto_dismiss = BooleanProperty(True) auto_dismiss = BooleanProperty(True)
@ -14,9 +13,10 @@ class ModalBehavior(object):
'cl', 'cc', 'cr', 'cl', 'cc', 'cr',
'bl', 'bc', 'br']) 'bl', 'bc', 'br'])
def __init__(self, **kw): def __init__(self, **kw):
for k,v in kw.items():
setattr(self, k,v)
self.time_task = None self.time_task = None
self._target = None self._target = None
super(Modal, self).__init__(**kw)
self.set_size_position() self.set_size_position()
self._target.bind(size=self.set_size_position) self._target.bind(size=self.set_size_position)
self.register_event_type('on_open') self.register_event_type('on_open')
@ -28,11 +28,17 @@ class ModalBehavior(object):
self.open() self.open()
def on_touchdown(self, o, touch): def on_touchdown(self, o, touch):
if not self.collide_point(touch.x, touch.y): print('on_touchdown() called')
if not self.collide_point(touch.x, touch.y):
if self.auto_dismiss: if self.auto_dismiss:
print('on_touchdown():auto_dismiss()')
self.dispatch('on_pre_dismiss') self.dispatch('on_pre_dismiss')
self.dismiss() self.dismiss()
return True return True
else:
print('on_touchdown(): not auto_dismiss')
else:
print('on_touchdown():inside modal')
def on_target(self, *args): def on_target(self, *args):
self._target = None self._target = None
@ -77,6 +83,7 @@ class ModalBehavior(object):
self.pos = x, y self.pos = x, y
else: else:
self.pos = self._target.pos[0] + x, self._target.pos[1] + y self.pos = self._target.pos[0] + x, self._target.pos[1] + y
print("modal",self._target.size, self.position, self.pos, self.size, self.size_hint)
def open(self): def open(self):
if self.time_task is not None: if self.time_task is not None:
@ -94,6 +101,7 @@ class ModalBehavior(object):
self._target.disabled = True self._target.disabled = True
def dismiss(self, *args): def dismiss(self, *args):
print('dismiss() called')
if self.time_task: if self.time_task:
self.time_task.cancel() self.time_task.cancel()
self.time_task = None self.time_task = None
@ -115,4 +123,3 @@ class ModalBehavior(object):
def on_pre_dismiss(self, *args): def on_pre_dismiss(self, *args):
pass pass
register_mixin('modalbehavior', ModalBehavior)

View File

@ -45,10 +45,12 @@ from .ffpyplayer_video import FFVideo
from .upload import UploadFile from .upload import UploadFile
from .pyinterpreter import PyInterpreter from .pyinterpreter import PyInterpreter
from .circle_progress import CircleProgress from .circle_progress import CircleProgress
from .modalbehavior import ModalBehavior
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('ModalBehavior', ModalBehavior)
r('CircleProgress', CircleProgress) r('CircleProgress', CircleProgress)
r('PyInterpreter', PyInterpreter) r('PyInterpreter', PyInterpreter)
r('UploadFile', UploadFile) r('UploadFile', UploadFile)

View File

@ -35,10 +35,10 @@ class Script:
self.register('.ui', TemplateHandler) self.register('.ui', TemplateHandler)
def url2filepath(self, url): def url2filepath(self, url):
if url.startswith('file:///'): if url.startswith('file://'):
url = url[8:] url = url[7:]
ret = join(self.root, *url.split('/')) ret = join(self.root, *url.split('/'))
# print('url2filepath():root=', self.root, url, ret) print('url2filepath():root=', self.root, url, ret)
return ret return ret
def show_info(self, env): def show_info(self, env):

View File

@ -1,5 +1,6 @@
import time import time
from kivy.logger import Logger from kivy.logger import Logger
from .mixin import register_mixin
class SwipeBehavior(object): class SwipeBehavior(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -56,6 +57,7 @@ class SwipeBehavior(object):
# Logger.info('SwipeBehavior:touch_down fired') # Logger.info('SwipeBehavior:touch_down fired')
if self.swipeenable: if self.swipeenable:
# Logger.info('SwipeBehavior:touch_down fired') # Logger.info('SwipeBehavior:touch_down fired')
touch.grab(self)
self.sb_start_point = touch.pos self.sb_start_point = touch.pos
self.sb_start_time = time.time() self.sb_start_time = time.time()
@ -69,8 +71,10 @@ class SwipeBehavior(object):
def on_touchup(self,o,touch): def on_touchup(self,o,touch):
ret = False ret = False
if self.collide_point(*touch.pos) and self.swipeenable: if self.collide_point(*touch.pos) and self.swipeenable and \
touch.grab_current is self:
# Logger.info('SwipeBehavior:touch_up fired') # Logger.info('SwipeBehavior:touch_up fired')
touch.ungrab(self)
self.sb_end_point = touch.pos self.sb_end_point = touch.pos
self.sb_end_time = time.time() self.sb_end_time = time.time()
self.check_context_menu() self.check_context_menu()
@ -116,3 +120,5 @@ class SwipeBehavior(object):
elif self.sb_start_point[1] - self.sb_end_point[1] >= \ elif self.sb_start_point[1] - self.sb_end_point[1] >= \
self.threshold: self.threshold:
self.dispatch('on_swipe_down') self.dispatch('on_swipe_down')
register_mixin('SwipeBehavior', SwipeBehavior)

View File

@ -48,8 +48,7 @@ def SUPER(klass, obj, kw):
super(klass, obj).__init__(**kw) super(klass, obj).__init__(**kw)
for k,v in dic.items(): for k,v in dic.items():
try: try:
if v is not None: setattr(obj, k, v)
setattr(obj, k, v)
except Exception as e: except Exception as e:
print(f'obj={obj}, setattr(obj, "{k}","{v}") error') print(f'obj={obj}, setattr(obj, "{k}","{v}") error')
print_exc() print_exc()

View File

@ -8,6 +8,7 @@
"hugest":6.5 "hugest":6.5
}, },
"font_name":"normal", "font_name":"normal",
"uihome":"file://",
"script_root":"$[workdir]$/scripts", "script_root":"$[workdir]$/scripts",
"root":{ "root":{
"widgettype":"urlwidget", "widgettype":"urlwidget",

View File

@ -14,6 +14,21 @@
"label":"Setting", "label":"Setting",
"icon":"{{entire_url('/imgs/setting.png')}}", "icon":"{{entire_url('/imgs/setting.png')}}",
"url":"{{entire_url('t.ui')}}" "url":"{{entire_url('t.ui')}}"
},
{
"id":"behavior1",
"label":"behavior1",
"url":"{{entire_url('boxlayout/behavior.ui')}}"
},
{
"id":"modal1",
"label":"Modal Text",
"url":"{{entire_url('boxlayout/modalbehavior.ui')}}"
},
{
"id":"boxlayout",
"label":"WBoxLayout",
"url":"{{entire_url('boxlayout/normal.ui')}}"
} }
] ]
} }

View File

@ -1,4 +0,0 @@
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=898222,RESOLUTION=1047x576,CODECS="avc1.77.30,mp4a.40.2"
chunklist_w891111828.m3u8