Skip to main content

libsurfer/
overview.rs

1use crate::message::Message;
2use crate::view::{DrawConfig, DrawingContext};
3use crate::viewport::Viewport;
4use crate::{SystemState, wave_data::WaveData};
5use egui::{Frame, Panel, PointerButton, Sense, Ui};
6use emath::{Align2, Pos2, Rect, RectTransform};
7use epaint::CornerRadius;
8
9impl SystemState {
10    pub(crate) fn add_overview_panel(
11        &self,
12        ui: &mut Ui,
13        waves: &WaveData,
14        msgs: &mut Vec<Message>,
15    ) {
16        Panel::bottom("overview")
17            .frame(Frame {
18                fill: self.user.config.theme.primary_ui_color.background,
19                ..Default::default()
20            })
21            .show_inside(ui, |ui| {
22                self.draw_overview(ui, waves, msgs);
23            });
24    }
25
26    fn draw_overview(&self, ui: &mut Ui, waves: &WaveData, msgs: &mut Vec<Message>) {
27        let (response, mut painter) = ui.allocate_painter(ui.available_size(), Sense::drag());
28        let frame_size = response.rect.size();
29        let cfg = DrawConfig::new(
30            frame_size,
31            self.user.config.layout.waveforms_line_height,
32            self.user.config.layout.waveforms_text_size,
33        );
34        let container_rect = Rect::from_min_size(Pos2::ZERO, frame_size);
35        let to_screen = RectTransform::from_to(container_rect, response.rect);
36
37        let mut ctx = DrawingContext {
38            painter: &mut painter,
39            cfg: &cfg,
40            to_screen: &|x, y| to_screen.transform_pos(Pos2::new(x, y)),
41            theme: &self.user.config.theme,
42        };
43
44        let num_timestamps = waves.safe_num_timestamps();
45        let viewport_all = waves.viewport_all();
46        let fill_color = self
47            .user
48            .config
49            .theme
50            .canvas_colors
51            .foreground
52            .gamma_multiply(0.3);
53
54        // Draw rectangles for each viewport
55        waves
56            .viewports
57            .iter()
58            .map(|viewport| get_viewport_rect(&ctx, &num_timestamps, &viewport_all, viewport))
59            .for_each(|rect| {
60                ctx.painter
61                    .rect_filled(rect, CornerRadius::ZERO, fill_color);
62            });
63
64        // Draw cursor
65        waves.draw_cursor(&self.user.config.theme, &mut ctx, &viewport_all);
66
67        // Draw ticks
68        let mut ticks = self.get_ticks_for_viewport(waves, &viewport_all, &cfg);
69
70        if ticks.len() >= 2 {
71            // Remove first and last tick
72            ticks.pop();
73            ticks.remove(0);
74            // Draw ticks
75            waves.draw_ticks(
76                self.user.config.theme.foreground,
77                &ticks,
78                &ctx,
79                frame_size.y * 0.5,
80                Align2::CENTER_CENTER,
81            );
82        }
83
84        // Draw markers
85        waves.draw_markers(&self.user.config.theme, &mut ctx, &viewport_all);
86        waves.draw_marker_number_boxes(&mut ctx, &self.user.config.theme, &viewport_all);
87
88        // Handle dragging of the primary viewport
89        response.dragged_by(PointerButton::Primary).then(|| {
90            let pointer_pos_global = ui.input(|i| i.pointer.interact_pos());
91            let pos = pointer_pos_global.map(|p| to_screen.inverse().transform_pos(p));
92            if let Some(pos) = pos {
93                let timestamp = viewport_all.as_time_bigint(pos.x, frame_size.x, &num_timestamps);
94                msgs.push(Message::GoToTime(Some(timestamp), 0));
95            }
96        });
97    }
98}
99
100fn get_viewport_rect(
101    ctx: &DrawingContext<'_>,
102    num_timestamps: &num::BigInt,
103    viewport_all: &Viewport,
104    viewport: &Viewport,
105) -> Rect {
106    let minx = viewport_all.pixel_from_absolute_time(
107        viewport.curr_left.absolute(num_timestamps),
108        ctx.cfg.canvas_size.x,
109        num_timestamps,
110    );
111    let maxx = viewport_all.pixel_from_absolute_time(
112        viewport.curr_right.absolute(num_timestamps),
113        ctx.cfg.canvas_size.x,
114        num_timestamps,
115    );
116    let mut min = (ctx.to_screen)(minx, 0.);
117    let mut max = (ctx.to_screen)(maxx, ctx.cfg.canvas_size.y);
118
119    if max.x < min.x {
120        std::mem::swap(&mut min.x, &mut max.x);
121    }
122
123    if max.x - min.x < 1.0 {
124        let center_x = min.x.midpoint(max.x);
125        min.x = center_x - 0.5;
126        max.x = center_x + 0.5;
127    }
128
129    Rect::from_min_max(min, max)
130}