Skip to content

Commit

Permalink
Add shifting of layers in stacks as blocks that collide and bump othe…
Browse files Browse the repository at this point in the history
…r 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 <[email protected]>
  • Loading branch information
adamgerhant and Keavon authored Aug 22, 2024
1 parent a7840b2 commit 78337f9
Show file tree
Hide file tree
Showing 19 changed files with 1,231 additions and 301 deletions.
6 changes: 4 additions & 2 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Graph
pub const GRID_SIZE: u32 = 24;
pub const EXPORTS_TO_EDGE_PIXEL_GAP: u32 = 120;
pub const IMPORTS_TO_EDGE_PIXEL_GAP: u32 = 120;
pub const EXPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72;
pub const EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP: u32 = 120;
pub const IMPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72;
pub const IMPORTS_TO_LEFT_EDGE_PIXEL_GAP: u32 = 120;

// Viewport
pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = (1. / 600.) * 3.;
Expand Down
2 changes: 1 addition & 1 deletion editor/src/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ mod test {
nodes: vec![rect_id.to_node(), ellipse_id.to_node()],
});
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
editor.handle_message(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
editor.handle_message(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
editor.draw_rect(0., 800., 12., 200.);
editor.handle_message(PortfolioMessage::PasteIntoFolder {
clipboard: Clipboard::Internal,
Expand Down
16 changes: 10 additions & 6 deletions editor/src/messages/input_mapper/input_mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::MouseButton;
use crate::messages::input_mapper::utility_types::macros::*;
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::prelude::*;
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
Expand Down Expand Up @@ -61,11 +62,10 @@ pub fn input_mappings() -> Mapping {
entry!(DoubleClick(MouseButton::Left); action_dispatch=NodeGraphMessage::EnterNestedNetwork),
entry!(PointerMove; refresh_keys=[Shift], action_dispatch=NodeGraphMessage::PointerMove {shift: Shift}),
entry!(KeyUp(Lmb); action_dispatch=NodeGraphMessage::PointerUp),
entry!(KeyUp(Escape); action_dispatch=NodeGraphMessage::CloseCreateNodeMenu),
entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: false }),
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: false }),
entry!(KeyDown(Delete); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: true }),
entry!(KeyDown(Backspace); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { reconnect: true }),
entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }),
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }),
entry!(KeyDown(Delete); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }),
entry!(KeyDown(Backspace); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }),
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut),
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy),
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes),
Expand All @@ -75,6 +75,10 @@ pub fn input_mappings() -> Mapping {
entry!(KeyDown(KeyC); modifiers=[Shift], action_dispatch=NodeGraphMessage::PrintSelectedNodeCoordinates),
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=NodeGraphMessage::SendClickTargets),
entry!(KeyUp(KeyC); action_dispatch=NodeGraphMessage::EndSendClickTargets),
entry!(KeyDown(ArrowUp); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Up, rubber_band: false }),
entry!(KeyDown(ArrowRight); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Right, rubber_band: false }),
entry!(KeyDown(ArrowDown); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Down, rubber_band: false }),
entry!(KeyDown(ArrowLeft); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Left, rubber_band: false }),
//
// TransformLayerMessage
entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation),
Expand Down Expand Up @@ -301,7 +305,7 @@ pub fn input_mappings() -> Mapping {
//
// DocumentMessage
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
entry!(KeyUp(Escape); action_dispatch=DocumentMessage::GraphViewOverlay { open: false }),
entry!(KeyUp(Escape); action_dispatch=DocumentMessage::Escape),
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),
Expand Down
1 change: 1 addition & 0 deletions editor/src/messages/portfolio/document/document_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub enum DocumentMessage {
EnterNestedNetwork {
node_id: NodeId,
},
Escape,
ExitNestedNetwork {
steps_back: usize,
},
Expand Down
51 changes: 33 additions & 18 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
info!("{:#?}", self.network_interface);
}
DocumentMessage::DeleteSelectedLayers => {
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
}
DocumentMessage::DeselectAllLayers => {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
Expand Down Expand Up @@ -400,6 +400,26 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
responses.add(NodeGraphMessage::SendGraph);
responses.add(DocumentMessage::ZoomCanvasToFitAll);
}
DocumentMessage::Escape => {
if self.node_graph_handler.drag_start.is_some() {
responses.add(DocumentMessage::AbortTransaction);
self.node_graph_handler.drag_start = None;
} else if self
.node_graph_handler
.context_menu
.as_ref()
.is_some_and(|context_menu| matches!(context_menu.context_menu_data, super::node_graph::utility_types::ContextMenuData::CreateNode))
{
// Close the context menu
self.node_graph_handler.context_menu = None;
responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None });
self.node_graph_handler.wire_in_progress_from_connector = None;
self.node_graph_handler.wire_in_progress_to_connector = None;
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
} else {
responses.add(DocumentMessage::GraphViewOverlay { open: false });
}
}
DocumentMessage::ExitNestedNetwork { steps_back } => {
for _ in 0..steps_back {
self.breadcrumb_network_path.pop();
Expand Down Expand Up @@ -434,10 +454,12 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
responses.add(FrontendMessage::TriggerGraphViewOverlay { open });
// Update the tilt menu bar buttons to be disabled when the graph is open
responses.add(MenuBarMessage::SendLayout);
responses.add(DocumentMessage::RenderRulers);
responses.add(DocumentMessage::RenderScrollbars);
if open {
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
responses.add(NodeGraphMessage::SetGridAlignedEdges);
responses.add(NodeGraphMessage::SendGraph);
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
}
}
DocumentMessage::GraphViewOverlayToggle => {
Expand Down Expand Up @@ -639,16 +661,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
resize_opposite_corner,
} => {
self.backup(responses);
if self.graph_view_overlay_open {
responses.add(NodeGraphMessage::ShiftNodes {
node_ids: self.network_interface.selected_nodes(&[]).unwrap().selected_nodes().cloned().collect(),
displacement_x: if delta_x == 0.0 { 0 } else { delta_x.signum() as i32 },
displacement_y: if delta_y == 0.0 { 0 } else { delta_y.signum() as i32 },
move_upstream: ipp.keyboard.get(Key::Shift as usize),
});

return;
}

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

let mut nodes = vec![];

Expand Down Expand Up @@ -965,7 +977,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
}
DocumentMessage::StartTransaction => self.backup(responses),
DocumentMessage::ToggleLayerExpansion { id } => {
let layer = LayerNodeIdentifier::new(id, &self.network_interface);
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]);
if self.collapsed.0.contains(&layer) {
self.collapsed.0.retain(|&collapsed_layer| collapsed_layer != layer);
} else {
Expand Down Expand Up @@ -1040,7 +1052,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
// Delete empty group folder
responses.add(NodeGraphMessage::DeleteNodes {
node_ids: vec![layer.to_node()],
reconnect: true,
delete_children: true,
});
}
DocumentMessage::PTZUpdate => {
Expand Down Expand Up @@ -1123,23 +1135,26 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag

// Additional actions if there are any selected layers
if self.network_interface.selected_nodes(&[]).unwrap().selected_layers(self.metadata()).next().is_some() {
let select = actions!(DocumentMessageDiscriminant;
let mut select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers,
DuplicateSelectedLayers,
GroupSelectedLayers,
NudgeSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
UngroupSelectedLayers,
);
if !self.graph_view_overlay_open {
select.extend(actions!(DocumentMessageDiscriminant; NudgeSelectedLayers));
}
common.extend(select);
}

// Additional actions if the node graph is open
if self.graph_view_overlay_open {
common.extend(actions!(DocumentMessageDiscriminant;
GraphViewOverlay,
Escape
));
common.extend(self.node_graph_handler.actions_additional_if_node_graph_is_open());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone();
if let NodeInput::Node { node_id, .. } = &primary_input {
if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) {
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface), artboard_layer, 0, &[]);
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface, &[]), artboard_layer, 0, &[]);
} else {
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]);
Expand Down Expand Up @@ -202,7 +202,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
for artboard in network_interface.all_artboards() {
responses.add(NodeGraphMessage::DeleteNodes {
node_ids: vec![artboard.to_node()],
reconnect: false,
delete_children: false,
});
}
// TODO: Replace deleted artboards with merge nodes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template();
self.network_interface.insert_node(new_id, new_merge_node, &[]);
LayerNodeIdentifier::new(new_id, self.network_interface)
LayerNodeIdentifier::new(new_id, self.network_interface, &[])
}

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

pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
Expand Down Expand Up @@ -222,7 +222,7 @@ impl<'a> ModifyInputsContext<'a> {
};
let export_node = network.exports.first().and_then(|export| export.as_node())?;
if self.network_interface.is_layer(&export_node, &[]) {
Some(LayerNodeIdentifier::new(export_node, self.network_interface))
Some(LayerNodeIdentifier::new(export_node, self.network_interface, &[]))
} else {
None
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::utility_types::Direction;
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector};
Expand All @@ -18,7 +19,6 @@ pub enum NodeGraphMessage {
Init,
SelectedNodesUpdated,
Copy,
CloseCreateNodeMenu,
CreateNodeFromContextMenu {
node_id: Option<NodeId>,
node_type: String,
Expand All @@ -32,10 +32,10 @@ pub enum NodeGraphMessage {
Cut,
DeleteNodes {
node_ids: Vec<NodeId>,
reconnect: bool,
delete_children: bool,
},
DeleteSelectedNodes {
reconnect: bool,
delete_children: bool,
},
DisconnectInput {
input_connector: InputConnector,
Expand Down Expand Up @@ -111,15 +111,18 @@ pub enum NodeGraphMessage {
node_id: NodeId,
alias: String,
},
ShiftNodePosition {
node_id: NodeId,
x: i32,
y: i32,
},
SetToNodeOrLayer {
node_id: NodeId,
is_layer: bool,
},
ShiftNodes {
node_ids: Vec<NodeId>,
displacement_x: i32,
displacement_y: i32,
move_upstream: bool,
ShiftSelectedNodes {
direction: Direction,
rubber_band: bool,
},
TogglePreview {
node_id: NodeId,
Expand Down
Loading

0 comments on commit 78337f9

Please sign in to comment.