Add support for pinning nodes in the Properties panel
This commit is contained in:
parent
b26dfbcd7c
commit
e6d8c4743d
|
|
@ -382,8 +382,8 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||||
|
|
||||||
let name = self.network_interface.frontend_display_name(&layer.to_node(), &[]);
|
let name = self.network_interface.frontend_display_name(&layer.to_node(), &[]);
|
||||||
|
|
||||||
let (_, angle, translation) = self.metadata().document_to_viewport.to_scale_angle_translation();
|
let (scale, angle, translation) = self.metadata().document_to_viewport.to_scale_angle_translation();
|
||||||
let translation = translation + bounds[0].min(bounds[1]) - DVec2::Y * 4.;
|
let translation = translation + scale * bounds[0].min(bounds[1]) - DVec2::Y * 4.;
|
||||||
let transform = DAffine2::from_angle_translation(angle, translation);
|
let transform = DAffine2::from_angle_translation(angle, translation);
|
||||||
|
|
||||||
overlay_context.text_with_transform(&name, COLOR_OVERLAY_GRAY, None, transform, Pivot::BottomLeft);
|
overlay_context.text_with_transform(&name, COLOR_OVERLAY_GRAY, None, transform, Pivot::BottomLeft);
|
||||||
|
|
|
||||||
|
|
@ -139,10 +139,15 @@ pub enum NodeGraphMessage {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
},
|
},
|
||||||
|
ToggleSelectedIsPinned,
|
||||||
ToggleSelectedVisibility,
|
ToggleSelectedVisibility,
|
||||||
ToggleVisibility {
|
ToggleVisibility {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
},
|
},
|
||||||
|
SetPinned {
|
||||||
|
node_id: NodeId,
|
||||||
|
pinned: bool,
|
||||||
|
},
|
||||||
SetVisibility {
|
SetVisibility {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
|
|
|
||||||
|
|
@ -1219,6 +1219,28 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
NodeGraphMessage::SetLocked { node_id, locked } => {
|
NodeGraphMessage::SetLocked { node_id, locked } => {
|
||||||
network_interface.set_locked(&node_id, selection_network_path, locked);
|
network_interface.set_locked(&node_id, selection_network_path, locked);
|
||||||
}
|
}
|
||||||
|
NodeGraphMessage::ToggleSelectedIsPinned => {
|
||||||
|
let Some(selected_nodes) = network_interface.selected_nodes(selection_network_path) else {
|
||||||
|
log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedIsPinned");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let node_ids = selected_nodes.selected_nodes().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// If any of the selected nodes are pinned, unpin them all. Otherwise, pin them all.
|
||||||
|
let pinned = !node_ids.iter().all(|node_id| {
|
||||||
|
if let Some(node) = network_interface.node_metadata(node_id, breadcrumb_network_path) {
|
||||||
|
node.persistent_metadata.pinned
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
responses.add(DocumentMessage::AddTransaction);
|
||||||
|
for node_id in &node_ids {
|
||||||
|
responses.add(NodeGraphMessage::SetPinned { node_id: *node_id, pinned });
|
||||||
|
}
|
||||||
|
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids });
|
||||||
|
}
|
||||||
NodeGraphMessage::ToggleSelectedVisibility => {
|
NodeGraphMessage::ToggleSelectedVisibility => {
|
||||||
let Some(network) = network_interface.network(selection_network_path) else {
|
let Some(network) = network_interface.network(selection_network_path) else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1227,7 +1249,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked");
|
log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let node_ids = selected_nodes.selected_nodes().cloned().collect::<Vec<_>>();
|
let node_ids = selected_nodes.selected_nodes().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
// If any of the selected nodes are hidden, show them all. Otherwise, hide them all.
|
// If any of the selected nodes are hidden, show them all. Otherwise, hide them all.
|
||||||
|
|
@ -1255,6 +1276,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
responses.add(NodeGraphMessage::SetVisibility { node_id, visible });
|
responses.add(NodeGraphMessage::SetVisibility { node_id, visible });
|
||||||
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids: vec![node_id] });
|
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids: vec![node_id] });
|
||||||
}
|
}
|
||||||
|
NodeGraphMessage::SetPinned { node_id, pinned } => {
|
||||||
|
network_interface.set_pinned(&node_id, selection_network_path, pinned);
|
||||||
|
}
|
||||||
NodeGraphMessage::SetVisibility { node_id, visible } => {
|
NodeGraphMessage::SetVisibility { node_id, visible } => {
|
||||||
network_interface.set_visibility(&node_id, selection_network_path, visible);
|
network_interface.set_visibility(&node_id, selection_network_path, visible);
|
||||||
}
|
}
|
||||||
|
|
@ -1459,8 +1483,7 @@ impl NodeGraphMessageHandler {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut selection = selected_nodes.selected_nodes();
|
let mut selection = selected_nodes.selected_nodes();
|
||||||
|
// If there is at least one selected node then show the hide or show button
|
||||||
// If there is at least one other selected node then show the hide or show button
|
|
||||||
if selection.next().is_some() {
|
if selection.next().is_some() {
|
||||||
// Check if any of the selected nodes are disabled
|
// Check if any of the selected nodes are disabled
|
||||||
let all_visible = selected_nodes.selected_nodes().all(|id| {
|
let all_visible = selected_nodes.selected_nodes().all(|id| {
|
||||||
|
|
@ -1479,7 +1502,7 @@ impl NodeGraphMessageHandler {
|
||||||
let (hide_show_label, hide_show_icon) = if all_visible { ("Make Hidden", "EyeVisible") } else { ("Make Visible", "EyeHidden") };
|
let (hide_show_label, hide_show_icon) = if all_visible { ("Make Hidden", "EyeVisible") } else { ("Make Visible", "EyeHidden") };
|
||||||
let hide_button = TextButton::new(hide_show_label)
|
let hide_button = TextButton::new(hide_show_label)
|
||||||
.icon(Some(hide_show_icon.to_string()))
|
.icon(Some(hide_show_icon.to_string()))
|
||||||
.tooltip(if all_visible { "Hide selected nodes/layers" } else { "Show selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" })
|
.tooltip(if all_visible { "Hide" } else { "Show" }.to_string() + " selected " + if multiple_nodes { "nodes/layers" } else { "node/layer" })
|
||||||
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility))
|
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility))
|
||||||
.on_update(move |_| NodeGraphMessage::ToggleSelectedVisibility.into())
|
.on_update(move |_| NodeGraphMessage::ToggleSelectedVisibility.into())
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
|
@ -1488,6 +1511,39 @@ impl NodeGraphMessageHandler {
|
||||||
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut selection = selected_nodes.selected_nodes();
|
||||||
|
// If there is at least one selected node then show the pin or unpin button
|
||||||
|
if selection.next().is_some() {
|
||||||
|
// Check if any of the selected nodes are pinned
|
||||||
|
let all_unpinned = !selected_nodes.selected_nodes().all(|id| {
|
||||||
|
if let Some(node) = network_interface.node_metadata(id, breadcrumb_network_path) {
|
||||||
|
node.persistent_metadata.pinned
|
||||||
|
} else {
|
||||||
|
error!("Could not get node {id} in update_selection_action_buttons");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if multiple nodes are selected
|
||||||
|
let multiple_nodes = selection.next().is_some();
|
||||||
|
|
||||||
|
// Generate the visible/hidden button accordingly
|
||||||
|
let (pin_unpin_label, pin_unpin_icon) = if all_unpinned { ("Pin", "CheckboxUnchecked") } else { ("Unpin", "CheckboxChecked") };
|
||||||
|
let pin_button = TextButton::new(pin_unpin_label)
|
||||||
|
.icon(Some(pin_unpin_icon.to_string()))
|
||||||
|
.tooltip(
|
||||||
|
if all_unpinned { "Pin" } else { "Unpin" }.to_string()
|
||||||
|
+ " selected " + if multiple_nodes { "nodes/layers" } else { "node/layer" }
|
||||||
|
+ " in the Properties panel when nothing is selected",
|
||||||
|
)
|
||||||
|
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedIsPinned))
|
||||||
|
.on_update(move |_| NodeGraphMessage::ToggleSelectedIsPinned.into())
|
||||||
|
.widget_holder();
|
||||||
|
widgets.push(pin_button);
|
||||||
|
|
||||||
|
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
||||||
|
}
|
||||||
|
|
||||||
let mut selection = selected_nodes.selected_nodes();
|
let mut selection = selected_nodes.selected_nodes();
|
||||||
// If only one node is selected then show the preview or stop previewing button
|
// If only one node is selected then show the preview or stop previewing button
|
||||||
if let (Some(&node_id), None) = (selection.next(), selection.next()) {
|
if let (Some(&node_id), None) = (selection.next(), selection.next()) {
|
||||||
|
|
@ -1518,10 +1574,12 @@ impl NodeGraphMessageHandler {
|
||||||
warn!("No selected nodes in collate_properties");
|
warn!("No selected nodes in collate_properties");
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
// We want:
|
// We want:
|
||||||
// - If only nodes (no layers) are selected: display each node's properties
|
// - If only nodes (no layers) are selected: display each node's properties
|
||||||
// - If one layer is selected, and zero or more of its upstream nodes: display the properties for the layer and its upstream nodes
|
// - If one layer is selected, and zero or more of its (primary flow) upstream nodes: display the properties for the layer and all its upstream nodes
|
||||||
// - If multiple layers are selected, or one node plus other non-upstream nodes: display nothing
|
// - If multiple layers are selected, or one node plus other non-upstream nodes: display nothing
|
||||||
|
// - If nothing is selected, display any pinned nodes/layers
|
||||||
|
|
||||||
// First, we filter all the selections into layers and nodes
|
// First, we filter all the selections into layers and nodes
|
||||||
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
|
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
|
||||||
|
|
@ -1536,10 +1594,35 @@ impl NodeGraphMessageHandler {
|
||||||
// Next, we decide what to display based on the number of layers and nodes selected
|
// Next, we decide what to display based on the number of layers and nodes selected
|
||||||
match layers.len() {
|
match layers.len() {
|
||||||
// If no layers are selected, show properties for all selected nodes
|
// If no layers are selected, show properties for all selected nodes
|
||||||
0 => nodes
|
0 => {
|
||||||
.iter()
|
let selected_nodes = nodes
|
||||||
.filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, context)))
|
.iter()
|
||||||
.collect(),
|
.filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, context)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if !selected_nodes.is_empty() {
|
||||||
|
return selected_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And if no nodes are selected, show properties for all pinned nodes
|
||||||
|
network
|
||||||
|
.nodes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(node_id, node)| {
|
||||||
|
let pinned = if let Some(node) = context.network_interface.node_metadata(node_id, context.selection_network_path) {
|
||||||
|
node.persistent_metadata.pinned
|
||||||
|
} else {
|
||||||
|
error!("Could not get node {node_id} in collate_properties");
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if pinned {
|
||||||
|
Some(node_properties::generate_node_properties(node, *node_id, context))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
// If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing.
|
// If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing.
|
||||||
1 => {
|
1 => {
|
||||||
let nodes_not_upstream_of_layer = nodes.into_iter().filter(|&selected_node_id| {
|
let nodes_not_upstream_of_layer = nodes.into_iter().filter(|&selected_node_id| {
|
||||||
|
|
|
||||||
|
|
@ -3749,11 +3749,20 @@ impl NodeNetworkInterface {
|
||||||
self.unload_node_click_targets(node_id, network_path);
|
self.unload_node_click_targets(node_id, network_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_pinned(&mut self, node_id: &NodeId, network_path: &[NodeId], pinned: bool) {
|
||||||
|
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||||
|
log::error!("Could not get node {node_id} in set_pinned");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
node_metadata.persistent_metadata.pinned = pinned;
|
||||||
|
self.transaction_modified();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_visibility(&mut self, node_id: &NodeId, network_path: &[NodeId], is_visible: bool) {
|
pub fn set_visibility(&mut self, node_id: &NodeId, network_path: &[NodeId], is_visible: bool) {
|
||||||
let Some(network) = self.network_mut(network_path) else {
|
let Some(network) = self.network_mut(network_path) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(node) = network.nodes.get_mut(node_id) else {
|
let Some(node) = network.nodes.get_mut(node_id) else {
|
||||||
log::error!("Could not get node {node_id} in set_visibility");
|
log::error!("Could not get node {node_id} in set_visibility");
|
||||||
return;
|
return;
|
||||||
|
|
@ -5301,6 +5310,9 @@ pub struct DocumentNodePersistentMetadata {
|
||||||
/// Represents the lock icon for locking/unlocking the node in the graph UI. When locked, a node cannot be moved in the graph UI.
|
/// Represents the lock icon for locking/unlocking the node in the graph UI. When locked, a node cannot be moved in the graph UI.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
|
/// Indicates that the node will be shown in the Properties panel when it would otherwise be empty, letting a user easily edit its properties by just deselecting everything.
|
||||||
|
#[serde(default)]
|
||||||
|
pub pinned: bool,
|
||||||
/// Metadata that is specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer.
|
/// Metadata that is specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer.
|
||||||
/// All fields in NodeTypePersistentMetadata should automatically be updated by using the network interface API
|
/// All fields in NodeTypePersistentMetadata should automatically be updated by using the network interface API
|
||||||
pub node_type_metadata: NodeTypePersistentMetadata,
|
pub node_type_metadata: NodeTypePersistentMetadata,
|
||||||
|
|
@ -5316,6 +5328,7 @@ impl Default for DocumentNodePersistentMetadata {
|
||||||
input_names: Vec::new(),
|
input_names: Vec::new(),
|
||||||
output_names: Vec::new(),
|
output_names: Vec::new(),
|
||||||
has_primary_output: true,
|
has_primary_output: true,
|
||||||
|
pinned: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
node_type_metadata: NodeTypePersistentMetadata::default(),
|
node_type_metadata: NodeTypePersistentMetadata::default(),
|
||||||
network_metadata: None,
|
network_metadata: None,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue