1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Support for scrolling sequences of 5×5 images horizontally.
//!
//! Each kind of scrolling sequence is represented by a type implementing
//! [`Animate`] (for controlling the sequence) and [`Render`] (for displaying
//! it).
//!
//! To create a new kind of scrolling sequence, make a new implementation of
//! [`Scrollable`]. It can implement `Render::brightness_at` by delegating to
//! `self.current_brightness_at()`. [`Animate`] will be implemented
//! automatically.
//!
//! See [`scrolling_text`] for scrolling text strings.
//!
//! See [`scrolling_statics`] for scrolling arbitrary images.
//!
//! [`scrolling_text`]: crate::scrolling_text
//! [`scrolling_statics`]: crate::scrolling_statics
use tiny_led_matrix::Render;
/// The state of an animation.
pub trait Animate {
/// Say whether the animation has completed.
fn is_finished(&self) -> bool;
/// Reset the animation to the beginning.
fn reset(&mut self);
/// Advance to the next step of the animation.
///
/// If the animation has completed, does nothing.
fn tick(&mut self);
}
/// Data needed to record the state of a scrolling animation.
///
/// Implementations of [`Scrollable`] should contain one of these and make it
/// available via `state()` and `state_mut()`.
#[derive(Default)]
#[derive(Copy, Clone, Debug)]
pub struct ScrollingState {
// index of the character being scrolled on, or about to be scrolled on
index: usize,
// 0..5
pixel: usize,
}
impl ScrollingState {
/// Reset the state to the beginning.
pub fn reset(&mut self) {
self.index = 0;
self.pixel = 0;
}
/// Advance the state by one tick.
pub fn tick(&mut self) {
self.pixel += 1;
if self.pixel == 5 {
self.pixel = 0;
self.index += 1;
}
}
}
/// A horizontally scrolling sequence of 5×5 images.
///
/// `Scrollable`s automatically implement [`Animate`].
///
/// When a `Scrollable` also implements `Render`, the rendered image is the
/// current state of the animation.
pub trait Scrollable {
/// The type of the underlying 5×5 images.
type Subimage: Render;
/// The number of underlying images.
fn length(&self) -> usize;
/// A [`ScrollingState`] indicating the current point in the animation.
fn state(&self) -> &ScrollingState;
/// A [`ScrollingState`] indicating the current point in the animation, as
/// a mutable reference.
fn state_mut(&mut self) -> &mut ScrollingState;
/// A reference to the underlying image at the specified index.
fn subimage(&self, index: usize) -> &Self::Subimage;
/// Returns the brightness value for a single LED in the current state.
///
/// Use this to implement `Render`.
fn current_brightness_at(&self, x: usize, y: usize) -> u8 {
if self.state().index > self.length() {return 0}
let state = self.state();
let (index, x) = if x + state.pixel < 5 {
if state.index == 0 {return 0}
(state.index - 1, x + state.pixel)
} else {
if state.index == self.length() {return 0}
(state.index, x + state.pixel - 5)
};
self.subimage(index).brightness_at(x, y)
}
}
impl<T : Scrollable> Animate for T {
fn is_finished(&self) -> bool {
self.state().index > self.length()
}
fn reset(&mut self) {
self.state_mut().reset();
}
fn tick(&mut self) {
if !self.is_finished() {
self.state_mut().tick();
}
}
}