2020-01-26 23:17:36 +00:00
|
|
|
import time
|
|
|
|
import random
|
|
|
|
from board import TOTAL_DOTS, BOARD
|
|
|
|
|
|
|
|
class Pixo:
|
|
|
|
"""
|
|
|
|
Class that provides ease of life methods for
|
|
|
|
displaying content on the board.
|
|
|
|
|
|
|
|
During boot, `BOARD.auto_write` is set to False,
|
|
|
|
which prevents newly written data from immediately
|
|
|
|
updating the content. Call `BOARD.show()` whenever
|
|
|
|
you want content to be updated.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def _random_color(self):
|
|
|
|
"""
|
|
|
|
Generates a random value from 0-224
|
|
|
|
"""
|
|
|
|
return random.randrange(0, 7) * 32
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
"""
|
|
|
|
Fills the board with a 0 value and updates
|
|
|
|
the content, turning off all LEDs
|
|
|
|
"""
|
|
|
|
self.fill((0, 0, 0))
|
|
|
|
BOARD.show()
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
def fill(self, color):
|
|
|
|
"""
|
|
|
|
Fills the board with an RGB value, provided
|
|
|
|
via `color` as either a list or tuple
|
|
|
|
"""
|
|
|
|
BOARD.fill(color)
|
|
|
|
BOARD.show()
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
def fill_image(self, image, show=True, slow=False):
|
|
|
|
"""
|
|
|
|
Fills the board with the provided `image`,
|
|
|
|
which is a list of tuples containing RGB values
|
|
|
|
|
|
|
|
When `show` is False, the board will not be updated
|
|
|
|
automatically. This is useful if chaining commands
|
|
|
|
together (such as setting the image, and then forcing
|
|
|
|
a specific color for active pixels in the image)
|
|
|
|
|
|
|
|
When `slow` is True, the content is updated pixel
|
|
|
|
by pixel, rather than all at once
|
|
|
|
"""
|
|
|
|
for dot in range(TOTAL_DOTS):
|
|
|
|
BOARD[dot] = image[dot]
|
|
|
|
if slow and show:
|
|
|
|
BOARD.show()
|
|
|
|
if not slow and show:
|
|
|
|
BOARD.show()
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
def fill_random(self, slow=False):
|
|
|
|
"""
|
|
|
|
Fills the board with random RGB values
|
|
|
|
|
|
|
|
When `Slow` is True, the content is updated pixel
|
|
|
|
by pixel, rather than all at once
|
|
|
|
"""
|
|
|
|
for dot in range(TOTAL_DOTS):
|
|
|
|
BOARD[dot] = (
|
|
|
|
self._random_color(),
|
|
|
|
self._random_color(),
|
|
|
|
self._random_color()
|
|
|
|
)
|
|
|
|
if slow:
|
|
|
|
BOARD.show()
|
|
|
|
if not slow:
|
|
|
|
BOARD.show()
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
2020-01-27 00:18:07 +00:00
|
|
|
def blink_image(self, image, force=(), delay=0.3):
|
2020-01-26 23:17:36 +00:00
|
|
|
"""
|
|
|
|
Fills the board with the provided `image`,
|
|
|
|
which is a list of tuples containing RGB values
|
|
|
|
|
2020-01-27 00:18:07 +00:00
|
|
|
When `force` is set, it should be a tuple of
|
|
|
|
RGB values; it will override all colors on the
|
|
|
|
board that are active.
|
2020-01-26 23:17:36 +00:00
|
|
|
|
|
|
|
`delay` is a float of how many seconds to wait
|
|
|
|
before the board gets blanked out.
|
|
|
|
|
|
|
|
To blink multiple times, call this in a loop
|
|
|
|
"""
|
2020-01-27 00:20:07 +00:00
|
|
|
if len(force) == 0:
|
2020-01-27 00:18:07 +00:00
|
|
|
self.fill_image(image)
|
|
|
|
else:
|
|
|
|
self.fill_image(image, False).force_color(force)
|
2020-01-26 23:17:36 +00:00
|
|
|
time.sleep(delay)
|
|
|
|
self.fill((0, 0, 0))
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
def force_color(self, color):
|
|
|
|
for dot in range(TOTAL_DOTS):
|
|
|
|
if BOARD[dot] != (0, 0, 0) and BOARD[dot] != color:
|
|
|
|
BOARD[dot] = color
|
|
|
|
BOARD.show()
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
2020-01-27 19:47:13 +00:00
|
|
|
def transition_image_random(self, image, delay=0.2):
|
|
|
|
"""
|
|
|
|
Changes a random pixel to the value of that
|
|
|
|
pixel on a newly provided `image`.
|
|
|
|
|
|
|
|
`delay` is how many seconds to wait between
|
|
|
|
changing each pixel
|
|
|
|
|
|
|
|
Prevents the same random value from being
|
|
|
|
selected multiple times
|
|
|
|
"""
|
|
|
|
already_changed = []
|
2020-01-28 00:57:31 +00:00
|
|
|
|
|
|
|
if image == (0, 0, 0):
|
|
|
|
image = [(0, 0, 0) for _ in range(TOTAL_DOTS)]
|
|
|
|
|
2020-01-27 19:47:13 +00:00
|
|
|
while len(already_changed) < TOTAL_DOTS:
|
|
|
|
dot = random.randrange(0, TOTAL_DOTS)
|
2020-01-28 00:57:31 +00:00
|
|
|
if dot not in already_changed:
|
2020-01-27 19:47:13 +00:00
|
|
|
already_changed.append(dot)
|
|
|
|
|
2020-01-28 00:57:31 +00:00
|
|
|
if not BOARD[dot] == image[dot]:
|
|
|
|
BOARD[dot] = image[dot]
|
|
|
|
time.sleep(delay)
|
|
|
|
BOARD.show()
|
2020-01-27 19:47:13 +00:00
|
|
|
|
|
|
|
return self
|
|
|
|
|
2020-01-28 00:57:31 +00:00
|
|
|
def transition_image_dissolve(self, delay=0.09):
|
2020-01-27 19:47:13 +00:00
|
|
|
"""
|
|
|
|
Randomly sets pixels to black, giving the
|
|
|
|
appearance of it dissolving away into the ether
|
|
|
|
|
|
|
|
`delay` is how many seconds to wait between
|
|
|
|
changing each pixel
|
|
|
|
"""
|
|
|
|
return self.transition_image_random((0, 0, 0), delay)
|
|
|
|
|
2020-01-26 23:17:36 +00:00
|
|
|
# This doesn't give the desired cycle that a gaming keyboard would
|
|
|
|
# def color_cycle(self):
|
|
|
|
# for r in range(100, 200):
|
|
|
|
# for g in range(100, 200):
|
|
|
|
# for b in range(100, 200):
|
|
|
|
# print((r, g, b))
|
2020-01-27 19:47:13 +00:00
|
|
|
# self.fill((r, g, b))
|