Utilities¶
morphui.utils.helpers
¶
Helper utilities for MorphUI components
FrozenGeometry(x=0.0, y=0.0, width=0.0, height=0.0)
dataclass
¶
Immutable snapshot of widget geometry for reference operations.
This dataclass captures and freezes the geometric properties of a widget at a specific point in time. It's particularly useful for resize operations, drag-and-drop, animation starting points, and other scenarios where you need to preserve the original state of a widget's dimensions and position.
The frozen nature ensures that the captured geometry cannot be accidentally modified, providing a reliable reference point for calculations and transformations.
| ATTRIBUTE | DESCRIPTION |
|---|---|
x |
The x-coordinate of the widget's left edge in pixels.
TYPE:
|
y |
The y-coordinate of the widget's bottom edge in pixels.
TYPE:
|
width |
The width of the widget in pixels.
TYPE:
|
height |
The height of the widget in pixels.
TYPE:
|
Properties
pos : Tuple[float, float] The position as a (x, y) tuple. size : Tuple[float, float] The size as a (width, height) tuple. center : Tuple[float, float] The center point as a (center_x, center_y) tuple. right : float The x-coordinate of the widget's right edge. top : float The y-coordinate of the widget's top edge. area : float The total area of the widget (width * height). aspect_ratio : float The width-to-height ratio.
Examples:
Capture widget geometry for resize reference:
# Before starting resize operation
original_geometry = FrozenGeometry.from_widget(widget)
# During resize, calculate relative changes
width_change = new_width - original_geometry.width
height_change = new_height - original_geometry.height
Store geometry for animation:
start_geometry = FrozenGeometry.from_widget(widget)
end_geometry = FrozenGeometry(x=100, y=100, width=200, height=150)
# Animate between the two states
animate_geometry_transition(widget, start_geometry, end_geometry)
Calculate relative positioning:
container_geometry = FrozenGeometry.from_widget(container)
child_geometry = FrozenGeometry.from_widget(child)
# Calculate child position relative to container
relative_x = child_geometry.x - container_geometry.x
relative_y = child_geometry.y - container_geometry.y
x = 0.0
class-attribute
instance-attribute
¶
The x-coordinate of the widget's left edge in pixels.
y = 0.0
class-attribute
instance-attribute
¶
The y-coordinate of the widget's bottom edge in pixels.
width = 0.0
class-attribute
instance-attribute
¶
The width of the widget in pixels.
height = 0.0
class-attribute
instance-attribute
¶
The height of the widget in pixels.
pos
property
¶
The position of the widget as a (x, y) tuple.
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
The position coordinates (x, y). |
size
property
¶
The size of the widget as a (width, height) tuple.
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
The size dimensions (width, height). |
center
property
¶
The center point of the widget as a (center_x, center_y) tuple.
Calculates the center coordinates based on position and size.
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
The center coordinates (center_x, center_y). |
right
property
¶
The x-coordinate of the widget's right edge.
| RETURNS | DESCRIPTION |
|---|---|
float
|
The x-coordinate of the right edge (x + width). |
top
property
¶
The y-coordinate of the widget's top edge.
| RETURNS | DESCRIPTION |
|---|---|
float
|
The y-coordinate of the top edge (y + height). |
area
property
¶
The total area of the widget.
| RETURNS | DESCRIPTION |
|---|---|
float
|
The area in square pixels (width * height). |
aspect_ratio
property
¶
The aspect ratio of the widget (width divided by height).
| RETURNS | DESCRIPTION |
|---|---|
float
|
The aspect ratio. Returns 1.0 if height is zero to avoid division by zero. |
from_widget(widget)
classmethod
¶
Create a FrozenGeometry instance from a Kivy widget.
This convenience method extracts the current geometry from any Kivy widget and creates an immutable snapshot. It's the recommended way to capture widget geometry for operations that need a reference point.
| PARAMETER | DESCRIPTION |
|---|---|
widget
|
Any Kivy widget with pos and size properties.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
FrozenGeometry
|
An immutable geometry snapshot of the widget. |
Examples:
point_delta(x, y)
¶
Calculate the delta from a point to this geometry's position.
This method computes how far a given point is from the widget's bottom-left corner (its position). It returns the horizontal and vertical differences as a tuple.
| PARAMETER | DESCRIPTION |
|---|---|
x
|
The x-coordinate of the point.
TYPE:
|
y
|
The y-coordinate of the point.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
A tuple (dx, dy) representing the difference in x and y coordinates from the point to the widget's position. |
Examples:
Calculate how far a mouse click is from the widget's origin:
scaled(scale_factor)
¶
Create a new geometry with scaled dimensions.
Creates a new FrozenGeometry instance with the size scaled by the given factor. The position remains unchanged, so the widget scales from its bottom-left corner.
| PARAMETER | DESCRIPTION |
|---|---|
scale_factor
|
The scaling factor. 1.0 = no change, 2.0 = double size, 0.5 = half size.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
FrozenGeometry
|
A new geometry with scaled dimensions. |
Examples:
translated(dx, dy)
¶
Create a new geometry with translated position.
Creates a new FrozenGeometry instance with the position offset by the given deltas. The size remains unchanged.
| PARAMETER | DESCRIPTION |
|---|---|
dx
|
The horizontal offset to apply.
TYPE:
|
dy
|
The vertical offset to apply.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
FrozenGeometry
|
A new geometry with translated position. |
Examples:
resized(new_width, new_height)
¶
Create a new geometry with different dimensions.
Creates a new FrozenGeometry instance with the specified size. The position remains unchanged.
| PARAMETER | DESCRIPTION |
|---|---|
new_width
|
The new width.
TYPE:
|
new_height
|
The new height.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
FrozenGeometry
|
A new geometry with the specified dimensions. |
Examples:
collide_point(x, y)
¶
Check if a point is within this geometry's bounds.
| PARAMETER | DESCRIPTION |
|---|---|
x
|
The x-coordinate to check.
TYPE:
|
y
|
The y-coordinate to check.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the point is within the bounds, False otherwise. |
Examples:
distance_to_point(x, y)
¶
Calculate the minimum distance from a point to this geometry.
If the point is inside the geometry, returns 0. Otherwise, returns the distance to the nearest edge or corner.
| PARAMETER | DESCRIPTION |
|---|---|
x
|
The x-coordinate of the point.
TYPE:
|
y
|
The y-coordinate of the point.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
The minimum distance to the geometry in pixels. |
Examples:
Distance to nearest edge or corner:
timeit(func)
¶
Decorator to measure and print execution time of a function.
This decorator wraps a function to measure its execution time and prints the time taken if it exceeds 1 millisecond. Useful for profiling performance-critical code.
| PARAMETER | DESCRIPTION |
|---|---|
func
|
The function to be timed.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
callable
|
The wrapped function with timing capability. |
Examples:
linspace(start, stop, num)
¶
Yield num evenly spaced values over [start, stop] inclusive.
A pure-Python generator equivalent of numpy.linspace.
| PARAMETER | DESCRIPTION |
|---|---|
start
|
The starting value of the sequence.
TYPE:
|
stop
|
The ending value of the sequence (inclusive).
TYPE:
|
num
|
Number of values to generate. Must be non-negative.
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
float
|
Evenly spaced floats from |
Examples:
calculate_text_size(text, font_size=16, font_name=None)
¶
Calculate the size needed to render text
clamp(value, min_value=None, max_value=None)
¶
Constrain a numeric value to lie within a specified range.
This function ensures that a value falls within the bounds defined by minimum and maximum values. If the value is below the minimum, it returns the minimum. If the value is above the maximum, it returns the maximum. Otherwise, it returns the original value unchanged.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
The value to constrain.
TYPE:
|
min_value
|
The minimum allowed value. If None, no minimum constraint is applied. Defaults to None.
TYPE:
|
max_value
|
The maximum allowed value. If None, no maximum constraint is applied. Defaults to None.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
The constrained value within the specified range. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If min_value is greater than max_value when both are specified. |
Examples:
Basic clamping with both bounds:
# Clamp to range [0, 100]
result = clamp(150, 0, 100) # Returns 100
result = clamp(-10, 0, 100) # Returns 0
result = clamp(50, 0, 100) # Returns 50
Clamping with only minimum:
# Ensure value is at least 0
result = clamp(-5, min_value=0) # Returns 0
result = clamp(10, min_value=0) # Returns 10
Clamping with only maximum:
get_effective_pos(widget)
¶
Get the effective position for canvas operations.
Returns (0, 0) for RelativeLayout widgets since they use local coordinates, otherwise returns (widget.x, widget.y). This is a common pattern in MorphUI for handling position calculations that need to work correctly with both regular widgets and RelativeLayout containers.
| PARAMETER | DESCRIPTION |
|---|---|
widget
|
The widget to get the effective position for. Should have x and y attributes.
|
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
The effective (x, y) position for canvas graphics operations. |
Examples:
Use in canvas operations:
from morphui.utils.helpers import get_effective_pos
# Get position that works for both regular widgets and RelativeLayout
x, y = get_effective_pos(self)
# Use in canvas instructions
with self.canvas:
Rectangle(pos=(x, y), size=self.size)
Use in layout calculations:
# Calculate absolute position for child widgets
container_x, container_y = get_effective_pos(container)
child_absolute_x = container_x + child.x
child_absolute_y = container_y + child.y
Notes
- RelativeLayout widgets use local coordinate system where (0, 0) is always the bottom-left corner of the layout
- Regular widgets use absolute coordinates within their parent
- This function abstracts away this difference for canvas operations
calculate_widget_local_pos(widget, window_pos)
¶
Calculate widget-local coordinates from window coordinates.
This function converts coordinates from window space to widget-local coordinates, accounting for coordinate system differences that occur when widgets are placed inside RelativeLayout containers (such as Screen widgets).
This function works for all types of coordinate transformations: - Touch events (touch down, move, up) - Mouse coordinates (position, movement, hovering) - Any other window-space coordinates that need widget-local conversion
In RelativeLayout containers, child widgets use local coordinates where their position is relative to the container, but events are reported in absolute window coordinates. This function calculates the necessary offset to transform any window position into the widget's coordinate space.
The calculation works by: 1. Getting the widget's absolute window position using to_window() 2. Comparing it with the widget's local position to find the offset 3. Applying this offset to the input coordinates
| PARAMETER | DESCRIPTION |
|---|---|
widget
|
The widget for which to calculate local coordinates. Must have x, y attributes and a to_window() method (like Kivy widgets).
TYPE:
|
window_pos
|
The position in window coordinates as (x, y).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Tuple[float, float]
|
The position in widget-local coordinates as (x, y). |
Examples:
Calculate ripple position for touch events:
from morphui.utils.helpers import calculate_widget_local_pos
def on_touch_down(self, touch):
# Convert window coordinates to widget-local coordinates
local_pos = calculate_widget_local_pos(self, touch.pos)
self.ripple_pos = local_pos
Handle mouse hovering:
def on_mouse_pos(self, *args):
mouse_x, mouse_y = Window.mouse_pos
local_x, local_y = calculate_widget_local_pos(self, (mouse_x, mouse_y))
# Use local coordinates for hover effects
self.is_hovered = self.collide_point(local_x, local_y)
Handle coordinates in RelativeLayout child:
# Widget inside a Screen (RelativeLayout)
class MyWidget(Widget):
def on_touch_move(self, touch):
# This correctly handles coordinate transformation
local_x, local_y = calculate_widget_local_pos(self, touch.pos)
# Use local_x, local_y for widget-relative calculations
Notes
- This function is particularly important for widgets inside Screen widgets or other RelativeLayout containers
- For widgets in regular layouts, this function typically returns the same coordinates as the input (no offset needed)
- Works for any coordinate source: touch events, mouse position, programmatic coordinates, etc.
- The offset calculation handles the coordinate system differences automatically
get_edges_params(left, right, bottom, top, offset)
cached
¶
Get parameters for creating edge lines around a rectangle.
This function calculates the start and end points for lines representing the edges of a rectangle, with an optional offset to adjust the position of the edges inward or outward.
| PARAMETER | DESCRIPTION |
|---|---|
left
|
The x-coordinate of the left edge.
TYPE:
|
right
|
The x-coordinate of the right edge.
TYPE:
|
bottom
|
The y-coordinate of the bottom edge.
TYPE:
|
top
|
The y-coordinate of the top edge.
TYPE:
|
offset
|
The offset to apply to each edge. Positive values move edges outward, negative values move them inward.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, List[float]]
|
A dictionary with keys 'left', 'right', 'bottom', 'top', each containing a list of two floats representing the start and end points of the corresponding edge line. |
refresh_widget(widget)
¶
Refresh a widget by calling its refresh methods.
This function iterates through all attributes of the given widget and calls any method that starts with 'refresh_' to update the widget's appearance or state.
| PARAMETER | DESCRIPTION |
|---|---|
widget
|
The widget to refresh.
TYPE:
|
morphui.utils.animations
¶
Animation utilities for MorphUI components
create_fade_animation(widget, fade_in=True, duration=0.3, callback=None)
¶
Create a fade in/out animation for a widget
create_slide_animation(widget, direction='up', distance=100, duration=0.3, callback=None)
¶
Create a slide animation for a widget
create_scale_animation(widget, scale_from=0.8, scale_to=1.0, duration=0.3, callback=None)
¶
Create a scale animation for a widget
create_color_animation(widget, color_property='color', target_color=None, duration=0.3, callback=None)
¶
Create a color transition animation for a widget
delayed_call(callback, delay=1.0)
¶
Execute a callback after a delay
morphui.utils.dotdict
¶
DotDict - A dictionary that supports dot notation access
DotDict(*args, **kwargs)
¶
Bases: dict
A dictionary subclass that allows attribute-style access to dictionary items.
| PARAMETER | DESCRIPTION |
|---|---|
*args
|
Arguments passed to dict constructor.
TYPE:
|
**kwargs
|
Keyword arguments passed to dict constructor.
TYPE:
|
| ATTRIBUTE | DESCRIPTION |
|---|---|
All dictionary keys become accessible as attributes. |
|
Notes
- Access items using dot notation: obj.key instead of obj['key']
- Supports all standard dictionary operations
- Nested DotDict support for nested dictionaries
- Safe attribute access with fallback to dict methods
Examples:
Basic usage:
data = DotDict({'name': 'John', 'age': 30})
print(data.name) # 'John'
print(data.age) # 30
data.city = 'New York'
print(data['city']) # 'New York'
Nested dictionaries:
nested = DotDict({
'user': {'name': 'Alice', 'profile': {'role': 'admin'}}
})
print(nested.user.name) # 'Alice'
print(nested.user.profile.role) # 'admin'
update(*args, **kwargs)
¶
Override update to convert nested dictionaries to DotDict.
| PARAMETER | DESCRIPTION |
|---|---|
*args
|
Arguments passed to dict.update().
TYPE:
|
**kwargs
|
Keyword arguments passed to dict.update().
TYPE:
|
get(key, default=None)
¶
Get an item with a default value.
| PARAMETER | DESCRIPTION |
|---|---|
key
|
The key to access.
TYPE:
|
default
|
Default value if key doesn't exist, by default None.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Any
|
The value or default. |
to_dict()
¶
Convert DotDict back to a regular dictionary (recursively).
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any]
|
A regular dictionary. |