cadmus_core/view/
rounded_button.rs1use super::icon::ICONS_PIXMAPS;
2use super::THICKNESS_MEDIUM;
3use super::{Bus, Event, Hub, Id, RenderData, RenderQueue, View, ID_FEEDER};
4use crate::color::{TEXT_INVERTED_HARD, TEXT_NORMAL};
5use crate::context::Context;
6use crate::device::CURRENT_DEVICE;
7use crate::font::Fonts;
8use crate::framebuffer::{Framebuffer, UpdateMode};
9use crate::geom::{BorderSpec, CornerSpec, Rectangle};
10use crate::gesture::GestureEvent;
11use crate::input::{DeviceEvent, FingerStatus};
12use crate::unit::scale_by_dpi;
13
14pub struct RoundedButton {
15 id: Id,
16 rect: Rectangle,
17 children: Vec<Box<dyn View>>,
18 name: String,
19 event: Event,
20 active: bool,
21}
22
23impl RoundedButton {
24 pub fn new(name: &str, rect: Rectangle, event: Event) -> RoundedButton {
25 RoundedButton {
26 id: ID_FEEDER.next(),
27 rect,
28 children: Vec::new(),
29 name: name.to_string(),
30 event,
31 active: false,
32 }
33 }
34}
35
36impl View for RoundedButton {
37 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, bus, rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
38 fn handle_event(
39 &mut self,
40 evt: &Event,
41 _hub: &Hub,
42 bus: &mut Bus,
43 rq: &mut RenderQueue,
44 _context: &mut Context,
45 ) -> bool {
46 match *evt {
47 Event::Device(DeviceEvent::Finger {
48 status, position, ..
49 }) => match status {
50 FingerStatus::Down if self.rect.includes(position) => {
51 self.active = true;
52 rq.add(RenderData::new(self.id, self.rect, UpdateMode::Fast));
53 true
54 }
55 FingerStatus::Up if self.active => {
56 self.active = false;
57 rq.add(RenderData::new(self.id, self.rect, UpdateMode::Gui));
58 true
59 }
60 _ => false,
61 },
62 Event::Gesture(GestureEvent::Tap(center)) if self.rect.includes(center) => {
63 bus.push_back(self.event.clone());
64 true
65 }
66 _ => false,
67 }
68 }
69 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, _fonts, _rect), fields(rect = ?_rect)))]
70 fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut Fonts) {
71 let dpi = CURRENT_DEVICE.dpi;
72 let thickness = scale_by_dpi(THICKNESS_MEDIUM, dpi) as u16;
73 let button_radius = self.rect.height() as i32 / 2;
74
75 let scheme = if self.active {
76 TEXT_INVERTED_HARD
77 } else {
78 TEXT_NORMAL
79 };
80
81 let pixmap = ICONS_PIXMAPS.get(&self.name[..]).unwrap();
82 let dx = (self.rect.width() as i32 - pixmap.width as i32) / 2;
83 let dy = (self.rect.height() as i32 - pixmap.height as i32) / 2;
84 let pt = self.rect.min + pt!(dx, dy);
85
86 fb.draw_rounded_rectangle_with_border(
87 &self.rect,
88 &CornerSpec::Uniform(button_radius),
89 &BorderSpec {
90 thickness: thickness as u16,
91 color: scheme[1],
92 },
93 &scheme[0],
94 );
95
96 fb.draw_blended_pixmap(pixmap, pt, scheme[1]);
97 }
98
99 fn rect(&self) -> &Rectangle {
100 &self.rect
101 }
102
103 fn rect_mut(&mut self) -> &mut Rectangle {
104 &mut self.rect
105 }
106
107 fn children(&self) -> &Vec<Box<dyn View>> {
108 &self.children
109 }
110
111 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
112 &mut self.children
113 }
114
115 fn id(&self) -> Id {
116 self.id
117 }
118}