Faster highlighting via single loop and callback
Thanks yet again to @tshirtman for suggesting this. Instead of defining a `on_mouse_pos()` on every widget simply register and track each widget and loop through them all once (or as much as is necessary) in a single callback. The assumption here is that we get a performance boost by looping widgets instead of having `kivy` loop and call back each widget thus avoiding costly python function calls.kivy_mainline_and_py3.8
parent
0fbab8b831
commit
5c070b1c43
|
@ -5,7 +5,6 @@ __author__ = 'Olivier Poyen'
|
||||||
|
|
||||||
|
|
||||||
from kivy.properties import BooleanProperty, ObjectProperty
|
from kivy.properties import BooleanProperty, ObjectProperty
|
||||||
from kivy.factory import Factory
|
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,38 +22,50 @@ class HoverBehavior(object):
|
||||||
# be used in `on_enter` or `on_leave` in order to know where was dispatched
|
# be used in `on_enter` or `on_leave` in order to know where was dispatched
|
||||||
# the event.
|
# the event.
|
||||||
border_point = ObjectProperty(None)
|
border_point = ObjectProperty(None)
|
||||||
|
_widgets = []
|
||||||
|
_last_hovered = None
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.register_event_type('on_enter')
|
self.register_event_type('on_enter')
|
||||||
self.register_event_type('on_leave')
|
self.register_event_type('on_leave')
|
||||||
Window.bind(mouse_pos=self.on_mouse_pos)
|
HoverBehavior._widgets.append(self)
|
||||||
super(HoverBehavior, self).__init__(**kwargs)
|
super(HoverBehavior, self).__init__(**kwargs)
|
||||||
|
Window.bind(mouse_pos=self.on_mouse_pos)
|
||||||
|
|
||||||
def on_mouse_pos(self, *args):
|
@classmethod
|
||||||
|
def on_mouse_pos(cls, *args):
|
||||||
|
# XXX: how to still do this at the class level?
|
||||||
# don't proceed if I'm not displayed <=> If have no parent
|
# don't proceed if I'm not displayed <=> If have no parent
|
||||||
if not self.get_root_window():
|
# if not self.get_root_window():
|
||||||
return
|
# return
|
||||||
|
|
||||||
pos = args[1]
|
pos = args[1]
|
||||||
# Next line to_widget allow to compensate for relative layout
|
# Next line to_widget allow to compensate for relative layout
|
||||||
inside = self.collide_point(*self.to_widget(*pos))
|
for widget in cls._widgets:
|
||||||
if self.hovered == inside:
|
w_coords = widget.to_widget(*pos)
|
||||||
# We have already done what was needed
|
inside = widget.collide_point(*w_coords)
|
||||||
|
if inside and widget.hovered:
|
||||||
|
return
|
||||||
|
elif inside:
|
||||||
|
# un-highlight the last highlighted
|
||||||
|
last_hovered = cls._last_hovered
|
||||||
|
if last_hovered:
|
||||||
|
last_hovered.dispatch('on_leave')
|
||||||
|
last_hovered.hovered = False
|
||||||
|
|
||||||
|
# highlight new widget
|
||||||
|
widget.border_point = pos
|
||||||
|
widget.hovered = True
|
||||||
|
widget.dispatch('on_enter')
|
||||||
|
cls._last_hovered = widget
|
||||||
return
|
return
|
||||||
self.border_point = pos
|
|
||||||
self.hovered = inside
|
|
||||||
if inside:
|
|
||||||
self.dispatch('on_enter')
|
|
||||||
else:
|
|
||||||
self.dispatch('on_leave')
|
|
||||||
|
|
||||||
# implement these in the widget impl
|
# implement these in the widget impl
|
||||||
|
|
||||||
def on_enter(self):
|
@classmethod
|
||||||
|
def on_enter(cls):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_leave(self):
|
@classmethod
|
||||||
|
def on_leave(cls):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# register for global use via kivy.factory.Factory
|
|
||||||
Factory.register('HoverBehavior', HoverBehavior)
|
|
||||||
|
|
Loading…
Reference in New Issue