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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! [super::Display] builder module

use display_interface::WriteOnlyDataCommand;
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};

use crate::{error::InitError, models::Model, ColorOrder, Display, ModelOptions, Orientation};

///
/// Constructor helper for creating [Display] instances
/// Exposes all possible display options
///
pub struct Builder<DI, MODEL>
where
    DI: WriteOnlyDataCommand,
    MODEL: Model,
{
    di: DI,
    model: MODEL,
    options: ModelOptions,
}

impl<DI, MODEL> Builder<DI, MODEL>
where
    DI: WriteOnlyDataCommand,
    MODEL: Model,
{
    ///
    /// Constructs a new builder from given [WriteOnlyDataCommand], [Model]
    /// and [ModelOptions]. For use by [Model] helpers, not public
    ///
    pub(crate) fn new(di: DI, model: MODEL, options: ModelOptions) -> Self {
        Self { di, model, options }
    }

    ///
    /// Constructs a new builder for given [Model] using the model's
    /// `default_options`
    ///
    pub fn with_model(di: DI, model: MODEL) -> Self {
        Self {
            di,
            model,
            options: MODEL::default_options(),
        }
    }

    ///
    /// Sets the invert color flag
    ///
    pub fn with_invert_colors(mut self, invert_colors: bool) -> Self {
        self.options.invert_colors = invert_colors;
        self
    }

    ///
    /// Sets the [ColorOrder]
    ///
    pub fn with_color_order(mut self, color_order: ColorOrder) -> Self {
        self.options.color_order = color_order;
        self
    }

    ///
    /// Sets the [Orientation]
    ///
    pub fn with_orientation(mut self, orientation: Orientation) -> Self {
        self.options.orientation = orientation;
        self
    }

    ///
    /// Inverts vertical refresh
    ///
    pub fn with_invert_vertical_refresh(mut self, invert: bool) -> Self {
        self.options.invert_vertical_refresh = invert;
        self
    }

    ///
    /// Inverts horizontal refresh
    ///
    pub fn with_invert_horizontal_refresh(mut self, invert: bool) -> Self {
        self.options.invert_horizontal_refresh = invert;
        self
    }

    ///
    /// Sets the display size
    ///
    pub fn with_display_size(mut self, width: u16, height: u16) -> Self {
        self.options.display_size = (width, height);
        self
    }

    ///
    /// Sets the framebuffer size
    ///
    pub fn with_framebuffer_size(mut self, width: u16, height: u16) -> Self {
        self.options.framebuffer_size = (width, height);
        self
    }

    ///
    /// Sets the window offset handler
    ///
    pub fn with_window_offset_handler(
        mut self,
        window_offset_handler: fn(_: &ModelOptions) -> (u16, u16),
    ) -> Self {
        self.options.window_offset_handler = window_offset_handler;
        self
    }

    ///
    /// Consumes the builder to create a new [Display] with an optional reset [OutputPin].
    /// Blocks using the provided [DelayUs] `delay_source` to perform the display initialization.
    /// ### WARNING
    /// The reset pin needs to be in *high* state in order for the display to operate.
    /// If it wasn't provided the user needs to ensure this is the case.
    ///
    pub fn init<RST>(
        self,
        delay_source: &mut impl DelayUs<u32>,
        rst: Option<RST>,
    ) -> Result<Display<DI, MODEL, RST>, InitError<RST::Error>>
    where
        RST: OutputPin,
    {
        let options = self.options;
        let madctl = options.madctl();

        let mut display = Display {
            di: self.di,
            model: self.model,
            rst,
            options,
            madctl,
        };

        display.init(delay_source)?;

        Ok(display)
    }
}