Add button in Properties panel to select the node connected to an exposed parameter (#3720)

* Navigation-Shortcut

* Fix as rec

* cleanup

* Update labels

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Kulcode 2026-02-18 15:55:02 +05:30 committed by GitHub
parent 5d5993bcca
commit b433ddd007
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 57 additions and 8 deletions

View File

@ -4,7 +4,7 @@ use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext};
use super::utility_types::FrontendGraphDataType; use super::utility_types::FrontendGraphDataType;
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface};
use crate::messages::portfolio::utility_types::{FontCatalogStyle, PersistentData}; use crate::messages::portfolio::utility_types::{FontCatalogStyle, PersistentData};
use crate::messages::prelude::*; use crate::messages::prelude::*;
use choice::enum_choice; use choice::enum_choice;
@ -79,6 +79,29 @@ pub fn add_blank_assist(widgets: &mut Vec<WidgetInstance>) {
]); ]);
} }
pub fn jump_to_source_widget(input: &NodeInput, network_interface: &NodeNetworkInterface, selection_network_path: &[NodeId]) -> WidgetInstance {
match input {
NodeInput::Node { node_id: source_id, .. } => {
let source_id = *source_id;
let node_name = network_interface.implementation_name(&source_id, selection_network_path);
TextButton::new(format!("From Graph ({})", node_name))
.tooltip_description("Click to select the node producing this parameter's data.")
.on_update(move |_| NodeGraphMessage::SelectedNodesSet { nodes: vec![source_id] }.into())
.widget_instance()
}
_ => TextLabel::new("From Graph (Disconnected)")
.tooltip_description(
"
This parameter is exposed as an input in the node graph, but not currently receiving data from any node.\n\
\n\
In the graph, drag a wire out from a compatible output connector of another node, and feed it into the input connector of this exposed node parameter. Alternatively, un-expose this parameter by clicking the triangle directly to the left of here.
"
.trim(),
)
.widget_instance(),
}
}
pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> { pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> {
let ParameterWidgetsInfo { let ParameterWidgetsInfo {
document_node, document_node,
@ -89,6 +112,8 @@ pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<Widget
input_type, input_type,
blank_assist, blank_assist,
exposable, exposable,
network_interface,
selection_network_path,
.. ..
} = parameter_widgets_info; } = parameter_widgets_info;
@ -106,6 +131,17 @@ pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<Widget
widgets.push(expose_widget(node_id, index, input_type, input.is_exposed())); widgets.push(expose_widget(node_id, index, input_type, input.is_exposed()));
} }
widgets.push(TextLabel::new(name).tooltip_description(description).widget_instance()); widgets.push(TextLabel::new(name).tooltip_description(description).widget_instance());
let mut blank_assist = blank_assist;
if input.is_exposed() {
if blank_assist {
add_blank_assist(&mut widgets);
blank_assist = false;
}
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
widgets.push(jump_to_source_widget(input, network_interface, selection_network_path));
}
if blank_assist { if blank_assist {
add_blank_assist(&mut widgets); add_blank_assist(&mut widgets);
} }
@ -233,14 +269,19 @@ pub(crate) fn property_from_type(
// OTHER // OTHER
// ===== // =====
_ => { _ => {
let is_exposed = default_info.is_exposed();
let mut widgets = start_widgets(default_info); let mut widgets = start_widgets(default_info);
widgets.extend_from_slice(&[
Separator::new(SeparatorStyle::Unrelated).widget_instance(), if !is_exposed {
TextLabel::new("-") widgets.extend_from_slice(&[
.tooltip_label(format!("Data Type: {concrete_type}")) Separator::new(SeparatorStyle::Unrelated).widget_instance(),
.tooltip_description("This data can only be supplied through the node graph because no widget exists for its type.") TextLabel::new("-")
.widget_instance(), .tooltip_label(format!("Data Type: {concrete_type}"))
]); .tooltip_description("This data can only be supplied through the node graph because no widget exists for its type.")
.widget_instance(),
]);
}
return Err(vec![widgets.into()]); return Err(vec![widgets.into()]);
} }
} }
@ -2144,6 +2185,8 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
pub struct ParameterWidgetsInfo<'a> { pub struct ParameterWidgetsInfo<'a> {
persistent_data: &'a PersistentData, persistent_data: &'a PersistentData,
network_interface: &'a NodeNetworkInterface,
selection_network_path: &'a [NodeId],
document_node: Option<&'a DocumentNode>, document_node: Option<&'a DocumentNode>,
node_id: NodeId, node_id: NodeId,
index: usize, index: usize,
@ -2165,6 +2208,8 @@ impl<'a> ParameterWidgetsInfo<'a> {
ParameterWidgetsInfo { ParameterWidgetsInfo {
persistent_data: context.persistent_data, persistent_data: context.persistent_data,
network_interface: context.network_interface,
selection_network_path: context.selection_network_path,
document_node, document_node,
node_id, node_id,
index, index,
@ -2175,6 +2220,10 @@ impl<'a> ParameterWidgetsInfo<'a> {
exposable: true, exposable: true,
} }
} }
pub fn is_exposed(&self) -> bool {
self.document_node.and_then(|node| node.inputs.get(self.index)).map(|input| input.is_exposed()).unwrap_or(false)
}
} }
pub mod choice { pub mod choice {