Rework navigation tool hints and navigation shortcuts (#1419)
* Added Pan,Tilt,Zoom to View menu + Tilt shortcut changes * formating * fixed menus, added action for when dispatch happens from menu * set key mappings to spec * fix labels for navigation tool * fix some spacing * add action that locks spacebar for navigation when using it as a modifier so the node overlay does not toggle * escape from the node-graph-overlay, set toggle to ctrl+space, fix demo art * move all transform state into an enum * rename confusing flag * fix demo art and tests --------- Co-authored-by: Ezbaze <rybitwamateusz3@gmail.com>
This commit is contained in:
parent
ad9ccaa800
commit
b29acbd784
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -79,7 +79,7 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";
|
|||
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
|
||||
|
||||
// Document
|
||||
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.17"; // Remember to update the demo artwork in /demos with both this version number and the contents so it remains editable
|
||||
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.18"; // Remember to update the demo artwork in /demos with both this version number and the contents so it remains editable
|
||||
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
|
||||
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
|
||||
pub const MAX_UNDO_HISTORY_LEN: usize = 100; // TODO: Add this to user preferences
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ pub fn default_mapping() -> Mapping {
|
|||
refresh_keys=[Control],
|
||||
action_dispatch=NavigationMessage::PointerMove { snap_angle: Control, wait_for_snap_angle_release: true, snap_zoom: Control, zoom_from_viewport: None },
|
||||
),
|
||||
entry!(KeyDown(Lmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Lmb }),
|
||||
entry!(KeyDown(Mmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Mmb }),
|
||||
entry!(KeyDown(Rmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Rmb }),
|
||||
// NORMAL PRIORITY:
|
||||
//
|
||||
// NodeGraphMessage
|
||||
|
|
@ -106,8 +109,7 @@ pub fn default_mapping() -> Mapping {
|
|||
entry!(KeyUp(Lmb); modifiers=[Shift], action_dispatch=NavigateToolMessage::ClickZoom { zoom_in: false }),
|
||||
entry!(KeyUp(Lmb); action_dispatch=NavigateToolMessage::ClickZoom { zoom_in: true }),
|
||||
entry!(PointerMove; refresh_keys=[Control], action_dispatch=NavigateToolMessage::PointerMove { snap_angle: Control, snap_zoom: Control }),
|
||||
entry!(KeyDown(Mmb); action_dispatch=NavigateToolMessage::TranslateCanvasBegin),
|
||||
entry!(KeyDown(Rmb); action_dispatch=NavigateToolMessage::RotateCanvasBegin),
|
||||
entry!(KeyDown(Lmb); modifiers=[Alt], action_dispatch=NavigateToolMessage::RotateCanvasBegin),
|
||||
entry!(KeyDown(Lmb); action_dispatch=NavigateToolMessage::ZoomCanvasBegin),
|
||||
entry!(KeyUp(Rmb); action_dispatch=NavigateToolMessage::TransformCanvasEnd),
|
||||
entry!(KeyUp(Lmb); action_dispatch=NavigateToolMessage::TransformCanvasEnd),
|
||||
|
|
@ -315,12 +317,15 @@ pub fn default_mapping() -> Mapping {
|
|||
entry!(KeyDown(KeyS); action_dispatch=TransformLayerMessage::BeginScale),
|
||||
//
|
||||
// NavigationMessage
|
||||
entry!(KeyDown(Mmb); modifiers=[Control], action_dispatch=NavigationMessage::RotateCanvasBegin),
|
||||
entry!(KeyDown(Lmb); modifiers=[Alt], action_dispatch=NavigationMessage::RotateCanvasBegin { was_dispatched_from_menu: false }),
|
||||
entry!(KeyDown(Mmb); modifiers=[Alt], action_dispatch=NavigationMessage::RotateCanvasBegin { was_dispatched_from_menu: false }),
|
||||
entry!(KeyDown(Mmb); modifiers=[Shift], action_dispatch=NavigationMessage::ZoomCanvasBegin),
|
||||
entry!(KeyDown(Lmb); modifiers=[Shift, Space], action_dispatch=NavigationMessage::ZoomCanvasBegin),
|
||||
entry!(KeyDown(Mmb); action_dispatch=NavigationMessage::TranslateCanvasBegin),
|
||||
entry!(KeyUp(Mmb); action_dispatch=NavigationMessage::TransformCanvasEnd),
|
||||
entry!(KeyUp(Mmb); action_dispatch=NavigationMessage::TransformCanvasEnd { abort_transform: false }),
|
||||
entry!(KeyDown(Lmb); modifiers=[Space], action_dispatch=NavigationMessage::TranslateCanvasBegin),
|
||||
entry!(KeyUp(Lmb); action_dispatch=NavigationMessage::TransformCanvasEnd),
|
||||
entry!(KeyUp(Lmb); action_dispatch=NavigationMessage::TransformCanvasEnd { abort_transform: false }),
|
||||
entry!(KeyUp(Rmb); action_dispatch=NavigationMessage::TransformCanvasEnd { abort_transform: true }),
|
||||
entry!(KeyDown(NumpadAdd); modifiers=[Accel], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
||||
entry!(KeyDown(Equal); modifiers=[Accel], action_dispatch=NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }),
|
||||
entry!(KeyDown(Minus); modifiers=[Accel], action_dispatch=NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }),
|
||||
|
|
@ -334,8 +339,8 @@ pub fn default_mapping() -> Mapping {
|
|||
entry!(KeyDown(Period); action_dispatch=NavigationMessage::FitViewportToSelection),
|
||||
//
|
||||
// PortfolioMessage
|
||||
entry!(KeyUp(Space); action_dispatch=PortfolioMessage::GraphViewOverlayToggle),
|
||||
entry!(KeyDownNoRepeat(Space); action_dispatch=PortfolioMessage::GraphViewOverlayToggleDisabled { disabled: false }),
|
||||
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=PortfolioMessage::GraphViewOverlayToggle),
|
||||
entry!(KeyUp(Escape); action_dispatch=PortfolioMessage::GraphViewOverlay { open: false }),
|
||||
entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument),
|
||||
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
|
||||
entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
||||
|
|
|
|||
|
|
@ -27,14 +27,21 @@ pub enum NavigationMessage {
|
|||
snap_zoom: Key,
|
||||
zoom_from_viewport: Option<DVec2>,
|
||||
},
|
||||
RotateCanvasBegin,
|
||||
RotateCanvasBegin {
|
||||
was_dispatched_from_menu: bool,
|
||||
},
|
||||
SetCanvasRotation {
|
||||
angle_radians: f64,
|
||||
},
|
||||
SetCanvasZoom {
|
||||
zoom_factor: f64,
|
||||
},
|
||||
TransformCanvasEnd,
|
||||
TransformCanvasEnd {
|
||||
abort_transform: bool,
|
||||
},
|
||||
TransformFromMenuEnd {
|
||||
commit_key: Key,
|
||||
},
|
||||
TranslateCanvas {
|
||||
delta: DVec2,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::consts::{
|
|||
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, VIEWPORT_ZOOM_WHEEL_RATE,
|
||||
};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup};
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion};
|
||||
use crate::messages::input_mapper::utility_types::input_mouse::{ViewportBounds, ViewportPosition};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||
|
|
@ -15,39 +15,35 @@ use graphene_core::renderer::format_transform_matrix;
|
|||
use glam::{DAffine2, DVec2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
enum TransformOperation {
|
||||
None,
|
||||
Pan { pre_commit_pan: DVec2 },
|
||||
Rotate { pre_commit_tilt: f64, snap_tilt: bool, snap_tilt_released: bool },
|
||||
Zoom { pre_commit_zoom: f64, snap_zoom_enabled: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct NavigationMessageHandler {
|
||||
pub pan: DVec2,
|
||||
panning: bool,
|
||||
snap_tilt: bool,
|
||||
snap_tilt_released: bool,
|
||||
|
||||
pub tilt: f64,
|
||||
tilting: bool,
|
||||
|
||||
pub zoom: f64,
|
||||
zooming: bool,
|
||||
snap_zoom: bool,
|
||||
|
||||
transform_operation: TransformOperation,
|
||||
mouse_position: ViewportPosition,
|
||||
finish_operation_with_click: bool,
|
||||
}
|
||||
|
||||
impl Default for NavigationMessageHandler {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pan: DVec2::ZERO,
|
||||
panning: false,
|
||||
snap_tilt: false,
|
||||
snap_tilt_released: false,
|
||||
|
||||
tilt: 0.,
|
||||
tilting: false,
|
||||
|
||||
zoom: 1.,
|
||||
zooming: false,
|
||||
snap_zoom: false,
|
||||
|
||||
mouse_position: ViewportPosition::default(),
|
||||
finish_operation_with_click: false,
|
||||
transform_operation: TransformOperation::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,75 +120,99 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
snap_zoom,
|
||||
zoom_from_viewport,
|
||||
} => {
|
||||
if self.panning {
|
||||
let delta = ipp.mouse.position - self.mouse_position;
|
||||
match self.transform_operation {
|
||||
TransformOperation::None => {}
|
||||
TransformOperation::Pan { .. } => {
|
||||
let delta = ipp.mouse.position - self.mouse_position;
|
||||
responses.add(TranslateCanvas { delta });
|
||||
}
|
||||
TransformOperation::Rotate {
|
||||
snap_tilt,
|
||||
snap_tilt_released,
|
||||
pre_commit_tilt,
|
||||
} => {
|
||||
let new_snap = ipp.keyboard.get(snap_angle as usize);
|
||||
|
||||
responses.add(TranslateCanvas { delta });
|
||||
}
|
||||
|
||||
if self.tilting {
|
||||
let new_snap = ipp.keyboard.get(snap_angle as usize);
|
||||
if !(wait_for_snap_angle_release && new_snap && !self.snap_tilt_released) {
|
||||
// When disabling snap, keep the viewed rotation as it was previously.
|
||||
if !new_snap && self.snap_tilt {
|
||||
self.tilt = self.snapped_angle();
|
||||
if !(wait_for_snap_angle_release && new_snap && !snap_tilt_released) {
|
||||
// When disabling snap, keep the viewed rotation as it was previously.
|
||||
if !new_snap && snap_tilt {
|
||||
self.tilt = self.snapped_angle();
|
||||
}
|
||||
self.transform_operation = TransformOperation::Rotate {
|
||||
pre_commit_tilt,
|
||||
snap_tilt: new_snap,
|
||||
snap_tilt_released: true,
|
||||
};
|
||||
}
|
||||
self.snap_tilt = new_snap;
|
||||
self.snap_tilt_released = true;
|
||||
|
||||
let half_viewport = ipp.viewport_bounds.size() / 2.;
|
||||
let rotation = {
|
||||
let start_offset = self.mouse_position - half_viewport;
|
||||
let end_offset = ipp.mouse.position - half_viewport;
|
||||
start_offset.angle_between(end_offset)
|
||||
};
|
||||
|
||||
responses.add(SetCanvasRotation { angle_radians: self.tilt + rotation });
|
||||
}
|
||||
TransformOperation::Zoom { snap_zoom_enabled, pre_commit_zoom } => {
|
||||
let zoom_start = self.snapped_scale();
|
||||
|
||||
let half_viewport = ipp.viewport_bounds.size() / 2.;
|
||||
let rotation = {
|
||||
let start_offset = self.mouse_position - half_viewport;
|
||||
let end_offset = ipp.mouse.position - half_viewport;
|
||||
start_offset.angle_between(end_offset)
|
||||
};
|
||||
let new_snap = ipp.keyboard.get(snap_zoom as usize);
|
||||
// When disabling snap, keep the viewed zoom as it was previously
|
||||
if !new_snap && snap_zoom_enabled {
|
||||
self.zoom = self.snapped_scale();
|
||||
}
|
||||
|
||||
responses.add(SetCanvasRotation { angle_radians: self.tilt + rotation });
|
||||
}
|
||||
if snap_zoom_enabled != new_snap {
|
||||
self.transform_operation = TransformOperation::Zoom {
|
||||
pre_commit_zoom,
|
||||
snap_zoom_enabled: new_snap,
|
||||
};
|
||||
}
|
||||
|
||||
if self.zooming {
|
||||
let zoom_start = self.snapped_scale();
|
||||
let difference = self.mouse_position.y - ipp.mouse.position.y;
|
||||
let amount = 1. + difference * VIEWPORT_ZOOM_MOUSE_RATE;
|
||||
|
||||
let new_snap = ipp.keyboard.get(snap_zoom as usize);
|
||||
// When disabling snap, keep the viewed zoom as it was previously
|
||||
if !new_snap && self.snap_zoom {
|
||||
self.zoom = self.snapped_scale();
|
||||
}
|
||||
self.snap_zoom = new_snap;
|
||||
self.zoom *= amount;
|
||||
self.zoom *= Self::clamp_zoom(self.zoom, document_bounds, old_zoom, ipp);
|
||||
|
||||
let difference = self.mouse_position.y - ipp.mouse.position.y;
|
||||
let amount = 1. + difference * VIEWPORT_ZOOM_MOUSE_RATE;
|
||||
if let Some(mouse) = zoom_from_viewport {
|
||||
let zoom_factor = self.snapped_scale() / zoom_start;
|
||||
|
||||
self.zoom *= amount;
|
||||
self.zoom *= Self::clamp_zoom(self.zoom, document_bounds, old_zoom, ipp);
|
||||
|
||||
if let Some(mouse) = zoom_from_viewport {
|
||||
let zoom_factor = self.snapped_scale() / zoom_start;
|
||||
|
||||
responses.add(SetCanvasZoom { zoom_factor: self.zoom });
|
||||
responses.add(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, mouse));
|
||||
} else {
|
||||
responses.add(SetCanvasZoom { zoom_factor: self.zoom });
|
||||
responses.add(SetCanvasZoom { zoom_factor: self.zoom });
|
||||
responses.add(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, mouse));
|
||||
} else {
|
||||
responses.add(SetCanvasZoom { zoom_factor: self.zoom });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
}
|
||||
RotateCanvasBegin => {
|
||||
RotateCanvasBegin { was_dispatched_from_menu } => {
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
|
||||
responses.add(FrontendMessage::UpdateInputHints {
|
||||
hint_data: HintData(vec![HintGroup(vec![HintInfo {
|
||||
key_groups: vec![KeysGroup(vec![Key::Control]).into()],
|
||||
key_groups_mac: None,
|
||||
mouse: None,
|
||||
label: String::from("Snap 15°"),
|
||||
plus: false,
|
||||
}])]),
|
||||
hint_data: HintData(vec![
|
||||
HintGroup(vec![HintInfo {
|
||||
key_groups: vec![KeysGroup(vec![Key::Control]).into()],
|
||||
key_groups_mac: None,
|
||||
mouse: None,
|
||||
label: String::from("Snap 15°"),
|
||||
plus: false,
|
||||
}]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Confirm")]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, "Abort")]),
|
||||
]),
|
||||
});
|
||||
|
||||
self.tilting = true;
|
||||
self.transform_operation = TransformOperation::Rotate {
|
||||
pre_commit_tilt: self.tilt,
|
||||
snap_tilt_released: false,
|
||||
snap_tilt: false,
|
||||
};
|
||||
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
self.finish_operation_with_click = was_dispatched_from_menu;
|
||||
}
|
||||
SetCanvasRotation { angle_radians } => {
|
||||
self.tilt = angle_radians;
|
||||
|
|
@ -208,19 +228,38 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||
}
|
||||
TransformCanvasEnd => {
|
||||
TransformCanvasEnd { abort_transform } => {
|
||||
if abort_transform {
|
||||
match self.transform_operation {
|
||||
TransformOperation::None => {}
|
||||
TransformOperation::Rotate { pre_commit_tilt, .. } => {
|
||||
responses.add(SetCanvasRotation { angle_radians: pre_commit_tilt });
|
||||
}
|
||||
TransformOperation::Pan { pre_commit_pan, .. } => {
|
||||
self.pan = pre_commit_pan;
|
||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||
}
|
||||
TransformOperation::Zoom { pre_commit_zoom, .. } => {
|
||||
self.zoom = pre_commit_zoom;
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tilt = self.snapped_angle();
|
||||
self.zoom = self.snapped_scale();
|
||||
responses.add(BroadcastEvent::CanvasTransformed);
|
||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||
responses.add(ToolMessage::UpdateCursor);
|
||||
responses.add(ToolMessage::UpdateHints);
|
||||
self.snap_tilt = false;
|
||||
self.snap_tilt_released = false;
|
||||
self.snap_zoom = false;
|
||||
self.panning = false;
|
||||
self.tilting = false;
|
||||
self.zooming = false;
|
||||
self.transform_operation = TransformOperation::None;
|
||||
responses.add(PortfolioMessage::GraphViewOverlayToggleDisabled { disabled: false });
|
||||
}
|
||||
TransformFromMenuEnd { commit_key } => {
|
||||
let abort_transform = commit_key == Key::Rmb;
|
||||
self.finish_operation_with_click = false;
|
||||
responses.add(TransformCanvasEnd { abort_transform });
|
||||
}
|
||||
TranslateCanvas { delta } => {
|
||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
|
||||
|
|
@ -232,13 +271,16 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
}
|
||||
TranslateCanvasBegin => {
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Grabbing });
|
||||
responses.add(FrontendMessage::UpdateInputHints { hint_data: HintData(Vec::new()) });
|
||||
|
||||
responses.add(FrontendMessage::UpdateInputHints {
|
||||
hint_data: HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, "Abort")])]),
|
||||
});
|
||||
// Because the pan key shares the Spacebar with toggling the graph view overlay, now that we've begun panning,
|
||||
// we need to prevent the graph view overlay from toggling when the Spacebar is released.
|
||||
// we need to prevent the graph view overlay from toggling when the control key is pressed.
|
||||
responses.add(PortfolioMessage::GraphViewOverlayToggleDisabled { disabled: true });
|
||||
|
||||
self.panning = true;
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
self.transform_operation = TransformOperation::Pan { pre_commit_pan: self.pan };
|
||||
}
|
||||
TranslateCanvasByViewportFraction { delta } => {
|
||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
|
||||
|
|
@ -268,17 +310,27 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
ZoomCanvasBegin => {
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::ZoomIn });
|
||||
responses.add(FrontendMessage::UpdateInputHints {
|
||||
hint_data: HintData(vec![HintGroup(vec![HintInfo {
|
||||
key_groups: vec![KeysGroup(vec![Key::Control]).into()],
|
||||
key_groups_mac: None,
|
||||
mouse: None,
|
||||
label: String::from("Snap Increments"),
|
||||
plus: false,
|
||||
}])]),
|
||||
hint_data: HintData(vec![
|
||||
HintGroup(vec![HintInfo {
|
||||
key_groups: vec![KeysGroup(vec![Key::Control]).into()],
|
||||
key_groups_mac: None,
|
||||
mouse: None,
|
||||
label: String::from("Snap Increments"),
|
||||
plus: false,
|
||||
}]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, "Abort")]),
|
||||
]),
|
||||
});
|
||||
|
||||
self.zooming = true;
|
||||
self.transform_operation = TransformOperation::Zoom {
|
||||
pre_commit_zoom: self.zoom,
|
||||
snap_zoom_enabled: false,
|
||||
};
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
|
||||
// Because the zoom key shares the Spacebar with toggling the graph view overlay, now that we've begun zooming,
|
||||
// we need to prevent the graph view overlay from toggling when the control key is pressed.
|
||||
responses.add(PortfolioMessage::GraphViewOverlayToggleDisabled { disabled: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -298,13 +350,22 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
FitViewportToSelection,
|
||||
);
|
||||
|
||||
if self.panning || self.tilting || self.zooming {
|
||||
if self.transform_operation != TransformOperation::None {
|
||||
let transforming = actions!(NavigationMessageDiscriminant;
|
||||
PointerMove,
|
||||
TransformCanvasEnd,
|
||||
);
|
||||
common.extend(transforming);
|
||||
}
|
||||
|
||||
if self.finish_operation_with_click {
|
||||
let transforming_from_menu = actions!(NavigationMessageDiscriminant;
|
||||
TransformFromMenuEnd,
|
||||
);
|
||||
|
||||
common.extend(transforming_from_menu);
|
||||
}
|
||||
|
||||
common
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +373,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||
impl NavigationMessageHandler {
|
||||
pub fn snapped_angle(&self) -> f64 {
|
||||
let increment_radians: f64 = VIEWPORT_ROTATE_SNAP_INTERVAL.to_radians();
|
||||
if self.snap_tilt {
|
||||
if let TransformOperation::Rotate { snap_tilt: true, .. } = self.transform_operation {
|
||||
(self.tilt / increment_radians).round() * increment_radians
|
||||
} else {
|
||||
self.tilt
|
||||
|
|
@ -320,7 +381,7 @@ impl NavigationMessageHandler {
|
|||
}
|
||||
|
||||
pub fn snapped_scale(&self) -> f64 {
|
||||
if self.snap_zoom {
|
||||
if let TransformOperation::Zoom { snap_zoom_enabled: true, .. } = self.transform_operation {
|
||||
*VIEWPORT_ZOOM_LEVELS
|
||||
.iter()
|
||||
.min_by(|a, b| (**a - self.zoom).abs().partial_cmp(&(**b - self.zoom).abs()).unwrap())
|
||||
|
|
|
|||
|
|
@ -257,36 +257,68 @@ impl LayoutHolder for MenuBarMessageHandler {
|
|||
MenuBarEntry::new_root(
|
||||
"View".into(),
|
||||
no_active_document,
|
||||
MenuBarEntryChildren(vec![vec![
|
||||
MenuBarEntry {
|
||||
label: "Zoom to Selected".into(),
|
||||
MenuBarEntryChildren(vec![
|
||||
vec![
|
||||
MenuBarEntry {
|
||||
label: "Tilt".into(),
|
||||
shortcut: action_keys!(NavigationMessageDiscriminant::RotateCanvasBegin),
|
||||
action: MenuBarEntry::create_action(|_| NavigationMessage::RotateCanvasBegin { was_dispatched_from_menu: true }.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Reset Tilt".into(),
|
||||
shortcut: action_keys!(NavigationMessageDiscriminant::SetCanvasRotation),
|
||||
action: MenuBarEntry::create_action(|_| NavigationMessage::SetCanvasRotation { angle_radians: 0.into() }.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
],
|
||||
vec![
|
||||
MenuBarEntry {
|
||||
label: "Zoom In".into(),
|
||||
shortcut: action_keys!(NavigationMessageDiscriminant::IncreaseCanvasZoom),
|
||||
action: MenuBarEntry::create_action(|_| NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom Out".into(),
|
||||
shortcut: action_keys!(NavigationMessageDiscriminant::DecreaseCanvasZoom),
|
||||
action: MenuBarEntry::create_action(|_| NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to Fit".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasToFitAll),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasToFitAll.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to 100%".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo100Percent),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo100Percent.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to 200%".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo200Percent),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo200Percent.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
],
|
||||
vec![MenuBarEntry {
|
||||
label: "Frame Selected".into(),
|
||||
shortcut: action_keys!(NavigationMessageDiscriminant::FitViewportToSelection),
|
||||
action: MenuBarEntry::create_action(|_| NavigationMessage::FitViewportToSelection.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to Fit".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasToFitAll),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasToFitAll.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to 100%".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo100Percent),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo100Percent.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
MenuBarEntry {
|
||||
label: "Zoom to 200%".into(),
|
||||
shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo200Percent),
|
||||
action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo200Percent.into()),
|
||||
disabled: no_active_document,
|
||||
..MenuBarEntry::default()
|
||||
},
|
||||
]]),
|
||||
}],
|
||||
]),
|
||||
),
|
||||
MenuBarEntry::new_root(
|
||||
"Help".into(),
|
||||
|
|
|
|||
|
|
@ -557,6 +557,11 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||
PrevDocument,
|
||||
);
|
||||
|
||||
if self.graph_view_overlay_open {
|
||||
let escape = actions!(PortfolioMessageDiscriminant; GraphViewOverlay);
|
||||
common.extend(escape);
|
||||
}
|
||||
|
||||
if let Some(document) = self.active_document() {
|
||||
if document.layer_metadata.values().any(|data| data.selected) {
|
||||
let select = actions!(PortfolioMessageDiscriminant;
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ impl Fsm for NavigateToolFsmState {
|
|||
|
||||
match navigate {
|
||||
ClickZoom { zoom_in } => {
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd);
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd { abort_transform: false });
|
||||
|
||||
// Mouse has not moved from pointerdown to pointerup
|
||||
if tool_data.drag_start == input.mouse.position {
|
||||
|
|
@ -146,7 +146,7 @@ impl Fsm for NavigateToolFsmState {
|
|||
}
|
||||
RotateCanvasBegin => {
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
responses.add_front(NavigationMessage::RotateCanvasBegin);
|
||||
responses.add_front(NavigationMessage::RotateCanvasBegin { was_dispatched_from_menu: false });
|
||||
NavigateToolFsmState::Tilting
|
||||
}
|
||||
ZoomCanvasBegin => {
|
||||
|
|
@ -155,11 +155,11 @@ impl Fsm for NavigateToolFsmState {
|
|||
NavigateToolFsmState::Zooming
|
||||
}
|
||||
TransformCanvasEnd => {
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd);
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd { abort_transform: false });
|
||||
NavigateToolFsmState::Ready
|
||||
}
|
||||
Abort => {
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd);
|
||||
responses.add_front(NavigationMessage::TransformCanvasEnd { abort_transform: false });
|
||||
NavigateToolFsmState::Ready
|
||||
}
|
||||
}
|
||||
|
|
@ -173,8 +173,12 @@ impl Fsm for NavigateToolFsmState {
|
|||
NavigateToolFsmState::Ready => HintData(vec![
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Zoom In"), HintInfo::keys([Key::Shift], "Zoom Out").prepend_plus()]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Zoom"), HintInfo::keys([Key::Control], "Snap Increments").prepend_plus()]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::MmbDrag, "Pan")]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::RmbDrag, "Tilt"), HintInfo::keys([Key::Control], "Snap 15°").prepend_plus()]),
|
||||
HintGroup(vec![
|
||||
HintInfo::mouse(MouseMotion::LmbDrag, " "),
|
||||
HintInfo::keys([Key::Space], "Or").prepend_plus(),
|
||||
HintInfo::mouse(MouseMotion::MmbDrag, "Pan"),
|
||||
]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, ""), HintInfo::keys([Key::Alt], "Tilt").prepend_plus()]),
|
||||
]),
|
||||
NavigateToolFsmState::Tilting => HintData(vec![HintGroup(vec![HintInfo::keys([Key::Control], "Snap 15°")])]),
|
||||
NavigateToolFsmState::Zooming => HintData(vec![HintGroup(vec![HintInfo::keys([Key::Control], "Snap Increments")])]),
|
||||
|
|
|
|||
Loading…
Reference in New Issue