libsurfer/
overview.rs

1use crate::message::Message;
2use crate::view::{DrawConfig, DrawingContext};
3use crate::{wave_data::WaveData, SystemState};
4use egui::{Context, Frame, PointerButton, Sense, TopBottomPanel, Ui};
5use emath::{Align2, Pos2, Rect, RectTransform, Vec2};
6use epaint::CornerRadiusF32;
7
8impl SystemState {
9    pub fn add_overview_panel(&self, ctx: &Context, waves: &WaveData, msgs: &mut Vec<Message>) {
10        TopBottomPanel::bottom("overview")
11            .frame(Frame {
12                fill: self.user.config.theme.primary_ui_color.background,
13                ..Default::default()
14            })
15            .show(ctx, |ui| {
16                self.draw_overview(ui, waves, msgs);
17            });
18    }
19
20    fn draw_overview(&self, ui: &mut Ui, waves: &WaveData, msgs: &mut Vec<Message>) {
21        let (response, mut painter) = ui.allocate_painter(ui.available_size(), Sense::drag());
22        let frame_width = response.rect.width();
23        let frame_height = response.rect.height();
24        let cfg = DrawConfig::new(
25            frame_height,
26            self.user.config.layout.waveforms_line_height,
27            self.user.config.layout.waveforms_text_size,
28        );
29        let container_rect = Rect::from_min_size(Pos2::ZERO, response.rect.size());
30        let to_screen = RectTransform::from_to(container_rect, response.rect);
31
32        let mut ctx = DrawingContext {
33            painter: &mut painter,
34            cfg: &cfg,
35            // This 0.5 is very odd, but it fixes the lines we draw being smushed out across two
36            // pixels, resulting in dimmer colors https://github.com/emilk/egui/issues/1322
37            // 1 comes from subtracting .5 in cursor draw as y-adjusement is not required for known vertical lines.
38            to_screen: &|x, y| to_screen.transform_pos(Pos2::new(x, y) + Vec2::new(0.5, 1.)),
39            theme: &self.user.config.theme,
40        };
41
42        let num_timestamps = waves.num_timestamps().unwrap_or(1.into());
43        let viewport_all = waves.viewport_all();
44        for vidx in 0..waves.viewports.len() {
45            let minx = viewport_all.pixel_from_absolute_time(
46                waves.viewports[vidx].curr_left.absolute(&num_timestamps),
47                frame_width,
48                &num_timestamps,
49            );
50            let maxx = viewport_all.pixel_from_absolute_time(
51                waves.viewports[vidx].curr_right.absolute(&num_timestamps),
52                frame_width,
53                &num_timestamps,
54            );
55            let min = (ctx.to_screen)(minx, 0.);
56            let max = (ctx.to_screen)(maxx, container_rect.max.y);
57            ctx.painter.rect_filled(
58                Rect { min, max },
59                CornerRadiusF32::ZERO,
60                self.user
61                    .config
62                    .theme
63                    .canvas_colors
64                    .foreground
65                    .gamma_multiply(0.3),
66            );
67        }
68
69        waves.draw_cursor(
70            &self.user.config.theme,
71            &mut ctx,
72            response.rect.size(),
73            &viewport_all,
74        );
75
76        let mut ticks = waves.get_ticks(
77            &viewport_all,
78            &waves.inner.metadata().timescale,
79            frame_width,
80            cfg.text_size,
81            &self.user.wanted_timeunit,
82            &self.get_time_format(),
83            &self.user.config,
84        );
85
86        if ticks.len() >= 2 {
87            ticks.pop();
88            ticks.remove(0);
89            waves.draw_ticks(
90                None,
91                &ticks,
92                &ctx,
93                frame_height * 0.5,
94                Align2::CENTER_CENTER,
95                &self.user.config,
96            );
97        }
98
99        waves.draw_markers(
100            &self.user.config.theme,
101            &mut ctx,
102            response.rect.size(),
103            &viewport_all,
104        );
105
106        waves.draw_marker_number_boxes(
107            &mut ctx,
108            response.rect.size(),
109            &self.user.config.theme,
110            &viewport_all,
111        );
112        response.dragged_by(PointerButton::Primary).then(|| {
113            let pointer_pos_global = ui.input(|i| i.pointer.interact_pos());
114            let pos = pointer_pos_global.map(|p| to_screen.inverse().transform_pos(p));
115            if let Some(pos) = pos {
116                let timestamp = viewport_all.as_time_bigint(pos.x, frame_width, &num_timestamps);
117                msgs.push(Message::GoToTime(Some(timestamp), 0));
118            }
119        });
120    }
121}