Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Menu links #313

Merged
merged 16 commits into from
Apr 1, 2021
38 changes: 38 additions & 0 deletions docs/_source/add_widgets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,44 @@ order to fit the menu size.
.. automethod:: pygame_menu._widgetmanager.WidgetManager.label


Add a menu link
---------------

Menu links are widgets that opens a new Menu within the parent Menu without using
a button. Links can be opened using the ``open`` method.

**Example:**

.. image:: ../_static/widget_menulink.png
:scale: 75%
:align: center

.. code-block:: python

menu = pygame_menu.Menu(...)
menu1 = pygame_menu.Menu(...)
menu2 = pygame_menu.Menu(...)
menu3 = pygame_menu.Menu(...)

def open_link(*args) -> None:
link: 'pygame_menu.widgets.MenuLink' = args[-1]
link.open()

# Create the links
link1 = menu.add.menu_link(menu1)
link2 = menu.add.menu_link(menu2)
link3 = menu.add.menu_link(menu3)

# Add a selection object, which opens the links
sel = menu.add.selector('Change menu ', [
('Menu 1', link1),
('Menu 2', link2),
('Menu 3', link3)
], onreturn=open_link)

.. automethod:: pygame_menu._widgetmanager.WidgetManager.menu_link


Add a none widget
-----------------

Expand Down
2 changes: 1 addition & 1 deletion docs/_source/widgets_menubar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ MenuBar
:members:
:show-inheritance:
:inherited-members:
:exclude-members: set_padding, scale, resize, set_max_height, set_max_width, set_selection_effect, set_border, _draw_background_color, _draw_border
:exclude-members: set_padding, scale, resize, set_max_height, set_max_width, set_selection_effect, set_border, _draw_background_color, _draw_border, flip, rotate
12 changes: 12 additions & 0 deletions docs/_source/widgets_menulink.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

.. module:: pygame_menu.widgets.widget.menulink

========
MenuLink
========

.. autoclass:: pygame_menu.widgets.MenuLink
:members:
:show-inheritance:
:inherited-members:
:exclude-members: _add_event, get_surface, get_sound, get_selection_effect, get_selected_time, get_padding, get_font_info, _render_string, _font_render_string, _blur, _focus, _disable_scale, get_value, set_onreturn, set_onmouseover, set_onmouseleave, set_onchange, set_default_value, reset_value, mouseover, mouseleave, is_selected, get_title, background_inflate_to_selection_effect, get_font_color_status, set_onselect, _apply_font, set_padding, set_title, get_rect, set_background_color, _draw_background_color, _draw_border, set_selection_effect, apply, change, _draw, _render, set_margin, _apply_transforms, set_font, update_font, set_position, flip, set_max_width, set_max_height, scale, resize, translate, rotate, set_alignment, select, set_shadow, set_sound, set_cursor, set_controls, set_value, update, add_update_callback, remove_update_callback, apply_update_callbacks, set_border, draw,
Binary file added docs/_static/widget_menulink.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 26 additions & 1 deletion docs/add_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
pygame.display.set_icon(icon)

# Set example, only this should change
EXAMPLE = 'CLOCK'
EXAMPLE = 'MENU_LINK'

# Create example
menu: 'pygame_menu.Menu'
Expand Down Expand Up @@ -255,6 +255,31 @@ def func(name):
menu.add.image(image_path, angle=10, scale=(0.15, 0.15))
menu.add.image(image_path, angle=-10, scale=(0.15, 0.15))

elif EXAMPLE == 'MENU_LINK':
menu = make_menu(pygame_menu.themes.THEME_DEFAULT, 'Menu Links')
menu1 = make_menu(pygame_menu.themes.THEME_ORANGE, 'Menu 1')
menu2 = make_menu(pygame_menu.themes.THEME_GREEN, 'Menu 2')
menu3 = make_menu(pygame_menu.themes.THEME_SOLARIZED, 'Menu 3')


def open_link(*args) -> None:
link: 'pygame_menu.widgets.MenuLink' = args[-1]
link.open()


# Create the links
link1 = menu.add.menu_link(menu1)
link2 = menu.add.menu_link(menu2)
link3 = menu.add.menu_link(menu3)

# Add a selection object, which opens the links
sel = menu.add.selector('Change menu ', [
('Menu 1', link1),
('Menu 2', link2),
('Menu 3', link3)
], onreturn=open_link)


elif EXAMPLE == 'LABEL':
menu = make_menu(pygame_menu.themes.THEME_BLUE, 'Label')

Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class. The currently existing classes are:
- :py:class:`~pygame_menu.widgets.Image`
- :py:class:`~pygame_menu.widgets.Label`
- :py:class:`~pygame_menu.widgets.MenuBar`
- :py:class:`~pygame_menu.widgets.MenuLink`
- :py:class:`~pygame_menu.widgets.NoneWidget`
- :py:class:`~pygame_menu.widgets.ScrollBar`
- :py:class:`~pygame_menu.widgets.Selector`
Expand Down Expand Up @@ -162,6 +163,7 @@ class to display large custom surfaces.
_source/widgets_image
_source/widgets_label
_source/widgets_menubar
_source/widgets_menulink
_source/widgets_none
_source/widgets_scrollbar
_source/widgets_selector
Expand Down
48 changes: 48 additions & 0 deletions pygame_menu/_widgetmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,54 @@ def none_widget(

return widget

def menu_link(
self,
menu: 'pygame_menu.Menu',
link_id: str = ''
) -> 'pygame_menu.widgets.MenuLink':
"""
Adds a link to another Menu. The behaviour is similar to a button, but
this widget is invisible, and cannot be selectable.

Added menus can be opened using the ``.open()`` method. Opened menus change
the state of the parent Menu (the current pointer).

.. note::

This is applied only to the base Menu (not the currently displayed,
stored in ``_current`` pointer); for such behaviour apply to
:py:meth:`pygame_menu.menu.Menu.get_current` object.

:param menu: Menu to be added as a link (the new submenu)
:param link_id: ID of the menu link widget
:return: Menu link widget
:rtype: :py:class:`pygame_menu.widgets.MenuLink`
"""
if isinstance(menu, type(self._menu)):
# Check for recursive
if menu == self._menu or menu.in_submenu(self._menu, recursive=True):
raise ValueError(
'Menu "{0}" is already on submenu structure, recursive menus'
'lead to unexpected behaviours. For returning to previous menu'
'use pygame_menu.events.BACK event defining an optional '
'back_count number of menus to return from, default is 1'
''.format(menu.get_title())
)

self._menu._submenus.append(menu)
else:
raise ValueError('menu object is not a pygame_menu.Menu class')

widget = pygame_menu.widgets.MenuLink(
menu=menu,
menu_opener_handler=self._menu._open,
link_id=link_id
)
self.configure_defaults_widget(widget)
self._append_widget(widget)

return widget

def generic_widget(
self,
widget: 'Widget',
Expand Down
13 changes: 8 additions & 5 deletions pygame_menu/baseimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
'IMAGE_EXAMPLE_GRAY_LINES',
'IMAGE_EXAMPLE_METAL',
'IMAGE_EXAMPLE_PYGAME_MENU',
'IMAGE_EXAMPLE_PYTHON',
'IMAGE_EXAMPLE_WALLPAPER',
'IMAGE_EXAMPLES',

Expand All @@ -65,7 +66,8 @@
from pygame_menu.locals import POSITION_NORTHWEST, POSITION_NORTHEAST, POSITION_CENTER, \
POSITION_WEST, POSITION_SOUTHWEST, POSITION_EAST, POSITION_SOUTHEAST, \
POSITION_SOUTH, POSITION_NORTH
from pygame_menu.utils import assert_vector, assert_position, assert_color
from pygame_menu.utils import assert_vector, assert_position, assert_color, \
load_pygame_image_file

from pygame_menu._types import Tuple2IntType, Union, Vector2NumberType, Callable, \
Tuple, List, NumberType, Optional, Dict, Tuple4IntType, Literal, Tuple2NumberType, \
Expand All @@ -78,10 +80,11 @@
IMAGE_EXAMPLE_GRAY_LINES = __images_path__.format('gray_lines.png')
IMAGE_EXAMPLE_METAL = __images_path__.format('metal.png')
IMAGE_EXAMPLE_PYGAME_MENU = __images_path__.format('pygame_menu.png')
IMAGE_EXAMPLE_PYTHON = __images_path__.format('python.svg')
IMAGE_EXAMPLE_WALLPAPER = __images_path__.format('wallpaper.jpg')

IMAGE_EXAMPLES = (IMAGE_EXAMPLE_CARBON_FIBER, IMAGE_EXAMPLE_GRAY_LINES,
IMAGE_EXAMPLE_METAL, IMAGE_EXAMPLE_PYGAME_MENU,
IMAGE_EXAMPLE_METAL, IMAGE_EXAMPLE_PYGAME_MENU, IMAGE_EXAMPLE_PYTHON,
IMAGE_EXAMPLE_WALLPAPER)

# Drawing modes
Expand All @@ -97,7 +100,8 @@

# Other constants
_VALID_IMAGE_FORMATS = ['.jpg', '.png', '.gif', '.bmp', '.pcx', '.tga', '.tif',
'.lbm', '.pbm', '.pgm', '.ppm', '.xpm', 'BytesIO', 'base64']
'.lbm', '.pbm', '.pgm', '.ppm', '.xpm', '.svg', 'BytesIO',
'base64']

# Custom types
ColorChannelType = Literal['r', 'g', 'b']
Expand Down Expand Up @@ -192,8 +196,7 @@ def __init__(

# Load the image and store as a surface
if load_from_file:
# pygame.image.get_extended()
self._surface = pygame.image.load(image_path)
self._surface = load_pygame_image_file(image_path)
self._original_surface = self._surface.copy()

# Other internals
Expand Down
5 changes: 5 additions & 0 deletions pygame_menu/examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
__all__ = ['create_example_window']

import pygame
import sys

from typing import Tuple

_PYGAME_ICON = [None]
Expand Down Expand Up @@ -71,6 +73,9 @@ def create_example_window(
os.environ['SDL_VIDEO_CENTERED'] = '1'

# Create pygame screen and objects
if sys.platform == 'darwin':
kwargs = {}

try:
surface = pygame.display.set_mode(window_size, **kwargs)
except TypeError:
Expand Down
113 changes: 113 additions & 0 deletions pygame_menu/resources/images/python.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading