mirror of https://github.com/kivy/kivy.git
Merge pull request #1471 from matham/toggle_behavior
Add a ToggleButton type behavior
This commit is contained in:
commit
709f0574bc
|
@ -19,10 +19,11 @@ do::
|
|||
|
||||
'''
|
||||
|
||||
__all__ = ('ButtonBehavior', )
|
||||
__all__ = ('ButtonBehavior', 'ToggleButtonBehavior')
|
||||
|
||||
from kivy.clock import Clock
|
||||
from kivy.properties import OptionProperty
|
||||
from kivy.properties import OptionProperty, ObjectProperty
|
||||
from weakref import ref
|
||||
|
||||
|
||||
class ButtonBehavior(object):
|
||||
|
@ -44,7 +45,6 @@ class ButtonBehavior(object):
|
|||
:data:`state` is an :class:`~kivy.properties.OptionProperty`.
|
||||
'''
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.register_event_type('on_press')
|
||||
self.register_event_type('on_release')
|
||||
|
@ -106,6 +106,7 @@ class ButtonBehavior(object):
|
|||
'''
|
||||
self._do_press()
|
||||
self.dispatch('on_press')
|
||||
|
||||
def trigger_release(dt):
|
||||
self._do_release()
|
||||
self.dispatch('on_release')
|
||||
|
@ -114,3 +115,92 @@ class ButtonBehavior(object):
|
|||
else:
|
||||
Clock.schedule_once(trigger_release, duration)
|
||||
|
||||
|
||||
class ToggleButtonBehavior(ButtonBehavior):
|
||||
'''ToggleButton behavior, see ToggleButton module documentation for more
|
||||
information.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
'''
|
||||
|
||||
__groups = {}
|
||||
|
||||
group = ObjectProperty(None, allownone=True)
|
||||
'''Group of the button. If None, no group will be used (button is
|
||||
independent). If specified, :data:`group` must be a hashable object, like
|
||||
a string. Only one button in a group can be in 'down' state.
|
||||
|
||||
:data:`group` is a :class:`~kivy.properties.ObjectProperty`
|
||||
'''
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._previous_group = None
|
||||
super(ToggleButtonBehavior, self).__init__(**kwargs)
|
||||
|
||||
def on_group(self, *largs):
|
||||
groups = ToggleButtonBehavior.__groups
|
||||
if self._previous_group:
|
||||
group = groups[self._previous_group]
|
||||
for item in group[:]:
|
||||
if item() is self:
|
||||
group.remove(item)
|
||||
break
|
||||
group = self._previous_group = self.group
|
||||
if group not in groups:
|
||||
groups[group] = []
|
||||
r = ref(self, ToggleButtonBehavior._clear_groups)
|
||||
groups[group].append(r)
|
||||
|
||||
def _release_group(self, current):
|
||||
if self.group is None:
|
||||
return
|
||||
group = self.__groups[self.group]
|
||||
for item in group[:]:
|
||||
widget = item()
|
||||
if widget is None:
|
||||
group.remove(item)
|
||||
if widget is current:
|
||||
continue
|
||||
widget.state = 'normal'
|
||||
|
||||
def _do_press(self):
|
||||
self._release_group(self)
|
||||
self.state = 'normal' if self.state == 'down' else 'down'
|
||||
|
||||
def _do_release(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _clear_groups(wk):
|
||||
# auto flush the element when the weak reference have been deleted
|
||||
groups = ToggleButtonBehavior.__groups
|
||||
for group in list(groups.values()):
|
||||
if wk in group:
|
||||
group.remove(wk)
|
||||
break
|
||||
|
||||
@staticmethod
|
||||
def get_widgets(groupname):
|
||||
'''Return the widgets contained in a specific group. If the group
|
||||
doesn't exist, an empty list will be returned.
|
||||
|
||||
.. important::
|
||||
|
||||
Always release the result of this method! In doubt, do::
|
||||
|
||||
l = ToggleButtonBehavior.get_widgets('mygroup')
|
||||
# do your job
|
||||
del l
|
||||
|
||||
.. warning::
|
||||
|
||||
It's possible that some widgets that you have previously deleted are
|
||||
still in the list. Garbage collector might need more elements before
|
||||
flushing it. The return of this method is informative, you've been
|
||||
warned!
|
||||
'''
|
||||
groups = ToggleButtonBehavior.__groups
|
||||
if groupname not in groups:
|
||||
return []
|
||||
return [x() for x in groups[groupname] if x()][:]
|
||||
|
||||
|
|
|
@ -23,95 +23,13 @@ for a Button class.
|
|||
|
||||
__all__ = ('ToggleButton', )
|
||||
|
||||
from weakref import ref
|
||||
from kivy.uix.button import Button
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.uix.behaviors import ToggleButtonBehavior
|
||||
|
||||
|
||||
class ToggleButton(Button):
|
||||
class ToggleButton(ToggleButtonBehavior, Button):
|
||||
'''Toggle button class, see module documentation for more information.
|
||||
'''
|
||||
|
||||
__groups = {}
|
||||
|
||||
group = ObjectProperty(None, allownone=True)
|
||||
'''Group of the button. If None, no group will be used (button is
|
||||
independent). If specified, :data:`group` must be a hashable object, like
|
||||
a string. Only one button in a group can be in 'down' state.
|
||||
|
||||
:data:`group` is a :class:`~kivy.properties.ObjectProperty`
|
||||
'''
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._previous_group = None
|
||||
super(ToggleButton, self).__init__(**kwargs)
|
||||
|
||||
def on_group(self, *largs):
|
||||
groups = ToggleButton.__groups
|
||||
if self._previous_group:
|
||||
group = groups[self._previous_group]
|
||||
for item in group[:]:
|
||||
if item() is self:
|
||||
group.remove(item)
|
||||
break
|
||||
group = self._previous_group = self.group
|
||||
if group not in groups:
|
||||
groups[group] = []
|
||||
r = ref(self, ToggleButton._clear_groups)
|
||||
groups[group].append(r)
|
||||
|
||||
def _release_group(self, current):
|
||||
if self.group is None:
|
||||
return
|
||||
group = self.__groups[self.group]
|
||||
for item in group[:]:
|
||||
widget = item()
|
||||
if widget is None:
|
||||
group.remove(item)
|
||||
if widget is current:
|
||||
continue
|
||||
widget.state = 'normal'
|
||||
|
||||
def _do_press(self):
|
||||
self._release_group(self)
|
||||
self.state = 'normal' if self.state == 'down' else 'down'
|
||||
|
||||
def _do_release(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _clear_groups(wk):
|
||||
# auto flush the element when the weak reference have been deleted
|
||||
groups = ToggleButton.__groups
|
||||
for group in list(groups.values()):
|
||||
if wk in group:
|
||||
group.remove(wk)
|
||||
break
|
||||
|
||||
@staticmethod
|
||||
def get_widgets(groupname):
|
||||
'''Return the widgets contained in a specific group. If the group
|
||||
doesn't exist, an empty list will be returned.
|
||||
|
||||
.. important::
|
||||
|
||||
Always release the result of this method! In doubt, do::
|
||||
|
||||
l = ToggleButton.get_widgets('mygroup')
|
||||
# do your job
|
||||
del l
|
||||
|
||||
.. warning::
|
||||
|
||||
It's possible that some widgets that you have previously deleted are
|
||||
still in the list. Garbage collector might need more elements before
|
||||
flushing it. The return of this method is informative, you've been
|
||||
warned!
|
||||
|
||||
.. versionadded:: 1.3.0
|
||||
'''
|
||||
groups = ToggleButton.__groups
|
||||
if groupname not in groups:
|
||||
return []
|
||||
return [x() for x in groups[groupname] if x()][:]
|
||||
pass
|
||||
|
||||
|
|
Loading…
Reference in New Issue