Repository: MyreMylar/pygame_gui
Pull request #579 (2024-04-13 15:15:36)

Sort out type hints for relative rect
Also, make windows create at border boundary excluding shadow.


Patch:
diff --git a/pygame_gui/core/gui_type_hints.py b/pygame_gui/core/gui_type_hints.py
new file mode 100644
index 0000000..fea1186
--- /dev/null
+++ b/pygame_gui/core/gui_type_hints.py
@@ -0,0 +1,15 @@
+from typing import Union, Tuple, Protocol
+
+from pygame import Vector2, Rect, FRect, Surface
+
+Coordinate = Union[Vector2, Tuple[float, float]]
+RectLike = Union[Rect, FRect, Tuple[float, float, float, float]]
+
+
+class SpriteWithHealth(Protocol):
+    current_health: int
+    health_capacity: int
+    rect: Rect
+    image: Surface
+
+
diff --git a/pygame_gui/core/interfaces/__init__.py b/pygame_gui/core/interfaces/__init__.py
index 27aaf8d..3fd4f09 100644
--- a/pygame_gui/core/interfaces/__init__.py
+++ b/pygame_gui/core/interfaces/__init__.py
@@ -1,7 +1,7 @@
 from pygame_gui.core.interfaces.colour_gradient_interface import IColourGradientInterface
 from pygame_gui.core.interfaces.font_dictionary_interface import IUIFontDictionaryInterface
 from pygame_gui.core.interfaces.appearance_theme_interface import IUIAppearanceThemeInterface
-from pygame_gui.core.interfaces.element_interface import IUIElementInterface, Coordinate
+from pygame_gui.core.interfaces.element_interface import IUIElementInterface
 from pygame_gui.core.interfaces.container_interface import IUIContainerInterface
 from pygame_gui.core.interfaces.container_interface import IContainerLikeInterface
 from pygame_gui.core.interfaces.window_interface import IWindowInterface
@@ -25,5 +25,5 @@ __all__ = ['IColourGradientInterface',
            'IUIManagerInterface',
            'IUITextOwnerInterface',
            'IGUIFontInterface',
-           'IGUISpriteInterface',
-           'Coordinate']
+           'IGUISpriteInterface'
+           ]
diff --git a/pygame_gui/core/interfaces/container_interface.py b/pygame_gui/core/interfaces/container_interface.py
index 9b69093..7296e26 100644
--- a/pygame_gui/core/interfaces/container_interface.py
+++ b/pygame_gui/core/interfaces/container_interface.py
@@ -5,6 +5,7 @@ from typing import Tuple, Union
 import pygame
 
 from pygame_gui.core.interfaces.element_interface import IUIElementInterface
+from pygame_gui.core.gui_type_hints import Coordinate
 
 
 class IUIContainerInterface(IUIElementInterface, metaclass=ABCMeta):
@@ -72,9 +73,7 @@ class IUIContainerInterface(IUIElementInterface, metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Set the absolute position of this container - it is usually less chaotic to deal with
         setting relative positions.
@@ -84,9 +83,7 @@ class IUIContainerInterface(IUIElementInterface, metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Set the position of this container, relative to the container it is within.
 
@@ -95,10 +92,7 @@ class IUIContainerInterface(IUIElementInterface, metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Set the dimension of this container and update the positions of elements within it
         accordingly.
diff --git a/pygame_gui/core/interfaces/element_interface.py b/pygame_gui/core/interfaces/element_interface.py
index 6445baa..1365ef3 100644
--- a/pygame_gui/core/interfaces/element_interface.py
+++ b/pygame_gui/core/interfaces/element_interface.py
@@ -5,7 +5,7 @@ import pygame
 
 from pygame_gui.core.interfaces.gui_sprite_interface import IGUISpriteInterface
 
-Coordinate = Union[pygame.math.Vector2, Tuple[int, int], Tuple[float, float]]
+from pygame_gui.core.gui_type_hints import Coordinate
 
 
 class IUIElementInterface(IGUISpriteInterface, metaclass=ABCMeta):
@@ -15,6 +15,25 @@ class IUIElementInterface(IGUISpriteInterface, metaclass=ABCMeta):
 
     """
 
+    @property
+    @abstractmethod
+    def hovered(self) -> bool:
+        """
+        Are we hovering over this element with the mouse pointer or other input highlighting method.
+
+        :return: True if hovered.
+        """
+
+    @hovered.setter
+    @abstractmethod
+    def hovered(self, value: bool):
+        """
+        Setter for if we are hovering over this element with the mouse pointer or other input highlighting method.
+
+        :param value: the hovering value to set.
+        :return:
+        """
+
     @abstractmethod
     def get_relative_rect(self) -> pygame.Rect:
         """
diff --git a/pygame_gui/core/interfaces/tool_tip_interface.py b/pygame_gui/core/interfaces/tool_tip_interface.py
index 1d4ca9c..08843b2 100644
--- a/pygame_gui/core/interfaces/tool_tip_interface.py
+++ b/pygame_gui/core/interfaces/tool_tip_interface.py
@@ -1,12 +1,11 @@
 from abc import ABCMeta, abstractmethod
-from typing import Tuple, Union
 
-import pygame
+from pygame_gui.core.gui_type_hints import Coordinate
 
 
 class IUITooltipInterface(metaclass=ABCMeta):
     """
-       A meta class that defines the interface that a UI Tool tip uses.
+       A metaclass that defines the interface that a UI Tool tip uses.
 
        Interfaces like this help us evade cyclical import problems by allowing us to define the
        actual manager class later on and have it make use of the classes that use the interface.
@@ -27,7 +26,7 @@ class IUITooltipInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def find_valid_position(self, position: pygame.math.Vector2) -> bool:
+    def find_valid_position(self, position: Coordinate) -> bool:
         """
         Finds a valid position for the tool tip inside the root container of the UI.
 
@@ -36,7 +35,7 @@ class IUITooltipInterface(metaclass=ABCMeta):
         the left and to the right, until we find a position that fits the whole tooltip rectangle
         on the screen at once.
 
-        If we fail to manage this then the method will return False. Otherwise it returns True and
+        If we fail to manage this then the method will return False. Otherwise, it returns True and
         set the position of the tool tip to our valid position.
 
         :param position: A 2D vector representing the position of the target this tool tip is for.
@@ -53,11 +52,9 @@ class IUITooltipInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
-        Sets the absolute screen position of this tool tip, updating it's subordinate text box at
+        Sets the absolute screen position of this tool tip, updating its subordinate text box at
         the same time.
 
         :param position: The absolute screen position to set.
@@ -65,11 +62,9 @@ class IUITooltipInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
-        Sets the relative screen position of this tool tip, updating it's subordinate text box at
+        Sets the relative screen position of this tool tip, updating its subordinate text box at
         the same time.
 
         :param position: The relative screen position to set.
@@ -77,9 +72,7 @@ class IUITooltipInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]]):
+    def set_dimensions(self, dimensions: Coordinate):
         """
         Directly sets the dimensions of this tool tip. This will overwrite the normal theming.
 
diff --git a/pygame_gui/core/interfaces/window_interface.py b/pygame_gui/core/interfaces/window_interface.py
index d15ecb9..ea72445 100644
--- a/pygame_gui/core/interfaces/window_interface.py
+++ b/pygame_gui/core/interfaces/window_interface.py
@@ -1,5 +1,6 @@
 from abc import ABCMeta, abstractmethod
-from typing import Tuple, Union
+
+from pygame_gui.core.gui_type_hints import Coordinate
 
 import pygame
 
@@ -24,9 +25,7 @@ class IWindowInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_minimum_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                                       Tuple[int, int],
-                                                       Tuple[float, float]]):
+    def set_minimum_dimensions(self, dimensions: Coordinate):
         """
         If this window is resizable, then the dimensions we set here will be the minimum that
         users can change the window to. They are also used as the minimum size when
@@ -37,9 +36,7 @@ class IWindowInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]]):
+    def set_dimensions(self, dimensions: Coordinate):
         """
         Set the size of this window and then re-sizes and shifts the contents of the windows
         container to fit the new size.
@@ -49,9 +46,7 @@ class IWindowInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Method to directly set the relative rect position of an element.
 
@@ -60,9 +55,7 @@ class IWindowInterface(metaclass=ABCMeta):
         """
 
     @abstractmethod
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Method to directly set the absolute screen rect position of an element.
 
diff --git a/pygame_gui/core/ui_container.py b/pygame_gui/core/ui_container.py
index 9b4a251..978b844 100644
--- a/pygame_gui/core/ui_container.py
+++ b/pygame_gui/core/ui_container.py
@@ -6,6 +6,7 @@ from pygame_gui.core.ui_element import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core.interfaces import IUIContainerInterface, IUIElementInterface
 from pygame_gui.core.ui_element import UIElement
+from pygame_gui.core.gui_type_hints import RectLike, Coordinate
 
 
 class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
@@ -30,7 +31,7 @@ class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
                     Warning - it's parent container visibility may override this.
     """
     def __init__(self,
-                 relative_rect: Union[pygame.Rect, Tuple[int, int, int, int]],
+                 relative_rect: RectLike,
                  manager: IUIManagerInterface,
                  *,
                  starting_height: int = 1,
@@ -178,9 +179,7 @@ class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
         for element in self.elements:
             element.update_containing_rect_position()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Set the absolute position of this container - it is usually less chaotic to deal with
         setting relative positions.
@@ -191,9 +190,7 @@ class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
         super().set_position(position)
         self.update_containing_rect_position()
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Set the position of this container, relative to the container it is within.
 
@@ -203,10 +200,7 @@ class UIContainer(UIElement, IUIContainerInterface, IContainerLikeInterface):
         super().set_relative_position(position)
         self.update_containing_rect_position()
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Set the dimension of this container and update the positions of elements within it
         accordingly.
diff --git a/pygame_gui/core/ui_element.py b/pygame_gui/core/ui_element.py
index 407caa6..1a2b0fb 100644
--- a/pygame_gui/core/ui_element.py
+++ b/pygame_gui/core/ui_element.py
@@ -5,7 +5,8 @@ from typing import TYPE_CHECKING
 
 import pygame
 
-from pygame_gui.core.interfaces import IUIElementInterface, Coordinate
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
+from pygame_gui.core.interfaces import IUIElementInterface
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core.utility import render_white_text_alpha_black_bg
 from pygame_gui.core.utility import basic_blit
@@ -39,7 +40,7 @@ class UIElement(GUISprite, IUIElementInterface):
     :param element_id: A list of string ID representing this element's class.
     """
 
-    def __init__(self, relative_rect: Union[pygame.Rect, Tuple[int, int, int, int]],
+    def __init__(self, relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface],
                  container: Optional[IContainerLikeInterface],
                  *,
@@ -49,7 +50,8 @@ class UIElement(GUISprite, IUIElementInterface):
                  visible: int = 1,
                  parent_element: Optional[IUIElementInterface] = None,
                  object_id: Union[ObjectID, str, None] = None,
-                 element_id: Optional[List[str]] = None):
+                 element_id: Optional[List[str]] = None,
+                 ignore_shadow_for_initial_size_and_pos: bool = False):
 
         self._layer = 0
         self.ui_manager = manager
@@ -62,28 +64,67 @@ class UIElement(GUISprite, IUIElementInterface):
 
         super().__init__(self.ui_manager.get_sprite_group())
 
+        self.ui_group = self.ui_manager.get_sprite_group()
+        self.ui_theme = self.ui_manager.get_theme()
+
         self.minimum_dimensions = (-1, -1)
 
-        if isinstance(relative_rect, pygame.Rect):
+        self.object_ids = None
+        self.class_ids = None
+        self.element_ids = None
+        self.element_base_ids = None
+        self.combined_element_ids = None
+        self.most_specific_combined_id = 'no_id'
+
+        # Themed parameters
+        self.shadow_width = None  # type: Union[None, int]
+        self.border_width = None  # type: Union[None, int]
+        self.shape_corner_radius: Optional[List[int]] = None
+
+        self.tool_tip_text = None
+        self.tool_tip_text_kwargs = None
+        self.tool_tip_object_id = None
+        self.tool_tip_delay = 1.0
+        self.tool_tip_wrap_width = None
+        self.tool_tip = None
+
+        element_ids = element_id
+        element_id = None
+        base_id = None
+        if element_ids is not None:
+            if len(element_ids) >= 1:
+                element_id = element_ids[0]
+
+            if len(element_ids) >= 2:
+                base_id = element_ids[1]
+
+            self._create_valid_ids(container=container,
+                                   parent_element=parent_element,
+                                   object_id=object_id,
+                                   element_id=element_id,
+                                   element_base_id=base_id)
+
+        if isinstance(relative_rect, pygame.Rect) or isinstance(relative_rect, pygame.FRect):
             self.relative_rect = relative_rect.copy()
         else:
             self.relative_rect = pygame.Rect(relative_rect)
+
+        if ignore_shadow_for_initial_size_and_pos:
+            # need to expand our rect by the shadow size and adjust position by it as well.
+            self._check_shape_theming_changed(defaults={'border_width': 1,
+                                                        'shadow_width': 2,
+                                                        'shape_corner_radius': [2, 2, 2, 2]})
+            self.relative_rect.width += self.shadow_width * 2
+            self.relative_rect.height += self.shadow_width * 2
+            self.relative_rect.top -= self.shadow_width  # This will need to be changed when we can adjust the anchor source
+            self.relative_rect.left -= self.shadow_width  # This will need to be changed when we can adjust the anchor source
+
         self.relative_rect.size = self._get_clamped_to_minimum_dimensions(self.relative_rect.size)
         self.rect = self.relative_rect.copy()
 
         self.dynamic_width = True if self.relative_rect.width == -1 else False
         self.dynamic_height = True if self.relative_rect.height == -1 else False
 
-        self.ui_group = self.ui_manager.get_sprite_group()
-        self.ui_theme = self.ui_manager.get_theme()
-
-        self.object_ids = None
-        self.class_ids = None
-        self.element_ids = None
-        self.element_base_ids = None
-        self.combined_element_ids = None
-        self.most_specific_combined_id = 'no_id'
-
         self.anchors = {}
         self.set_anchors(anchors)
 
@@ -105,7 +146,7 @@ class UIElement(GUISprite, IUIElementInterface):
         self.starting_height = starting_height
 
         self.is_enabled = True
-        self.hovered = False
+        self._hovered = False
         self.is_focused = False
         self.hover_time = 0.0
 
@@ -116,18 +157,6 @@ class UIElement(GUISprite, IUIElementInterface):
 
         self._visual_debug_mode = False
 
-        # Themed parameters
-        self.shadow_width = None  # type: Union[None, int]
-        self.border_width = None  # type: Union[None, int]
-        self.shape_corner_radius: Optional[List[int]] = None
-
-        self.tool_tip_text = None
-        self.tool_tip_text_kwargs = None
-        self.tool_tip_object_id = None
-        self.tool_tip_delay = 1.0
-        self.tool_tip_wrap_width = None
-        self.tool_tip = None
-
         self._setup_container(container)
 
         self.dirty = 1
@@ -139,21 +168,13 @@ class UIElement(GUISprite, IUIElementInterface):
 
         self._focus_set = {self}
 
-        element_ids = element_id
-        element_id = None
-        base_id = None
-        if element_ids is not None:
-            if len(element_ids) >= 1:
-                element_id = element_ids[0]
+    @property
+    def hovered(self) -> bool:
+        return self._hovered
 
-            if len(element_ids) >= 2:
-                base_id = element_ids[1]
-
-            self._create_valid_ids(container=container,
-                                   parent_element=parent_element,
-                                   object_id=object_id,
-                                   element_id=element_id,
-                                   element_base_id=base_id)
+    @hovered.setter
+    def hovered(self, value: bool):
+        self._hovered = value
 
     def _get_clamped_to_minimum_dimensions(self, dimensions, clamp_to_container=False):
         if self.ui_container is not None and clamp_to_container:
@@ -909,7 +930,7 @@ class UIElement(GUISprite, IUIElementInterface):
         self.relative_rect.height = int(dimensions[1])
         self.rect.size = self.relative_rect.size
 
-        if dimensions[0] >= 0 and dimensions[1] >= 0:
+        if self.relative_rect.width >= 0 and self.relative_rect.height >= 0:
             self._update_absolute_rect_position_from_anchors(recalculate_margins=True)
 
             if self.drawable_shape is not None:
diff --git a/pygame_gui/elements/ui_2d_slider.py b/pygame_gui/elements/ui_2d_slider.py
index dc98bd1..56a3c3f 100644
--- a/pygame_gui/elements/ui_2d_slider.py
+++ b/pygame_gui/elements/ui_2d_slider.py
@@ -1,7 +1,8 @@
 import pygame
 from pygame_gui._constants import UI_2D_SLIDER_MOVED
 from pygame_gui.core import UIElement, UIContainer, ObjectID
-from pygame_gui.core.interfaces import IUIManagerInterface, IContainerLikeInterface, Coordinate
+from pygame_gui.core.interfaces import IUIManagerInterface, IContainerLikeInterface
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 from pygame_gui.elements import UIButton
 
@@ -32,7 +33,7 @@ class UI2DSlider(UIElement):
     """
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  start_value_x: Union[float, int],
                  value_range_x: Union[Tuple[float, float], Tuple[int, int]],
                  start_value_y: Union[float, int],
diff --git a/pygame_gui/elements/ui_auto_resizing_container.py b/pygame_gui/elements/ui_auto_resizing_container.py
index 4d1ff06..92ccb6a 100644
--- a/pygame_gui/elements/ui_auto_resizing_container.py
+++ b/pygame_gui/elements/ui_auto_resizing_container.py
@@ -1,6 +1,7 @@
 import pygame
 from pygame_gui.core import UIElement, UIContainer, ObjectID
 from pygame_gui.core.interfaces import IUIElementInterface, IUIManagerInterface, IContainerLikeInterface
+from pygame_gui.core.gui_type_hints import RectLike
 
 from typing import *
 
@@ -33,7 +34,7 @@ class UIAutoResizingContainer(UIContainer):
     """
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  min_edges_rect: pygame.Rect = None,
                  max_edges_rect: pygame.Rect = None,
                  resize_left: bool = True,
diff --git a/pygame_gui/elements/ui_button.py b/pygame_gui/elements/ui_button.py
index d1b32d6..d1d824d 100644
--- a/pygame_gui/elements/ui_button.py
+++ b/pygame_gui/elements/ui_button.py
@@ -11,20 +11,21 @@ from pygame_gui.core.drawable_shapes import EllipseDrawableShape, RoundedRectang
 from pygame_gui.core.drawable_shapes import RectDrawableShape
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core.ui_element import UIElement
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIButton(UIElement):
     """
     A push button, a lot of the appearance of the button, including images to be displayed, is
-    setup via the theme file. This button is designed to be pressed, do something, and then reset -
+    set up via the theme file. This button is designed to be pressed, do something, and then reset -
     rather than to be toggled on or off.
 
     The button element is reused throughout the UI as part of other elements as it happens to be a
     very flexible interactive element.
 
     :param relative_rect: Normally a rectangle describing the position (relative to its container) and
-                          dimensions. Also accepts a position Tuple, or Vector2 where the dimensions
-                          will be dynamic depending on the button's contents. Dynamic dimensions can
+                          dimensions. Also accepts a position Coordinate where the dimensions
+                          will be dynamic depending on the text contents. Dynamic dimensions can
                           be requested by setting the required dimension to -1.
     :param text: Text for the button.
     :param manager: The UIManager that manages this element. If not provided or set to None,
@@ -33,12 +34,12 @@ class UIButton(UIElement):
                       will be the root window's container.
     :param tool_tip_text: Optional tool tip text, can be formatted with HTML. If supplied will
                           appear on hover.
-    :param starting_height: The height in layers above it's container that this element will be
+    :param starting_height: The height in layers above its container that this element will be
                             placed.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
-    :param allow_double_clicks: Enables double clicking on buttons which will generate a
+    :param allow_double_clicks: Enables double-clicking on buttons which will generate a
                                 unique event.
     :param visible: Whether the element is visible by default. Warning - container visibility may
                     override this.
@@ -48,7 +49,7 @@ class UIButton(UIElement):
                         in the middle.
     """
 
-    def __init__(self, relative_rect: Union[pygame.Rect, Tuple[float, float], pygame.Vector2],
+    def __init__(self, relative_rect: Union[RectLike, Coordinate],
                  text: str,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
@@ -68,7 +69,7 @@ class UIButton(UIElement):
                  max_dynamic_width: Optional[int] = None
                  ):
 
-        rel_rect = (relative_rect if isinstance(relative_rect, pygame.Rect)
+        rel_rect = (relative_rect if len(relative_rect) == 4
                     else pygame.Rect(relative_rect, (-1, -1)))
         super().__init__(rel_rect,
                          manager, container,
@@ -213,8 +214,8 @@ class UIButton(UIElement):
         """
         Tests if a position should be considered 'hovering' the button. Normally this just means
         our mouse pointer is inside the buttons rectangle, however if we are holding onto the
-        button for a purpose(e.g. dragging a window around by it's menu bar) the hover radius can
-        be made to grow so we don't keep losing touch with whatever we are moving.
+        button for a purpose(e.g. dragging a window around by its menu bar) the hover radius can
+        be made to grow, so we don't keep losing touch with whatever we are moving.
 
         :param hover_x: horizontal pixel coordinate to test.
         :param hover_y: vertical pixel coordinate to test
@@ -317,7 +318,7 @@ class UIButton(UIElement):
 
         :param event: The event to process.
 
-        :return: Return True if we want to consume this event so it is not passed on to the
+        :return: Return True if we want to consume this event, so it is not passed on to the
                  rest of the UI.
 
         """
@@ -329,9 +330,9 @@ class UIButton(UIElement):
                 if self.is_enabled:
                     if (self.allow_double_clicks and self.last_click_button == event.button and
                             self.double_click_timer <= self.ui_manager.get_double_click_time()):
-                        self.on_self_event(UI_BUTTON_DOUBLE_CLICKED, {'mouse_button':event.button})
+                        self.on_self_event(UI_BUTTON_DOUBLE_CLICKED, {'mouse_button': event.button})
                     else:
-                        self.on_self_event(UI_BUTTON_START_PRESS, {'mouse_button':event.button})
+                        self.on_self_event(UI_BUTTON_START_PRESS, {'mouse_button': event.button})
                         self.double_click_timer = 0.0
                         self.last_click_button = event.button
                         self.held = True
@@ -349,7 +350,7 @@ class UIButton(UIElement):
                 self._set_inactive()
                 consumed_event = True
                 self.pressed_event = True
-                self.on_self_event(UI_BUTTON_PRESSED, {'mouse_button':event.button})
+                self.on_self_event(UI_BUTTON_PRESSED, {'mouse_button': event.button})
 
             if self.is_enabled and self.held:
                 self.held = False
@@ -358,7 +359,7 @@ class UIButton(UIElement):
 
         return consumed_event
     
-    def bind(self, event:int, function:Callable = None):
+    def bind(self, event: int, function: Callable = None):
         """
         Bind a function to an element event.
 
@@ -376,7 +377,7 @@ class UIButton(UIElement):
             if num_params == 1:
                 self._handler[event] = function
             elif num_params == 0:
-                self._handler[event] = lambda _:function()
+                self._handler[event] = lambda _: function()
             else:
                 raise ValueError("Command function signatures can have 0 or 1 parameter. "
                                  "If one parameter is set it will contain data for the id of the mouse button used "
@@ -384,7 +385,7 @@ class UIButton(UIElement):
         else:
             raise TypeError("Command function must be callable")
     
-    def on_self_event(self, event:int, data:Dict[str, Any]=None):
+    def on_self_event(self, event: int, data: Dict[str, Any] = None):
         """
         Called when an event is triggered by this element. Handles these events either by posting the event back
         to the event queue, or by running a function supplied by the user.
@@ -438,7 +439,7 @@ class UIButton(UIElement):
 
     def enable(self):
         """
-        Re-enables the button so we can once again interact with it.
+        Re-enables the button, so we can once again interact with it.
         """
         if not self.is_enabled:
             self.is_enabled = True
@@ -791,7 +792,7 @@ class UIButton(UIElement):
             if 'left' in self.anchors and self.anchors['left'] == 'right' and self.dynamic_width:
                 left_offset = self.dynamic_dimensions_orig_top_left[0]
                 new_left = left_offset - self.relative_rect.width
-            # if we have anchored the top side of our button to the bottom of it's container then
+            # if we have anchored the top side of our button to the bottom of its container then
             # changing the height is going to mess up the vert position as well.
             if 'top' in self.anchors and self.anchors['top'] == 'bottom' and self.dynamic_height:
                 top_offset = self.dynamic_dimensions_orig_top_left[1]
diff --git a/pygame_gui/elements/ui_drop_down_menu.py b/pygame_gui/elements/ui_drop_down_menu.py
index ffedcac..c391b06 100644
--- a/pygame_gui/elements/ui_drop_down_menu.py
+++ b/pygame_gui/elements/ui_drop_down_menu.py
@@ -12,11 +12,12 @@ from pygame_gui.core.ui_container import UIContainer
 
 from pygame_gui.elements.ui_button import UIButton
 from pygame_gui.elements.ui_selection_list import UISelectionList
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIExpandedDropDownState:
     """
-    The expanded state of the drop down  displays the currently chosen option, all the available
+    The expanded state of the drop-down  displays the currently chosen option, all the available
     options and a button to close the menu and return to the closed state.
 
     Picking an option will also close the menu.
@@ -29,8 +30,8 @@ class UIExpandedDropDownState:
     :param expand_direction: Direction of expansion, 'up' or 'down'.
     :param manager: The UI Manager for the whole UI.
     :param container: The container the element is within.
-    :param object_ids: The object IDs for the drop down UI element.
-    :param element_ids: The element IDs for the drop down UI element.
+    :param object_ids: The object IDs for the drop-down UI element.
+    :param element_ids: The element IDs for the drop-down UI element.
     """
 
     def __init__(self,
@@ -173,7 +174,7 @@ class UIExpandedDropDownState:
                 expand_button_symbol = '▼'
 
                 if self.drop_down_menu_ui.expansion_height_limit is None:
-                    height_limit = (self.drop_down_menu_ui.ui_container.relative_rect.height -
+                    height_limit = (self.drop_down_menu_ui.ui_container.get_container().get_relative_rect().height -
                                     self.base_position_rect.bottom)
                     self.drop_down_menu_ui.expansion_height_limit = height_limit
 
@@ -257,11 +258,11 @@ class UIExpandedDropDownState:
 
     def process_event(self, event: pygame.event.Event) -> bool:
         """
-        Processes events for the closed state of the drop down.
+        Processes events for the closed state of the drop-down.
 
         :param event: The event to process.
 
-        :return: Return True if we want to consume this event so it is not passed on to the
+        :return: Return True if we want to consume this event, so it is not passed on to the
                  rest of the UI.
 
         """
@@ -296,10 +297,10 @@ class UIExpandedDropDownState:
 
     def update_position(self):
         """
-        Update the position of all the button elements in the open drop down state.
+        Update the position of all the button elements in the open drop-down state.
 
-        Used when the position of the  drop down has been altered directly, rather than when it
-        has been moved as a consequence of it's container being moved.
+        Used when the position of the  drop-down has been altered directly, rather than when it
+        has been moved as a consequence of its container being moved.
         """
 
         # update the base position rect
@@ -321,9 +322,9 @@ class UIExpandedDropDownState:
 
     def update_dimensions(self):
         """
-        Update the dimensions of all the button elements in the closed drop down state.
+        Update the dimensions of all the button elements in the closed drop-down state.
 
-        Used when the dimensions of the drop down have been altered.
+        Used when the dimensions of the drop-down have been altered.
         """
 
         # update the base position rect
@@ -373,7 +374,7 @@ class UIExpandedDropDownState:
 
 class UIClosedDropDownState:
     """
-    The closed state of the drop down just displays the currently chosen option and a button that
+    The closed state of the drop-down just displays the currently chosen option and a button that
     will switch the menu to the expanded state.
 
     :param drop_down_menu_ui: The UIDropDownElement this state belongs to.
@@ -383,8 +384,8 @@ class UIClosedDropDownState:
     :param expand_direction: Direction of expansion, 'up' or 'down'.
     :param manager: The UI Manager for the whole UI.
     :param container: The container the element is within.
-    :param object_ids: The object IDs for the drop down UI element.
-    :param element_ids: The element IDs for the drop down UI element.
+    :param object_ids: The object IDs for the drop-down UI element.
+    :param element_ids: The element IDs for the drop-down UI element.
     :param visible: Whether the element is visible by default. Warning -
                     container visibility may override this.
     """
@@ -436,7 +437,7 @@ class UIClosedDropDownState:
 
     def enable(self):
         """
-        Re-enables the closed state so we can once again interact with it.
+        Re-enables the closed state, so we can once again interact with it.
         """
         if self.selected_option_button is not None:
             self.selected_option_button.enable()
@@ -547,11 +548,11 @@ class UIClosedDropDownState:
 
     def process_event(self, event: pygame.event.Event) -> bool:
         """
-        Processes events for the closed state of the drop down.
+        Processes events for the closed state of the drop-down.
 
         :param event: The event to process.
 
-        :return: Return True if we want to consume this event so it is not passed on to the
+        :return: Return True if we want to consume this event, so it is not passed on to the
                  rest of the UI.
         """
         if event.type == UI_BUTTON_PRESSED:
@@ -565,10 +566,10 @@ class UIClosedDropDownState:
 
     def update_position(self):
         """
-        Update the position of all the button elements in the closed drop down state.
+        Update the position of all the button elements in the closed drop-down state.
 
-        Used when the position of the  drop down has been altered directly, rather than when it has
-        been moved as a consequence of it's container being moved.
+        Used when the position of the  drop-down has been altered directly, rather than when it has
+        been moved as a consequence of its container being moved.
         """
 
         # update the base position rect
@@ -588,9 +589,9 @@ class UIClosedDropDownState:
 
     def update_dimensions(self):
         """
-        Update the dimensions of all the button elements in the closed drop down state.
+        Update the dimensions of all the button elements in the closed drop-down state.
 
-        Used when the dimensions of the drop down have been altered.
+        Used when the dimensions of the drop-down have been altered.
         """
 
         # update the base position rect
@@ -638,15 +639,15 @@ class UIClosedDropDownState:
 
 class UIDropDownMenu(UIContainer):
     """
-    A drop down menu lets us choose one text option from a list. That list of options can be
-    expanded and hidden at the press of a button. While the element is called a drop down,
+    A drop-down menu lets us choose one text option from a list. That list of options can be
+    expanded and hidden at the press of a button. While the element is called a drop-down,
     it can also be made to 'climb up' by changing the 'expand_direction' styling option to 'up'
     in the theme file.
 
-    The drop down is implemented through two states, one representing the 'closed' menu state
+    The drop-down is implemented through two states, one representing the 'closed' menu state
     and one for when it has been 'expanded'.
 
-    :param options_list: The list of of options to choose from. They must be strings.
+    :param options_list: The list of options to choose from. They must be strings.
     :param starting_option: The starting option, selected when the menu is first created.
     :param relative_rect: The size and position of the element when not expanded.
     :param manager: The UIManager that manages this element. If not provided or set to None,
@@ -654,13 +655,13 @@ class UIDropDownMenu(UIContainer):
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param expansion_height_limit: Limit on the height that this will expand to, defaults to the
                                    container bounds.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
-    :param expand_on_option_click: If this is set to False the drop down will only expand when
+    :param expand_on_option_click: If this is set to False the drop-down will only expand when
                                    the open/close button is pressed and not when the selected
                                    option is pressed.
     """
@@ -668,7 +669,7 @@ class UIDropDownMenu(UIContainer):
     def __init__(self,
                  options_list: Union[List[str], List[Tuple[str, str]]],
                  starting_option: Union[str, Tuple[str, str]],
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
                  parent_element: UIElement = None,
@@ -687,6 +688,7 @@ class UIDropDownMenu(UIContainer):
                          starting_height=0,
                          anchors=anchors,
                          visible=visible,
+                         parent_element=parent_element,
                          object_id=object_id,
                          element_id=['drop_down_menu'])
 
@@ -755,12 +757,13 @@ class UIDropDownMenu(UIContainer):
 
     @layer_thickness.setter
     def layer_thickness(self, value):
+        int(value)
         # ignore passed in value and hardcode to 4
         self.__layer_thickness_including_expansion = 4
 
     def add_options(self, new_options: Union[List[str], List[Tuple[str, str]]]) -> None:
         """
-        Add new options to the drop down. Will close the drop-down if it is currently open.
+        Add new options to the drop-down. Will close the drop-down if it is currently open.
 
         In many cases it may be easier just to recreate the drop-down with whatever the new options list is.
 
@@ -774,7 +777,7 @@ class UIDropDownMenu(UIContainer):
 
         self.menu_states['expanded'].options_list = self.options_list
 
-        # if we have the dropdown open, close it so it can be reopened with the new options in place
+        # if we have the dropdown open - close it, so it can be reopened with the new options in place
         self._close_dropdown_if_open()
 
     def remove_options(self, options_to_remove: Union[List[str], List[Tuple[str, str]]]) -> None:
@@ -792,7 +795,7 @@ class UIDropDownMenu(UIContainer):
         self.options_list = [option for option in self.options_list if option not in real_options_to_remove]
         self.menu_states['expanded'].options_list = self.options_list
 
-        # if we have the dropdown open, close it so it can be reopened with the new options in place
+        # if we have the dropdown open - close it, so it can be reopened with the new options in place
         self._close_dropdown_if_open()
 
     def _close_dropdown_if_open(self):
@@ -805,7 +808,7 @@ class UIDropDownMenu(UIContainer):
     def kill(self):
         """
         Overrides the standard sprite kill to also properly kill/finish the current state of the
-        drop down. Depending on whether it is expanded or closed the drop down menu will have
+        drop-down. Depending on whether it is expanded or closed the drop-down menu will have
         different elements to clean up.
         """
         self.current_state.finish()
@@ -818,7 +821,7 @@ class UIDropDownMenu(UIContainer):
 
     def update(self, time_delta: float):
         """
-        The update here deals with transitioning between the two states of the drop down menu and
+        The update here deals with transitioning between the two states of the drop-down menu and
         then passes the rest of the work onto whichever state is active.
 
         :param time_delta: The time in second between calls to update.
@@ -833,12 +836,12 @@ class UIDropDownMenu(UIContainer):
 
     def process_event(self, event: pygame.event.Event) -> bool:
         """
-        Handles various interactions with the drop down menu by passing them along to the
+        Handles various interactions with the drop-down menu by passing them along to the
         active state.
 
         :param event: The event to process.
 
-        :return: Return True if we want to consume this event so it is not passed on to the
+        :return: Return True if we want to consume this event, so it is not passed on to the
                  rest of the UI.
 
         """
@@ -850,8 +853,8 @@ class UIDropDownMenu(UIContainer):
 
     def rebuild_from_changed_theme_data(self):
         """
-        Triggers the element to rebuild if any of it's theming data has changed, which involves a
-        lot of checking and validating it's theming data.
+        Triggers the element to rebuild if any of its theming data has changed, which involves a
+        lot of checking and validating its theming data.
 
         """
         super().rebuild_from_changed_theme_data()
@@ -929,9 +932,7 @@ class UIDropDownMenu(UIContainer):
         if self.current_state is not None:
             self.current_state.rebuild()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this drop down, updating all subordinate button
         elements at the same time.
@@ -942,9 +943,7 @@ class UIDropDownMenu(UIContainer):
         super().set_position(position)
         self.current_state.update_position()
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Sets the relative screen position of this drop down, updating all subordinate button
         elements at the same time.
@@ -955,10 +954,7 @@ class UIDropDownMenu(UIContainer):
         super().set_relative_position(position)
         self.current_state.update_position()
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Sets the dimensions of this drop down, updating all subordinate button
         elements at the same time.
@@ -995,7 +991,7 @@ class UIDropDownMenu(UIContainer):
 
     def enable(self):
         """
-        Re-enables the button so we can once again interact with it.
+        Re-enables the button so, we can once again interact with it.
         """
         if not self.is_enabled:
             self.is_enabled = True
@@ -1005,7 +1001,7 @@ class UIDropDownMenu(UIContainer):
     def show(self):
         """
         In addition to the base UIElement.show() - call show() on the closed state -
-        showing it's buttons.
+        showing its buttons.
         """
         super().show()
         if self.current_state is not None and self.menu_states is not None:
@@ -1013,7 +1009,7 @@ class UIDropDownMenu(UIContainer):
 
     def hide(self):
         """
-        In addition to the base UIElement.hide() - if the current state is 'expanded' call it's
+        In addition to the base UIElement.hide() - if the current state is 'expanded' call its
         hide() method, which begins a transition of the UIDropDownMenu to the 'closed' state, and
         call the hide() method of the 'closed' state which hides all it's children widgets.
         """
diff --git a/pygame_gui/elements/ui_horizontal_scroll_bar.py b/pygame_gui/elements/ui_horizontal_scroll_bar.py
index d63375d..5718391 100644
--- a/pygame_gui/elements/ui_horizontal_scroll_bar.py
+++ b/pygame_gui/elements/ui_horizontal_scroll_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict, Optional
+from typing import Union, Dict, Optional
 
 import pygame
 
@@ -8,6 +8,7 @@ from pygame_gui.core import UIElement, UIContainer
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 
 from pygame_gui.elements.ui_button import UIButton
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIHorizontalScrollBar(UIElement):
@@ -23,14 +24,14 @@ class UIHorizontalScrollBar(UIElement):
     :param container: The container that this element is within. If set to None will be the
                       root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
     """
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  visible_percentage: float,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
@@ -507,9 +508,7 @@ class UIHorizontalScrollBar(UIElement):
         if has_any_changed:
             self.rebuild()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this scroll bar, updating all subordinate button
         elements at the same time.
@@ -525,9 +524,7 @@ class UIHorizontalScrollBar(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Sets the relative screen position of this scroll bar, updating all subordinate button
         elements at the same time.
@@ -543,10 +540,7 @@ class UIHorizontalScrollBar(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Method to directly set the dimensions of an element.
 
@@ -583,7 +577,7 @@ class UIHorizontalScrollBar(UIElement):
 
     def disable(self):
         """
-        Disables the scroll bar so it is no longer interactive.
+        Disables the scroll bar, so it is no longer interactive.
         """
         if self.is_enabled:
             self.is_enabled = False
@@ -595,7 +589,7 @@ class UIHorizontalScrollBar(UIElement):
 
     def enable(self):
         """
-        Enables the scroll bar so it is interactive once again.
+        Enables the scroll bar, so it is interactive once again.
         """
         if not self.is_enabled:
             self.is_enabled = True
diff --git a/pygame_gui/elements/ui_horizontal_slider.py b/pygame_gui/elements/ui_horizontal_slider.py
index 679b264..5b42683 100644
--- a/pygame_gui/elements/ui_horizontal_slider.py
+++ b/pygame_gui/elements/ui_horizontal_slider.py
@@ -11,6 +11,7 @@ from pygame_gui.core import UIElement, UIContainer
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 
 from pygame_gui.elements.ui_button import UIButton
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIHorizontalSlider(UIElement):
@@ -26,14 +27,14 @@ class UIHorizontalSlider(UIElement):
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
     :param click_increment: the amount to increment by when clicking one of the arrow buttons.
     """
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  start_value: Union[float, int],
                  value_range: Tuple[Union[float, int], Union[float, int]],
                  manager: Optional[IUIManagerInterface] = None,
@@ -364,7 +365,7 @@ class UIHorizontalSlider(UIElement):
         issue a warning if the value set is not in the value range.
 
         :param value: The value to set.
-        :param warn: set to false to suppress the default warning,
+        :param warn: set to 'False' to suppress the default warning,
                      instead the value will be clamped.
 
         """
@@ -458,9 +459,7 @@ class UIHorizontalSlider(UIElement):
         if has_any_changed:
             self.rebuild()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this slider, updating all subordinate button elements
         at the same time.
@@ -476,9 +475,7 @@ class UIHorizontalSlider(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Sets the relative screen position of this slider, updating all subordinate button elements
         at the same time.
@@ -494,10 +491,7 @@ class UIHorizontalSlider(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Method to directly set the dimensions of an element.
 
diff --git a/pygame_gui/elements/ui_image.py b/pygame_gui/elements/ui_image.py
index 980f8d3..19cfa04 100644
--- a/pygame_gui/elements/ui_image.py
+++ b/pygame_gui/elements/ui_image.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict, Optional
+from typing import Union, Dict, Optional
 
 import pygame
 
@@ -6,28 +6,29 @@ from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core import UIElement
 from pygame_gui.core.utility import premul_alpha_surface
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIImage(UIElement):
     """
-    Displays a pygame surface as a UI element, intended for an image but it can serve
+    Displays a pygame surface as a UI element, intended for an image, but it can serve
     other purposes.
 
     :param relative_rect: The rectangle that contains, positions and scales the image relative to
-                          it's container.
+                          its container.
     :param image_surface: A pygame surface to display.
     :param manager: The UIManager that manages this element. If not provided or set to None,
                     it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If not provided or set to None
                       will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
     """
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  image_surface: pygame.surface.Surface,
                  manager: Optional[IUIManagerInterface] = None,
                  image_is_alpha_premultiplied: bool = False,
@@ -58,10 +59,7 @@ class UIImage(UIElement):
                                             default_value=1.0,
                                             casting_func=float)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Set the dimensions of this image, scaling the image surface to match.
 
@@ -91,7 +89,7 @@ class UIImage(UIElement):
         of the UIImage element it will be scaled to fit. In this situation, an original size image is retained
         as well in case of future resizing events.
 
-        :param new_image: the new image surface to use in the UIIamge element.
+        :param new_image: the new image surface to use in the UIImage element.
         :param image_is_alpha_premultiplied: set to True if the image is already in alpha multiplied colour format.
         """
         image_surface = new_image.convert_alpha()
diff --git a/pygame_gui/elements/ui_label.py b/pygame_gui/elements/ui_label.py
index 00938fc..245646b 100644
--- a/pygame_gui/elements/ui_label.py
+++ b/pygame_gui/elements/ui_label.py
@@ -14,6 +14,7 @@ from pygame_gui._constants import UITextEffectType, TEXT_EFFECT_TYPING_APPEAR
 from pygame_gui._constants import TEXT_EFFECT_FADE_IN, TEXT_EFFECT_FADE_OUT
 from pygame_gui.core.text.text_effects import TypingAppearEffect, FadeInEffect, FadeOutEffect
 from pygame_gui.core.text import TextLineChunkFTFont
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UILabel(UIElement, IUITextOwnerInterface):
@@ -21,15 +22,17 @@ class UILabel(UIElement, IUITextOwnerInterface):
     A label lets us display a single line of text with a single font style. It's a quick to
     rebuild and simple alternative to the text box element.
 
-    :param relative_rect: The rectangle that contains and positions the label relative to it's
-                          container.
+    :param relative_rect: Normally a rectangle describing the position (relative to its container) and
+                          dimensions. Also accepts a position Coordinate where the dimensions
+                          will be dynamic depending on the text contents. Dynamic dimensions can
+                          be requested by setting the required dimension to -1.
     :param text: The text to display in the label.
     :param manager: The UIManager that manages this label. If not provided or set to None,
                     it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If not provided or set to None
                       will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
@@ -38,7 +41,7 @@ class UILabel(UIElement, IUITextOwnerInterface):
                         in the middle.
     """
 
-    def __init__(self, relative_rect: pygame.Rect,
+    def __init__(self, relative_rect: Union[RectLike, Coordinate],
                  text: str,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
@@ -49,7 +52,10 @@ class UILabel(UIElement, IUITextOwnerInterface):
                  *,
                  text_kwargs: Optional[Dict[str, str]] = None):
 
-        super().__init__(relative_rect, manager, container,
+        rel_rect = (relative_rect if len(relative_rect) == 4
+                    else pygame.Rect(relative_rect, (-1, -1)))
+
+        super().__init__(rel_rect, manager, container,
                          starting_height=1,
                          layer_thickness=1,
                          anchors=anchors,
@@ -175,7 +181,7 @@ class UILabel(UIElement, IUITextOwnerInterface):
             if 'left' in self.anchors and self.anchors['left'] == 'right' and self.dynamic_width:
                 left_offset = self.dynamic_dimensions_orig_top_left[0]
                 new_left = left_offset - self.relative_rect.width
-            # if we have anchored the top side of our button to the bottom of it's container then
+            # if we have anchored the top side of our button to the bottom of its container then
             # changing the height is going to mess up the vert position as well.
             if 'top' in self.anchors and self.anchors['top'] == 'bottom' and self.dynamic_height:
                 top_offset = self.dynamic_dimensions_orig_top_left[1]
diff --git a/pygame_gui/elements/ui_panel.py b/pygame_gui/elements/ui_panel.py
index 4938c3d..ed10686 100644
--- a/pygame_gui/elements/ui_panel.py
+++ b/pygame_gui/elements/ui_panel.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict, Tuple, Optional, Iterator
+from typing import Union, Dict, Optional, Iterator
 
 import pygame
 
@@ -9,6 +9,8 @@ from pygame_gui.core.interfaces import IContainerLikeInterface, IUIContainerInte
 from pygame_gui.core import UIElement, UIContainer
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
+
 
 class UIPanel(UIElement, IContainerLikeInterface):
     """
@@ -29,7 +31,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
                     it will try to use the first UIManager that was created by your application.
     :param margins: Controls the distance between the edge of the panel and where it's
                     container should begin.
-    :param container: The container this panel is inside of - distinct from this panel's own
+    :param container: The container this panel is inside - distinct from this panel's own
                       container.
     :param parent_element: A hierarchical 'parent' used for signifying belonging and used in
                            theming and events.
@@ -41,7 +43,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
                     may override this.
     """
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  starting_height: int = 1,
                  manager: Optional[IUIManagerInterface] = None,
                  *,
@@ -153,10 +155,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
         self.get_container().kill()
         super().kill()
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Set the size of this panel and then re-sizes and shifts the contents of the panel container
         to fit the new size.
@@ -177,9 +176,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
         if new_container_dimensions != self.get_container().get_size():
             self.get_container().set_dimensions(new_container_dimensions)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Method to directly set the relative rect position of an element.
 
@@ -189,9 +186,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
         super().set_relative_position(position)
         self.get_container().set_relative_position(self.relative_rect.topleft)
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Method to directly set the absolute screen rect position of an element.
 
@@ -276,7 +271,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
 
     def disable(self):
         """
-        Disables all elements in the panel so they are no longer interactive.
+        Disables all elements in the panel, so they are no longer interactive.
         """
         if self.is_enabled:
             self.is_enabled = False
@@ -285,7 +280,7 @@ class UIPanel(UIElement, IContainerLikeInterface):
 
     def enable(self):
         """
-        Enables all elements in the panel so they are interactive again.
+        Enables all elements in the panel, so they are interactive again.
         """
         if not self.is_enabled:
             self.is_enabled = True
diff --git a/pygame_gui/elements/ui_progress_bar.py b/pygame_gui/elements/ui_progress_bar.py
index c3113f6..10d66af 100644
--- a/pygame_gui/elements/ui_progress_bar.py
+++ b/pygame_gui/elements/ui_progress_bar.py
@@ -1,11 +1,11 @@
 from typing import Union, Dict, Optional
 
-import pygame
 
 from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core import UIElement
 from pygame_gui.elements.ui_status_bar import UIStatusBar
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIProgressBar(UIStatusBar):
@@ -18,7 +18,7 @@ class UIProgressBar(UIStatusBar):
     :param container: The container that this element is within. If not provided or set to None
                       will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
@@ -26,7 +26,7 @@ class UIProgressBar(UIStatusBar):
     element_id = 'progress_bar'
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
                  parent_element: Optional[UIElement] = None,
diff --git a/pygame_gui/elements/ui_screen_space_health_bar.py b/pygame_gui/elements/ui_screen_space_health_bar.py
index 056e43e..5575579 100644
--- a/pygame_gui/elements/ui_screen_space_health_bar.py
+++ b/pygame_gui/elements/ui_screen_space_health_bar.py
@@ -1,12 +1,12 @@
 from typing import Union, Dict, Optional
 
-import pygame
 from pygame.sprite import Sprite
 
 from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core import UIElement
 from pygame_gui.elements.ui_status_bar import UIStatusBar
+from pygame_gui.core.gui_type_hints import RectLike, SpriteWithHealth
 
 
 class UIScreenSpaceHealthBar(UIStatusBar):
@@ -21,7 +21,7 @@ class UIScreenSpaceHealthBar(UIStatusBar):
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
@@ -29,9 +29,9 @@ class UIScreenSpaceHealthBar(UIStatusBar):
     element_id = 'screen_space_health_bar'
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
-                 sprite_to_monitor: Optional[Sprite] = None,
+                 sprite_to_monitor: Optional[SpriteWithHealth] = None,
                  container: Optional[IContainerLikeInterface] = None,
                  parent_element: Optional[UIElement] = None,
                  object_id: Optional[Union[ObjectID, str]] = None,
@@ -75,7 +75,7 @@ class UIScreenSpaceHealthBar(UIStatusBar):
         # Now that we subclass UIStatusBar, this is here for backward compatibility.
         return self.health_percent()
 
-    def set_sprite_to_monitor(self, sprite_to_monitor: pygame.sprite.Sprite):
+    def set_sprite_to_monitor(self, sprite_to_monitor: Sprite):
         if sprite_to_monitor:
             if not hasattr(sprite_to_monitor, 'health_capacity'):
                 raise AttributeError('Sprite does not have health_capacity attribute')
@@ -86,4 +86,3 @@ class UIScreenSpaceHealthBar(UIStatusBar):
     def status_text(self):
         """ Subclass and override this method to change what text is displayed, or to suppress the text. """
         return f"{int(self.current_health)}/{int(self.health_capacity)}"
-
diff --git a/pygame_gui/elements/ui_scrolling_container.py b/pygame_gui/elements/ui_scrolling_container.py
index c5c1893..e531619 100644
--- a/pygame_gui/elements/ui_scrolling_container.py
+++ b/pygame_gui/elements/ui_scrolling_container.py
@@ -4,7 +4,8 @@ import pygame
 
 from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIContainerInterface
-from pygame_gui.core.interfaces import IUIManagerInterface, Coordinate, IUIElementInterface
+from pygame_gui.core.interfaces import IUIManagerInterface, IUIElementInterface
+from pygame_gui.core.gui_type_hints import Coordinate
 from pygame_gui.core import UIElement, UIContainer
 
 from pygame_gui.elements.ui_vertical_scroll_bar import UIVerticalScrollBar
diff --git a/pygame_gui/elements/ui_selection_list.py b/pygame_gui/elements/ui_selection_list.py
index f138d9e..35a1a37 100644
--- a/pygame_gui/elements/ui_selection_list.py
+++ b/pygame_gui/elements/ui_selection_list.py
@@ -14,6 +14,7 @@ from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleS
 
 from pygame_gui.elements.ui_button import UIButton
 from pygame_gui.elements.ui_vertical_scroll_bar import UIVerticalScrollBar
+from pygame_gui.core.gui_type_hints import RectLike, Coordinate
 
 
 class UISelectionList(UIElement):
@@ -32,10 +33,10 @@ class UISelectionList(UIElement):
                     it will try to use the first UIManager that was created by your application.
     :param allow_multi_select: True if we are allowed to pick multiple things from the selection
                                list.
-    :param allow_double_clicks: True if we can double click on items in the selection list.
-    :param container: The container this element is inside of (by default the root container)
+    :param allow_double_clicks: True if we can double-click on items in the selection list.
+    :param container: The container this element is inside (by default the root container)
                       distinct from this panel's container.
-    :param starting_height: The starting height up from it's container where this list is placed
+    :param starting_height: The starting height up from its container where this list is placed
                             into a layer.
     :param parent_element: A hierarchical 'parent' used for signifying belonging and used in
                            theming and events.
@@ -48,7 +49,7 @@ class UISelectionList(UIElement):
     """
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  item_list: Union[List[str], List[Tuple[str, str]]],
                  manager: Optional[IUIManagerInterface] = None,
                  *,
@@ -355,9 +356,9 @@ class UISelectionList(UIElement):
         """
         Set the default selection of the list. The default selection type must be a string or (str,
         str) tuple for single selection lists. For multi-selection lists, they can be a single
-        string, an (str, str) tuple, a list of strings, or a list of (str, str) tuples.
+        string, a (str, str) tuple, a list of strings, or a list of (str, str) tuples.
 
-        For foregivess' sake, a single-item list MAY be used to specify the default value for a
+        For ease of use, a single-item list MAY be used to specify the default value for a
         single-selection list.
 
         Tuples should be arranged like so:
@@ -497,10 +498,7 @@ class UISelectionList(UIElement):
 
         return False  # Don't consume any events
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Set the size of this panel and then resizes and shifts the contents of the panel container
         to fit the new size.
@@ -551,9 +549,7 @@ class UISelectionList(UIElement):
             self.scroll_bar.has_moved_recently = True
             self.update(0.0)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Method to directly set the relative rect position of an element.
 
@@ -566,9 +562,7 @@ class UISelectionList(UIElement):
         container_top = self.relative_rect.top + border_and_shadow
         self.list_and_scroll_bar_container.set_relative_position((container_left, container_top))
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this slider, updating all subordinate button
         elements at the same time.
@@ -695,7 +689,7 @@ class UISelectionList(UIElement):
 
     def disable(self):
         """
-        Disables all elements in the selection list so they are no longer interactive.
+        Disables all elements in the selection list, so they are no longer interactive.
         """
         if self.is_enabled:
             self.is_enabled = False
@@ -709,7 +703,7 @@ class UISelectionList(UIElement):
 
     def enable(self):
         """
-        Enables all elements in the selection list so they are interactive again.
+        Enables all elements in the selection list, so they are interactive again.
         """
         if not self.is_enabled:
             self.is_enabled = True
@@ -719,7 +713,7 @@ class UISelectionList(UIElement):
     def show(self):
         """
         In addition to the base UIElement.show() - call show() of owned container -
-        list_and_scroll_bar_container. All other subelements (item_list_container, scrollbar) are
+        list_and_scroll_bar_container. All other sub-elements (item_list_container, scrollbar) are
         children of list_and_scroll_bar_container, so it's visibility will propagate to them -
         there is no need to call their show() methods separately.
         """
@@ -730,7 +724,7 @@ class UISelectionList(UIElement):
     def hide(self):
         """
         In addition to the base UIElement.hide() - call hide() of owned container -
-        list_and_scroll_bar_container. All other subelements (item_list_container, scrollbar) are
+        list_and_scroll_bar_container. All other sub-elements (item_list_container, scrollbar) are
         children of list_and_scroll_bar_container, so it's visibility will propagate to them -
         there is no need to call their hide() methods separately.
         """
diff --git a/pygame_gui/elements/ui_status_bar.py b/pygame_gui/elements/ui_status_bar.py
index 17b45d1..2dac14f 100644
--- a/pygame_gui/elements/ui_status_bar.py
+++ b/pygame_gui/elements/ui_status_bar.py
@@ -6,13 +6,14 @@ from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core import UIElement
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
+from pygame_gui.core.gui_type_hints import RectLike, SpriteWithHealth
 
 
 class UIStatusBar(UIElement):
     """
     Displays a status/progress bar.
 
-    This is a flexible class that can be used to display status for a sprite (health/mana/fatigue, etc),
+    This is a flexible class that can be used to display status for a sprite (health/mana/fatigue, etc.),
     or to provide a status bar on the screen not attached to any particular object. You can use multiple
     status bars for a sprite to show different status items if desired.
 
@@ -32,7 +33,7 @@ class UIStatusBar(UIElement):
                     it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If set to None will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
@@ -41,9 +42,9 @@ class UIStatusBar(UIElement):
     element_id = 'status_bar'
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
-                 sprite: Union[pygame.sprite.Sprite, None] = None,
+                 sprite: Optional[SpriteWithHealth] = None,
                  follow_sprite: bool = True,
                  percent_method: Union[Callable[[], float], None] = None,
                  container: Union[IContainerLikeInterface, None] = None,
@@ -61,7 +62,7 @@ class UIStatusBar(UIElement):
                          object_id=object_id,
                          element_id=[self.element_id])
 
-        self.sprite = sprite
+        self.sprite: SpriteWithHealth = sprite
         self.follow_sprite = follow_sprite
         self.follow_sprite_offset = (0, 0)
 
diff --git a/pygame_gui/elements/ui_tab_container.py b/pygame_gui/elements/ui_tab_container.py
index b3932ba..1e1ced1 100644
--- a/pygame_gui/elements/ui_tab_container.py
+++ b/pygame_gui/elements/ui_tab_container.py
@@ -1,11 +1,12 @@
-from typing import List, Dict, Optional, Union, Tuple
+from typing import List, Dict, Optional, Union
 
 import pygame
 
-from pygame_gui.core.interfaces import (Coordinate, IContainerLikeInterface,
+from pygame_gui.core.interfaces import (IContainerLikeInterface,
                                         IUIManagerInterface, IUIElementInterface)
 from pygame_gui._constants import UI_BUTTON_PRESSED
 from pygame_gui.core import UIElement, UIContainer, ObjectID
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 from pygame_gui.elements import UIButton, UIPanel
 
 
@@ -30,7 +31,7 @@ class UITabContainer(UIElement):
                     override this.
     """
 
-    def __init__(self, relative_rect: Union[pygame.Rect, Tuple[int, int, int, int]],
+    def __init__(self, relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
                  *,
diff --git a/pygame_gui/elements/ui_text_box.py b/pygame_gui/elements/ui_text_box.py
index 0d106f2..9a70acc 100644
--- a/pygame_gui/elements/ui_text_box.py
+++ b/pygame_gui/elements/ui_text_box.py
@@ -33,6 +33,7 @@ from pygame_gui.core.text.text_box_layout import TextBoxLayout
 from pygame_gui.core.text.text_line_chunk import TextLineChunkFTFont
 from pygame_gui.core.text.text_effects import TextEffect, TypingAppearEffect, FadeInEffect, FadeOutEffect
 from pygame_gui.core.text.text_effects import BounceEffect, TiltEffect, ExpandContractEffect, ShakeEffect
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UITextBox(UIElement, IUITextOwnerInterface):
@@ -98,7 +99,7 @@ class UITextBox(UIElement, IUITextOwnerInterface):
 
     def __init__(self,
                  html_text: str,
-                 relative_rect: Union[pygame.Rect, Tuple[int, int, int, int]],
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  wrap_to_height: bool = False,
                  starting_height: int = 1,
@@ -117,7 +118,7 @@ class UITextBox(UIElement, IUITextOwnerInterface):
         # Need to move some declarations early as they are indirectly referenced via the ui element
         # constructor
         self.scroll_bar = None
-        relative_rect.height = -1 if wrap_to_height else relative_rect.height
+        relative_rect[3] = -1 if wrap_to_height else relative_rect[3]
         super().__init__(relative_rect, manager, container,
                          starting_height=starting_height,
                          layer_thickness=2,
@@ -583,9 +584,7 @@ class UITextBox(UIElement, IUITextOwnerInterface):
         self.background_surf = self.drawable_shape.get_fresh_surface()
         self.redraw_from_text_block()
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Sets the relative screen position of this text box, updating its subordinate scroll bar at
         the same time.
@@ -602,9 +601,7 @@ class UITextBox(UIElement, IUITextOwnerInterface):
                                    self.shadow_width)
             self.scroll_bar.set_relative_position(scroll_bar_position)
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this text box, updating its subordinate scroll bar
         at the same time.
@@ -621,10 +618,7 @@ class UITextBox(UIElement, IUITextOwnerInterface):
                                    self.shadow_width)
             self.scroll_bar.set_relative_position(scroll_bar_position)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Method to directly set the dimensions of a text box.
 
diff --git a/pygame_gui/elements/ui_text_entry_box.py b/pygame_gui/elements/ui_text_entry_box.py
index 695f576..6500e66 100644
--- a/pygame_gui/elements/ui_text_entry_box.py
+++ b/pygame_gui/elements/ui_text_entry_box.py
@@ -1,8 +1,8 @@
-from typing import Union, Tuple, Dict, Optional
+from typing import Union, Dict, Optional
 
 from pygame_gui.core.utility import clipboard_paste, clipboard_copy
 
-from pygame import Rect, KEYDOWN, TEXTINPUT
+from pygame import KEYDOWN, TEXTINPUT
 from pygame import KMOD_META, KMOD_CTRL, KMOD_ALT, K_x, K_v
 from pygame import K_BACKSPACE, K_DELETE, K_RETURN
 from pygame import key
@@ -12,6 +12,7 @@ from pygame_gui.core import ObjectID
 from pygame_gui.core.ui_element import UIElement
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.elements.ui_text_box import UITextBox
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UITextEntryBox(UITextBox):
@@ -34,7 +35,7 @@ class UITextEntryBox(UITextBox):
     """
 
     def __init__(self,
-                 relative_rect: Union[Rect, Tuple[int, int, int, int]],
+                 relative_rect: RectLike,
                  initial_text: str = "",
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
diff --git a/pygame_gui/elements/ui_text_entry_line.py b/pygame_gui/elements/ui_text_entry_line.py
index b92d6f9..eb5f6b5 100644
--- a/pygame_gui/elements/ui_text_entry_line.py
+++ b/pygame_gui/elements/ui_text_entry_line.py
@@ -1,7 +1,7 @@
 import re
 import warnings
 
-from typing import Union, List, Dict, Optional, Tuple
+from typing import Union, List, Dict, Optional
 
 import pygame
 from pygame import KMOD_META, KMOD_CTRL, KMOD_ALT, K_a, K_x, K_c
@@ -17,6 +17,7 @@ from pygame_gui.core.utility import clipboard_paste, clipboard_copy, translate
 
 from pygame_gui.core import UIElement
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UITextEntryLine(UIElement):
@@ -69,7 +70,7 @@ class UITextEntryLine(UIElement):
                                         _number_character_set['en'])}
 
     def __init__(self,
-                 relative_rect: Union[pygame.Rect, Tuple[int, int, int, int]],
+                 relative_rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
                  parent_element: Optional[UIElement] = None,
diff --git a/pygame_gui/elements/ui_tool_tip.py b/pygame_gui/elements/ui_tool_tip.py
index 8946429..0916bd7 100644
--- a/pygame_gui/elements/ui_tool_tip.py
+++ b/pygame_gui/elements/ui_tool_tip.py
@@ -9,6 +9,7 @@ from pygame_gui.core.interfaces import IUIManagerInterface, IUITooltipInterface,
 from pygame_gui.core.ui_element import UIElement
 
 from pygame_gui.elements.ui_text_box import UITextBox
+from pygame_gui.core.gui_type_hints import Coordinate
 
 
 class UITooltip(UIElement, IUITooltipInterface):
@@ -28,7 +29,7 @@ class UITooltip(UIElement, IUITooltipInterface):
     :param manager: The UIManager that manages this element. If not provided or set to None,
                     it will try to use the first UIManager that was created by your application.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param text_kwargs: a dictionary of variable arguments to pass to the translated text
                         useful when you have multiple translations that need variables inserted
@@ -98,7 +99,7 @@ class UITooltip(UIElement, IUITooltipInterface):
         self.text_block.kill()
         super().kill()
 
-    def find_valid_position(self, position: pygame.math.Vector2) -> bool:
+    def find_valid_position(self, position: Coordinate) -> bool:
         """
         Finds a valid position for the tool tip inside the root container of the UI.
 
@@ -107,7 +108,7 @@ class UITooltip(UIElement, IUITooltipInterface):
         the left and to the right, until we find a position that fits the whole tooltip rectangle
         on the screen at once.
 
-        If we fail to manage this then the method will return False. Otherwise it returns True and
+        If we fail to manage this then the method will return False. Otherwise, it returns True and
         set the position of the tool tip to our valid position.
 
         :param position: A 2D vector representing the position of the target this tool tip is for.
@@ -119,8 +120,8 @@ class UITooltip(UIElement, IUITooltipInterface):
         window_rect = self.ui_manager.get_root_container().get_rect()
 
         if window_rect.contains(pygame.Rect(int(position[0]), int(position[1]), 1, 1)):
-            self.rect.left = int(position.x)
-            self.rect.top = int(position.y + self.hover_distance_from_target[1])
+            self.rect.left = int(position[0])
+            self.rect.top = int(position[1] + self.hover_distance_from_target[1])
 
             if window_rect.contains(self.rect):
                 self.relative_rect = self.rect.copy()
@@ -128,7 +129,7 @@ class UITooltip(UIElement, IUITooltipInterface):
                 return True
             else:
                 if self.rect.bottom > window_rect.bottom:
-                    self.rect.bottom = int(position.y - self.hover_distance_from_target[1])
+                    self.rect.bottom = int(position[0] - self.hover_distance_from_target[1])
                 if self.rect.right > window_rect.right:
                     self.rect.right = window_rect.right - self.hover_distance_from_target[0]
                 if self.rect.left < window_rect.left:
@@ -167,11 +168,9 @@ class UITooltip(UIElement, IUITooltipInterface):
         if has_any_changed:
             self.rebuild()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
-        Sets the absolute screen position of this tool tip, updating it's subordinate text box at
+        Sets the absolute screen position of this tool tip, updating its subordinate text box at
         the same time.
 
         :param position: The absolute screen position to set.
@@ -180,11 +179,9 @@ class UITooltip(UIElement, IUITooltipInterface):
         super().set_position(position)
         self.text_block.set_position(position)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
-        Sets the relative screen position of this tool tip, updating it's subordinate text box at
+        Sets the relative screen position of this tool tip, updating its subordinate text box at
         the same time.
 
         :param position: The relative screen position to set.
@@ -193,10 +190,7 @@ class UITooltip(UIElement, IUITooltipInterface):
         super().set_relative_position(position)
         self.text_block.set_relative_position(position)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Directly sets the dimensions of this tool tip. This will overwrite the normal theming.
 
diff --git a/pygame_gui/elements/ui_vertical_scroll_bar.py b/pygame_gui/elements/ui_vertical_scroll_bar.py
index d971ef9..09aa554 100644
--- a/pygame_gui/elements/ui_vertical_scroll_bar.py
+++ b/pygame_gui/elements/ui_vertical_scroll_bar.py
@@ -8,6 +8,7 @@ from pygame_gui.core import UIElement, UIContainer
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 
 from pygame_gui.elements.ui_button import UIButton
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 
 
 class UIVerticalScrollBar(UIElement):
@@ -30,7 +31,7 @@ class UIVerticalScrollBar(UIElement):
     """
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  visible_percentage: float,
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
@@ -503,9 +504,7 @@ class UIVerticalScrollBar(UIElement):
         if has_any_changed:
             self.rebuild()
 
-    def set_position(self, position: Union[pygame.math.Vector2,
-                                           Tuple[int, int],
-                                           Tuple[float, float]]):
+    def set_position(self, position: Coordinate):
         """
         Sets the absolute screen position of this scroll bar, updating all subordinate button
         elements at the same time.
@@ -521,9 +520,7 @@ class UIVerticalScrollBar(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_relative_position(self, position: Union[pygame.math.Vector2,
-                                                    Tuple[int, int],
-                                                    Tuple[float, float]]):
+    def set_relative_position(self, position: Coordinate):
         """
         Sets the relative screen position of this scroll bar, updating all subordinate button
         elements at the same time.
@@ -539,10 +536,7 @@ class UIVerticalScrollBar(UIElement):
 
         self.button_container.set_relative_position(self.background_rect.topleft)
 
-    def set_dimensions(self, dimensions: Union[pygame.math.Vector2,
-                                               Tuple[int, int],
-                                               Tuple[float, float]],
-                       clamp_to_container: bool = False):
+    def set_dimensions(self, dimensions: Coordinate, clamp_to_container: bool = False):
         """
         Method to directly set the dimensions of an element.
 
diff --git a/pygame_gui/elements/ui_window.py b/pygame_gui/elements/ui_window.py
index 6a2d344..b26280d 100644
--- a/pygame_gui/elements/ui_window.py
+++ b/pygame_gui/elements/ui_window.py
@@ -6,9 +6,10 @@ from pygame_gui._constants import UI_WINDOW_CLOSE, UI_WINDOW_MOVED_TO_FRONT, UI_
 from pygame_gui._constants import OldType
 
 from pygame_gui.core import ObjectID
-from pygame_gui.core.interfaces import IContainerLikeInterface, IUIContainerInterface, Coordinate
+from pygame_gui.core.interfaces import IContainerLikeInterface, IUIContainerInterface
 from pygame_gui.core.interfaces import IWindowInterface, IUIManagerInterface, IUIElementInterface
 from pygame_gui.core import UIElement, UIContainer
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 from pygame_gui.core.drawable_shapes import RectDrawableShape, RoundedRectangleShape
 
 from pygame_gui.elements.ui_button import UIButton
@@ -34,14 +35,16 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
     """
 
     def __init__(self,
-                 rect: pygame.Rect,
+                 rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  window_display_title: str = "",
                  element_id: Union[List[str], str, None] = None,
                  object_id: Optional[Union[ObjectID, str]] = None,
                  resizable: bool = False,
                  visible: int = 1,
-                 draggable: bool = True):
+                 draggable: bool = True,
+                 *,
+                 ignore_shadow_for_initial_size_and_pos: bool = True):
 
         self.window_display_title = window_display_title
         self._window_root_container = None  # type: Optional[UIContainer]
@@ -61,7 +64,8 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
                          layer_thickness=1,
                          visible=visible,
                          object_id=object_id,
-                         element_id=element_ids)
+                         element_id=element_ids,
+                         ignore_shadow_for_initial_size_and_pos=ignore_shadow_for_initial_size_and_pos)
 
         self.minimum_dimensions = (100, 100)
 
diff --git a/pygame_gui/elements/ui_world_space_health_bar.py b/pygame_gui/elements/ui_world_space_health_bar.py
index 9baeb51..eecc983 100644
--- a/pygame_gui/elements/ui_world_space_health_bar.py
+++ b/pygame_gui/elements/ui_world_space_health_bar.py
@@ -6,6 +6,7 @@ from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
 from pygame_gui.core import UIElement
 from pygame_gui.elements.ui_status_bar import UIStatusBar
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIWorldSpaceHealthBar(UIStatusBar):
@@ -23,7 +24,7 @@ class UIWorldSpaceHealthBar(UIStatusBar):
     :param container: The container that this element is within. If not provided or set to None
                       will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
-    :param object_id: A custom defined ID for fine tuning of theming.
+    :param object_id: A custom defined ID for fine-tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
@@ -45,7 +46,7 @@ class UIWorldSpaceHealthBar(UIStatusBar):
     element_id = 'world_space_health_bar'
 
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  sprite_to_monitor: Union[pygame.sprite.Sprite, ExampleHealthSprite],
                  manager: Optional[IUIManagerInterface] = None,
                  container: Optional[IContainerLikeInterface] = None,
diff --git a/pygame_gui/windows/ui_colour_picker_dialog.py b/pygame_gui/windows/ui_colour_picker_dialog.py
index 9175203..a6b6257 100644
--- a/pygame_gui/windows/ui_colour_picker_dialog.py
+++ b/pygame_gui/windows/ui_colour_picker_dialog.py
@@ -7,7 +7,8 @@ from pygame_gui._constants import UI_BUTTON_PRESSED, UI_HORIZONTAL_SLIDER_MOVED
 from pygame_gui._constants import UI_COLOUR_PICKER_COLOUR_PICKED, UI_TEXT_ENTRY_FINISHED, UI_2D_SLIDER_MOVED
 from pygame_gui._constants import UI_COLOUR_PICKER_COLOUR_CHANNEL_CHANGED, OldType
 
-from pygame_gui.core.interfaces import IUIManagerInterface, IContainerLikeInterface, Coordinate
+from pygame_gui.core.interfaces import IUIManagerInterface, IContainerLikeInterface
+from pygame_gui.core.gui_type_hints import Coordinate, RectLike
 from pygame_gui.core import UIElement, UIContainer, ObjectID
 
 from pygame_gui.elements import UIWindow, UIButton, UIImage
@@ -41,7 +42,7 @@ class UIColourChannelEditor(UIElement):
                     may override this.
     """
     def __init__(self,
-                 relative_rect: pygame.Rect,
+                 relative_rect: RectLike,
                  name: str,
                  channel_index: int,
                  value_range: Tuple[int, int],
@@ -73,7 +74,7 @@ class UIColourChannelEditor(UIElement):
 
         self._set_image(self.ui_manager.get_universal_empty_surface())
 
-        self.element_container = UIContainer(relative_rect,
+        self.element_container = UIContainer(self.relative_rect,
                                              self.ui_manager,
                                              container=self.ui_container,
                                              parent_element=self,
@@ -304,7 +305,7 @@ class UIColourPickerDialog(UIWindow):
                       '#colour_picker_dialog'
     :param visible: Whether the element is visible by default.
     """
-    def __init__(self, rect: pygame.Rect,
+    def __init__(self, rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  *,
                  initial_colour: pygame.Color = pygame.Color(0, 0, 0, 255),
@@ -320,8 +321,8 @@ class UIColourPickerDialog(UIWindow):
                          visible=visible)
 
         minimum_dimensions = (390, 390)
-        if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]:
-            warn_string = ("Initial size: " + str(rect.size) +
+        if self.relative_rect.width < minimum_dimensions[0] or self.relative_rect.height < minimum_dimensions[1]:
+            warn_string = ("Initial size: " + str(self.relative_rect.size) +
                            " is less than minimum dimensions: " + str(minimum_dimensions))
             warnings.warn(warn_string, UserWarning)
         self.set_minimum_dimensions(minimum_dimensions)
diff --git a/pygame_gui/windows/ui_confirmation_dialog.py b/pygame_gui/windows/ui_confirmation_dialog.py
index 9ad1e6d..fcf06e7 100644
--- a/pygame_gui/windows/ui_confirmation_dialog.py
+++ b/pygame_gui/windows/ui_confirmation_dialog.py
@@ -7,6 +7,7 @@ from pygame_gui.core import ObjectID
 from pygame_gui._constants import UI_CONFIRMATION_DIALOG_CONFIRMED, UI_BUTTON_PRESSED, OldType
 from pygame_gui.core.interfaces import IUIManagerInterface
 from pygame_gui.elements import UIWindow, UIButton, UITextBox
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIConfirmationDialog(UIWindow):
@@ -33,7 +34,7 @@ class UIConfirmationDialog(UIWindow):
                                          in the middle.
     """
 
-    def __init__(self, rect: pygame.Rect,
+    def __init__(self, rect: RectLike,
                  action_long_desc: str,
                  manager: Optional[IUIManagerInterface] = None,
                  *,
@@ -53,8 +54,8 @@ class UIConfirmationDialog(UIWindow):
                          visible=visible)
 
         minimum_dimensions = (260, 200)
-        if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]:
-            warn_string = ("Initial size: " + str(rect.size) +
+        if self.relative_rect.width < minimum_dimensions[0] or self.relative_rect.height < minimum_dimensions[1]:
+            warn_string = ("Initial size: " + str(self.relative_rect.size) +
                            " is less than minimum dimensions: " + str(minimum_dimensions))
             warnings.warn(warn_string, UserWarning)
         self.set_minimum_dimensions(minimum_dimensions)
diff --git a/pygame_gui/windows/ui_console_window.py b/pygame_gui/windows/ui_console_window.py
index dedb4fd..f7aa879 100644
--- a/pygame_gui/windows/ui_console_window.py
+++ b/pygame_gui/windows/ui_console_window.py
@@ -8,6 +8,7 @@ from pygame_gui.core.interfaces import IUIManagerInterface
 from pygame_gui.elements import UIWindow, UITextBox, UITextEntryLine
 from pygame_gui._constants import UI_TEXT_ENTRY_FINISHED, UI_TEXT_ENTRY_CHANGED
 from pygame_gui._constants import UI_CONSOLE_COMMAND_ENTERED
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIConsoleWindow(UIWindow):
@@ -29,7 +30,7 @@ class UIConsoleWindow(UIWindow):
     :param visible: Whether the element is visible by default.
     """
     def __init__(self,
-                 rect: pygame.Rect,
+                 rect: RectLike,
                  manager: Optional[IUIManagerInterface] = None,
                  window_title: str = 'pygame-gui.console_title_bar',
                  object_id: Union[ObjectID, str] = ObjectID('#console_window', None),
diff --git a/pygame_gui/windows/ui_file_dialog.py b/pygame_gui/windows/ui_file_dialog.py
index 1a749f1..e115288 100644
--- a/pygame_gui/windows/ui_file_dialog.py
+++ b/pygame_gui/windows/ui_file_dialog.py
@@ -17,6 +17,7 @@ from pygame_gui._constants import UI_CONFIRMATION_DIALOG_CONFIRMED, UI_FILE_DIAL
 from pygame_gui.core.interfaces import IUIManagerInterface
 from pygame_gui.elements import UIWindow, UIButton, UITextEntryLine, UISelectionList
 from pygame_gui.windows.ui_confirmation_dialog import UIConfirmationDialog
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIFileDialog(UIWindow):
@@ -36,7 +37,7 @@ class UIFileDialog(UIWindow):
     """
 
     def __init__(self,
-                 rect: pygame.Rect,
+                 rect: RectLike,
                  manager: Optional[IUIManagerInterface],
                  window_title: str = 'pygame-gui.file_dialog_title_bar',
                  allowed_suffixes: Optional[Set[str]] = None,
@@ -57,8 +58,8 @@ class UIFileDialog(UIWindow):
         locale.setlocale(locale.LC_ALL, "")
 
         minimum_dimensions = (260, 300)
-        if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]:
-            warn_string = ("Initial size: " + str(rect.size) +
+        if self.relative_rect.width < minimum_dimensions[0] or self.relative_rect.height < minimum_dimensions[1]:
+            warn_string = ("Initial size: " + str(self.relative_rect.size) +
                            " is less than minimum dimensions: " + str(minimum_dimensions))
             warnings.warn(warn_string, UserWarning)
         self.set_minimum_dimensions(minimum_dimensions)
diff --git a/pygame_gui/windows/ui_message_window.py b/pygame_gui/windows/ui_message_window.py
index 041a67f..a373de1 100644
--- a/pygame_gui/windows/ui_message_window.py
+++ b/pygame_gui/windows/ui_message_window.py
@@ -7,6 +7,7 @@ from pygame_gui.core import ObjectID
 from pygame_gui._constants import UI_BUTTON_PRESSED
 from pygame_gui.core.interfaces import IUIManagerInterface
 from pygame_gui.elements import UIButton, UITextBox, UIWindow
+from pygame_gui.core.gui_type_hints import RectLike
 
 
 class UIMessageWindow(UIWindow):
@@ -21,7 +22,7 @@ class UIMessageWindow(UIWindow):
     :param object_id: A custom defined ID for fine-tuning of theming. Defaults to '#message_window'.
     :param visible: Whether the element is visible by default.
     """
-    def __init__(self, rect: pygame.Rect,
+    def __init__(self, rect: RectLike,
                  html_message: str,
                  manager: Optional[IUIManagerInterface] = None,
                  *,
@@ -38,8 +39,8 @@ class UIMessageWindow(UIWindow):
                          visible=visible)
 
         minimum_dimensions = (250, 160)
-        if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]:
-            warn_string = ("Initial size: " + str(rect.size) +
+        if self.relative_rect.width < minimum_dimensions[0] or self.relative_rect.height < minimum_dimensions[1]:
+            warn_string = ("Initial size: " + str(self.relative_rect.size) +
                            " is less than minimum dimensions: " + str(minimum_dimensions))
             warnings.warn(warn_string, UserWarning)
         self.set_minimum_dimensions(minimum_dimensions)


Test patch:
diff --git a/tests/test_elements/test_ui_window.py b/tests/test_elements/test_ui_window.py
index 4dcefeb..42ce3c9 100644
--- a/tests/test_elements/test_ui_window.py
+++ b/tests/test_elements/test_ui_window.py
@@ -56,11 +56,13 @@ class TestUIWindow:
         window.set_minimum_dimensions((200, 200))
         window.set_dimensions((100, 100))
 
-        assert window.rect.size == (200, 200)
+        assert window.rect.size == (200,
+                                    200)
 
         window.set_minimum_dimensions((250, 250))
 
-        assert window.rect.size == (250, 250)
+        assert window.rect.size == (250,
+                                    250)
 
     def test_set_dimensions(self, _init_pygame, default_ui_manager: IUIManagerInterface,
                             _display_surface_return_none):
@@ -81,13 +83,13 @@ class TestUIWindow:
 
         assert button.rect.topright == (window.get_container().rect.right - 10,
                                         window.get_container().rect.top + 10)
-        assert button.rect.topright == (374, 253)
+        assert button.rect.topright == (389, 238)
 
         window.set_dimensions((300, 400))
 
         assert button.rect.topright == (window.get_container().rect.right - 10,
                                         window.get_container().rect.top + 10)
-        assert button.rect.topright == (474, 253)
+        assert button.rect.topright == (459, 238)
         
         confirm_event_fired = False
         event_object_id = None
@@ -122,9 +124,9 @@ class TestUIWindow:
                                    'top': 'top',
                                    'bottom': 'top'})
 
-        assert button.rect.topright == (374, 253)
+        assert button.rect.topright == (389, 238)
         window.set_relative_position((100, 100))
-        assert button.rect.topright == (274, 153)
+        assert button.rect.topright == (304, 153)
 
     def test_set_position(self, _init_pygame, default_ui_manager: IUIManagerInterface,
                           _display_surface_return_none):
@@ -143,9 +145,9 @@ class TestUIWindow:
                                    'top': 'top',
                                    'bottom': 'top'})
 
-        assert button.rect.topright == (374, 253)
+        assert button.rect.topright == (389, 238)
         window.set_position((100, 100))
-        assert button.rect.topright == (274, 153)
+        assert button.rect.topright == (304, 153)
 
     def test_process_event(self, _init_pygame, default_ui_manager,
                            _display_surface_return_none: None):
@@ -262,7 +264,7 @@ class TestUIWindow:
         default_ui_manager.mouse_position = (150, 10)
         window.update(time_delta=0.05)
 
-        assert window.get_relative_rect().topleft == (50, 0)
+        assert window.get_relative_rect().topleft == (35, -15)
 
         window = UIWindow(pygame.Rect(0, 0, 200, 200), window_display_title="Test Window",
                           manager=default_ui_manager, draggable=False)
@@ -273,7 +275,7 @@ class TestUIWindow:
         default_ui_manager.mouse_position = (150, 10)
         window.update(time_delta=0.05)
 
-        assert window.get_relative_rect().topleft == (0, 0)
+        assert window.get_relative_rect().topleft == (-15, -15)
 
     def test_check_hover(self, _init_pygame, default_ui_manager: UIManager,
                          _display_surface_return_none: None):
@@ -646,14 +648,15 @@ class TestUIWindow:
         assert window.get_relative_mouse_pos() is None
 
         default_ui_manager.mouse_position = (200, 200)
-        assert window.get_relative_mouse_pos() == (84, 57)
+        assert window.get_relative_mouse_pos() == (99, 72)
 
     def test_drag_resizing(self, _init_pygame, default_ui_manager,
                            _display_surface_return_none):
         window = UIWindow(pygame.Rect(0, 0, 101, 101),
                           window_display_title="Test Window",
                           manager=default_ui_manager,
-                          visible=0)
+                          visible=0,
+                          ignore_shadow_for_initial_size_and_pos=False)
 
         window.start_resize_point = (50, 101)
         window.start_resize_rect = window.rect.copy()
diff --git a/tests/test_windows/test_ui_file_dialog.py b/tests/test_windows/test_ui_file_dialog.py
index 78c5a0a..abdbe9c 100644
--- a/tests/test_windows/test_ui_file_dialog.py
+++ b/tests/test_windows/test_ui_file_dialog.py
@@ -84,7 +84,7 @@ class TestUIUIFileDialog:
 
     def test_press_ok_button(self, _init_pygame, default_ui_manager,
                              _display_surface_return_none):
-        file_dialog = UIFileDialog(rect=pygame.Rect(100, 100, 440, 500),
+        file_dialog = UIFileDialog(rect=(100, 100, 440, 500),
                                    manager=default_ui_manager)
 
         file_dialog.current_file_path = Path('tests/data/images/splat.png').absolute()