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, PartialEq, Eq)]
68pub enum ColorInversion {
69    /// Normal colors.
70    Normal,
71    /// Inverted colors.
72    Inverted,
73}
74
75impl Default for ColorInversion {
76    fn default() -> Self {
77        Self::Normal
78    }
79}
80
81/// Vertical refresh order.
82#[derive(Copy, Clone, Debug, PartialEq, Eq)]
83pub enum VerticalRefreshOrder {
84    /// Refresh from top to bottom.
85    TopToBottom,
86    /// Refresh from bottom to top.
87    BottomToTop,
88}
89
90impl Default for VerticalRefreshOrder {
91    fn default() -> Self {
92        Self::TopToBottom
93    }
94}
95
96impl VerticalRefreshOrder {
97    /// Returns the opposite refresh order.
98    #[must_use]
99    pub const fn flip(self) -> Self {
100        match self {
101            Self::TopToBottom => Self::BottomToTop,
102            Self::BottomToTop => Self::TopToBottom,
103        }
104    }
105}
106
107/// Horizontal refresh order.
108#[derive(Copy, Clone, Debug, PartialEq, Eq)]
109pub enum HorizontalRefreshOrder {
110    /// Refresh from left to right.
111    LeftToRight,
112    /// Refresh from right to left.
113    RightToLeft,
114}
115
116impl Default for HorizontalRefreshOrder {
117    fn default() -> Self {
118        Self::LeftToRight
119    }
120}
121
122impl HorizontalRefreshOrder {
123    /// Returns the opposite refresh order.
124    #[must_use]
125    pub const fn flip(self) -> Self {
126        match self {
127            Self::LeftToRight => Self::RightToLeft,
128            Self::RightToLeft => Self::LeftToRight,
129        }
130    }
131}
132
133/// Display refresh order.
134///
135/// Defaults to left to right, top to bottom.
136#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
137pub struct RefreshOrder {
138    /// Vertical refresh order.
139    pub vertical: VerticalRefreshOrder,
140    /// Horizontal refresh order.
141    pub horizontal: HorizontalRefreshOrder,
142}
143
144impl RefreshOrder {
145    /// Creates a new refresh order.
146    pub const fn new(vertical: VerticalRefreshOrder, horizontal: HorizontalRefreshOrder) -> Self {
147        Self {
148            vertical,
149            horizontal,
150        }
151    }
152
153    /// Returns a refresh order with flipped vertical refresh order.
154    #[must_use]
155    pub const fn flip_vertical(self) -> Self {
156        Self {
157            vertical: self.vertical.flip(),
158            ..self
159        }
160    }
161
162    /// Returns a refresh order with flipped horizontal refresh order.
163    #[must_use]
164    pub const fn flip_horizontal(self) -> Self {
165        Self {
166            horizontal: self.horizontal.flip(),
167            ..self
168        }
169    }
170}
171
172/// Tearing effect output setting.
173#[derive(Copy, Clone, Debug, PartialEq, Eq)]
174pub enum TearingEffect {
175    /// Disable output.
176    Off,
177    /// Output vertical blanking information.
178    Vertical,
179    /// Output horizontal and vertical blanking information.
180    HorizontalAndVertical,
181}
182
183/// Subpixel order.
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185pub enum ColorOrder {
186    /// RGB subpixel order.
187    Rgb,
188    /// BGR subpixel order.
189    Bgr,
190}
191
192impl Default for ColorOrder {
193    fn default() -> Self {
194        Self::Rgb
195    }
196}