Skip to content

Commit 70acc6a

Browse files
committed
added zoom and scrolling for all instruments
1 parent 4a7058c commit 70acc6a

3 files changed

Lines changed: 70 additions & 33 deletions

File tree

src/app/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ pub(super) enum PlotTool {
7979
Eraser,
8080
}
8181

82+
impl PlotTool {
83+
pub(super) fn is_navigation(self) -> bool {
84+
matches!(self, Self::None)
85+
}
86+
87+
pub(super) fn is_continuous_point_editing(self) -> bool {
88+
matches!(self, Self::Dotted | Self::Spray | Self::Eraser)
89+
}
90+
}
91+
8292
/// Распределение точек для spray-кисти.
8393
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8494
pub(super) enum SprayBrush {

src/app/ui/plot_panel.rs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
33
use super::*;
44

5+
const POINT_EDIT_BUTTON: egui::PointerButton = egui::PointerButton::Primary;
6+
const NAVIGATION_PAN_BUTTON: egui::PointerButton = egui::PointerButton::Primary;
7+
const POINT_TOOL_PAN_BUTTON: egui::PointerButton = egui::PointerButton::Middle;
8+
59
pub(super) fn add_point_from_plot(app: &mut CurveFitApp, x: f64, y: f64, record_undo: bool) {
610
let point = match Point::try_new(x, y) {
711
Ok(point) => point,
@@ -89,32 +93,52 @@ fn plot_position_from_screen(
8993
Some(plot_response.transform.value_from_position(screen_pos))
9094
}
9195

96+
fn pointer_button_down_on(response: &egui::Response, button: egui::PointerButton) -> bool {
97+
response.is_pointer_button_down_on()
98+
&& response
99+
.ctx
100+
.input(|input| input.pointer.button_down(button))
101+
}
102+
103+
fn pointer_button_pressed_this_frame_on(
104+
response: &egui::Response,
105+
button: egui::PointerButton,
106+
) -> bool {
107+
pointer_button_down_on(response, button)
108+
&& response
109+
.ctx
110+
.input(|input| input.pointer.button_pressed(button))
111+
}
112+
113+
fn pan_pointer_button_for(tool: PlotTool) -> egui::PointerButton {
114+
if tool.is_navigation() {
115+
NAVIGATION_PAN_BUTTON
116+
} else {
117+
POINT_TOOL_PAN_BUTTON
118+
}
119+
}
120+
92121
pub(super) fn handle_plot_tools(app: &mut CurveFitApp, plot_response: &PlotResponse<()>) {
93122
if app.fit_in_progress {
94123
app.reset_spray_rate_state();
95124
return;
96125
}
97126

98127
let response = &plot_response.response;
99-
let is_continuous_tool = matches!(
100-
app.plot_tool,
101-
PlotTool::Dotted | PlotTool::Spray | PlotTool::Eraser
102-
);
103-
let primary_down_on_plot = response.is_pointer_button_down_on();
128+
let is_continuous_tool = app.plot_tool.is_continuous_point_editing();
129+
let point_edit_down_on_plot = pointer_button_down_on(response, POINT_EDIT_BUTTON);
104130
// Для "Точки" нужен одноразовый триггер на момент нажатия ЛКМ.
105-
let primary_pressed_this_frame_on_plot = primary_down_on_plot
106-
&& response
107-
.ctx
108-
.input(|input| input.pointer.button_pressed(egui::PointerButton::Primary));
109-
if is_continuous_tool && primary_down_on_plot {
131+
let point_edit_pressed_this_frame_on_plot =
132+
pointer_button_pressed_this_frame_on(response, POINT_EDIT_BUTTON);
133+
if is_continuous_tool && point_edit_down_on_plot {
110134
if app.active_tool_bounds.is_none() {
111135
app.push_current_points_undo_snapshot();
112136
}
113137
app.active_tool_bounds
114138
.get_or_insert(*plot_response.transform.bounds());
115139
}
116140

117-
let spray_active = app.plot_tool == PlotTool::Spray && primary_down_on_plot;
141+
let spray_active = app.plot_tool == PlotTool::Spray && point_edit_down_on_plot;
118142
if spray_active {
119143
// Просим следующий кадр, чтобы поддерживать стабильный points/sec даже без движения мыши.
120144
response.ctx.request_repaint();
@@ -129,29 +153,29 @@ pub(super) fn handle_plot_tools(app: &mut CurveFitApp, plot_response: &PlotRespo
129153
match app.plot_tool {
130154
PlotTool::None => {}
131155
PlotTool::SinglePoint => {
132-
if primary_pressed_this_frame_on_plot
156+
if point_edit_pressed_this_frame_on_plot
133157
&& let Some(screen_pos) = response.interact_pointer_pos()
134158
&& let Some(plot_pos) = plot_position_from_screen(plot_response, screen_pos)
135159
{
136160
add_point_from_plot(app, plot_pos.x, plot_pos.y, true);
137161
}
138162
}
139163
PlotTool::Dotted => {
140-
let clicked_primary = response.clicked_by(egui::PointerButton::Primary);
141-
let dragged_primary_with_motion = response.dragged_by(egui::PointerButton::Primary)
142-
&& response.drag_delta() != egui::Vec2::ZERO;
143-
if (clicked_primary || dragged_primary_with_motion)
164+
let clicked_point_edit = response.clicked_by(POINT_EDIT_BUTTON);
165+
let dragged_point_edit_with_motion =
166+
response.dragged_by(POINT_EDIT_BUTTON) && response.drag_delta() != egui::Vec2::ZERO;
167+
if (clicked_point_edit || dragged_point_edit_with_motion)
144168
&& let Some(screen_pos) = response.interact_pointer_pos()
145169
&& let Some(plot_pos) = plot_position_from_screen(plot_response, screen_pos)
146170
{
147171
// Быстрый клик может завершиться в одном кадре без фазы `pointer_down`,
148172
// тогда undo-снимок не успевает сохраниться в блоке непрерывного ввода.
149-
let record_undo = clicked_primary && app.active_tool_bounds.is_none();
173+
let record_undo = clicked_point_edit && app.active_tool_bounds.is_none();
150174
add_point_from_plot(app, plot_pos.x, plot_pos.y, record_undo);
151175
}
152176
}
153177
PlotTool::Spray => {
154-
if primary_down_on_plot
178+
if point_edit_down_on_plot
155179
&& let Some(screen_pos) = response.interact_pointer_pos()
156180
&& let Some(plot_pos) = plot_position_from_screen(plot_response, screen_pos)
157181
{
@@ -169,7 +193,7 @@ pub(super) fn handle_plot_tools(app: &mut CurveFitApp, plot_response: &PlotRespo
169193
}
170194
}
171195
PlotTool::Eraser => {
172-
if primary_down_on_plot
196+
if point_edit_down_on_plot
173197
&& let Some(screen_pos) = response.interact_pointer_pos()
174198
&& let Some(plot_pos) = plot_position_from_screen(plot_response, screen_pos)
175199
{
@@ -180,7 +204,7 @@ pub(super) fn handle_plot_tools(app: &mut CurveFitApp, plot_response: &PlotRespo
180204
}
181205
}
182206

183-
if !(is_continuous_tool && primary_down_on_plot) {
207+
if !(is_continuous_tool && point_edit_down_on_plot) {
184208
app.flush_points_text_from_cache_if_pending();
185209
app.active_tool_bounds = None;
186210
}
@@ -195,7 +219,9 @@ pub(super) fn ui_plot(app: &mut CurveFitApp, ui: &mut egui::Ui, height: f32) {
195219
}
196220
let points_slice = visible_points.as_slice();
197221
let (x_min, x_max) = plot_domain(points_slice);
198-
let navigation_mode = matches!(app.plot_tool, PlotTool::None);
222+
let navigation_mode = app.plot_tool.is_navigation();
223+
let ctrl_zoom_mode = ui.input(|input| input.modifiers.ctrl);
224+
let pan_pointer_button = pan_pointer_button_for(app.plot_tool);
199225
let spline_curve = app.spline_plot_curve.clone();
200226
let spline_curve_slice = spline_curve.as_deref();
201227
let sampled_curve = if spline_curve_slice.is_none() {
@@ -280,8 +306,9 @@ pub(super) fn ui_plot(app: &mut CurveFitApp, ui: &mut egui::Ui, height: f32) {
280306
.legend(Legend::default().background_alpha(0.55))
281307
.show_axes([true, true])
282308
.show_grid([true, true])
283-
.allow_drag(navigation_mode)
284-
.allow_zoom(navigation_mode)
309+
.pan_pointer_button(pan_pointer_button)
310+
.allow_drag(true)
311+
.allow_zoom(navigation_mode || ctrl_zoom_mode)
285312
.allow_scroll(navigation_mode)
286313
.allow_double_click_reset(navigation_mode)
287314
.allow_boxed_zoom(navigation_mode)

src/app/ui/points_editor_panel.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -643,28 +643,28 @@ fn tool_usage_hint(language: UiLanguage, tool: PlotTool) -> &'static str {
643643
match tool {
644644
PlotTool::None => tr(
645645
language,
646-
"Navigation mode\n- Drag to pan the plot\n- Use wheel/trackpad to zoom\n- Double-click resets view bounds",
647-
"Режим навигации\n- Перетаскивание двигает график\n- Колесо/трекпад меняют масштаб\n- Двойной клик сбрасывает вид в границы данных",
646+
"Navigation mode\n- Drag to pan the plot\n- Wheel/trackpad scroll pans the plot\n- Hold Ctrl and use wheel/trackpad to zoom\n- Double-click resets view bounds",
647+
"Режим навигации\n- Перетаскивание двигает график\n- Колесо/трекпад сдвигают график\n- Зажмите Ctrl и используйте колесо/трекпад для масштаба\n- Двойной клик сбрасывает вид в границы данных",
648648
),
649649
PlotTool::SinglePoint => tr(
650650
language,
651-
"Single point tool\n- Press left mouse button on plot to place one sample immediately\n- No extra points are added while button is held\n- Best for precise manual placement",
652-
"Инструмент одной точки\n- Нажмите левую кнопку на графике, чтобы сразу поставить одну точку\n- Пока кнопка зажата, новые точки не добавляются\n- Подходит для точного ручного ввода",
651+
"Single point tool\n- Press left mouse button on plot to place one sample immediately\n- Hold middle mouse button to pan the plot\n- Hold Ctrl and use wheel/trackpad to zoom\n- No extra points are added while button is held\n- Best for precise manual placement",
652+
"Инструмент одной точки\n- Нажмите левую кнопку на графике, чтобы сразу поставить одну точку\n- Зажмите среднюю кнопку мыши, чтобы двигать график\n- Зажмите Ctrl и используйте колесо/трекпад для масштаба\n- Пока кнопка зажата, новые точки не добавляются\n- Подходит для точного ручного ввода",
653653
),
654654
PlotTool::Dotted => tr(
655655
language,
656-
"Dotted tool\n- Left click on plot to add one sample\n- Hold left mouse button and move cursor to place points along the path",
657-
"Инструмент пунктира\n- Левый клик по графику добавляет одну точку\n- Зажмите левую кнопку и ведите курсор, чтобы ставить точки по траектории",
656+
"Dotted tool\n- Left click on plot to add one sample\n- Hold left mouse button and move cursor to place points along the path\n- Hold middle mouse button to pan the plot\n- Hold Ctrl and use wheel/trackpad to zoom",
657+
"Инструмент пунктира\n- Левый клик по графику добавляет одну точку\n- Зажмите левую кнопку и ведите курсор, чтобы ставить точки по траектории\n- Зажмите среднюю кнопку мыши, чтобы двигать график\n- Зажмите Ctrl и используйте колесо/трекпад для масштаба",
658658
),
659659
PlotTool::Spray => tr(
660660
language,
661-
"Spray tool\n- Hold left mouse button to add a stream of points\n- Rate controls points per second\n- Radius controls spread around cursor",
662-
"Инструмент распыления\n- Зажмите левую кнопку, чтобы добавлять поток точек\n- Скорость задаёт число точек в секунду\n- Радиус задаёт разброс вокруг курсора",
661+
"Spray tool\n- Hold left mouse button to add a stream of points\n- Hold middle mouse button to pan the plot\n- Hold Ctrl and use wheel/trackpad to zoom\n- Rate controls points per second\n- Radius controls spread around cursor",
662+
"Инструмент распыления\n- Зажмите левую кнопку, чтобы добавлять поток точек\n- Зажмите среднюю кнопку мыши, чтобы двигать график\n- Зажмите Ctrl и используйте колесо/трекпад для масштаба\n- Скорость задаёт число точек в секунду\n- Радиус задаёт разброс вокруг курсора",
663663
),
664664
PlotTool::Eraser => tr(
665665
language,
666-
"Eraser tool\n- Hold left mouse button to remove points\n- Radius controls erase area around cursor",
667-
"Ластик\n- Зажмите левую кнопку, чтобы удалять точки\n- Радиус задаёт область стирания вокруг курсора",
666+
"Eraser tool\n- Hold left mouse button to remove points\n- Hold middle mouse button to pan the plot\n- Hold Ctrl and use wheel/trackpad to zoom\n- Radius controls erase area around cursor",
667+
"Ластик\n- Зажмите левую кнопку, чтобы удалять точки\n- Зажмите среднюю кнопку мыши, чтобы двигать график\n- Зажмите Ctrl и используйте колесо/трекпад для масштаба\n- Радиус задаёт область стирания вокруг курсора",
668668
),
669669
}
670670
}

0 commit comments

Comments
 (0)