Exemple #1
0
    def add_line(
            self,
            pos1: Tuple2NumberType,
            pos2: Tuple2NumberType,
            color: ColorInputType,
            width: int = 1,
            prev: bool = True,
            **kwargs
    ) -> str:
        """
        Adds a line.

        .. note::

            Consider ``(0, 0)`` coordinates as the center of the object.

        kwargs (Optional)
            - ``use_center_positioning``            Uses object center position as *(0, 0)*. ``True`` by default

        :param pos1: Position 1 (x1, y1)
        :param pos2: Position 2 (x2, y2)
        :param color: Line color
        :param width: Line width in px
        :param prev: If ``True`` draw previous the object, else draws post
        :param kwargs: Optional keyword arguments
        :return: ID of the decoration
        """
        assert_vector(pos1, 2)
        assert_vector(pos2, 2)
        color = assert_color(color)
        assert isinstance(width, int) and width >= 1
        length = math.sqrt(math.pow(pos1[0] - pos2[0], 2) + math.pow(pos1[1] - pos2[1], 2))
        assert length > 0, 'line cannot be zero-length'
        return self._add_decor(DECORATION_LINE, prev, ((tuple(pos1), tuple(pos2)), color, width, kwargs))
    def __init__(
            self,
            image_path: Union[str, 'BaseImage', 'Path', 'BytesIO'],
            angle: NumberType = 0,
            image_id: str = '',
            onselect: CallbackType = None,
            scale: Tuple2NumberType = (1, 1),
            scale_smooth: bool = True
    ) -> None:
        assert isinstance(image_path, (str, Path, BaseImage, BytesIO))
        assert isinstance(image_id, str)
        assert isinstance(angle, NumberInstance)
        assert isinstance(scale_smooth, bool)
        assert_vector(scale, 2)

        super(Image, self).__init__(
            onselect=onselect,
            widget_id=image_id
        )

        if isinstance(image_path, BaseImage):
            self._image = image_path
        else:
            self._image = BaseImage(image_path)
            self._image.rotate(angle)
            self._image.scale(scale[0], scale[1], smooth=scale_smooth)
Exemple #3
0
    def middle_rect_click(rect: Union['pygame_menu.widgets.Widget',
                                      'pygame.Rect', Tuple2NumberType],
                          menu: Optional['pygame_menu.Menu'] = None,
                          evtype: int = pygame.MOUSEBUTTONUP,
                          inlist: bool = True,
                          rel: Tuple2IntType = (0, 0),
                          button: int = 3,
                          delta: Tuple2IntType = (0, 0),
                          testmode: bool = True) -> EventListType:
        """
        Return event clicking the middle of a given rect.

        :param rect: Widget, Rect object, or Tuple
        :param menu: Menu object
        :param evtype: event type, it can be MOUSEBUTTONUP,  MOUSEBUTTONDOWN, MOUSEMOTION, FINGERUP, FINGERDOWN, FINGERMOTION
        :param inlist: If ``True`` return the event within a list
        :param rel: Rel position (relative movement)
        :param button: Which button presses, ``1`` to ``3`` are the main buttons; ``4`` and ``5`` is the wheel
        :param delta: Add tuple to rect position
        :param testmode: Event is in test mode
        :return: Event
        """
        assert isinstance(button, int) and button > 0
        assert_vector(rel, 2, int)
        assert_vector(delta, 2, int)
        if isinstance(rect, pygame_menu.widgets.Widget):
            x, y = rect.get_rect(to_real_position=True,
                                 apply_padding=False,
                                 render=True).center
            menu = rect.get_menu()
        elif isinstance(rect, pygame.Rect):
            x, y = rect.center
        elif isinstance(rect, tuple):
            x, y = rect
        elif isinstance(rect, list):
            x, y = rect[0], rect[1]
        else:
            raise ValueError('unknown rect type')
        if evtype == FINGERDOWN or evtype == FINGERUP or evtype == FINGERMOTION:
            assert menu is not None, \
                'menu cannot be none if FINGERDOWN, FINGERUP, or FINGERMOTION'
            display = menu.get_window_size()
            evt = pygame.event.Event(
                evtype, {
                    'button': button,
                    'rel': rel,
                    'test': testmode,
                    'x': (x + delta[0]) / display[0],
                    'y': (y + delta[1]) / display[1]
                })
            if inlist:
                evt = [evt]
            return evt
        return PygameEventUtils.mouse_click(x=x + delta[0],
                                            y=y + delta[1],
                                            inlist=inlist,
                                            evtype=evtype,
                                            rel=rel,
                                            button=button,
                                            testmode=testmode)
Exemple #4
0
    def get_at(
            self,
            pos: Tuple2NumberType,
            ignore_alpha: bool = False
    ) -> Union[Tuple3IntType, Tuple4IntType]:
        """
        Get the color from a certain position in image on x-axis and y-axis (x, y).

        ``get_at`` return a copy of the RGBA Color value at the given pixel. If the
        Surface has no per pixel alpha, then the alpha value will always be ``255``
        (opaque). If the pixel position is outside the area of the Surface an
        ``IndexError`` exception will be raised.

        Getting and setting pixels one at a time is generally too slow to be used
        in a game or realtime situation. It is better to use methods which operate
        on many pixels at a time like with the blit, fill and draw methods - or by
        using pygame.surfarraypygame module for accessing surface pixel data using
        array interfaces/pygame.PixelArraypygame object for direct pixel access of
        surfaces.

        :param pos: Position on x-axis and y-axis (x, y) in px
        :param ignore_alpha: If ``True`` returns only the three main channels
        :return: Color
        """
        assert_vector(pos, 2)
        color = self._surface.get_at(pos)
        if ignore_alpha:
            return color[0], color[1], color[2]
        return color
Exemple #5
0
    def mouse_click(x: NumberType,
                    y: NumberType,
                    inlist: bool = True,
                    evtype: int = pygame.MOUSEBUTTONUP,
                    rel: Tuple2IntType = (0, 0),
                    button: int = 3,
                    testmode: bool = True,
                    update_mouse: bool = False) -> EventListType:
        """
        Generate a mouse click event.

        :param x: X coordinate in px
        :param y: Y coordinate in px
        :param inlist: Return event in a list
        :param evtype: event type, it can be MOUSEBUTTONUP or MOUSEBUTTONDOWN
        :param rel: Rel position (relative movement)
        :param button: Which button presses, ``1`` to ``3`` are the main buttons; ``4`` and ``5`` is the wheel
        :param testmode: Event is in test mode
        :param update_mouse: If ``True`` updates the mouse position
        :return: Event
        """
        assert isinstance(button, int) and button > 0
        assert_vector(rel, 2, int)
        event_obj = pygame.event.Event(evtype, {
            'button': button,
            'pos': (x, y),
            'rel': rel,
            'test': testmode
        })
        if update_mouse:
            print('set mouse position', (x, y))
            pygame.mouse.set_pos((x, y))
        if inlist:
            event_obj = [event_obj]
        return event_obj
    def __init__(self,
                 margin_left: NumberType,
                 margin_right: NumberType,
                 margin_top: NumberType,
                 margin_bottom: NumberType,
                 arrow_size: Tuple2IntType = (10, 15),
                 arrow_vertical_offset: NumberType = 0,
                 blink_ms: NumberType = 0) -> None:
        super(ArrowSelection, self).__init__(margin_left=margin_left,
                                             margin_right=margin_right,
                                             margin_top=margin_top,
                                             margin_bottom=margin_bottom)

        assert_vector(arrow_size, 2, int)
        assert isinstance(arrow_vertical_offset, NumberInstance)
        assert isinstance(blink_ms, int)
        assert arrow_size[0] > 0 and arrow_size[
            1] > 0, 'arrow size must be greater than zero'
        assert blink_ms >= 0, 'blinking milliseconds must be greater than or equal to zero'

        self._arrow_vertical_offset = int(arrow_vertical_offset)
        self._arrow_size = (arrow_size[0], arrow_size[1])
        self._blink_ms = blink_ms
        self._blink_time = 0
        self._blink_status = True
        self._last_widget = None
Exemple #7
0
    def set_drawing_offset(self, offset: Vector2NumberType) -> 'BaseImage':
        """
        Set the image drawing offset.

        :param offset: Drawing offset tuple on x-axis and y-axis (x, y) in px
        :return: Self reference
        """
        assert_vector(offset, 2)
        self._drawing_offset = (int(offset[0]), int(offset[1]))
        return self
Exemple #8
0
    def set_at(self, pos: Tuple2NumberType, color: ColorInputType) -> 'BaseImage':
        """
        Set the color of pixel on x-axis and y-axis (x, y).

        :param pos: Position on x-axis and y-axis (x, y) in px
        :param color: Color
        :return: Self reference
        """
        assert_vector(pos, 2)
        self._surface.set_at(pos, assert_color(color))
        return self
Exemple #9
0
    def set_at(
        self, pos: Tuple2NumberType, color: Union['pygame.Color', str,
                                                  List[int],
                                                  ColorType]) -> 'BaseImage':
        """
        Set the color of the *(x, y)* pixel.

        :param pos: Position in *(x, y)*
        :param color: Color
        :return: Self reference
        """
        assert_vector(pos, 2)
        self._surface.set_at(pos, color)
        return self
Exemple #10
0
    def add_line(self, pos1: Tuple2NumberType, pos2: Tuple2NumberType, color: ColorType, width: int = 1,
                 prev: bool = True) -> str:
        """
        Adds a line.

        :param pos1: Position 1 *(x1, y1)*
        :param pos2: Position 2 *(x2, y2)*
        :param color: Line color
        :param width: Line width in px
        :param prev: If ``True`` draw previous the object, else draws post
        :return: ID of the decoration
        """
        assert_vector(pos1, 2)
        assert_vector(pos2, 2)
        assert_color(color)
        assert isinstance(width, int) and width >= 1
        return self._add_decor(DECORATION_LINE, prev, ((tuple(pos1), tuple(pos2)), color, width))
Exemple #11
0
    def touch_click(x: NumberType,
                    y: NumberType,
                    inlist: bool = True,
                    evtype: int = FINGERUP,
                    rel: Tuple2IntType = (0, 0),
                    normalize: bool = True,
                    menu: Union['pygame_menu.Menu', None] = None,
                    testmode: bool = True) -> EventListType:
        """
        Generate a mouse click event.

        :param x: X coordinate
        :param y: Y coordinate
        :param inlist: Return event in a list
        :param evtype: Event type, it can be FINGERUP, FINGERDOWN or FINGERMOTION
        :param rel: Rel position (relative movement)
        :param normalize: Normalize event position
        :param menu: Menu reference
        :param testmode: Event is in test mode
        :return: Event
        """
        assert isinstance(x, NumberInstance)
        assert isinstance(y, NumberInstance)
        assert_vector(rel, 2, int)
        if normalize:
            assert menu is not None, \
                'menu reference must be provided if normalize is used (related to touch events)'
            display_size = menu.get_window_size()
            x /= display_size[0]
            y /= display_size[1]
        event_obj = pygame.event.Event(evtype, {
            'x': x,
            'y': y,
            'rel': rel,
            'test': testmode
        })
        if inlist:
            event_obj = [event_obj]
        return event_obj
Exemple #12
0
    def draw(
            self,
            surface: 'pygame.Surface',
            area: Optional['pygame.Rect'] = None,
            position: Tuple2IntType = (0, 0)
    ) -> 'BaseImage':
        """
        Draw the image in a given surface.

        :param surface: Pygame surface object
        :param area: Area to draw; if ``None`` the image will be drawn on entire surface
        :param position: Position to draw on x-axis and y-axis (x, y) in px
        :return: Self reference
        """
        assert isinstance(surface, pygame.Surface)
        assert isinstance(area, (pygame.Rect, type(None)))
        assert_vector(position, 2, int)

        if area is None:
            area = surface.get_rect()

        # Compute offset based on drawing offset + drawing position
        px, py = self._get_position_delta()
        if self._drawing_mode != IMAGE_MODE_SIMPLE:
            px = 0
            py = 0

        offx = self._drawing_offset[0] - px
        offy = self._drawing_offset[1] - py

        if self._drawing_mode == IMAGE_MODE_FILL:
            # Check if exists the transformed surface
            if area.width == self._last_transform[0] and area.height == self._last_transform[1] and \
                    self._last_transform[2] is not None:
                surf = self._last_transform[2]
            else:  # Transform scale
                if self.smooth_scaling and self._surface.get_bitsize() > 8:
                    surf = pygame.transform.smoothscale(self._surface, (area.width, area.height))
                else:
                    surf = pygame.transform.scale(self._surface, (area.width, area.height))
                self._last_transform = (area.width, area.height, surf)

            surface.blit(
                surf,
                (
                    offx + position[0],
                    offy + position[1]
                ))

        elif self._drawing_mode == IMAGE_MODE_REPEAT_X:
            w = self._surface.get_width()
            times = int(math.ceil(float(area.width) / w))
            assert times > 0, \
                'invalid size, width must be greater than zero'
            for x in range(times):
                surface.blit(
                    self._surface,
                    (
                        x * w + offx + position[0],
                        offy + position[1]
                    ),
                    area
                )

        elif self._drawing_mode == IMAGE_MODE_REPEAT_Y:
            h = self._surface.get_height()
            times = int(math.ceil(float(area.height) / h))
            assert times > 0, \
                'invalid size, height must be greater than zero'
            for y in range(times):
                surface.blit(
                    self._surface,
                    (
                        0 + offx + position[0],
                        y * h + offy + position[1]
                    ),
                    area
                )

        elif self._drawing_mode == IMAGE_MODE_REPEAT_XY:
            w, h = self._surface.get_size()
            timesx = int(math.ceil(float(area.width) / w))
            timesy = int(math.ceil(float(area.height) / h))
            assert timesx > 0 and timesy > 0, \
                'invalid size, width and height must be greater than zero'
            for x in range(timesx):
                for y in range(timesy):
                    surface.blit(
                        self._surface,
                        (
                            x * w + offx + position[0],
                            y * h + offy + position[1]
                        ),
                        area
                    )

        elif self._drawing_mode == IMAGE_MODE_CENTER:
            sw, hw = area.width, area.height  # Window
            w, h = self._surface.get_size()  # Image
            surface.blit(
                self._surface,
                (
                    int(float(sw - w) / 2 + offx + position[0]),
                    int(float(hw - h) / 2 + offy + position[1])
                ),
                area
            )

        elif self._drawing_mode == IMAGE_MODE_SIMPLE:
            surface.blit(
                self._surface,
                (
                    offx + position[0],
                    offy + position[1]
                ),
                area
            )

        return self
    def __init__(self,
                 title: Any,
                 items: Union[List[Tuple[Any, ...]], List[str]],
                 dropselect_id: str = '',
                 default: Optional[Union[int, List[int]]] = None,
                 max_selected: int = 0,
                 onchange: CallbackType = None,
                 onreturn: CallbackType = None,
                 onselect: CallbackType = None,
                 open_middle: bool = False,
                 placeholder: str = 'Select an option',
                 placeholder_add_to_selection_box: bool = True,
                 placeholder_selected: str = '{0} selected',
                 selection_box_arrow_color: ColorInputType = (150, 150, 150),
                 selection_box_arrow_margin: Tuple3IntType = (5, 5, 0),
                 selection_box_bgcolor: ColorInputType = (255, 255, 255),
                 selection_box_border_color: ColorInputType = (150, 150, 150),
                 selection_box_border_width: int = 1,
                 selection_box_height: int = 3,
                 selection_box_inflate: Tuple2IntType = (0, 0),
                 selection_box_margin: Tuple2NumberType = (25, 0),
                 selection_box_text_margin: int = 5,
                 selection_box_width: int = 0,
                 selection_infinite: bool = False,
                 selection_option_active_bgcolor: ColorInputType = (188, 227,
                                                                    244),
                 selection_option_active_font_color: ColorInputType = (0, 0,
                                                                       0),
                 selection_option_border_color: ColorInputType = (220, 220,
                                                                  220),
                 selection_option_border_width: int = 1,
                 selection_option_cursor: CursorInputType = None,
                 selection_option_font: Optional[FontType] = None,
                 selection_option_font_color: ColorInputType = (0, 0, 0),
                 selection_option_font_size: Optional[int] = None,
                 selection_option_padding: PaddingType = 5,
                 selection_option_selected_bgcolor: ColorInputType = (142, 247,
                                                                      141),
                 selection_option_selected_box: bool = True,
                 selection_option_selected_box_border: int = 1,
                 selection_option_selected_box_color: ColorInputType = (150,
                                                                        150,
                                                                        150),
                 selection_option_selected_box_height: float = 0.5,
                 selection_option_selected_box_margin: Tuple3IntType = (0, 5,
                                                                        0),
                 selection_option_selected_font_color: ColorInputType = (0, 0,
                                                                         0),
                 *args,
                 **kwargs) -> None:
        super(DropSelectMultiple, self).__init__(
            dropselect_id=dropselect_id,
            items=items,
            onchange=onchange,
            onreturn=onreturn,
            onselect=onselect,
            open_middle=open_middle,
            placeholder=placeholder,
            placeholder_add_to_selection_box=placeholder_add_to_selection_box,
            selection_box_arrow_color=selection_box_arrow_color,
            selection_box_arrow_margin=selection_box_arrow_margin,
            selection_box_bgcolor=selection_box_bgcolor,
            selection_box_border_color=selection_box_border_color,
            selection_box_border_width=selection_box_border_width,
            selection_box_height=selection_box_height,
            selection_box_inflate=selection_box_inflate,
            selection_box_margin=selection_box_margin,
            selection_box_text_margin=selection_box_text_margin,
            selection_box_width=selection_box_width,
            selection_infinite=selection_infinite,
            selection_option_border_color=selection_option_border_color,
            selection_option_border_width=selection_option_border_width,
            selection_option_cursor=selection_option_cursor,
            selection_option_font=selection_option_font,
            selection_option_font_color=selection_option_font_color,
            selection_option_font_size=selection_option_font_size,
            selection_option_padding=selection_option_padding,
            selection_option_selected_bgcolor=selection_option_selected_bgcolor,
            selection_option_selected_font_color=
            selection_option_selected_font_color,
            title=title,
            **kwargs)

        # Asserts
        assert isinstance(placeholder_selected, str)
        assert isinstance(selection_option_selected_box, bool)
        assert isinstance(selection_option_selected_box_border, int) and \
               selection_option_selected_box_border > 0
        assert_vector(selection_option_selected_box_margin, 3, int)
        assert isinstance(selection_option_selected_box_height, (int, float))
        assert 0 < selection_option_selected_box_height <= 1, 'height factor must be between 0 and 1'
        assert isinstance(max_selected, int) and max_selected >= 0

        # Configure parent
        self._args = args or []
        self._close_on_apply = False
        self._max_selected = max_selected
        self._selection_option_left_space = True
        self._selection_option_left_space_height_factor = selection_option_selected_box_height
        self._selection_option_left_space_margin = selection_option_selected_box_margin

        # Set style
        self._placeholder_selected = placeholder_selected
        self._selection_option_active_bgcolor = assert_color(
            selection_option_active_bgcolor)
        self._selection_option_active_font_color = assert_color(
            selection_option_active_font_color)
        self._selection_option_selected_box = selection_option_selected_box
        self._selection_option_selected_box_color = assert_color(
            selection_option_selected_box_color)
        self._selection_option_selected_box_width = selection_option_selected_box_border

        self.set_default_value(default)
Exemple #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
Exemple #15
0
    def pack(
        self,
        widget: Union['Widget', List['Widget'], Tuple['Widget', ...]],
        alignment: str = _locals.ALIGN_LEFT,
        vertical_position: str = _locals.POSITION_NORTH,
        margin: Vector2NumberType = (0, 0)
    ) -> Union['Widget', List['Widget'], Tuple['Widget', ...], Any]:
        """
        Packs widget in the frame line. To pack a widget it has to be already
        appended to Menu, and the Menu must be the same as the frame.

        Packing is added to the same line, for example if three LEFT widgets are added:

            .. code-block:: python

                <frame horizontal>
                frame.pack(W1, alignment=ALIGN_LEFT, vertical_position=POSITION_NORTH)
                frame.pack(W2, alignment=ALIGN_LEFT, vertical_position=POSITION_CENTER)
                frame.pack(W3, alignment=ALIGN_LEFT, vertical_position=POSITION_SOUTH)

                ----------------
                |W1            |
                |   W2         |
                |      W3      |
                ----------------

        Another example:

            .. code-block:: python

                <frame horizontal>
                frame.pack(W1, alignment=ALIGN_LEFT)
                frame.pack(W2, alignment=ALIGN_CENTER)
                frame.pack(W3, alignment=ALIGN_RIGHT)

                ----------------
                |W1    W2    W3|
                ----------------

            .. code-block:: python

                <frame vertical>
                frame.pack(W1, alignment=ALIGN_LEFT)
                frame.pack(W2, alignment=ALIGN_CENTER)
                frame.pack(W3, alignment=ALIGN_RIGHT)

                --------
                |W1    |
                |  W2  |
                |    W3|
                --------

        .. note::

            Frame does not consider previous widget margin. For such purpose, use
            ``margin`` pack parameter.

        .. note::

            It is recommended to force menu rendering after packing all widgets.

        .. note::

            Packing applies a virtual translation to the widget, previous translation
            is not modified.

        .. note::

            Widget floating is also considered within frames. If a widget is floating,
            it does not add any size to the respective positioning.

        :param widget: Widget to be packed
        :param alignment: Widget alignment
        :param vertical_position: Vertical position of the widget within frame. See :py:mod:`pygame_menu.locals`
        :param margin: (left, top) margin of added widget in px. It overrides the previous widget margin
        :return: Added widget references
        """
        assert self._menu is not None, \
            'frame menu must be set before packing widgets'
        if isinstance(widget, (tuple, list)):
            for w in widget:
                self.pack(widget=w,
                          alignment=alignment,
                          vertical_position=vertical_position)
            return widget
        assert isinstance(widget, Widget)
        if isinstance(widget, Frame):
            assert widget.get_menu() is not None, \
                '{0} menu cannot be None'.format(widget.get_class_id())
        assert widget.get_id() not in self._widgets.keys(), \
            '{0} already exists in {1}'.format(widget.get_class_id(), self.get_class_id())
        assert widget.get_menu() == self._menu or widget.get_menu() is None, \
            'widget menu to be added to frame must be in same menu as frame, or it can have any Menu instance'
        assert widget.get_frame() is None, \
            '{0} is already packed in {1}'.format(widget.get_class_id(), widget.get_frame().get_class_id())
        assert_alignment(alignment)
        assert vertical_position in (_locals.POSITION_NORTH, _locals.POSITION_CENTER, _locals.POSITION_SOUTH), \
            'vertical position must be NORTH, CENTER, or SOUTH'
        assert_vector(margin, 2)
        assert widget.configured, 'widget must be configured before packing'

        if widget.get_margin() != (0, 0) and self._pack_margin_warning:
            msg = '{0} margin should be (0, 0) if packed, but received {1}; {2}.pack() does not consider ' \
                  'previous widget margin. Set frame._pack_margin_warning=False to hide this warning' \
                  ''.format(widget.get_class_id(), widget.get_margin(), self.get_class_id())
            warnings.warn(msg)

        if isinstance(widget, Frame):
            widget.update_indices()

        widget.set_frame(self)
        widget.set_margin(*margin)
        if self._frame_scrollarea is not None:
            widget.set_scrollarea(self._frame_scrollarea)
            self._sort_menu_scrollable_frames()
        else:
            widget.set_scrollarea(self._scrollarea)
        self._widgets[widget.get_id()] = widget
        self._widgets_props[widget.get_id()] = (alignment, vertical_position)

        # Sort widgets to keep selection order
        menu_widgets = self._menu._widgets
        if widget.get_menu() is not None and widget in menu_widgets:
            self._menu._validate_frame_widgetmove = False
            widgets_list = list(self._widgets.values())

            # Move frame to last
            if len(self._widgets) > 1:
                wlast = widgets_list[-2]  # -1 is the last added
                for i in range(2, len(self._widgets)):
                    if wlast.get_menu() is None and len(self._widgets) > 2:
                        wlast = widgets_list[-(i + 1)]
                    else:
                        break

                # Check for last if wlast is frame
                while True:
                    if not (isinstance(wlast, Frame) and wlast.get_indices() !=
                            (-1, -1)) or wlast.get_menu() is None:
                        break
                    wlast = menu_widgets[wlast.last_index]

                if wlast.get_menu() == self._menu:
                    self._menu.move_widget_index(self, wlast, render=False)

            # Swap
            self._menu.move_widget_index(widget, self, render=False)
            if isinstance(widget, Frame):
                reverse = menu_widgets.index(widget) == len(menu_widgets) - 1
                widgs = widget.get_widgets(unpack_subframes_include_frame=True,
                                           reverse=reverse)
                for w in widgs:
                    if w.get_menu() is None:
                        continue
                    self._menu.move_widget_index(w, self, render=False)
                if len(widgs) >= 1:
                    swap_target = widgs[-1]
                    if not reverse:
                        swap_target = widgs[0]
                    menu_widgets.remove(widget)
                    menu_widgets.insert(menu_widgets.index(swap_target),
                                        widget)

            # Move widget to first
            menu_widgets.remove(self)
            for k in range(len(widgets_list)):
                if widgets_list[k].get_menu() == self._menu:
                    menu_widgets.insert(menu_widgets.index(widgets_list[k]),
                                        self)
                    break
            self._menu._validate_frame_widgetmove = True

            # Update control widget
            if self._control_widget is None:
                self._control_widget = widget
                self._control_widget_last_pos = self._control_widget.get_position(
                )

        if isinstance(widget, Frame):
            self._has_frames = True

        # Update menu selected widget
        self._menu.move_widget_index(None, update_selected_index=True)

        # Render is mandatory as it modifies row/column layout
        try:
            self.update_position()
            self._menu._render()
        except _FrameSizeException:
            self.unpack(widget)
            raise

        # Request scroll if widget is selected
        if widget.is_selected():
            widget.scroll_to_widget()
            widget.scroll_to_widget()

        return widget
Exemple #16
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
Exemple #17
0
    def __init__(self,
                 title: Any,
                 toggleswitch_id: str = '',
                 default_state: int = 0,
                 infinite: bool = False,
                 onchange: CallbackType = None,
                 onselect: CallbackType = None,
                 slider_color: ColorInputType = (255, 255, 255),
                 slider_height_factor: NumberType = 1,
                 slider_thickness: int = 25,
                 slider_vmargin: NumberType = 0,
                 state_color: Tuple[ColorInputType,
                                    ...] = ((178, 178, 178), (117, 185, 54)),
                 state_text: Tuple[str, ...] = ('Off', 'On'),
                 state_text_font: Optional[FontType] = None,
                 state_text_font_color: Tuple[ColorInputType,
                                              ...] = ((255, 255, 255),
                                                      (255, 255, 255)),
                 state_text_font_size: Optional[int] = None,
                 state_text_position: Tuple2NumberType = (0.5, 0.5),
                 state_values: Tuple[Any, ...] = (False, True),
                 state_width: Union[Tuple[int, ...], int] = 150,
                 switch_border_color: ColorInputType = (40, 40, 40),
                 switch_border_width: int = 1,
                 switch_height: NumberType = 1.25,
                 switch_margin: Tuple2NumberType = (25, 0),
                 *args,
                 **kwargs) -> None:
        super(ToggleSwitch, self).__init__(args=args,
                                           kwargs=kwargs,
                                           onchange=onchange,
                                           onselect=onselect,
                                           title=title,
                                           widget_id=toggleswitch_id)

        # Asserts
        assert isinstance(default_state, int)
        assert isinstance(state_values, tuple)
        assert isinstance(infinite, bool)

        self._total_states = len(state_values)
        assert 2 <= self._total_states, 'the minimum number of states is 2'
        assert 0 <= default_state < self._total_states, 'invalid default state value'

        if state_text_font is not None:
            assert_font(state_text_font)
        assert isinstance(state_text_font_size, (int, type(None)))
        if state_text_font_size is not None:
            assert state_text_font_size > 0, 'state text font size must be equal or greater than zero'

        assert_vector(state_text_position, 2)
        switch_border_color = assert_color(switch_border_color)
        assert isinstance(switch_border_width, int) and switch_border_width >= 0, \
            'border width must be equal or greater than zero'
        slider_color = assert_color(slider_color)

        assert slider_height_factor > 0, 'slider height factor cannot be negative'
        assert slider_thickness >= 0, 'slider thickness cannot be negative'
        assert isinstance(slider_vmargin, NumberInstance)
        assert_vector(switch_margin, 2)
        assert isinstance(switch_height, NumberInstance) and switch_height > 0, \
            'switch height factor cannot be zero or negative'
        assert isinstance(state_color,
                          tuple) and len(state_color) == self._total_states

        new_state_color = []
        for c in state_color:
            new_state_color.append(assert_color(c))
        state_color = tuple(new_state_color)

        assert isinstance(state_text,
                          tuple) and len(state_text) == self._total_states
        for c in state_text:
            assert isinstance(c, str), 'all states text must be string-type'
        assert isinstance(
            state_text_font_color,
            tuple) and len(state_text_font_color) == self._total_states

        new_state_text_font_color = []
        for c in state_text_font_color:
            new_state_text_font_color.append(assert_color(c))
        state_text_font_color = tuple(new_state_text_font_color)

        self._switch_width = 0
        if isinstance(state_width, NumberInstance):
            state_width = [state_width]
        assert_vector(state_width, self._total_states - 1, int)

        for i in range(len(state_width)):
            assert isinstance(state_width[i],
                              int), 'each state width must be an integer'
            assert state_width[
                i] > 0, 'each state width must be greater than zero'
            self._switch_width += state_width[i]

        # Store properties
        self._switch_border_color = switch_border_color
        self._switch_border_width = switch_border_width
        self._infinite = infinite
        self._slider_color = slider_color
        self._slider_height_factor = slider_height_factor
        self._slider_thickness = slider_thickness
        self._slider_vmargin = slider_vmargin
        self._state = default_state
        self._state_color = state_color
        self._state_text = state_text
        self._state_text_font = state_text_font
        self._state_text_font_color = state_text_font_color
        self._state_text_font_size = state_text_font_size
        self._state_text_position = state_text_position
        self._state_values = state_values
        self._state_width = state_width
        self._switch_height_factor = float(switch_height)
        self._switch_margin = switch_margin

        # Compute state width accum
        self._state_width_accum = [0]
        accum = 0
        for w in self._state_width:
            accum += w
            self._state_width_accum.append(accum - self._slider_thickness -
                                           2 * self._switch_border_width)

        # Inner properties
        self._slider_height = 0
        self._slider_pos = (0, 0)  # to add to (rect.x, rect.y)
        self._state_font = None
        self._switch_font_rendered = []  # Stores font render for each state
        self._switch_height = 0
        self._switch_pos = (0, 0)  # horizontal pos, and delta to title
Exemple #18
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
Exemple #19
0
    def update_cell_style(
        self,
        column: Union[int, Vector2IntType],
        row: Union[int, Vector2IntType],
        align: Optional[str] = None,
        background_color: Optional[ColorInputType] = None,
        border_color: Optional[ColorInputType] = None,
        border_position: Optional[WidgetBorderPositionType] = None,
        border_width: Optional[int] = None,
        font: Optional[FontType] = None,
        font_color: Optional[ColorInputType] = None,
        font_size: Optional[int] = None,
        padding: Optional[PaddingType] = None,
        vertical_position: Optional[str] = None
    ) -> Union['Widget', List['Widget']]:
        """
        Update cell style. If a parameter is ``None`` the default cell property
        will be used.

        :param column: Cell column position (counting from 1). If -1 update all column from the given row. Also, a 2-item list/tuple is accepted (from, to), ``to=-1`` is also accepted (last)
        :param row: Cell row position (counting from 1). If ``-1`` update all rows from the given column. Also, a 2-item list/tuple is accepted (from, to), ``to=-1`` is also accepted (last)
        :param align: Horizontal align of each cell. See :py:mod:`pygame_menu.locals`
        :param background_color: Background color
        :param border_color: Border color of each cell
        :param border_position: Border position of each cell. Valid only: north, south, east, and west. See :py:mod:`pygame_menu.locals`
        :param border_width: Border width in px of each cell
        :param font: Font name or path
        :param font_color: Font color
        :param font_size: Font size
        :param padding: Cell padding according to CSS rules. General shape: (top, right, bottom, left)
        :param vertical_position: Vertical position of each cell. Only valid: north, center, and south. See :py:mod:`pygame_menu.locals`
        :return: Cell widget
        """
        if row == -1 or isinstance(row, VectorInstance):
            max_rows = len(self._rows)
            if row == -1:
                row = []
                for i in range(max_rows):
                    row.append(i + 1)
            else:
                assert_vector(row, 2, int)
                row_k = list(row)
                if row_k[1] == -1:
                    row_k[1] = len(self._rows)
                assert 1 <= row_k[0] <= row_k[1] <= max_rows, \
                    f'(from, to) of rows vector must be increasing and between 1-{max_rows}'
                row = [row_k[0]]
                for i in range(row_k[1] - row_k[0]):
                    row.append(row_k[0] + (i + 1))
            if isinstance(column, VectorInstance) and column != [1, -1]:
                assert self.is_rectangular(), \
                    f'only rectangular tables (same number of columns for each row) ' \
                    f'accept a variable column different than -1 or [1, -1], but ' \
                    f'received "{column}"'
            updated_wid = []
            for i in row:
                w = self.update_cell_style(column=column,
                                           row=i,
                                           align=align,
                                           background_color=background_color,
                                           border_color=border_color,
                                           border_position=border_position,
                                           border_width=border_width,
                                           font=font,
                                           font_color=font_color,
                                           font_size=font_size,
                                           padding=padding,
                                           vertical_position=vertical_position)
                if not isinstance(w, list):
                    w = [w]
                for k in w:
                    updated_wid.append(k)
            return updated_wid
        if column == -1 or isinstance(column, VectorInstance):
            assert isinstance(row, int) and 1 <= row <= len(self._rows), \
                f'row index ({row}) cannot exceed the number of rows ({len(self._rows)})'
            max_columns = self._rows[row - 1].get_total_packed()
            if column == -1:
                column = []
                for i in range(max_columns):
                    column.append(i + 1)
            else:
                assert_vector(column, 2, int)
                column_k = list(column)
                if column_k[1] == -1:
                    column_k[1] = max_columns
                assert 1 <= column_k[0] <= column_k[1] <= max_columns, \
                    f'(from, to) of column vector must be increasing and between 1-{max_columns} for row {row}'
                column = [column_k[0]]
                for i in range(column_k[1] - column_k[0]):
                    column.append(column_k[0] + (i + 1))
            updated_wid = []
            for i in column:
                w = self.update_cell_style(column=i,
                                           row=row,
                                           align=align,
                                           background_color=background_color,
                                           border_color=border_color,
                                           border_position=border_position,
                                           border_width=border_width,
                                           font=font,
                                           font_color=font_color,
                                           font_size=font_size,
                                           padding=padding,
                                           vertical_position=vertical_position)
                if not isinstance(w, list):
                    w = [w]
                for k in w:
                    updated_wid.append(k)
            return updated_wid
        cell = self.get_cell(column, row)
        r = self._rows[row - 1]

        if align is None:
            align = cell.get_attribute('align')
        if background_color is None:
            background_color = cell.get_attribute('background_color')
        if border_color is None:
            border_color = cell.get_attribute('border_color')
        if border_position is None:
            border_position = cell.get_attribute('border_position')
        if border_width is None:
            border_width = cell.get_attribute('border_width')
        if padding is None:
            padding = cell.get_attribute('padding')
        if vertical_position is None:
            vertical_position = cell.get_attribute('vertical_position')

        self._check_cell_style(align=align,
                               background_color=background_color,
                               border_color=border_color,
                               border_position=border_position,
                               border_width=border_width,
                               padding=padding,
                               vertical_position=vertical_position)
        if background_color is not None:
            background_color = assert_color(background_color)
        if border_color is not None:
            border_color = assert_color(border_color)
        padding = parse_padding(padding)

        # Update background color
        if background_color != r._background_color:
            cell.set_background_color(background_color)
        else:
            cell.set_background_color(None)

        # Update font
        if font_color is None:
            font_color = cell._font_color
        assert_color(font_color)
        if font is None:
            font = cell._font_name
        assert_font(font)
        if font_size is None:
            font_size = cell._font_size

        try:
            cell.update_font({'color': font_color, 'name': font})
        except AssertionError:
            pass

        try:
            if isinstance(font_size, int) and font_size > 0:
                cell.update_font({'size': font_size})
        except AssertionError:
            pass

        if isinstance(border_position, str):
            border_position = [border_position]

        # Update cell
        cell.set_attribute('align', align)
        cell.set_attribute('background_color', background_color)
        cell.set_attribute('border_color', border_color)
        cell.set_attribute('border_position', border_position)
        cell.set_attribute('border_width', border_width)
        cell.set_attribute('padding', padding)
        cell.set_attribute('vertical_position', vertical_position)

        self._update_row_sizing()
        self._render()
        self.force_menu_surface_update()
        return cell
    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'] = 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
Exemple #21
0
    def __init__(self,
                 title: Any,
                 items: Union[List[Tuple[Any, ...]], List[str]],
                 selector_id: str = '',
                 default: int = 0,
                 onchange: CallbackType = None,
                 onreturn: CallbackType = None,
                 onselect: CallbackType = None,
                 style: SelectorStyleType = SELECTOR_STYLE_CLASSIC,
                 style_fancy_arrow_color: ColorInputType = (160, 160, 160),
                 style_fancy_arrow_margin: Tuple3IntType = (5, 5, 0),
                 style_fancy_bgcolor: ColorInputType = (180, 180, 180),
                 style_fancy_bordercolor: ColorInputType = (0, 0, 0),
                 style_fancy_borderwidth: int = 1,
                 style_fancy_box_inflate: Tuple2IntType = (0, 0),
                 style_fancy_box_margin: Tuple2NumberType = (25, 0),
                 *args,
                 **kwargs) -> None:
        assert isinstance(items, list)
        assert isinstance(selector_id, str)
        assert isinstance(default, int)
        assert style in (SELECTOR_STYLE_CLASSIC, SELECTOR_STYLE_FANCY), \
            'invalid selector style'

        # Check items list
        check_selector_items(items)
        assert default >= 0, \
            'default position must be equal or greater than zero'
        assert default < len(items), \
            'default position should be lower than number of values'
        assert isinstance(selector_id, str), 'id must be a string'
        assert isinstance(default, int), 'default must be an integer'

        # Check fancy style
        style_fancy_arrow_color = assert_color(style_fancy_arrow_color)
        assert_vector(style_fancy_arrow_margin, 3, int)
        assert_vector(style_fancy_box_margin, 2)
        style_fancy_bgcolor = assert_color(style_fancy_bgcolor)
        style_fancy_bordercolor = assert_color(style_fancy_bordercolor)
        assert isinstance(style_fancy_borderwidth,
                          int) and style_fancy_borderwidth >= 0
        assert_vector(style_fancy_box_inflate, 2, int)
        assert style_fancy_box_inflate[0] >= 0 and style_fancy_box_inflate[1] >= 0, \
            'box inflate must be equal or greater than zero on both axis'

        super(Selector, self).__init__(onchange=onchange,
                                       onreturn=onreturn,
                                       onselect=onselect,
                                       title=title,
                                       widget_id=selector_id,
                                       args=args,
                                       kwargs=kwargs)

        self._index = 0
        self._items = items.copy()
        self._sformat = ''
        self._style = style
        self._title_size = 0

        # Store fancy style
        self._style_fancy_arrow_color = style_fancy_arrow_color
        self._style_fancy_arrow_margin = style_fancy_arrow_margin
        self._style_fancy_bgcolor = style_fancy_bgcolor
        self._style_fancy_bordercolor = style_fancy_bordercolor
        self._style_fancy_borderwidth = style_fancy_borderwidth
        self._style_fancy_box_inflate = style_fancy_box_inflate
        self._style_fancy_box_margin = (int(style_fancy_box_margin[0]),
                                        int(style_fancy_box_margin[1]))

        # Apply default item
        default %= len(self._items)
        for k in range(0, default):
            self._right()

        # Last configs
        self.set_sformat('{0}< {1} >')
        self.set_default_value(default)
Exemple #22
0
    def pack(
        self,
        widget: Union['Widget', List['Widget'], Tuple['Widget', ...]],
        alignment: str = _locals.ALIGN_LEFT,
        vertical_position: PackPositionTypes = _locals.POSITION_NORTH,
        margin: Vector2NumberType = (0, 0)
    ) -> Union['Widget', List['Widget'], Tuple['Widget', ...]]:
        """
        Packs widget in the frame line. To pack a widget it has to be already
        appended to Menu, and the Menu must be the same as the frame.

        Packing is added to the same line, for example if three LEFT widgets are added:

            .. code-block:: python

                <frame horizontal>
                frame.pack(W1, alignment=ALIGN_LEFT, vertical_position=POSITION_NORTH)
                frame.pack(W2, alignment=ALIGN_LEFT, vertical_position=POSITION_CENTER)
                frame.pack(W3, alignment=ALIGN_LEFT, vertical_position=POSITION_SOUTH)

                ----------------
                |W1            |
                |   W2         |
                |      W3      |
                ----------------

        Another example:

            .. code-block:: python

                <frame horizontal>
                frame.pack(W1, alignment=ALIGN_LEFT)
                frame.pack(W2, alignment=ALIGN_CENTER)
                frame.pack(W3, alignment=ALIGN_RIGHT)

                ----------------
                |W1    W2    W3|
                ----------------

            .. code-block:: python

                <frame vertical>
                frame.pack(W1, alignment=ALIGN_LEFT)
                frame.pack(W2, alignment=ALIGN_CENTER)
                frame.pack(W3, alignment=ALIGN_RIGHT)

                --------
                |W1    |
                |  W2  |
                |    W3|
                --------

        .. note::

            It is recommended to force menu rendering after packing all widgets.

        :param widget: Widget to be packed
        :param alignment: Widget alignment
        :param vertical_position: Vertical position of the widget
        :param margin: *(left, top)* margin of added widget in px. It overrides the previous widget margin
        :return: Added widget reference
        """
        menu = self.get_menu()
        assert menu is not None, \
            'menu must be set before packing widgets'
        if isinstance(widget, (list, tuple)):
            for w in widget:
                self.pack(widget=w,
                          alignment=alignment,
                          vertical_position=vertical_position)
            return widget
        assert isinstance(widget, Widget)
        assert widget.get_id() not in self._widgets.keys(), \
            'widget already in frame'
        assert widget.get_menu() == menu, \
            'widget menu to be added to frame must be in same menu as frame'
        assert widget.get_frame() is None, \
            'widget already is in another frame'
        assert_alignment(alignment)
        assert vertical_position in (_locals.POSITION_NORTH, _locals.POSITION_CENTER, _locals.POSITION_SOUTH), \
            'vertical position must be NORTH, CENTER, or SOUTH'
        assert widget._translate[0] == 0 and widget._translate[1] == 0, \
            'widget cannot have a previous translation if appended. Frame overrides translation'
        assert_vector(margin, 2)

        widget.set_frame(self)
        widget.set_float()
        widget.set_margin(*margin)
        self._widgets[widget.get_id()] = (widget, alignment, vertical_position)

        # Notify menu and sort widgets to keep selection order
        # noinspection PyProtectedMember
        menu_widgets = menu._widgets

        frame_index = menu_widgets.index(self)
        widgt_index = menu_widgets.index(widget)
        assert widgt_index > frame_index, 'widget cannot be appended before frame'
        menu_widgets.pop(widgt_index)
        menu_widgets.insert(frame_index, widget)
        if widget.is_selected():
            widget.select(False)
            menu.select_widget(widget)

        if self._control_widget is None:
            self._control_widget = widget
            self._control_widget_last_pos = self._control_widget.get_position()

        # Render is mandatory as it modifies row/column layout
        try:
            menu.render()
        except _FrameSizeException:
            self.unpack(widget)
            raise
        self.update_indices()

        return widget