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