]> Repositories - hackapet/Adafruit_Blinka_Displayio.git/blobdiff - displayio/_group.py
Merge pull request #114 from makermelissa/add-grayscale
[hackapet/Adafruit_Blinka_Displayio.git] / displayio / _group.py
index 8e006b23b589b688b163a736b429c381873ca3fc..a5c6688f5f66d7d8b715dbb4a54159d700fef15b 100644 (file)
@@ -19,17 +19,18 @@ displayio for Blinka
 
 from __future__ import annotations
 from typing import Union, Callable
-from recordclass import recordclass
+from circuitpython_typing import WriteableBuffer
+from ._structs import TransformStruct
 from ._tilegrid import TileGrid
+from ._colorspace import Colorspace
+from ._area import Area
 
-__version__ = "0.0.0-auto.0"
+__version__ = "0.0.0+auto.0"
 __repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
 
 
-Transform = recordclass("Transform", "x y dx dy scale transpose_xy mirror_x mirror_y")
-
-
 class Group:
+    # pylint: disable=too-many-instance-attributes
     """
     Manage a group of sprites and groups and how they are inter-related.
 
@@ -47,19 +48,22 @@ class Group:
         if not isinstance(scale, int) or scale < 1:
             raise ValueError("Scale must be >= 1")
         self._scale = 1  # Use the setter below to actually set the scale
+        self._name = "Group"
         self._group_x = x
         self._group_y = y
         self._hidden_group = False
+        self._hidden_by_parent = False
         self._layers = []
         self._supported_types = (TileGrid, Group)
-        self.in_group = False
-        self._absolute_transform = Transform(0, 0, 1, 1, 1, False, False, False)
+        self._in_group = False
+        self._item_removed = False
+        self._absolute_transform = TransformStruct(0, 0, 1, 1, 1, False, False, False)
         self._set_scale(scale)  # Set the scale via the setter
 
     def _update_transform(self, parent_transform):
         """Update the parent transform and child transforms"""
-        self.in_group = parent_transform is not None
-        if self.in_group:
+        self._in_group = parent_transform is not None
+        if self._in_group:
             x = self._group_x
             y = self._group_y
             if parent_transform.transpose_xy:
@@ -76,20 +80,19 @@ class Group:
 
     def _update_child_transforms(self):
         # pylint: disable=protected-access
-        if self.in_group:
+        if self._in_group:
             for layer in self._layers:
                 layer._update_transform(self._absolute_transform)
-        # pylint: enable=protected-access
 
     def _removal_cleanup(self, index):
+        # pylint: disable=protected-access
         layer = self._layers[index]
-        layer._update_transform(None)  # pylint: disable=protected-access
+        layer._update_transform(None)
 
     def _layer_update(self, index):
         # pylint: disable=protected-access
         layer = self._layers[index]
         layer._update_transform(self._absolute_transform)
-        # pylint: enable=protected-access
 
     def append(self, layer: Union[Group, TileGrid]) -> None:
         """Append a layer to the group. It will be drawn
@@ -101,7 +104,7 @@ class Group:
         """Insert a layer into the group."""
         if not isinstance(layer, self._supported_types):
             raise ValueError("Invalid Group Member")
-        if layer.in_group:
+        if layer._in_group:  # pylint: disable=protected-access
             raise ValueError("Layer already in a group.")
         self._layers.insert(index, layer)
         self._layer_update(index)
@@ -112,59 +115,106 @@ class Group:
         """
         return self._layers.index(layer)
 
-    def pop(self, index=-1) -> Union[Group, TileGrid]:
+    def pop(self, index: int = -1) -> Union[Group, TileGrid]:
         """Remove the ith item and return it."""
         self._removal_cleanup(index)
         return self._layers.pop(index)
 
-    def remove(self, layer) -> None:
+    def remove(self, layer: Union[Group, TileGrid]) -> None:
         """Remove the first copy of layer. Raises ValueError
         if it is not present."""
         index = self.index(layer)
         self._layers.pop(index)
 
+    def __bool__(self) -> bool:
+        """Returns if there are any layers"""
+        return len(self._layers) > 0
+
     def __len__(self) -> int:
         """Returns the number of layers in a Group"""
         return len(self._layers)
 
-    def __getitem__(self, index) -> Union[Group, TileGrid]:
+    def __getitem__(self, index: int) -> Union[Group, TileGrid]:
         """Returns the value at the given index."""
         return self._layers[index]
 
-    def __setitem__(self, index, value) -> None:
+    def __setitem__(self, index: int, value: Union[Group, TileGrid]) -> None:
         """Sets the value at the given index."""
         self._removal_cleanup(index)
         self._layers[index] = value
         self._layer_update(index)
 
-    def __delitem__(self, index) -> None:
+    def __delitem__(self, index: int) -> None:
         """Deletes the value at the given index."""
         del self._layers[index]
 
-    def _fill_area(self, buffer):
-        if self._hidden_group:
-            return
-
-        for layer in self._layers:
-            if isinstance(layer, (Group, TileGrid)):
-                layer._fill_area(buffer)  # pylint: disable=protected-access
+    def _fill_area(
+        self,
+        colorspace: Colorspace,
+        area: Area,
+        mask: WriteableBuffer,
+        buffer: WriteableBuffer,
+    ) -> bool:
+        if not self._hidden_group:
+            for layer in reversed(self._layers):
+                if isinstance(layer, (Group, TileGrid)):
+                    if layer._fill_area(  # pylint: disable=protected-access
+                        colorspace, area, mask, buffer
+                    ):
+                        return True
+        return False
 
     def sort(self, key: Callable, reverse: bool) -> None:
         """Sort the members of the group."""
         self._layers.sort(key=key, reverse=reverse)
 
+    def _finish_refresh(self):
+        for layer in reversed(self._layers):
+            if isinstance(layer, (Group, TileGrid)):
+                layer._finish_refresh()  # pylint: disable=protected-access
+
+    def _get_refresh_areas(self, areas: list[Area]) -> None:
+        # pylint: disable=protected-access
+        for layer in reversed(self._layers):
+            if isinstance(layer, Group):
+                layer._get_refresh_areas(areas)
+            elif isinstance(layer, TileGrid):
+                if not layer._get_rendered_hidden():
+                    layer._get_refresh_areas(areas)
+
+    def _set_hidden(self, hidden: bool) -> None:
+        if self._hidden_group == hidden:
+            return
+        self._hidden_group = hidden
+        if self._hidden_by_parent:
+            return
+        for layer in self._layers:
+            if isinstance(layer, (Group, TileGrid)):
+                layer._set_hidden_by_parent(hidden)  # pylint: disable=protected-access
+
+    def _set_hidden_by_parent(self, hidden: bool) -> None:
+        if self._hidden_by_parent == hidden:
+            return
+        self._hidden_by_parent = hidden
+        if self._hidden_group:
+            return
+        for layer in self._layers:
+            if isinstance(layer, (Group, TileGrid)):
+                layer._set_hidden_by_parent(hidden)  # pylint: disable=protected-access
+
     @property
     def hidden(self) -> bool:
-        """True when the Group and all of its layers are not visible. When False, the
-        Group’s layers are visible if they havent been hidden.
+        """True when the Group and all of it's layers are not visible. When False, the
+        Group’s layers are visible if they haven't been hidden.
         """
         return self._hidden_group
 
     @hidden.setter
-    def hidden(self, value: bool):
+    def hidden(self, value: bool) -> None:
         if not isinstance(value, (bool, int)):
             raise ValueError("Expecting a boolean or integer value")
-        self._hidden_group = bool(value)
+        value = bool(value)
+        self._set_hidden(value)
 
     @property
     def scale(self) -> int:
@@ -232,3 +282,6 @@ class Group:
                 self._absolute_transform.y += dy_value * (value - self._group_y)
             self._group_y = value
             self._update_child_transforms()
+
+
+circuitpython_splash = Group(scale=2, x=0, y=0)