tm1637_embedded_hal/options/
scroll.rs

1//! Scroll animation settings.
2
3use crate::TM1637;
4
5mod direction;
6mod style;
7
8use super::{windows::windows, DisplayOptions};
9pub use direction::ScrollDirection;
10pub use style::ScrollStyle;
11
12/// High-level API for scroll animations.
13#[derive(Debug)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct ScrollDisplayOptions<'d, const N: usize, T, CLK, DIO, DELAY, I, D> {
16    options: DisplayOptions<'d, N, T, CLK, DIO, DELAY, I, D>,
17    delay_ms: u32,
18    direction: ScrollDirection,
19    style: ScrollStyle,
20}
21
22impl<'d, const N: usize, T, CLK, DIO, DELAY, I, M>
23    ScrollDisplayOptions<'d, N, T, CLK, DIO, DELAY, I, M>
24{
25    /// Create a new [`ScrollDisplayOptions`] instance.
26    pub const fn new(
27        options: DisplayOptions<'d, N, T, CLK, DIO, DELAY, I, M>,
28        delay_ms: u32,
29        direction: ScrollDirection,
30        style: ScrollStyle,
31    ) -> Self {
32        Self {
33            options,
34            delay_ms,
35            direction,
36            style,
37        }
38    }
39
40    /// Create a new [`ScrollDisplayOptions`] instance with default settings.
41    pub const fn new_with_defaults(
42        options: DisplayOptions<'d, N, T, CLK, DIO, DELAY, I, M>,
43    ) -> Self {
44        Self::new(
45            options,
46            500,
47            ScrollDirection::RightToLeft,
48            ScrollStyle::Circular,
49        )
50    }
51
52    /// Set the delay in milliseconds between each animation step.
53    pub const fn delay_ms(mut self, delay_ms: u32) -> Self {
54        self.delay_ms = delay_ms;
55        self
56    }
57
58    /// Set the animation direction.
59    pub const fn direction(mut self, direction: ScrollDirection) -> Self {
60        self.direction = direction;
61        self
62    }
63
64    /// Set the animation direction to [`ScrollDirection::LeftToRight`].
65    pub const fn left_to_right(mut self) -> Self {
66        self.direction = ScrollDirection::LeftToRight;
67        self
68    }
69
70    /// Set the animation direction to [`ScrollDirection::RightToLeft`].
71    pub const fn right_to_left(mut self) -> Self {
72        self.direction = ScrollDirection::RightToLeft;
73        self
74    }
75
76    /// Set the animation style.
77    pub const fn style(mut self, style: ScrollStyle) -> Self {
78        self.style = style;
79        self
80    }
81
82    /// Set the animation style to [`ScrollStyle::Circular`].
83    pub const fn circular(mut self) -> Self {
84        self.style = ScrollStyle::Circular;
85        self
86    }
87
88    /// Set the animation style to [`ScrollStyle::Linear`].
89    pub const fn linear(mut self) -> Self {
90        self.style = ScrollStyle::Linear;
91        self
92    }
93
94    /// Finish setting the scroll animation.
95    pub fn finish(
96        self,
97    ) -> Scroller<
98        'd,
99        N,
100        T,
101        CLK,
102        DIO,
103        DELAY,
104        impl Iterator<Item = impl DoubleEndedIterator<Item = u8> + ExactSizeIterator>,
105        M,
106    >
107    where
108        I: DoubleEndedIterator<Item = u8> + ExactSizeIterator,
109    {
110        let iter =
111            windows::<N>(self.options.iter, self.direction, self.style).map(|i| i.into_iter());
112
113        Scroller {
114            device: self.options.device,
115            inner_iter_len: N,
116            position: self.options.position,
117            delay_ms: self.delay_ms,
118            iter,
119            _flip: self.options._flip,
120        }
121    }
122}
123
124/// Scroll animation.
125///
126/// Responsible for running the animation.
127#[derive(Debug)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct Scroller<'d, const N: usize, T, CLK, DIO, DELAY, I, M> {
130    device: &'d mut TM1637<N, T, CLK, DIO, DELAY>,
131    inner_iter_len: usize,
132    position: usize,
133    delay_ms: u32,
134    iter: I,
135    _flip: M,
136}
137
138impl<'d, const N: usize, T, CLK, DIO, DELAY, I, M> Scroller<'d, N, T, CLK, DIO, DELAY, I, M> {
139    /// Create a new [`Scroller`] instance.
140    pub const fn new(
141        device: &'d mut TM1637<N, T, CLK, DIO, DELAY>,
142        inner_iter_len: usize,
143        position: usize,
144        delay_ms: u32,
145        iter: I,
146        _flip: M,
147    ) -> Self {
148        Self {
149            device,
150            inner_iter_len,
151            position,
152            delay_ms,
153            iter,
154            _flip,
155        }
156    }
157}
158
159#[::duplicate::duplicate_item(
160    module        async     await               Token                     DelayTrait                             ScrollIter;
161    [asynch]      [async]   [await.identity()]  [crate::tokens::Async]    [::embedded_hal_async::delay::DelayNs] [::futures::Stream];
162    [blocking]    []        [identity()]        [crate::tokens::Blocking] [::embedded_hal::delay::DelayNs]       [Iterator];
163)]
164mod module {
165    use ::embedded_hal::digital::OutputPin;
166    #[allow(unused_imports)]
167    use ::futures::StreamExt as _;
168
169    use crate::{
170        align::{Align, Aligned},
171        maybe_flipped::MaybeFlipped,
172        ConditionalInputPin, Error, Identity,
173    };
174
175    use super::Scroller;
176
177    #[::duplicate::duplicate_item(
178        NUM_POS ;
179        [4] ;
180        [6] ;
181    )]
182    impl<'d, CLK, DIO, DELAY, ERR, I, M, InI> Scroller<'d, NUM_POS, Token, CLK, DIO, DELAY, I, M>
183    where
184        ERR: 'd,
185        CLK: OutputPin<Error = ERR>,
186        DIO: OutputPin<Error = ERR> + ConditionalInputPin<ERR>,
187        DELAY: DelayTrait,
188        I: Iterator<Item = InI> + 'd,
189        InI: DoubleEndedIterator<Item = u8> + ExactSizeIterator + 'd,
190        M: MaybeFlipped<NUM_POS> + 'd,
191    {
192        fn _calculate(
193            position: usize,
194            iter: I,
195            inner_iter_len: usize,
196        ) -> (usize, impl Iterator<Item = impl Iterator<Item = u8>>) {
197            let original_position = position;
198
199            let iter = iter.map(move |item| {
200                let (position, bytes) = M::calculate(original_position, item.into_iter());
201                let (_, bytes) = Align::<NUM_POS>::align(position, bytes);
202
203                bytes
204            });
205
206            let position = M::position(original_position, inner_iter_len);
207            let position = Align::<NUM_POS>::position(position);
208
209            (position, iter)
210        }
211
212        /// Release the `device` and return the calculated position and bytes.
213        pub fn calculate(self) -> (usize, impl Iterator<Item = impl Iterator<Item = u8>>) {
214            Self::_calculate(self.position, self.iter, self.inner_iter_len)
215        }
216
217        /// Return the scroll animation as an iterator.
218        pub fn steps(self) -> impl ScrollIter<Item = Result<(), Error<ERR>>> + 'd {
219            let (position, iter) = Self::_calculate(self.position, self.iter, self.inner_iter_len);
220
221            self.device.scroll(position, self.delay_ms, iter)
222        }
223
224        /// Run the scroll animation and return the number of steps.
225        pub async fn run(self) -> usize {
226            self.steps().count().await
227        }
228    }
229}