Skip to content

Commit 78337f9

Browse files
adamgerhantKeavon
andauthored
Add shifting of layers in stacks as blocks that collide and bump other layers/nodes (#1940)
* Shift nodes as blocks * Implement rubber banding * Improve upstream locking when shifting layers * WIP: Reworked shifting * WIP: Reworked node shifting * Finish shifting * Fix demo artwork * Code review * Right click to end shift * Improve rubber banding * Fix clippy issues * Skip collision for intersecting nodes * Rubber banding bug fix * Fix ctrl+delete node in chain * Grip drag * Fix layer width * Add icon to frontend for the solo drag grip * Reconnect during ctrl+delete * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent a7840b2 commit 78337f9

19 files changed

+1231
-301
lines changed

editor/src/consts.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Graph
22
pub const GRID_SIZE: u32 = 24;
3-
pub const EXPORTS_TO_EDGE_PIXEL_GAP: u32 = 120;
4-
pub const IMPORTS_TO_EDGE_PIXEL_GAP: u32 = 120;
3+
pub const EXPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72;
4+
pub const EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP: u32 = 120;
5+
pub const IMPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72;
6+
pub const IMPORTS_TO_LEFT_EDGE_PIXEL_GAP: u32 = 120;
57

68
// Viewport
79
pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = (1. / 600.) * 3.;

editor/src/dispatcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ mod test {
386386
nodes: vec![rect_id.to_node(), ellipse_id.to_node()],
387387
});
388388
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
389-
editor.handle_message(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
389+
editor.handle_message(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
390390
editor.draw_rect(0., 800., 12., 200.);
391391
editor.handle_message(PortfolioMessage::PasteIntoFolder {
392392
clipboard: Clipboard::Internal,

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::MouseButton;
55
use crate::messages::input_mapper::utility_types::macros::*;
66
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
77
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
8+
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
89
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
910
use crate::messages::prelude::*;
1011
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
@@ -61,11 +62,10 @@ pub fn input_mappings() -> Mapping {
6162
entry!(DoubleClick(MouseButton::Left); action_dispatch=NodeGraphMessage::EnterNestedNetwork),
6263
entry!(PointerMove; refresh_keys=[Shift], action_dispatch=NodeGraphMessage::PointerMove {shift: Shift}),
6364
entry!(KeyUp(Lmb); action_dispatch=NodeGraphMessage::PointerUp),
64-
entry!(KeyUp(Escape); action_dispatch=NodeGraphMessage::CloseCreateNodeMenu),
65-
entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: false }),
66-
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: false }),
67-
entry!(KeyDown(Delete); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: true }),
68-
entry!(KeyDown(Backspace); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: true }),
65+
entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }),
66+
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }),
67+
entry!(KeyDown(Delete); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }),
68+
entry!(KeyDown(Backspace); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }),
6969
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut),
7070
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy),
7171
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes),
@@ -75,6 +75,10 @@ pub fn input_mappings() -> Mapping {
7575
entry!(KeyDown(KeyC); modifiers=[Shift], action_dispatch=NodeGraphMessage::PrintSelectedNodeCoordinates),
7676
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=NodeGraphMessage::SendClickTargets),
7777
entry!(KeyUp(KeyC); action_dispatch=NodeGraphMessage::EndSendClickTargets),
78+
entry!(KeyDown(ArrowUp); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Up, rubber_band: false }),
79+
entry!(KeyDown(ArrowRight); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Right, rubber_band: false }),
80+
entry!(KeyDown(ArrowDown); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Down, rubber_band: false }),
81+
entry!(KeyDown(ArrowLeft); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Left, rubber_band: false }),
7882
//
7983
// TransformLayerMessage
8084
entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation),
@@ -301,7 +305,7 @@ pub fn input_mappings() -> Mapping {
301305
//
302306
// DocumentMessage
303307
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
304-
entry!(KeyUp(Escape); action_dispatch=DocumentMessage::GraphViewOverlay { open: false }),
308+
entry!(KeyUp(Escape); action_dispatch=DocumentMessage::Escape),
305309
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
306310
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
307311
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),

editor/src/messages/portfolio/document/document_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub enum DocumentMessage {
5757
EnterNestedNetwork {
5858
node_id: NodeId,
5959
},
60+
Escape,
6061
ExitNestedNetwork {
6162
steps_back: usize,
6263
},

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
366366
info!("{:#?}", self.network_interface);
367367
}
368368
DocumentMessage::DeleteSelectedLayers => {
369-
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
369+
responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
370370
}
371371
DocumentMessage::DeselectAllLayers => {
372372
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
@@ -400,6 +400,26 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
400400
responses.add(NodeGraphMessage::SendGraph);
401401
responses.add(DocumentMessage::ZoomCanvasToFitAll);
402402
}
403+
DocumentMessage::Escape => {
404+
if self.node_graph_handler.drag_start.is_some() {
405+
responses.add(DocumentMessage::AbortTransaction);
406+
self.node_graph_handler.drag_start = None;
407+
} else if self
408+
.node_graph_handler
409+
.context_menu
410+
.as_ref()
411+
.is_some_and(|context_menu| matches!(context_menu.context_menu_data, super::node_graph::utility_types::ContextMenuData::CreateNode))
412+
{
413+
// Close the context menu
414+
self.node_graph_handler.context_menu = None;
415+
responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None });
416+
self.node_graph_handler.wire_in_progress_from_connector = None;
417+
self.node_graph_handler.wire_in_progress_to_connector = None;
418+
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
419+
} else {
420+
responses.add(DocumentMessage::GraphViewOverlay { open: false });
421+
}
422+
}
403423
DocumentMessage::ExitNestedNetwork { steps_back } => {
404424
for _ in 0..steps_back {
405425
self.breadcrumb_network_path.pop();
@@ -434,10 +454,12 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
434454
responses.add(FrontendMessage::TriggerGraphViewOverlay { open });
435455
// Update the tilt menu bar buttons to be disabled when the graph is open
436456
responses.add(MenuBarMessage::SendLayout);
457+
responses.add(DocumentMessage::RenderRulers);
458+
responses.add(DocumentMessage::RenderScrollbars);
437459
if open {
460+
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
438461
responses.add(NodeGraphMessage::SetGridAlignedEdges);
439462
responses.add(NodeGraphMessage::SendGraph);
440-
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
441463
}
442464
}
443465
DocumentMessage::GraphViewOverlayToggle => {
@@ -639,16 +661,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
639661
resize_opposite_corner,
640662
} => {
641663
self.backup(responses);
642-
if self.graph_view_overlay_open {
643-
responses.add(NodeGraphMessage::ShiftNodes {
644-
node_ids: self.network_interface.selected_nodes(&[]).unwrap().selected_nodes().cloned().collect(),
645-
displacement_x: if delta_x == 0.0 { 0 } else { delta_x.signum() as i32 },
646-
displacement_y: if delta_y == 0.0 { 0 } else { delta_y.signum() as i32 },
647-
move_upstream: ipp.keyboard.get(Key::Shift as usize),
648-
});
649-
650-
return;
651-
}
652664

653665
let opposite_corner = ipp.keyboard.key(resize_opposite_corner);
654666
let delta = DVec2::new(delta_x, delta_y);
@@ -862,7 +874,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
862874
self.selected_layers_reorder(relative_index_offset, responses);
863875
}
864876
DocumentMessage::SelectLayer { id, ctrl, shift } => {
865-
let layer = LayerNodeIdentifier::new(id, &self.network_interface);
877+
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]);
866878

867879
let mut nodes = vec![];
868880

@@ -965,7 +977,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
965977
}
966978
DocumentMessage::StartTransaction => self.backup(responses),
967979
DocumentMessage::ToggleLayerExpansion { id } => {
968-
let layer = LayerNodeIdentifier::new(id, &self.network_interface);
980+
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]);
969981
if self.collapsed.0.contains(&layer) {
970982
self.collapsed.0.retain(|&collapsed_layer| collapsed_layer != layer);
971983
} else {
@@ -1040,7 +1052,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
10401052
// Delete empty group folder
10411053
responses.add(NodeGraphMessage::DeleteNodes {
10421054
node_ids: vec![layer.to_node()],
1043-
reconnect: true,
1055+
delete_children: true,
10441056
});
10451057
}
10461058
DocumentMessage::PTZUpdate => {
@@ -1123,23 +1135,26 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
11231135

11241136
// Additional actions if there are any selected layers
11251137
if self.network_interface.selected_nodes(&[]).unwrap().selected_layers(self.metadata()).next().is_some() {
1126-
let select = actions!(DocumentMessageDiscriminant;
1138+
let mut select = actions!(DocumentMessageDiscriminant;
11271139
DeleteSelectedLayers,
11281140
DuplicateSelectedLayers,
11291141
GroupSelectedLayers,
1130-
NudgeSelectedLayers,
11311142
SelectedLayersLower,
11321143
SelectedLayersLowerToBack,
11331144
SelectedLayersRaise,
11341145
SelectedLayersRaiseToFront,
11351146
UngroupSelectedLayers,
11361147
);
1148+
if !self.graph_view_overlay_open {
1149+
select.extend(actions!(DocumentMessageDiscriminant; NudgeSelectedLayers));
1150+
}
11371151
common.extend(select);
11381152
}
1153+
11391154
// Additional actions if the node graph is open
11401155
if self.graph_view_overlay_open {
11411156
common.extend(actions!(DocumentMessageDiscriminant;
1142-
GraphViewOverlay,
1157+
Escape
11431158
));
11441159
common.extend(self.node_graph_handler.actions_additional_if_node_graph_is_open());
11451160
}

editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
124124
let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone();
125125
if let NodeInput::Node { node_id, .. } = &primary_input {
126126
if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) {
127-
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface), artboard_layer, 0, &[]);
127+
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface, &[]), artboard_layer, 0, &[]);
128128
} else {
129129
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
130130
network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]);
@@ -202,7 +202,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
202202
for artboard in network_interface.all_artboards() {
203203
responses.add(NodeGraphMessage::DeleteNodes {
204204
node_ids: vec![artboard.to_node()],
205-
reconnect: false,
205+
delete_children: false,
206206
});
207207
}
208208
// TODO: Replace deleted artboards with merge nodes

editor/src/messages/portfolio/document/graph_operation/utility_types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl<'a> ModifyInputsContext<'a> {
116116
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
117117
let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template();
118118
self.network_interface.insert_node(new_id, new_merge_node, &[]);
119-
LayerNodeIdentifier::new(new_id, self.network_interface)
119+
LayerNodeIdentifier::new(new_id, self.network_interface, &[])
120120
}
121121

122122
/// Creates an artboard as the primary export for the document network
@@ -130,7 +130,7 @@ impl<'a> ModifyInputsContext<'a> {
130130
Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)),
131131
]);
132132
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
133-
LayerNodeIdentifier::new(new_id, self.network_interface)
133+
LayerNodeIdentifier::new(new_id, self.network_interface, &[])
134134
}
135135

136136
pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
@@ -222,7 +222,7 @@ impl<'a> ModifyInputsContext<'a> {
222222
};
223223
let export_node = network.exports.first().and_then(|export| export.as_node())?;
224224
if self.network_interface.is_layer(&export_node, &[]) {
225-
Some(LayerNodeIdentifier::new(export_node, self.network_interface))
225+
Some(LayerNodeIdentifier::new(export_node, self.network_interface, &[]))
226226
} else {
227227
None
228228
}

editor/src/messages/portfolio/document/node_graph/node_graph_message.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::utility_types::Direction;
12
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
23
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
34
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector};
@@ -18,7 +19,6 @@ pub enum NodeGraphMessage {
1819
Init,
1920
SelectedNodesUpdated,
2021
Copy,
21-
CloseCreateNodeMenu,
2222
CreateNodeFromContextMenu {
2323
node_id: Option<NodeId>,
2424
node_type: String,
@@ -32,10 +32,10 @@ pub enum NodeGraphMessage {
3232
Cut,
3333
DeleteNodes {
3434
node_ids: Vec<NodeId>,
35-
reconnect: bool,
35+
delete_children: bool,
3636
},
3737
DeleteSelectedNodes {
38-
reconnect: bool,
38+
delete_children: bool,
3939
},
4040
DisconnectInput {
4141
input_connector: InputConnector,
@@ -111,15 +111,18 @@ pub enum NodeGraphMessage {
111111
node_id: NodeId,
112112
alias: String,
113113
},
114+
ShiftNodePosition {
115+
node_id: NodeId,
116+
x: i32,
117+
y: i32,
118+
},
114119
SetToNodeOrLayer {
115120
node_id: NodeId,
116121
is_layer: bool,
117122
},
118-
ShiftNodes {
119-
node_ids: Vec<NodeId>,
120-
displacement_x: i32,
121-
displacement_y: i32,
122-
move_upstream: bool,
123+
ShiftSelectedNodes {
124+
direction: Direction,
125+
rubber_band: bool,
123126
},
124127
TogglePreview {
125128
node_id: NodeId,

0 commit comments

Comments
 (0)