Skip to content

Commit d12219e

Browse files
authored
Improvements to the layer transform cage UX (#589)
* Allow input system to handle mousedown while dragging * Fix abort * Add apsect ratio * Make comment more explicit * Fix abort when dragging * Constrain when dragging edge
1 parent a7431be commit d12219e

File tree

5 files changed

+57
-32
lines changed

5 files changed

+57
-32
lines changed

editor/src/input/input_mapper.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl Default for Mapping {
4545
entry! {action=SelectToolMessage::PointerMove { axis_align: KeyShift, snap_angle: KeyControl, center: KeyAlt }, message=InputMapperMessage::PointerMove},
4646
entry! {action=SelectToolMessage::DragStart { add_to_selection: KeyShift }, key_down=Lmb},
4747
entry! {action=SelectToolMessage::DragStop, key_up=Lmb},
48+
entry! {action=SelectToolMessage::DragStop, key_down=KeyEnter},
4849
entry! {action=SelectToolMessage::EditLayer, message=InputMapperMessage::DoubleClick},
4950
entry! {action=SelectToolMessage::Abort, key_down=Rmb},
5051
entry! {action=SelectToolMessage::Abort, key_down=KeyEscape},

editor/src/input/input_preprocessor_message_handler.rs

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::input_preprocessor::{KeyPosition, ModifierKeys};
1+
use super::input_preprocessor::ModifierKeys;
22
use super::keyboard::{Key, KeyStates};
33
use super::mouse::{MouseKeys, MouseState, ViewportBounds};
44
use crate::message_prelude::*;
@@ -83,9 +83,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
8383
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
8484
self.mouse.position = mouse_state.position;
8585

86-
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Pressed) {
87-
responses.push_back(message);
88-
}
86+
self.translate_mouse_event(mouse_state, responses);
8987
}
9088
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
9189
self.handle_modifier_keys(modifier_keys, responses);
@@ -94,16 +92,17 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
9492
self.mouse.position = mouse_state.position;
9593

9694
responses.push_back(InputMapperMessage::PointerMove.into());
95+
96+
// While any pointer button is already down, additional button down events are not reported, but they are sent as `pointermove` events
97+
self.translate_mouse_event(mouse_state, responses);
9798
}
9899
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
99100
self.handle_modifier_keys(modifier_keys, responses);
100101

101102
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
102103
self.mouse.position = mouse_state.position;
103104

104-
if let Some(message) = self.translate_mouse_event(mouse_state, KeyPosition::Released) {
105-
responses.push_back(message);
106-
}
105+
self.translate_mouse_event(mouse_state, responses);
107106
}
108107
};
109108
}
@@ -115,27 +114,20 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
115114
}
116115

117116
impl InputPreprocessorMessageHandler {
118-
fn translate_mouse_event(&mut self, new_state: MouseState, position: KeyPosition) -> Option<Message> {
119-
// Calculate the difference between the two key states (binary xor)
120-
let difference = self.mouse.mouse_keys ^ new_state.mouse_keys;
121-
122-
self.mouse = new_state;
123-
124-
let key = match difference {
125-
MouseKeys::LEFT => Key::Lmb,
126-
MouseKeys::RIGHT => Key::Rmb,
127-
MouseKeys::MIDDLE => Key::Mmb,
128-
MouseKeys::NONE => return None, // self.mouse.mouse_keys was invalid, e.g. when a drag began outside the client
129-
_ => {
130-
log::warn!("The number of buttons modified at the same time was greater than 1. Modification: {:#010b}", difference);
131-
Key::UnknownKey
117+
fn translate_mouse_event(&mut self, new_state: MouseState, responses: &mut VecDeque<Message>) {
118+
for (bit_flag, key) in [(MouseKeys::LEFT, Key::Lmb), (MouseKeys::RIGHT, Key::Rmb), (MouseKeys::MIDDLE, Key::Mmb)] {
119+
// Calculate the intersection between the two key states
120+
let old_down = self.mouse.mouse_keys & bit_flag == bit_flag;
121+
let new_down = new_state.mouse_keys & bit_flag == bit_flag;
122+
if !old_down && new_down {
123+
responses.push_back(InputMapperMessage::KeyDown(key).into());
132124
}
133-
};
125+
if old_down && !new_down {
126+
responses.push_back(InputMapperMessage::KeyUp(key).into());
127+
}
128+
}
134129

135-
Some(match position {
136-
KeyPosition::Pressed => InputMapperMessage::KeyDown(key).into(),
137-
KeyPosition::Released => InputMapperMessage::KeyUp(key).into(),
138-
})
130+
self.mouse = new_state;
139131
}
140132

141133
fn handle_modifier_keys(&mut self, modifier_keys: ModifierKeys, responses: &mut VecDeque<Message>) {

editor/src/viewport_tools/tools/select_tool.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ impl<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> for SelectTool {
254254

255255
match self.fsm_state {
256256
Ready => actions!(SelectToolMessageDiscriminant; DragStart, PointerMove, EditLayer),
257-
Dragging => actions!(SelectToolMessageDiscriminant; DragStop, PointerMove, EditLayer),
258257
_ => actions!(SelectToolMessageDiscriminant; DragStop, PointerMove, Abort, EditLayer),
259258
}
260259
}
@@ -588,11 +587,27 @@ impl Fsm for SelectToolFsmState {
588587
);
589588
Ready
590589
}
590+
(Dragging, Abort) => {
591+
data.snap_handler.cleanup(responses);
592+
responses.push_back(DocumentMessage::Undo.into());
593+
Ready
594+
}
591595
(_, Abort) => {
592596
if let Some(path) = data.drag_box_overlay_layer.take() {
593597
responses.push_front(DocumentMessage::Overlays(Operation::DeleteLayer { path }.into()).into())
594598
};
595-
if let Some(bounding_box_overlays) = data.bounding_box_overlays.take() {
599+
if let Some(mut bounding_box_overlays) = data.bounding_box_overlays.take() {
600+
let selected = data.layers_dragging.iter().collect::<Vec<_>>();
601+
let mut selected = Selected::new(
602+
&mut bounding_box_overlays.original_transforms,
603+
&mut bounding_box_overlays.pivot,
604+
&selected,
605+
responses,
606+
&document.graphene_document,
607+
);
608+
609+
selected.revert_operation();
610+
596611
bounding_box_overlays.delete(responses);
597612
}
598613

editor/src/viewport_tools/tools/shared/transformation_cage.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use graphene::color::Color;
88
use graphene::layers::style::{self, Fill, Stroke};
99
use graphene::Operation;
1010

11-
use glam::{DAffine2, DVec2, Vec2Swizzles};
11+
use glam::{DAffine2, DVec2};
1212

1313
/// Contains the edges that are being dragged along with the origional bounds
1414
#[derive(Clone, Debug, Default)]
@@ -18,11 +18,22 @@ pub struct SelectedEdges {
1818
bottom: bool,
1919
left: bool,
2020
right: bool,
21+
// Aspect ratio in the form of width/height, so x:1 = width:height
22+
aspect_ratio: f64,
2123
}
2224

2325
impl SelectedEdges {
2426
pub fn new(top: bool, bottom: bool, left: bool, right: bool, bounds: [DVec2; 2]) -> Self {
25-
Self { top, bottom, left, right, bounds }
27+
let size = (bounds[0] - bounds[1]).abs();
28+
let aspect_ratio = size.x / size.y;
29+
Self {
30+
top,
31+
bottom,
32+
left,
33+
right,
34+
bounds,
35+
aspect_ratio,
36+
}
2637
}
2738

2839
/// Calculate the pivot for the operation (the opposite point to the edge dragged)
@@ -67,8 +78,13 @@ impl SelectedEdges {
6778
}
6879

6980
let mut size = max - min;
70-
if constrain && ((self.top || self.bottom) && (self.left || self.right)) {
71-
size = size.abs().max(size.abs().yx()) * size.signum();
81+
if constrain {
82+
size = match ((self.top || self.bottom), (self.left || self.right)) {
83+
(true, true) => DVec2::new(size.x, size.x / self.aspect_ratio).abs().max(DVec2::new(size.y * self.aspect_ratio, size.y).abs()) * size.signum(),
84+
(true, false) => DVec2::new(size.y * self.aspect_ratio, size.y),
85+
(false, true) => DVec2::new(size.x, size.x / self.aspect_ratio),
86+
_ => size,
87+
};
7288
}
7389
if center {
7490
if self.left || self.right {

frontend/src/lifetime/input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
104104

105105
// Pointer events
106106

107+
// While any pointer button is already down, additional button down events are not reported, but they are sent as `pointermove` events and these are handled in the backend
107108
const onPointerMove = (e: PointerEvent): void => {
108109
if (!e.buttons) viewportPointerInteractionOngoing = false;
109110

0 commit comments

Comments
 (0)