mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 16:38:13 +08:00
Improve the Select tool's input hints (#1667)
* Refactor hints in SelectTool * Unify Keyhints and fix DrawingBox state so that it holds nested behaviour info * Code review cleanup; rename hints --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
dcce519426
commit
343523ab34
@@ -206,22 +206,20 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SelectT
|
|||||||
fn actions(&self) -> ActionList {
|
fn actions(&self) -> ActionList {
|
||||||
use SelectToolFsmState::*;
|
use SelectToolFsmState::*;
|
||||||
|
|
||||||
match self.fsm_state {
|
let mut common = actions!(SelectToolMessageDiscriminant;
|
||||||
Ready => actions!(SelectToolMessageDiscriminant;
|
PointerMove,
|
||||||
DragStart,
|
Abort,
|
||||||
PointerMove,
|
EditLayer,
|
||||||
Abort,
|
Enter,
|
||||||
EditLayer,
|
);
|
||||||
Enter,
|
|
||||||
),
|
let additional = match self.fsm_state {
|
||||||
_ => actions!(SelectToolMessageDiscriminant;
|
Ready { .. } => actions!(SelectToolMessageDiscriminant; DragStart),
|
||||||
DragStop,
|
_ => actions!(SelectToolMessageDiscriminant; DragStop),
|
||||||
PointerMove,
|
};
|
||||||
Abort,
|
common.extend(additional);
|
||||||
EditLayer,
|
|
||||||
Enter,
|
common
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,17 +232,21 @@ impl ToolTransition for SelectTool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
|
||||||
enum SelectToolFsmState {
|
enum SelectToolFsmState {
|
||||||
#[default]
|
Ready { selection: NestedSelectionBehavior },
|
||||||
Ready,
|
DrawingBox { selection: NestedSelectionBehavior },
|
||||||
Dragging,
|
Dragging,
|
||||||
DrawingBox,
|
|
||||||
ResizingBounds,
|
ResizingBounds,
|
||||||
RotatingBounds,
|
RotatingBounds,
|
||||||
DraggingPivot,
|
DraggingPivot,
|
||||||
}
|
}
|
||||||
|
impl Default for SelectToolFsmState {
|
||||||
|
fn default() -> Self {
|
||||||
|
let selection = NestedSelectionBehavior::Deepest;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct SelectToolData {
|
struct SelectToolData {
|
||||||
@@ -432,7 +434,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
tool_data.pivot.update_pivot(document, &mut overlay_context);
|
tool_data.pivot.update_pivot(document, &mut overlay_context);
|
||||||
|
|
||||||
// Update dragging box
|
// Update dragging box
|
||||||
if self == Self::DrawingBox {
|
if matches!(self, Self::DrawingBox { .. }) {
|
||||||
overlay_context.quad(Quad::from_box([tool_data.drag_start, tool_data.drag_current]));
|
overlay_context.quad(Quad::from_box([tool_data.drag_start, tool_data.drag_current]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +451,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Ready, SelectToolMessage::DragStart { add_to_selection, select_deepest }) => {
|
(SelectToolFsmState::Ready { .. }, SelectToolMessage::DragStart { add_to_selection, select_deepest }) => {
|
||||||
tool_data.drag_start = input.mouse.position;
|
tool_data.drag_start = input.mouse.position;
|
||||||
tool_data.drag_current = input.mouse.position;
|
tool_data.drag_current = input.mouse.position;
|
||||||
|
|
||||||
@@ -584,7 +586,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
responses.add(DocumentMessage::DeselectAllLayers);
|
responses.add(DocumentMessage::DeselectAllLayers);
|
||||||
tool_data.layers_dragging.clear();
|
tool_data.layers_dragging.clear();
|
||||||
}
|
}
|
||||||
SelectToolFsmState::DrawingBox
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::DrawingBox { selection }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tool_data.non_duplicated_layers = None;
|
tool_data.non_duplicated_layers = None;
|
||||||
@@ -594,7 +597,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => {
|
(SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => {
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::AbortTransaction);
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Dragging, SelectToolMessage::PointerMove(modifier_keys)) => {
|
(SelectToolFsmState::Dragging, SelectToolMessage::PointerMove(modifier_keys)) => {
|
||||||
tool_data.has_dragged = true;
|
tool_data.has_dragged = true;
|
||||||
@@ -759,7 +763,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
SelectToolFsmState::DraggingPivot
|
SelectToolFsmState::DraggingPivot
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DrawingBox, SelectToolMessage::PointerMove(modifier_keys)) => {
|
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::PointerMove(modifier_keys)) => {
|
||||||
tool_data.drag_current = input.mouse.position;
|
tool_data.drag_current = input.mouse.position;
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
@@ -773,9 +777,10 @@ impl Fsm for SelectToolFsmState {
|
|||||||
responses,
|
responses,
|
||||||
);
|
);
|
||||||
|
|
||||||
SelectToolFsmState::DrawingBox
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::DrawingBox { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Ready, SelectToolMessage::PointerMove(_)) => {
|
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => {
|
||||||
let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true));
|
let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true));
|
||||||
|
|
||||||
// Dragging the pivot overrules the other operations
|
// Dragging the pivot overrules the other operations
|
||||||
@@ -791,7 +796,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Dragging, SelectToolMessage::PointerOutsideViewport(_)) => {
|
(SelectToolFsmState::Dragging, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||||
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
|
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
|
||||||
@@ -816,7 +822,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DrawingBox, SelectToolMessage::PointerOutsideViewport(_)) => {
|
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||||
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
|
if let Some(shift) = AutoPanning::shift_viewport(input.mouse.position, input.viewport_bounds.size(), responses) {
|
||||||
tool_data.drag_start += shift;
|
tool_data.drag_start += shift;
|
||||||
}
|
}
|
||||||
@@ -842,7 +848,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
responses.add_front(response);
|
responses.add_front(response);
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Dragging, SelectToolMessage::DragStop { remove_from_selection }) => {
|
(SelectToolFsmState::Dragging, SelectToolMessage::DragStop { remove_from_selection }) => {
|
||||||
// Deselect layer if not snap dragging
|
// Deselect layer if not snap dragging
|
||||||
@@ -879,7 +886,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
tool_data.select_single_layer = None;
|
tool_data.select_single_layer = None;
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::ResizingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
(SelectToolFsmState::ResizingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||||
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
||||||
@@ -894,7 +902,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
bounds.original_transforms.clear();
|
bounds.original_transforms.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::RotatingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
(SelectToolFsmState::RotatingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||||
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
||||||
@@ -907,7 +916,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
bounds.original_transforms.clear();
|
bounds.original_transforms.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
(SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||||
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
||||||
@@ -918,9 +928,10 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||||
let quad = tool_data.selection_quad();
|
let quad = tool_data.selection_quad();
|
||||||
let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect();
|
let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect();
|
||||||
let current_selected: HashSet<_> = document.selected_nodes.selected_layers(document.metadata()).collect();
|
let current_selected: HashSet<_> = document.selected_nodes.selected_layers(document.metadata()).collect();
|
||||||
@@ -933,9 +944,10 @@ impl Fsm for SelectToolFsmState {
|
|||||||
}
|
}
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Ready, SelectToolMessage::Enter) => {
|
(SelectToolFsmState::Ready { .. }, SelectToolMessage::Enter) => {
|
||||||
let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
|
let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
|
||||||
|
|
||||||
if let Some(layer) = selected_layers.next() {
|
if let Some(layer) = selected_layers.next() {
|
||||||
@@ -946,14 +958,16 @@ impl Fsm for SelectToolFsmState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(SelectToolFsmState::Dragging, SelectToolMessage::Abort) => {
|
(SelectToolFsmState::Dragging, SelectToolMessage::Abort) => {
|
||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::Undo);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
SelectToolFsmState::Ready
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(_, SelectToolMessage::Abort) => {
|
(_, SelectToolMessage::Abort) => {
|
||||||
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
|
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
|
||||||
@@ -975,7 +989,9 @@ impl Fsm for SelectToolFsmState {
|
|||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
SelectToolFsmState::Ready
|
|
||||||
|
let selection = tool_data.nested_selection_behavior;
|
||||||
|
SelectToolFsmState::Ready { selection }
|
||||||
}
|
}
|
||||||
(_, SelectToolMessage::SetPivot { position }) => {
|
(_, SelectToolMessage::SetPivot { position }) => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
@@ -989,16 +1005,30 @@ impl Fsm for SelectToolFsmState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut Self::ToolData) -> bool {
|
fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque<Message>, _tool_data: &mut Self::ToolData) -> bool {
|
||||||
// Check for standard hits or cursor events
|
// Check for standard hits or cursor events
|
||||||
match message {
|
match message {
|
||||||
ToolMessage::UpdateHints => {
|
ToolMessage::UpdateHints => {
|
||||||
|
self.update_hints(responses);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ToolMessage::UpdateCursor => {
|
||||||
|
self.update_cursor(responses);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_hints(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
match self {
|
||||||
|
SelectToolFsmState::Ready { selection } => {
|
||||||
let hint_data = HintData(vec![
|
let hint_data = HintData(vec![
|
||||||
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]),
|
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]),
|
||||||
HintGroup(vec![HintInfo::keys([Key::KeyG, Key::KeyR, Key::KeyS], "Grab/Rotate/Scale Selected")]),
|
HintGroup(vec![HintInfo::keys([Key::KeyG, Key::KeyR, Key::KeyS], "Grab/Rotate/Scale Selected")]),
|
||||||
HintGroup({
|
HintGroup({
|
||||||
let mut hints = vec![HintInfo::mouse(MouseMotion::Lmb, "Select Object"), HintInfo::keys([Key::Shift], "Extend Selection").prepend_plus()];
|
let mut hints = vec![HintInfo::mouse(MouseMotion::Lmb, "Select Object"), HintInfo::keys([Key::Shift], "Extend Selection").prepend_plus()];
|
||||||
if tool_data.nested_selection_behavior == NestedSelectionBehavior::Shallowest {
|
if *selection == NestedSelectionBehavior::Shallowest {
|
||||||
hints.extend([HintInfo::keys([Key::Accel], "Deepest").prepend_plus(), HintInfo::mouse(MouseMotion::LmbDouble, "Deepen Selection")]);
|
hints.extend([HintInfo::keys([Key::Accel], "Deepest").prepend_plus(), HintInfo::mouse(MouseMotion::LmbDouble, "Deepen Selection")]);
|
||||||
}
|
}
|
||||||
hints
|
hints
|
||||||
@@ -1018,21 +1048,26 @@ impl Fsm for SelectToolFsmState {
|
|||||||
HintInfo::keys([Key::Control, Key::KeyD], "Duplicate").add_mac_keys([Key::Command, Key::KeyD]),
|
HintInfo::keys([Key::Control, Key::KeyD], "Duplicate").add_mac_keys([Key::Command, Key::KeyD]),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
self.update_hints(responses);
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
ToolMessage::UpdateCursor => {
|
SelectToolFsmState::Dragging => {
|
||||||
self.update_cursor(responses);
|
let hint_data = HintData(vec![
|
||||||
true
|
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
|
||||||
|
HintGroup(vec![
|
||||||
|
HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "Move Duplicate"),
|
||||||
|
HintInfo::keys([Key::Control, Key::KeyD], "Place Duplicate").add_mac_keys([Key::Command, Key::KeyD]),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
}
|
}
|
||||||
_ => false,
|
SelectToolFsmState::DrawingBox { .. } => {
|
||||||
|
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]);
|
||||||
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_hints(&self, _responses: &mut VecDeque<Message>) {}
|
|
||||||
|
|
||||||
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
|
||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user