scrollkit 0.8.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scrollkit/__init__.py +16 -0
- scrollkit/app/__init__.py +6 -0
- scrollkit/app/base.py +918 -0
- scrollkit/app/memory.py +70 -0
- scrollkit/config/__init__.py +1 -0
- scrollkit/config/settings_manager.py +215 -0
- scrollkit/config/transition_names.py +31 -0
- scrollkit/dev/__init__.py +41 -0
- scrollkit/dev/capabilities.py +374 -0
- scrollkit/dev/harness.py +383 -0
- scrollkit/dev/metrics.py +91 -0
- scrollkit/dev/performance.py +174 -0
- scrollkit/dev/validation.py +245 -0
- scrollkit/display/__init__.py +14 -0
- scrollkit/display/_graphics.py +299 -0
- scrollkit/display/_recording.py +165 -0
- scrollkit/display/_sim_backend.py +99 -0
- scrollkit/display/bitmap_text.py +408 -0
- scrollkit/display/boards.py +186 -0
- scrollkit/display/colors.py +176 -0
- scrollkit/display/content.py +604 -0
- scrollkit/display/gradient_text.py +167 -0
- scrollkit/display/interface.py +126 -0
- scrollkit/display/simulator.py +80 -0
- scrollkit/display/text_fill.py +59 -0
- scrollkit/display/text_pixels.py +250 -0
- scrollkit/display/unified.py +595 -0
- scrollkit/effects/__init__.py +28 -0
- scrollkit/effects/drip_splash.py +253 -0
- scrollkit/effects/easing.py +131 -0
- scrollkit/effects/overlay.py +92 -0
- scrollkit/effects/particles.py +355 -0
- scrollkit/effects/reveal_splash.py +132 -0
- scrollkit/effects/scrolling.py +363 -0
- scrollkit/effects/swarm_reveal.py +512 -0
- scrollkit/effects/text_render.py +25 -0
- scrollkit/effects/transitions.py +873 -0
- scrollkit/exceptions.py +55 -0
- scrollkit/network/__init__.py +1 -0
- scrollkit/network/http_client.py +505 -0
- scrollkit/network/mdns.py +44 -0
- scrollkit/network/wifi_manager.py +382 -0
- scrollkit/ota/__init__.py +13 -0
- scrollkit/ota/client.py +528 -0
- scrollkit/ota/display_progress.py +125 -0
- scrollkit/ota/manifest.py +206 -0
- scrollkit/ota/publish.py +379 -0
- scrollkit/simulator/ATTRIBUTION.md +20 -0
- scrollkit/simulator/CIRCUITPYTHON_COMPATIBILITY.md +364 -0
- scrollkit/simulator/LICENSE +176 -0
- scrollkit/simulator/README.md +87 -0
- scrollkit/simulator/__init__.py +11 -0
- scrollkit/simulator/adafruit_bitmap_font/__init__.py +5 -0
- scrollkit/simulator/adafruit_bitmap_font/bitmap_font.py +273 -0
- scrollkit/simulator/adafruit_bitmap_font/glyph_cache.py +70 -0
- scrollkit/simulator/adafruit_display_text/__init__.py +5 -0
- scrollkit/simulator/adafruit_display_text/label.py +336 -0
- scrollkit/simulator/bitmaptools.py +50 -0
- scrollkit/simulator/core/__init__.py +8 -0
- scrollkit/simulator/core/color_utils.py +62 -0
- scrollkit/simulator/core/device_benchmarks.json +254 -0
- scrollkit/simulator/core/feasibility.py +160 -0
- scrollkit/simulator/core/hardware_profile.py +191 -0
- scrollkit/simulator/core/led_matrix.py +307 -0
- scrollkit/simulator/core/matrixportal_s3_baseline.json +12 -0
- scrollkit/simulator/core/performance_manager.py +253 -0
- scrollkit/simulator/core/pixel_buffer.py +188 -0
- scrollkit/simulator/devices/__init__.py +7 -0
- scrollkit/simulator/devices/base_device.py +79 -0
- scrollkit/simulator/devices/matrixportal_s3.py +87 -0
- scrollkit/simulator/displayio/__init__.py +12 -0
- scrollkit/simulator/displayio/bitmap.py +158 -0
- scrollkit/simulator/displayio/display.py +195 -0
- scrollkit/simulator/displayio/fourwire.py +54 -0
- scrollkit/simulator/displayio/group.py +125 -0
- scrollkit/simulator/displayio/ondiskbitmap.py +109 -0
- scrollkit/simulator/displayio/palette.py +115 -0
- scrollkit/simulator/displayio/tilegrid.py +155 -0
- scrollkit/simulator/fonts/3x5.bdf +2474 -0
- scrollkit/simulator/fonts/Arial_16.bdf +7366 -0
- scrollkit/simulator/fonts/Arial_16.bdf.license +3 -0
- scrollkit/simulator/fonts/Arial_Bold_12.bdf +6131 -0
- scrollkit/simulator/fonts/Arial_Bold_12.bdf.license +2 -0
- scrollkit/simulator/fonts/Arial_Bold_18.bdf +32653 -0
- scrollkit/simulator/fonts/Arial_Bold_18.bdf.license +2 -0
- scrollkit/simulator/fonts/Junction_regular_24.bdf +8676 -0
- scrollkit/simulator/fonts/Junction_regular_24.bdf.license +3 -0
- scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf +12458 -0
- scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf.license +1921 -0
- scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf +12458 -0
- scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf.license +4 -0
- scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf +16818 -0
- scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf.license +1921 -0
- scrollkit/simulator/fonts/tom-thumb.bdf +2353 -0
- scrollkit/simulator/fonts/viii-bold.bdf +2673 -0
- scrollkit/simulator/fonts/viii.bdf +2659 -0
- scrollkit/simulator/terminalio/__init__.py +20 -0
- scrollkit/utils/__init__.py +1 -0
- scrollkit/utils/color_utils.py +54 -0
- scrollkit/utils/diagnostics.py +227 -0
- scrollkit/utils/error_handler.py +347 -0
- scrollkit/utils/system_utils.py +245 -0
- scrollkit/utils/url_utils.py +46 -0
- scrollkit/web/__init__.py +6 -0
- scrollkit/web/settings_server.py +328 -0
- scrollkit/web/wifi_setup.py +331 -0
- scrollkit-0.8.3.dist-info/METADATA +248 -0
- scrollkit-0.8.3.dist-info/RECORD +111 -0
- scrollkit-0.8.3.dist-info/WHEEL +5 -0
- scrollkit-0.8.3.dist-info/licenses/LICENSE +31 -0
- scrollkit-0.8.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026 Michael Winslow Czeiszperger
|
|
2
|
+
"""CircuitPython displayio.Palette equivalent."""
|
|
3
|
+
|
|
4
|
+
from ..core.color_utils import rgb565_to_rgb888, rgb888_to_rgb565
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Palette:
|
|
8
|
+
"""Color palette for indexed color display.
|
|
9
|
+
|
|
10
|
+
Stores a collection of colors that can be referenced by index.
|
|
11
|
+
Compatible with CircuitPython's displayio.Palette API.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, color_count):
|
|
15
|
+
"""Initialize palette with specified number of colors.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
color_count: Maximum number of colors in palette
|
|
19
|
+
"""
|
|
20
|
+
self._color_count = color_count
|
|
21
|
+
self._colors = [None] * color_count
|
|
22
|
+
self._transparent = [False] * color_count
|
|
23
|
+
|
|
24
|
+
def __len__(self):
|
|
25
|
+
"""Get number of colors in palette."""
|
|
26
|
+
return self._color_count
|
|
27
|
+
|
|
28
|
+
def __setitem__(self, index, color):
|
|
29
|
+
"""Set a color in the palette.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
index: Color index (0 to color_count-1)
|
|
33
|
+
color: Color value as RGB565 integer or RGB888 tuple
|
|
34
|
+
"""
|
|
35
|
+
if not 0 <= index < self._color_count:
|
|
36
|
+
raise IndexError(f"Palette index {index} out of range")
|
|
37
|
+
|
|
38
|
+
if isinstance(color, (list, tuple)):
|
|
39
|
+
# Convert RGB888 tuple to RGB565
|
|
40
|
+
if len(color) >= 3:
|
|
41
|
+
self._colors[index] = rgb888_to_rgb565(color[0], color[1], color[2])
|
|
42
|
+
else:
|
|
43
|
+
raise ValueError("Color tuple must have at least 3 values")
|
|
44
|
+
else:
|
|
45
|
+
# displayio palettes take 24-bit RGB888 integers (0xRRGGBB). Do NOT
|
|
46
|
+
# guess RGB565-vs-RGB888 by magnitude: colors with a zero red byte
|
|
47
|
+
# (e.g. green 0x00FF00, blue 0x0000FF) are <= 0xFFFF and would be
|
|
48
|
+
# mis-read as RGB565, rendering green as yellow, blue as purple, etc.
|
|
49
|
+
r = (color >> 16) & 0xFF
|
|
50
|
+
g = (color >> 8) & 0xFF
|
|
51
|
+
b = color & 0xFF
|
|
52
|
+
self._colors[index] = rgb888_to_rgb565(r, g, b)
|
|
53
|
+
|
|
54
|
+
def __getitem__(self, index):
|
|
55
|
+
"""Get a color from the palette.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
index: Color index
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Color value as RGB565 integer
|
|
62
|
+
"""
|
|
63
|
+
if not 0 <= index < self._color_count:
|
|
64
|
+
raise IndexError(f"Palette index {index} out of range")
|
|
65
|
+
|
|
66
|
+
color = self._colors[index]
|
|
67
|
+
return 0 if color is None else color
|
|
68
|
+
|
|
69
|
+
def make_transparent(self, index):
|
|
70
|
+
"""Make a palette entry transparent.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
index: Color index to make transparent
|
|
74
|
+
"""
|
|
75
|
+
if not 0 <= index < self._color_count:
|
|
76
|
+
raise IndexError(f"Palette index {index} out of range")
|
|
77
|
+
|
|
78
|
+
self._transparent[index] = True
|
|
79
|
+
|
|
80
|
+
def make_opaque(self, index):
|
|
81
|
+
"""Make a palette entry opaque.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
index: Color index to make opaque
|
|
85
|
+
"""
|
|
86
|
+
if not 0 <= index < self._color_count:
|
|
87
|
+
raise IndexError(f"Palette index {index} out of range")
|
|
88
|
+
|
|
89
|
+
self._transparent[index] = False
|
|
90
|
+
|
|
91
|
+
def is_transparent(self, index):
|
|
92
|
+
"""Check if a palette entry is transparent.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
index: Color index to check
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
True if transparent, False otherwise
|
|
99
|
+
"""
|
|
100
|
+
if not 0 <= index < self._color_count:
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
return self._transparent[index]
|
|
104
|
+
|
|
105
|
+
def get_rgb888(self, index):
|
|
106
|
+
"""Get a color as RGB888 tuple.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
index: Color index
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
(r, g, b) tuple in 0-255 range
|
|
113
|
+
"""
|
|
114
|
+
color565 = self[index]
|
|
115
|
+
return rgb565_to_rgb888(color565)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026 Michael Winslow Czeiszperger
|
|
2
|
+
"""CircuitPython displayio.TileGrid equivalent."""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TileGrid:
|
|
6
|
+
"""TileGrid arranges bitmap tiles on screen.
|
|
7
|
+
|
|
8
|
+
A TileGrid is a grid of tiles that are sourced from a bitmap.
|
|
9
|
+
Each tile can be individually positioned and colored using a palette.
|
|
10
|
+
Compatible with CircuitPython's displayio.TileGrid API.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, bitmap, *, pixel_shader, width=1, height=1,
|
|
14
|
+
tile_width=None, tile_height=None, default_tile=0, x=0, y=0):
|
|
15
|
+
"""Initialize TileGrid.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
bitmap: Source bitmap containing tile graphics
|
|
19
|
+
pixel_shader: Palette to use for coloring
|
|
20
|
+
width: Number of tiles wide (default 1)
|
|
21
|
+
height: Number of tiles high (default 1)
|
|
22
|
+
tile_width: Width of each tile in pixels (default: bitmap width)
|
|
23
|
+
tile_height: Height of each tile in pixels (default: bitmap height)
|
|
24
|
+
default_tile: Default tile index (default 0)
|
|
25
|
+
x: X position of grid (default 0)
|
|
26
|
+
y: Y position of grid (default 0)
|
|
27
|
+
"""
|
|
28
|
+
self.bitmap = bitmap
|
|
29
|
+
self.pixel_shader = pixel_shader
|
|
30
|
+
self.width = width
|
|
31
|
+
self.height = height
|
|
32
|
+
|
|
33
|
+
# Set tile dimensions
|
|
34
|
+
if tile_width is None:
|
|
35
|
+
self.tile_width = bitmap.width
|
|
36
|
+
else:
|
|
37
|
+
self.tile_width = tile_width
|
|
38
|
+
|
|
39
|
+
if tile_height is None:
|
|
40
|
+
self.tile_height = bitmap.height
|
|
41
|
+
else:
|
|
42
|
+
self.tile_height = tile_height
|
|
43
|
+
|
|
44
|
+
# Calculate tiles per row in bitmap
|
|
45
|
+
self._tiles_per_row = bitmap.width // self.tile_width
|
|
46
|
+
|
|
47
|
+
# Initialize tile indices
|
|
48
|
+
self._tiles = [[default_tile for _ in range(width)] for _ in range(height)]
|
|
49
|
+
|
|
50
|
+
# Position and visibility
|
|
51
|
+
self.x = x
|
|
52
|
+
self.y = y
|
|
53
|
+
self.hidden = False
|
|
54
|
+
self._transpose_xy = False
|
|
55
|
+
self._flip_x = False
|
|
56
|
+
self._flip_y = False
|
|
57
|
+
|
|
58
|
+
def __setitem__(self, index, tile_index):
|
|
59
|
+
"""Set tile at given position.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
index: (x, y) tuple or flat index
|
|
63
|
+
tile_index: Index of tile in bitmap
|
|
64
|
+
"""
|
|
65
|
+
if isinstance(index, tuple):
|
|
66
|
+
x, y = index
|
|
67
|
+
if not (0 <= x < self.width and 0 <= y < self.height):
|
|
68
|
+
raise IndexError(f"Tile index ({x}, {y}) out of bounds")
|
|
69
|
+
else:
|
|
70
|
+
# Convert flat index to x, y
|
|
71
|
+
y = index // self.width
|
|
72
|
+
x = index % self.width
|
|
73
|
+
if not (0 <= index < self.width * self.height):
|
|
74
|
+
raise IndexError(f"Tile index {index} out of bounds")
|
|
75
|
+
|
|
76
|
+
self._tiles[y][x] = tile_index
|
|
77
|
+
|
|
78
|
+
def __getitem__(self, index):
|
|
79
|
+
"""Get tile at given position.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
index: (x, y) tuple or flat index
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Tile index
|
|
86
|
+
"""
|
|
87
|
+
if isinstance(index, tuple):
|
|
88
|
+
x, y = index
|
|
89
|
+
if not (0 <= x < self.width and 0 <= y < self.height):
|
|
90
|
+
raise IndexError(f"Tile index ({x}, {y}) out of bounds")
|
|
91
|
+
else:
|
|
92
|
+
# Convert flat index to x, y
|
|
93
|
+
y = index // self.width
|
|
94
|
+
x = index % self.width
|
|
95
|
+
if not (0 <= index < self.width * self.height):
|
|
96
|
+
raise IndexError(f"Tile index {index} out of bounds")
|
|
97
|
+
|
|
98
|
+
return self._tiles[y][x]
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def transpose_xy(self):
|
|
102
|
+
"""Get transpose_xy setting."""
|
|
103
|
+
return self._transpose_xy
|
|
104
|
+
|
|
105
|
+
@transpose_xy.setter
|
|
106
|
+
def transpose_xy(self, value):
|
|
107
|
+
"""Set whether to swap x and y coordinates."""
|
|
108
|
+
self._transpose_xy = bool(value)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def flip_x(self):
|
|
112
|
+
"""Get flip_x setting."""
|
|
113
|
+
return self._flip_x
|
|
114
|
+
|
|
115
|
+
@flip_x.setter
|
|
116
|
+
def flip_x(self, value):
|
|
117
|
+
"""Set whether to flip horizontally."""
|
|
118
|
+
self._flip_x = bool(value)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def flip_y(self):
|
|
122
|
+
"""Get flip_y setting."""
|
|
123
|
+
return self._flip_y
|
|
124
|
+
|
|
125
|
+
@flip_y.setter
|
|
126
|
+
def flip_y(self, value):
|
|
127
|
+
"""Set whether to flip vertically."""
|
|
128
|
+
self._flip_y = bool(value)
|
|
129
|
+
|
|
130
|
+
def get_tile_bitmap(self, tile_index):
|
|
131
|
+
"""Get bitmap data for a specific tile.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
tile_index: Index of tile to get
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Bitmap-like object with tile data
|
|
138
|
+
"""
|
|
139
|
+
# Calculate tile position in source bitmap
|
|
140
|
+
tile_x = (tile_index % self._tiles_per_row) * self.tile_width
|
|
141
|
+
tile_y = (tile_index // self._tiles_per_row) * self.tile_height
|
|
142
|
+
|
|
143
|
+
# Create a view of the tile data
|
|
144
|
+
# (In actual implementation, this would return a view of the bitmap data)
|
|
145
|
+
return (tile_x, tile_y, self.tile_width, self.tile_height)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def pixel_width(self):
|
|
149
|
+
"""Get total width in pixels."""
|
|
150
|
+
return self.width * self.tile_width
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def pixel_height(self):
|
|
154
|
+
"""Get total height in pixels."""
|
|
155
|
+
return self.height * self.tile_height
|