cadmus_core/view/
preset.rs

1use super::BORDER_RADIUS_MEDIUM;
2use super::{Bus, Event, Hub, Id, RenderData, RenderQueue, View, ID_FEEDER};
3use crate::color::{TEXT_INVERTED_HARD, TEXT_NORMAL};
4use crate::context::Context;
5use crate::device::CURRENT_DEVICE;
6use crate::font::{font_from_style, Fonts, NORMAL_STYLE};
7use crate::framebuffer::{Framebuffer, UpdateMode};
8use crate::geom::{CornerSpec, CycleDir, Rectangle};
9use crate::gesture::GestureEvent;
10use crate::input::{DeviceEvent, FingerStatus};
11use crate::unit::scale_by_dpi;
12
13pub struct Preset {
14    id: Id,
15    rect: Rectangle,
16    children: Vec<Box<dyn View>>,
17    kind: PresetKind,
18    active: bool,
19}
20
21pub enum PresetKind {
22    Normal(String, usize),
23    Page(CycleDir),
24}
25
26impl Preset {
27    pub fn new(rect: Rectangle, kind: PresetKind) -> Preset {
28        Preset {
29            id: ID_FEEDER.next(),
30            rect,
31            children: Vec::new(),
32            kind,
33            active: false,
34        }
35    }
36}
37
38impl View for Preset {
39    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, bus, rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
40    fn handle_event(
41        &mut self,
42        evt: &Event,
43        _hub: &Hub,
44        bus: &mut Bus,
45        rq: &mut RenderQueue,
46        _context: &mut Context,
47    ) -> bool {
48        match *evt {
49            Event::Device(DeviceEvent::Finger {
50                status, position, ..
51            }) => match status {
52                FingerStatus::Down if self.rect.includes(position) => {
53                    self.active = true;
54                    rq.add(RenderData::new(self.id, self.rect, UpdateMode::Fast));
55                    true
56                }
57                FingerStatus::Up if self.active => {
58                    self.active = false;
59                    rq.add(RenderData::new(self.id, self.rect, UpdateMode::Gui));
60                    true
61                }
62                _ => false,
63            },
64            Event::Gesture(GestureEvent::Tap(center)) if self.rect.includes(center) => {
65                match self.kind {
66                    PresetKind::Normal(_, index) => bus.push_back(Event::LoadPreset(index)),
67                    PresetKind::Page(dir) => bus.push_back(Event::Page(dir)),
68                }
69                true
70            }
71            Event::Gesture(GestureEvent::HoldFingerShort(center, ..))
72                if self.rect.includes(center) =>
73            {
74                if let PresetKind::Normal(_, index) = self.kind {
75                    bus.push_back(Event::TogglePresetMenu(self.rect, index));
76                }
77                true
78            }
79            _ => false,
80        }
81    }
82
83    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, fonts, _rect), fields(rect = ?_rect)))]
84    fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, fonts: &mut Fonts) {
85        let dpi = CURRENT_DEVICE.dpi;
86
87        let (scheme, border_radius) = if self.active {
88            (
89                TEXT_INVERTED_HARD,
90                scale_by_dpi(BORDER_RADIUS_MEDIUM, dpi) as i32,
91            )
92        } else {
93            (TEXT_NORMAL, 0)
94        };
95
96        fb.draw_rounded_rectangle(&self.rect, &CornerSpec::Uniform(border_radius), scheme[0]);
97
98        let font = font_from_style(fonts, &NORMAL_STYLE, dpi);
99        let x_height = font.x_heights.0 as i32;
100        let padding = font.em() as i32;
101        let max_width = self.rect.width() as i32 - padding;
102
103        let name = match self.kind {
104            PresetKind::Normal(ref text, _) => text,
105            _ => "…",
106        };
107
108        let plan = font.plan(name, Some(max_width), None);
109
110        let dx = (self.rect.width() as i32 - plan.width) / 2;
111        let dy = (self.rect.height() as i32 - x_height) / 2;
112        let pt = pt!(self.rect.min.x + dx, self.rect.max.y - dy);
113
114        font.render(fb, scheme[1], &plan, pt);
115    }
116
117    fn rect(&self) -> &Rectangle {
118        &self.rect
119    }
120
121    fn rect_mut(&mut self) -> &mut Rectangle {
122        &mut self.rect
123    }
124
125    fn children(&self) -> &Vec<Box<dyn View>> {
126        &self.children
127    }
128
129    fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
130        &mut self.children
131    }
132
133    fn id(&self) -> Id {
134        self.id
135    }
136}