Skip to content

Commit 0f50d83

Browse files
authored
Merge pull request #2592 from makermelissa/main
Animated Message Board Working
2 parents b5eb256 + d00b87c commit 0f50d83

File tree

19 files changed

+1154
-0
lines changed

19 files changed

+1154
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import time
6+
from adafruit_matrixportal.matrix import Matrix
7+
from messageboard import MessageBoard
8+
from messageboard.fontpool import FontPool
9+
from messageboard.message import Message
10+
11+
matrix = Matrix(width=128, height=16, bit_depth=5)
12+
messageboard = MessageBoard(matrix)
13+
messageboard.set_background("images/background.bmp")
14+
fontpool = FontPool()
15+
fontpool.add_font("arial", "fonts/Arial-10.pcf")
16+
17+
while True:
18+
message = Message(fontpool.find_font("arial"), mask_color=0xFF00FF, opacity=0.8)
19+
message.add_image("images/maskedstar.bmp")
20+
message.add_text("Hello World!", color=0xFFFF00, x_offset=2, y_offset=2)
21+
messageboard.animate(message, "Scroll", "in_from_right")
22+
time.sleep(1)
23+
messageboard.animate(message, "Scroll", "out_to_left")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import time
6+
from adafruit_matrixportal.matrix import Matrix
7+
from messageboard import MessageBoard
8+
from messageboard.fontpool import FontPool
9+
from messageboard.message import Message
10+
11+
matrix = Matrix(width=128, height=16, bit_depth=5)
12+
messageboard = MessageBoard(matrix)
13+
messageboard.set_background("images/background.bmp")
14+
15+
fontpool = FontPool()
16+
fontpool.add_font("arial", "fonts/Arial-10.pcf")
17+
fontpool.add_font("comic", "fonts/Comic-10.pcf")
18+
fontpool.add_font("dejavu", "fonts/DejaVuSans-10.pcf")
19+
20+
message = Message(fontpool.find_font("terminal"), opacity=0.8)
21+
message.add_image("images/maskedstar.bmp")
22+
message.add_text("Hello World!", color=0xFFFF00, x_offset=2, y_offset=2)
23+
24+
message1 = Message(fontpool.find_font("dejavu"))
25+
26+
message2 = Message(fontpool.find_font("comic"), mask_color=0x00FF00)
27+
print("add blinka")
28+
message2.add_image("images/maskedblinka.bmp")
29+
print("add text")
30+
message2.add_text("CircuitPython", color=0xFFFF00, y_offset=-2)
31+
32+
message3 = Message(fontpool.find_font("dejavu"))
33+
message3.add_text("circuitpython.com", color=0xFF0000)
34+
35+
message4 = Message(fontpool.find_font("arial"))
36+
message4.add_text("Buy Electronics", color=0xFFFFFF)
37+
38+
while True:
39+
message1.clear()
40+
message1.add_text("Scroll Text In", color=0xFF0000)
41+
42+
messageboard.animate(message1, "Scroll", "in_from_left")
43+
time.sleep(1)
44+
message1.clear()
45+
message1.add_text("Change Messages")
46+
messageboard.animate(message1, "Static", "show")
47+
time.sleep(1)
48+
message1.clear()
49+
message1.add_text("And Scroll Out")
50+
51+
messageboard.animate(message1, "Static", "show")
52+
messageboard.animate(message1, "Scroll", "out_to_right")
53+
time.sleep(1)
54+
55+
message1.clear()
56+
message1.add_text("Or more effects like looping ", color=0xFFFF00)
57+
messageboard.animate(
58+
message1, "Split", "in_vertically"
59+
) # Split never completely joins
60+
messageboard.animate(
61+
message1, "Loop", "left"
62+
) # Text too high (probably from split)
63+
messageboard.animate(
64+
message1, "Static", "flash", count=3
65+
) # Flashes in weird positions
66+
67+
messageboard.animate(message1, "Split", "out_vertically")
68+
time.sleep(1)
69+
70+
messageboard.animate(message2, "Static", "fade_in")
71+
time.sleep(1)
72+
messageboard.animate(message2, "Static", "fade_out")
73+
74+
messageboard.set_background(0x00FF00)
75+
messageboard.animate(message3, "Scroll", "in_from_top")
76+
time.sleep(1)
77+
messageboard.animate(message3, "Scroll", "out_to_bottom")
78+
messageboard.set_background("images/background.bmp")
79+
80+
messageboard.animate(message4, "Scroll", "in_from_right")
81+
time.sleep(1)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
696 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import bitmaptools
6+
import displayio
7+
import adafruit_imageload
8+
from .doublebuffer import DoubleBuffer
9+
from .message import Message
10+
11+
12+
class MessageBoard:
13+
def __init__(self, matrix):
14+
self.fonts = {}
15+
self.display = matrix.display
16+
self._buffer_width = self.display.width * 2
17+
self._buffer_height = self.display.height * 2
18+
self._dbl_buf = DoubleBuffer(
19+
self.display, self._buffer_width, self._buffer_height
20+
)
21+
self._background = None
22+
self.set_background() # Set to black
23+
self._position = (0, 0)
24+
25+
def set_background(self, file_or_color=0x000000):
26+
"""The background image to a bitmap file."""
27+
if isinstance(file_or_color, str): # its a filenme:
28+
background, bg_shader = adafruit_imageload.load(file_or_color)
29+
self._dbl_buf.shader = bg_shader
30+
self._background = background
31+
elif isinstance(file_or_color, int):
32+
# Make a background color fill
33+
bg_shader = displayio.ColorConverter(
34+
input_colorspace=displayio.Colorspace.RGB565
35+
)
36+
background = displayio.Bitmap(
37+
self.display.width, self.display.height, 65535
38+
)
39+
background.fill(displayio.ColorConverter().convert(file_or_color))
40+
self._dbl_buf.shader = bg_shader
41+
self._background = background
42+
else:
43+
raise RuntimeError("Unknown type of background")
44+
45+
def animate(self, message, animation_class, animation_function, **kwargs):
46+
anim_class = __import__(
47+
f"{self.__module__}.animations.{animation_class.lower()}"
48+
)
49+
anim_class = getattr(anim_class, "animations")
50+
anim_class = getattr(anim_class, animation_class.lower())
51+
anim_class = getattr(anim_class, animation_class)
52+
animation = anim_class(
53+
self.display, self._draw, self._position
54+
) # Instantiate the class
55+
# Call the animation function and pass kwargs along with the message (positional)
56+
anim_func = getattr(animation, animation_function)
57+
anim_func(message, **kwargs)
58+
59+
def _draw(
60+
self,
61+
image,
62+
x,
63+
y,
64+
opacity=None,
65+
mask_color=0xFF00FF,
66+
blendmode=bitmaptools.BlendMode.Normal,
67+
post_draw_position=None,
68+
):
69+
"""Draws a message to the buffer taking its current settings into account.
70+
It also sets the current position and performs a swap.
71+
"""
72+
self._position = (x, y)
73+
buffer_x_offset = self._buffer_width - self.display.width
74+
buffer_y_offset = self._buffer_height - self.display.height
75+
76+
# Image can be a message in which case its properties will be used
77+
if isinstance(image, Message):
78+
if opacity is None:
79+
opacity = image.opacity
80+
mask_color = image.mask_color
81+
blendmode = image.blendmode
82+
image = image.buffer
83+
if opacity is None:
84+
opacity = 1.0
85+
86+
if mask_color > 65535:
87+
mask_color = displayio.ColorConverter().convert(mask_color)
88+
89+
# Blit the background
90+
bitmaptools.blit(
91+
self._dbl_buf.active_buffer,
92+
self._background,
93+
buffer_x_offset,
94+
buffer_y_offset,
95+
)
96+
97+
# If the image is wider than the display buffer, we need to shrink it
98+
if x + buffer_x_offset < 0:
99+
new_image = displayio.Bitmap(
100+
image.width - self.display.width, image.height, 65535
101+
)
102+
bitmaptools.blit(
103+
new_image,
104+
image,
105+
0,
106+
0,
107+
x1=self.display.width,
108+
y1=0,
109+
x2=image.width,
110+
y2=image.height,
111+
)
112+
x += self.display.width
113+
image = new_image
114+
115+
# If the image is taller than the display buffer, we need to shrink it
116+
if y + buffer_y_offset < 0:
117+
new_image = displayio.Bitmap(
118+
image.width, image.height - self.display.height, 65535
119+
)
120+
bitmaptools.blit(
121+
new_image,
122+
image,
123+
0,
124+
0,
125+
x1=0,
126+
y1=self.display.height,
127+
x2=image.width,
128+
y2=image.height,
129+
)
130+
y += self.display.height
131+
image = new_image
132+
133+
# Clear the foreground buffer
134+
foreground_buffer = displayio.Bitmap(
135+
self._buffer_width, self._buffer_height, 65535
136+
)
137+
foreground_buffer.fill(mask_color)
138+
139+
bitmaptools.blit(
140+
foreground_buffer, image, x + buffer_x_offset, y + buffer_y_offset
141+
)
142+
143+
# Blend the foreground buffer into the main buffer
144+
bitmaptools.alphablend(
145+
self._dbl_buf.active_buffer,
146+
self._dbl_buf.active_buffer,
147+
foreground_buffer,
148+
displayio.Colorspace.RGB565,
149+
1.0,
150+
opacity,
151+
blendmode=blendmode,
152+
skip_source2_index=mask_color,
153+
)
154+
self._dbl_buf.show()
155+
156+
# Allow for an override of the position after drawing (needed for split effects)
157+
if post_draw_position is not None and isinstance(post_draw_position, tuple):
158+
self._position = post_draw_position
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import time
6+
7+
8+
class Animation:
9+
def __init__(self, display, draw_callback, starting_position=(0, 0)):
10+
self._display = display
11+
self._position = starting_position
12+
self._draw = draw_callback
13+
14+
@staticmethod
15+
def _wait(start_time, duration):
16+
"""Uses time.monotonic() to wait from the start time for a specified duration"""
17+
while time.monotonic() < (start_time + duration):
18+
pass
19+
return time.monotonic()
20+
21+
def _get_centered_position(self, message):
22+
return int(self._display.width / 2 - message.buffer.width / 2), int(
23+
self._display.height / 2 - message.buffer.height / 2
24+
)

0 commit comments

Comments
 (0)