diff --git a/adafruit_displayio_layout/layouts/__init__.py b/adafruit_displayio_layout/layouts/__init__.py index e69de29..7d9f684 100644 --- a/adafruit_displayio_layout/layouts/__init__.py +++ b/adafruit_displayio_layout/layouts/__init__.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 Shubham Patel +# +# SPDX-License-Identifier: MIT + +from micropython import const + +try: + from typing import Tuple +except ImportError: + pass + +# Anchor point constants for anchor method. +ANCHOR_TOP_LEFT = const((0.0, 0.0)) +ANCHOR_TOP_CENTER = const((0.5, 0.0)) +ANCHOR_TOP_RIGHT = const((1.0, 0.0)) +ANCHOR_CENTER_LEFT = const((0.0, 0.5)) +ANCHOR_CENTER = const((0.5, 0.5)) +ANCHOR_CENTER_RIGHT = const((1.0, 0.5)) +ANCHOR_BOTTOM_LEFT = const((0.0, 1.0)) +ANCHOR_BOTTOM_CENTER = const((0.5, 1.0)) +ANCHOR_BOTTOM_RIGHT = const((1.0, 1.0)) + + +def anchor(obj, anchor: Tuple[float, float], width: int, height: int) -> None: + """Helper to position a display object on screen using a defined anchor point. + + Sets `anchor_point` and `anchored_position` for display elements such as `Label`, + `Widget`, `AnchoredTileGrid`, or `AnchoredGroup`. + + :param obj: The object to be positioned. Must support `anchor_point` and `anchored_position`. + :param anchor: One of the predefined anchor constants (e.g. ANCHOR_TOP_LEFT, ANCHOR_CENTER) + :param width: Width of the display in pixels + :param height: Height of the display in pixels + """ + if not hasattr(obj, "anchor_point") or not hasattr(obj, "anchored_position"): + raise AttributeError( + "Object must have both `anchor_point` and `anchored_position` attributes." + ) + + if anchor not in { + ANCHOR_TOP_LEFT, + ANCHOR_TOP_CENTER, + ANCHOR_TOP_RIGHT, + ANCHOR_CENTER_LEFT, + ANCHOR_CENTER, + ANCHOR_CENTER_RIGHT, + ANCHOR_BOTTOM_LEFT, + ANCHOR_BOTTOM_CENTER, + ANCHOR_BOTTOM_RIGHT, + }: + raise ValueError( + "Anchor must be one of: ANCHOR_TOP_LEFT, ANCHOR_TOP_CENTER, ANCHOR_TOP_RIGHT,\n" + "ANCHOR_CENTER_LEFT, ANCHOR_CENTER, ANCHOR_CENTER_RIGHT,\n" + "ANCHOR_BOTTOM_LEFT, ANCHOR_BOTTOM_CENTER, ANCHOR_BOTTOM_RIGHT." + ) + + obj.anchor_point = anchor + obj.anchored_position = ( + int(anchor[0] * width), + int(anchor[1] * height), + ) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 5d2be9b..b57bd16 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -378,6 +378,13 @@ def add_content( then the cell_anchor_point from the GridLayout will be used. :return: None""" + grid_x, grid_y = grid_position + max_grid_x, max_grid_y = self.grid_size + if grid_x >= max_grid_x or grid_y >= max_grid_y: + raise ValueError( + f"Grid position {grid_position} is out of bounds for grid size {self.grid_size}" + ) + if cell_anchor_point: _this_cell_anchor_point = cell_anchor_point else: @@ -393,31 +400,63 @@ def add_content( if layout_cells: self._layout_cells() - def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: + def get_content(self, grid_position: Tuple[int, int]) -> displayio.Group: """ - Return a cells content based on the cell_coordinates. Raises + Return a cells content based on the grid_position. Raises KeyError if coordinates were not found in the GridLayout. - :param tuple cell_coordinates: the coordinates to lookup in the grid + :param tuple grid_position: the coordinates to lookup in the grid :return: the displayio content object at those coordinates """ for index, cell in enumerate(self._cell_content_list): # exact location 1x1 cell - if cell["grid_position"] == cell_coordinates: + if cell["grid_position"] == grid_position: return self._cell_content_list[index]["content"] # multi-spanning cell, any size bigger than 1x1 if ( cell["grid_position"][0] - <= cell_coordinates[0] + <= grid_position[0] < cell["grid_position"][0] + cell["cell_size"][0] and cell["grid_position"][1] - <= cell_coordinates[1] + <= grid_position[1] < cell["grid_position"][1] + cell["cell_size"][1] ): return self._cell_content_list[index]["content"] - raise KeyError(f"GridLayout does not contain cell at coordinates {cell_coordinates}") + raise KeyError(f"GridLayout does not contain content at coordinates {grid_position}") + + def pop_content(self, grid_position: Tuple[int, int]) -> None: + """ + Remove and return a cells content based on the grid_position. Raises + KeyError if coordinates were not found in the GridLayout. + + :param tuple grid_position: the coordinates to lookup in the grid + :return: the displayio content object at those coordinates + """ + for index, cell in enumerate(self._cell_content_list): + # exact location 1x1 cell + if cell["grid_position"] == grid_position: + _found = self._cell_content_list.pop(index) + self._layout_cells() + self.remove(_found["content"]) + return _found["content"] + + # multi-spanning cell, any size bigger than 1x1 + if ( + cell["grid_position"][0] + <= grid_position[0] + < cell["grid_position"][0] + cell["cell_size"][0] + and cell["grid_position"][1] + <= grid_position[1] + < cell["grid_position"][1] + cell["cell_size"][1] + ): + _found = self._cell_content_list.pop(index) + self._layout_cells() + self.remove(_found["content"]) + return _found["content"] + + raise KeyError(f"GridLayout does not contain content at coordinates {grid_position}") @property def cell_size_pixels(self) -> Tuple[int, int]: diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index ac5875d..84f70fb 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -28,6 +28,7 @@ from adafruit_bitmap_font.bdf import BDF from adafruit_bitmap_font.pcf import PCF + from circuitpython_typing.displayio import AnyDisplay from fontio import BuiltinFont except ImportError: pass @@ -53,7 +54,7 @@ class TabLayout(displayio.Group): :param int x: x location the layout should be placed. Pixel coordinates. :param int y: y location the layout should be placed. Pixel coordinates. - :param displayio.Display display: The Display object to show the tab layout on. + :param AnyDisplay display: The Display object to show the tab layout on. :param int tab_text_scale: Size of the text shown in the tabs. Whole numbers 1 and greater are valid :param Optional[Union[BuiltinFont, BDF, PCF]] custom_font: A pre-loaded font object to use @@ -75,7 +76,7 @@ def __init__( self, x: int = 0, y: int = 0, - display: Optional[displayio.Display] = None, + display: Optional[AnyDisplay] = None, tab_text_scale: int = 1, custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, inactive_tab_spritesheet: Optional[str] = None, diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index cbdae52..83156dc 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -38,6 +38,8 @@ try: from typing import Any, List, Optional, Tuple + + from circuitpython_typing.displayio import AnyDisplay except ImportError: pass @@ -54,7 +56,7 @@ class FlipInput(Widget, Control): :param int x: pixel position :param int y: pixel position - :param displayio.Display display: the display where the widget will be displayed + :param AnyDisplay display: the display where the widget will be displayed :param value_list: the list of strings that will be displayed :type value_list: List[str] :param Font font: the font used for the text (defaults to ``terminalio.FONT``) @@ -87,7 +89,7 @@ class FlipInput(Widget, Control): def __init__( self, - display: displayio.Display, + display: AnyDisplay, *, value_list: List[str], font: FONT = FONT, @@ -586,7 +588,7 @@ def _blit_constrained( # _animate_bitmap - performs animation of scrolling between two bitmaps def _animate_bitmap( - display: displayio.Display, + display: AnyDisplay, target_bitmap: displayio.Bitmap, bitmap1: displayio.Bitmap, bitmap1_offset: Tuple[int, int], diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 2e43821..f63fd25 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -37,7 +37,7 @@ try: from typing import Any, Optional, Tuple - from busdisplay import BusDisplay + from circuitpython_typing.displayio import AnyDisplay except ImportError: pass @@ -86,7 +86,7 @@ class IconAnimated(IconWidget): @classmethod def init_class( cls, - display: Optional[BusDisplay], + display: Optional[AnyDisplay], max_scale: float = 1.5, max_icon_size: Tuple[int, int] = (80, 80), max_color_depth: int = 256, @@ -100,7 +100,7 @@ def init_class( ``IconAnimated.init_class(display=board.DISPLAY, max_scale=1.5, max_icon_size=(80,80), max_color_depth=256)`` - :param displayio.Display display: The display where the icons will be displayed. + :param AnyDisplay display: The display where the icons will be displayed. :param float max_scale: The maximum zoom of the any of the icons, should be >= 1.0, (default: 1.5) :param max_icon_size: The maximum (x,y) pixel dimensions of any `IconAnimated` bitmap size diff --git a/requirements.txt b/requirements.txt index 1cfb615..433415f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ adafruit-circuitpython-bitmap-font adafruit-circuitpython-display-text adafruit-circuitpython-imageload adafruit-circuitpython-display-shapes +adafruit-circuitpython-typing pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy