diff --git a/CHANGELOG.md b/CHANGELOG.md index 76220abe57..8b5c84811a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Arcade [PyPi Release History](https://pypi.org/project/arcade/#history) page. - Upgraded Pillow to 12.0.0 for Python 3.14 support. - Adds a new `arcade.NoAracdeWindowError` exception type. This is raised when certain window operations are performed and there is no valid Arcade window found. Previously where this error would be raised, we raised a standard `RuntimeError`, this made it harder to properly catch and act accordingly. This new exception subclasses `RuntimeError`, so you can still catch this error the same way as before. The `arcade.get_window()` function will now raise this if there is no window. - Along with the new exception type, is a new `arcade.windows_exists()` function which will return True or False based on if there is currently an active window. +- GUI + - `UIManager` did not apply size hint of (0,0). Mainly an issue with `UIBoxLayout`. + - Allow multiple children in `UIScrollArea`. + - Fix `UIDropdown Overlay` positioning within a `UIScrollArea`. ## 3.3.3 diff --git a/arcade/gui/experimental/scroll_area.py b/arcade/gui/experimental/scroll_area.py index bd7db75412..3bee0c13e9 100644 --- a/arcade/gui/experimental/scroll_area.py +++ b/arcade/gui/experimental/scroll_area.py @@ -239,9 +239,6 @@ def __init__( def add(self, child: W, **kwargs) -> W: """Add a child to the widget.""" - if self._children: - raise ValueError("UIScrollArea can only have one child") - super().add(child, **kwargs) self.trigger_full_render() diff --git a/arcade/gui/ui_manager.py b/arcade/gui/ui_manager.py index 3a5707d47d..f7b6500d5f 100644 --- a/arcade/gui/ui_manager.py +++ b/arcade/gui/ui_manager.py @@ -246,8 +246,8 @@ def _do_layout(self): # actual layout if child.size_hint: sh_x, sh_y = child.size_hint - nw = surface_width * sh_x if sh_x else None - nh = surface_height * sh_y if sh_y else None + nw = surface_width * sh_x if sh_x is not None else None + nh = surface_height * sh_y if sh_y is not None else None child.rect = child.rect.resize(nw, nh, anchor=AnchorPoint.BOTTOM_LEFT) if child.size_hint_min: diff --git a/arcade/gui/widgets/dropdown.py b/arcade/gui/widgets/dropdown.py index afa75c495a..43e88358a9 100644 --- a/arcade/gui/widgets/dropdown.py +++ b/arcade/gui/widgets/dropdown.py @@ -6,6 +6,7 @@ from arcade import uicolor from arcade.gui import UIEvent, UIMousePressEvent from arcade.gui.events import UIControllerButtonPressEvent, UIOnChangeEvent, UIOnClickEvent +from arcade.gui.experimental import UIScrollArea from arcade.gui.experimental.focus import UIFocusMixin from arcade.gui.ui_manager import UIManager from arcade.gui.widgets import UILayout, UIWidget @@ -21,7 +22,7 @@ class _UIDropdownOverlay(UIFocusMixin, UIBoxLayout): # TODO move also options logic to this class - def show(self, manager: UIManager): + def show(self, manager: UIManager | UIScrollArea): manager.add(self, layer=UIManager.OVERLAY_LAYER) def hide(self): @@ -197,11 +198,19 @@ def _update_options(self): self._overlay.detect_focusable_widgets() def _show_overlay(self): - manager = self.get_ui_manager() - if manager is None: - raise Exception("UIDropdown could not find UIManager in its parents.") - - self._overlay.show(manager) + # traverse parents until UIManager or UIScrollArea is found + parent = self.parent + while parent is not None: + if isinstance(parent, UIManager): + break + if isinstance(parent, UIScrollArea): + break + parent = parent.parent + + if parent is None: + raise Exception("UIDropdown could not find a valid parent for the overlay.") + + self._overlay.show(parent) def _on_button_click(self, _: UIOnClickEvent): self._show_overlay() diff --git a/tests/unit/gui/test_uimanager_layouting.py b/tests/unit/gui/test_uimanager_layouting.py index 1f6487867b..f9f29ee409 100644 --- a/tests/unit/gui/test_uimanager_layouting.py +++ b/tests/unit/gui/test_uimanager_layouting.py @@ -25,9 +25,13 @@ def test_supports_size_hint(window): widget3 = UIDummy() widget3.size_hint = (1, None) + widget4 = UIDummy() + widget4.size_hint = (0, 0) + manager.add(widget1) manager.add(widget2) manager.add(widget3) + manager.add(widget4) with sized(window, 200, 300): manager.draw() @@ -35,6 +39,7 @@ def test_supports_size_hint(window): assert widget1.size == Vec2(200, 300) assert widget2.size == Vec2(100, 75) assert widget3.size == Vec2(200, 100) + assert widget4.size == Vec2(0, 0) def test_supports_size_hint_min(window):