diff --git a/editor/src/consts.rs b/editor/src/consts.rs index b5959ef9..042c2de2 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -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; diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index c8bc65b8..5c4aa75f 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -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() +} diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index cc33f987..3d37bb3c 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -193,6 +193,7 @@ impl MessageHandler> 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); diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index 90b312f9..88150570 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -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> 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> 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 } diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs index 63f7d59a..933ea1ef 100644 --- a/editor/src/messages/preferences/preferences_message.rs +++ b/editor/src/messages/preferences/preferences_message.rs @@ -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 }, } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index af05eea6..9a5b2ee1 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -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 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 } => {