Source code for campy.gui.ginteractors

"""Graphical interactors.

This module provides five types of interactors:

- :class:`GButton`: A clickable button.
- :class:`GCheckBox`: A checkable box.
- :class:`GSlider`: A slider between numeric values.
- :class:`GChooser`: A list of selectable items.
- :class:`GTextField`: A single-line string entry.
"""

import campy.graphics.gobjects as gobjects
import campy.private.platform as _platform

from campy.graphics.gevents import *


[docs]class GInteractor(gobjects.GObject): """Superclass of all graphical interactors. In most applications, interactors will be added to one region in a :class:`GWindow`, but interactors can also be placed in specific positions in a :class:`GCompound` (or the :class:`GWindow`'s default top :class:`GCompound`) just like any other :class:`GObject`. """ def __init__(self, command=''): """Initialize a :class:`GInteractor` with a command. The command is accessible as part of any :class:`GActionEvents` that this interactor generates. :param command: The action command for this interactor. """ # TODO(sredmond): Consider stripping the concept of "action commands" # entirely, since it violates "There should be one way to do things." super().__init__() self._command = command @property def command(self): """Get or set the action command for this interactor.""" return self._command @command.setter def command(self, command): self._command = command _platform.Platform().ginteractor_set_action_command(self, action_command)
# TODO(sredmond): Provide a general mechanism for setting an interactor's size. # TODO(sredmond): Provide a general mechanism to get the location and bounds # of an interactor.
[docs]class GButton(GInteractor): """An onscreen, clickable button. The following program displays a button that, when pressed, generates the message: "Please do not press this button again!" (credit Douglas Adams):: window = GWindow() button = GButton('RED BUTTON') window.add_to_region(button, Region.NORTH) @button.onclick def chastise(event): event.button.label = 'Please do not press this button again!' event.button.disable() """ def __init__(self, label): """Construct a GButton with the specified label. :param str label: A label for this GButton. """ super().__init__() self._label = label self._disabled = False # Collection of self._listeners = [] # Tell the underlying platform to construct this object. _platform.Platform().gbutton_constructor(self) ############## # PROPERTIES # ############## @property def label(self): """Get or set this :class:`GButton`:'s label.""" return self._label @label.setter def label(self, label): self._label = label _platform.Platform().gbutton_set_label(self) @property def disabled(self): """Get or set whether this :class:`GButton`: is disabled.""" return self._disabled @disabled.setter def disabled(self, disabled): self._disabled = disabled _platform.Platform().gbutton_set_disabled(self) # TODO(sredmond): Consider removing these convenience functions.
[docs] def enable(self): """Enable this :class:`GButton`, meaning it can receive clicks.""" self.disabled = False
[docs] def disable(self): """Disable this :class:`GButton`, meaning it cannot receive clicks.""" self.disabled = True
################# # BUTTON EVENTS # #################
[docs] def onclick(self, function): self._listeners.append(function) return function
[docs] def add_click_handler(self, function): self._listeners.append(function)
[docs] def remove_click_handler(self, function): try: self._listeners.remove(function) return True except ValueError: return False
def _click(self, event): """Default click implementation doesn't do anything.""" for listener in self._listeners: listener(event)
[docs] def click(self): # Make an event to pass to click handler. event = GActionEvent(None, None, None) self._click(event)
[docs]class GCheckBox(GInteractor): """An onscreen check box. Clicking once on the check box selects it; clicking again removes the selection. Clicking on the box generates a GActionEvent. """ def __init__(self, label): """ Creates a GCheckBox with the specified label. In contrast to the GButton constructor, this constructor does not set an action command. :param str label: A label for this GCheckBox. """ super().__init__() self.label = label _platform.Platform().gcheckbox_constructor(self, label) @property def selected(self): """Get or set whether the checkbox is selected. :param bool state: Whether the checkbox is selected. """ return _platform.Platform().gcheckbox_is_selected(self) @selected.setter def selected(self, state): return _platform.Platform().gcheckbox_set_selected(self, state) def __str__(self): return 'GCheckBox("{}")'.format(self.label)
[docs]class GSlider(GInteractor): """An onscreen slider. Dragging """ def __init__(self, min_value=0, max_value=100, starting_value=50): """Create a horizontal GSlider. The client can specify a minimum value, maximum value, and starting value. :param int min_value: The minimum value of this GSlider. :param int max_value: The maximum value of this GSlider. Should be >= min_value, but this is not currently enforced. :param int starting_value: The starting value of this GSlider. Should be between min_value and max_value. If not, is set to min_value. """ super().__init__() self.min_value = min_value self.max_value = max_value # TODO(sredmond): Error check that max_value >= min_value. if not min_value <= starting_value <= max_value: starting_value = min_value _platform.Platform().gslider_constructor(self, min_value, max_value, starting_value) @property def value(self): """Get or set the current value of the GSlider. :param int value: The value of the GSlider. """ return _platform.Platform().gslider_get_value(self) @value.setter def value(self, new_value): _platform.Platform().gslider_set_value(self, value) def __str__(self): return "GSlider(value={}, min={}, max={})".format(self.value, self.min_value, self.max_value)
[docs]class GTextField(GInteractor): """An onscreen text field for entering short text strings. Hitting RETURN in a text field generates a :class:`GActionEvent`. """ def __init__(self, width=10): """Create a text field with a maximum width. A :class:`GActionEvent` is generated whenever the user presses the RETURN key while this interactor has focus. :param width: The maximum number of characters this field can hold. """ super().__init__(self) self._width = width _platform.Platform().gtextfield_constructor(self) @property def text(self): """Get or set the contents of this :class:`GTextField`.""" return _platform.Platform().gtextfield_get_text(self) @text.setter def text(self, content): _platform.Platform().gtextfield_set_text(self, content) def __str__(self): return "GTextField(text={}, width={})".format(self.text, self.width)
[docs]class GChooser(GInteractor): """A list of selectable items. You can construct a :class:`GChooser` with an ordered collection of items, or :meth:`add` and :meth:`remove` items after construction:: size_chooser = GChooser('Small', 'Medium', 'Large') size_chooser.add_item('X-Large') size_chooser.remove_item('Medium') To get the selected item:: size_chooser = GChooser('Small', 'Medium', 'Large') selected = size_chooser.selected_item """ def __init__(self, *items): """Create a :class:`GChooser`, optionally with some items. These items are supplied as extra positional arguments:: size_chooser = GChooser('Small', 'Medium', 'Large') To construct a :class:`GChooser` from a collection of elements, unpack the elements into the constructor:: options = ('Small', 'Medium', 'Large') size_chooser = GChooser(*options) A :class:`GActionEvent` is generated each time the user selects an item. """ super().__init__(self) self._items = list(items) _platform.Platform().gchooser_constructor(self)
[docs] def add_item(self, item): """Add a new option to this :class:`GChooser`. :param item: The new item to add to this :class:`GChooser`. """ self._items.append(item) _platform.Platform().gchooser_add_item(self, item)
[docs] def remove_item(self, item): """Remove an option from this :class:`GChooser`. :param item: The item to remove from this :class:`GChooser`. :return: Whether the item was removed. """ try: self._items.remove(item) _platform.Platform().gchooser_remove_item(self, item) return True except ValueError: return False
@property def selected_item(self): """Get or set the currently selected item of this :class:`GChooser`. Setting the selected item to something not in this :class:`GChooser`'s list of items results in no change. """ return _platform.Platform().gchooser_get_selected_item(self) @selected_item.setter def selected_item(self, item): if item not in self._items: return _platform.Platform().gchooser_set_selected_item(self, item) def __str__(self): return "GChooser(items={})".format(self._items)