cadmus_core/view/rotation_values/
mod.rs1use 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 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}