.. currentmodule:: sdl2.ext User interface elements ======================= User interface elements within :mod:`sdl2.ext` are simple :class:`Sprite` objects, which are enhanced by certain input hooks; as such, they are not classes on their own, but implemented as mixins. The user input itself is handled by an :class:`UIProcessor` object, which takes care of delegating input events, such as mouse movements, clicks and keyboard input, to the correct UI element. Depending on the event type (e.g. pressing a mouse button), the UIProcessor will execute its matching method (e.g. ``mousedown()``) with only those UI elements, which support the event type. .. image:: images/uiprocessing.png .. _ui-elem-types: UI element types ---------------- Every :class:`sdl2.ext` UI element is a simple :class:`Sprite` object, to which additional attributes and methods are bound. Every UI element features the following attributes ``element.uitype`` The ``uitype`` attribute can have one of the following values, identifying the UI element: * ``BUTTON`` - a UI element, which can react on mouse input * ``CHECKBUTTON`` - as ``BUTTON``, but it retains its state on clicks * ``TEXTENTRY`` - a UI element that reacts on keyboard input ``element.events`` A dictionary containing the SDL2 event mappings. Each supported SDL2 event (e.g. ``SDL_MOUSEMOTION``) is associated with a bound :class:`EventHandler` acting as callback for user code (e.g. ``mousemotion()``). Depending on the exact type of the element, it will feature additional methods and attributes explained below. Button elements ^^^^^^^^^^^^^^^ ``BUTTON`` UI elements feature a ``state`` attribute, which can be one of the following values. ======== ===================================================================== state Description ======== ===================================================================== RELEASED Indicates that the UI element is not pressed. HOVERED Indicates that the mouse cursor is currently hovering the UI element. PRESSED Indicates that a mouse button is pressed on the UI element. ======== ===================================================================== ``BUTTON`` UI elements react with the following event handlers on events: ``button.motion(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if the mouse moves around while being over the ``BUTTON``. ``button.pressed(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if a mouse button is pressed on the ``BUTTON``. ``button.released(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if a mouse button is released on the ``BUTTON``. ``button.click(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if a mouse button is pressed and released on the ``BUTTON``. Besides the ``BUTTON`` a special ``CHECKBUTTON`` UI element type exists, which enhances the ``BUTTON`` bindings by an additional ``checked`` attribute. The ``checked`` attribute switches its status (``False`` to ``True`` and ``True`` to ``False``) every time the UI element is clicked. Text input elements ^^^^^^^^^^^^^^^^^^^ ``TEXTENTRY`` elements react on text input, once they are activated. Text being input, once a ``TEXTENTRY`` has been activated, is stored in its ``text`` attribute. The ``TEXTENTRY`` reacts with the following event handlers on events: ``textentry.motion(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if the mouse moves around while being over the ``TEXTENTRY``. ``textentry.pressed(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if a mouse button is pressed on the ``TEXTENTRY``. ``textentry.released(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked, if a mouse button is released on the ``TEXTENTRY``. ``textentry.keydown(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked on pressing a key. ``textentry.keyup(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked on releasing a key. ``textentry.input(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked on text input events. Text input events are automatically created, once the :class:`UIProcessor` activates a ``TEXTENTRY`` UI element. ``textentry.editing(event : sdl2.events.SDL_Event)`` An :class:`EventHandler` that is invoked on text editing events. Text editing events are automatically created, once the :class:`UIProcessor` activates a ``TEXTENTRY`` UI element. Text editing events are however only raised, if an IME system is involved, which combines glyphs and symbols to characters or word fragments. API --- .. class:: UIFactory(spritefactory : SpriteFactory[, **kwargs]) A factory class for creating UI elements. The :class:`UIFactory` allows you to create UI elements based on the :class:`Sprite` class. To do this, it requires a :class:`SpriteFactory`, which will create the sprites, to which the :class:`UIFactory` then binds the additional methods and attributes. The additional *kwargs* are used as default arguments for creating **sprites** within the factory methods. .. attribute:: default_args A dictionary containing the default arguments to be passed to the sprite creation methods of the bound :class:`SpriteFactory`. .. attribute:: spritefactory The :class:`SpriteFactory` being used for creating new :class:`Sprite` objects. .. method:: create_button(**kwargs) -> Sprite Creates a new button UI element. *kwargs* are the arguments to be passed for the sprite construction and can vary depending on the sprite type. See :meth:`SpriteFactory.create_sprite()` for further details. .. method:: create_check_button(**kwargs) -> Sprite Creates a new checkbutton UI element. *kwargs* are the arguments to be passed for the sprite construction and can vary depending on the sprite type. See :meth:`SpriteFactory.create_sprite()` for further details. .. method:: create_text_entry(**kwargs) -> Sprite Creates a new textentry UI element. *kwargs* are the arguments to be passed for the sprite construction and can vary depending on the sprite type. See :meth:`SpriteFactory.create_sprite()` for further details. .. method:: from_color(color : object , size) -> Sprite Creates a UI element with a specific color. *uitype* must be one of the supported :ref:`ui-elem-types` classifying the type of UI element to be created. .. method:: from_image(uitype : int, fname : str) -> Sprite Creates a UI element from an image file. The image must be loadable via :func:`load_image()`. *uitype* must be one of the supported :ref:`ui-elem-types` classifying the type of UI element to be created. .. method:: from_object(uitype : int, obj: object) -> Sprite Creates a UI element from an object. The object will be passed through :func:`sdl2.rwops_from_object()` in order to try to load image data from it. *uitype* must be one of the supported :ref:`ui-elem-types` classifying the type of UI element to be created. .. method:: from_surface(uitype : int, surface : SDL_Surface[, free=False]) -> Sprite Creates a UI element from the passed :class:`sdl2.surface.SDL_Surface`. If *free* is set to ``True``, the passed *surface* will be freed automatically. *uitype* must be one of the supported :ref:`ui-elem-types` classifying the type of UI element to be created. .. class:: UIProcessor() A processing system for user interface elements and events. .. attribute:: handlers A dict containing the mapping of SDL2 events to the available :class:`EventHandler` bindings of the :class:`UIProcessor`. .. method:: activate(component : object) -> None Activates a UI control to receive text input. .. method:: deactivate(component : object) -> None Deactivate the currently active UI control. .. method:: passevent(component : object, event : SDL_Event) -> None Passes the *event* to a *component* without any additional checks or restrictions. .. method:: mousemotion(component : object, event : SDL_Event) -> None Checks, if the event's motion position is on the *component* and executes the component's event handlers on demand. If the motion event position is not within the area of the *component*, nothing will be done. In case the component is a ``BUTTON``, its :attr:`state` will be adjusted to reflect, if it is currently hovered or not. .. method:: mousedown(component : object, event : SDL_Event) -> None Checks, if the event's button press position is on the *component* and executes the component's event handlers on demand. If the button press position is not within the area of the component, nothing will be done. In case the component is a ``BUTTON``, its :attr:`state` will be adjusted to reflect, if it is currently pressed or not. In case the component is a ``TEXTENTRY`` and the pressed button is the primary mouse button, the component will be marked as the next control to activate for text input. .. method:: mouseup(self, component, event) -> None Checks, if the event's button release position is on the *component* and executes the component's event handlers on demand. If the button release position is not within the area of the component, nothing will be done. In case the component is a ``BUTTON``, its :attr:`state` will be adjusted to reflect, whether it is hovered or not. If the button release followed a button press on the same component and if the button is the primary button, the ``click()`` event handler is invoked, if the component is a ``BUTTON``. .. method:: dispatch(obj : object, event : SDL_Event) -> None Passes an event to the given object. If *obj* is a :class:`World` object, UI relevant components will receive the event, if they support the event type. If *obj* is a single object, ``obj.events`` **must** be a dict consisting of SDL event type identifiers and :class:`EventHandler` instances bound to the object. If *obj* is a iterable, such as a list or set, every item within *obj* **must** feature an ``events`` attribute as described above. .. method:: process(world : World, components : iterable) -> None The :class:`UIProcessor` class does not implement the `process()` method by default. Instead it uses :meth:`dispatch()` to send events around to components. :meth:`process()` does nothing.