mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 23:48:11 +08:00
Rework drag start
This commit is contained in:
@@ -57,12 +57,11 @@ pub struct NodeGraphMessageHandler {
|
|||||||
has_selection: bool,
|
has_selection: bool,
|
||||||
widgets: [LayoutGroup; 2],
|
widgets: [LayoutGroup; 2],
|
||||||
/// Used to add a transaction for the first node move when dragging.
|
/// Used to add a transaction for the first node move when dragging.
|
||||||
begin_dragging: bool,
|
|
||||||
/// Used to prevent entering a nested network if the node is dragged after double clicking
|
/// Used to prevent entering a nested network if the node is dragged after double clicking
|
||||||
node_has_moved_in_drag: bool,
|
node_has_moved_in_drag: bool,
|
||||||
/// If dragging the selected nodes, this stores the starting position both in viewport and node graph coordinates,
|
/// If dragging the selected nodes, this stores the current position of the node,
|
||||||
/// plus a flag indicating if it has been dragged since the mousedown began.
|
/// plus a flag indicating if it has been dragged since the mousedown began.
|
||||||
pub drag_start: Option<(DragStart, bool)>,
|
pub drag_start: Option<DragStart>,
|
||||||
// Store the selected chain nodes on drag start so they can be reconnected if shaken
|
// Store the selected chain nodes on drag start so they can be reconnected if shaken
|
||||||
pub drag_start_chain_nodes: Vec<NodeId>,
|
pub drag_start_chain_nodes: Vec<NodeId>,
|
||||||
/// If dragging the background to create a box selection, this stores its starting point in node graph coordinates,
|
/// If dragging the background to create a box selection, this stores its starting point in node graph coordinates,
|
||||||
@@ -965,14 +964,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
|
|
||||||
// If this node is selected (whether from before or just now), prepare it for dragging
|
// If this node is selected (whether from before or just now), prepare it for dragging
|
||||||
if updated_selected.contains(&clicked_id) {
|
if updated_selected.contains(&clicked_id) {
|
||||||
let drag_start = DragStart {
|
let drag_start_position = IVec2::new((node_graph_point.x / 24.).round() as i32, (node_graph_point.y / 24.).round() as i32);
|
||||||
start_x: node_graph_point.x,
|
|
||||||
start_y: node_graph_point.y,
|
|
||||||
round_x: 0,
|
|
||||||
round_y: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.drag_start = Some((drag_start, false));
|
self.drag_start = Some(DragStart::No(drag_start_position));
|
||||||
let selected_chain_nodes = updated_selected
|
let selected_chain_nodes = updated_selected
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
|
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
|
||||||
@@ -987,7 +981,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
|
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
self.begin_dragging = true;
|
|
||||||
self.node_has_moved_in_drag = false;
|
self.node_has_moved_in_drag = false;
|
||||||
self.update_node_graph_hints(responses);
|
self.update_node_graph_hints(responses);
|
||||||
}
|
}
|
||||||
@@ -1105,36 +1098,28 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
};
|
};
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) });
|
||||||
}
|
}
|
||||||
} else if let Some((drag_start, dragged)) = &mut self.drag_start {
|
} else if let Some(drag_start) = &mut self.drag_start {
|
||||||
if drag_start.start_x != point.x || drag_start.start_y != point.y {
|
match drag_start {
|
||||||
*dragged = true;
|
DragStart::Yes => {
|
||||||
}
|
sync_selected_node_position_with_mouse(network_interface, breadcrumb_network_path, point, responses);
|
||||||
|
|
||||||
self.node_has_moved_in_drag = true;
|
|
||||||
if self.begin_dragging {
|
|
||||||
self.begin_dragging = false;
|
|
||||||
if ipp.keyboard.get(Key::Alt as usize) {
|
|
||||||
responses.add(NodeGraphMessage::DuplicateSelectedNodes);
|
|
||||||
// Duplicating sets a 2x2 offset, so shift the nodes back to the original position
|
|
||||||
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount {
|
|
||||||
graph_delta: IVec2::new(-2, -2),
|
|
||||||
rubber_band: false,
|
|
||||||
});
|
|
||||||
self.preview_on_mouse_up = None;
|
|
||||||
}
|
}
|
||||||
}
|
DragStart::No(start) => {
|
||||||
|
let mouse_position_grid_space = IVec2::new((point.x / 24.).round() as i32, (point.y / 24.).round() as i32);
|
||||||
let mut graph_delta = IVec2::new(((point.x - drag_start.start_x) / 24.).round() as i32, ((point.y - drag_start.start_y) / 24.).round() as i32);
|
if *start != mouse_position_grid_space {
|
||||||
let previous_round_x = drag_start.round_x;
|
*drag_start = DragStart::Yes;
|
||||||
let previous_round_y = drag_start.round_y;
|
if ipp.keyboard.get(Key::Alt as usize) {
|
||||||
|
responses.add(NodeGraphMessage::DuplicateSelectedNodes);
|
||||||
drag_start.round_x = graph_delta.x;
|
// Duplicating sets a 2x2 offset, so shift the nodes back to the original position
|
||||||
drag_start.round_y = graph_delta.y;
|
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount {
|
||||||
|
graph_delta: IVec2::new(-2, -2),
|
||||||
graph_delta.x -= previous_round_x;
|
rubber_band: false,
|
||||||
graph_delta.y -= previous_round_y;
|
});
|
||||||
|
self.preview_on_mouse_up = None;
|
||||||
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true });
|
}
|
||||||
|
sync_selected_node_position_with_mouse(network_interface, breadcrumb_network_path, point, responses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.update_node_graph_hints(responses);
|
self.update_node_graph_hints(responses);
|
||||||
} else if let Some((_, box_selection_dragged)) = &mut self.box_selection_start {
|
} else if let Some((_, box_selection_dragged)) = &mut self.box_selection_start {
|
||||||
@@ -1204,7 +1189,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
self.preview_on_mouse_up = None;
|
self.preview_on_mouse_up = None;
|
||||||
}
|
}
|
||||||
if let Some(node_to_deselect) = self.deselect_on_pointer_up.take()
|
if let Some(node_to_deselect) = self.deselect_on_pointer_up.take()
|
||||||
&& !self.drag_start.as_ref().is_some_and(|t| t.1)
|
&& self.drag_start.as_ref().is_some_and(|start| !start.dragged())
|
||||||
{
|
{
|
||||||
let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone();
|
let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone();
|
||||||
new_selected_nodes.remove(node_to_deselect);
|
new_selected_nodes.remove(node_to_deselect);
|
||||||
@@ -1268,7 +1253,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of dragging a node
|
// End of dragging a node
|
||||||
else if let Some((drag_start, _)) = &self.drag_start {
|
else if let Some(drag_start) = &self.drag_start {
|
||||||
self.shift_without_push = false;
|
self.shift_without_push = false;
|
||||||
|
|
||||||
// Reset all offsets to end the rubber banding while dragging
|
// Reset all offsets to end the rubber banding while dragging
|
||||||
@@ -1280,8 +1265,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
|
|
||||||
// Only select clicked node if multiple are selected and they were not dragged
|
// Only select clicked node if multiple are selected and they were not dragged
|
||||||
if let Some(select_if_not_dragged) = self.select_if_not_dragged {
|
if let Some(select_if_not_dragged) = self.select_if_not_dragged {
|
||||||
let not_dragged = drag_start.start_x == point.x && drag_start.start_y == point.y;
|
if !drag_start.dragged()
|
||||||
if not_dragged
|
|
||||||
&& (selected_nodes.selected_nodes_ref().len() != 1
|
&& (selected_nodes.selected_nodes_ref().len() != 1
|
||||||
|| selected_nodes
|
|| selected_nodes
|
||||||
.selected_nodes_ref()
|
.selected_nodes_ref()
|
||||||
@@ -1310,7 +1294,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// Check if a single node was dragged onto a wire and that the node was dragged onto the wire
|
// Check if a single node was dragged onto a wire and that the node was dragged onto the wire
|
||||||
if selected_nodes.selected_nodes_ref().len() == 1 && !self.begin_dragging {
|
if selected_nodes.selected_nodes_ref().len() == 1 && self.drag_start.as_ref().is_some_and(|drag_start| drag_start.dragged()) {
|
||||||
let selected_node_id = selected_nodes.selected_nodes_ref()[0];
|
let selected_node_id = selected_nodes.selected_nodes_ref()[0];
|
||||||
let has_primary_output_connection = network_interface
|
let has_primary_output_connection = network_interface
|
||||||
.outward_wires(selection_network_path)
|
.outward_wires(selection_network_path)
|
||||||
@@ -1422,7 +1406,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.drag_start = None;
|
self.drag_start = None;
|
||||||
self.begin_dragging = false;
|
|
||||||
self.box_selection_start = None;
|
self.box_selection_start = None;
|
||||||
|
|
||||||
self.wire_in_progress_from_connector = None;
|
self.wire_in_progress_from_connector = None;
|
||||||
@@ -1449,11 +1432,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ShakeNode => {
|
NodeGraphMessage::ShakeNode => {
|
||||||
let Some(drag_start) = &self.drag_start else {
|
|
||||||
log::error!("Drag start should be initialized when shaking a node");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
|
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -1466,9 +1444,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
.inverse()
|
.inverse()
|
||||||
.transform_point2(viewport_location);
|
.transform_point2(viewport_location);
|
||||||
|
|
||||||
// Collect the distance to move the shaken nodes after the undo
|
|
||||||
let graph_delta = IVec2::new(((point.x - drag_start.0.start_x) / 24.).round() as i32, ((point.y - drag_start.0.start_y) / 24.).round() as i32);
|
|
||||||
|
|
||||||
// Undo to the state of the graph before shaking
|
// Undo to the state of the graph before shaking
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::AbortTransaction);
|
||||||
|
|
||||||
@@ -1559,7 +1534,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: false });
|
sync_selected_node_position_with_mouse(network_interface, breadcrumb_network_path, point, responses);
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
}
|
}
|
||||||
@@ -2761,8 +2736,8 @@ impl NodeGraphMessageHandler {
|
|||||||
// A wire is in progress and its start and end connectors are set
|
// A wire is in progress and its start and end connectors are set
|
||||||
let wiring = self.wire_in_progress_from_connector.is_some();
|
let wiring = self.wire_in_progress_from_connector.is_some();
|
||||||
|
|
||||||
// Node gragging is in progress (having already moved at least one pixel from the mouse down position)
|
// Node dragging is in progress (having already moved at least one pixel from the mouse down position)
|
||||||
let dragging_nodes = self.drag_start.as_ref().is_some_and(|(_, dragged)| *dragged);
|
let dragging_nodes = self.drag_start.as_ref().is_some_and(|drag_start| drag_start.dragged());
|
||||||
|
|
||||||
// A box selection is in progress
|
// A box selection is in progress
|
||||||
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
|
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
|
||||||
@@ -2809,7 +2784,6 @@ impl Default for NodeGraphMessageHandler {
|
|||||||
has_selection: false,
|
has_selection: false,
|
||||||
widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: Vec::new() }],
|
widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: Vec::new() }],
|
||||||
drag_start: None,
|
drag_start: None,
|
||||||
begin_dragging: false,
|
|
||||||
node_has_moved_in_drag: false,
|
node_has_moved_in_drag: false,
|
||||||
shift_without_push: false,
|
shift_without_push: false,
|
||||||
box_selection_start: None,
|
box_selection_start: None,
|
||||||
@@ -2840,7 +2814,6 @@ impl PartialEq for NodeGraphMessageHandler {
|
|||||||
&& self.has_selection == other.has_selection
|
&& self.has_selection == other.has_selection
|
||||||
&& self.widgets == other.widgets
|
&& self.widgets == other.widgets
|
||||||
&& self.drag_start == other.drag_start
|
&& self.drag_start == other.drag_start
|
||||||
&& self.begin_dragging == other.begin_dragging
|
|
||||||
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
|
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
|
||||||
&& self.box_selection_start == other.box_selection_start
|
&& self.box_selection_start == other.box_selection_start
|
||||||
&& self.initial_disconnecting == other.initial_disconnecting
|
&& self.initial_disconnecting == other.initial_disconnecting
|
||||||
@@ -2850,3 +2823,20 @@ impl PartialEq for NodeGraphMessageHandler {
|
|||||||
&& self.context_menu == other.context_menu
|
&& self.context_menu == other.context_menu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sync_selected_node_position_with_mouse(network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId], mouse_position_node_graph_space: DVec2, responses: &mut VecDeque<Message>) {
|
||||||
|
let mouse_position_grid_space = IVec2::new((mouse_position_node_graph_space.x / 24.).round() as i32, (mouse_position_node_graph_space.y / 24.).round() as i32);
|
||||||
|
|
||||||
|
let Some(selected_nodes_bbox) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path) else {
|
||||||
|
log::error!("Could not get selected_nodes_bounding_box when dragging");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut selected_nodes_center = (selected_nodes_bbox[0] + selected_nodes_bbox[1]) / 2.;
|
||||||
|
// Add 1 to correct for floating point errors
|
||||||
|
selected_nodes_center += DVec2::ONE;
|
||||||
|
let selected_nodes_center_grid_space = IVec2::new((selected_nodes_center.x / 24.).round() as i32, (selected_nodes_center.y / 24.).round() as i32);
|
||||||
|
let graph_delta = mouse_position_grid_space - selected_nodes_center_grid_space;
|
||||||
|
if graph_delta != IVec2::ZERO {
|
||||||
|
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,12 +110,18 @@ pub struct FrontendNodeType {
|
|||||||
pub input_types: Vec<String>,
|
pub input_types: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State to represent the grid space coordinate from which the pointer started the drag
|
||||||
|
/// Once the nodes have been dragged, it is toggled to the Yes variant
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct DragStart {
|
pub enum DragStart {
|
||||||
pub start_x: f64,
|
Yes,
|
||||||
pub start_y: f64,
|
No(IVec2),
|
||||||
pub round_x: i32,
|
}
|
||||||
pub round_y: i32,
|
|
||||||
|
impl DragStart {
|
||||||
|
pub fn dragged(&self) -> bool {
|
||||||
|
matches!(self, DragStart::Yes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
|||||||
Reference in New Issue
Block a user