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 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 waves.draw_cursor(&self.user.config.theme, &mut ctx, &viewport_all);
75
76 let mut ticks = self.get_ticks_for_viewport(waves, &viewport_all, &cfg);
78
79 if ticks.len() >= 2 {
80 ticks.pop();
82 ticks.remove(0);
83 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 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 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}