Source code for pygame_menu.menu

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

MENU
Menu class.
"""
# File constants no. 0

from __future__ import annotations

__all__ = ["Menu"]

import math
import os
import sys
import time
from typing import TYPE_CHECKING, Any

import pygame
import pygame.gfxdraw as gfxdraw

import pygame_menu.events as _events
from pygame_menu._base import Base
from pygame_menu._decorator import Decorator
from pygame_menu._scrollarea import ScrollArea, get_scrollbars_from_position

# Import types
from pygame_menu._types import (
    CallableNoArgsType,
    EventListType,
    EventType,
    EventVectorType,
    MenuColumnMaxWidthType,
    MenuColumnMinWidthType,
    MenuRowsType,
    NumberInstance,
    NumberType,
    Tuple2BoolType,
    Tuple2IntType,
    Tuple4Tuple2IntType,
    Vector2BoolType,
    Vector2IntType,
    Vector2NumberType,
    VectorInstance,
    VectorType,
)
from pygame_menu._widgetmanager import WidgetManager
from pygame_menu.controls import Controller
from pygame_menu.locals import (
    ALIGN_CENTER,
    ALIGN_LEFT,
    ALIGN_RIGHT,
    FINGERDOWN,
    FINGERMOTION,
    FINGERUP,
    ORIENTATION_HORIZONTAL,
    ORIENTATION_VERTICAL,
)
from pygame_menu.sound import Sound
from pygame_menu.themes import THEME_DEFAULT, Theme
from pygame_menu.utils import (
    assert_vector,
    check_key_pressed_valid,
    get_finger_pos,
    make_surface,
    mouse_motion_current_mouse_position,
    print_menu_widget_structure,
    warn,
)
from pygame_menu.widgets import Frame, MenuBar, Widget
from pygame_menu.widgets.core.widget import WIDGET_MOUSEOVER, check_widget_mouseleave

if TYPE_CHECKING:
    from collections.abc import Callable

# Joy events
JOY_EVENT_LEFT = 1
JOY_EVENT_RIGHT = 2
JOY_EVENT_UP = 4
JOY_EVENT_DOWN = 8

# Select types
SELECT_KEY = "key"
SELECT_MOUSE_BUTTON_DOWN = "mouse_button_down"
SELECT_MOUSE_MOTION = "mouse_motion"
SELECT_MOVE = "move"
SELECT_OPEN = "open"
SELECT_RECURSIVE = "recursive"
SELECT_REMOVE = "remove"
SELECT_RESET = "reset"
SELECT_TOUCH = "touch"
SELECT_WIDGET = "widget"






class _MenuStats:
    """
    Menu stats.
    """

    def __init__(self) -> None:
        # Widget update
        self.added_widgets = 0
        self.removed_widgets = 0

        # Widget position
        self.build_surface = 0
        self.position_update = 0
        self.center_content = 0

        # Render
        self.last_build_surface_time = 0
        self.render_private = 0
        self.render_public = 0
        self.total_building_time = 0
        self.total_rendering_time = 0

        # Other
        self.clear = 0
        self.draw = 0
        self.draw_update_cached = 0
        self.loop = 0
        self.reset = 0
        self.select = 0
        self.update = 0


class _MenuCopyException(Exception):
    """
    If user tries to copy a Menu.
    """

    pass


class _MenuRuntimeErrorConfig:
    """
    Controls the runtime errors of the Menu.
    """

    def __init__(self) -> None:
        self.close = True
        self.draw = True
        self.mainloop = True
        self.update = (
            True  # It should be True, as non-active Menus SHOULD NOT receive updates
        )

    @staticmethod
    def throw(throw_runtime: bool, msg: str) -> None:
        """
        Throws an error, if ``throw_runtime=True`` throws a ``RuntimeError``, otherwise
        only a warning.

        :param throw_runtime: If error is raised
        :param msg: Message
        """
        if throw_runtime:
            raise RuntimeError(msg)
        warn(msg)


class _MenuSizingException(Exception):
    """
    Exception thrown if widget exceeds maximum size of column/row layout.
    """

    pass


class _MenuWidgetOverflow(Exception):
    """
    Exception thrown if adding more widgets than menu can contain on row/column layout.
    """

    pass


class _MenuMultipleSelectedWidgetsException(Exception):
    """
    Exception thrown if multiple widgets are selected at the same time.
    """

    pass