From 9b6084e15d48237a3b8a7ba57972034581a67bb1 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 14 Nov 2022 17:07:42 +0800 Subject: [PATCH] bugfix --- kivyblocks/bgcolorbehavior.py | 136 +++++++++--------- kivyblocks/blocks.py | 58 ++++++-- kivyblocks/mixin.py | 45 +++++- kivyblocks/modalbehavior.py | 17 ++- kivyblocks/register.py | 2 + kivyblocks/script.py | 6 +- kivyblocks/swipebehavior.py | 242 ++++++++++++++++---------------- kivyblocks/utils.py | 3 +- test/script/conf/config.json | 37 ++--- test/script/scripts/mainmenu.ui | 15 ++ test/script/scripts/t.m3u8 | 4 - 11 files changed, 335 insertions(+), 230 deletions(-) delete mode 100644 test/script/scripts/t.m3u8 diff --git a/kivyblocks/bgcolorbehavior.py b/kivyblocks/bgcolorbehavior.py index 952e539..c5231d7 100644 --- a/kivyblocks/bgcolorbehavior.py +++ b/kivyblocks/bgcolorbehavior.py @@ -1,67 +1,69 @@ -from kivy.logger import Logger -from kivy.graphics import Color, Rectangle, RoundedRectangle -from kivy.properties import ListProperty, NumericProperty -from .color_definitions import getColors - -_logcnt = 0 -class BGColorBehavior(object): - color_level=NumericProperty(0) - radius = ListProperty([]) - def __init__(self, **kwargs): - self.bg_ready = False - self.bgcolor = [] - self.fgcolor = [] - fg,bg= getColors(self.color_level) - self.fgcolor = fg - self.bgcolor = bg - self.normal_bgcolor = bg - self.normal_fgcolor = fg - fg,bg= getColors(self.color_level,selected=True) - self.selected_bgcolor = bg - self.selected_fgcolor = fg - # self.on_bgcolor() - - self.bind(size=self.onSize_bgcolor_behavior, - pos=self.onSize_bgcolor_behavior) - # self.bind(children=self.on_bgcolor) - - def onSize_bgcolor_behavior(self,o,v=None): - if not hasattr(self,'rect'): - self.on_bgcolor() - else: - self.rect.pos = self.pos - self.rect.size = self.size - - def on_bgcolor(self,o=None,v=None): - if self.bgcolor == []: - return - - if self.canvas: - with self.canvas.before: - Color(*self.bgcolor) - if self.radius != []: - self.rect = RoundedRectangle(pos=self.pos, - size=self.size, - radius=self.radius) - else: - self.rect = Rectangle(pos=self.pos, - size=self.size) - else: - print('on_bgcolor():self.canvas is None') - - def is_selected(self): - return self.bgcolor == self.selected_bgcolor - - def selected(self): - if self.bgcolor == self.selected_bgcolor: - return - self.bgcolor = self.selected_bgcolor - self.color = self.fgcolor = self.selected_fgcolor - self.on_bgcolor() - - def unselected(self): - if self.bgcolor == self.normal_bgcolor: - return - self.bgcolor = self.normal_bgcolor - self.color = self.fgcolor = self.normal_fgcolor - self.on_bgcolor() +from kivy.logger import Logger +from kivy.graphics import Color, Rectangle, RoundedRectangle +from kivy.properties import ListProperty, NumericProperty +from .color_definitions import getColors +from .mixin import register_mixin + +class BGColorBehavior(object): + color_level=NumericProperty(0) + radius = ListProperty([]) + def __init__(self, **kwargs): + self.bg_ready = False + self.bgcolor = [] + self.fgcolor = [] + fg,bg= getColors(self.color_level) + self.fgcolor = fg + self.bgcolor = bg + self.normal_bgcolor = bg + self.normal_fgcolor = fg + fg,bg= getColors(self.color_level,selected=True) + self.selected_bgcolor = bg + self.selected_fgcolor = fg + # self.on_bgcolor() + + self.bind(size=self.onSize_bgcolor_behavior, + pos=self.onSize_bgcolor_behavior) + # self.bind(children=self.on_bgcolor) + + def onSize_bgcolor_behavior(self,o,v=None): + if not hasattr(self,'rect'): + self.on_bgcolor() + else: + self.rect.pos = self.pos + self.rect.size = self.size + + def on_bgcolor(self,o=None,v=None): + if self.bgcolor == []: + return + + if self.canvas: + with self.canvas.before: + Color(*self.bgcolor) + if self.radius != []: + self.rect = RoundedRectangle(pos=self.pos, + size=self.size, + radius=self.radius) + else: + self.rect = Rectangle(pos=self.pos, + size=self.size) + else: + print('on_bgcolor():self.canvas is None') + + def is_selected(self): + return self.bgcolor == self.selected_bgcolor + + def selected(self): + if self.bgcolor == self.selected_bgcolor: + return + self.bgcolor = self.selected_bgcolor + self.color = self.fgcolor = self.selected_fgcolor + self.on_bgcolor() + + def unselected(self): + if self.bgcolor == self.normal_bgcolor: + return + self.bgcolor = self.normal_bgcolor + self.color = self.fgcolor = self.normal_fgcolor + self.on_bgcolor() + +register_mixin('BGColorBehavior', BGColorBehavior) diff --git a/kivyblocks/blocks.py b/kivyblocks/blocks.py index 3391e0e..185f8ba 100755 --- a/kivyblocks/blocks.py +++ b/kivyblocks/blocks.py @@ -103,6 +103,7 @@ def registerWidget(name:str,widget): globals()[name] = widget +klass_cnt = 0 class Blocks(EventDispatcher): def __init__(self): EventDispatcher.__init__(self) @@ -113,6 +114,47 @@ class Blocks(EventDispatcher): config = getConfig() 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): self.env[k] = v @@ -243,19 +285,17 @@ class Blocks(EventDispatcher): if not widgetClass: Logger.info("Block: w_build(), desc invalid", desc) raise Exception(desc) - - widgetClass = desc['widgettype'] opts_org = self.valueExpr(desc.get('options',{}).copy()) - opts = filter_mixin(opts_org) - bopts = get_mixins(opts_org) widget = None try: + """ klass = Factory.get(widgetClass) widget = klass(**opts) - mixin_behaviors(widget, bopts) + """ + widget = self.klassBuild(widgetClass, opts_org) except Exception as e: - print('Error:',widgetClass,'contructon error') + print('Error:',widgetClass,'construction error') print_exc() raise NotExistsObject(widgetClass) @@ -314,7 +354,7 @@ class Blocks(EventDispatcher): kw = self.valueExpr(sw.copy(), localnamespace={'self':widget}) w = b.widgetBuild(kw) - if w: + if w and not w.parent: widget.add_widget(w) @@ -684,7 +724,9 @@ class Blocks(EventDispatcher): if widgettype is None: print('Block3: desc must be a dict object not None') return None - return doit(desc) + w = doit(desc) + print('widgetBuild():w=', w) + return w @classmethod def findWidget(self, id:str, from_widget:Widget=None) -> Widget: diff --git a/kivyblocks/mixin.py b/kivyblocks/mixin.py index 67a2707..89e0650 100644 --- a/kivyblocks/mixin.py +++ b/kivyblocks/mixin.py @@ -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 _mix_ins = {} +# def on_press(inst, *args): +# pass + +# ButtonBehavior.on_press = on_press + 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): - 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): _mix_ins[name] = klass + Factory.register(name, klass) def mix_other(inst, other): - for k,v in other.__dict__.items(): - setattr(inst, k, v) + excluded = ['__class__', '__dict__', '__weakref__'] + 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): behaviors_kw = get_mixins(kwargs) for name, dic in behaviors_kw.items(): klass = _mix_ins.get(name) if klass: - other = Factory.Blocks().widgetBuild(dic) + mix_other(klass, inst.__class__) + desc = { + "widgettype":name, + "options":dic + } + other = Factory.Blocks().widgetBuild(desc) if 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) diff --git a/kivyblocks/modalbehavior.py b/kivyblocks/modalbehavior.py index a0db041..621aad8 100644 --- a/kivyblocks/modalbehavior.py +++ b/kivyblocks/modalbehavior.py @@ -1,10 +1,9 @@ +from kivy.core.window import Window from kivy.properties import DictProperty, BooleanProperty, \ StringProperty, OptionProperty, \ NumericProperty -from mixin import register_mixin - class ModalBehavior(object): auto_open = BooleanProperty(True) auto_dismiss = BooleanProperty(True) @@ -14,9 +13,10 @@ class ModalBehavior(object): 'cl', 'cc', 'cr', 'bl', 'bc', 'br']) def __init__(self, **kw): + for k,v in kw.items(): + setattr(self, k,v) self.time_task = None self._target = None - super(Modal, self).__init__(**kw) self.set_size_position() self._target.bind(size=self.set_size_position) self.register_event_type('on_open') @@ -28,11 +28,17 @@ class ModalBehavior(object): self.open() 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: + print('on_touchdown():auto_dismiss()') self.dispatch('on_pre_dismiss') self.dismiss() return True + else: + print('on_touchdown(): not auto_dismiss') + else: + print('on_touchdown():inside modal') def on_target(self, *args): self._target = None @@ -77,6 +83,7 @@ class ModalBehavior(object): self.pos = x, y else: 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): if self.time_task is not None: @@ -94,6 +101,7 @@ class ModalBehavior(object): self._target.disabled = True def dismiss(self, *args): + print('dismiss() called') if self.time_task: self.time_task.cancel() self.time_task = None @@ -115,4 +123,3 @@ class ModalBehavior(object): def on_pre_dismiss(self, *args): pass -register_mixin('modalbehavior', ModalBehavior) diff --git a/kivyblocks/register.py b/kivyblocks/register.py index 39cb3ab..fa947f2 100644 --- a/kivyblocks/register.py +++ b/kivyblocks/register.py @@ -45,10 +45,12 @@ from .ffpyplayer_video import FFVideo from .upload import UploadFile from .pyinterpreter import PyInterpreter from .circle_progress import CircleProgress +from .modalbehavior import ModalBehavior r = Factory.register # if kivy.platform in ['win','linux', 'macosx']: # r('ScreenWithMic', ScreenWithMic) +r('ModalBehavior', ModalBehavior) r('CircleProgress', CircleProgress) r('PyInterpreter', PyInterpreter) r('UploadFile', UploadFile) diff --git a/kivyblocks/script.py b/kivyblocks/script.py index e777b69..1d6eb2e 100644 --- a/kivyblocks/script.py +++ b/kivyblocks/script.py @@ -35,10 +35,10 @@ class Script: self.register('.ui', TemplateHandler) def url2filepath(self, url): - if url.startswith('file:///'): - url = url[8:] + if url.startswith('file://'): + url = url[7:] ret = join(self.root, *url.split('/')) - # print('url2filepath():root=', self.root, url, ret) + print('url2filepath():root=', self.root, url, ret) return ret def show_info(self, env): diff --git a/kivyblocks/swipebehavior.py b/kivyblocks/swipebehavior.py index e7a4e30..e18502d 100644 --- a/kivyblocks/swipebehavior.py +++ b/kivyblocks/swipebehavior.py @@ -1,118 +1,124 @@ -import time -from kivy.logger import Logger - -class SwipeBehavior(object): - def __init__(self, **kwargs): - object.__init__(self) - self.swipeenable = True - self.register_event_type('on_context_menu') - self.register_event_type('on_swipe_left') - self.register_event_type('on_swipe_right') - self.register_event_type('on_swipe_up') - self.register_event_type('on_swipe_down') - self.sb_start_point = None - self.sb_end_point = None - self.sb_start_time = None - self.sb_end_time = None - self.threshold=20 - self.threshold_time = 0.6 - self.bind(on_touch_down=self.on_touchdown) - self.bind(on_touch_move=self.on_touchmove) - self.bind(on_touch_up=self.on_touchup) - - def disable_swipe(self): - self.swipeenable = False - - def enable_swipe(self): - self.swipeenable = True - - def on_context_menu(self): - pass - # Logger.info('SwipeBehavior:on_context_menu fired') - - def on_swipe_left(self): - pass - # Logger.info('SwipeBehavior:on_swipe_left fired') - - def on_swipe_right(self): - pass - # Logger.info('SwipeBehavior:on_swipe_right fired') - - def on_swipe_up(self): - pass - # Logger.info('SwipeBehavior:on_swipe_up fired') - - def on_swipe_down(self): - pass - # Logger.info('SwipeBehavior:on_swipe_down fired') - - def on_touchdown(self,o, touch): - if touch.is_mouse_scrolling: - # Logger.info('SwipeBehavior:is_mouse_scrolling') - return False - if not self.collide_point(touch.x, touch.y): - return False - - # Logger.info('SwipeBehavior:touch_down fired') - if self.swipeenable: - # Logger.info('SwipeBehavior:touch_down fired') - self.sb_start_point = touch.pos - self.sb_start_time = time.time() - - def on_touchmove(self,o,touch): - if self.collide_point(*touch.pos) and self.swipeenable: - # Logger.info('SwipeBehavior:touch_move fired') - if self.sb_start_point is None: - self.sb_start_point = touch.pos - else: - self.sb_end_point = touch.pos - - def on_touchup(self,o,touch): - ret = False - if self.collide_point(*touch.pos) and self.swipeenable: - # Logger.info('SwipeBehavior:touch_up fired') - self.sb_end_point = touch.pos - self.sb_end_time = time.time() - self.check_context_menu() - ret = True - self.check_swipe() - self.sb_start_point = None - self.sb_end_point = None - self.sb_start_time = None - self.sb_end_time = None - - def check_context_menu(self): - if not self.sb_start_time: - return - if not self.sb_end_time: - return - period_time = self.sb_end_time - self.sb_start_time - # Logger.info('SwipeBehavior:period_time=%f,threshold_time=%f', - # period_time, self.threshold_time) - if period_time >= self.threshold_time: - self.dispatch('on_context_menu') - - def check_swipe(self): - if not self.sb_end_point: - return - - if not self.sb_start_point: - return - - if abs(self.sb_end_point[0] - self.sb_start_point[0]) > \ - abs(self.sb_end_point[1] - self.sb_start_point[1]): - Logger.info('SwipeBehavior:check_swipe x>y') - if self.sb_end_point[0] - self.sb_start_point[0] >= \ - self.threshold: - self.dispatch('on_swipe_right') - elif self.sb_start_point[0] - self.sb_end_point[0] >= \ - self.threshold: - self.dispatch('on_swipe_left') - else: - # Logger.info('SwipeBehavior:check_swipe x= \ - self.threshold: - self.dispatch('on_swipe_up') - elif self.sb_start_point[1] - self.sb_end_point[1] >= \ - self.threshold: - self.dispatch('on_swipe_down') +import time +from kivy.logger import Logger +from .mixin import register_mixin + +class SwipeBehavior(object): + def __init__(self, **kwargs): + object.__init__(self) + self.swipeenable = True + self.register_event_type('on_context_menu') + self.register_event_type('on_swipe_left') + self.register_event_type('on_swipe_right') + self.register_event_type('on_swipe_up') + self.register_event_type('on_swipe_down') + self.sb_start_point = None + self.sb_end_point = None + self.sb_start_time = None + self.sb_end_time = None + self.threshold=20 + self.threshold_time = 0.6 + self.bind(on_touch_down=self.on_touchdown) + self.bind(on_touch_move=self.on_touchmove) + self.bind(on_touch_up=self.on_touchup) + + def disable_swipe(self): + self.swipeenable = False + + def enable_swipe(self): + self.swipeenable = True + + def on_context_menu(self): + pass + # Logger.info('SwipeBehavior:on_context_menu fired') + + def on_swipe_left(self): + pass + # Logger.info('SwipeBehavior:on_swipe_left fired') + + def on_swipe_right(self): + pass + # Logger.info('SwipeBehavior:on_swipe_right fired') + + def on_swipe_up(self): + pass + # Logger.info('SwipeBehavior:on_swipe_up fired') + + def on_swipe_down(self): + pass + # Logger.info('SwipeBehavior:on_swipe_down fired') + + def on_touchdown(self,o, touch): + if touch.is_mouse_scrolling: + # Logger.info('SwipeBehavior:is_mouse_scrolling') + return False + if not self.collide_point(touch.x, touch.y): + return False + + # Logger.info('SwipeBehavior:touch_down fired') + if self.swipeenable: + # Logger.info('SwipeBehavior:touch_down fired') + touch.grab(self) + self.sb_start_point = touch.pos + self.sb_start_time = time.time() + + def on_touchmove(self,o,touch): + if self.collide_point(*touch.pos) and self.swipeenable: + # Logger.info('SwipeBehavior:touch_move fired') + if self.sb_start_point is None: + self.sb_start_point = touch.pos + else: + self.sb_end_point = touch.pos + + def on_touchup(self,o,touch): + ret = False + if self.collide_point(*touch.pos) and self.swipeenable and \ + touch.grab_current is self: + # Logger.info('SwipeBehavior:touch_up fired') + touch.ungrab(self) + self.sb_end_point = touch.pos + self.sb_end_time = time.time() + self.check_context_menu() + ret = True + self.check_swipe() + self.sb_start_point = None + self.sb_end_point = None + self.sb_start_time = None + self.sb_end_time = None + + def check_context_menu(self): + if not self.sb_start_time: + return + if not self.sb_end_time: + return + period_time = self.sb_end_time - self.sb_start_time + # Logger.info('SwipeBehavior:period_time=%f,threshold_time=%f', + # period_time, self.threshold_time) + if period_time >= self.threshold_time: + self.dispatch('on_context_menu') + + def check_swipe(self): + if not self.sb_end_point: + return + + if not self.sb_start_point: + return + + if abs(self.sb_end_point[0] - self.sb_start_point[0]) > \ + abs(self.sb_end_point[1] - self.sb_start_point[1]): + Logger.info('SwipeBehavior:check_swipe x>y') + if self.sb_end_point[0] - self.sb_start_point[0] >= \ + self.threshold: + self.dispatch('on_swipe_right') + elif self.sb_start_point[0] - self.sb_end_point[0] >= \ + self.threshold: + self.dispatch('on_swipe_left') + else: + # Logger.info('SwipeBehavior:check_swipe x= \ + self.threshold: + self.dispatch('on_swipe_up') + elif self.sb_start_point[1] - self.sb_end_point[1] >= \ + self.threshold: + self.dispatch('on_swipe_down') + +register_mixin('SwipeBehavior', SwipeBehavior) diff --git a/kivyblocks/utils.py b/kivyblocks/utils.py index 1413fd8..c1b1984 100644 --- a/kivyblocks/utils.py +++ b/kivyblocks/utils.py @@ -48,8 +48,7 @@ def SUPER(klass, obj, kw): super(klass, obj).__init__(**kw) for k,v in dic.items(): try: - if v is not None: - setattr(obj, k, v) + setattr(obj, k, v) except Exception as e: print(f'obj={obj}, setattr(obj, "{k}","{v}") error') print_exc() diff --git a/test/script/conf/config.json b/test/script/conf/config.json index 3c4603f..f07b98e 100644 --- a/test/script/conf/config.json +++ b/test/script/conf/config.json @@ -1,18 +1,19 @@ -{ - "font_sizes":{ - "smallest":1.5, - "small":2.5, - "normal":3.5, - "large":4.5, - "huge":5.5, - "hugest":6.5 - }, - "font_name":"normal", - "script_root":"$[workdir]$/scripts", - "root":{ - "widgettype":"urlwidget", - "options":{ - "url":"file://index.ui" - } - } -} +{ + "font_sizes":{ + "smallest":1.5, + "small":2.5, + "normal":3.5, + "large":4.5, + "huge":5.5, + "hugest":6.5 + }, + "font_name":"normal", + "uihome":"file://", + "script_root":"$[workdir]$/scripts", + "root":{ + "widgettype":"urlwidget", + "options":{ + "url":"file://index.ui" + } + } +} diff --git a/test/script/scripts/mainmenu.ui b/test/script/scripts/mainmenu.ui index 1d9b7a0..9f0b671 100644 --- a/test/script/scripts/mainmenu.ui +++ b/test/script/scripts/mainmenu.ui @@ -14,6 +14,21 @@ "label":"Setting", "icon":"{{entire_url('/imgs/setting.png')}}", "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')}}" } ] } diff --git a/test/script/scripts/t.m3u8 b/test/script/scripts/t.m3u8 deleted file mode 100644 index 87aa3d8..0000000 --- a/test/script/scripts/t.m3u8 +++ /dev/null @@ -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