Skip to content

Menu

src.view.menu

Menu rendering layer.

The menu view draws the main menu, hero selection interface, and settings screen. It delegates event interpretation and selection state updates to MenuHandler.

The documentation follows Google-style docstrings so tools such as pdoc, Sphinx Napoleon, or MkDocs-based pipelines can expose parameters, return values, and side effects in a consistent HTML API reference.

Menu

Pygame rendering layer for the start, selection, and settings menus.

Attributes:

Name Type Description
settings Settings

Shared application settings.

screen Screen

Display wrapper used for rendering.

Notes

This class is documented as part of the public project API and is intended to be readable in generated HTML documentation.

Source code in src\view\menu.py
class Menu:
    """Pygame rendering layer for the start, selection, and settings menus.

    Attributes:
        settings (Settings): Shared application settings.
        screen (Screen): Display wrapper used for rendering.

    Notes:
        This class is documented as part of the public project API and is intended to be readable in generated HTML documentation."""

    def __init__(self):
        """Load menu settings and initialize the menu state.

        Side Effects:
            Initializes instance attributes and keeps references to shared runtime objects."""
        self.settings = Settings()
        pass

    def start(self, menu_handler):
        """Create menu assets and return the selected units after the setup loop.

        Args:
            menu_handler: MenuHandler used to process menu events and selections.

        Returns:
            object: The value produced by the menu or game loop, when one is returned by the underlying flow.

        Side Effects:
            Runs menu or game loops and may initialize runtime state."""
        pygame.init()
        is_running = True
        pressed = False
        icon = pygame.image.load('assets/ui/icon.png')
        banner = pygame.image.load('assets/ui/banner.png')
        pygame.display.set_icon(icon)
        pygame.display.set_caption('Strategy Game')
        screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        banner = pygame.transform.scale(banner, screen.get_size())
        self.menu(pressed, screen, banner, menu_handler)
        pygame.quit()

    def menu(self, pressed, screen, banner, menu_handler):
        """Draw the main menu and delegate menu input handling.

        Args:
            pressed: Current keyboard state returned by Pygame.
            screen: Pygame surface or screen wrapper used as the drawing target.
            banner: Menu banner surface or rectangle used by the menu screen.
            menu_handler: MenuHandler used to process menu events and selections.

        Returns:
            None: This method is executed for its side effects.

        Side Effects:
            Handles menu events, screen transitions, and display refresh."""
        is_running = True
        clock = pygame.time.Clock()
        try:
            play_button, play_button_rect = self.settings.create_ui_element('play_button', (250, 100), math.ceil(screen.get_width() / 2.5), math.ceil(screen.get_height() / 3))
            settings_button, settings_button_rect = self.settings.create_ui_element('settings_button', (250, 100), math.ceil(screen.get_width() / 2.5), play_button_rect.y + 10)
            settings_button_rect.y += settings_button_rect.height
            exit_button, exit_button_rect = self.settings.create_ui_element('exit_button', (250, 100), math.ceil(screen.get_width() / 2.5), settings_button_rect.y + settings_button_rect.height + 10)
        except pygame.error as e:
            print(f'Error loading button image: {e}')
            return
        while is_running:
            screen.blit(banner, (0, 0))
            if not pressed:
                screen.blit(play_button, play_button_rect)
                screen.blit(settings_button, settings_button_rect)
                screen.blit(exit_button, exit_button_rect)
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if play_button_rect.collidepoint(event.pos):
                        self.choose_player(screen, banner, menu_handler)
                    elif settings_button_rect.collidepoint(event.pos):
                        print('Settings button pressed.')
                    elif exit_button_rect.collidepoint(event.pos):
                        is_running = False
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_END:
                        is_running = False
            pygame.display.flip()
            clock.tick(60)

    def choose_player(self, screen, banner, menu_handler):
        """Draw the player and hero selection screen.

        Args:
            screen: Pygame surface or screen wrapper used as the drawing target.
            banner: Menu banner surface or rectangle used by the menu screen.
            menu_handler: MenuHandler used to process menu events and selections.

        Returns:
            None: This method is executed for its side effects.

        Side Effects:
            Processes player naming, hero selection, and confirmation events."""
        is_running = True
        active = False
        font = pygame.font.Font(None, 36)
        text = ''
        try:
            input_button = pygame.image.load(f'{Settings().path}/assets/ui/input.png')
            input_button = pygame.transform.scale(input_button, (400, 150))
            input_rect = input_button.get_rect(center=(screen.get_width() // 2, screen.get_height() // 4))
            placeholder, placeholder_rect = self.settings.create_ui_element('placeholder', (400, 45), input_rect.x, input_rect.y - 10)
            erza_avatar, erza_rect = self.settings.create_ui_element('erza_avatar', (200, 300), 80, input_rect.y + input_rect.height + 10)
            gray_avatar, gray_rect = self.settings.create_ui_element('gray_avatar', (200, 300), 320, input_rect.y + input_rect.height + 10)
            natsu_avatar, natsu_rect = self.settings.create_ui_element('natsu_avatar', (200, 300), 560, input_rect.y + input_rect.height + 10)
            gowther_avatar, gowther_rect = self.settings.create_ui_element('gowther_avatar', (200, 300), 800, input_rect.y + input_rect.height + 10)
            heisuke_avatar, heisuke_rect = self.settings.create_ui_element('heisuke_avatar', (200, 300), 1040, input_rect.y + input_rect.height + 10)
            kansuke_avatar, kansuke_rect = self.settings.create_ui_element('kansuke_avatar', (200, 300), 1280, input_rect.y + input_rect.height + 10)
            ok_button = pygame.image.load(f'{Settings().path}/assets/ui/ok_button.png')
            ok_button = pygame.transform.scale(ok_button, (200, 75))
            ok_rect = ok_button.get_rect(center=(screen.get_width() / 2, 3 * screen.get_height() / 4))
        except pygame.error as e:
            print(f'Error loading button image: {e}')
            return
        clock = pygame.time.Clock()
        while is_running:
            screen.blit(banner, (0, 0))
            screen.blit(input_button, input_rect)
            screen.blit(placeholder, placeholder_rect)
            overlay_color = (0, 255, 0, 128) if active else (255, 0, 0, 128)
            overlay_surface = pygame.Surface((input_rect.width - 40, input_rect.height - 80), pygame.SRCALPHA)
            overlay_surface.fill(overlay_color)
            overlay_x = input_rect.x + 20
            overlay_y = input_rect.y + 40
            screen.blit(overlay_surface, (overlay_x, overlay_y))
            screen.blit(erza_avatar, erza_rect)
            screen.blit(gray_avatar, gray_rect)
            screen.blit(natsu_avatar, natsu_rect)
            screen.blit(gowther_avatar, gowther_rect)
            screen.blit(heisuke_avatar, heisuke_rect)
            screen.blit(kansuke_avatar, kansuke_rect)
            screen.blit(ok_button, ok_rect)
            text_surface = font.render(text, True, (255, 255, 255))
            screen.blit(text_surface, (overlay_x, overlay_y))
            for x, y in zip(menu_handler.x, menu_handler.y):
                screen.blit(pygame.image.load(f'{Settings().path}/assets/ui/selected.png'), (x, y))
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_END:
                        is_running = False
                if event.type == pygame.MOUSEBUTTONDOWN:
                    active = input_rect.collidepoint(event.pos)
                menu_handler.select_units(event, erza_rect, gray_rect, natsu_rect, gowther_rect, kansuke_rect, heisuke_rect)
                text, active = menu_handler.get_player_name(event, input_rect, text, active)
                new_text = menu_handler.submit(event, ok_rect)
                if new_text is not None:
                    if new_text != 'end':
                        text = new_text
                    else:
                        is_running = False
            pygame.display.flip()
            clock.tick(60)

    def display_settings(self):
        """Draw the display settings screen.

        Returns:
            None: This method is executed for its side effects.

        Side Effects:
            Applies settings-screen events and may update display resolution."""
        pass

start(menu_handler)

Create menu assets and return the selected units after the setup loop.

Parameters:

Name Type Description Default
menu_handler

MenuHandler used to process menu events and selections.

required

Returns:

Name Type Description
object

The value produced by the menu or game loop, when one is returned by the underlying flow.

Side Effects

Runs menu or game loops and may initialize runtime state.

Source code in src\view\menu.py
def start(self, menu_handler):
    """Create menu assets and return the selected units after the setup loop.

    Args:
        menu_handler: MenuHandler used to process menu events and selections.

    Returns:
        object: The value produced by the menu or game loop, when one is returned by the underlying flow.

    Side Effects:
        Runs menu or game loops and may initialize runtime state."""
    pygame.init()
    is_running = True
    pressed = False
    icon = pygame.image.load('assets/ui/icon.png')
    banner = pygame.image.load('assets/ui/banner.png')
    pygame.display.set_icon(icon)
    pygame.display.set_caption('Strategy Game')
    screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
    banner = pygame.transform.scale(banner, screen.get_size())
    self.menu(pressed, screen, banner, menu_handler)
    pygame.quit()

menu(pressed, screen, banner, menu_handler)

Draw the main menu and delegate menu input handling.

Parameters:

Name Type Description Default
pressed

Current keyboard state returned by Pygame.

required
screen

Pygame surface or screen wrapper used as the drawing target.

required
banner

Menu banner surface or rectangle used by the menu screen.

required
menu_handler

MenuHandler used to process menu events and selections.

required

Returns:

Name Type Description
None

This method is executed for its side effects.

Side Effects

Handles menu events, screen transitions, and display refresh.

Source code in src\view\menu.py
def menu(self, pressed, screen, banner, menu_handler):
    """Draw the main menu and delegate menu input handling.

    Args:
        pressed: Current keyboard state returned by Pygame.
        screen: Pygame surface or screen wrapper used as the drawing target.
        banner: Menu banner surface or rectangle used by the menu screen.
        menu_handler: MenuHandler used to process menu events and selections.

    Returns:
        None: This method is executed for its side effects.

    Side Effects:
        Handles menu events, screen transitions, and display refresh."""
    is_running = True
    clock = pygame.time.Clock()
    try:
        play_button, play_button_rect = self.settings.create_ui_element('play_button', (250, 100), math.ceil(screen.get_width() / 2.5), math.ceil(screen.get_height() / 3))
        settings_button, settings_button_rect = self.settings.create_ui_element('settings_button', (250, 100), math.ceil(screen.get_width() / 2.5), play_button_rect.y + 10)
        settings_button_rect.y += settings_button_rect.height
        exit_button, exit_button_rect = self.settings.create_ui_element('exit_button', (250, 100), math.ceil(screen.get_width() / 2.5), settings_button_rect.y + settings_button_rect.height + 10)
    except pygame.error as e:
        print(f'Error loading button image: {e}')
        return
    while is_running:
        screen.blit(banner, (0, 0))
        if not pressed:
            screen.blit(play_button, play_button_rect)
            screen.blit(settings_button, settings_button_rect)
            screen.blit(exit_button, exit_button_rect)
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN:
                if play_button_rect.collidepoint(event.pos):
                    self.choose_player(screen, banner, menu_handler)
                elif settings_button_rect.collidepoint(event.pos):
                    print('Settings button pressed.')
                elif exit_button_rect.collidepoint(event.pos):
                    is_running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_END:
                    is_running = False
        pygame.display.flip()
        clock.tick(60)

choose_player(screen, banner, menu_handler)

Draw the player and hero selection screen.

Parameters:

Name Type Description Default
screen

Pygame surface or screen wrapper used as the drawing target.

required
banner

Menu banner surface or rectangle used by the menu screen.

required
menu_handler

MenuHandler used to process menu events and selections.

required

Returns:

Name Type Description
None

This method is executed for its side effects.

Side Effects

Processes player naming, hero selection, and confirmation events.

Source code in src\view\menu.py
def choose_player(self, screen, banner, menu_handler):
    """Draw the player and hero selection screen.

    Args:
        screen: Pygame surface or screen wrapper used as the drawing target.
        banner: Menu banner surface or rectangle used by the menu screen.
        menu_handler: MenuHandler used to process menu events and selections.

    Returns:
        None: This method is executed for its side effects.

    Side Effects:
        Processes player naming, hero selection, and confirmation events."""
    is_running = True
    active = False
    font = pygame.font.Font(None, 36)
    text = ''
    try:
        input_button = pygame.image.load(f'{Settings().path}/assets/ui/input.png')
        input_button = pygame.transform.scale(input_button, (400, 150))
        input_rect = input_button.get_rect(center=(screen.get_width() // 2, screen.get_height() // 4))
        placeholder, placeholder_rect = self.settings.create_ui_element('placeholder', (400, 45), input_rect.x, input_rect.y - 10)
        erza_avatar, erza_rect = self.settings.create_ui_element('erza_avatar', (200, 300), 80, input_rect.y + input_rect.height + 10)
        gray_avatar, gray_rect = self.settings.create_ui_element('gray_avatar', (200, 300), 320, input_rect.y + input_rect.height + 10)
        natsu_avatar, natsu_rect = self.settings.create_ui_element('natsu_avatar', (200, 300), 560, input_rect.y + input_rect.height + 10)
        gowther_avatar, gowther_rect = self.settings.create_ui_element('gowther_avatar', (200, 300), 800, input_rect.y + input_rect.height + 10)
        heisuke_avatar, heisuke_rect = self.settings.create_ui_element('heisuke_avatar', (200, 300), 1040, input_rect.y + input_rect.height + 10)
        kansuke_avatar, kansuke_rect = self.settings.create_ui_element('kansuke_avatar', (200, 300), 1280, input_rect.y + input_rect.height + 10)
        ok_button = pygame.image.load(f'{Settings().path}/assets/ui/ok_button.png')
        ok_button = pygame.transform.scale(ok_button, (200, 75))
        ok_rect = ok_button.get_rect(center=(screen.get_width() / 2, 3 * screen.get_height() / 4))
    except pygame.error as e:
        print(f'Error loading button image: {e}')
        return
    clock = pygame.time.Clock()
    while is_running:
        screen.blit(banner, (0, 0))
        screen.blit(input_button, input_rect)
        screen.blit(placeholder, placeholder_rect)
        overlay_color = (0, 255, 0, 128) if active else (255, 0, 0, 128)
        overlay_surface = pygame.Surface((input_rect.width - 40, input_rect.height - 80), pygame.SRCALPHA)
        overlay_surface.fill(overlay_color)
        overlay_x = input_rect.x + 20
        overlay_y = input_rect.y + 40
        screen.blit(overlay_surface, (overlay_x, overlay_y))
        screen.blit(erza_avatar, erza_rect)
        screen.blit(gray_avatar, gray_rect)
        screen.blit(natsu_avatar, natsu_rect)
        screen.blit(gowther_avatar, gowther_rect)
        screen.blit(heisuke_avatar, heisuke_rect)
        screen.blit(kansuke_avatar, kansuke_rect)
        screen.blit(ok_button, ok_rect)
        text_surface = font.render(text, True, (255, 255, 255))
        screen.blit(text_surface, (overlay_x, overlay_y))
        for x, y in zip(menu_handler.x, menu_handler.y):
            screen.blit(pygame.image.load(f'{Settings().path}/assets/ui/selected.png'), (x, y))
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_END:
                    is_running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                active = input_rect.collidepoint(event.pos)
            menu_handler.select_units(event, erza_rect, gray_rect, natsu_rect, gowther_rect, kansuke_rect, heisuke_rect)
            text, active = menu_handler.get_player_name(event, input_rect, text, active)
            new_text = menu_handler.submit(event, ok_rect)
            if new_text is not None:
                if new_text != 'end':
                    text = new_text
                else:
                    is_running = False
        pygame.display.flip()
        clock.tick(60)

display_settings()

Draw the display settings screen.

Returns:

Name Type Description
None

This method is executed for its side effects.

Side Effects

Applies settings-screen events and may update display resolution.

Source code in src\view\menu.py
def display_settings(self):
    """Draw the display settings screen.

    Returns:
        None: This method is executed for its side effects.

    Side Effects:
        Applies settings-screen events and may update display resolution."""
    pass