181 lines
6.4 KiB
Python
181 lines
6.4 KiB
Python
#!/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"]]
|