#!/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"]]