cadmus_core/view/home/
directory.rs

1use crate::color::{BLACK, TEXT_BUMP_SMALL, WHITE};
2use crate::context::Context;
3use crate::device::CURRENT_DEVICE;
4use crate::font::{font_from_style, Fonts, NORMAL_STYLE};
5use crate::framebuffer::Framebuffer;
6use crate::geom::{BorderSpec, CornerSpec, Rectangle};
7use crate::gesture::GestureEvent;
8use crate::unit::scale_by_dpi;
9use crate::view::{Align, Bus, Event, Hub, Id, RenderQueue, View, ID_FEEDER};
10use crate::view::{BORDER_RADIUS_SMALL, THICKNESS_SMALL};
11use std::path::{Path, PathBuf};
12
13pub struct Directory {
14    id: Id,
15    rect: Rectangle,
16    children: Vec<Box<dyn View>>,
17    pub path: PathBuf,
18    selected: bool,
19    align: Align,
20    max_width: Option<i32>,
21}
22
23impl Directory {
24    pub fn new(
25        rect: Rectangle,
26        path: PathBuf,
27        selected: bool,
28        align: Align,
29        max_width: Option<i32>,
30    ) -> Directory {
31        Directory {
32            id: ID_FEEDER.next(),
33            rect,
34            children: Vec::new(),
35            path,
36            selected,
37            align,
38            max_width,
39        }
40    }
41
42    pub fn update_selected(&mut self, current_directory: &Path) -> bool {
43        let selected = current_directory.starts_with(&self.path);
44        self.selected = selected;
45        selected
46    }
47}
48
49impl View for Directory {
50    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, bus, _rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
51    fn handle_event(
52        &mut self,
53        evt: &Event,
54        _hub: &Hub,
55        bus: &mut Bus,
56        _rq: &mut RenderQueue,
57        _context: &mut Context,
58    ) -> bool {
59        match *evt {
60            Event::Gesture(GestureEvent::Tap(center)) if self.rect.includes(center) => {
61                bus.push_back(Event::ToggleSelectDirectory(self.path.clone()));
62                true
63            }
64            _ => false,
65        }
66    }
67    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, fonts, _rect), fields(rect = ?_rect)))]
68    fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, fonts: &mut Fonts) {
69        let dpi = CURRENT_DEVICE.dpi;
70        fb.draw_rectangle(&self.rect, TEXT_BUMP_SMALL[0]);
71        let font = font_from_style(fonts, &NORMAL_STYLE, dpi);
72        let x_height = font.x_heights.0 as i32;
73        let text = self.path.file_name().unwrap().to_string_lossy();
74        let plan = font.plan(text, self.max_width, None);
75
76        let dx = self.align.offset(plan.width, self.rect.width() as i32);
77        let dy = (self.rect.height() as i32 - x_height) / 2;
78
79        if self.selected {
80            let padding = font.em() as i32 / 2 - scale_by_dpi(3.0, dpi) as i32;
81            let small_x_height = font.x_heights.0 as i32;
82            let bg_width = plan.width + 2 * padding;
83            let bg_height = 3 * small_x_height;
84            let x_offset = dx - padding;
85            let y_offset = dy + x_height - 2 * small_x_height;
86            let pt = self.rect.min + pt!(x_offset, y_offset);
87            let bg_rect = rect![pt, pt + pt!(bg_width, bg_height)];
88            let border_radius = scale_by_dpi(BORDER_RADIUS_SMALL, dpi) as i32;
89            let border_thickness = scale_by_dpi(THICKNESS_SMALL, dpi) as u16;
90            fb.draw_rounded_rectangle_with_border(
91                &bg_rect,
92                &CornerSpec::Uniform(border_radius),
93                &BorderSpec {
94                    thickness: border_thickness,
95                    color: BLACK,
96                },
97                &WHITE,
98            );
99        }
100
101        let pt = pt!(self.rect.min.x + dx, self.rect.max.y - dy);
102        font.render(fb, TEXT_BUMP_SMALL[1], &plan, pt);
103    }
104
105    fn rect(&self) -> &Rectangle {
106        &self.rect
107    }
108
109    fn rect_mut(&mut self) -> &mut Rectangle {
110        &mut self.rect
111    }
112
113    fn children(&self) -> &Vec<Box<dyn View>> {
114        &self.children
115    }
116
117    fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
118        &mut self.children
119    }
120
121    fn id(&self) -> Id {
122        self.id
123    }
124}