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(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 max_timestamp = waves.safe_max_timestamp();
45        let viewport_all = waves.viewport_all();
46        let base_fill_color = self.user.config.theme.canvas_colors.foreground;
47
48        // Draw rectangles for each viewport
49        let time_offset = waves.time_offset();
50        waves
51            .viewports
52            .iter()
53            .enumerate()
54            .map(|(idx, viewport)| {
55                (
56                    idx,
57                    get_viewport_rect(&ctx, &max_timestamp, &viewport_all, viewport, time_offset),
58                )
59            })
60            .for_each(|(idx, rect)| {
61                let gamma = if idx == waves.last_active_viewport_idx {
62                    0.6
63                } else {
64                    0.3
65                };
66                ctx.painter.rect_filled(
67                    rect,
68                    CornerRadius::ZERO,
69                    base_fill_color.gamma_multiply(gamma),
70                );
71            });
72
73        // Draw cursor
74        waves.draw_cursor(&self.user.config.theme, &mut ctx, &viewport_all);
75
76        // Draw ticks
77        let mut ticks = self.get_ticks_for_viewport(waves, &viewport_all, &cfg);
78
79        if ticks.len() >= 2 {
80            // Remove first and last tick
81            ticks.pop();
82            ticks.remove(0);
83            // Draw ticks
84            waves.draw_ticks(
85                self.user.config.theme.foreground,
86                &ticks,
87                &ctx,
88                frame_size.y * 0.5,
89                Align2::CENTER_CENTER,
90            );
91        }
92
93        // Draw markers
94        waves.draw_markers(&self.user.config.theme, &mut ctx, &viewport_all);
95        waves.draw_marker_number_boxes(&mut ctx, &self.user.config.theme, &viewport_all);
96
97        // Handle dragging of the primary viewport
98        response.dragged_by(PointerButton::Primary).then(|| {
99            let pointer_pos_global = ui.input(|i| i.pointer.interact_pos());
100            let pos = pointer_pos_global.map(|p| to_screen.inverse().transform_pos(p));
101            if let Some(pos) = pos {
102                let timestamp =
103                    viewport_all.as_time_bigint(pos.x, frame_size.x, &max_timestamp, time_offset);
104                msgs.push(Message::GoToTime(Some(timestamp), 0));
105            }
106        });
107    }
108}
109
110fn get_viewport_rect(
111    ctx: &DrawingContext<'_>,
112    max_timestamp: &num::BigInt,
113    viewport_all: &Viewport,
114    viewport: &Viewport,
115    time_offset: &num::BigInt,
116) -> Rect {
117    let minx = viewport_all.pixel_from_absolute_time(
118        viewport.curr_left.absolute(max_timestamp, time_offset),
119        ctx.cfg.canvas_size.x,
120        max_timestamp,
121        time_offset,
122    );
123    let maxx = viewport_all.pixel_from_absolute_time(
124        viewport.curr_right.absolute(max_timestamp, time_offset),
125        ctx.cfg.canvas_size.x,
126        max_timestamp,
127        time_offset,
128    );
129    let mut min = (ctx.to_screen)(minx, 0.);
130    let mut max = (ctx.to_screen)(maxx, ctx.cfg.canvas_size.y);
131
132    if max.x < min.x {
133        std::mem::swap(&mut min.x, &mut max.x);
134    }
135
136    if max.x - min.x < 1.0 {
137        let center_x = min.x.midpoint(max.x);
138        min.x = center_x - 0.5;
139        max.x = center_x + 0.5;
140    }
141
142    Rect::from_min_max(min, max)
143}