mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Viewport canvas navigation with modifier keys and zoom widget (#229)
* Add rotation around the center * Document transform centred * Fix drawing hexagon on rotated document * Format * Fix translation on rotated document * Remove logging * Rotate around centre of viewport * Rotate with shift + MMB drag * Zoom with +/- keys * Rotation input field * Implement frontend zoom buttons * Zoom with ctrl + MMB * Format * Update number inputs * Require Ctrl + Plus / Minus key * Ctrl scroll * Update zoom -> Multiply Zoom * Fix typo * More fixing typo * Remove :v-on * Add mouse scroll X * Scrolling on document * Refactor * Format * Fix ctrl + plus/minus to zoom * Reduce zoom sensitivity * Ctrl + shift + mmb drag = snap rotate * Further reduce zoom speed * Add ctrl + number key to change zoom * Switch Ctrl and Shift for zoom and rotate * Fix compile errors * Format JS * Add increment to snap angle * Edit getting layerdata functions * Pass viewport size directily into create_document_transform_from_layerdata * Add to_dvec2() * Refactor get_transform * Get -> Calculate * Add consts * Use to_radians * Remove get from function names * Use .entry when getting layerdata that does not exist * Fix distance scroll calculations * Fix zooming. * Remove 'Violation' in chrome * Fix compile errors
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use crate::consts::{MINUS_KEY_MULTIPLIER, PLUS_KEY_MULTIPLIER};
|
||||
use crate::message_prelude::*;
|
||||
use crate::tool::ToolType;
|
||||
|
||||
@@ -13,6 +14,7 @@ const SHIFT_NUDGE_AMOUNT: f64 = 10.;
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum InputMapperMessage {
|
||||
PointerMove,
|
||||
MouseScroll,
|
||||
KeyUp(Key),
|
||||
KeyDown(Key),
|
||||
}
|
||||
@@ -62,6 +64,7 @@ struct Mapping {
|
||||
up: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
down: [KeyMappingEntries; NUMBER_OF_KEYS],
|
||||
pointer_move: KeyMappingEntries,
|
||||
mouse_scroll: KeyMappingEntries,
|
||||
}
|
||||
|
||||
macro_rules! modifiers {
|
||||
@@ -91,21 +94,23 @@ macro_rules! mapping {
|
||||
let mut up = KeyMappingEntries::key_array();
|
||||
let mut down = KeyMappingEntries::key_array();
|
||||
let mut pointer_move: KeyMappingEntries = Default::default();
|
||||
let mut mouse_scroll: KeyMappingEntries = Default::default();
|
||||
$(
|
||||
let arr = match $entry.trigger {
|
||||
InputMapperMessage::KeyDown(key) => &mut down[key as usize],
|
||||
InputMapperMessage::KeyUp(key) => &mut up[key as usize],
|
||||
InputMapperMessage::PointerMove => &mut pointer_move,
|
||||
InputMapperMessage::MouseScroll => &mut mouse_scroll,
|
||||
};
|
||||
arr.push($entry);
|
||||
)*
|
||||
(up, down, pointer_move)
|
||||
(up, down, pointer_move, mouse_scroll)
|
||||
}};
|
||||
}
|
||||
|
||||
impl Default for Mapping {
|
||||
fn default() -> Self {
|
||||
let (up, down, pointer_move) = mapping![
|
||||
let (up, down, pointer_move, mouse_scroll) = mapping![
|
||||
entry! {action=DocumentMessage::PasteLayers, key_down=KeyV, modifiers=[KeyControl]},
|
||||
// Select
|
||||
entry! {action=SelectMessage::MouseMove, message=InputMapperMessage::PointerMove},
|
||||
@@ -181,8 +186,18 @@ impl Default for Mapping {
|
||||
entry! {action=DocumentMessage::ExportDocument, key_down=KeyS, modifiers=[KeyControl, KeyShift]},
|
||||
entry! {action=DocumentMessage::ExportDocument, key_down=KeyE, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::MouseMove, message=InputMapperMessage::PointerMove},
|
||||
entry! {action=DocumentMessage::RotateDown{snap:true}, key_down=Mmb, modifiers=[KeyControl, KeyShift]},
|
||||
entry! {action=DocumentMessage::RotateDown{snap:false}, key_down=Mmb, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::ZoomDown, key_down=Mmb, modifiers=[KeyShift]},
|
||||
entry! {action=DocumentMessage::TranslateDown, key_down=Mmb},
|
||||
entry! {action=DocumentMessage::TranslateUp, key_up=Mmb},
|
||||
entry! {action=DocumentMessage::TransformUp, key_up=Mmb},
|
||||
entry! {action=DocumentMessage::MultiplyZoom(PLUS_KEY_MULTIPLIER), key_down=KeyPlus, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::MultiplyZoom(PLUS_KEY_MULTIPLIER), key_down=KeyEquals, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::MultiplyZoom(MINUS_KEY_MULTIPLIER), key_down=KeyMinus, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::SetZoom(1.), key_down=Key1, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::SetZoom(2.), key_down=Key2, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::WheelZoom, message=InputMapperMessage::MouseScroll, modifiers=[KeyControl]},
|
||||
entry! {action=DocumentMessage::WheelTranslate, message=InputMapperMessage::MouseScroll},
|
||||
entry! {action=DocumentMessage::NewDocument, key_down=KeyN, modifiers=[KeyShift]},
|
||||
entry! {action=DocumentMessage::NextDocument, key_down=KeyTab, modifiers=[KeyShift]},
|
||||
entry! {action=DocumentMessage::CloseActiveDocument, key_down=KeyW, modifiers=[KeyShift]},
|
||||
@@ -217,7 +232,7 @@ impl Default for Mapping {
|
||||
entry! {action=GlobalMessage::LogDebug, key_down=Key2},
|
||||
entry! {action=GlobalMessage::LogTrace, key_down=Key3},
|
||||
];
|
||||
Self { up, down, pointer_move }
|
||||
Self { up, down, pointer_move, mouse_scroll }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +243,7 @@ impl Mapping {
|
||||
KeyDown(key) => &self.down[key as usize],
|
||||
KeyUp(key) => &self.up[key as usize],
|
||||
PointerMove => &self.pointer_move,
|
||||
MouseScroll => &self.mouse_scroll,
|
||||
};
|
||||
list.match_mapping(keys, actions)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use std::usize;
|
||||
|
||||
use super::keyboard::{Key, KeyStates};
|
||||
use super::mouse::{MouseKeys, MouseState, ViewportPosition};
|
||||
use super::mouse::{MouseKeys, MouseState, ScrollDelta, ViewportPosition};
|
||||
use crate::message_prelude::*;
|
||||
use bitflags::bitflags;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use document_core::DocumentResponse;
|
||||
use glam::DVec2;
|
||||
|
||||
#[impl_message(Message, InputPreprocessor)]
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
@@ -14,8 +15,10 @@ pub enum InputPreprocessorMessage {
|
||||
MouseDown(MouseState, ModifierKeys),
|
||||
MouseUp(MouseState, ModifierKeys),
|
||||
MouseMove(ViewportPosition, ModifierKeys),
|
||||
MouseScroll(ScrollDelta, ModifierKeys),
|
||||
KeyUp(Key, ModifierKeys),
|
||||
KeyDown(Key, ModifierKeys),
|
||||
ViewportResize(ViewportPosition),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@@ -32,6 +35,7 @@ bitflags! {
|
||||
pub struct InputPreprocessor {
|
||||
pub keyboard: KeyStates,
|
||||
pub mouse: MouseState,
|
||||
pub viewport_size: ViewportPosition,
|
||||
}
|
||||
|
||||
enum KeyPosition {
|
||||
@@ -41,32 +45,46 @@ enum KeyPosition {
|
||||
|
||||
impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessor {
|
||||
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
|
||||
let response = match message {
|
||||
match message {
|
||||
InputPreprocessorMessage::MouseMove(pos, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.mouse.position = pos;
|
||||
InputMapperMessage::PointerMove.into()
|
||||
responses.push_back(InputMapperMessage::PointerMove.into());
|
||||
}
|
||||
InputPreprocessorMessage::MouseScroll(delta, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.mouse.scroll_delta = delta;
|
||||
responses.push_back(InputMapperMessage::MouseScroll.into());
|
||||
}
|
||||
InputPreprocessorMessage::MouseDown(state, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.translate_mouse_event(state, KeyPosition::Pressed)
|
||||
responses.push_back(self.translate_mouse_event(state, KeyPosition::Pressed));
|
||||
}
|
||||
InputPreprocessorMessage::MouseUp(state, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.translate_mouse_event(state, KeyPosition::Released)
|
||||
responses.push_back(self.translate_mouse_event(state, KeyPosition::Released));
|
||||
}
|
||||
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.keyboard.set(key as usize);
|
||||
InputMapperMessage::KeyDown(key).into()
|
||||
responses.push_back(InputMapperMessage::KeyDown(key).into());
|
||||
}
|
||||
InputPreprocessorMessage::KeyUp(key, modifier_keys) => {
|
||||
self.handle_modifier_keys(modifier_keys, responses);
|
||||
self.keyboard.unset(key as usize);
|
||||
InputMapperMessage::KeyUp(key).into()
|
||||
responses.push_back(InputMapperMessage::KeyUp(key).into());
|
||||
}
|
||||
InputPreprocessorMessage::ViewportResize(size) => {
|
||||
responses.push_back(
|
||||
document_core::Operation::TransformLayer {
|
||||
path: vec![],
|
||||
transform: glam::DAffine2::from_translation(DVec2::new((size.x as f64 - self.viewport_size.x as f64) / 2., (size.y as f64 - self.viewport_size.y as f64) / 2.)).to_cols_array(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
self.viewport_size = size;
|
||||
}
|
||||
};
|
||||
responses.push_back(response)
|
||||
}
|
||||
// clean user input and if possible reconstruct it
|
||||
// store the changes in the keyboard if it is a key event
|
||||
|
||||
@@ -55,6 +55,9 @@ pub enum Key {
|
||||
Key8,
|
||||
Key9,
|
||||
KeyEnter,
|
||||
KeyEquals,
|
||||
KeyMinus,
|
||||
KeyPlus,
|
||||
KeyShift,
|
||||
KeyControl,
|
||||
KeyDelete,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use bitflags::bitflags;
|
||||
use glam::DVec2;
|
||||
|
||||
// origin is top left
|
||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||
@@ -13,12 +14,31 @@ impl ViewportPosition {
|
||||
let y_diff = other.y as i64 - self.y as i64;
|
||||
f64::sqrt((x_diff * x_diff + y_diff * y_diff) as f64)
|
||||
}
|
||||
pub fn to_dvec2(&self) -> DVec2 {
|
||||
DVec2::new(self.x as f64, self.y as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||
pub struct ScrollDelta {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub z: i32,
|
||||
}
|
||||
impl ScrollDelta {
|
||||
pub fn new(x: i32, y: i32, z: i32) -> ScrollDelta {
|
||||
ScrollDelta { x, y, z }
|
||||
}
|
||||
pub fn to_dvec2(&self) -> DVec2 {
|
||||
DVec2::new(self.x as f64, self.y as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||
pub struct MouseState {
|
||||
pub position: ViewportPosition,
|
||||
pub mouse_keys: MouseKeys,
|
||||
pub scroll_delta: ScrollDelta,
|
||||
}
|
||||
|
||||
impl MouseState {
|
||||
@@ -30,11 +50,16 @@ impl MouseState {
|
||||
MouseState {
|
||||
position: ViewportPosition { x, y },
|
||||
mouse_keys: MouseKeys::default(),
|
||||
scroll_delta: ScrollDelta::default(),
|
||||
}
|
||||
}
|
||||
pub fn from_u8_pos(keys: u8, position: ViewportPosition) -> Self {
|
||||
let mouse_keys = MouseKeys::from_bits(keys).expect("invalid modifier keys");
|
||||
Self { position, mouse_keys }
|
||||
Self {
|
||||
position,
|
||||
mouse_keys,
|
||||
scroll_delta: ScrollDelta::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
|
||||
Reference in New Issue
Block a user