Source code for pygame_menu.menu

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

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

__all__ = ['Menu']

import math
import os
import sys
import time

import pygame
import pygame.gfxdraw as gfxdraw
import pygame_menu.controls as ctrl
import pygame_menu.events as _events

from pygame_menu._base import Base
from pygame_menu._decorator import Decorator
from pygame_menu._widgetmanager import WidgetManager
from pygame_menu.locals import ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT, \
    ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL, FINGERDOWN, FINGERUP, FINGERMOTION
from pygame_menu._scrollarea import ScrollArea, get_scrollbars_from_position
from pygame_menu.sound import Sound
from pygame_menu.themes import Theme, THEME_DEFAULT
from pygame_menu.utils import assert_vector, make_surface, warn, \
    check_key_pressed_valid, mouse_motion_current_mouse_position, get_finger_pos, \
    print_menu_widget_structure
from pygame_menu.widgets import Frame, Widget, MenuBar
from pygame_menu.widgets.core.widget import check_widget_mouseleave, WIDGET_MOUSEOVER

# Import types
from pygame_menu._types import Callable, Any, Dict, NumberType, VectorType, \
    Vector2NumberType, Union, Tuple, List, Vector2IntType, Vector2BoolType, \
    Tuple4Tuple2IntType, Tuple2IntType, MenuColumnMaxWidthType, MenuColumnMinWidthType, \
    MenuRowsType, Optional, Tuple2BoolType, NumberInstance, VectorInstance, EventType, \
    EventVectorType, EventListType, CallableNoArgsType

# 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(object):
    """
    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(object):
    """
    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