From 02b698ebdce2382a4b0105d42e0b3d8509457be5 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 22:03:34 -0300 Subject: [PATCH 01/16] OSX test fix --- test/_utils.py | 10 +++++++--- test/test_baseimage.py | 9 +++++++-- test/test_examples.py | 5 ++++- test/test_frame.py | 20 +++++++++++++++++--- test/test_menu.py | 19 +++++++++++++++---- test/test_scrollarea.py | 10 +++++++--- test/test_selection.py | 3 ++- test/test_sound.py | 8 +++++++- test/test_widgets.py | 18 +++++++++++++++++- 9 files changed, 83 insertions(+), 19 deletions(-) diff --git a/test/_utils.py b/test/_utils.py index 45aeacc2..c64b2c81 100644 --- a/test/_utils.py +++ b/test/_utils.py @@ -33,6 +33,7 @@ # Globals 'PYGAME_V2', + 'SYS_PLATFORM_OSX', 'TEST_THEME', 'THEME_NON_FIXED_TITLE', 'WIDGET_MOUSEOVER', @@ -51,6 +52,7 @@ ] import random +import sys import pygame import pygame_menu @@ -61,9 +63,9 @@ from pygame_menu.widgets.core.widget import check_widget_mouseleave # noinspection PyProtectedMember -from pygame_menu._types import NumberType, Union, List, Tuple, Optional, Tuple2IntType, EventType, \ - MenuColumnMaxWidthType, MenuColumnMinWidthType, Any, MenuRowsType, Tuple2NumberType, VectorIntType, \ - VectorInstance +from pygame_menu._types import NumberType, Union, List, Tuple, Optional, EventType, \ + Tuple2IntType, MenuColumnMaxWidthType, MenuColumnMinWidthType, Any, MenuRowsType, \ + Tuple2NumberType, VectorIntType, VectorInstance EventListType = Union[EventType, List[EventType]] @@ -86,6 +88,8 @@ WIDGET_MOUSEOVER = pygame_menu.widgets.core.widget.WIDGET_MOUSEOVER WIDGET_TOP_CURSOR = pygame_menu.widgets.core.widget.WIDGET_TOP_CURSOR +SYS_PLATFORM_OSX = sys.platform == 'darwin' + def reset_widgets_over() -> None: """ diff --git a/test/test_baseimage.py b/test/test_baseimage.py index 2f6c4c75..d7c9c831 100644 --- a/test/test_baseimage.py +++ b/test/test_baseimage.py @@ -32,7 +32,7 @@ __all__ = ['BaseImageTest'] from pathlib import Path -from test._utils import surface, PYGAME_V2 +from test._utils import surface, PYGAME_V2, SYS_PLATFORM_OSX import base64 import copy import io @@ -61,6 +61,8 @@ def test_from_bytesio(self) -> None: """ Test image load from base64. """ + if SYS_PLATFORM_OSX: + return photo = 'R0lGODlhRgBGAPZUAAAAAAAAMwAAzAArAAArMwArzAAr/wBVmQBVzABV/zMAADMAMzMrADMrMzMrmTMrzDMr/zNVADNVMzNVZjNVmTN' \ 'VzDNV/zOAADOAMzOAZjOA/zOqM2YAM2YrAGYrM2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmW' \ 'aqzJkrAJkrM5lVAJlVM5lVZplVmZmAAJmAM5mAZpmAmZmAzJmqZpmqmZmqzJmq/5nVmZnVzMxVAMxVM8xVZsyAAMyAM8yAZsyqZsyqm' \ @@ -255,6 +257,8 @@ def test_operations(self) -> None: """ Test the file operations. """ + if SYS_PLATFORM_OSX: + return image_original = pygame_menu.BaseImage(pygame_menu.baseimage.IMAGE_EXAMPLE_GRAY_LINES) image = pygame_menu.BaseImage(pygame_menu.baseimage.IMAGE_EXAMPLE_GRAY_LINES) self.assertTrue(image.equals(image_original)) @@ -336,7 +340,8 @@ def test_transform(self) -> None: # noinspection PyTypeChecker image.pick_channels(('r', 'g', 'b')) - self.assertEqual(image.get_at((10, 10)), (56, 56, 56, 255)) + if not SYS_PLATFORM_OSX: + self.assertEqual(image.get_at((10, 10)), (56, 56, 56, 255)) image.set_at((10, 10), (0, 0, 0)) # self.assertEqual(image.get_at((10, 10)), (0, 0, 0, 255)) diff --git a/test/test_examples.py b/test/test_examples.py index ade92eba..a8f14829 100644 --- a/test/test_examples.py +++ b/test/test_examples.py @@ -31,7 +31,8 @@ __all__ = ['ExamplesTest'] -from test._utils import test_reset_surface, MenuUtils, PygameEventUtils +from test._utils import test_reset_surface, MenuUtils, PygameEventUtils, \ + SYS_PLATFORM_OSX import unittest import pygame @@ -195,6 +196,8 @@ def test_example_other_ui_solar_system(self) -> None: """ Test solar system. """ + if SYS_PLATFORM_OSX: + return app = ui_solarsystem.main(test=True) self.assertFalse(app.menu._disable_draw) app.process_events(PygameEventUtils.keydown([pygame.K_p]), app.menu) diff --git a/test/test_frame.py b/test/test_frame.py index 595372ff..ec13be3a 100644 --- a/test/test_frame.py +++ b/test/test_frame.py @@ -32,14 +32,16 @@ __all__ = ['FrameWidgetTest'] -from test._utils import MenuUtils, surface, PygameEventUtils, test_reset_surface, TEST_THEME, PYGAME_V2, \ - WIDGET_MOUSEOVER, reset_widgets_over, THEME_NON_FIXED_TITLE +from test._utils import MenuUtils, surface, PygameEventUtils, test_reset_surface, \ + TEST_THEME, PYGAME_V2, WIDGET_MOUSEOVER, reset_widgets_over, THEME_NON_FIXED_TITLE, \ + SYS_PLATFORM_OSX import unittest import pygame import pygame_menu -from pygame_menu.controls import KEY_MOVE_UP, KEY_LEFT, KEY_RIGHT, JOY_RIGHT, JOY_LEFT, KEY_MOVE_DOWN +from pygame_menu.controls import KEY_MOVE_UP, KEY_LEFT, KEY_RIGHT, JOY_RIGHT, \ + JOY_LEFT, KEY_MOVE_DOWN from pygame_menu.locals import ORIENTATION_VERTICAL, ORIENTATION_HORIZONTAL from pygame_menu.utils import set_pygame_cursor from pygame_menu.widgets import Button @@ -57,6 +59,8 @@ def test_general(self) -> None: """ Test frame widget containers. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(theme=TEST_THEME.copy()) menu.add.button('rr') @@ -553,6 +557,8 @@ def test_scrollarea(self) -> None: """ Test scrollarea frame. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(theme=THEME_NON_FIXED_TITLE) self.assertRaises(AssertionError, lambda: menu.add.frame_v(300, 400, max_width=400)) self.assertRaises(AssertionError, lambda: menu.add.frame_v(300, 400, max_height=500)) @@ -1231,6 +1237,9 @@ def test_menu_support(self) -> None: """ Test frame menu support. """ + if SYS_PLATFORM_OSX: + return + # Test frame movement theme = TEST_THEME.copy() theme.widget_margin = (0, 0) @@ -1710,6 +1719,9 @@ def test_title(self) -> None: """ Test frame title. """ + if SYS_PLATFORM_OSX: + return + menu = MenuUtils.generic_menu(theme=THEME_NON_FIXED_TITLE) pad = 5 @@ -1868,6 +1880,8 @@ def test_resize(self) -> None: """ Test resize. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu() # No title, no scrollable diff --git a/test/test_menu.py b/test/test_menu.py index 28d06e5f..b9b9984b 100644 --- a/test/test_menu.py +++ b/test/test_menu.py @@ -31,8 +31,9 @@ __all__ = ['MenuTest'] -from test._utils import surface, test_reset_surface, MenuUtils, PygameEventUtils, TEST_THEME, PYGAME_V2, \ - WIDGET_MOUSEOVER, WIDGET_TOP_CURSOR, reset_widgets_over, THEME_NON_FIXED_TITLE +from test._utils import surface, test_reset_surface, MenuUtils, PygameEventUtils,\ + TEST_THEME, PYGAME_V2, WIDGET_MOUSEOVER, WIDGET_TOP_CURSOR, reset_widgets_over,\ + THEME_NON_FIXED_TITLE, SYS_PLATFORM_OSX from typing import Any, Tuple import copy import math @@ -43,8 +44,8 @@ import pygame_menu from pygame_menu import events -from pygame_menu.controls import KEY_MOVE_DOWN, KEY_MOVE_UP, KEY_LEFT, KEY_RIGHT, JOY_DOWN, JOY_UP, \ - JOY_LEFT, JOY_RIGHT +from pygame_menu.controls import KEY_MOVE_DOWN, KEY_MOVE_UP, KEY_LEFT, KEY_RIGHT, \ + JOY_DOWN, JOY_UP, JOY_LEFT, JOY_RIGHT from pygame_menu.locals import FINGERDOWN, FINGERMOTION from pygame_menu.utils import set_pygame_cursor from pygame_menu.widgets import Label, Button @@ -137,6 +138,8 @@ def test_position(self) -> None: """ Test position. """ + if SYS_PLATFORM_OSX: + return # Test centering theme_src = TEST_THEME.copy() @@ -293,6 +296,8 @@ def test_translate(self) -> None: """ Test menu translation. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(width=400, theme=THEME_NON_FIXED_TITLE) btn = menu.add.button('button') self.assertEqual(menu.get_menubar().get_height(), 55) @@ -679,6 +684,8 @@ def test_centering(self) -> None: """ Test centering menu. """ + if SYS_PLATFORM_OSX: + return # Vertical offset disables centering theme = pygame_menu.themes.THEME_BLUE.copy() theme.widget_offset = (0, 100) @@ -1314,6 +1321,8 @@ def test_focus(self) -> None: """ Test menu focus effect. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(title='menu', mouse_motion_selection=True) btn = menu.add.button('nice') @@ -1625,6 +1634,8 @@ def test_widget_move_index(self) -> None: """ Test widget index moving. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(theme=TEST_THEME.copy()) btn1 = menu.add.button('1') btn2 = menu.add.button('2') diff --git a/test/test_scrollarea.py b/test/test_scrollarea.py index cea30662..6b853a66 100644 --- a/test/test_scrollarea.py +++ b/test/test_scrollarea.py @@ -33,13 +33,15 @@ import copy import unittest -from test._utils import MenuUtils, PygameEventUtils, surface, TEST_THEME, PYGAME_V2 +from test._utils import MenuUtils, PygameEventUtils, surface, TEST_THEME, PYGAME_V2, \ + SYS_PLATFORM_OSX import pygame_menu from pygame_menu.locals import POSITION_SOUTHEAST, POSITION_CENTER, POSITION_NORTHWEST, \ - POSITION_SOUTH, POSITION_NORTHEAST, POSITION_SOUTHWEST, POSITION_EAST, POSITION_WEST, POSITION_NORTH, \ - SCROLLAREA_POSITION_FULL, SCROLLAREA_POSITION_BOTH_VERTICAL, SCROLLAREA_POSITION_BOTH_HORIZONTAL, \ + POSITION_SOUTH, POSITION_NORTHEAST, POSITION_SOUTHWEST, POSITION_EAST, \ + POSITION_WEST, POSITION_NORTH, SCROLLAREA_POSITION_FULL, \ + SCROLLAREA_POSITION_BOTH_VERTICAL, SCROLLAREA_POSITION_BOTH_HORIZONTAL, \ INPUT_TEXT, ORIENTATION_VERTICAL, ORIENTATION_HORIZONTAL # noinspection PyProtectedMember from pygame_menu._scrollarea import get_scrollbars_from_position @@ -152,6 +154,8 @@ def test_size(self) -> None: """ Test size. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(title='menu', theme=TEST_THEME.copy()) menu.render() self.assertEqual(menu.get_height(widget=True), 0) diff --git a/test/test_selection.py b/test/test_selection.py index b92f7f8a..4337e7c9 100644 --- a/test/test_selection.py +++ b/test/test_selection.py @@ -36,7 +36,8 @@ import unittest from pygame_menu.widgets import Button -from pygame_menu.widgets.selection import LeftArrowSelection, RightArrowSelection, HighlightSelection, NoneSelection +from pygame_menu.widgets.selection import LeftArrowSelection, RightArrowSelection, \ + HighlightSelection, NoneSelection class SelectionTest(unittest.TestCase): diff --git a/test/test_sound.py b/test/test_sound.py index fdb6a530..5dd4f217 100644 --- a/test/test_sound.py +++ b/test/test_sound.py @@ -31,7 +31,7 @@ __all__ = ['SoundTest'] -from test._utils import MenuUtils +from test._utils import MenuUtils, SYS_PLATFORM_OSX import copy import unittest @@ -50,6 +50,8 @@ def test_copy(self) -> None: """ Test sound copy. """ + if SYS_PLATFORM_OSX: + return sound_src = pygame_menu.sound.Sound() sound_src.load_example_sounds() @@ -65,6 +67,8 @@ def test_none_channel(self) -> None: """ Test none channel. """ + if SYS_PLATFORM_OSX: + return new_sound = pygame_menu.sound.Sound(uniquechannel=False) new_sound.load_example_sounds() new_sound.play_widget_selection() @@ -79,6 +83,8 @@ def test_channel(self) -> None: """ Test channel. """ + if SYS_PLATFORM_OSX: + return new_sound = pygame_menu.sound.Sound(uniquechannel=False) new_sound.get_channel() self.sound.get_channel_info() diff --git a/test/test_widgets.py b/test/test_widgets.py index 953eb82e..3598ce09 100644 --- a/test/test_widgets.py +++ b/test/test_widgets.py @@ -32,7 +32,7 @@ __all__ = ['WidgetsTest'] from test._utils import MenuUtils, surface, PygameEventUtils, test_reset_surface, \ - TEST_THEME, PYGAME_V2, WINDOW_SIZE, THEME_NON_FIXED_TITLE + TEST_THEME, PYGAME_V2, WINDOW_SIZE, THEME_NON_FIXED_TITLE, SYS_PLATFORM_OSX import copy import unittest @@ -264,6 +264,8 @@ def test_max_width_height(self) -> None: """ Test widget max width/height. """ + if SYS_PLATFORM_OSX: + return label = Label('my label is really long yeah, it should be scaled in the width') label.set_font(pygame_menu.font.FONT_OPEN_SANS, 25, (255, 255, 255), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)) @@ -390,6 +392,8 @@ def test_menubar(self) -> None: """ Test menubar widget. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu() for mode in (MENUBAR_STYLE_ADAPTIVE, MENUBAR_STYLE_NONE, MENUBAR_STYLE_SIMPLE, MENUBAR_STYLE_UNDERLINE, MENUBAR_STYLE_UNDERLINE_TITLE, @@ -549,6 +553,8 @@ def test_colorinput(self) -> None: """ Test ColorInput widget. """ + if SYS_PLATFORM_OSX: + return def _assert_invalid_color(widg) -> None: """ @@ -879,6 +885,8 @@ def test_textinput(self) -> None: """ Test TextInput widget. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu() # Assert bad settings @@ -1369,6 +1377,8 @@ def test_update_callback(self) -> None: """ Test update callback. """ + if SYS_PLATFORM_OSX: + return def update(event, widget, _) -> None: """ @@ -1468,6 +1478,8 @@ def test_dropselect_multiple(self) -> None: """ Test dropselect multiple widget. """ + if SYS_PLATFORM_OSX: + return theme = pygame_menu.themes.THEME_DEFAULT.copy() theme.widget_font_size = 25 menu = MenuUtils.generic_menu(mouse_motion_selection=True, theme=theme) @@ -1629,6 +1641,8 @@ def test_dropselect(self) -> None: """ Test dropselect widget. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(mouse_motion_selection=True, theme=THEME_NON_FIXED_TITLE) items = [('This is a really long selection item', 1), ('epic', 2)] for i in range(10): @@ -2589,6 +2603,8 @@ def test_widget_floating_zero(self) -> None: """ Test widgets with zero position if float. """ + if SYS_PLATFORM_OSX: + return menu = MenuUtils.generic_menu(title='Example menu') img = pygame_menu.BaseImage(pygame_menu.baseimage.IMAGE_EXAMPLE_PYGAME_MENU) img.scale(0.3, 0.3) From f6b31cbd6f8e30e339da1204e81f58eb29dda1d2 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 22:03:53 -0300 Subject: [PATCH 02/16] Added windows bmp file exception --- pygame_menu/baseimage.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/pygame_menu/baseimage.py b/pygame_menu/baseimage.py index b354f2b6..8837bc18 100644 --- a/pygame_menu/baseimage.py +++ b/pygame_menu/baseimage.py @@ -65,7 +65,7 @@ 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, warn from pygame_menu._types import Tuple2IntType, Union, Vector2NumberType, Callable, \ Tuple, List, NumberType, Optional, Dict, Tuple4IntType, Literal, Tuple2NumberType, \ @@ -192,8 +192,27 @@ 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) + # Try to load the image + try: + self._surface = pygame.image.load(image_path) + + except pygame.error as exc: + # Check if file is not a windows file + if str(exc) == 'File is not a Windows BMP file': + # Check if Pillow exists + try: + # noinspection PyPackageRequirements + from PIL import Image + img_pil = Image.open(image_path) + self._surface = pygame.image.fromstring( + img_pil.tobytes(), img_pil.size, img_pil.mode).convert() + except (ModuleNotFoundError, ImportError): + warn('Image file could not be loaded, as pygame.error is' + ' raised. To avoid this issue install the Pillow ' + 'library') + raise + else: + raise self._original_surface = self._surface.copy() # Other internals From 233f575a9e89c709b75ea01b0d37d3646cad7092 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:35:52 -0300 Subject: [PATCH 03/16] Added docs for menulink --- docs/_source/widgets_menulink.rst | 12 ++++++++++++ docs/index.rst | 2 ++ 2 files changed, 14 insertions(+) create mode 100644 docs/_source/widgets_menulink.rst diff --git a/docs/_source/widgets_menulink.rst b/docs/_source/widgets_menulink.rst new file mode 100644 index 00000000..1f17e109 --- /dev/null +++ b/docs/_source/widgets_menulink.rst @@ -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, diff --git a/docs/index.rst b/docs/index.rst index fb070f6a..8e3c978f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -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` @@ -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 From c2880f7a7b796bfa14a764e7011fd10e3959bc50 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:36:21 -0300 Subject: [PATCH 04/16] Added menulink class --- pygame_menu/widgets/__init__.py | 4 +- pygame_menu/widgets/widget/__init__.py | 1 + pygame_menu/widgets/widget/menulink.py | 78 ++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 pygame_menu/widgets/widget/menulink.py diff --git a/pygame_menu/widgets/__init__.py b/pygame_menu/widgets/__init__.py index a747b4d2..698d8840 100644 --- a/pygame_menu/widgets/__init__.py +++ b/pygame_menu/widgets/__init__.py @@ -39,8 +39,8 @@ # Widgets from pygame_menu.widgets.widget import Button, ColorInput, DropSelect, \ - DropSelectMultiple, Frame, HMargin, Image, Label, MenuBar, NoneWidget, ScrollBar, \ - Selector, SurfaceWidget, Table, TextInput, ToggleSwitch, VMargin + DropSelectMultiple, Frame, HMargin, Image, Label, MenuBar, MenuLink, NoneWidget, \ + ScrollBar, Selector, SurfaceWidget, Table, TextInput, ToggleSwitch, VMargin # Widget constants from pygame_menu.widgets.widget.colorinput import COLORINPUT_TYPE_RGB, \ diff --git a/pygame_menu/widgets/widget/__init__.py b/pygame_menu/widgets/widget/__init__.py index 05064f3e..5d1750e1 100644 --- a/pygame_menu/widgets/widget/__init__.py +++ b/pygame_menu/widgets/widget/__init__.py @@ -38,6 +38,7 @@ from pygame_menu.widgets.widget.image import Image from pygame_menu.widgets.widget.label import Label from pygame_menu.widgets.widget.menubar import MenuBar +from pygame_menu.widgets.widget.menulink import MenuLink from pygame_menu.widgets.widget.none import NoneWidget from pygame_menu.widgets.widget.scrollbar import ScrollBar from pygame_menu.widgets.widget.selector import Selector diff --git a/pygame_menu/widgets/widget/menulink.py b/pygame_menu/widgets/widget/menulink.py new file mode 100644 index 00000000..01487a2a --- /dev/null +++ b/pygame_menu/widgets/widget/menulink.py @@ -0,0 +1,78 @@ +""" +pygame-menu +https://github.com/ppizarror/pygame-menu + +MENULINK +Similar to a Button that opens a Menu, MenuLink is a widget that contains a Menu +reference. This Menu can be opened with .open() method. + +License: +------------------------------------------------------------------------------- +The MIT License (MIT) +Copyright 2017-2021 Pablo Pizarro R. @ppizarror + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------- +""" + +__all__ = ['MenuLink'] + +import pygame_menu + +from pygame_menu.widgets.widget.none import NoneWidget +from pygame_menu.utils import is_callable + +from pygame_menu._types import Callable + + +# noinspection PyMissingOrEmptyDocstring +class MenuLink(NoneWidget): + """ + Menu link widget. + + :param link_id: Link ID + :param menu_opener_handler: Callback for opening the menu object + :param menu: Menu object + """ + menu: 'pygame_menu.Menu' + + def __init__( + self, + menu: 'pygame_menu.Menu', + menu_opener_handler: Callable, + link_id: str = '' + ) -> None: + assert isinstance(menu, pygame_menu.Menu) + assert is_callable(menu_opener_handler), \ + 'menu opener handler must be callable (a function)' + super(MenuLink, self).__init__( + widget_id=link_id + ) + self.menu = menu + self._onreturn = menu_opener_handler + self._visible = False + self.is_selectable = False + + def hide(self) -> 'MenuLink': + pass + + def show(self) -> 'MenuLink': + pass + + def open(self) -> None: + return self._onreturn(self.menu) From a9d9627cac7c951495e743a883c4bed323168cb7 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:36:33 -0300 Subject: [PATCH 05/16] Added menu link for manager and tests --- pygame_menu/_widgetmanager.py | 48 +++++++++++++++++++++++++++ test/test_menu.py | 4 +-- test/test_widgets.py | 62 +++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/pygame_menu/_widgetmanager.py b/pygame_menu/_widgetmanager.py index 6327f9c1..16435ce7 100644 --- a/pygame_menu/_widgetmanager.py +++ b/pygame_menu/_widgetmanager.py @@ -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 .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', diff --git a/test/test_menu.py b/test/test_menu.py index b9b9984b..e84135ad 100644 --- a/test/test_menu.py +++ b/test/test_menu.py @@ -31,8 +31,8 @@ __all__ = ['MenuTest'] -from test._utils import surface, test_reset_surface, MenuUtils, PygameEventUtils,\ - TEST_THEME, PYGAME_V2, WIDGET_MOUSEOVER, WIDGET_TOP_CURSOR, reset_widgets_over,\ +from test._utils import surface, test_reset_surface, MenuUtils, PygameEventUtils, \ + TEST_THEME, PYGAME_V2, WIDGET_MOUSEOVER, WIDGET_TOP_CURSOR, reset_widgets_over, \ THEME_NON_FIXED_TITLE, SYS_PLATFORM_OSX from typing import Any, Tuple import copy diff --git a/test/test_widgets.py b/test/test_widgets.py index 3598ce09..1fced38f 100644 --- a/test/test_widgets.py +++ b/test/test_widgets.py @@ -2627,3 +2627,65 @@ def test_widget_floating_zero(self) -> None: image_widget.translate(-50, 0) menu.render() self.assertEqual(image_widget.get_position(), (-42, 60)) + + # noinspection PyTypeChecker + def test_menu_links(self) -> None: + """ + Test menu link. + """ + menu = MenuUtils.generic_menu() + menu1 = MenuUtils.generic_menu(title='Menu1', theme=pygame_menu.themes.THEME_BLUE) + menu1.add.button('Back', pygame_menu.events.BACK) + menu2 = MenuUtils.generic_menu(title='Menu2', theme=pygame_menu.themes.THEME_ORANGE) + menu2.add.button('Back', pygame_menu.events.BACK) + menu3 = MenuUtils.generic_menu(title='Menu3', theme=pygame_menu.themes.THEME_GREEN) + menu3.add.button('Back', pygame_menu.events.BACK) + btn1 = menu.add.button('menu1', menu1) + btn2 = menu.add.button('menu2', menu2) + btn3 = menu.add.button('menu3', menu3) + + # Hide the buttons + btn1.hide() + btn2.hide() + btn3.hide() + + # Now open menu with the button, this should open Menu1 by default + self.assertEqual(menu.get_current(), menu) + btn1.apply() + self.assertEqual(menu.get_current(), menu1) + menu.full_reset() + self.assertEqual(menu.get_current(), menu) + + # Add menu link + link_test = menu.add.menu_link(menu2) + link_test.open() + self.assertEqual(menu.get_current(), menu2) + menu.full_reset() + self.assertEqual(menu.get_current(), menu) + + self.assertFalse(link_test.is_visible()) + link_test.hide() + self.assertFalse(link_test.is_visible()) + link_test.show() + self.assertFalse(link_test.is_visible()) + + self.assertRaises(ValueError, lambda: menu.add.menu_link(menu)) + + # Invalid objects + self.assertRaises(ValueError, lambda: menu.add.menu_link(True)) + + # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring + def open_link(*args) -> None: + link: 'pygame_menu.widgets.MenuLink' = args[-1] + self.assertIsInstance(link, pygame_menu.widgets.MenuLink) + link.open() + + # Add a selection object, which opens the links + sel = menu.add.selector('Change menu ', [ + ('Menu 1', menu.add.menu_link(menu1)), + ('Menu 2', menu.add.menu_link(menu2)), + ('Menu 3', menu.add.menu_link(menu3)) + ], onreturn=open_link, style=pygame_menu.widgets.SELECTOR_STYLE_FANCY) + + menu.mainloop(surface) + sel.update(PygameEventUtils.key(KEY_APPLY, keydown=True)) From 66b6ee2d24eac10cceec04398060cb5858f5f01b Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:40:07 -0300 Subject: [PATCH 06/16] Fix tests --- test/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_widgets.py b/test/test_widgets.py index 1fced38f..4178bad7 100644 --- a/test/test_widgets.py +++ b/test/test_widgets.py @@ -2687,5 +2687,5 @@ def open_link(*args) -> None: ('Menu 3', menu.add.menu_link(menu3)) ], onreturn=open_link, style=pygame_menu.widgets.SELECTOR_STYLE_FANCY) - menu.mainloop(surface) + # menu.mainloop(surface) sel.update(PygameEventUtils.key(KEY_APPLY, keydown=True)) From 5c9259443d5403e4639de02abc2dd7673a846c4f Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:58:02 -0300 Subject: [PATCH 07/16] Fix darwin kwargs to surface --- pygame_menu/examples/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pygame_menu/examples/__init__.py b/pygame_menu/examples/__init__.py index 8bc314d5..d17e1052 100644 --- a/pygame_menu/examples/__init__.py +++ b/pygame_menu/examples/__init__.py @@ -32,6 +32,8 @@ __all__ = ['create_example_window'] import pygame +import sys + from typing import Tuple _PYGAME_ICON = [None] @@ -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: From d84776d3a8a71702bbc7af5b8e0b716575a311ed Mon Sep 17 00:00:00 2001 From: ppizarror Date: Tue, 30 Mar 2021 23:58:09 -0300 Subject: [PATCH 08/16] Added menu link example --- docs/_source/add_widgets.rst | 38 ++++++++++++++++++++++++++++++++++++ docs/add_widgets.py | 27 ++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/_source/add_widgets.rst b/docs/_source/add_widgets.rst index 3769bfaa..c0008282 100644 --- a/docs/_source/add_widgets.rst +++ b/docs/_source/add_widgets.rst @@ -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_label.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 ----------------- diff --git a/docs/add_widgets.py b/docs/add_widgets.py index fa0650a6..26d26975 100644 --- a/docs/add_widgets.py +++ b/docs/add_widgets.py @@ -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' @@ -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') From 89840d62515a8926b8477314a276ff8f52dc4896 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 21:36:53 -0300 Subject: [PATCH 09/16] Added svg test --- pygame_menu/baseimage.py | 32 ++----- pygame_menu/resources/images/python.svg | 113 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 pygame_menu/resources/images/python.svg diff --git a/pygame_menu/baseimage.py b/pygame_menu/baseimage.py index 8837bc18..de4805f1 100644 --- a/pygame_menu/baseimage.py +++ b/pygame_menu/baseimage.py @@ -40,6 +40,7 @@ 'IMAGE_EXAMPLE_GRAY_LINES', 'IMAGE_EXAMPLE_METAL', 'IMAGE_EXAMPLE_PYGAME_MENU', + 'IMAGE_EXAMPLE_PYTHON', 'IMAGE_EXAMPLE_WALLPAPER', 'IMAGE_EXAMPLES', @@ -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, warn +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, \ @@ -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 @@ -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'] @@ -192,27 +196,7 @@ def __init__( # Load the image and store as a surface if load_from_file: - # Try to load the image - try: - self._surface = pygame.image.load(image_path) - - except pygame.error as exc: - # Check if file is not a windows file - if str(exc) == 'File is not a Windows BMP file': - # Check if Pillow exists - try: - # noinspection PyPackageRequirements - from PIL import Image - img_pil = Image.open(image_path) - self._surface = pygame.image.fromstring( - img_pil.tobytes(), img_pil.size, img_pil.mode).convert() - except (ModuleNotFoundError, ImportError): - warn('Image file could not be loaded, as pygame.error is' - ' raised. To avoid this issue install the Pillow ' - 'library') - raise - else: - raise + self._surface = load_pygame_image_file(image_path) self._original_surface = self._surface.copy() # Other internals diff --git a/pygame_menu/resources/images/python.svg b/pygame_menu/resources/images/python.svg new file mode 100644 index 00000000..366f52f3 --- /dev/null +++ b/pygame_menu/resources/images/python.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + From fa04c14b3e750e41dd78200ee33bf513074e6e49 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 21:37:05 -0300 Subject: [PATCH 10/16] Added menulink example image --- docs/_source/add_widgets.rst | 2 +- docs/_static/widget_menulink.png | Bin 0 -> 14238 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/_static/widget_menulink.png diff --git a/docs/_source/add_widgets.rst b/docs/_source/add_widgets.rst index c0008282..500fec3b 100644 --- a/docs/_source/add_widgets.rst +++ b/docs/_source/add_widgets.rst @@ -390,7 +390,7 @@ a button. Links can be opened using the ``open`` method. **Example:** -.. image:: ../_static/widget_label.png +.. image:: ../_static/widget_menulink.png :scale: 75% :align: center diff --git a/docs/_static/widget_menulink.png b/docs/_static/widget_menulink.png new file mode 100644 index 0000000000000000000000000000000000000000..318f3308e3b95f95fda2e5671f1e3319d810dce4 GIT binary patch literal 14238 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 Date: Wed, 31 Mar 2021 21:37:15 -0300 Subject: [PATCH 11/16] v402 --- pygame_menu/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygame_menu/version.py b/pygame_menu/version.py index 9de13225..be25f734 100644 --- a/pygame_menu/version.py +++ b/pygame_menu/version.py @@ -57,6 +57,6 @@ def __str__(self) -> str: patch = property(lambda self: self[2]) -vernum = Version(4, 0, 1) +vernum = Version(4, 0, 2) ver = str(vernum) rev = '' From 4f3d9e8e88c03c68c04e903e22053ce349209d70 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 21:37:36 -0300 Subject: [PATCH 12/16] Test more gradients frame title --- test/test_frame.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_frame.py b/test/test_frame.py index ec13be3a..ca51be30 100644 --- a/test/test_frame.py +++ b/test/test_frame.py @@ -1876,6 +1876,14 @@ def click_button(**kwargs) -> None: menu.update(PygameEventUtils.middle_rect_mouse_motion(frame2._frame_title, rel=(0, 100))) self.assertEqual(frame2.get_translate(), (10, 115)) + # Test more title gradients + frame2.set_title('title', + background_color=((10, 36, 106), (166, 202, 240), True, True)) + frame2.set_title('title', + background_color=((10, 36, 106), (166, 202, 240), True, False)) + frame2.set_title('title', + background_color=((10, 36, 106), (166, 202, 240), False, False)) + def test_resize(self) -> None: """ Test resize. From 7dc85db219e4a470f98b75a617cc09c5b56faeb0 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 21:37:44 -0300 Subject: [PATCH 13/16] Move load image file to utils --- pygame_menu/utils.py | 47 ++++++++++++++++++++++++++++++++++++++++++ test/test_baseimage.py | 16 ++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pygame_menu/utils.py b/pygame_menu/utils.py index bd48ddc1..1aa278f5 100644 --- a/pygame_menu/utils.py +++ b/pygame_menu/utils.py @@ -45,6 +45,7 @@ 'format_color', 'get_finger_pos', 'is_callable', + 'load_pygame_image_file', 'make_surface', 'mouse_motion_current_mouse_position', 'parse_padding', @@ -380,6 +381,52 @@ def is_callable(func: Any) -> bool: types.MethodType, functools.partial)) +def load_pygame_image_file(image_path: str, **kwargs) -> 'pygame.Surface': + """ + Loads an image and returns a surface. + + :param image_path: Image file + :param kwargs: Optional keyword arguments + :return: Surface + """ + # Try to load the image + try: + if 'test' in kwargs.keys(): + raise pygame.error('File is not a Windows BMP file') + + surface = pygame.image.load(image_path) + + except pygame.error as exc: + # Check if file is not a windows file + if str(exc) == 'File is not a Windows BMP file': + pil_invalid_exception = Exception + + # Check if Pillow exists + try: + # noinspection PyPackageRequirements + from PIL import Image, UnidentifiedImageError + + pil_invalid_exception = UnidentifiedImageError + img_pil = Image.open(image_path) + surface = pygame.image.fromstring( + img_pil.tobytes(), img_pil.size, img_pil.mode).convert() + + except (ModuleNotFoundError, ImportError): + warn('Image file could not be loaded, as pygame.error is' + ' raised. To avoid this issue install the Pillow ' + 'library') + raise + + except pil_invalid_exception: + warn('The image could not be loaded using Pillow') + raise + + else: + raise + + return surface + + def make_surface( width: NumberType, height: NumberType, diff --git a/test/test_baseimage.py b/test/test_baseimage.py index d7c9c831..320b95ca 100644 --- a/test/test_baseimage.py +++ b/test/test_baseimage.py @@ -43,6 +43,7 @@ from pygame_menu.baseimage import IMAGE_MODE_CENTER, IMAGE_MODE_FILL, IMAGE_MODE_REPEAT_X, \ IMAGE_MODE_REPEAT_XY, IMAGE_MODE_REPEAT_Y, IMAGE_MODE_SIMPLE +from pygame_menu.utils import load_pygame_image_file class BaseImageTest(unittest.TestCase): @@ -277,6 +278,21 @@ def test_operations(self) -> None: image.restore() self.assertFalse(image.equals(image_original)) + def test_invalid_image(self) -> None: + """ + Test invalid image opening. + """ + image = pygame_menu.BaseImage(pygame_menu.baseimage.IMAGE_EXAMPLE_PYTHON) + self.assertEqual(image.get_size(), (110, 109)) + + image._drawing_position = 'invalid' + self.assertRaises(ValueError, lambda: image._get_position_delta()) + + # Test invalid image + self.assertRaises(Exception, + lambda: load_pygame_image_file(pygame_menu.baseimage.IMAGE_EXAMPLE_PYTHON, + test=True)) + def test_copy(self) -> None: """ Test copy image. From f55cb06111cc9cd32144a7d30ed7967f132f5213 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 21:38:30 -0300 Subject: [PATCH 14/16] Improve menulink docs --- pygame_menu/_widgetmanager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygame_menu/_widgetmanager.py b/pygame_menu/_widgetmanager.py index 16435ce7..96c9572c 100644 --- a/pygame_menu/_widgetmanager.py +++ b/pygame_menu/_widgetmanager.py @@ -2588,8 +2588,8 @@ def menu_link( 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 .open() method. Opened menus change the - state of the parent Menu (the current pointer). + Added menus can be opened using the ``.open()`` method. Opened menus change + the state of the parent Menu (the current pointer). .. note:: From a0285defe5278d3f65b1d592c4797bca30bcd771 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 22:35:30 -0300 Subject: [PATCH 15/16] Ignore menubar rotate and flip --- docs/_source/widgets_menubar.rst | 2 +- pygame_menu/widgets/widget/menubar.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/_source/widgets_menubar.rst b/docs/_source/widgets_menubar.rst index a3b0f6d3..c845edf2 100644 --- a/docs/_source/widgets_menubar.rst +++ b/docs/_source/widgets_menubar.rst @@ -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 diff --git a/pygame_menu/widgets/widget/menubar.py b/pygame_menu/widgets/widget/menubar.py index 71d58168..7fb6d195 100644 --- a/pygame_menu/widgets/widget/menubar.py +++ b/pygame_menu/widgets/widget/menubar.py @@ -188,6 +188,9 @@ def scale(self, *args, **kwargs) -> 'MenuBar': def resize(self, *args, **kwargs) -> 'MenuBar': return self + def rotate(self, *args, **kwargs) -> 'MenuBar': + return self + def set_max_height(self, *args, **kwargs) -> 'MenuBar': return self @@ -200,6 +203,9 @@ def set_selection_effect(self, *args, **kwargs) -> 'MenuBar': def set_border(self, *args, **kwargs) -> 'MenuBar': return self + def flip(self, *args, **kwargs) -> 'MenuBar': + return self + def _check_title_color(self, background_menu: bool) -> None: """ Performs title color and prints a warning if the color is similar to the From 6c3e38bd695fe44c803727e9cac44b18d4938a61 Mon Sep 17 00:00:00 2001 From: ppizarror Date: Wed, 31 Mar 2021 22:35:38 -0300 Subject: [PATCH 16/16] Improve widgets tests --- test/test_widgets.py | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/test_widgets.py b/test/test_widgets.py index 4178bad7..a0ce6cc6 100644 --- a/test/test_widgets.py +++ b/test/test_widgets.py @@ -474,6 +474,35 @@ def test_menubar(self) -> None: self.assertFalse(mb.update(PygameEventUtils.middle_rect_click(mb._backbox_rect, evtype=pygame.MOUSEBUTTONDOWN))) self.assertTrue(mb.update(PygameEventUtils.joy_button(pygame_menu.controls.JOY_BUTTON_BACK))) + # Test none methods + mb.rotate(10) + self.assertEqual(mb._angle, 0) + + mb.resize(10, 10) + self.assertFalse(mb._scale[0]) + self.assertEqual(mb._scale[1], 1) + self.assertEqual(mb._scale[2], 1) + + mb.scale(100, 100) + self.assertFalse(mb._scale[0]) + self.assertEqual(mb._scale[1], 1) + self.assertEqual(mb._scale[2], 1) + + mb.flip(True, True) + self.assertFalse(mb._flip[0]) + self.assertFalse(mb._flip[1]) + + mb.set_max_width(100) + self.assertIsNone(mb._max_width[0]) + + mb.set_max_height(100) + self.assertIsNone(mb._max_height[0]) + + # Ignore others + mb.set_padding() + mb.set_border() + mb.set_selection_effect() + # noinspection PyArgumentEqualDefault,PyTypeChecker def test_selector(self) -> None: """ @@ -705,6 +734,10 @@ def _assert_color(widg, cr, cg, cb) -> None: _assert_color(widget, 18, 255, 170) widget.set_value(' 59C1e5') _assert_color(widget, 89, 193, 229) + + widget.render() + widget.draw(surface) + widget.clear() self.assertEqual(widget._input_string, '#') # This cannot be empty self.assertEqual(widget._cursor_position, 1) @@ -768,6 +801,7 @@ def test_label(self) -> None: Test label widget. """ menu = MenuUtils.generic_menu() + # noinspection SpellCheckingInspection label = menu.add.label('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ' 'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, ' @@ -869,6 +903,12 @@ def generator() -> str: self.assertEqual(label.get_title(), 'b') self.assertIsNone(label._title_generator) + # Label set to empty + label_e = menu.add.label('new') + self.assertRaises(ValueError, lambda: label_e.set_value('')) + label_e.set_title('') + label_e.draw(surface) + def test_clock(self) -> None: """ Test clock. @@ -1338,7 +1378,10 @@ def callback(**kwargs) -> None: btn = menu.add.button('epic', pygame_menu.events.NONE) self.assertEqual(btn._decorator._total_decor(), 0) btn.add_underline((0, 0, 0), 1, 1, force_render=True) + self.assertNotEqual(btn._last_underline[0], '') self.assertEqual(btn._decorator._total_decor(), 1) + btn.remove_underline() + self.assertEqual(btn._last_underline[0], '') # Test return fun def fun() -> str: @@ -1968,6 +2011,8 @@ def test_dropselect(self) -> None: # Test onchange test = [-1, False] + drop2.set_default_value(0) + def test_change(item, v) -> None: """ Test change.