Adafruit_Learning_System_Gu.../QT_Py_Cube/cube.py
2022-09-07 11:26:30 -04:00

184 lines
5.9 KiB
Python

# SPDX-FileCopyrightText: 2022 Charlyn Gonda for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import adafruit_dotstar
from adafruit_led_animation.animation.rainbowchase import RainbowChase
from adafruit_led_animation.color import AMBER, JADE, CYAN, GOLD, PINK
from adafruit_pixel_framebuf import PixelFramebuffer
class Cube():
def __init__(
self,
top_cin,
top_din,
side_panels_cin,
side_panels_din,
bottom_cin,
bottom_din):
# static numbers
self.num_pixels = 64*4
self.num_pixels_topbottom = 64
self.pixel_width = 8*4
self.pixel_height = 8
# top pixels
top_pixels = adafruit_dotstar.DotStar(
top_cin, top_din, self.num_pixels_topbottom,
brightness=0.03, auto_write=False)
self.pixel_framebuf_top = PixelFramebuffer(
top_pixels,
self.pixel_height,
self.pixel_height,
rotation=1,
alternating=False,
)
# side pixels
self.side_pixels = adafruit_dotstar.DotStar(
side_panels_cin, side_panels_din, self.num_pixels,
brightness=0.03, auto_write=False)
self.pixel_framebuf_sides = PixelFramebuffer(
self.side_pixels,
self.pixel_height,
self.pixel_width,
rotation=1,
alternating=False,
reverse_y=True,
reverse_x=False
)
self.rainbow_sides = RainbowChase(
self.side_pixels, speed=0.1, size=3, spacing=6)
# bottom pixels
pixels_bottom = adafruit_dotstar.DotStar(
bottom_cin, bottom_din, self.num_pixels_topbottom,
brightness=0.03, auto_write=False)
self.pixel_framebuf_bottom = PixelFramebuffer(
pixels_bottom,
self.pixel_height,
self.pixel_height,
rotation=0,
alternating=False,
reverse_y=False,
reverse_x=True
)
# scrolling word state vars
self.last_color_time = -1
self.color_wait = 1
self.word = ''
self.total_scroll_len = 0
self.scroll_x_pos = -self.pixel_width
self.color_idx = 0
self.color_list = [AMBER, JADE, CYAN, PINK, GOLD]
self.done_scrolling = False
# whether or not the cube is already clear
self.clear = False
# top pixel vars
self.top_pixel_coords = []
self.top_pixel_color = CYAN
# upside down mode
self.bottom_last = -1
self.bottom_wait = 1
self.bottom_squares = [[0, 0, 8, 8], [
1, 1, 6, 6], [2, 2, 4, 4], [3, 3, 2, 2]]
self.bottom_squares_idx = 0
def update(self, word, color, coords):
self.word = word
self.total_scroll_len = (len(self.word) * 5) + len(self.word)
self.top_pixel_coords = coords
self.top_pixel_color = color
def scroll_word_and_update_top(self):
if self.scroll_x_pos >= self.total_scroll_len:
self.scroll_x_pos = -self.pixel_width
self.clear_cube()
self.done_scrolling = True
else:
self.done_scrolling = False
self.clear = False
self.__scroll_framebuf(self.word, self.scroll_x_pos, 0)
self.__display_top_pixels()
self.scroll_x_pos = self.scroll_x_pos + 1
def clear_cube(self, clear_top=False):
if not self.clear:
self.pixel_framebuf_sides.fill(0)
self.pixel_framebuf_sides.display()
self.side_pixels.fill(0)
self.side_pixels.show()
self.pixel_framebuf_bottom.fill(0)
self.pixel_framebuf_bottom.display()
if clear_top:
self.pixel_framebuf_top.fill(0)
self.pixel_framebuf_top.display()
self.clear = True
def upside_down_mode(self):
self.clear_cube(True)
self.rainbow_sides.animate()
now = time.monotonic()
self.__bottom_square_animation(now)
def waiting_mode(self):
self.pixel_framebuf_top.pixel(3, 3, CYAN)
self.pixel_framebuf_top.pixel(4, 4, PINK)
self.pixel_framebuf_top.display()
def __bottom_square_animation(self, now):
self.pixel_framebuf_bottom.fill(0)
color_int = self._rgb_to_int(CYAN)
if now > self.bottom_last + self.bottom_wait:
self.__coord_wrap()
self.bottom_last = now
x, y, w, h = self.bottom_squares[self.bottom_squares_idx]
self.pixel_framebuf_bottom.rect(x, y, w, h, color_int)
self.pixel_framebuf_bottom.display()
def __coord_wrap(self):
self.bottom_squares_idx = self.bottom_squares_idx + 1
if self.bottom_squares_idx >= len(self.bottom_squares):
self.bottom_squares_idx = 0
def __display_top_pixels(self):
self.pixel_framebuf_top.fill(0)
for coord in self.top_pixel_coords:
x, y = coord.split(":")
self.pixel_framebuf_top.pixel(int(x), int(y), self.top_pixel_color)
self.pixel_framebuf_top.display()
def __scroll_framebuf(self, word, shift_x, shift_y):
self.pixel_framebuf_sides.fill(0)
color = self.__next_color()
color_int = self._rgb_to_int(color)
# negate x so that the word can be shown from left to right
self.pixel_framebuf_sides.text(word, -shift_x, shift_y, color_int)
self.pixel_framebuf_sides.display()
def __next_color(self):
if self.color_idx >= len(self.color_list):
self.color_idx = 0
result = self.color_list[self.color_idx]
now = time.monotonic()
if now >= self.last_color_time + self.color_wait:
self.color_idx = self.color_idx + 1
self.last_color_time = now
return result
@staticmethod
def _rgb_to_int(rgb):
return rgb[0] << 16 | rgb[1] << 8 | rgb[2]