1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use crate::core::transform::YAxis;
use crate::widget::high_level::Plot2D;
/// A widget for interactively setting the plot limits, scaling, and grid options.
pub struct LimitsWidget {
win: crate::widget::detached::DetachedWindow,
pub open: bool,
// Staged limits. When the user types/drags values, they update these,
// and then apply them to the plot (or auto-apply if configured).
x_min: f64,
x_max: f64,
y_min: f64,
y_max: f64,
// Options
x_log: bool,
y_log: bool,
grid: bool,
initialized: bool,
}
impl Default for LimitsWidget {
fn default() -> Self {
Self {
win: crate::widget::detached::DetachedWindow::new(
egui::Id::new("limits_widget"),
egui::vec2(300.0, 360.0),
),
open: false,
x_min: 0.0,
x_max: 1.0,
y_min: 0.0,
y_max: 1.0,
x_log: false,
y_log: false,
grid: true,
initialized: false,
}
}
}
impl LimitsWidget {
/// Create a new LimitsWidget.
pub fn new() -> Self {
Self::default()
}
/// Synchronize the widget state with the current plot state.
fn sync_from_plot(&mut self, plot: &Plot2D) {
let (x_min, x_max) = plot.get_graph_x_limits();
self.x_min = x_min;
self.x_max = x_max;
if let Some((y_min, y_max)) = plot.get_graph_y_limits(YAxis::Left) {
self.y_min = y_min;
self.y_max = y_max;
}
// Note: PlotWidget doesn't easily expose is_x_log getter directly in high_level yet,
// but it could. For now, we assume this widget drives the settings, or we
// just let the user toggle it. If they toggle it here, it pushes to plot.
}
/// Show the Limits window.
pub fn show(&mut self, ctx: &egui::Context, plot: &mut Plot2D) {
if !self.initialized {
self.sync_from_plot(plot);
self.initialized = true;
}
if !self.open {
return;
}
let mut apply = false;
let pos = self.win.position(ctx);
let id = self.win.id();
let size = self.win.size();
let signals = crate::widget::detached::show_detached(
ctx,
id,
"Axis & Limits Settings",
size,
pos,
|ui| {
ui.group(|ui| {
ui.heading("X Axis");
ui.horizontal(|ui| {
ui.label("Min:");
if ui
.add(egui::DragValue::new(&mut self.x_min).speed(0.1))
.changed()
{
apply = true;
}
ui.label("Max:");
if ui
.add(egui::DragValue::new(&mut self.x_max).speed(0.1))
.changed()
{
apply = true;
}
});
if ui.checkbox(&mut self.x_log, "Log Scale").changed() {
plot.set_graph_x_log(self.x_log);
}
});
ui.group(|ui| {
ui.heading("Y Axis");
ui.horizontal(|ui| {
ui.label("Min:");
if ui
.add(egui::DragValue::new(&mut self.y_min).speed(0.1))
.changed()
{
apply = true;
}
ui.label("Max:");
if ui
.add(egui::DragValue::new(&mut self.y_max).speed(0.1))
.changed()
{
apply = true;
}
});
if ui.checkbox(&mut self.y_log, "Log Scale").changed() {
plot.set_graph_y_log(self.y_log);
}
});
ui.separator();
if ui.checkbox(&mut self.grid, "Show Grid").changed() {
// Match silx's GridAction gridMode="both": grid on = major +
// minor (see high_level.rs toolbar grid button).
plot.set_graph_grid_mode(if self.grid {
crate::core::plot::GraphGrid::MajorAndMinor
} else {
crate::core::plot::GraphGrid::None
});
}
ui.horizontal(|ui| {
if ui.button("Sync from Plot").clicked() {
self.sync_from_plot(plot);
}
});
},
);
self.win.apply_signals(&signals, &mut self.open);
if apply {
// Apply limits to plot
plot.set_graph_x_limits(self.x_min, self.x_max);
plot.set_graph_y_limits(self.y_min, self.y_max, YAxis::Left);
}
}
}