Set the mouse cursor in the canvas based on the current tool and its state (#480)
* Add FrontendMouseCursor and DisplayMouseCursor * Add update_cursor method to the Fsm trait and implement it for all tools * Rename DisplayMouseCursor to UpdateMouseCursor * Add 'To CSS Cursor Property' transform decorator and change the mouse cursor in the canvas based on the current tool and its state * Implement update_cursor for Navigate tool properly * Keep the cursor when dragging outside of the canvas * Change the mouse cursor to 'zoom-in' when LMB dragging on canvas with Navigate tool * Rename FrontendMouseCursor to MouseCursorIcon * Rename 'event' to 'e' and replace v-on with @ * Change the definition of the MouseCursorIcon type in TS * Replace switch with dictionary look-up * Move the definition of MouseCursorIcon closer to where it's used
This commit is contained in:
parent
e877eea457
commit
0515cc4eca
|
|
@ -1,4 +1,4 @@
|
||||||
use super::utility_types::FrontendDocumentDetails;
|
use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon};
|
||||||
use crate::document::layer_panel::{LayerPanelEntry, RawBuffer};
|
use crate::document::layer_panel::{LayerPanelEntry, RawBuffer};
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
use crate::misc::HintData;
|
use crate::misc::HintData;
|
||||||
|
|
@ -37,6 +37,7 @@ pub enum FrontendMessage {
|
||||||
UpdateDocumentRulers { origin: (f64, f64), spacing: f64, interval: f64 },
|
UpdateDocumentRulers { origin: (f64, f64), spacing: f64, interval: f64 },
|
||||||
UpdateDocumentScrollbars { position: (f64, f64), size: (f64, f64), multiplier: (f64, f64) },
|
UpdateDocumentScrollbars { position: (f64, f64), size: (f64, f64), multiplier: (f64, f64) },
|
||||||
UpdateInputHints { hint_data: HintData },
|
UpdateInputHints { hint_data: HintData },
|
||||||
|
UpdateMouseCursor { cursor: MouseCursorIcon },
|
||||||
UpdateOpenDocumentsList { open_documents: Vec<FrontendDocumentDetails> },
|
UpdateOpenDocumentsList { open_documents: Vec<FrontendDocumentDetails> },
|
||||||
UpdateWorkingColors { primary: Color, secondary: Color },
|
UpdateWorkingColors { primary: Color, secondary: Color },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,12 @@ pub struct FrontendDocumentDetails {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub enum MouseCursorIcon {
|
||||||
|
Default,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
|
Grabbing,
|
||||||
|
Crosshair,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ pub trait Fsm {
|
||||||
) -> Self;
|
) -> Self;
|
||||||
|
|
||||||
fn update_hints(&self, responses: &mut VecDeque<Message>);
|
fn update_hints(&self, responses: &mut VecDeque<Message>);
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -49,5 +49,6 @@ pub enum ToolMessage {
|
||||||
#[child]
|
#[child]
|
||||||
Shape(ShapeMessage),
|
Shape(ShapeMessage),
|
||||||
SwapColors,
|
SwapColors,
|
||||||
|
UpdateCursor,
|
||||||
UpdateHints,
|
UpdateHints,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,13 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the Abort state transition to the tool
|
// Send the Abort state transition to the tool
|
||||||
let mut send_abort_to_tool = |tool_type, message: ToolMessage, update_hints: bool| {
|
let mut send_abort_to_tool = |tool_type, message: ToolMessage, update_hints_and_cursor: bool| {
|
||||||
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
||||||
tool.process_action(message, (document, document_data, input), responses);
|
tool.process_action(message, (document, document_data, input), responses);
|
||||||
|
|
||||||
if update_hints {
|
if update_hints_and_cursor {
|
||||||
tool.process_action(ToolMessage::UpdateHints, (document, document_data, input), responses);
|
tool.process_action(ToolMessage::UpdateHints, (document, document_data, input), responses);
|
||||||
|
tool.process_action(ToolMessage::UpdateCursor, (document, document_data, input), responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use super::shared::resize::Resize;
|
use super::shared::resize::Resize;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -35,11 +36,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Ellipse {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,4 +184,8 @@ impl Fsm for EllipseToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::consts::SELECTION_TOLERANCE;
|
use crate::consts::SELECTION_TOLERANCE;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::MouseMotion;
|
use crate::input::keyboard::MouseMotion;
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -34,11 +35,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Eyedropper {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,4 +134,8 @@ impl Fsm for EyedropperToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::consts::SELECTION_TOLERANCE;
|
use crate::consts::SELECTION_TOLERANCE;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::MouseMotion;
|
use crate::input::keyboard::MouseMotion;
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -34,11 +35,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Fill {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,4 +128,8 @@ impl Fsm for FillToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::consts::LINE_ROTATE_SNAP_ANGLE;
|
use crate::consts::LINE_ROTATE_SNAP_ANGLE;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::mouse::ViewportPosition;
|
use crate::input::mouse::ViewportPosition;
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
|
|
@ -38,11 +39,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Line {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,6 +214,10 @@ impl Fsm for LineToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message {
|
fn generate_transform(data: &mut LineToolData, lock: bool, snap: bool, center: bool) -> Message {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -34,11 +35,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Navigate {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,4 +218,15 @@ impl Fsm for NavigateToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
let cursor = match *self {
|
||||||
|
NavigateToolFsmState::Ready => MouseCursorIcon::ZoomIn,
|
||||||
|
NavigateToolFsmState::Panning => MouseCursorIcon::Grabbing,
|
||||||
|
NavigateToolFsmState::Tilting => MouseCursorIcon::Default,
|
||||||
|
NavigateToolFsmState::Zooming => MouseCursorIcon::ZoomIn,
|
||||||
|
};
|
||||||
|
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::consts::{COLOR_ACCENT, VECTOR_MANIPULATOR_ANCHOR_MARKER_SIZE};
|
use crate::consts::{COLOR_ACCENT, VECTOR_MANIPULATOR_ANCHOR_MARKER_SIZE};
|
||||||
use crate::document::utility_types::{VectorManipulatorSegment, VectorManipulatorShape};
|
use crate::document::utility_types::{VectorManipulatorSegment, VectorManipulatorShape};
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -41,11 +42,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Path {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,6 +483,10 @@ impl Fsm for PathToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VectorManipulatorTypes {
|
struct VectorManipulatorTypes {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -44,11 +45,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Pen {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,6 +200,10 @@ impl Fsm for PenToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_preview(data: &PenToolData) -> Message {
|
fn remove_preview(data: &PenToolData) -> Message {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use super::shared::resize::Resize;
|
use super::shared::resize::Resize;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -35,11 +36,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Rectangle {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,4 +184,8 @@ impl Fsm for RectangleToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::consts::{COLOR_ACCENT, SELECTION_DRAG_ANGLE, SELECTION_TOLERANCE};
|
use crate::consts::{COLOR_ACCENT, SELECTION_DRAG_ANGLE, SELECTION_TOLERANCE};
|
||||||
use crate::document::utility_types::{AlignAggregate, AlignAxis, FlipAxis};
|
use crate::document::utility_types::{AlignAggregate, AlignAxis, FlipAxis};
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::mouse::ViewportPosition;
|
use crate::input::mouse::ViewportPosition;
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
|
|
@ -46,11 +47,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Select {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,4 +427,8 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use super::shared::resize::Resize;
|
use super::shared::resize::Resize;
|
||||||
use crate::document::DocumentMessageHandler;
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::input::keyboard::{Key, MouseMotion};
|
use crate::input::keyboard::{Key, MouseMotion};
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
use crate::message_prelude::*;
|
use crate::message_prelude::*;
|
||||||
|
|
@ -36,11 +37,17 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for Shape {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == ToolMessage::UpdateCursor {
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses);
|
||||||
|
|
||||||
if self.fsm_state != new_state {
|
if self.fsm_state != new_state {
|
||||||
self.fsm_state = new_state;
|
self.fsm_state = new_state;
|
||||||
self.fsm_state.update_hints(responses);
|
self.fsm_state.update_hints(responses);
|
||||||
|
self.fsm_state.update_cursor(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,4 +192,8 @@ impl Fsm for ShapeToolFsmState {
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
<CanvasRuler :origin="rulerOrigin.y" :majorMarkSpacing="rulerSpacing" :numberInterval="rulerInterval" :direction="'Vertical'" />
|
<CanvasRuler :origin="rulerOrigin.y" :majorMarkSpacing="rulerSpacing" :numberInterval="rulerInterval" :direction="'Vertical'" />
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
<LayoutCol :class="'canvas-area'">
|
<LayoutCol :class="'canvas-area'">
|
||||||
<div class="canvas" ref="canvas">
|
<div class="canvas" ref="canvas" :style="{ cursor: canvasCursor }" @pointerdown="(e: PointerEvent) => canvasPointerDown(e)">
|
||||||
<svg class="artboards" v-html="artboardSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
<svg class="artboards" v-html="artboardSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||||
<svg class="artwork" v-html="artworkSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
<svg class="artwork" v-html="artworkSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||||
<svg class="overlays" v-html="overlaysSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
<svg class="overlays" v-html="overlaysSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||||
|
|
@ -261,6 +261,7 @@ import {
|
||||||
UpdateCanvasRotation,
|
UpdateCanvasRotation,
|
||||||
ToolName,
|
ToolName,
|
||||||
UpdateDocumentArtboards,
|
UpdateDocumentArtboards,
|
||||||
|
UpdateMouseCursor,
|
||||||
} from "@/dispatcher/js-messages";
|
} from "@/dispatcher/js-messages";
|
||||||
|
|
||||||
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
||||||
|
|
@ -338,6 +339,10 @@ export default defineComponent({
|
||||||
resetWorkingColors() {
|
resetWorkingColors() {
|
||||||
this.editor.instance.reset_colors();
|
this.editor.instance.reset_colors();
|
||||||
},
|
},
|
||||||
|
canvasPointerDown(e: PointerEvent) {
|
||||||
|
const canvas = this.$refs.canvas as HTMLElement;
|
||||||
|
canvas.setPointerCapture(e.pointerId);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
|
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
|
||||||
|
|
@ -378,6 +383,10 @@ export default defineComponent({
|
||||||
this.documentRotation = (360 + (newRotation % 360)) % 360;
|
this.documentRotation = (360 + (newRotation % 360)) % 360;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.editor.dispatcher.subscribeJsMessage(UpdateMouseCursor, (updateMouseCursor) => {
|
||||||
|
this.canvasCursor = updateMouseCursor.cursor;
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener("resize", this.viewportResize);
|
window.addEventListener("resize", this.viewportResize);
|
||||||
window.addEventListener("DOMContentLoaded", this.viewportResize);
|
window.addEventListener("DOMContentLoaded", this.viewportResize);
|
||||||
},
|
},
|
||||||
|
|
@ -401,6 +410,7 @@ export default defineComponent({
|
||||||
overlaysSvg: "",
|
overlaysSvg: "",
|
||||||
canvasSvgWidth: "100%",
|
canvasSvgWidth: "100%",
|
||||||
canvasSvgHeight: "100%",
|
canvasSvgHeight: "100%",
|
||||||
|
canvasCursor: "default",
|
||||||
activeTool: "Select" as ToolName,
|
activeTool: "Select" as ToolName,
|
||||||
activeToolOptions: {},
|
activeToolOptions: {},
|
||||||
documentModeEntries,
|
documentModeEntries,
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,24 @@ export class UpdateDocumentRulers extends JsMessage {
|
||||||
readonly interval!: number;
|
readonly interval!: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MouseCursorIcon = "default" | "zoom-in" | "zoom-out" | "grabbing" | "crosshair";
|
||||||
|
|
||||||
|
const ToCssCursorProperty = Transform(({ value }) => {
|
||||||
|
const cssNames: Record<string, MouseCursorIcon> = {
|
||||||
|
ZoomIn: "zoom-in",
|
||||||
|
ZoomOut: "zoom-out",
|
||||||
|
Grabbing: "grabbing",
|
||||||
|
Crosshair: "crosshair",
|
||||||
|
};
|
||||||
|
|
||||||
|
return cssNames[value] || "default";
|
||||||
|
});
|
||||||
|
|
||||||
|
export class UpdateMouseCursor extends JsMessage {
|
||||||
|
@ToCssCursorProperty
|
||||||
|
readonly cursor!: MouseCursorIcon;
|
||||||
|
}
|
||||||
|
|
||||||
export class TriggerFileDownload extends JsMessage {
|
export class TriggerFileDownload extends JsMessage {
|
||||||
readonly document!: string;
|
readonly document!: string;
|
||||||
|
|
||||||
|
|
@ -378,6 +396,7 @@ export const messageConstructors: Record<string, MessageMaker> = {
|
||||||
UpdateWorkingColors,
|
UpdateWorkingColors,
|
||||||
UpdateCanvasZoom,
|
UpdateCanvasZoom,
|
||||||
UpdateCanvasRotation,
|
UpdateCanvasRotation,
|
||||||
|
UpdateMouseCursor,
|
||||||
DisplayDialogError,
|
DisplayDialogError,
|
||||||
DisplayDialogPanic,
|
DisplayDialogPanic,
|
||||||
DisplayConfirmationToCloseDocument,
|
DisplayConfirmationToCloseDocument,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue