pygo/sgc/widgets/radio_button.py

181 lines
6.4 KiB
Python
Raw Normal View History

2012-04-14 22:38:47 +00:00
#!/usr/bin/env python
# Copyright (C) 2012 Michael Rochester, Sam Bull
"""
Radio Button, allows the user to select a single option from a group.
"""
import pygame.mouse
from pygame.locals import *
from _locals import *
from _locals import focus
from base_widget import Simple
class Radio(Simple):
"""
A selectable radio button.
Attributes:
groups: A dictionary containing the active radio button or ``None`` for
each radio group. Key is ``str`` containing the name of the group.
selected: True if widget is the currently selected radio button in
it's group.
Images:
'image': The default, inactive button state.
'over': The image used when the cursor is hovering over the button.
'active': The image used for the active button in a group
(if applicable).
"""
_can_focus = True
_available_images = ("over", "active")
_settings_default = {"group": None, "label": "", "col": (118, 45, 215),
"label_col": Font.col, "radius": 7}
_over_state = False
_draw_rect = False
groups = {}
_order = {}
def _config(self, **kwargs):
"""
group: ``str`` Name of the group for widget to be added to.
label: ``str`` Text to be displayed to the right of the widget.
active: ``True`` Makes this the active radio button for it's group.
col: ``tuple`` (r,g,b) The colour to be used for the 'over' image
if not using a custom image.
label_col: ``tuple`` (r,g,b) The colour for the label text.
radius: ``int`` Radius of the button if not using a custom image.
"""
if "group" in kwargs:
if kwargs["group"] not in self.groups:
self.groups[kwargs["group"]] = None
self._order[kwargs["group"]] = []
self._settings["group"] = kwargs["group"]
self._order[self._settings["group"]].append(self)
if "label" in kwargs:
self._settings["label"] = kwargs["label"]
if "col" in kwargs:
self._settings["col"] = kwargs["col"]
if "label_col" in kwargs:
self._settings["label_col"] = kwargs["label_col"]
if "radius" in kwargs:
self._settings["radius"] = kwargs["radius"]
assert self._settings["group"] is not None
if "active" in kwargs:
self._draw()
self._activate()
def _draw(self, draw):
r = self._settings["radius"]
# Render text
label = Simple(Font["widget"].render(self._settings["label"], True,
self._settings["label_col"]))
if not hasattr(self, "image"):
self._create_base_images((r*2 + 10 + label.rect.w,
max(label.rect.height, r*2)))
pos = (r, self.rect.h/2)
# Background circles
draw.circle(self._images["image"], (255,255,255), pos, r)
draw.circle(self._images["over"], self._settings["col"], pos, r)
# Border circles
draw.circle(self._images["image"], (0,0,1), pos, r, 1)
draw.circle(self._images["over"], (0,0,1), pos, r, 1)
# Central dot for 'active' state
draw.circle(self._images["active"],(0,0,1), pos, int(r/1.5))
label.rect.midleft = (r*2 + 10, pos[1])
self._images["image"].blit(label.image, label.pos)
self._images["over"].blit(label.image, label.pos)
self._draw_button()
def update(self, time):
"""Update the radio button each frame."""
if self.rect_abs.collidepoint(pygame.mouse.get_pos()):
if not self._over_state:
# Draw over state
self._over_state = True
self._draw_button()
elif self._over_state:
# Draw normal state
self._over_state = False
self._draw_button()
def _event(self, event):
if event.type == MOUSEBUTTONUP and event.button == 1:
if self.rect_abs.collidepoint(event.pos):
self._activate()
elif event.type == KEYDOWN:
def focus_change(diff):
next_widget = order[order.index(widget) + diff]
next_widget._activate()
if self._parent:
self._parent._focus.add(1, next_widget)
else:
focus.add(1, next_widget)
order = self._order[self._settings["group"]]
widget = self.groups[self._settings["group"]]
if event.key == K_UP and order.index(widget) > 0:
focus_change(-1)
elif event.key == K_DOWN and order.index(widget) < len(order)-1:
focus_change(1)
elif event.type == KEYUP:
if event.key in (K_SPACE, K_RETURN):
self._activate()
def _focus_enter(self, focus):
"""Draw rectangle when focus is gained from keyboard."""
if focus == 1:
self._draw_rect = True
self._draw_button()
def _focus_exit(self):
"""Stop drawing rectangle when focus is lost."""
self._draw_rect = False
self._draw_button()
def _draw_button(self):
"""Draw the button."""
if not self._over_state:
self.image = self._images["image"].copy()
else:
self.image = self._images["over"].copy()
if self.groups[self._settings["group"]] is self:
self.image.blit(self._images["active"], (0,0))
# Draw dotted rectangle to show keyboard focus
if self._draw_rect:
self._dotted_rect()
def _activate(self):
"""Reset drawing of new and previous widget."""
old = self.groups[self._settings["group"]]
self.groups[self._settings["group"]] = self
if old is not None: old._draw_button()
self._draw_button()
def clear(self, group=None):
"""
Clear a group so no radio button is selected.
Args:
group: ``str`` Group name to clear. Clear this widget's group if None.
"""
if group is None: group = self._settings["group"]
old = self.groups[group]
self.groups[group] = None
if old is not None: old._draw_button()
@property
def selected(self):
return self is self.groups[self._settings["group"]]