X-Git-Url: https://git.ayoreis.com/hackapet/Adafruit_Blinka_Displayio.git/blobdiff_plain/e46cbbe709e52c0a1ce5bd8107440ec78919bc6c..2a71c94d562fb8c5ec12a1697d26107ed6a0e4fd:/displayio/_tilegrid.py diff --git a/displayio/_tilegrid.py b/displayio/_tilegrid.py index 91b3232..a3f21eb 100644 --- a/displayio/_tilegrid.py +++ b/displayio/_tilegrid.py @@ -23,7 +23,6 @@ from circuitpython_typing import WriteableBuffer from ._bitmap import Bitmap from ._colorconverter import ColorConverter from ._ondiskbitmap import OnDiskBitmap -from ._shape import Shape from ._palette import Palette from ._structs import ( InputPixelStruct, @@ -47,7 +46,7 @@ class TileGrid: def __init__( self, - bitmap: Union[Bitmap, OnDiskBitmap, Shape], + bitmap: Union[Bitmap, OnDiskBitmap], *, pixel_shader: Union[ColorConverter, Palette], width: int = 1, @@ -64,7 +63,7 @@ class TileGrid: tile_width and tile_height match the height of the bitmap by default. """ - if not isinstance(bitmap, (Bitmap, OnDiskBitmap, Shape)): + if not isinstance(bitmap, (Bitmap, OnDiskBitmap)): raise ValueError("Unsupported Bitmap type") self._bitmap = bitmap bitmap_width = bitmap.width @@ -121,6 +120,7 @@ class TileGrid: self._tiles_in_bitmap = self._bitmap_width_in_tiles * ( bitmap_height // tile_height ) + self._needs_refresh = True def _update_transform(self, absolute_transform): """Update the parent transform and child transforms""" @@ -132,6 +132,7 @@ class TileGrid: self._update_current_y() def _update_current_x(self): + self._needs_refresh = True if self._transpose_xy: width = self._pixel_height else: @@ -169,6 +170,7 @@ class TileGrid: ) def _update_current_y(self): + self._needs_refresh = True if self._transpose_xy: height = self._pixel_width else: @@ -244,10 +246,12 @@ class TileGrid: if self._hidden_tilegrid or self._hidden_by_parent: return False - overlap = Area() # area, current_area, overlap if not area.compute_overlap(self._current_area, overlap): return False + # else: + # print("Checking", area.x1, area.y1, area.x2, area.y2) + # print("Overlap", overlap.x1, overlap.y1, overlap.x2, overlap.y2) if self._bitmap.width <= 0 or self._bitmap.height <= 0: return False @@ -339,7 +343,7 @@ class TileGrid: # We always want to read bitmap pixels by row first and then transpose into # the destination buffer because most bitmaps are row associated. - if isinstance(self._bitmap, (Bitmap, Shape, OnDiskBitmap)): + if isinstance(self._bitmap, (Bitmap, OnDiskBitmap)): input_pixel.pixel = ( self._bitmap._get_pixel( # pylint: disable=protected-access input_pixel.tile_x, input_pixel.tile_y @@ -365,19 +369,19 @@ class TileGrid: if colorspace.depth == 16: struct.pack_into( "H", - buffer, + buffer.cast("B"), offset * 2, output_pixel.pixel, ) elif colorspace.depth == 32: struct.pack_into( "I", - buffer, + buffer.cast("B"), offset * 4, output_pixel.pixel, ) elif colorspace.depth == 8: - buffer[offset] = output_pixel.pixel & 0xFF + buffer.cast("B")[offset] = output_pixel.pixel & 0xFF elif colorspace.depth < 8: # Reorder the offsets to pack multiple rows into # a byte (meaning they share a column). @@ -389,31 +393,35 @@ class TileGrid: # even if we multiply it back out offset = ( col * pixels_per_byte - + (row // pixels_per_byte) * width + + (row // pixels_per_byte) * pixels_per_byte * width + (row % pixels_per_byte) ) shift = (offset % pixels_per_byte) * colorspace.depth if colorspace.reverse_pixels_in_byte: # Reverse the shift by subtracting it from the leftmost shift shift = (pixels_per_byte - 1) * colorspace.depth - shift - buffer[offset // pixels_per_byte] |= output_pixel.pixel << shift + buffer.cast("B")[offset // pixels_per_byte] |= ( + output_pixel.pixel << shift + ) + return full_coverage def _finish_refresh(self): - first_draw = self._previous_area.x1 == self._previous_area.x2 - hidden = self._hidden_tilegrid or self._hidden_by_parent - if not first_draw and hidden: - self._previous_area.x2 = self._previous_area.x1 - elif self._moved or first_draw: - self._current_area.copy_into(self._previous_area) - - self._moved = False - self._full_change = False - self._partial_change = False - if isinstance(self._pixel_shader, (Palette, ColorConverter)): - self._pixel_shader._finish_refresh() # pylint: disable=protected-access - if isinstance(self._bitmap, (Bitmap, Shape)): - self._bitmap._finish_refresh() # pylint: disable=protected-access + if not self._needs_refresh: + first_draw = self._previous_area.x1 == self._previous_area.x2 + hidden = self._hidden_tilegrid or self._hidden_by_parent + if not first_draw and hidden: + self._previous_area.x2 = self._previous_area.x1 + elif self._moved or first_draw: + self._current_area.copy_into(self._previous_area) + + self._moved = False + self._full_change = False + self._partial_change = False + if isinstance(self._pixel_shader, (Palette, ColorConverter)): + self._pixel_shader._finish_refresh() # pylint: disable=protected-access + if isinstance(self._bitmap, Bitmap): + self._bitmap._finish_refresh() # pylint: disable=protected-access def _get_refresh_areas(self, areas: list[Area]) -> None: # pylint: disable=invalid-name, too-many-branches, too-many-statements @@ -425,14 +433,17 @@ class TileGrid: self._rendered_hidden = True if not first_draw: areas.append(self._previous_area) + self._needs_refresh = False return if self._moved and not first_draw: self._previous_area.union(self._current_area, self._dirty_area) if self._dirty_area.size() < 2 * self._pixel_width * self._pixel_height: areas.append(self._dirty_area) + self._needs_refresh = False return areas.append(self._current_area) areas.append(self._previous_area) + self._needs_refresh = False return tail = areas[-1] if areas else None @@ -440,7 +451,7 @@ class TileGrid: if isinstance(self._bitmap, Bitmap): self._bitmap._get_refresh_areas(areas) # pylint: disable=protected-access refresh_area = areas[-1] if areas else None - if tail != refresh_area: + if refresh_area != tail: # Special case a TileGrid that shows a full bitmap and use its # dirty area. Copy it to ours so we can transform it. if self._tiles_in_bitmap == 1: @@ -448,12 +459,6 @@ class TileGrid: self._partial_change = True else: self._full_change = True - elif isinstance(self._bitmap, Shape): - self._bitmap._get_refresh_areas(areas) # pylint: disable=protected-access - refresh_area = areas[-1] if areas else None - if refresh_area != tail: - refresh_area.copy_into(self._dirty_area) - self._partial_change = True self._full_change = self._full_change or ( isinstance(self._pixel_shader, (Palette, ColorConverter)) @@ -461,6 +466,7 @@ class TileGrid: ) if self._full_change or first_draw: areas.append(self._current_area) + self._needs_refresh = False return if self._partial_change: @@ -504,14 +510,17 @@ class TileGrid: self._dirty_area.x1, ) areas.append(self._dirty_area) + self._needs_refresh = False def _set_hidden(self, hidden: bool) -> None: + self._needs_refresh = True self._hidden_tilegrid = hidden self._rendered_hidden = False if not hidden: self._full_change = True def _set_hidden_by_parent(self, hidden: bool) -> None: + self._needs_refresh = True self._hidden_by_parent = hidden self._rendered_hidden = False if not hidden: @@ -529,6 +538,30 @@ class TileGrid: ) self._full_change = True + def _set_tile(self, x: int, y: int, tile_index: int) -> None: + self._needs_refresh = True + self._tiles[y * self._width_in_tiles + x] = tile_index + temp_area = Area() + if not self._partial_change: + tile_area = self._dirty_area + else: + tile_area = temp_area + top_x = (x - self._top_left_x) % self._width_in_tiles + if top_x < 0: + top_x += self._width_in_tiles + tile_area.x1 = top_x * self._tile_width + tile_area.x2 = tile_area.x1 + self._tile_width + top_y = (y - self._top_left_y) % self._height_in_tiles + if top_y < 0: + top_y += self._height_in_tiles + tile_area.y1 = top_y * self._tile_height + tile_area.y2 = tile_area.y1 + self._tile_height + + if self._partial_change: + self._dirty_area.union(temp_area, self._dirty_area) + + self._partial_change = True + def _set_top_left(self, x: int, y: int) -> None: self._top_left_x = x self._top_left_y = y @@ -587,6 +620,7 @@ class TileGrid: if not isinstance(value, bool): raise TypeError("Flip X should be a boolean type") if self._flip_x != value: + self._needs_refresh = True self._flip_x = value self._full_change = True @@ -600,6 +634,7 @@ class TileGrid: if not isinstance(value, bool): raise TypeError("Flip Y should be a boolean type") if self._flip_y != value: + self._needs_refresh = True self._flip_y = value self._full_change = True @@ -615,6 +650,7 @@ class TileGrid: if not isinstance(value, bool): raise TypeError("Transpose XY should be a boolean type") if self._transpose_xy != value: + self._needs_refresh = True self._transpose_xy = value if self._pixel_width == self._pixel_height: self._full_change = True @@ -639,21 +675,20 @@ class TileGrid: self._pixel_shader = new_pixel_shader self._full_change = True + self._needs_refresh = True @property - def bitmap(self) -> Union[Bitmap, OnDiskBitmap, Shape]: - """The Bitmap, OnDiskBitmap, or Shape that is assigned to this TileGrid""" + def bitmap(self) -> Union[Bitmap, OnDiskBitmap]: + """The Bitmap or OnDiskBitmap that is assigned to this TileGrid""" return self._bitmap @bitmap.setter - def bitmap(self, new_bitmap: Union[Bitmap, OnDiskBitmap, Shape]) -> None: - if ( - not isinstance(new_bitmap, Bitmap) - and not isinstance(new_bitmap, OnDiskBitmap) - and not isinstance(new_bitmap, Shape) + def bitmap(self, new_bitmap: Union[Bitmap, OnDiskBitmap]) -> None: + if not isinstance(new_bitmap, Bitmap) and not isinstance( + new_bitmap, OnDiskBitmap ): raise TypeError( - "Unsupported Type: new_bitmap must be Bitmap, OnDiskBitmap, or Shape" + "Unsupported Type: new_bitmap must be Bitmap or OnDiskBitmap" ) if ( @@ -662,6 +697,7 @@ class TileGrid: ): raise ValueError("New bitmap must be same size as old bitmap") + self._needs_refresh = True self._bitmap = new_bitmap self._full_change = True @@ -679,23 +715,23 @@ class TileGrid: or index >= len(self._tiles) ): raise ValueError("Tile index out of bounds") - return index + return x, y def __getitem__(self, index: Union[Tuple[int, int], int]) -> int: """Returns the tile index at the given index. The index can either be an x,y tuple or an int equal to ``y * width + x``'. """ - index = self._extract_and_check_index(index) - return self._tiles[index] + x, y = self._extract_and_check_index(index) + return self._tiles[y * self._width_in_tiles + x] def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None: """Sets the tile index at the given index. The index can either be an x,y tuple or an int equal to ``y * width + x``. """ - index = self._extract_and_check_index(index) + x, y = self._extract_and_check_index(index) if not 0 <= value <= 255: raise ValueError("Tile value out of bounds") - self._tiles[index] = value + self._set_tile(x, y, value) @property def width(self) -> int: