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:
mobile-bungalow 2023-09-10 15:42:27 -07:00 committed by GitHub
parent ad9ccaa800
commit b29acbd784
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 249 additions and 133 deletions

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

View File

@ -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

View File

@ -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),

View File

@ -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,
},

View File

@ -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())

View File

@ -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(),

View File

@ -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;

View File

@ -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")])]),