cadmus_core/view/
search_bar.rs

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}