mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Implement SelectedNodes as trait
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use super::simple_dialogs::{self, AboutGraphiteDialog, ComingSoonDialog, DemoArtworkDialog, LicensesDialog};
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
pub struct DialogMessageData<'a> {
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::utility_types::clipboards::Clipboard;
|
||||
use super::utility_types::error::EditorError;
|
||||
use super::utility_types::misc::{SnappingOptions, SnappingState, GET_SNAP_BOX_FUNCTIONS, GET_SNAP_GEOMETRY_FUNCTIONS};
|
||||
use super::utility_types::network_interface::{NodeNetworkInterface, NodeNetworkPersistentMetadata, TransactionStatus};
|
||||
use super::utility_types::nodes::{CollapsedLayers, SelectedNodes};
|
||||
use super::utility_types::nodes::{CollapsedLayers, OldSelectedNodes, SelectedNodes};
|
||||
use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH};
|
||||
use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
|
||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||
@@ -48,7 +48,7 @@ pub struct OldDocumentMessageHandler {
|
||||
/// It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content.
|
||||
pub network: OldNodeNetwork,
|
||||
/// List of the [`NodeId`]s that are currently selected by the user.
|
||||
pub selected_nodes: SelectedNodes,
|
||||
pub selected_nodes: OldSelectedNodes,
|
||||
/// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel.
|
||||
/// Collapsed means that the expansion arrow isn't set to show the children of these layers.
|
||||
pub collapsed: CollapsedLayers,
|
||||
@@ -1507,7 +1507,7 @@ impl DocumentMessageHandler {
|
||||
.unwrap_or_else(|| self.network_interface.all_artboards().iter().next().copied().unwrap_or(LayerNodeIdentifier::ROOT_PARENT))
|
||||
}
|
||||
|
||||
pub fn get_calculated_insert_index(metadata: &DocumentMetadata, selected_nodes: SelectedNodes, parent: LayerNodeIdentifier) -> usize {
|
||||
pub fn get_calculated_insert_index(metadata: &DocumentMetadata, selected_nodes: impl SelectedNodes, parent: LayerNodeIdentifier) -> usize {
|
||||
parent
|
||||
.children(metadata)
|
||||
.enumerate()
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{self, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
@@ -1037,27 +1038,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||
responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: true });
|
||||
}
|
||||
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesAdd");
|
||||
return;
|
||||
};
|
||||
selected_nodes.add_selected_nodes(nodes);
|
||||
network_interface.add_selected_nodes(nodes, selection_network_path);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
}
|
||||
NodeGraphMessage::SelectedNodesRemove { nodes } => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesRemove");
|
||||
return;
|
||||
};
|
||||
selected_nodes.retain_selected_nodes(|node| !nodes.contains(node));
|
||||
network_interface.remove_selected_nodes(nodes, selection_network_path);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
}
|
||||
NodeGraphMessage::SelectedNodesSet { nodes } => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesSet");
|
||||
return;
|
||||
};
|
||||
selected_nodes.set_selected_nodes(nodes);
|
||||
network_interface.set_selected_nodes(nodes, selection_network_path);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
@@ -1324,11 +1313,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||
// Update the import/export UI edges whenever the PTZ changes or the bounding box of all nodes changes
|
||||
}
|
||||
NodeGraphMessage::UpdateNewNodeGraph => {
|
||||
let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::UpdateNewNodeGraph");
|
||||
return;
|
||||
};
|
||||
selected_nodes.clear_selected_nodes();
|
||||
network_interface.set_selected_nodes(Vec::new(), selection_network_path);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
@@ -1343,6 +1328,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||
for path in resolved_types.remove {
|
||||
network_interface.resolved_types.types.remove(&path.to_vec());
|
||||
}
|
||||
|
||||
self.node_graph_errors = node_graph_errors;
|
||||
}
|
||||
NodeGraphMessage::UpdateActionButtons => {
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::utility_types::OverlayContext;
|
||||
use crate::consts::HIDE_HANDLE_DISTANCE;
|
||||
use crate::messages::tool::common_functionality::shape_editor::{SelectedLayerState, ShapeState};
|
||||
use crate::messages::tool::tool_messages::tool_prelude::DocumentMessageHandler;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graphene_core::vector::ManipulatorPointId;
|
||||
|
||||
|
||||
@@ -127,20 +127,22 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
/// Get the selected nodes for the network at the network_path
|
||||
pub fn selected_nodes(&self, network_path: &[NodeId]) -> Option<SelectedNodes> {
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in selected_nodes");
|
||||
pub fn selected_nodes(&self, network_path: &[NodeId]) -> Option<impl SelectedNodes> {
|
||||
let Some(network) = self.network(network_path) else {
|
||||
log::error!("Could not get network in selected_nodes");
|
||||
return None;
|
||||
};
|
||||
let Some(selection_undo_history) = self.selection_undo_history(network_path) else {
|
||||
log::error!("Could not get nested selection_undo_history for path {network_path:?}");
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(
|
||||
network_metadata
|
||||
.persistent_metadata
|
||||
.selection_undo_history
|
||||
selection_undo_history
|
||||
.back()
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.filtered_selected_nodes(network_metadata.persistent_metadata.node_metadata.keys().cloned().collect()),
|
||||
.filtered_selected_nodes(network.nodes.keys().cloned().collect()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1079,6 +1081,18 @@ impl NodeNetworkInterface {
|
||||
Some(top_right)
|
||||
}
|
||||
|
||||
pub fn selection_undo_history(&self, network_path: &[NodeId]) -> Option<&VecDeque<Vec<NodeId>>> {
|
||||
let Some(tagged_value) = self.metadata_value(MetadataType::SelectionUndoHistory, network_path) else {
|
||||
log::error!("Could not get tagged value in selection_undo_history");
|
||||
return None;
|
||||
};
|
||||
let TaggedValue::SelectionHistory(selection_undo_history) = tagged_value else {
|
||||
log::error!("Tagged value should be SelectionUndoHistory in selection_undo_history");
|
||||
return None;
|
||||
};
|
||||
Some(selection_undo_history)
|
||||
}
|
||||
|
||||
pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<String> {
|
||||
self.node_metadata(node_id, network_path)
|
||||
.and_then(|node_metadata| node_metadata.persistent_metadata.reference.as_ref().map(|reference| reference.to_string()))
|
||||
@@ -1459,7 +1473,6 @@ impl NodeNetworkInterface {
|
||||
log::error!("Could not get nested network in from_old_network");
|
||||
continue;
|
||||
};
|
||||
nested_network_metadata.persistent_metadata.previewing = Previewing::No;
|
||||
for (node_id, old_node) in old_network.nodes {
|
||||
let mut node = DocumentNode::default();
|
||||
let mut node_metadata = DocumentNodeMetadata::default();
|
||||
@@ -1613,44 +1626,137 @@ impl NodeNetworkInterface {
|
||||
self.transaction_status = TransactionStatus::Finished;
|
||||
}
|
||||
|
||||
/// Mutably get the selected nodes for the network at the network_path. Every time they are mutated, the transient metadata for the top of the stack gets unloaded.
|
||||
pub fn selected_nodes_mut(&mut self, network_path: &[NodeId]) -> Option<&mut SelectedNodes> {
|
||||
self.unload_stack_dependents(network_path);
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
/// Change the selected nodes for the network at the network_path. Every time they are mutated, the transient metadata for the top of the stack gets unloaded.
|
||||
fn mutate_selected_nodes(&mut self, nodes: Vec<NodeId>, selection_operation: SelectionOperation, network_path: &[NodeId]) {
|
||||
let Some(selection_undo_history) = self.selection_undo_history(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in selected_nodes");
|
||||
return None;
|
||||
return;
|
||||
};
|
||||
|
||||
let last_selection_state = network_metadata.persistent_metadata.selection_undo_history.back().cloned().unwrap_or_default();
|
||||
|
||||
network_metadata.persistent_metadata.selection_undo_history.push_back(last_selection_state);
|
||||
network_metadata.persistent_metadata.selection_redo_history.clear();
|
||||
|
||||
if network_metadata.persistent_metadata.selection_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
||||
network_metadata.persistent_metadata.selection_undo_history.pop_front();
|
||||
let mut last_selection_state = selection_undo_history.back().cloned().unwrap_or_default();
|
||||
match selection_operation {
|
||||
SelectionOperation::Add => {
|
||||
last_selection_state.extend(nodes);
|
||||
}
|
||||
SelectionOperation::Remove => {
|
||||
last_selection_state.retain(|node| !nodes.contains(node));
|
||||
}
|
||||
SelectionOperation::Set => {
|
||||
last_selection_state = nodes;
|
||||
}
|
||||
}
|
||||
network_metadata.persistent_metadata.selection_undo_history.back_mut()
|
||||
|
||||
let network = self.network_mut(&[]).unwrap();
|
||||
let metadata_node_id = Self::metadata_node_id(MetadataType::SelectionUndoHistory, network_path);
|
||||
let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else {
|
||||
log::error!("Could not get metadata node with id {metadata_node_id} in set_metadata");
|
||||
return;
|
||||
};
|
||||
let Some(metadata_input) = metadata_node.inputs.get_mut(0) else {
|
||||
log::error!("Could not get metadata input in set_metadata");
|
||||
return;
|
||||
};
|
||||
let Some(mut value) = metadata_input.as_value_mut() else {
|
||||
log::error!("Could not get tagged value in set_metadata");
|
||||
return;
|
||||
};
|
||||
let TaggedValue::SelectionHistory(selection_undo_history) = value.deref_mut() else {
|
||||
log::error!("Tagged value should be SelectionUndoHistory in set_metadata");
|
||||
return;
|
||||
};
|
||||
selection_undo_history.push_back(last_selection_state);
|
||||
if selection_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
||||
selection_undo_history.pop_front();
|
||||
}
|
||||
drop(value);
|
||||
self.unload_stack_dependents(network_path);
|
||||
self.set_metadata(MetadataType::SelectionRedoHistory, TaggedValue::SelectionHistory(VecDeque::new()), network_path);
|
||||
}
|
||||
|
||||
pub fn add_selected_nodes(&mut self, nodes: Vec<NodeId>, network_path: &[NodeId]) {
|
||||
self.mutate_selected_nodes(nodes, SelectionOperation::Add, network_path);
|
||||
}
|
||||
pub fn remove_selected_nodes(&mut self, nodes: Vec<NodeId>, network_path: &[NodeId]) {
|
||||
self.mutate_selected_nodes(nodes, SelectionOperation::Remove, network_path);
|
||||
}
|
||||
pub fn set_selected_nodes(&mut self, nodes: Vec<NodeId>, network_path: &[NodeId]) {
|
||||
self.mutate_selected_nodes(nodes, SelectionOperation::Set, network_path);
|
||||
}
|
||||
pub fn remove_selection_history_step(&mut self, network_path: &[NodeId]) {
|
||||
let network = self.network_mut(&[]).unwrap();
|
||||
let metadata_node_id = Self::metadata_node_id(MetadataType::SelectionUndoHistory, network_path);
|
||||
let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else {
|
||||
log::error!("Could not get metadata node with id {metadata_node_id} in set_metadata");
|
||||
return;
|
||||
};
|
||||
let Some(metadata_input) = metadata_node.inputs.get_mut(0) else {
|
||||
log::error!("Could not get metadata input in set_metadata");
|
||||
return;
|
||||
};
|
||||
let Some(mut value) = metadata_input.as_value_mut() else {
|
||||
log::error!("Could not get tagged value in set_metadata");
|
||||
return;
|
||||
};
|
||||
let TaggedValue::SelectionHistory(selection_undo_history) = value.deref_mut() else {
|
||||
log::error!("Tagged value should be SelectionUndoHistory in set_metadata");
|
||||
return;
|
||||
};
|
||||
selection_undo_history.pop_back();
|
||||
}
|
||||
|
||||
pub fn selection_step_back(&mut self, network_path: &[NodeId]) {
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in selection_step_back");
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(selection_state) = network_metadata.persistent_metadata.selection_undo_history.pop_back() {
|
||||
network_metadata.persistent_metadata.selection_redo_history.push_front(selection_state);
|
||||
}
|
||||
self.selection_step(SelectionDirection::Back, network_path);
|
||||
}
|
||||
|
||||
pub fn selection_step_forward(&mut self, network_path: &[NodeId]) {
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in selection_step_forward");
|
||||
return;
|
||||
self.selection_step(SelectionDirection::Forward, network_path);
|
||||
}
|
||||
|
||||
fn selection_step(&mut self, direction: SelectionDirection, network_path: &[NodeId]) {
|
||||
let (adding_to, removing_from) = match direction {
|
||||
SelectionDirection::Back => (MetadataType::SelectionUndoHistory, MetadataType::SelectionRedoHistory),
|
||||
SelectionDirection::Forward => (MetadataType::SelectionRedoHistory, MetadataType::SelectionUndoHistory),
|
||||
};
|
||||
|
||||
if let Some(selection_state) = network_metadata.persistent_metadata.selection_redo_history.pop_front() {
|
||||
network_metadata.persistent_metadata.selection_undo_history.push_back(selection_state);
|
||||
let network = self.network_mut(&[]).unwrap();
|
||||
let metadata_node_id = Self::metadata_node_id(adding_to, network_path);
|
||||
let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else {
|
||||
log::error!("Could not get metadata node with id {metadata_node_id} in selection_step");
|
||||
return;
|
||||
};
|
||||
let Some(metadata_input) = metadata_node.inputs.get_mut(0) else {
|
||||
log::error!("Could not get metadata input in selection_step");
|
||||
return;
|
||||
};
|
||||
let Some(mut value) = metadata_input.as_value_mut() else {
|
||||
log::error!("Could not get tagged value in selection_step");
|
||||
return;
|
||||
};
|
||||
let TaggedValue::SelectionHistory(selection_history) = value.deref_mut() else {
|
||||
log::error!("Tagged value should be SelectionHistory in selection_step");
|
||||
return;
|
||||
};
|
||||
if let Some(selection_state) = selection_history.pop_back() {
|
||||
drop(value);
|
||||
let network = self.network_mut(&[]).unwrap();
|
||||
let metadata_node_id = Self::metadata_node_id(removing_from, network_path);
|
||||
let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else {
|
||||
log::error!("Could not get metadata node with id {metadata_node_id} in selection_step");
|
||||
return;
|
||||
};
|
||||
let Some(metadata_input) = metadata_node.inputs.get_mut(0) else {
|
||||
log::error!("Could not get metadata input in selection_step");
|
||||
return;
|
||||
};
|
||||
let Some(mut value) = metadata_input.as_value_mut() else {
|
||||
log::error!("Could not get tagged value in selection_step");
|
||||
return;
|
||||
};
|
||||
let TaggedValue::SelectionHistory(selection_history) = value.deref_mut() else {
|
||||
log::error!("Tagged value should be SelectionHistory in selection_step");
|
||||
return;
|
||||
};
|
||||
selection_history.push_back(selection_state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3519,6 +3625,16 @@ impl NodeNetworkInterface {
|
||||
TaggedValue::DVec2(persistent_metadata.navigation_metadata.node_graph_top_right),
|
||||
network_path,
|
||||
);
|
||||
self.insert_node_metadata(
|
||||
MetadataType::SelectionUndoHistory,
|
||||
TaggedValue::SelectionHistory(persistent_metadata.selection_undo_history),
|
||||
network_path,
|
||||
);
|
||||
self.insert_node_metadata(
|
||||
MetadataType::SelectionRedoHistory,
|
||||
TaggedValue::SelectionHistory(persistent_metadata.selection_redo_history),
|
||||
network_path,
|
||||
);
|
||||
// TODO: Add the rest of the network metadata nodes
|
||||
|
||||
for (node_id, node_metadata) in persistent_metadata.node_metadata {
|
||||
@@ -3635,11 +3751,7 @@ impl NodeNetworkInterface {
|
||||
self.unload_all_nodes_bounding_box(network_path);
|
||||
// Instead of unloaded all node click targets, just unload the nodes upstream from the deleted nodes. unload_upstream_node_click_targets will not work since the nodes have been deleted.
|
||||
self.unload_all_nodes_click_targets(network_path);
|
||||
let Some(selected_nodes) = self.selected_nodes_mut(network_path) else {
|
||||
log::error!("Could not get selected nodes in NodeGraphMessage::DeleteNodes");
|
||||
return;
|
||||
};
|
||||
selected_nodes.retain_selected_nodes(|node_id| !nodes_to_delete.contains(node_id));
|
||||
self.remove_selected_nodes(nodes_to_delete, network_path);
|
||||
}
|
||||
|
||||
/// Removes all references to the node with the given id from the network, and reconnects the input to the node below.
|
||||
@@ -3703,12 +3815,7 @@ impl NodeNetworkInterface {
|
||||
let upstream_nodes = self.upstream_flow_back_from_nodes(vec![*reconnect_node], network_path, FlowType::PrimaryFlow).collect::<Vec<_>>();
|
||||
|
||||
// Select the reconnect node to move to ensure the shifting works correctly
|
||||
let Some(selected_nodes) = self.selected_nodes_mut(network_path) else {
|
||||
log::error!("Could not get selected nodes in remove_references_from_network");
|
||||
return false;
|
||||
};
|
||||
|
||||
let old_selected_nodes = selected_nodes.replace_with(upstream_nodes);
|
||||
self.set_selected_nodes(upstream_nodes, network_path);
|
||||
|
||||
// Shift up until there is either a collision or the disconnected node position is reached
|
||||
let mut current_shift_distance = 0;
|
||||
@@ -3717,7 +3824,7 @@ impl NodeNetworkInterface {
|
||||
current_shift_distance += 1;
|
||||
}
|
||||
|
||||
let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes);
|
||||
self.remove_selection_history_step(network_path);
|
||||
}
|
||||
|
||||
true
|
||||
@@ -4774,11 +4881,7 @@ impl NodeNetworkInterface {
|
||||
// If there is an upstream node in the new location for the layer, create space for the moved layer by shifting the upstream node down
|
||||
if let Some(upstream_node_id) = post_node_input.as_node() {
|
||||
// Select the layer to move to ensure the shifting works correctly
|
||||
let Some(selected_nodes) = self.selected_nodes_mut(network_path) else {
|
||||
log::error!("Could not get selected nodes in move_layer_to_stack");
|
||||
return;
|
||||
};
|
||||
let old_selected_nodes = selected_nodes.replace_with(vec![upstream_node_id]);
|
||||
self.set_selected_nodes(vec![upstream_node_id], network_path);
|
||||
|
||||
// Create the minimum amount space for the moved layer
|
||||
for _ in 0..3 {
|
||||
@@ -4797,7 +4900,7 @@ impl NodeNetworkInterface {
|
||||
self.vertical_shift_with_push(&upstream_node_id, 1, &mut HashSet::new(), network_path);
|
||||
}
|
||||
|
||||
let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes);
|
||||
self.remove_selection_history_step(network_path);
|
||||
}
|
||||
|
||||
// If inserting into a stack with a parent, ensure the parent stack has enough space for the child stack
|
||||
@@ -4836,17 +4939,13 @@ impl NodeNetworkInterface {
|
||||
let upstream_nodes = self
|
||||
.upstream_flow_back_from_nodes(vec![upstream_sibling.to_node()], network_path, FlowType::UpstreamFlow)
|
||||
.collect::<Vec<_>>();
|
||||
let Some(selected_nodes) = self.selected_nodes_mut(network_path) else {
|
||||
log::error!("Could not get selected nodes in move_layer_to_stack");
|
||||
return;
|
||||
};
|
||||
let old_selected_nodes = selected_nodes.replace_with(upstream_nodes);
|
||||
|
||||
self.set_selected_nodes(upstream_nodes, network_path);
|
||||
|
||||
for _ in 0..(target_gap - current_gap).max(0) {
|
||||
self.shift_selected_nodes(Direction::Down, true, network_path);
|
||||
}
|
||||
|
||||
let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes);
|
||||
self.remove_selection_history_step(network_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5131,10 +5230,10 @@ pub struct NodeNetworkPersistentMetadata {
|
||||
pub navigation_metadata: NavigationMetadata,
|
||||
/// Stack of selection snapshots for previous history states.
|
||||
#[serde(default)]
|
||||
pub selection_undo_history: VecDeque<SelectedNodes>,
|
||||
pub selection_undo_history: VecDeque<Vec<NodeId>>,
|
||||
/// Stack of selection snapshots for future history states.
|
||||
#[serde(default)]
|
||||
pub selection_redo_history: VecDeque<SelectedNodes>,
|
||||
pub selection_redo_history: VecDeque<Vec<NodeId>>,
|
||||
}
|
||||
|
||||
/// This is the same as Option, but more clear in the context of having cached metadata either being loaded or unloaded
|
||||
@@ -5159,7 +5258,6 @@ impl<T> TransientMetadata<T> {
|
||||
/// If some network calculation is too slow to compute for every usage, cache the data here
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NodeNetworkTransientMetadata {
|
||||
pub selected_nodes: SelectedNodes,
|
||||
/// Sole dependents of the top of the stacks of all selected nodes. Used to determine which nodes are checked for collision when shifting.
|
||||
/// The LayerOwner is used to determine whether the collided node should be shifted, or the layer that owns it.
|
||||
pub stack_dependents: TransientMetadata<HashMap<NodeId, LayerOwner>>,
|
||||
@@ -5422,6 +5520,17 @@ impl Default for NavigationMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
enum SelectionDirection {
|
||||
Back,
|
||||
Forward,
|
||||
}
|
||||
|
||||
enum SelectionOperation {
|
||||
Add,
|
||||
Remove,
|
||||
Set,
|
||||
}
|
||||
|
||||
// PartialEq required by message handlers
|
||||
/// All persistent editor and Graphene data for a node. Used to serialize and deserialize a node, pass it through the editor, and create definitions.
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -58,10 +58,47 @@ pub struct LayerPanelEntry {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||
pub struct SelectedNodes(pub Vec<NodeId>);
|
||||
pub struct OldSelectedNodes(pub Vec<NodeId>);
|
||||
|
||||
impl SelectedNodes {
|
||||
pub fn layer_visible(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool {
|
||||
pub trait SelectedNodes {
|
||||
fn layer_visible(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool;
|
||||
|
||||
fn selected_visible_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_;
|
||||
|
||||
fn layer_locked(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool;
|
||||
|
||||
fn selected_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_;
|
||||
|
||||
fn selected_visible_and_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_;
|
||||
|
||||
fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_;
|
||||
|
||||
fn selected_layers_except_artboards<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_;
|
||||
|
||||
fn selected_layers_contains(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool;
|
||||
|
||||
fn selected_nodes(&self) -> impl Iterator<Item = &NodeId> + '_;
|
||||
|
||||
fn selected_nodes_ref(&self) -> &Vec<NodeId>;
|
||||
|
||||
fn network_has_selected_nodes(&self, network: &NodeNetwork) -> bool;
|
||||
|
||||
fn has_selected_nodes(&self) -> bool;
|
||||
|
||||
fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool);
|
||||
|
||||
fn set_selected_nodes(&mut self, new: Vec<NodeId>);
|
||||
|
||||
fn add_selected_nodes(&mut self, new: Vec<NodeId>);
|
||||
|
||||
fn clear_selected_nodes(&mut self);
|
||||
|
||||
fn replace_with(&mut self, new: Vec<NodeId>) -> Vec<NodeId>;
|
||||
|
||||
fn filtered_selected_nodes(&self, node_ids: std::collections::HashSet<NodeId>) -> Vec<NodeId>;
|
||||
}
|
||||
impl SelectedNodes for Vec<NodeId> {
|
||||
fn layer_visible(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool {
|
||||
layer.ancestors(network_interface.document_metadata()).all(|layer| {
|
||||
if layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
network_interface.is_visible(&layer.to_node(), &[])
|
||||
@@ -71,12 +108,12 @@ impl SelectedNodes {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn selected_visible_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
fn selected_visible_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
self.selected_layers(network_interface.document_metadata())
|
||||
.filter(move |&layer| self.layer_visible(layer, network_interface))
|
||||
}
|
||||
|
||||
pub fn layer_locked(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool {
|
||||
fn layer_locked(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool {
|
||||
layer.ancestors(network_interface.document_metadata()).any(|layer| {
|
||||
if layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
network_interface.is_locked(&layer.to_node(), &[])
|
||||
@@ -86,67 +123,67 @@ impl SelectedNodes {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn selected_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
fn selected_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
self.selected_layers(network_interface.document_metadata())
|
||||
.filter(move |&layer| !self.layer_locked(layer, network_interface))
|
||||
}
|
||||
|
||||
pub fn selected_visible_and_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
fn selected_visible_and_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
self.selected_layers(network_interface.document_metadata())
|
||||
.filter(move |&layer| self.layer_visible(layer, network_interface) && !self.layer_locked(layer, network_interface))
|
||||
}
|
||||
|
||||
pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
metadata.all_layers().filter(|layer| self.0.contains(&layer.to_node()))
|
||||
fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
metadata.all_layers().filter(|layer| self.contains(&layer.to_node()))
|
||||
}
|
||||
|
||||
pub fn selected_layers_except_artboards<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
fn selected_layers_except_artboards<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||
self.selected_layers(network_interface.document_metadata())
|
||||
.filter(move |&layer| !network_interface.is_artboard(&layer.to_node(), &[]))
|
||||
}
|
||||
|
||||
pub fn selected_layers_contains(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool {
|
||||
fn selected_layers_contains(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool {
|
||||
self.selected_layers(metadata).any(|selected| selected == layer)
|
||||
}
|
||||
|
||||
pub fn selected_nodes(&self) -> impl Iterator<Item = &NodeId> + '_ {
|
||||
self.0.iter()
|
||||
fn selected_nodes(&self) -> impl Iterator<Item = &NodeId> + '_ {
|
||||
self.iter()
|
||||
}
|
||||
|
||||
pub fn selected_nodes_ref(&self) -> &Vec<NodeId> {
|
||||
&self.0
|
||||
fn selected_nodes_ref(&self) -> &Vec<NodeId> {
|
||||
&self
|
||||
}
|
||||
|
||||
pub fn network_has_selected_nodes(&self, network: &NodeNetwork) -> bool {
|
||||
self.0.iter().any(|node_id| network.nodes.contains_key(node_id))
|
||||
fn network_has_selected_nodes(&self, network: &NodeNetwork) -> bool {
|
||||
self.iter().any(|node_id| network.nodes.contains_key(node_id))
|
||||
}
|
||||
|
||||
pub fn has_selected_nodes(&self) -> bool {
|
||||
!self.0.is_empty()
|
||||
fn has_selected_nodes(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
|
||||
self.0.retain(f);
|
||||
fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
|
||||
self.retain(f);
|
||||
}
|
||||
|
||||
pub fn set_selected_nodes(&mut self, new: Vec<NodeId>) {
|
||||
self.0 = new;
|
||||
fn set_selected_nodes(&mut self, new: Vec<NodeId>) {
|
||||
*self = new;
|
||||
}
|
||||
|
||||
pub fn add_selected_nodes(&mut self, new: Vec<NodeId>) {
|
||||
self.0.extend(new);
|
||||
fn add_selected_nodes(&mut self, new: Vec<NodeId>) {
|
||||
self.extend(new);
|
||||
}
|
||||
|
||||
pub fn clear_selected_nodes(&mut self) {
|
||||
self.0 = Vec::new();
|
||||
fn clear_selected_nodes(&mut self) {
|
||||
*self = Vec::new();
|
||||
}
|
||||
|
||||
pub fn replace_with(&mut self, new: Vec<NodeId>) -> Vec<NodeId> {
|
||||
std::mem::replace(&mut self.0, new)
|
||||
fn replace_with(&mut self, new: Vec<NodeId>) -> Vec<NodeId> {
|
||||
std::mem::replace(self, new)
|
||||
}
|
||||
|
||||
pub fn filtered_selected_nodes(&self, node_ids: std::collections::HashSet<NodeId>) -> SelectedNodes {
|
||||
SelectedNodes(self.0.iter().filter(|node_id| node_ids.contains(node_id)).cloned().collect())
|
||||
fn filtered_selected_nodes(&self, node_ids: std::collections::HashSet<NodeId>) -> Vec<NodeId> {
|
||||
self.iter().filter(|node_id| node_ids.contains(node_id)).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::messages::dialog::simple_dialogs;
|
||||
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::portfolio::document::DocumentMessageData;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::{HintData, HintGroup};
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use graphene_std::vector::PointId;
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapData;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_core::renderer::Quad;
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::NodeId;
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_gradient;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graphene_core::vector::style::{Fill, Gradient, GradientType};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::shape_editor::{ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedPointsInfo, ShapeState};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapData, SnapManager};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_core::vector::ManipulatorPointId;
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::messages::portfolio::document::overlays::utility_types::OverlayContex
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::portfolio::document::utility_types::transformation::Selected;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name;
|
||||
use crate::messages::tool::common_functionality::pivot::Pivot;
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::application::generate_uuid;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::messages::portfolio::document::utility_types::transformation::{Axis,
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::utility_types::{ToolData, ToolType};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
|
||||
use graphene_core::vector::ManipulatorPointId;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use graphene_core::{Color, MemoHash, Node, Type};
|
||||
use dyn_any::DynAny;
|
||||
pub use dyn_any::StaticType;
|
||||
pub use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Display;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
@@ -180,6 +181,7 @@ tagged_value! {
|
||||
FontCache(Arc<graphene_core::text::FontCache>),
|
||||
Previewing(crate::document::Previewing),
|
||||
PTZ(crate::document::PTZ),
|
||||
SelectionHistory(VecDeque<Vec<NodeId>>),
|
||||
}
|
||||
|
||||
impl TaggedValue {
|
||||
|
||||
Reference in New Issue
Block a user