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 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 waves.draw_cursor(&self.user.config.theme, &mut ctx, &viewport_all);
66
67 let mut ticks = self.get_ticks_for_viewport(waves, &viewport_all, &cfg);
69
70 if ticks.len() >= 2 {
71 ticks.pop();
73 ticks.remove(0);
74 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 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 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}