Repository: MyreMylar/pygame_gui
Pull request #537 (2024-03-10 14:18:00)

Add expand_left & _top to UIContainer
Step 3 of splitting mega-PR #494 into smaller easier to review PRs


Patch:
diff --git a/pygame_gui/core/ui_container.py b/pygame_gui/core/ui_container.py
index e1e1ff8..03047f7 100644
--- a/pygame_gui/core/ui_container.py
+++ b/pygame_gui/core/ui_container.py
@@ -219,6 +219,56 @@ class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
         super().set_dimensions(dimensions)
         self.update_containing_rect_position()
 
+    def expand_left(self, width_increase: int) -> None:
+        """
+        Increases the width of the container, but instead of expanding the right edge, it expands the left edge.
+        This is achieved by setting the new dimensions and updating the anchors of all the elements anchored
+        to the left of the container.
+
+        :param width_increase: The width to increase by. Pass in negative values to decrease the size
+        :return: None
+        """
+
+        # Increase width
+        dim = self.rect.width + width_increase, self.rect.height
+        self.set_dimensions(dim)
+
+        # Reposition so that the right edge is back to where it was
+        pos = self.relative_rect.left - width_increase, self.relative_rect.top
+        self.set_relative_position(pos)
+
+        # Moving the elements anchored to the top to make it seem like the container just increased its top edge
+        for element in self.elements:
+            anchors = element.get_anchors()
+            if "left" in anchors.values() and "left_target" not in anchors:
+                pos = pygame.Vector2(element.get_relative_rect().topleft) + pygame.Vector2(width_increase, 0)
+                element.set_relative_position(pos)
+
+    def expand_top(self, height_increase: int) -> None:
+        """
+        Increases the height of the container, but instead of expanding the bottom edge, it expands the top edge.
+        This is achieved by setting the new dimensions and updating the anchors of all the elements anchored
+        to the top of the container.
+
+        :param height_increase: The height to increase by. Pass in negative values to decrease the size
+        :return: None
+        """
+
+        # Increase height
+        dim = self.rect.width, self.rect.height + height_increase
+        self.set_dimensions(dim)
+
+        # Reposition so that the bottom edge is back to where it was
+        pos = self.relative_rect.left, self.relative_rect.top - height_increase
+        self.set_relative_position(pos)
+
+        # Moving the elements anchored to the top to make it seem like the container just increased its top edge
+        for element in self.elements:
+            anchors = element.get_anchors()
+            if "top" in anchors.values() and "top_target" not in anchors:
+                pos = pygame.Vector2(element.get_relative_rect().topleft) + pygame.Vector2(0, height_increase)
+                element.set_relative_position(pos)
+
     def get_top_layer(self) -> int:
         """
         Assuming we have correctly calculated the 'thickness' of this container, this method will


Test patch:
diff --git a/tests/test_core/test_ui_container.py b/tests/test_core/test_ui_container.py
index 3ac380e..cce27eb 100644
--- a/tests/test_core/test_ui_container.py
+++ b/tests/test_core/test_ui_container.py
@@ -144,7 +144,7 @@ class TestUIContainer:
         default_ui_manager.mouse_position = (150, 150)
         assert container.check_hover(0.5, False) is True  # already hovering
         container.kill()
-        assert container.check_hover(0.5, False) is False  # dead so can't hover any more
+        assert container.check_hover(0.5, False) is False  # dead so can't hover anymore
 
     def test_resizing_with_anchors(self, _init_pygame, default_ui_manager,
                                    _display_surface_return_none):
@@ -232,6 +232,38 @@ class TestUIContainer:
         assert container.visible == 0
         assert button.visible == 1
 
+    def test_expand_left(self, _init_pygame, default_ui_manager: IUIManagerInterface,
+                         _display_surface_return_none):
+        container = UIContainer(pygame.Rect(100, 100, 200, 200), manager=default_ui_manager, visible=0)
+        button = UIButton(relative_rect=pygame.Rect(50, 50, 50, 50), text="",
+                          manager=default_ui_manager, container=container)
+
+        assert button.get_abs_rect() == pygame.Rect(150, 150, 50, 50)
+        assert button.get_relative_rect() == pygame.Rect(50, 50, 50, 50)
+        assert container.get_relative_rect() == pygame.Rect(100, 100, 200, 200)
+
+        container.expand_left(50)
+
+        assert button.get_abs_rect() == pygame.Rect(150, 150, 50, 50)
+        assert button.get_relative_rect() == pygame.Rect(100, 50, 50, 50)
+        assert container.get_relative_rect() == pygame.Rect(50, 100, 250, 200)
+
+    def test_expand_top(self, _init_pygame, default_ui_manager: IUIManagerInterface,
+                        _display_surface_return_none):
+        container = UIContainer(pygame.Rect(100, 100, 200, 200), manager=default_ui_manager, visible=0)
+        button = UIButton(relative_rect=pygame.Rect(50, 50, 50, 50), text="",
+                          manager=default_ui_manager, container=container)
+
+        assert button.get_abs_rect() == pygame.Rect(150, 150, 50, 50)
+        assert button.get_relative_rect() == pygame.Rect(50, 50, 50, 50)
+        assert container.get_relative_rect() == pygame.Rect(100, 100, 200, 200)
+
+        container.expand_top(50)
+
+        assert button.get_abs_rect() == pygame.Rect(150, 150, 50, 50)
+        assert button.get_relative_rect() == pygame.Rect(50, 100, 50, 50)
+        assert container.get_relative_rect() == pygame.Rect(100, 50, 200, 250)
+
 
 if __name__ == '__main__':
     pytest.console_main()