Skip to content

Commit 3c1ec45

Browse files
Add option to adjust viewport zoom rate in the preferences dialog (#2420)
* zoom rate preference * Add generic range mapping functions for improved reusability * cleanup * Map zoom slider's default value of 50 to the original zoom rate (0.005) * use . instead of .0 for whole-number floats * Refactor zoom rate mapping to use a fixed reference point and adjustable curve steepness * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent 6a8386d commit 3c1ec45

File tree

6 files changed

+60
-2
lines changed

6 files changed

+60
-2
lines changed

editor/src/consts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub const VIEWPORT_ZOOM_LEVELS: [f64; 74] = [
1616
0.04, 0.05, 0.06, 0.08, 0.1, 0.125, 0.15, 0.2, 0.25, 0.33333333, 0.4, 0.5, 0.66666666, 0.8, 1., 1.25, 1.6, 2., 2.5, 3.2, 4., 5., 6.4, 8., 10., 12.5, 16., 20., 25., 32., 40., 50., 64., 80., 100.,
1717
128., 160., 200., 256., 320., 400., 512., 640., 800., 1024., 1280., 1600., 2048., 2560.,
1818
];
19+
/// Higher values create a steeper curve (a faster zoom rate change)
20+
pub const VIEWPORT_ZOOM_WHEEL_RATE_CHANGE: f64 = 3.;
1921

2022
/// Helps push values that end in approximately half, plus or minus some floating point imprecision, towards the same side of the round() function.
2123
pub const VIEWPORT_GRID_ROUNDING_BIAS: f64 = 0.002;

editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::consts::{VIEWPORT_ZOOM_WHEEL_RATE, VIEWPORT_ZOOM_WHEEL_RATE_CHANGE};
12
use crate::messages::layout::utility_types::widget_prelude::*;
23
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
34
use crate::messages::preferences::SelectionMode;
@@ -39,6 +40,32 @@ impl PreferencesDialogMessageHandler {
3940

4041
let navigation_header = vec![TextLabel::new("Navigation").italic(true).widget_holder()];
4142

43+
let zoom_rate_tooltip = "Adjust how fast zooming occurs when using the scroll wheel or pinch gesture (relative to a default of 50)";
44+
let zoom_rate_label = vec![
45+
Separator::new(SeparatorType::Unrelated).widget_holder(),
46+
Separator::new(SeparatorType::Unrelated).widget_holder(),
47+
TextLabel::new("Zoom Rate").tooltip(zoom_rate_tooltip).widget_holder(),
48+
];
49+
let zoom_rate = vec![
50+
Separator::new(SeparatorType::Unrelated).widget_holder(),
51+
Separator::new(SeparatorType::Unrelated).widget_holder(),
52+
NumberInput::new(Some(map_zoom_rate_to_display(preferences.viewport_zoom_wheel_rate)))
53+
.tooltip(zoom_rate_tooltip)
54+
.mode_range()
55+
.int()
56+
.min(1.)
57+
.max(100.)
58+
.on_update(|number_input: &NumberInput| {
59+
if let Some(display_value) = number_input.value {
60+
let actual_rate = map_display_to_zoom_rate(display_value);
61+
PreferencesMessage::ViewportZoomWheelRate { rate: actual_rate }.into()
62+
} else {
63+
PreferencesMessage::ViewportZoomWheelRate { rate: VIEWPORT_ZOOM_WHEEL_RATE }.into()
64+
}
65+
})
66+
.widget_holder(),
67+
];
68+
4269
let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
4370
let zoom_with_scroll = vec![
4471
Separator::new(SeparatorType::Unrelated).widget_holder(),
@@ -184,6 +211,8 @@ impl PreferencesDialogMessageHandler {
184211

185212
Layout::WidgetLayout(WidgetLayout::new(vec![
186213
LayoutGroup::Row { widgets: navigation_header },
214+
LayoutGroup::Row { widgets: zoom_rate_label },
215+
LayoutGroup::Row { widgets: zoom_rate },
187216
LayoutGroup::Row { widgets: zoom_with_scroll },
188217
LayoutGroup::Row { widgets: editing_header },
189218
LayoutGroup::Row { widgets: selection_label },
@@ -250,3 +279,20 @@ impl PreferencesDialogMessageHandler {
250279
});
251280
}
252281
}
282+
283+
/// Maps display values (1-100) to actual zoom rates.
284+
fn map_display_to_zoom_rate(display: f64) -> f64 {
285+
// Calculate the relative distance from the reference point (50)
286+
let distance_from_reference = display - 50.;
287+
let scaling_factor = (VIEWPORT_ZOOM_WHEEL_RATE_CHANGE * distance_from_reference / 50.).exp();
288+
VIEWPORT_ZOOM_WHEEL_RATE * scaling_factor
289+
}
290+
291+
/// Maps actual zoom rates back to display values (1-100).
292+
fn map_zoom_rate_to_display(rate: f64) -> f64 {
293+
// Calculate the scaling factor from the reference rate
294+
let scaling_factor = rate / VIEWPORT_ZOOM_WHEEL_RATE;
295+
let distance_from_reference = 50. * scaling_factor.ln() / VIEWPORT_ZOOM_WHEEL_RATE_CHANGE;
296+
let display = 50. + distance_from_reference;
297+
display.clamp(1., 100.).round()
298+
}

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
193193
},
194194
document_ptz: &mut self.document_ptz,
195195
graph_view_overlay_open: self.graph_view_overlay_open,
196+
preferences,
196197
};
197198

198199
self.navigation_handler.process_message(message, responses, data);

editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::consts::{
22
VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN,
3-
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, VIEWPORT_ZOOM_WHEEL_RATE,
3+
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
44
};
55
use crate::messages::frontend::utility_types::MouseCursorIcon;
66
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
@@ -20,6 +20,7 @@ pub struct NavigationMessageData<'a> {
2020
pub selection_bounds: Option<[DVec2; 2]>,
2121
pub document_ptz: &'a mut PTZ,
2222
pub graph_view_overlay_open: bool,
23+
pub preferences: &'a PreferencesMessageHandler,
2324
}
2425

2526
#[derive(Debug, Clone, PartialEq, Default)]
@@ -39,6 +40,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for Navigation
3940
selection_bounds,
4041
document_ptz,
4142
graph_view_overlay_open,
43+
preferences,
4244
} = data;
4345

4446
fn get_ptz<'a>(document_ptz: &'a PTZ, network_interface: &'a NodeNetworkInterface, graph_view_overlay_open: bool, breadcrumb_network_path: &[NodeId]) -> Option<&'a PTZ> {
@@ -228,7 +230,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for Navigation
228230
}
229231
NavigationMessage::CanvasZoomMouseWheel => {
230232
let scroll = ipp.mouse.scroll_delta.scroll_delta();
231-
let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE;
233+
let mut zoom_factor = 1. + scroll.abs() * preferences.viewport_zoom_wheel_rate;
232234
if ipp.mouse.scroll_delta.y > 0. {
233235
zoom_factor = 1. / zoom_factor
234236
}

editor/src/messages/preferences/preferences_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub enum PreferencesMessage {
1515
VectorMeshes { enabled: bool },
1616
ModifyLayout { zoom_with_scroll: bool },
1717
GraphWireStyle { style: GraphWireStyle },
18+
ViewportZoomWheelRate { rate: f64 },
1819
// ImaginateRefreshFrequency { seconds: f64 },
1920
// ImaginateServerHostname { hostname: String },
2021
}

editor/src/messages/preferences/preferences_message_handler.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::consts::VIEWPORT_ZOOM_WHEEL_RATE;
12
use crate::messages::input_mapper::key_mapping::MappingVariant;
23
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
34
use crate::messages::preferences::SelectionMode;
@@ -13,6 +14,7 @@ pub struct PreferencesMessageHandler {
1314
pub use_vello: bool,
1415
pub vector_meshes: bool,
1516
pub graph_wire_style: GraphWireStyle,
17+
pub viewport_zoom_wheel_rate: f64,
1618
}
1719

1820
impl PreferencesMessageHandler {
@@ -47,6 +49,7 @@ impl Default for PreferencesMessageHandler {
4749
use_vello,
4850
vector_meshes: false,
4951
graph_wire_style: GraphWireStyle::default(),
52+
viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE,
5053
}
5154
}
5255
}
@@ -99,6 +102,9 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
99102
self.graph_wire_style = style;
100103
responses.add(NodeGraphMessage::SendGraph);
101104
}
105+
PreferencesMessage::ViewportZoomWheelRate { rate } => {
106+
self.viewport_zoom_wheel_rate = rate;
107+
}
102108
}
103109
// TODO: Reenable when Imaginate is restored (and move back up one line since the auto-formatter doesn't like it in that block)
104110
// PreferencesMessage::ImaginateRefreshFrequency { seconds } => {

0 commit comments

Comments
 (0)