cadmus_core/view/calculator/
input_bar.rs1use crate::color::{SEPARATOR_NORMAL, TEXT_BUMP_SMALL};
2use crate::context::Context;
3use crate::device::CURRENT_DEVICE;
4use crate::font::Fonts;
5use crate::framebuffer::Framebuffer;
6use crate::geom::{CycleDir, Rectangle};
7use crate::gesture::GestureEvent;
8use crate::input::DeviceEvent;
9use crate::unit::scale_by_dpi;
10use crate::view::filler::Filler;
11use crate::view::icon::Icon;
12use crate::view::input_field::InputField;
13use crate::view::{Bus, Event, Hub, Id, RenderQueue, View, ViewId, ID_FEEDER, THICKNESS_MEDIUM};
14
15pub struct InputBar {
16 id: Id,
17 pub rect: Rectangle,
18 children: Vec<Box<dyn View>>,
19}
20
21impl InputBar {
22 pub fn new(rect: Rectangle, placeholder: &str, text: &str, context: &mut Context) -> InputBar {
23 let id = ID_FEEDER.next();
24 let mut children = Vec::new();
25 let dpi = CURRENT_DEVICE.dpi;
26 let thickness = scale_by_dpi(THICKNESS_MEDIUM, dpi) as i32;
27 let side = rect.height() as i32;
28
29 let prev_icon = Icon::new(
30 "angle-up",
31 rect![rect.min, rect.min + side],
32 Event::History(CycleDir::Previous, false),
33 )
34 .background(TEXT_BUMP_SMALL[0]);
35 children.push(Box::new(prev_icon) as Box<dyn View>);
36
37 let separator = Filler::new(
38 rect![
39 pt!(rect.min.x + side, rect.min.y),
40 pt!(rect.min.x + side + thickness, rect.max.y)
41 ],
42 SEPARATOR_NORMAL,
43 );
44 children.push(Box::new(separator) as Box<dyn View>);
45
46 let input_field = InputField::new(
47 rect![
48 pt!(rect.min.x + side + thickness, rect.min.y),
49 pt!(rect.max.x - side - thickness, rect.max.y)
50 ],
51 ViewId::CalculatorInput,
52 )
53 .border(false)
54 .text(text, context)
55 .placeholder(placeholder);
56 children.push(Box::new(input_field) as Box<dyn View>);
57
58 let separator = Filler::new(
59 rect![
60 pt!(rect.max.x - side - thickness, rect.min.y),
61 pt!(rect.max.x - side, rect.max.y)
62 ],
63 SEPARATOR_NORMAL,
64 );
65 children.push(Box::new(separator) as Box<dyn View>);
66
67 let next_icon = Icon::new(
68 "angle-down",
69 rect![
70 pt!(rect.max.x - side, rect.min.y),
71 pt!(rect.max.x, rect.max.y)
72 ],
73 Event::History(CycleDir::Next, false),
74 )
75 .background(TEXT_BUMP_SMALL[0]);
76 children.push(Box::new(next_icon) as Box<dyn View>);
77
78 InputBar { id, rect, children }
79 }
80
81 pub fn set_text(
82 &mut self,
83 text: &str,
84 move_cursor: bool,
85 rq: &mut RenderQueue,
86 context: &mut Context,
87 ) {
88 if let Some(input_field) = self.children[2].downcast_mut::<InputField>() {
89 input_field.set_text(text, move_cursor, rq, context);
90 }
91 }
92
93 pub fn text_before_cursor(&self) -> &str {
94 self.children[2]
95 .downcast_ref::<InputField>()
96 .unwrap()
97 .text_before_cursor()
98 }
99}
100
101impl View for InputBar {
102 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, _bus, _rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
103 fn handle_event(
104 &mut self,
105 evt: &Event,
106 _hub: &Hub,
107 _bus: &mut Bus,
108 _rq: &mut RenderQueue,
109 _context: &mut Context,
110 ) -> bool {
111 match *evt {
112 Event::Gesture(GestureEvent::Tap(center))
113 | Event::Gesture(GestureEvent::HoldFingerShort(center, ..))
114 if self.rect.includes(center) =>
115 {
116 true
117 }
118 Event::Gesture(GestureEvent::Swipe { start, .. }) if self.rect.includes(start) => true,
119 Event::Device(DeviceEvent::Finger { position, .. }) if self.rect.includes(position) => {
120 true
121 }
122 _ => false,
123 }
124 }
125
126 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _fb, _fonts, _rect), fields(rect = ?_rect)))]
127 fn render(&self, _fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut Fonts) {}
128
129 fn resize(&mut self, rect: Rectangle, hub: &Hub, rq: &mut RenderQueue, context: &mut Context) {
130 let dpi = CURRENT_DEVICE.dpi;
131 let thickness = scale_by_dpi(THICKNESS_MEDIUM, dpi) as i32;
132 let side = rect.height() as i32;
133 self.children[0].resize(rect![rect.min, rect.min + side], hub, rq, context);
134 self.children[1].resize(
135 rect![
136 pt!(rect.min.x + side, rect.min.y),
137 pt!(rect.min.x + side + thickness, rect.max.y)
138 ],
139 hub,
140 rq,
141 context,
142 );
143 self.children[2].resize(
144 rect![
145 pt!(rect.min.x + side + thickness, rect.min.y),
146 pt!(rect.max.x - side - thickness, rect.max.y)
147 ],
148 hub,
149 rq,
150 context,
151 );
152 self.children[3].resize(
153 rect![
154 pt!(rect.max.x - side - thickness, rect.min.y),
155 pt!(rect.max.x - side, rect.max.y)
156 ],
157 hub,
158 rq,
159 context,
160 );
161 self.children[4].resize(
162 rect![
163 pt!(rect.max.x - side, rect.min.y),
164 pt!(rect.max.x, rect.max.y)
165 ],
166 hub,
167 rq,
168 context,
169 );
170 self.rect = rect;
171 }
172
173 fn rect(&self) -> &Rectangle {
174 &self.rect
175 }
176
177 fn rect_mut(&mut self) -> &mut Rectangle {
178 &mut self.rect
179 }
180
181 fn children(&self) -> &Vec<Box<dyn View>> {
182 &self.children
183 }
184
185 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
186 &mut self.children
187 }
188
189 fn id(&self) -> Id {
190 self.id
191 }
192}