--- /dev/null
+# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams, written for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+change-template: "- $TITLE #$NUMBER by @$AUTHOR"
+template: |
+ ## What's Changed
+
+ $CHANGES
+
+ To use in CPython, `pip3 install adafruit-blinka-displayio`.
+
+ Read the [docs](https://adafruit-blinka-displayio.readthedocs.io/en/latest/)) for info on how to use it.
--- /dev/null
+# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams, written for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+name: Release Drafter
+
+on:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: read
+
+jobs:
+ update_release_draft:
+ permissions:
+ # write permission is required to create a github release
+ contents: write
+ pull-requests: read
+ runs-on: ubuntu-latest
+ steps:
+ - uses: release-drafter/release-drafter@v5
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# SPDX-License-Identifier: MIT
"""
-`displayio.display`
+`busdisplay`
================================================================================
-displayio for Blinka
+busdisplay for Blinka
**Software and Dependencies:**
import digitalio
import microcontroller
from circuitpython_typing import WriteableBuffer, ReadableBuffer
-from ._displaycore import _DisplayCore
-from ._displaybus import _DisplayBus
-from ._colorconverter import ColorConverter
-from ._group import Group, circuitpython_splash
-from ._area import Area
-from ._constants import (
+from displayio._displaycore import _DisplayCore
+from displayio._colorconverter import ColorConverter
+from displayio._group import Group, circuitpython_splash
+from displayio._area import Area
+from displayio._constants import (
CHIP_SELECT_TOGGLE_EVERY_BYTE,
CHIP_SELECT_UNTOUCHED,
DISPLAY_COMMAND,
NO_COMMAND,
DELAY,
)
+from ._displaybus import _DisplayBus
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
-class Display:
+class BusDisplay:
# pylint: disable=too-many-instance-attributes, too-many-statements
"""This initializes a display and connects it into CircuitPython. Unlike other objects
in CircuitPython, Display objects live until ``displayio.release_displays()`` is called.
SH1107_addressing: bool = False,
):
# pylint: disable=too-many-locals,invalid-name, too-many-branches
- """Create a Display object on the given display bus (`displayio.FourWire` or
- `paralleldisplay.ParallelBus`).
+ """Create a Display object on the given display bus (`fourwire.FourWire` or
+ `paralleldisplaybus.ParallelBus`).
The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins
with a command byte followed by a byte to determine the parameter count and if a
b"\\x11\\x80\\x78" # Exit Sleep then delay 0x78 (120ms)
b"\\x29\\x80\\x78" # Display on then delay 0x78 (120ms)
)
- display = displayio.Display(display_bus, init_sequence, width=320, height=240)
+ display = busdisplay.BusDisplay(display_bus, init_sequence, width=320, height=240)
The first command is 0xE1 with 15 (0x0F) parameters following. The second and third
are 0x11 and 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters.
self.auto_refresh = auto_refresh
def __new__(cls, *args, **kwargs):
- from . import ( # pylint: disable=import-outside-toplevel, cyclic-import
+ from displayio import ( # pylint: disable=import-outside-toplevel, cyclic-import
allocate_display,
)
)
self._core.send(DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, pixels)
- def show(self, group: Group) -> None:
- """
- .. note:: `show()` is deprecated and will be removed when CircuitPython 9.0.0
- is released. Use ``.root_group = group`` instead.
-
- Switches to displaying the given group of layers. When group is None, the
- default CircuitPython terminal will be shown.
-
- :param Group group: The group to show.
- """
- if group is None:
- group = circuitpython_splash
- self._core.set_root_group(group)
+ @staticmethod
+ def show(_group: Group) -> None: # pylint: disable=missing-function-docstring
+ raise AttributeError(".show(x) removed. Use .root_group = x")
def _set_root_group(self, root_group: Group) -> None:
ok = self._core.set_root_group(root_group)
# SPDX-License-Identifier: MIT
"""
-`displayio._displaybus`
+`busdisplay._displaybus`
================================================================================
-Type aliases for Blinka
+DisplayBus Type aliases for Blinka
**Software and Dependencies:**
"""
from typing import Union
-import paralleldisplay
-from ._fourwire import FourWire
-from ._i2cdisplay import I2CDisplay
+import paralleldisplaybus
+import fourwire
+import i2cdisplaybus
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_Blinka_Displayio.git"
-_DisplayBus = Union[FourWire, I2CDisplay, paralleldisplay.ParallelBus]
+_DisplayBus = Union[
+ fourwire.FourWire, i2cdisplaybus.I2CDisplayBus, paralleldisplaybus.ParallelBus
+]
"""
import threading
from typing import Union
-from ._fourwire import FourWire
-from ._i2cdisplay import I2CDisplay
+from busdisplay import BusDisplay
+from busdisplay._displaybus import _DisplayBus
+from epaperdisplay import EPaperDisplay
from ._bitmap import Bitmap
from ._colorspace import Colorspace
from ._colorconverter import ColorConverter
-from ._display import Display
-from ._epaperdisplay import EPaperDisplay
from ._group import Group
from ._ondiskbitmap import OnDiskBitmap
from ._palette import Palette
-from ._shape import Shape
from ._tilegrid import TileGrid
-from ._displaybus import _DisplayBus
from ._constants import CIRCUITPY_DISPLAY_LIMIT
__version__ = "0.0.0+auto.0"
display_buses.clear()
-def allocate_display(new_display: Union[Display, EPaperDisplay]) -> None:
+def allocate_display(new_display: Union[BusDisplay, EPaperDisplay]) -> None:
"""Add a display to the displays pool and return the new display"""
if len(displays) >= CIRCUITPY_DISPLAY_LIMIT:
raise RuntimeError("Too many displays")
import time
import struct
from circuitpython_typing import WriteableBuffer, ReadableBuffer
-from paralleldisplay import ParallelBus
-from ._fourwire import FourWire
+from paralleldisplaybus import ParallelBus
+from fourwire import FourWire
+from i2cdisplaybus import I2CDisplayBus
+from busdisplay._displaybus import _DisplayBus
from ._group import Group
-from ._i2cdisplay import I2CDisplay
from ._structs import ColorspaceStruct, TransformStruct
from ._area import Area
-from ._displaybus import _DisplayBus
from ._helpers import bswap16
from ._constants import (
CHIP_SELECT_UNTOUCHED,
self.last_refresh = 0
if bus:
- if isinstance(bus, (FourWire, I2CDisplay, ParallelBus)):
+ if isinstance(bus, (FourWire, I2CDisplayBus, ParallelBus)):
self._bus_reset = bus.reset
self._bus_free = bus._free
self._begin_transaction = bus._begin_transaction
load times. These load times may result in frame tearing where only part of the image is
visible.
- It's easiest to use on a board with a built in display such as the `Hallowing M0 Express
- <https://www.adafruit.com/product/3900>`_.
-
.. code-block:: Python
import board
board.DISPLAY.auto_brightness = False
board.DISPLAY.brightness = 0
splash = displayio.Group()
- board.DISPLAY.show(splash)
+ board.DISPLAY.root_group = splash
odb = displayio.OnDiskBitmap(\'/sample.bmp\')
face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
+++ /dev/null
-# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries
-#
-# SPDX-License-Identifier: MIT
-
-
-"""
-`displayio.shape`
-================================================================================
-
-displayio for Blinka
-
-**Software and Dependencies:**
-
-* Adafruit Blinka:
- https://github.com/adafruit/Adafruit_Blinka/releases
-
-* Author(s): Melissa LeBlanc-Williams
-
-"""
-
-from ._bitmap import Bitmap
-from ._area import Area
-from ._helpers import clamp
-
-__version__ = "0.0.0+auto.0"
-__repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
-
-
-class Shape(Bitmap):
- """Create a Shape object with the given fixed size. Each pixel is one bit and is stored
- by the column boundaries of the shape on each row. Each row’s boundary defaults to the
- full row.
- """
-
- def __init__(
- self, width: int, height: int, *, mirror_x: bool = False, mirror_y: bool = False
- ):
- """Create a Shape object with the given fixed size. Each pixel is one bit and is
- stored by the column boundaries of the shape on each row. Each row’s boundary
- defaults to the full row.
- """
- self._mirror_x = mirror_x
- self._mirror_y = mirror_y
- self._width = width
- self._height = height
- if self._mirror_x:
- width //= 2
- width += self._width % 2
- self._half_width = width
- if self._mirror_y:
- height //= 2
- height += self._height % 2
- self._half_height = height
- self._data = bytearray(height * 4)
- for i in range(height):
- self._data[2 * i] = 0
- self._data[2 * i + 1] = width
-
- self._dirty_area = Area(0, 0, width, height)
- super().__init__(width, height, 2)
-
- def set_boundary(self, y: int, start_x: int, end_x: int) -> None:
- """Loads pre-packed data into the given row."""
- max_y = self._height - 1
- if self._mirror_y:
- max_y = self._half_height - 1
- y = clamp(y, 0, max_y)
- max_x = self._width - 1
- if self._mirror_x:
- max_x = self._half_width - 1
- start_x = clamp(start_x, 0, max_x)
- end_x = clamp(end_x, 0, max_x)
-
- # find x-boundaries for updating based on current data and start_x, end_x, and mirror_x
- lower_x = min(start_x, self._data[2 * y])
-
- if self._mirror_x:
- upper_x = (
- self._width - lower_x + 1
- ) # dirty rectangles are treated with max value exclusive
- else:
- upper_x = max(
- end_x, self._data[2 * y + 1]
- ) # dirty rectangles are treated with max value exclusive
-
- # find y-boundaries based on y and mirror_y
- lower_y = y
-
- if self._mirror_y:
- upper_y = (
- self._height - lower_y + 1
- ) # dirty rectangles are treated with max value exclusive
- else:
- upper_y = y + 1 # dirty rectangles are treated with max value exclusive
-
- self._data[2 * y] = start_x # update the data array with the new boundaries
- self._data[2 * y + 1] = end_x
-
- if self._dirty_area.x1 == self._dirty_area.x2: # dirty region is empty
- self._dirty_area.x1 = lower_x
- self._dirty_area.x2 = upper_x
- self._dirty_area.y1 = lower_y
- self._dirty_area.y2 = upper_y
- else:
- self._dirty_area.x1 = min(lower_x, self._dirty_area.x1)
- self._dirty_area.x2 = max(upper_x, self._dirty_area.x2)
- self._dirty_area.y1 = min(lower_y, self._dirty_area.y1)
- self._dirty_area.y2 = max(upper_y, self._dirty_area.y2)
-
- def _get_pixel(self, x: int, y: int) -> int:
- if x >= self._width or x < 0 or y >= self._height or y < 0:
- return 0
- if self._mirror_x and x >= self._half_width:
- x = self._width - x - 1
- if self._mirror_y and y >= self._half_height:
- y = self._height - y - 1
- start_x = self._data[2 * y]
- end_x = self._data[2 * y + 1]
- if x < start_x or x >= end_x:
- return 0
- return 1
-
- def _finish_refresh(self):
- self._dirty_area.x1 = 0
- self._dirty_area.x2 = 0
-
- def _get_refresh_areas(self, areas: list[Area]) -> None:
- if self._dirty_area.x1 != self._dirty_area.x2:
- areas.append(self._dirty_area)
from ._bitmap import Bitmap
from ._colorconverter import ColorConverter
from ._ondiskbitmap import OnDiskBitmap
-from ._shape import Shape
from ._palette import Palette
from ._structs import (
InputPixelStruct,
def __init__(
self,
- bitmap: Union[Bitmap, OnDiskBitmap, Shape],
+ bitmap: Union[Bitmap, OnDiskBitmap],
*,
pixel_shader: Union[ColorConverter, Palette],
width: int = 1,
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
# 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
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)):
+ if isinstance(self._bitmap, Bitmap):
self._bitmap._finish_refresh() # pylint: disable=protected-access
def _get_refresh_areas(self, areas: list[Area]) -> None:
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))
self._full_change = 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 (
.. automodule:: displayio
- :members: Bitmap, ColorConverter, Display, EPaperDisplay, FourWire, Group, I2CDisplay,
- OnDiskBitmap, Palette, Shape, TileGrid
+ :members: Bitmap, ColorConverter, Group, OnDiskBitmap, Palette, TileGrid
.. automodule:: fontio
:members:
.. automodule:: terminalio
:members:
-.. automodule:: paralleldisplay
+.. automodule:: paralleldisplaybus
+ :members:
+
+.. automodule:: i2cdisplaybus
+ :members:
+
+.. automodule:: fourwire
+ :members:
+
+.. automodule:: busdisplay
:members:
# SPDX-License-Identifier: MIT
"""
-`displayio.epaperdisplay`
+`epaperdisplay`
================================================================================
-displayio for Blinka
+epaperdisplay for Blinka
**Software and Dependencies:**
import microcontroller
from digitalio import DigitalInOut
from circuitpython_typing import ReadableBuffer
-from ._displaycore import _DisplayCore
-from ._group import Group, circuitpython_splash
-from ._colorconverter import ColorConverter
-from ._displaybus import _DisplayBus
-from ._area import Area
-from ._constants import (
+from busdisplay._displaybus import _DisplayBus
+from displayio._displaycore import _DisplayCore
+from displayio._group import Group, circuitpython_splash
+from displayio._colorconverter import ColorConverter
+from displayio._area import Area
+from displayio._constants import (
CHIP_SELECT_TOGGLE_EVERY_BYTE,
CHIP_SELECT_UNTOUCHED,
DISPLAY_COMMAND,
address_little_endian: bool = False,
) -> None:
# pylint: disable=too-many-locals
- """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or
- `paralleldisplay.ParallelBus`).
+ """Create a EPaperDisplay object on the given display bus (`fourwire.FourWire` or
+ `paralleldisplaybus.ParallelBus`).
The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every
command begins with a command byte followed by a byte to determine the parameter count and
definition.
:param display_bus: The bus that the display is connected to
- :type _DisplayBus: displayio.FourWire or paralleldisplay.ParallelBus
+ :type _DisplayBus: fourwire.FourWire or paralleldisplaybus.ParallelBus
:param ~circuitpython_typing.ReadableBuffer start_sequence: Byte-packed command sequence.
:param ~circuitpython_typing.ReadableBuffer stop_sequence: Byte-packed command sequence.
:param int width: Width in pixels
self._refreshing = False
color_depth = 1
core_grayscale = True
+ # Disable while initializing
+ self._ticks_disabled = True
if advanced_color_epaper:
color_depth = 4
if highlight_color == 0x00 and write_color_ram_command != NO_COMMAND:
"""TODO: Clear"""
- self.show(circuitpython_splash)
+ self._set_root_group(circuitpython_splash)
def __new__(cls, *args, **kwargs):
- from . import ( # pylint: disable=import-outside-toplevel, cyclic-import
+ from displayio import ( # pylint: disable=import-outside-toplevel, cyclic-import
allocate_display,
)
allocate_display(display_instance)
return display_instance
- def show(self, group: Group) -> None:
- # pylint: disable=unnecessary-pass
- """
- .. note:: `show()` is deprecated and will be removed when CircuitPython 9.0.0
- is released. Use ``.root_group = group`` instead.
-
- Switches to displaying the given group of layers. When group is None, the default
- CircuitPython terminal will be shown (eventually).
- """
- if group is None:
- group = circuitpython_splash
- self._core.set_root_group(group)
+ @staticmethod
+ def show(_group: Group) -> None: # pylint: disable=missing-function-docstring
+ raise AttributeError(".show(x) removed. Use .root_group = x")
def _set_root_group(self, root_group: Group) -> None:
ok = self._core.set_root_group(root_group)
# SPDX-License-Identifier: MIT
"""
-`displayio.fourwire`
+`fourwire`
================================================================================
-displayio for Blinka
+fourwire for Blinka
**Software and Dependencies:**
import busio
import microcontroller
from circuitpython_typing import ReadableBuffer
-from ._constants import (
+from displayio._constants import (
CHIP_SELECT_TOGGLE_EVERY_BYTE,
CHIP_SELECT_UNTOUCHED,
DISPLAY_COMMAND,
# SPDX-License-Identifier: MIT
"""
-`displayio.i2cdisplay`
+`i2cdisplaybus`
================================================================================
-displayio for Blinka
+i2cdisplaybus for Blinka
**Software and Dependencies:**
import busio
import digitalio
from circuitpython_typing import ReadableBuffer
-from ._constants import CHIP_SELECT_UNTOUCHED, DISPLAY_COMMAND
+from displayio._constants import CHIP_SELECT_UNTOUCHED, DISPLAY_COMMAND
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
-class I2CDisplay:
+class I2CDisplayBus:
"""Manage updating a display over I2C in the background while Python code runs.
It doesn’t handle display initialization.
"""
def __init__(self, i2c_bus: busio.I2C, *, device_address: int, reset=None):
- """Create a I2CDisplay object associated with the given I2C bus and reset pin.
+ """Create a I2CDisplayBus object associated with the given I2C bus and reset pin.
The I2C bus and pins are then in use by the display until displayio.release_displays() is
called even after a reload. (It does this so CircuitPython can use the display after your
self._dev_addr = device_address
def __new__(cls, *args, **kwargs):
- from . import ( # pylint: disable=import-outside-toplevel, cyclic-import
+ from displayio import ( # pylint: disable=import-outside-toplevel, cyclic-import
allocate_display_bus,
)
# SPDX-License-Identifier: MIT
"""
-`paralleldisplay`
+`paralleldisplaybus`
================================================================================
-paralleldisplay for Blinka
+paralleldisplaybus for Blinka
**Software and Dependencies:**
keywords="adafruit blinka circuitpython micropython displayio lcd tft display pitft",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
- py_modules=["fontio", "terminalio", "paralleldisplay"],
- packages=["displayio", "vectorio"],
+ py_modules=["fontio", "terminalio"],
+ packages=[
+ "displayio",
+ "vectorio",
+ "paralleldisplaybus",
+ "i2cdisplaybus",
+ "fourwire",
+ "busdisplay",
+ ],
)