Exemplo n.º 1
0
    def update_callback(self, callback, *args):
        """
        Update function triggered by the button; ``callback`` cannot point to a Menu, that behaviour
        is only valid using ``Menu.add_button()`` method.

        .. note::

            If button points to a submenu, and the callback is changed to a function,
            the submenu will be removed from the parent menu. Thus preserving the structure.

        :param callback: Function
        :type callback: callable
        :param args: Arguments used by the function once triggered
        :type args: any
        :return: None
        """
        assert is_callable(callback), 'only function are allowed'

        # If return is a Menu object, remove it from submenus list
        if self._menu is not None and self._on_return is not None and self.to_menu:
            assert len(self._args) == 1
            submenu = self._args[0]  # Menu
            assert self._menu.in_submenu(submenu, recursive=False), \
                'pointed menu is not in submenu list of parent container'
            # noinspection PyProtectedMember
            assert self._menu._remove_submenu(
                submenu, recursive=False), 'submenu could not be removed'
            self.to_menu = False

        self._args = args or []  # type: list
        self._on_return = callback
Exemplo n.º 2
0
    def add_callable(self,
                     fun: Union[Callable[['pygame.Surface', Any], Any],
                                Callable[[], Any]],
                     prev: bool = True,
                     pass_args: bool = True) -> str:
        """
        Adds a callable method. The function receives the surface and the object;
        for example, if adding to a widget:

        .. code-block:: python

            fun(surface, object)

        .. note::

            If your callable function changes over time set ``decorator.cache=False``
            or force cache manually by calling Decorator method
            :py:meth:`pygame_menu._decorator.Decorator.force_cache_update`. Also,
            the object should force the menu surface cache to update.

        :param fun: Function
        :param prev: If ``True`` draw previous the object, else draws post
        :param pass_args: If ``False`` function is called without (surface, object) as args
        :return: ID of the decoration
        """
        assert is_callable(fun), 'fun must be a callable type'
        assert isinstance(pass_args, bool)
        if pass_args:
            return self._add_decor(DECORATION_CALLABLE, prev, fun)
        else:
            return self._add_decor(DECORATION_CALLABLE_NO_ARGS, prev, fun)
Exemplo n.º 3
0
    def add_draw_callback(self, draw_callback):
        """
        Adds a function to the widget to be executed each time the widget is drawn.

        The function that this method receives receives two objects: the widget itself and
        the menu reference.

        .. code-block:: python

            import math

            def draw_update_function(widget, menu):
                t = widget.get_attribute('t', 0)
                t += menu.get_clock().get_time()
                widget.set_padding(10*(1 + math.sin(t)))) # Oscillating padding

            button = menu.add_button('This button updates its padding', None)
            button.set_draw_callback(draw_update_function)

        After creating a new callback, this functions returns the ID of the call. It can be removed
        anytime using ``widget.remove_draw_callback(id)``.

        :param draw_callback: Function
        :type draw_callback: callable
        :return: Callback ID
        :rtype: str
        """
        assert is_callable(
            draw_callback), 'draw callback must be a function type'
        callback_id = str(uuid4())
        self._draw_callbacks[callback_id] = draw_callback
        return callback_id
Exemplo n.º 4
0
    def update_callback(self, callback: Callable, *args) -> None:
        """
        Update function triggered by the button; ``callback`` cannot point to a Menu, that
        behaviour is only valid using :py:meth:`pygame_menu.menu.Menu.add.button` method.

        .. note::

            If button points to a submenu, and the callback is changed to a
            function, the submenu will be removed from the parent Menu. Thus
            preserving the structure.

        :param callback: Function
        :param args: Arguments used by the function once triggered
        :return: None
        """
        assert is_callable(callback), \
            'only callable (function-type) are allowed'

        # If return is a Menu object, remove it from submenus list
        if self._menu is not None and self._onreturn is not None and self.to_menu:
            assert len(self._args) == 1
            submenu = self._args[0]  # Menu
            assert self._menu.in_submenu(submenu), \
                'pointed menu is not in submenu list of parent container'
            # noinspection PyProtectedMember
            assert self._menu._remove_submenu(submenu), \
                'submenu could not be removed'
            self.to_menu = False

        self._args = args or []
        self._onreturn = callback
Exemplo n.º 5
0
    def _get_current_selected_text(self) -> str:
        if len(self._selected_indices) == 0:
            return self._placeholder

        # Apply selected format
        if self._selection_placeholder_format == DROPSELECT_MULTIPLE_SFORMAT_TOTAL:
            return self._placeholder_selected.format(len(self._selected_indices))

        list_items = self._get_selected_items_list_str()
        if self._selection_placeholder_format == DROPSELECT_MULTIPLE_SFORMAT_LIST_COMMA:
            return self._placeholder_selected.format(','.join(list_items))

        elif self._selection_placeholder_format == DROPSELECT_MULTIPLE_SFORMAT_LIST_HYPHEN:
            return self._placeholder_selected.format('-'.join(list_items))

        elif isinstance(self._selection_placeholder_format, str):
            return self._placeholder_selected.format(self._selection_placeholder_format.join(list_items))

        elif is_callable(self._selection_placeholder_format):
            try:
                o = self._selection_placeholder_format(list_items)
            except TypeError:
                raise ValueError('selection placeholder function receives only 1 '
                                 'argument (a list of the selected items string)'
                                 ' and must return a string')
            assert isinstance(o, str), \
                'output from selection placeholder format function must be a ' \
                'string (List[str]=>str), not {0} type ({1} returned)' \
                ''.format(type(o), o)
            return self._placeholder_selected.format(o)

        else:
            raise ValueError('invalid selection placeholder format type')
Exemplo n.º 6
0
 def __init__(self,
              menu: 'pygame_menu.Menu',
              menu_opener_handler: Callable,
              link_id: str = '') -> None:
     assert isinstance(menu, pygame_menu.Menu)
     assert is_callable(menu_opener_handler), \
         'menu opener handler must be callable (a function)'
     super(MenuLink, self).__init__(widget_id=link_id)
     self.menu = menu
     self._onreturn = menu_opener_handler
     self._visible = False
     self.is_selectable = False
Exemplo n.º 7
0
    def set_selection_callback(
            self,
            callback: Optional[Callable[[bool, 'Widget', 'pygame_menu.Menu'], Any]]
    ) -> None:
        """
        Update the button selection callback, once button is selected, the callback
        function is executed as follows:

        .. code-block:: python

            callback(selected, widget, menu)

        :param callback: Callback when selecting the widget, executed in :py:meth:`pygame_menu.widgets.core.widget.Widget.set_selected`
        :return: None
        """
        if callback is not None:
            assert is_callable(callback), \
                'callback must be callable (function-type) or None'
        self._onselect = callback
Exemplo n.º 8
0
    def set_title_generator(self,
                            generator: LabelTitleGeneratorType) -> 'Label':
        """
        Set a title generator. This function is executed each time the label updates,
        returning a new title (string) which replaces the current label title.

        The generator does not take any input as argument.

        :param generator: Function which generates a new text status
        :return: Self reference
        """
        if generator is not None:
            assert is_callable(generator)
        self._title_generator = generator

        # Update update widgets
        menu_update_widgets = self._get_menu_update_widgets()
        if generator is None and self in menu_update_widgets:
            menu_update_widgets.remove(self)
        if generator is not None and self not in menu_update_widgets:
            menu_update_widgets.append(self)
        return self
Exemplo n.º 9
0
    def add_update_callback(self, update_callback):
        """
        Adds a function to the widget to be executed each time the widget is updated.

        The function that this method receives receives two objects: the widget itself and
        the menu reference. It is similar to ``add_draw_callback``.

        After creating a new callback, this functions returns the ID of the call. It can be removed
        anytime using ``widget.remove_update_callback(id)``.

        .. note:: Not all widgets are updated, so the provided function may never be executed.

        :param update_callback: Function
        :type update_callback: callable
        :return: Callback ID
        :rtype: str
        """
        assert is_callable(
            update_callback), 'update callback must be a function type'
        callback_id = str(uuid4())
        self._update_callbacks[callback_id] = update_callback
        return callback_id
Exemplo n.º 10
0
    def _get(params: Dict[str, Any],
             key: str,
             allowed_types: Optional[Union[Type, str, List[Type],
                                           Tuple[Type, ...]]] = None,
             default: Any = None) -> Any:
        """
        Return a value from a dictionary.

        Custom types (str)
            -   alignment           – pygame-menu alignment (locals)
            -   callable            – Is callable type, same as ``"function"``
            -   color               – Check color
            -   color_image         – Color or :py:class:`pygame_menu.baseimage.BaseImage`
            -   color_image_none    – Color, :py:class:`pygame_menu.baseimage.BaseImage`, or None
            -   color_none          – Color or None
            -   cursor              – Cursor object (pygame)
            -   font                – Font type
            -   image               – Value must be ``BaseImage``
            -   none                – None only
            -   position            – pygame-menu position (locals)
            -   position_vector     – pygame-menu position (str or vector)
            -   tuple2              – Only valid numeric tuples ``(x, y)`` or ``[x, y]``
            -   tuple2int           – Only valid integer tuples ``(x, y)`` or ``[x, y]``
            -   tuple3              – Only valid numeric tuples ``(x, y, z)`` or ``[x, y, z]``
            -   tuple3int           – Only valid integer tuples ``(x, y, z)`` or ``[x, y, z]``
            -   type                – Type-class (bool, str, etc...)

        :param params: Parameters dictionary
        :param key: Key to look for
        :param allowed_types: List of allowed types
        :param default: Default value to return
        :return: The value associated to the key
        """
        value = params.pop(key, default)
        if allowed_types is not None:
            other_types = []  # Contain other types to check from
            if not isinstance(allowed_types, VectorInstance):
                allowed_types = (allowed_types, )
            for val_type in allowed_types:

                if val_type == 'alignment':
                    assert_alignment(value)

                elif val_type == callable or val_type == 'function' or val_type == 'callable':
                    assert is_callable(value), \
                        'value must be callable type'

                elif val_type == 'color':
                    value = assert_color(value)

                elif val_type == 'color_image':
                    if not isinstance(value, BaseImage):
                        value = assert_color(value)

                elif val_type == 'color_image_none':
                    if not (value is None or isinstance(value, BaseImage)):
                        value = assert_color(value)

                elif val_type == 'color_none':
                    if value is not None:
                        value = assert_color(value)

                elif val_type == 'cursor':
                    assert_cursor(value)

                elif val_type == 'font':
                    assert_font(value)

                elif val_type == 'image':
                    assert isinstance(value, BaseImage), \
                        'value must be BaseImage type'

                elif val_type == 'none':
                    assert value is None

                elif val_type == 'position':
                    assert_position(value)

                elif val_type == 'position_vector':
                    assert_position_vector(value)

                elif val_type == 'type':
                    assert isinstance(value, type), \
                        'value is not type-class'

                elif val_type == 'tuple2':
                    assert_vector(value, 2)

                elif val_type == 'tuple2int':
                    assert_vector(value, 2, int)

                elif val_type == 'tuple3':
                    assert_vector(value, 3)

                elif val_type == 'tuple3int':
                    assert_vector(value, 3, int)

                else:  # Unknown type
                    assert isinstance(val_type, type), \
                        'allowed type "{0}" is not a type-class'.format(val_type)
                    other_types.append(val_type)

            # Check other types
            if len(other_types) > 0:
                others = tuple(other_types)
                assert isinstance(value, others), \
                    'Theme.{} type shall be in {} types (got {})'.format(key, others, type(value))

        return value
Exemplo n.º 11
0
    def __init__(self,
                 title='',
                 widget_id='',
                 onchange=None,
                 onreturn=None,
                 args=None,
                 kwargs=None):
        assert isinstance(widget_id, str), 'widget id must be a string'
        if onchange:
            assert is_callable(onchange), 'onchange must be callable or None'
        if onreturn:
            assert is_callable(onreturn), 'onreturn must be callable or None'

        # Store id, if None or empty create new ID based on UUID
        if widget_id is None or len(widget_id) == 0:
            widget_id = uuid4()

        self._alignment = _locals.ALIGN_CENTER
        self._attributes = {}  # Stores widget attributes
        self._background_color = None
        self._background_inflate = (0, 0)
        self._events = []  # type: list
        self._id = str(widget_id)
        self._margin = (0.0, 0.0)  # type: tuple
        self._max_width = None  # type: (int,float)
        self._padding = (0, 0, 0, 0)  # top, right, bottom, left
        self._selection_time = 0  # type: float
        self._title = to_string(title)

        # Widget transforms
        self._angle = 0  # Rotation angle (degrees)
        self._flip = (False, False)  # x, y
        self._scale = [False, 1, 1, False,
                       False]  # do_scale, x, y, smooth, use_same_xy
        self._translate = (0.0, 0.0)  # type: tuple

        # Widget rect. This object does not contain padding. For getting the widget+padding
        # use .get_rect() Widget method instead
        self._rect = pygame.Rect(0, 0, 0, 0)  # type: pygame.Rect

        # Callbacks
        self._draw_callbacks = {}  # type: dict
        self._update_callbacks = {}  # type: dict

        self._args = args or []  # type: list
        self._kwargs = kwargs or {}  # type: dict
        self._on_change = onchange  # type: callable
        self._on_return = onreturn  # type: callable

        # Surface of the widget
        self._surface = None  # type: (pygame.Surface,None)

        # Menu reference
        self._menu = None

        # If this is True then the widget forces the Menu to update because the
        # widget render has changed
        self._menu_surface_needs_update = False

        # Modified in set_font() method
        self._font = None  # type: (pygame.font.Font,None)
        self._font_antialias = True  # type: bool
        self._font_background_color = None  # type: (tuple, None)
        self._font_color = (0, 0, 0)  # type: tuple
        self._font_name = ''  # type: str
        self._font_selected_color = (255, 255, 255)  # type: tuple
        self._font_size = 0  # type: int

        # Text shadow
        self._shadow = False  # type: bool
        self._shadow_color = (0, 0, 0)  # type: tuple
        self._shadow_offset = 2.0  # type: float
        self._shadow_position = _locals.POSITION_NORTHWEST
        self._shadow_tuple = None  # (x px offset, y px offset)
        self._create_shadow_tuple()

        # Rendering, this variable may be used by render() method
        # If the hash of the variables change respect to the last render hash
        # (hash computed using self._hash_variables() method)
        # then the widget should render and update the hash
        self._last_render_hash = 0  # type: int

        # Selection effect, for avoiding exception while getting object rect, NullSelection
        # was created. Initially it was None
        self._selection_effect = _NullSelection()  # type: Selection

        # Public attributes
        self.active = False  # Widget requests focus
        self.is_selectable = True  # Some widgets cannot be selected like labels
        self.joystick_enabled = True
        self.lock_position = False  # If True, locks position after first call to .set_position(x,y) method
        self.mouse_enabled = True
        self.selected = False
        self.selection_effect_enabled = True  # Some widgets cannot have selection effect
        self.selection_expand_background = False  # If True, the widget background will inflate to match selection margin if selected
        self.sound = Sound()  # type: Sound
        self.touchscreen_enabled = True
        self.visible = True  # Use .show() or .hide() to modify this status
Exemplo n.º 12
0
    def _get(params: Dict[str, Any], key: str,
             allowed_types: Optional[Union[Type, str, List[Type], Tuple[Type, ...]]] = None,
             default: Any = None) -> Any:
        """
        Return a value from a dictionary.

        Custom types (str)
            -   alignment           pygame-menu alignment (locals)
            -   callable            Is callable type, same as ``'function'``
            -   color               Check color
            -   color_image         Color or :py:class:`pygame_menu.baseimage.BaseImage`
            -   color_image_none    Color, :py:class:`pygame_menu.baseimage.BaseImage`, or None
            -   color_none          Color or None
            -   image               Value must be ``BaseImage``
            -   none                None only
            -   position            pygame-menu position (locals)}
            -   type                Type-class (bool, str, etc...)
            -   tuple2              Only valid numeric tuples ``(x,y)`` or ``[x,y]``
            -   tuple3              Only valid numeric tuples ``(x,y,z)`` or ``[x,y,z]``

        :param params: Parameters dictionary
        :param key: Key to look for
        :param allowed_types: List of allowed types
        :param default: Default value to return
        :return: The value associated to the key
        """
        value = params.pop(key, default)
        if allowed_types is not None:
            other_types = []  # Contain other types to check from
            if not isinstance(allowed_types, (tuple, list)):
                allowed_types = (allowed_types,)
            for valtype in allowed_types:

                if valtype == 'alignment':
                    _utils.assert_alignment(value)

                elif valtype == callable or valtype == 'function' or valtype == 'callable':
                    assert _utils.is_callable(value), 'value must be callable type'

                elif valtype == 'color':
                    _utils.assert_color(value)

                elif valtype == 'color_image':
                    if isinstance(value, BaseImage):
                        return value
                    _utils.assert_color(value)

                elif valtype == 'color_image_none':
                    if value is None or isinstance(value, BaseImage):
                        return value
                    _utils.assert_color(value)

                elif valtype == 'color_none':
                    if value is None:
                        return value
                    _utils.assert_color(value)

                elif valtype == 'image':
                    assert isinstance(value, BaseImage), 'value must be BaseImage type'

                elif valtype == 'none':
                    assert value is None

                elif valtype == 'position':
                    _utils.assert_position(value)

                elif valtype == 'type':
                    assert isinstance(value, type), 'value is not type-class'

                elif valtype == 'tuple2':
                    _utils.assert_vector(value, 2)

                elif valtype == 'tuple3':
                    _utils.assert_vector(value, 3)

                else:  # Unknown type
                    assert isinstance(valtype, type), \
                        'allowed type "{0}" is not a type-class'.format(valtype)
                    other_types.append(valtype)

            # Check other types
            if len(other_types) > 0:
                others = tuple(other_types)
                msg = 'Theme.{} type shall be in {} types (got {})'.format(key, others, type(value))
                assert isinstance(value, others), msg

        return value
Exemplo n.º 13
0
 def test_callable(self) -> None:
     """
     Test is callable.
     """
     self.assertTrue(ut.is_callable(bool))
     self.assertFalse(ut.is_callable(1))
Exemplo n.º 14
0
    def __init__(
            self,
            title: Any,
            progressbar_id: str = '',
            default: NumberType = 0,
            width: int = 150,
            onselect: CallbackType = None,
            box_background_color: ColorInputType = (255, 255, 255),
            box_border_color: ColorInputType = (0, 0, 0),
            box_border_width: int = 1,
            box_margin: Tuple2IntType = (25, 0),
            box_progress_color: ColorInputType = (0, 255, 0),
            box_progress_padding: PaddingType = (1, 1),
            progress_text_align: str = ALIGN_CENTER,
            progress_text_enabled: bool = True,
            progress_text_font: Optional[FontType] = None,
            progress_text_font_color: ColorInputType = (0, 0, 0),
            progress_text_font_hfactor: float = 0.8,
            progress_text_format: ProgressBarTextFormatType = lambda x: str(round(x, 1)),
            progress_text_margin: Tuple2IntType = (0, 0),
            progress_text_placeholder: str = '{0} %',
            *args,
            **kwargs
    ) -> None:
        super(ProgressBar, self).__init__(
            args=args,
            kwargs=kwargs,
            onselect=onselect,
            title=title,
            widget_id=progressbar_id
        )

        # Check the value
        assert isinstance(default, NumberInstance)
        assert 0 <= default <= 100, 'default value must range from 0 to 100'

        # Check fonts
        if progress_text_font is not None:
            assert_font(progress_text_font)
        assert isinstance(progress_text_font_hfactor, NumberInstance)
        assert progress_text_font_hfactor > 0, \
            'progress text font height factor must be greater than zero'

        # Check colors
        box_background_color = assert_color(box_background_color)
        box_border_color = assert_color(box_border_color)
        box_progress_color = assert_color(box_progress_color)
        progress_text_font_color = assert_color(progress_text_font_color)

        # Check dimensions and sizes
        assert isinstance(box_border_width, int)
        assert box_border_width >= 0, \
            'box border width must be equal or greater than zero'
        assert_vector(box_margin, 2, int)
        assert_vector(progress_text_margin, 2, int)
        assert isinstance(width, int)
        assert width > 0, 'width must be greater than zero'
        box_progress_padding = parse_padding(box_progress_padding)
        self._box_progress_padding = box_progress_padding

        # Check progress text
        assert isinstance(progress_text_enabled, bool)
        assert is_callable(progress_text_format)
        assert isinstance(progress_text_format(0), str)
        assert isinstance(progress_text_placeholder, str)
        assert_alignment(progress_text_align)

        # Store properties
        self._default_value = default
        self._box_background_color = box_background_color
        self._box_border_color = box_border_color
        self._box_border_width = box_border_width
        self._box_margin = box_margin
        self._box_progress_color = box_progress_color
        self._progress = default
        self._progress_text_align = progress_text_align
        self._progress_text_enabled = progress_text_enabled
        self._progress_text_font = progress_text_font
        self._progress_text_font_color = progress_text_font_color
        self._progress_text_font_height = 0
        self._progress_text_font_height_factor = progress_text_font_hfactor
        self._progress_text_format = progress_text_format
        self._progress_text_margin = progress_text_margin
        self._progress_text_placeholder = progress_text_placeholder
        self._width = width