Skip to content

Add preview and disable buttons for nodes #905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions editor/src/messages/layout/utility_types/layout_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ pub enum LayoutGroup {
#[serde(rename = "section")]
Section { name: String, layout: SubLayout },
}

impl Default for LayoutGroup {
fn default() -> Self {
Self::Row { widgets: Vec::new() }
}
}

impl LayoutGroup {
/// Applies a tooltip to all widgets in this row or column without a tooltip.
pub fn with_tooltip(self, tooltip: impl Into<String>) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ pub enum NodeGraphMessage {
input_index: usize,
value: TaggedValue,
},
SetSelectedEnabled {
enabled: bool,
},
SetSelectedOutput {
output: bool,
},
ShiftNode {
node_id: NodeId,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
use crate::messages::layout::utility_types::widgets::button_widgets::BreadcrumbTrailButtons;
use crate::messages::layout::utility_types::widgets::button_widgets::{BreadcrumbTrailButtons, TextButton};
use crate::messages::prelude::*;

use document_legacy::document::Document;
Expand Down Expand Up @@ -65,6 +65,8 @@ pub struct FrontendNode {
pub exposed_inputs: Vec<NodeGraphInput>,
pub outputs: Vec<FrontendGraphDataType>,
pub position: (i32, i32),
pub disabled: bool,
pub output: bool,
}

// (link_start, link_end, link_end_input_index)
Expand Down Expand Up @@ -92,11 +94,13 @@ impl FrontendNodeType {
}
}

#[derive(Debug, Clone, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct NodeGraphMessageHandler {
pub layer_path: Option<Vec<document_legacy::LayerId>>,
pub nested_path: Vec<graph_craft::document::NodeId>,
pub selected_nodes: Vec<graph_craft::document::NodeId>,
#[serde(skip)]
pub widgets: [LayoutGroup; 2],
}

impl NodeGraphMessageHandler {
Expand Down Expand Up @@ -124,8 +128,20 @@ impl NodeGraphMessageHandler {
network
}

/// Send the cached layout for the bar at the top of the node panel to the frontend
fn send_node_bar_layout(&self, responses: &mut VecDeque<Message>) {
responses.push_back(
LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())),
layout_target: crate::messages::layout::utility_types::misc::LayoutTarget::NodeGraphBar,
}
.into(),
);
}

/// Collect the addresses of the currently viewed nested node e.g. Root -> MyFunFilter -> Exposure
fn collect_nested_addresses(&self, document: &Document, responses: &mut VecDeque<Message>) {
fn collect_nested_addresses(&mut self, document: &Document, responses: &mut VecDeque<Message>) {
// Build path list
let mut path = vec!["Root".to_string()];
let mut network = self.get_root_network(document);
for node_id in &self.nested_path {
Expand All @@ -137,24 +153,56 @@ impl NodeGraphMessageHandler {
}
let nesting = path.len();

responses.push_back(
LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons {
labels: path,
on_update: WidgetCallback::new(move |input: &u64| {
NodeGraphMessage::ExitNestedNetwork {
depth_of_nesting: nesting - (*input as usize) - 1,
}
.into()
}),
// Update UI
self.widgets[0] = LayoutGroup::Row {
widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons {
labels: path.clone(),
on_update: WidgetCallback::new(move |input: &u64| {
NodeGraphMessage::ExitNestedNetwork {
depth_of_nesting: nesting - (*input as usize) - 1,
}
.into()
}),
..Default::default()
}))],
};

self.send_node_bar_layout(responses);
}

/// Updates the buttons for disable and preview
fn update_selection_action_buttons(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
if let Some(network) = self.get_active_network_mut(document) {
let mut widgets = Vec::new();

// Show an enable or disable nodes button if there is a selection
if !self.selected_nodes.is_empty() {
let is_enabled = self.selected_nodes.iter().any(|id| !network.disabled.contains(id));
let enable_button = WidgetHolder::new(Widget::TextButton(TextButton {
label: if is_enabled { "Disable" } else { "Enable" }.to_string(),
on_update: WidgetCallback::new(move |_| NodeGraphMessage::SetSelectedEnabled { enabled: !is_enabled }.into()),
..Default::default()
}));
widgets.push(enable_button);
}

// If only one node is selected then show the preview or stop previewing button
if self.selected_nodes.len() == 1 {
let is_output = network.output == self.selected_nodes[0];
// Don't show stop previewing on the output node
if !(is_output && network.previous_output.filter(|&id| id != self.selected_nodes[0]).is_none()) {
let output_button = WidgetHolder::new(Widget::TextButton(TextButton {
label: if is_output { "Stop Previewing" } else { "Preview" }.to_string(),
on_update: WidgetCallback::new(move |_| NodeGraphMessage::SetSelectedOutput { output: !is_output }.into()),
..Default::default()
}))],
}])),
layout_target: crate::messages::layout::utility_types::misc::LayoutTarget::NodeGraphBar,
}));
widgets.push(output_button);
}
}
.into(),
);

self.widgets[1] = LayoutGroup::Row { widgets };
}
self.send_node_bar_layout(responses);
}

pub fn collate_properties(&self, node_graph_frame: &NodeGraphFrameLayer, context: &mut NodePropertiesContext, sections: &mut Vec<LayoutGroup>) {
Expand Down Expand Up @@ -237,14 +285,17 @@ impl NodeGraphMessageHandler {
.collect(),
outputs: node_type.outputs.to_vec(),
position: node.metadata.position,
output: network.output == *id,
disabled: network.disabled.contains(id),
})
}
log::debug!("Frontend Nodes:\n{:#?}\n\nLinks:\n{:#?}", nodes, links);
responses.push_back(FrontendMessage::UpdateNodeGraph { nodes, links }.into());
}

/// Updates the frontend's selection state inline with the backend
fn update_selected(&self, responses: &mut VecDeque<Message>) {
/// Updates the frontend's selection state in line with the backend
fn update_selected(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document, responses);
responses.push_back(
FrontendMessage::UpdateNodeGraphSelection {
selected: self.selected_nodes.clone(),
Expand Down Expand Up @@ -388,6 +439,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
)]
.into_iter()
.collect(),
..Default::default()
};

network.nodes.insert(
Expand All @@ -413,6 +465,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
}
self.update_selected(document, responses);
}
NodeGraphMessage::DeleteSelectedNodes => {
if let Some(network) = self.get_active_network_mut(document) {
Expand All @@ -425,6 +478,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
}
self.update_selected(document, responses);
}
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
let Some(network) = self.get_active_network_mut(document) else {
Expand All @@ -443,7 +497,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
Self::send_graph(network, responses);
}
NodeGraphMessage::DoubleClickNode { node } => {
self.selected_nodes = Vec::new();
self.selected_nodes.clear();
if let Some(network) = self.get_active_network_mut(document) {
if network.nodes.get(&node).and_then(|node| node.implementation.get_network()).is_some() {
self.nested_path.push(node);
Expand All @@ -453,7 +507,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
Self::send_graph(network, responses);
}
self.collect_nested_addresses(document, responses);
self.update_selected(responses);
self.update_selected(document, responses);
}
NodeGraphMessage::DuplicateSelectedNodes => {
if let Some(network) = self.get_active_network_mut(document) {
Expand All @@ -476,18 +530,19 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
}
self.selected_nodes = new_selected;
Self::send_graph(network, responses);
self.update_selected(responses);
self.update_selected(document, responses);
}
}
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
self.selected_nodes = Vec::new();
self.selected_nodes.clear();
for _ in 0..depth_of_nesting {
self.nested_path.pop();
}
if let Some(network) = self.get_active_network_mut(document) {
Self::send_graph(network, responses);
}
self.collect_nested_addresses(document, responses);
self.update_selected(document, responses);
}
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
let Some(network) = self.get_active_network_mut(document) else{
Expand Down Expand Up @@ -542,6 +597,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
responses.push_back(FrontendMessage::UpdateNodeTypes { node_types }.into());
}
self.collect_nested_addresses(document, responses);
self.update_selected(document, responses);
}
NodeGraphMessage::PasteNodes { serialized_nodes } => {
let Some(network) = self.get_active_network_mut(document) else{
Expand All @@ -567,10 +623,11 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
}

Self::send_graph(network, responses);
self.update_selected(responses);
self.update_selected(document, responses);
}
NodeGraphMessage::SelectNodes { nodes } => {
self.selected_nodes = nodes;
self.update_selection_action_buttons(document, responses);
responses.push_back(PropertiesPanelMessage::ResendActiveProperties.into());
}
NodeGraphMessage::SetInputValue { node, input_index, value } => {
Expand Down Expand Up @@ -615,6 +672,31 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
}
}
}
NodeGraphMessage::SetSelectedEnabled { enabled } => {
if let Some(network) = self.get_active_network_mut(document) {
if enabled {
network.disabled.retain(|id| !self.selected_nodes.contains(id));
} else {
network.disabled.extend(&self.selected_nodes);
}
Self::send_graph(network, responses);
}
self.update_selection_action_buttons(document, responses);
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
NodeGraphMessage::SetSelectedOutput { output } => {
if let Some(network) = self.get_active_network_mut(document) {
if output {
network.previous_output = Some(network.previous_output.unwrap_or(network.output));
network.output = self.selected_nodes[0];
} else if let Some(output) = network.previous_output.take() {
network.output = output
}
Self::send_graph(network, responses);
}
self.update_selection_action_buttons(document, responses);
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
NodeGraphMessage::ShiftNode { node_id } => {
let Some(network) = self.get_active_network_mut(document) else{
warn!("No network");
Expand Down
47 changes: 26 additions & 21 deletions editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,30 @@ impl PortfolioMessageHandler {
self.document_ids.iter().position(|id| id == &document_id).expect("Active document is missing from document ids")
}

/// Execute the network by flattening it and creating a borrow stack. Casts the output to the generic `T`.
fn execute_network<T: dyn_any::StaticType>(mut network: NodeNetwork, image: Image) -> Result<T, String> {
for node_id in network.nodes.keys().copied().collect::<Vec<_>>() {
network.flatten(node_id);
}

let mut proto_network = network.into_proto_network();
proto_network.reorder_ids();

assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
let stack = borrow_stack::FixedSizeStack::new(proto_network.nodes.len());
for (_id, node) in proto_network.nodes {
interpreted_executor::node_registry::push_node(node, &stack);
}

use borrow_stack::BorrowStack;
use dyn_any::IntoDynAny;
use graphene_core::Node;

let boxed = unsafe { stack.get().last().unwrap().eval(image.into_dyn()) };

dyn_any::downcast::<T>(boxed).map(|v| *v)
}

/// Computes an input for a node in the graph
fn compute_input<T: dyn_any::StaticType>(old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, image: Cow<Image>) -> Result<T, String> {
let mut network = old_network.clone();
Expand Down Expand Up @@ -694,26 +718,7 @@ impl PortfolioMessageHandler {
}
}

let stack = borrow_stack::FixedSizeStack::new(256);
for node_id in old_network.nodes.keys() {
network.flatten(*node_id);
}

let mut proto_network = network.into_proto_network();
proto_network.reorder_ids();

assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
for (_id, node) in proto_network.nodes {
interpreted_executor::node_registry::push_node(node, &stack);
}

use borrow_stack::BorrowStack;
use dyn_any::IntoDynAny;
use graphene_core::Node;

let boxed = unsafe { stack.get().last().unwrap().eval(image.into_owned().into_dyn()) };

dyn_any::downcast::<T>(boxed).map(|v| *v)
Self::execute_network(network, image.into_owned())
}

/// Encodes an image into a format using the image crate
Expand Down Expand Up @@ -856,7 +861,7 @@ impl PortfolioMessageHandler {
.into(),
);
} else {
let mut image: Image = Self::compute_input(&network, &[1], 0, Cow::Owned(image))?;
let mut image: Image = Self::execute_network(network, image)?;

// If no image was generated, use the input image
if image.width == 0 || image.height == 0 {
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/tool/tool_messages/imaginate_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ impl Fsm for ImaginateToolFsmState {
)]
.into_iter()
.collect(),
..Default::default()
};
let mut imaginate_inputs: Vec<NodeInput> = imaginate_node_type.inputs.iter().map(|input| input.default.clone()).collect();
imaginate_inputs[0] = NodeInput::Node(0);
Expand Down Expand Up @@ -197,6 +198,7 @@ impl Fsm for ImaginateToolFsmState {
]
.into_iter()
.collect(),
..Default::default()
};

responses.push_back(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ impl Fsm for NodeGraphToolFsmState {
]
.into_iter()
.collect(),
..Default::default()
};

responses.push_back(
Expand Down
Loading