mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 01:58:11 +08:00
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:
co-authored by
Keavon Chambers
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.,
|
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.,
|
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.
|
/// 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;
|
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::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
@@ -39,6 +40,32 @@ impl PreferencesDialogMessageHandler {
|
|||||||
|
|
||||||
let navigation_header = vec![TextLabel::new("Navigation").italic(true).widget_holder()];
|
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_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
|
||||||
let zoom_with_scroll = vec![
|
let zoom_with_scroll = vec![
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
@@ -184,6 +211,8 @@ impl PreferencesDialogMessageHandler {
|
|||||||
|
|
||||||
Layout::WidgetLayout(WidgetLayout::new(vec![
|
Layout::WidgetLayout(WidgetLayout::new(vec![
|
||||||
LayoutGroup::Row { widgets: navigation_header },
|
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: zoom_with_scroll },
|
||||||
LayoutGroup::Row { widgets: editing_header },
|
LayoutGroup::Row { widgets: editing_header },
|
||||||
LayoutGroup::Row { widgets: selection_label },
|
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,
|
document_ptz: &mut self.document_ptz,
|
||||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
graph_view_overlay_open: self.graph_view_overlay_open,
|
||||||
|
preferences,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.navigation_handler.process_message(message, responses, data);
|
self.navigation_handler.process_message(message, responses, data);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::consts::{
|
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_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::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
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 selection_bounds: Option<[DVec2; 2]>,
|
||||||
pub document_ptz: &'a mut PTZ,
|
pub document_ptz: &'a mut PTZ,
|
||||||
pub graph_view_overlay_open: bool,
|
pub graph_view_overlay_open: bool,
|
||||||
|
pub preferences: &'a PreferencesMessageHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
@@ -39,6 +40,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for Navigation
|
|||||||
selection_bounds,
|
selection_bounds,
|
||||||
document_ptz,
|
document_ptz,
|
||||||
graph_view_overlay_open,
|
graph_view_overlay_open,
|
||||||
|
preferences,
|
||||||
} = data;
|
} = 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> {
|
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 => {
|
NavigationMessage::CanvasZoomMouseWheel => {
|
||||||
let scroll = ipp.mouse.scroll_delta.scroll_delta();
|
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. {
|
if ipp.mouse.scroll_delta.y > 0. {
|
||||||
zoom_factor = 1. / zoom_factor
|
zoom_factor = 1. / zoom_factor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub enum PreferencesMessage {
|
|||||||
VectorMeshes { enabled: bool },
|
VectorMeshes { enabled: bool },
|
||||||
ModifyLayout { zoom_with_scroll: bool },
|
ModifyLayout { zoom_with_scroll: bool },
|
||||||
GraphWireStyle { style: GraphWireStyle },
|
GraphWireStyle { style: GraphWireStyle },
|
||||||
|
ViewportZoomWheelRate { rate: f64 },
|
||||||
// ImaginateRefreshFrequency { seconds: f64 },
|
// ImaginateRefreshFrequency { seconds: f64 },
|
||||||
// ImaginateServerHostname { hostname: String },
|
// 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::input_mapper::key_mapping::MappingVariant;
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
use crate::messages::portfolio::document::node_graph::utility_types::GraphWireStyle;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
@@ -13,6 +14,7 @@ pub struct PreferencesMessageHandler {
|
|||||||
pub use_vello: bool,
|
pub use_vello: bool,
|
||||||
pub vector_meshes: bool,
|
pub vector_meshes: bool,
|
||||||
pub graph_wire_style: GraphWireStyle,
|
pub graph_wire_style: GraphWireStyle,
|
||||||
|
pub viewport_zoom_wheel_rate: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreferencesMessageHandler {
|
impl PreferencesMessageHandler {
|
||||||
@@ -47,6 +49,7 @@ impl Default for PreferencesMessageHandler {
|
|||||||
use_vello,
|
use_vello,
|
||||||
vector_meshes: false,
|
vector_meshes: false,
|
||||||
graph_wire_style: GraphWireStyle::default(),
|
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;
|
self.graph_wire_style = style;
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
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)
|
// 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 } => {
|
// PreferencesMessage::ImaginateRefreshFrequency { seconds } => {
|
||||||
|
|||||||
Reference in New Issue
Block a user