Skip to main content

lcd_async/
options.rs

1//! [ModelOptions] and other helper types.
2
3use crate::models::Model;
4
5mod orientation;
6pub(crate) use orientation::MemoryMapping;
7pub use orientation::{InvalidAngleError, Orientation, Rotation};
8
9/// [ModelOptions] are passed to the [`init`](Model::init) method of [Model]
10/// implementations.
11#[derive(Clone)]
12#[non_exhaustive]
13pub struct ModelOptions {
14    /// Subpixel order.
15    pub color_order: ColorOrder,
16    /// Initial display orientation.
17    pub orientation: Orientation,
18    /// Whether to invert colors for this display/model (INVON)
19    pub invert_colors: ColorInversion,
20    /// Display refresh order.
21    pub refresh_order: RefreshOrder,
22    /// Display size (w, h) for given display.
23    pub display_size: (u16, u16),
24    /// Display offset (x, y) for given display.
25    pub display_offset: (u16, u16),
26}
27
28impl ModelOptions {
29    /// Creates model options for the entire framebuffer.
30    pub fn full_size<M: Model>() -> Self {
31        Self {
32            color_order: ColorOrder::default(),
33            orientation: Orientation::default(),
34            invert_colors: ColorInversion::default(),
35            refresh_order: RefreshOrder::default(),
36            display_size: M::FRAMEBUFFER_SIZE,
37            display_offset: (0, 0),
38        }
39    }
40
41    /// Creates model options for the given size and offset.
42    pub fn with_all(display_size: (u16, u16), display_offset: (u16, u16)) -> Self {
43        Self {
44            color_order: ColorOrder::default(),
45            orientation: Orientation::default(),
46            invert_colors: ColorInversion::default(),
47            refresh_order: RefreshOrder::default(),
48            display_size,
49            display_offset,
50        }
51    }
52
53    /// Returns the display size based on current orientation and display options.
54    ///
55    /// Used by models.
56    #[allow(dead_code)]
57    pub(crate) fn display_size(&self) -> (u16, u16) {
58        if self.orientation.rotation.is_horizontal() {
59            self.display_size
60        } else {
61            (self.display_size.1, self.display_size.0)
62        }
63    }
64}
65
66/// Color inversion.
67#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69pub enum ColorInversion {
70    /// Normal colors.
71    #[default]
72    Normal,
73    /// Inverted colors.
74    Inverted,
75}
76
77/// Vertical refresh order.
78#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum VerticalRefreshOrder {
81    /// Refresh from top to bottom.
82    #[default]
83    TopToBottom,
84    /// Refresh from bottom to top.
85    BottomToTop,
86}
87
88impl VerticalRefreshOrder {
89    /// Returns the opposite refresh order.
90    #[must_use]
91    pub const fn flip(self) -> Self {
92        match self {
93            Self::TopToBottom => Self::BottomToTop,
94            Self::BottomToTop => Self::TopToBottom,
95        }
96    }
97}
98
99/// Horizontal refresh order.
100#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub enum HorizontalRefreshOrder {
103    /// Refresh from left to right.
104    #[default]
105    LeftToRight,
106    /// Refresh from right to left.
107    RightToLeft,
108}
109
110impl HorizontalRefreshOrder {
111    /// Returns the opposite refresh order.
112    #[must_use]
113    pub const fn flip(self) -> Self {
114        match self {
115            Self::LeftToRight => Self::RightToLeft,
116            Self::RightToLeft => Self::LeftToRight,
117        }
118    }
119}
120
121/// Display refresh order.
122///
123/// Defaults to left to right, top to bottom.
124#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126pub struct RefreshOrder {
127    /// Vertical refresh order.
128    pub vertical: VerticalRefreshOrder,
129    /// Horizontal refresh order.
130    pub horizontal: HorizontalRefreshOrder,
131}
132
133impl RefreshOrder {
134    /// Creates a new refresh order.
135    pub const fn new(vertical: VerticalRefreshOrder, horizontal: HorizontalRefreshOrder) -> Self {
136        Self {
137            vertical,
138            horizontal,
139        }
140    }
141
142    /// Returns a refresh order with flipped vertical refresh order.
143    #[must_use]
144    pub const fn flip_vertical(self) -> Self {
145        Self {
146            vertical: self.vertical.flip(),
147            ..self
148        }
149    }
150
151    /// Returns a refresh order with flipped horizontal refresh order.
152    #[must_use]
153    pub const fn flip_horizontal(self) -> Self {
154        Self {
155            horizontal: self.horizontal.flip(),
156            ..self
157        }
158    }
159}
160
161/// Tearing effect output setting.
162#[derive(Copy, Clone, Debug, PartialEq, Eq)]
163#[cfg_attr(feature = "defmt", derive(defmt::Format))]
164pub enum TearingEffect {
165    /// Disable output.
166    Off,
167    /// Output vertical blanking information.
168    Vertical,
169    /// Output horizontal and vertical blanking information.
170    HorizontalAndVertical,
171}
172
173/// Subpixel order.
174#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
176pub enum ColorOrder {
177    /// RGB subpixel order.
178    #[default]
179    Rgb,
180    /// BGR subpixel order.
181    Bgr,
182}