Add selection removal to the Select tool's box select (Ctrl+Shift modifier) (#2162)

* select parent-node,remove deselect all layers message

* Comment nits

* implement negative selection box

* moved comment and formatting

* Apply suggestions from code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0SlowPoke0
2024-12-28 11:43:29 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent 6d737f15ee
commit 6c3c2e8529
2 changed files with 34 additions and 16 deletions
@@ -98,7 +98,7 @@ pub fn input_mappings() -> Mapping {
// SelectToolMessage // SelectToolMessage
entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove(SelectToolPointerKeys { axis_align: Shift, snap_angle: Control, center: Alt, duplicate: Alt })), entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove(SelectToolPointerKeys { axis_align: Shift, snap_angle: Control, center: Alt, duplicate: Alt })),
entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, select_deepest: Accel }), entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, select_deepest: Accel }),
entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Shift }), entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Shift, negative_box_selection: Control }),
entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter), entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter),
entry!(DoubleClick(MouseButton::Left); action_dispatch=SelectToolMessage::EditLayer), entry!(DoubleClick(MouseButton::Left); action_dispatch=SelectToolMessage::EditLayer),
entry!(KeyDown(MouseRight); action_dispatch=SelectToolMessage::Abort), entry!(KeyDown(MouseRight); action_dispatch=SelectToolMessage::Abort),
@@ -72,7 +72,7 @@ pub enum SelectToolMessage {
// Tool-specific messages // Tool-specific messages
DragStart { extend_selection: Key, select_deepest: Key }, DragStart { extend_selection: Key, select_deepest: Key },
DragStop { remove_from_selection: Key }, DragStop { remove_from_selection: Key, negative_box_selection: Key },
EditLayer, EditLayer,
Enter, Enter,
PointerMove(SelectToolPointerKeys), PointerMove(SelectToolPointerKeys),
@@ -902,7 +902,7 @@ impl Fsm for SelectToolFsmState {
let selection = tool_data.nested_selection_behavior; let selection = tool_data.nested_selection_behavior;
SelectToolFsmState::Ready { selection } 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
responses.add(DocumentMessage::EndTransaction); responses.add(DocumentMessage::EndTransaction);
@@ -1001,20 +1001,34 @@ impl Fsm for SelectToolFsmState {
let selection = tool_data.nested_selection_behavior; let selection = tool_data.nested_selection_behavior;
SelectToolFsmState::Ready { selection } SelectToolFsmState::Ready { selection }
} }
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { (
SelectToolFsmState::DrawingBox { .. },
SelectToolMessage::DragStop {
remove_from_selection,
negative_box_selection,
},
) => {
let quad = tool_data.selection_quad(); let quad = tool_data.selection_quad();
let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect();
let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect(); let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect();
if new_selected != current_selected { if new_selected != current_selected {
let parent_selected: HashSet<_> = new_selected // Negative selection when both Shift and Ctrl are pressed
.into_iter() if input.keyboard.key(remove_from_selection) && input.keyboard.key(negative_box_selection) {
.map(|layer| { let updated_selection = current_selected
// Find the parent node .into_iter()
layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer) .filter(|layer| !new_selected.iter().any(|selected| layer.starts_with(*selected, document.metadata())))
}) .collect();
.collect(); tool_data.layers_dragging = updated_selection;
} else {
tool_data.layers_dragging.extend(parent_selected.iter().copied()); let parent_selected: HashSet<_> = new_selected
.into_iter()
.map(|layer| {
// Find the parent node
layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer)
})
.collect();
tool_data.layers_dragging.extend(parent_selected.iter().copied());
}
responses.add(NodeGraphMessage::SelectedNodesSet { responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: tool_data nodes: tool_data
.layers_dragging .layers_dragging
@@ -1143,9 +1157,13 @@ impl Fsm for SelectToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data }); responses.add(FrontendMessage::UpdateInputHints { hint_data });
} }
SelectToolFsmState::DrawingBox { .. } => { SelectToolFsmState::DrawingBox { .. } => {
// TODO: Add hint and implement functionality for holding Shift to extend the selection, thus preventing the prior selection from being cleared let hint_data = HintData(vec![
// TODO: Also fix the current functionality so canceling the box select doesn't clear the prior selection HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]); HintGroup(vec![HintInfo::keys([Key::Control, Key::Shift], "Remove from Selection").add_mac_keys([Key::Command, Key::Shift])]),
// TODO: Re-select deselected layers during drag when Shift is pressed, and re-deselect if Shift is released before drag ends.
// TODO: (See https://discord.com/channels/731730685944922173/1216976541947531264/1321360311298818048)
// HintGroup(vec![HintInfo::keys([Key::Shift], "Extend Selection")])
]);
responses.add(FrontendMessage::UpdateInputHints { hint_data }); responses.add(FrontendMessage::UpdateInputHints { hint_data });
} }
_ => {} _ => {}