cadmus_core/view/rotation_values/
mod.rs

1use crate::color::{BLACK, GRAY07, WHITE};
2use crate::context::Context;
3use crate::device::CURRENT_DEVICE;
4use crate::font::{font_from_style, Fonts, DISPLAY_STYLE, NORMAL_STYLE};
5use crate::framebuffer::{Framebuffer, UpdateMode};
6use crate::geom::{Point, Rectangle};
7use crate::gesture::GestureEvent;
8use crate::view::{Bus, Event, Hub, RenderData, RenderQueue, View};
9use crate::view::{Id, ID_FEEDER};
10use std::mem;
11use tracing::{debug, error, info};
12
13const MESSAGE_1: &str = "Hold you device in portrait mode\n\
14                         with the Kobo logo at the bottom,\n\
15                         and tap each gray corner\n\
16                         in clockwise order\n\
17                         starting from the top left.";
18const MESSAGE_2: &str = "Tap the black corner.";
19const CORNERS_COUNT: usize = 4;
20
21pub struct RotationValues {
22    id: Id,
23    rect: Rectangle,
24    children: Vec<Box<dyn View>>,
25    mirror_x: bool,
26    mirror_y: bool,
27    swap_xy: bool,
28    width: i32,
29    height: i32,
30    read_rotation: i8,
31    written_rotation: i8,
32    finished: bool,
33    taps: Vec<Point>,
34}
35
36impl RotationValues {
37    pub fn new(rect: Rectangle, rq: &mut RenderQueue, context: &mut Context) -> RotationValues {
38        let id = ID_FEEDER.next();
39        let rotation = context.display.rotation;
40        let (width, height) = context.display.dims;
41        let (mirror_x, mirror_y) = CURRENT_DEVICE.should_mirror_axes(rotation);
42        let swap_xy = CURRENT_DEVICE.should_swap_axes(rotation);
43        rq.add(RenderData::new(id, rect, UpdateMode::Full));
44        RotationValues {
45            id,
46            rect,
47            children: Vec::new(),
48            mirror_x,
49            mirror_y,
50            swap_xy,
51            width: width as i32,
52            height: height as i32,
53            read_rotation: context.fb.rotation(),
54            written_rotation: rotation,
55            finished: false,
56            taps: Vec::new(),
57        }
58    }
59}
60
61impl View for RotationValues {
62    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, hub, _bus, rq, context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
63    fn handle_event(
64        &mut self,
65        evt: &Event,
66        hub: &Hub,
67        _bus: &mut Bus,
68        rq: &mut RenderQueue,
69        context: &mut Context,
70    ) -> bool {
71        match *evt {
72            Event::Gesture(GestureEvent::Tap(mut pt)) if !self.finished => {
73                if self.mirror_x {
74                    pt.x = self.width - 1 - pt.x;
75                }
76
77                if self.mirror_y {
78                    pt.y = self.height - 1 - pt.y;
79                }
80
81                if self.swap_xy {
82                    mem::swap(&mut pt.x, &mut pt.y);
83                }
84
85                debug!("Tap {} {:?}", pt, context.fb.dims());
86
87                self.taps.push(pt);
88                self.finished = self.taps.len() >= 2 * CORNERS_COUNT;
89
90                if self.taps.len() >= CORNERS_COUNT {
91                    let rotation = if self.finished {
92                        self.written_rotation
93                    } else {
94                        (self.taps.len() - CORNERS_COUNT) as i8
95                    };
96                    context
97                        .fb
98                        .set_rotation(rotation)
99                        .map_err(|e| error!("Can't set rotation: {:#}.", e))
100                        .ok();
101                    if context.fb.rotation() == self.read_rotation {
102                        self.written_rotation = rotation;
103                    }
104                    self.children.clear();
105                    self.rect = context.fb.rect();
106                }
107
108                if self.finished {
109                    // Infer the startup rotation and the mirroring scheme.
110                    let first = self.taps[0];
111                    let startup_rotation = self.taps[CORNERS_COUNT..2 * CORNERS_COUNT]
112                        .iter()
113                        .enumerate()
114                        .min_by_key(|(_, &pt)| first.dist2(pt))
115                        .map(|(i, _)| i)
116                        .unwrap();
117                    let origin = self.taps[CORNERS_COUNT..2 * CORNERS_COUNT]
118                        .iter()
119                        .enumerate()
120                        .min_by_key(|(_, pt)| pt.x + pt.y)
121                        .map(|(i, _)| i)
122                        .unwrap();
123                    let center = (origin + 2) % 4;
124                    let next = self.taps[CORNERS_COUNT + (center + 1) % 4];
125                    let polarity = 2 * ((origin + startup_rotation) as i8 % 2) - 1;
126                    let dir = if next.x < next.y { polarity } else { -polarity };
127                    info!("Startup rotation: {}.", startup_rotation);
128                    info!("Mirroring scheme: ({}, {}).", center, dir);
129                    hub.send(Event::Back).ok();
130                } else {
131                    rq.add(RenderData::new(self.id, self.rect, UpdateMode::Full));
132                }
133
134                true
135            }
136            _ => false,
137        }
138    }
139
140    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, fonts, _rect), fields(rect = ?_rect)))]
141    fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, fonts: &mut Fonts) {
142        let dpi = CURRENT_DEVICE.dpi;
143        let width = self.rect.width() as i32;
144        let height = self.rect.height() as i32;
145        let side = width.min(height) / 4;
146
147        fb.draw_rectangle(&self.rect, WHITE);
148
149        let step = 1 + (self.taps.len() % CORNERS_COUNT);
150        let msg = format!("{} / {}", step, CORNERS_COUNT);
151        let font = font_from_style(fonts, &DISPLAY_STYLE, dpi);
152        let plan = font.plan(msg, None, Some(&["lnum".to_string()]));
153        let dx = (width - plan.width as i32) / 2;
154        let mut dy = (height - font.x_heights.1 as i32) / 3;
155
156        font.render(fb, BLACK, &plan, self.rect.min + pt!(dx, dy));
157
158        dy += 4 * (font.x_heights.1 as i32) / 3;
159        let msg = if self.taps.len() < CORNERS_COUNT {
160            MESSAGE_1
161        } else {
162            MESSAGE_2
163        };
164        let font = font_from_style(fonts, &NORMAL_STYLE, dpi);
165
166        for line in msg.lines() {
167            let plan = font.plan(line, None, None);
168            let dx = (width - plan.width as i32) / 2;
169            font.render(fb, BLACK, &plan, self.rect.min + pt!(dx, dy));
170            dy += 3 * font.x_heights.0 as i32;
171        }
172
173        if self.taps.len() < CORNERS_COUNT {
174            fb.draw_triangle(&[pt!(0, 0), pt!(side, 0), pt!(0, side)], GRAY07);
175            fb.draw_triangle(
176                &[
177                    pt!(width - 1, 0),
178                    pt!(width - 1, side),
179                    pt!(width - 1 - side, 0),
180                ],
181                GRAY07,
182            );
183            fb.draw_triangle(
184                &[
185                    pt!(width - 1, height - 1),
186                    pt!(width - 1 - side, height - 1),
187                    pt!(width - 1, height - 1 - side),
188                ],
189                GRAY07,
190            );
191            fb.draw_triangle(
192                &[
193                    pt!(0, height - 1),
194                    pt!(0, height - 1 - side),
195                    pt!(side, height - 1),
196                ],
197                GRAY07,
198            );
199        } else {
200            fb.draw_triangle(&[pt!(0, 0), pt!(side, 0), pt!(0, side)], BLACK);
201        }
202    }
203
204    fn might_rotate(&self) -> bool {
205        false
206    }
207
208    fn rect(&self) -> &Rectangle {
209        &self.rect
210    }
211
212    fn rect_mut(&mut self) -> &mut Rectangle {
213        &mut self.rect
214    }
215
216    fn children(&self) -> &Vec<Box<dyn View>> {
217        &self.children
218    }
219
220    fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
221        &mut self.children
222    }
223
224    fn id(&self) -> Id {
225        self.id
226    }
227}