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>
This commit is contained in:
parent
6a8386d1e9
commit
3c1ec45188
|
|
@ -16,6 +16,8 @@ pub const VIEWPORT_ZOOM_LEVELS: [f64; 74] = [
|
|||
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.,
|
||||
128., 160., 200., 256., 320., 400., 512., 640., 800., 1024., 1280., 1600., 2048., 2560.,
|
||||
];
|
||||
/// Higher values create a steeper curve (a faster zoom rate change)
|
||||
pub const VIEWPORT_ZOOM_WHEEL_RATE_CHANGE: f64 = 3.;
|
||||
|
||||
/// Helps push values that end in approximately half, plus or minus some floating point imprecision, towards the same side of the round() function.
|
||||
pub const VIEWPORT_GRID_ROUNDING_BIAS: f64 = 0.002;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::consts::{VIEWPORT_ZOOM_WHEEL_RATE, VIEWPORT_ZOOM_WHEEL_RATE_CHANGE};
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||
use crate::messages::preferences::SelectionMode;
|
||||
|
|
@ -39,6 +40,32 @@ impl PreferencesDialogMessageHandler {
|
|||
|
||||
let navigation_header = vec![TextLabel::new("Navigation").italic(true).widget_holder()];
|
||||
|
||||
let zoom_rate_tooltip = "Adjust how fast zooming occurs when using the scroll wheel or pinch gesture (relative to a default of 50)";
|
||||
let zoom_rate_label = vec![
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
TextLabel::new("Zoom Rate").tooltip(zoom_rate_tooltip).widget_holder(),
|
||||
];
|
||||
let zoom_rate = vec![
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
NumberInput::new(Some(map_zoom_rate_to_display(preferences.viewport_zoom_wheel_rate)))
|
||||
.tooltip(zoom_rate_tooltip)
|
||||
.mode_range()
|
||||
.int()
|
||||
.min(1.)
|
||||
.max(100.)
|
||||
.on_update(|number_input: &NumberInput| {
|
||||
if let Some(display_value) = number_input.value {
|
||||
let actual_rate = map_display_to_zoom_rate(display_value);
|
||||
PreferencesMessage::ViewportZoomWheelRate { rate: actual_rate }.into()
|
||||
} else {
|
||||
PreferencesMessage::ViewportZoomWheelRate { rate: VIEWPORT_ZOOM_WHEEL_RATE }.into()
|
||||
}
|
||||
})
|
||||
.widget_holder(),
|
||||
];
|
||||
|
||||
let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
|
||||
let zoom_with_scroll = vec![
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
|
|
@ -184,6 +211,8 @@ impl PreferencesDialogMessageHandler {
|
|||
|
||||
Layout::WidgetLayout(WidgetLayout::new(vec![
|
||||
LayoutGroup::Row { widgets: navigation_header },
|
||||
LayoutGroup::Row { widgets: zoom_rate_label },
|
||||
LayoutGroup::Row { widgets: zoom_rate },
|
||||
LayoutGroup::Row { widgets: zoom_with_scroll },
|
||||
LayoutGroup::Row { widgets: editing_header },
|
||||
LayoutGroup::Row { widgets: selection_label },
|
||||
|
|
@ -250,3 +279,20 @@ impl PreferencesDialogMessageHandler {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps display values (1-100) to actual zoom rates.
|
||||
fn map_display_to_zoom_rate(display: f64) -> f64 {
|
||||
// Calculate the relative distance from the reference point (50)
|
||||
let distance_from_reference = display - 50.;
|
||||
let scaling_factor = (VIEWPORT_ZOOM_WHEEL_RATE_CHANGE * distance_from_reference / 50.).exp();
|
||||
VIEWPORT_ZOOM_WHEEL_RATE * scaling_factor
|
||||
}
|
||||
|
||||
/// Maps actual zoom rates back to display values (1-100).
|
||||
fn map_zoom_rate_to_display(rate: f64) -> f64 {
|
||||
// Calculate the scaling factor from the reference rate
|
||||
let scaling_factor = rate / VIEWPORT_ZOOM_WHEEL_RATE;
|
||||
let distance_from_reference = 50. * scaling_factor.ln() / VIEWPORT_ZOOM_WHEEL_RATE_CHANGE;
|
||||
let display = 50. + distance_from_reference;
|
||||
display.clamp(1., 100.).round()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
|||
},
|
||||
document_ptz: &mut self.document_ptz,
|
||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
||||
preferences,
|
||||
};
|
||||
|
||||
self.navigation_handler.process_message(message, responses, data);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::consts::{
|
||||
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,
|
||||
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, VIEWPORT_ZOOM_WHEEL_RATE,
|
||||
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
|
||||
};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
||||
|
|
@ -20,6 +20,7 @@ pub struct NavigationMessageData<'a> {
|
|||
pub selection_bounds: Option<[DVec2; 2]>,
|
||||
pub document_ptz: &'a mut PTZ,
|
||||
pub graph_view_overlay_open: bool,
|
||||
pub preferences: &'a PreferencesMessageHandler,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
|
|
@ -39,6 +40,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for Navigation
|
|||
selection_bounds,
|
||||
document_ptz,
|
||||
graph_view_overlay_open,
|
||||
preferences,
|
||||
} = data;
|
||||
|
||||
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
|
|||
}
|
||||
NavigationMessage::CanvasZoomMouseWheel => {
|
||||
let scroll = ipp.mouse.scroll_delta.scroll_delta();
|
||||
let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE;
|
||||
let mut zoom_factor = 1. + scroll.abs() * preferences.viewport_zoom_wheel_rate;
|
||||
if ipp.mouse.scroll_delta.y > 0. {
|
||||
zoom_factor = 1. / zoom_factor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub enum PreferencesMessage {
|
|||
VectorMeshes { enabled: bool },
|
||||
ModifyLayout { zoom_with_scroll: bool },
|
||||
GraphWireStyle { style: GraphWireStyle },
|
||||
ViewportZoomWheelRate { rate: f64 },
|
||||
// ImaginateRefreshFrequency { seconds: f64 },
|
||||
// ImaginateServerHostname { hostname: String },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::consts::VIEWPORT_ZOOM_WHEEL_RATE;
|
||||
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||
use crate::messages::preferences::SelectionMode;
|
||||
|
|
@ -13,6 +14,7 @@ pub struct PreferencesMessageHandler {
|
|||
pub use_vello: bool,
|
||||
pub vector_meshes: bool,
|
||||
pub graph_wire_style: GraphWireStyle,
|
||||
pub viewport_zoom_wheel_rate: f64,
|
||||
}
|
||||
|
||||
impl PreferencesMessageHandler {
|
||||
|
|
@ -47,6 +49,7 @@ impl Default for PreferencesMessageHandler {
|
|||
use_vello,
|
||||
vector_meshes: false,
|
||||
graph_wire_style: GraphWireStyle::default(),
|
||||
viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +102,9 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
|||
self.graph_wire_style = style;
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
PreferencesMessage::ViewportZoomWheelRate { rate } => {
|
||||
self.viewport_zoom_wheel_rate = rate;
|
||||
}
|
||||
}
|
||||
// TODO: Reenable when Imaginate is restored (and move back up one line since the auto-formatter doesn't like it in that block)
|
||||
// PreferencesMessage::ImaginateRefreshFrequency { seconds } => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue