cadmus_core/view/calculator/
bottom_bar.rs1use crate::color::WHITE;
2use crate::context::Context;
3use crate::font::Fonts;
4use crate::framebuffer::Framebuffer;
5use crate::geom::{divide, Rectangle};
6use crate::gesture::GestureEvent;
7use crate::input::DeviceEvent;
8use crate::view::filler::Filler;
9use crate::view::labeled_icon::LabeledIcon;
10use crate::view::{Bus, Event, Hub, Id, RenderQueue, View, ViewId, ID_FEEDER};
11
12pub struct BottomBar {
13 id: Id,
14 rect: Rectangle,
15 children: Vec<Box<dyn View>>,
16}
17
18impl BottomBar {
19 pub fn new(rect: Rectangle, margin_width: i32, font_size: f32) -> BottomBar {
20 let id = ID_FEEDER.next();
21 let mut children = Vec::new();
22 let labelled_icon_width = 5 * rect.height() as i32 / 2;
23 let paddings = divide(rect.width() as i32 - 2 * labelled_icon_width, 3);
24
25 let mut x_offset = rect.min.x;
26 let filler = Filler::new(
27 rect![x_offset, rect.min.y, x_offset + paddings[0], rect.max.y],
28 WHITE,
29 );
30 x_offset += paddings[0];
31 children.push(Box::new(filler) as Box<dyn View>);
32
33 let margin_width_rect = rect![
34 x_offset,
35 rect.min.y,
36 x_offset + labelled_icon_width,
37 rect.max.y
38 ];
39 let margin_width_icon = LabeledIcon::new(
40 "margin",
41 margin_width_rect,
42 Event::ToggleNear(ViewId::MarginWidthMenu, margin_width_rect),
43 format!("{} mm", margin_width),
44 );
45 children.push(Box::new(margin_width_icon) as Box<dyn View>);
46 x_offset += labelled_icon_width;
47
48 let filler = Filler::new(
49 rect![x_offset, rect.min.y, x_offset + paddings[1], rect.max.y],
50 WHITE,
51 );
52 children.push(Box::new(filler) as Box<dyn View>);
53 x_offset += paddings[1];
54
55 let font_size_rect = rect![
56 x_offset,
57 rect.min.y,
58 x_offset + labelled_icon_width,
59 rect.max.y
60 ];
61 let font_size_icon = LabeledIcon::new(
62 "font_size",
63 font_size_rect,
64 Event::ToggleNear(ViewId::FontSizeMenu, font_size_rect),
65 format!("{:.1} pt", font_size),
66 );
67 children.push(Box::new(font_size_icon) as Box<dyn View>);
68 x_offset += labelled_icon_width;
69
70 let filler = Filler::new(
71 rect![x_offset, rect.min.y, x_offset + paddings[2], rect.max.y],
72 WHITE,
73 );
74 children.push(Box::new(filler) as Box<dyn View>);
75
76 BottomBar { id, rect, children }
77 }
78
79 pub fn update_font_size(&mut self, font_size: f32, rq: &mut RenderQueue) {
80 if let Some(labeled_icon) = self.children[3].downcast_mut::<LabeledIcon>() {
81 labeled_icon.update(&format!("{:.1} pt", font_size), rq);
82 }
83 }
84
85 pub fn update_margin_width(&mut self, margin_width: i32, rq: &mut RenderQueue) {
86 if let Some(labeled_icon) = self.children[1].downcast_mut::<LabeledIcon>() {
87 labeled_icon.update(&format!("{} mm", margin_width), rq);
88 }
89 }
90}
91
92impl View for BottomBar {
93 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, _bus, _rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
94 fn handle_event(
95 &mut self,
96 evt: &Event,
97 _hub: &Hub,
98 _bus: &mut Bus,
99 _rq: &mut RenderQueue,
100 _context: &mut Context,
101 ) -> bool {
102 match *evt {
103 Event::Gesture(GestureEvent::Tap(center))
104 | Event::Gesture(GestureEvent::HoldFingerShort(center, ..))
105 if self.rect.includes(center) =>
106 {
107 true
108 }
109 Event::Gesture(GestureEvent::Swipe { start, .. }) if self.rect.includes(start) => true,
110 Event::Device(DeviceEvent::Finger { position, .. }) if self.rect.includes(position) => {
111 true
112 }
113 _ => false,
114 }
115 }
116
117 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _fb, _fonts, _rect), fields(rect = ?_rect)))]
118 fn render(&self, _fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut Fonts) {}
119
120 fn resize(&mut self, rect: Rectangle, hub: &Hub, rq: &mut RenderQueue, context: &mut Context) {
121 let labelled_icon_width = 5 * rect.height() as i32 / 2;
122 let paddings = divide(rect.width() as i32 - 2 * labelled_icon_width, 3);
123
124 let mut x_offset = rect.min.x;
125
126 let filr_rect = rect![x_offset, rect.min.y, x_offset + paddings[0], rect.max.y];
127 self.children[0].resize(filr_rect, hub, rq, context);
128 x_offset += paddings[0];
129
130 let margin_width_rect = rect![
131 x_offset,
132 rect.min.y,
133 x_offset + labelled_icon_width,
134 rect.max.y
135 ];
136 self.children[1].resize(margin_width_rect, hub, rq, context);
137 x_offset += labelled_icon_width;
138
139 let filr_rect = rect![x_offset, rect.min.y, x_offset + paddings[1], rect.max.y];
140 self.children[2].resize(filr_rect, hub, rq, context);
141 x_offset += paddings[1];
142
143 let font_size_rect = rect![
144 x_offset,
145 rect.min.y,
146 x_offset + labelled_icon_width,
147 rect.max.y
148 ];
149 self.children[3].resize(font_size_rect, hub, rq, context);
150 x_offset += labelled_icon_width;
151
152 let filr_rect = rect![x_offset, rect.min.y, x_offset + paddings[2], rect.max.y];
153 self.children[4].resize(filr_rect, hub, rq, context);
154
155 self.rect = rect;
156 }
157
158 fn rect(&self) -> &Rectangle {
159 &self.rect
160 }
161
162 fn rect_mut(&mut self) -> &mut Rectangle {
163 &mut self.rect
164 }
165
166 fn children(&self) -> &Vec<Box<dyn View>> {
167 &self.children
168 }
169
170 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
171 &mut self.children
172 }
173
174 fn id(&self) -> Id {
175 self.id
176 }
177}