events_advanced/
events_advanced.rs1use liveplot::{
19 channel_plot, run_liveplot, EventController, EventFilter, EventKind, LivePlotConfig, PlotPoint,
20};
21use std::time::{Duration, SystemTime, UNIX_EPOCH};
22
23fn main() -> eframe::Result<()> {
24 let event_ctrl = EventController::new();
26 let rx = event_ctrl.subscribe(EventFilter::all());
27
28 std::thread::spawn(move || {
30 while let Ok(evt) = rx.recv() {
31 let k = evt.kinds;
32
33 if k.contains(EventKind::CLICK) || k.contains(EventKind::DOUBLE_CLICK) {
35 let label = if k.contains(EventKind::DOUBLE_CLICK) {
36 "DOUBLE_CLICK"
37 } else {
38 "CLICK"
39 };
40 if let Some(c) = &evt.click {
41 let (px, py) = if let Some(p) = c.plot_pos {
43 (p.x, p.y)
44 } else {
45 (f64::NAN, f64::NAN)
46 };
47 let (sx, sy) = if let Some(s) = c.screen_pos {
48 (s.x, s.y)
49 } else {
50 (f32::NAN, f32::NAN)
51 };
52 println!(
53 "[{label}] plot=({:.4},{:.4}) screen=({:.1},{:.1}) scope={}",
54 px,
55 py,
56 sx,
57 sy,
58 c.scope_id.map_or("?".into(), |id| id.to_string()),
59 );
60 } else {
61 println!("[{label}]");
62 }
63 }
64
65 if k.contains(EventKind::PAUSE) || k.contains(EventKind::RESUME) {
67 let label = if k.contains(EventKind::RESUME) {
68 "RESUME"
69 } else {
70 "PAUSE"
71 };
72 if let Some(p) = &evt.pause {
73 println!("[{label}] scope={}", p.scope_id.unwrap_or(0));
74 } else {
75 println!("[{label}]");
76 }
77 }
78
79 if k.contains(EventKind::ZOOM)
81 || k.contains(EventKind::PAN)
82 || k.contains(EventKind::FIT_TO_VIEW)
83 {
84 let label = if k.contains(EventKind::FIT_TO_VIEW) {
85 "FIT_TO_VIEW"
86 } else if k.contains(EventKind::ZOOM) {
87 "ZOOM"
88 } else {
89 "PAN"
90 };
91 if let Some(v) = &evt.view_change {
92 println!(
93 "[{label}] x={:?} y={:?} scope={}",
94 v.x_range,
95 v.y_range,
96 v.scope_id.map_or("?".into(), |id| id.to_string()),
97 );
98 } else {
99 println!("[{label}]");
100 }
101 }
102
103 if k.contains(EventKind::MEASUREMENT_POINT) {
105 let complete = k.contains(EventKind::MEASUREMENT_COMPLETE);
106 if let Some(m) = &evt.measurement {
107 println!(
108 "[MEASUREMENT{}] name={:?} point=({:.4},{:.4}) p1={:?} p2={:?} slope={:?} dist={:?}",
109 if complete { " COMPLETE" } else { "" },
110 m.measurement_name,
111 m.point[0], m.point[1],
112 m.p1, m.p2, m.slope, m.distance,
113 );
114 }
115 }
116 if k.contains(EventKind::MEASUREMENT_CLEARED) {
117 println!("[MEASUREMENT_CLEARED]");
118 }
119
120 if k.contains(EventKind::RESIZE) {
122 if let Some(r) = &evt.resize {
123 println!("[RESIZE] {}×{}", r.width as u32, r.height as u32);
124 }
125 }
126
127 if k.contains(EventKind::KEY_PRESSED) {
129 if let Some(kp) = &evt.key_press {
130 println!(
131 "[KEY] {:?} ctrl={} alt={} shift={} cmd={}",
132 kp.key,
133 kp.modifiers.ctrl,
134 kp.modifiers.alt,
135 kp.modifiers.shift,
136 kp.modifiers.command,
137 );
138 }
139 }
140
141 if k.contains(EventKind::DATA_UPDATED) {
143 if let Some(d) = &evt.data_update {
144 println!("[DATA_UPDATED] traces={:?}", d.traces);
145 }
146 }
147
148 if k.contains(EventKind::TRACE_SHOWN) || k.contains(EventKind::TRACE_HIDDEN) {
150 if let Some(t) = &evt.trace {
151 println!(
152 "[TRACE_{}] {:?} visible={:?}",
153 if k.contains(EventKind::TRACE_SHOWN) {
154 "SHOWN"
155 } else {
156 "HIDDEN"
157 },
158 t.trace.0,
159 t.visible,
160 );
161 }
162 }
163 if k.contains(EventKind::TRACE_COLOR_CHANGED) {
164 if let Some(t) = &evt.trace {
165 println!("[TRACE_COLOR] {:?} rgb={:?}", t.trace.0, t.color_rgb);
166 }
167 }
168 if k.contains(EventKind::TRACE_OFFSET_CHANGED) {
169 if let Some(t) = &evt.trace {
170 println!("[TRACE_OFFSET] {:?} offset={:?}", t.trace.0, t.offset);
171 }
172 }
173
174 if k.contains(EventKind::MATH_TRACE_ADDED) {
176 if let Some(m) = &evt.math_trace {
177 println!("[MATH_TRACE_ADDED] {:?} formula={:?}", m.name, m.formula);
178 }
179 }
180 if k.contains(EventKind::MATH_TRACE_REMOVED) {
181 if let Some(m) = &evt.math_trace {
182 println!("[MATH_TRACE_REMOVED] {:?}", m.name);
183 }
184 }
185
186 if k.contains(EventKind::THRESHOLD_EXCEEDED) {
188 if let Some(t) = &evt.threshold {
189 println!(
190 "[THRESHOLD_EXCEEDED] {:?} trace={:?} area={:?}",
191 t.threshold_name, t.trace, t.area,
192 );
193 }
194 }
195 if k.contains(EventKind::THRESHOLD_REMOVED) {
196 if let Some(t) = &evt.threshold {
197 println!("[THRESHOLD_REMOVED] {:?}", t.threshold_name);
198 }
199 }
200
201 if k.contains(EventKind::EXPORT) || k.contains(EventKind::SCREENSHOT) {
203 let label = if k.contains(EventKind::SCREENSHOT) {
204 "SCREENSHOT"
205 } else {
206 "EXPORT"
207 };
208 if let Some(e) = &evt.export {
209 println!("[{label}] format={:?} path={:?}", e.format, e.path);
210 }
211 }
212
213 if k.contains(EventKind::SCOPE_ADDED) {
215 if let Some(s) = &evt.scope_manage {
216 println!("[SCOPE_ADDED] id={}", s.scope_id);
217 }
218 }
219 if k.contains(EventKind::SCOPE_REMOVED) {
220 if let Some(s) = &evt.scope_manage {
221 println!("[SCOPE_REMOVED] id={}", s.scope_id);
222 }
223 }
224 }
225 println!("[event] channel closed");
226 });
227
228 let (sink, data_rx) = channel_plot();
230 let t_sin = sink.create_trace("sin", Some("Sine"));
231 let t_cos = sink.create_trace("cos", Some("Cosine"));
232
233 std::thread::spawn(move || {
234 let dt = Duration::from_millis(1);
235 loop {
236 let t_s = SystemTime::now()
237 .duration_since(UNIX_EPOCH)
238 .map(|d| d.as_secs_f64())
239 .unwrap_or(0.0);
240 let _ = sink.send_point(
241 &t_sin,
242 PlotPoint {
243 x: t_s,
244 y: (2.0 * std::f64::consts::PI * 2.0 * t_s).sin(),
245 },
246 );
247 let _ = sink.send_point(
248 &t_cos,
249 PlotPoint {
250 x: t_s,
251 y: (2.0 * std::f64::consts::PI * 2.0 * t_s).cos(),
252 },
253 );
254 std::thread::sleep(dt);
255 }
256 });
257
258 let mut cfg = LivePlotConfig::default();
259 cfg.controllers.event = Some(event_ctrl);
260
261 run_liveplot(data_rx, cfg)
262}