1use super::{Bus, Event, Hub, Id, RenderData, RenderQueue, View, ViewId, ID_FEEDER};
2use crate::color::{BLACK, WHITE};
3use crate::context::Context;
4use crate::device::CURRENT_DEVICE;
5use crate::document::BYTES_PER_PAGE;
6use crate::font::{font_from_style, Fonts, NORMAL_STYLE};
7use crate::framebuffer::{Framebuffer, UpdateMode};
8use crate::geom::Rectangle;
9use crate::gesture::GestureEvent;
10
11pub struct PageLabel {
12 id: Id,
13 rect: Rectangle,
14 children: Vec<Box<dyn View>>,
15 current_page: usize,
16 pages_count: usize,
17 synthetic: bool,
18}
19
20impl PageLabel {
21 pub fn new(
22 rect: Rectangle,
23 current_page: usize,
24 pages_count: usize,
25 synthetic: bool,
26 ) -> PageLabel {
27 PageLabel {
28 id: ID_FEEDER.next(),
29 rect,
30 children: Vec::new(),
31 current_page,
32 pages_count,
33 synthetic,
34 }
35 }
36
37 pub fn update(&mut self, current_page: usize, pages_count: usize, rq: &mut RenderQueue) {
38 let mut render = false;
39 if self.current_page != current_page {
40 self.current_page = current_page;
41 render = true;
42 }
43 if self.pages_count != pages_count {
44 self.pages_count = pages_count;
45 render = true;
46 }
47 if render {
48 rq.add(RenderData::new(self.id, self.rect, UpdateMode::Gui));
49 }
50 }
51
52 pub fn text(&self, size: u8) -> String {
53 if self.pages_count == 0 {
54 return "No pages".to_string();
55 }
56 let (current_page, pages_count, precision) = if self.synthetic {
57 (
58 self.current_page as f64 / BYTES_PER_PAGE,
59 self.pages_count as f64 / BYTES_PER_PAGE,
60 1,
61 )
62 } else {
63 (self.current_page as f64 + 1.0, self.pages_count as f64, 0)
64 };
65 let percent = 100.0 * self.current_page as f32 / self.pages_count as f32;
66 match size {
67 0 => format!(
68 "Page {1:.0$} of {2:.0$} ({3:.1}%)",
69 precision, current_page, pages_count, percent
70 ),
71 1 => format!(
72 "P. {1:.0$} of {2:.0$} ({3:.1}%)",
73 precision, current_page, pages_count, percent
74 ),
75 2 => format!(
76 "{1:.0$}/{2:.0$} ({3:.1}%)",
77 precision, current_page, pages_count, percent
78 ),
79 3 => format!("{1:.0$} ({2:.1}%)", precision, current_page, percent),
80 _ => format!("{:.1}%", percent),
81 }
82 }
83}
84
85impl View for PageLabel {
86 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, bus, _rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
87 fn handle_event(
88 &mut self,
89 evt: &Event,
90 _hub: &Hub,
91 bus: &mut Bus,
92 _rq: &mut RenderQueue,
93 _context: &mut Context,
94 ) -> bool {
95 match *evt {
96 Event::Gesture(GestureEvent::Tap(center)) if self.rect.includes(center) => {
97 bus.push_back(Event::Toggle(ViewId::GoToPage));
98 true
99 }
100 Event::Gesture(GestureEvent::HoldFingerShort(center, ..))
101 if self.rect.includes(center) =>
102 {
103 bus.push_back(Event::ToggleNear(ViewId::PageMenu, self.rect));
104 true
105 }
106 _ => false,
107 }
108 }
109
110 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, fonts, _rect), fields(rect = ?_rect)))]
111 fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, fonts: &mut Fonts) {
112 let dpi = CURRENT_DEVICE.dpi;
113 let font = font_from_style(fonts, &NORMAL_STYLE, dpi);
114 let padding = font.em() as i32 / 2;
115 let max_width = self.rect.width().saturating_sub(2 * padding as u32) as i32;
116 let mut plan = font.plan(&self.text(0), None, None);
117 for size in 1..=4 {
118 if plan.width <= max_width {
119 break;
120 }
121 plan = font.plan(&self.text(size), None, None);
122 }
123 font.crop_right(&mut plan, max_width);
124 let dx = padding + (max_width - plan.width) / 2;
125 let dy = (self.rect.height() as i32 - font.x_heights.0 as i32) / 2;
126 let pt = pt!(self.rect.min.x + dx, self.rect.max.y - dy);
127 fb.draw_rectangle(&self.rect, WHITE);
128 font.render(fb, BLACK, &plan, pt);
129 }
130
131 fn rect(&self) -> &Rectangle {
132 &self.rect
133 }
134
135 fn rect_mut(&mut self) -> &mut Rectangle {
136 &mut self.rect
137 }
138
139 fn children(&self) -> &Vec<Box<dyn View>> {
140 &self.children
141 }
142
143 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
144 &mut self.children
145 }
146
147 fn id(&self) -> Id {
148 self.id
149 }
150}