Source code for pygame_menu._widgetmanager

"""
pygame-menu
https://github.com/ppizarror/pygame-menu

MENU WIDGET MANAGER
Easy widget add/remove to Menus.
"""

__all__ = ['WidgetManager']

import pygame_menu

from pygame_menu._base import Base
from pygame_menu.font import assert_font
from pygame_menu.utils import assert_vector, assert_color, assert_cursor, \
    assert_position_vector, warn

# Import widgets
from pygame_menu.widgets.core.widget import Widget, check_widget_mouseleave

from pygame_menu.widgets.widget.button import ButtonManager
from pygame_menu.widgets.widget.colorinput import ColorInputManager
from pygame_menu.widgets.widget.dropselect import DropSelectManager
from pygame_menu.widgets.widget.dropselect_multiple import DropSelectMultipleManager
from pygame_menu.widgets.widget.frame import FrameManager
from pygame_menu.widgets.widget.hmargin import HMarginManager
from pygame_menu.widgets.widget.image import ImageManager
from pygame_menu.widgets.widget.label import LabelManager
from pygame_menu.widgets.widget.menulink import MenuLinkManager
from pygame_menu.widgets.widget.none import NoneWidgetManager
from pygame_menu.widgets.widget.progressbar import ProgressBarManager
from pygame_menu.widgets.widget.rangeslider import RangeSliderManager
from pygame_menu.widgets.widget.selector import SelectorManager
from pygame_menu.widgets.widget.surface import SurfaceWidgetManager
from pygame_menu.widgets.widget.table import TableManager
from pygame_menu.widgets.widget.textinput import TextInputManager
from pygame_menu.widgets.widget.toggleswitch import ToggleSwitchManager
from pygame_menu.widgets.widget.vmargin import VMarginManager

from pygame_menu._types import Any, Dict, PaddingInstance


# noinspection PyProtectedMember
[docs]class WidgetManager( Base, ButtonManager, ColorInputManager, DropSelectManager, DropSelectMultipleManager, FrameManager, HMarginManager, ImageManager, LabelManager, MenuLinkManager, NoneWidgetManager, ProgressBarManager, RangeSliderManager, SelectorManager, SurfaceWidgetManager, TableManager, TextInputManager, ToggleSwitchManager, VMarginManager ): """ Add/Remove widgets to the Menu. :param menu: Menu reference """ def __init__(self, menu: 'pygame_menu.Menu') -> None: super(WidgetManager, self).__init__(object_id=menu.get_id() + '+widget-manager') self._menu = menu @property def _theme(self) -> 'pygame_menu.Theme': return self._menu.get_theme() def _add_submenu(self, menu: 'pygame_menu.Menu', hook: 'Widget') -> None: assert isinstance(menu, pygame_menu.Menu) assert menu != self._menu, 'submenu cannot point to menu itself' assert isinstance(hook, Widget) if menu not in self._menu._submenus.keys(): self._menu._submenus[menu] = [] assert hook not in self._menu._submenus[menu], \ f'widget {hook.get_class_id()} already hooks submenu {menu.get_class_id()}' self._menu._submenus[menu].append(hook) hook._menu_hook = menu def _filter_widget_attributes(self, kwargs: Dict) -> Dict[str, Any]: attributes = {} # align align = kwargs.pop('align', self._theme.widget_alignment) assert isinstance(align, str) attributes['align'] = align # background_color background_is_color = False background_color = kwargs.pop('background_color', self._theme.widget_background_color) if background_color is not None: if isinstance(background_color, pygame_menu.BaseImage): pass else: background_color = assert_color(background_color) background_is_color = True attributes['background_color'] = background_color # background_inflate background_inflate = kwargs.pop('background_inflate', self._theme.widget_background_inflate) if background_inflate == 0: background_inflate = (0, 0) assert_vector(background_inflate, 2, int) assert background_inflate[0] >= 0 and background_inflate[1] >= 0, \ 'both background inflate components must be equal or greater than zero' attributes['background_inflate'] = background_inflate # border_color border_color = kwargs.pop('border_color', self._theme.widget_border_color) if border_color is not None: border_color = assert_color(border_color) attributes['border_color'] = border_color # border_inflate border_inflate = kwargs.pop('border_inflate', self._theme.widget_border_inflate) if border_inflate == 0: border_inflate = (0, 0) assert_vector(border_inflate, 2, int) assert isinstance(border_inflate[0], int) and border_inflate[0] >= 0 assert isinstance(border_inflate[1], int) and border_inflate[1] >= 0 attributes['border_inflate'] = border_inflate # border_position border_position = kwargs.pop('border_position', self._theme.widget_border_position) assert_position_vector(border_position) attributes['border_position'] = border_position # border_width border_width = kwargs.pop('border_width', self._theme.widget_border_width) assert isinstance(border_width, int) and border_width >= 0 attributes['border_width'] = border_width # cursor cursor = kwargs.pop('cursor', self._theme.widget_cursor) assert_cursor(cursor) attributes['cursor'] = cursor # floating status float_ = kwargs.pop('float', False) assert isinstance(float_, bool) attributes['float'] = float_ float_origin_position = kwargs.pop('float_origin_position', False) assert isinstance(float_origin_position, bool) attributes['float_origin_position'] = float_origin_position # font_antialias attributes['font_antialias'] = self._theme.widget_font_antialias # font_background_color font_background_color = kwargs.pop('font_background_color', self._theme.widget_font_background_color) if font_background_color is None and \ self._theme.widget_font_background_color_from_menu and \ not background_is_color: if not isinstance(self._theme.background_color, pygame_menu.BaseImage): font_background_color = assert_color(self._theme.background_color) attributes['font_background_color'] = font_background_color # font_color font_color = kwargs.pop('font_color', self._theme.widget_font_color) attributes['font_color'] = assert_color(font_color) # font_name font_name = kwargs.pop('font_name', self._theme.widget_font) assert_font(font_name) attributes['font_name'] = str(font_name) # font_shadow font_shadow = kwargs.pop('font_shadow', self._theme.widget_font_shadow) assert isinstance(font_shadow, bool) attributes['font_shadow'] = font_shadow # font_shadow_color font_shadow_color = kwargs.pop('font_shadow_color', self._theme.widget_font_shadow_color) attributes['font_shadow_color'] = assert_color(font_shadow_color) # font_shadow_offset font_shadow_offset = kwargs.pop('font_shadow_offset', self._theme.widget_font_shadow_offset) assert isinstance(font_shadow_offset, int) attributes['font_shadow_offset'] = font_shadow_offset # font_shadow_position font_shadow_position = kwargs.pop('font_shadow_position', self._theme.widget_font_shadow_position) assert isinstance(font_shadow_position, str) attributes['font_shadow_position'] = font_shadow_position # font_size font_size = kwargs.pop('font_size', self._theme.widget_font_size) assert isinstance(font_size, int) assert font_size > 0, 'font size must be greater than zero' attributes['font_size'] = font_size # margin margin = kwargs.pop('margin', self._theme.widget_margin) if margin == 0: margin = (0, 0) assert_vector(margin, 2) attributes['margin'] = margin # padding padding = kwargs.pop('padding', self._theme.widget_padding) assert isinstance(padding, PaddingInstance) attributes['padding'] = padding # readonly_color readonly_color = kwargs.pop('readonly_color', self._theme.readonly_color) attributes['readonly_color'] = assert_color(readonly_color) # readonly_selected_color readonly_selected_color = kwargs.pop('readonly_selected_color', self._theme.readonly_selected_color) attributes['readonly_selected_color'] = assert_color(readonly_selected_color) # selection_color selection_color = kwargs.pop('selection_color', self._theme.selection_color) attributes['selection_color'] = assert_color(selection_color) # selection_effect selection_effect = kwargs.pop('selection_effect', self._theme.widget_selection_effect) if selection_effect is None: selection_effect = pygame_menu.widgets.NoneSelection() else: selection_effect = selection_effect.copy() assert isinstance(selection_effect, pygame_menu.widgets.core.Selection) selection_effect.set_color(attributes['selection_color']) attributes['selection_effect'] = selection_effect # shadow attributes['shadow_aa'] = kwargs.pop('shadow_aa', self._theme.widget_shadow_aa) attributes['shadow_color'] = kwargs.pop('shadow_color', self._theme.widget_shadow_color) attributes['shadow_radius'] = kwargs.pop('shadow_radius', self._theme.widget_shadow_radius) attributes['shadow_type'] = kwargs.pop('shadow_type', self._theme.widget_shadow_type) attributes['shadow_width'] = kwargs.pop('shadow_width', self._theme.widget_shadow_width) # tab_size attributes['tab_size'] = kwargs.pop('tab_size', self._theme.widget_tab_size) return attributes def _configure_widget(self, widget: 'Widget', **kwargs) -> None: assert isinstance(widget, Widget) widget.set_alignment( align=kwargs['align'] ) widget.set_background_color( color=kwargs['background_color'], inflate=kwargs['background_inflate'] ) widget.set_border( color=kwargs['border_color'], inflate=kwargs['border_inflate'], position=kwargs['border_position'], width=kwargs['border_width'] ) widget.set_controls( joystick=self._menu._joystick, keyboard=self._menu._keyboard, mouse=self._menu._mouse, touchscreen=self._menu._touchscreen ) widget.set_cursor( cursor=kwargs['cursor'] ) widget.set_float( float_status=kwargs['float'], origin_position=kwargs['float_origin_position'] ) widget.set_font( antialias=kwargs['font_antialias'], background_color=kwargs['font_background_color'], color=kwargs['font_color'], font=kwargs['font_name'], font_size=kwargs['font_size'], readonly_color=kwargs['readonly_color'], readonly_selected_color=kwargs['readonly_selected_color'], selected_color=kwargs['selection_color'] ) widget.set_font_shadow( color=kwargs['font_shadow_color'], enabled=kwargs['font_shadow'], offset=kwargs['font_shadow_offset'], position=kwargs['font_shadow_position'] ) widget.set_margin( x=kwargs['margin'][0], y=kwargs['margin'][1] ) widget.set_padding( padding=kwargs['padding'] ) widget.set_selection_effect( selection=kwargs['selection_effect'] ) widget.set_tab_size( tab_size=kwargs['tab_size'] ) widget.shadow( aa_amount=kwargs['shadow_aa'], color=kwargs['shadow_color'], corner_radius=kwargs['shadow_radius'], shadow_type=kwargs['shadow_type'], shadow_width=kwargs['shadow_width'] ) if self._theme.widget_background_inflate_to_selection: widget.background_inflate_to_selection_effect() widget._update__repr___(self) widget._keyboard_ignore_nonphysical = self._menu._keyboard_ignore_nonphysical widget.configured = True widget._configure() @staticmethod def _check_kwargs(kwargs: Dict) -> None: for invalid_keyword in kwargs.keys(): raise ValueError(f'widget addition optional parameter kwargs.{invalid_keyword} is not valid') def _append_widget(self, widget: 'Widget') -> None: assert isinstance(widget, Widget) if widget.get_menu() is None: widget.set_menu(self._menu) assert widget.get_menu() == self._menu, \ 'widget cannot have a different instance of menu' self._menu._check_id_duplicated(widget.get_id()) if widget.get_scrollarea() is None: widget.set_scrollarea(self._menu.get_scrollarea()) # Unselect widget.select(False) # Append to lists self._menu._widgets.append(widget) # Update selection index if self._menu._index < 0 and widget.is_selectable: widget.select() self._menu._index = len(self._menu._widgets) - 1 # Force menu rendering, this checks if the menu overflows or has sizing # errors; if added on execution time forces the update of the surface self._menu._widgets_surface = None try: self._menu._render() except (pygame_menu.menu._MenuSizingException, pygame_menu.menu._MenuWidgetOverflow): self._menu.remove_widget(widget) raise self._menu.render() # Sort frame widgets, as render position changes frame position/frame if len(self._menu._update_frames) > 0: self._menu._update_frames[0]._sort_menu_update_frames() # Update widgets check_widget_mouseleave() # Call event widget._append_to_menu() # noinspection PyMissingOrEmptyDocstring
[docs] def configure_defaults_widget(self, widget: 'Widget') -> None: self._configure_widget(widget, **self._filter_widget_attributes({}))
[docs] def generic_widget( self, widget: 'Widget', configure_defaults: bool = False ) -> 'Widget': """ Add generic widget to the Menu. .. note:: The widget should be fully configured by the user: font, padding, etc. .. note:: This is applied only to the base Menu (not the currently displayed, stored in ``_current`` pointer); for such behaviour apply to :py:meth:`pygame_menu.menu.Menu.get_current` object. .. warning:: Unintended behaviours may happen while using this method, use only with caution; specially while creating nested submenus with buttons. :param widget: Widget to be added :param configure_defaults: Apply defaults widget configuration (for example, theme) :return: The added widget object :rtype: :py:class:`pygame_menu.widgets.Widget` """ assert isinstance(widget, Widget) if widget.get_menu() is not None: raise ValueError('widget to be added is already appended to another Menu') # Raise warning if adding button with Menu if isinstance(widget, pygame_menu.widgets.Button) and widget.to_menu: warn( 'prefer adding submenus using add_button method instead, ' 'unintended behaviours may occur' ) # Configure widget if configure_defaults: self.configure_defaults_widget(widget) self._append_widget(widget) return widget