Skip to content

Commit 16dae0f

Browse files
0HyperCubeKeavon
andauthored
Add preview and disable buttons for nodes (#905)
* Add preview and disable button * Fix tests Co-authored-by: Keavon Chambers <[email protected]>
1 parent ae8b3b1 commit 16dae0f

File tree

10 files changed

+195
-48
lines changed

10 files changed

+195
-48
lines changed

editor/src/messages/layout/utility_types/layout_widget.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ pub enum LayoutGroup {
250250
#[serde(rename = "section")]
251251
Section { name: String, layout: SubLayout },
252252
}
253+
254+
impl Default for LayoutGroup {
255+
fn default() -> Self {
256+
Self::Row { widgets: Vec::new() }
257+
}
258+
}
259+
253260
impl LayoutGroup {
254261
/// Applies a tooltip to all widgets in this row or column without a tooltip.
255262
pub fn with_tooltip(self, tooltip: impl Into<String>) -> Self {

editor/src/messages/portfolio/document/node_graph/node_graph_message.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ pub enum NodeGraphMessage {
6767
input_index: usize,
6868
value: TaggedValue,
6969
},
70+
SetSelectedEnabled {
71+
enabled: bool,
72+
},
73+
SetSelectedOutput {
74+
output: bool,
75+
},
7076
ShiftNode {
7177
node_id: NodeId,
7278
},

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 108 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
2-
use crate::messages::layout::utility_types::widgets::button_widgets::BreadcrumbTrailButtons;
2+
use crate::messages::layout::utility_types::widgets::button_widgets::{BreadcrumbTrailButtons, TextButton};
33
use crate::messages::prelude::*;
44

55
use document_legacy::document::Document;
@@ -65,6 +65,8 @@ pub struct FrontendNode {
6565
pub exposed_inputs: Vec<NodeGraphInput>,
6666
pub outputs: Vec<FrontendGraphDataType>,
6767
pub position: (i32, i32),
68+
pub disabled: bool,
69+
pub output: bool,
6870
}
6971

7072
// (link_start, link_end, link_end_input_index)
@@ -92,11 +94,13 @@ impl FrontendNodeType {
9294
}
9395
}
9496

95-
#[derive(Debug, Clone, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize)]
97+
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
9698
pub struct NodeGraphMessageHandler {
9799
pub layer_path: Option<Vec<document_legacy::LayerId>>,
98100
pub nested_path: Vec<graph_craft::document::NodeId>,
99101
pub selected_nodes: Vec<graph_craft::document::NodeId>,
102+
#[serde(skip)]
103+
pub widgets: [LayoutGroup; 2],
100104
}
101105

102106
impl NodeGraphMessageHandler {
@@ -124,8 +128,20 @@ impl NodeGraphMessageHandler {
124128
network
125129
}
126130

131+
/// Send the cached layout for the bar at the top of the node panel to the frontend
132+
fn send_node_bar_layout(&self, responses: &mut VecDeque<Message>) {
133+
responses.push_back(
134+
LayoutMessage::SendLayout {
135+
layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())),
136+
layout_target: crate::messages::layout::utility_types::misc::LayoutTarget::NodeGraphBar,
137+
}
138+
.into(),
139+
);
140+
}
141+
127142
/// Collect the addresses of the currently viewed nested node e.g. Root -> MyFunFilter -> Exposure
128-
fn collect_nested_addresses(&self, document: &Document, responses: &mut VecDeque<Message>) {
143+
fn collect_nested_addresses(&mut self, document: &Document, responses: &mut VecDeque<Message>) {
144+
// Build path list
129145
let mut path = vec!["Root".to_string()];
130146
let mut network = self.get_root_network(document);
131147
for node_id in &self.nested_path {
@@ -137,24 +153,56 @@ impl NodeGraphMessageHandler {
137153
}
138154
let nesting = path.len();
139155

140-
responses.push_back(
141-
LayoutMessage::SendLayout {
142-
layout: Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
143-
widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons {
144-
labels: path,
145-
on_update: WidgetCallback::new(move |input: &u64| {
146-
NodeGraphMessage::ExitNestedNetwork {
147-
depth_of_nesting: nesting - (*input as usize) - 1,
148-
}
149-
.into()
150-
}),
156+
// Update UI
157+
self.widgets[0] = LayoutGroup::Row {
158+
widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons {
159+
labels: path.clone(),
160+
on_update: WidgetCallback::new(move |input: &u64| {
161+
NodeGraphMessage::ExitNestedNetwork {
162+
depth_of_nesting: nesting - (*input as usize) - 1,
163+
}
164+
.into()
165+
}),
166+
..Default::default()
167+
}))],
168+
};
169+
170+
self.send_node_bar_layout(responses);
171+
}
172+
173+
/// Updates the buttons for disable and preview
174+
fn update_selection_action_buttons(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
175+
if let Some(network) = self.get_active_network_mut(document) {
176+
let mut widgets = Vec::new();
177+
178+
// Show an enable or disable nodes button if there is a selection
179+
if !self.selected_nodes.is_empty() {
180+
let is_enabled = self.selected_nodes.iter().any(|id| !network.disabled.contains(id));
181+
let enable_button = WidgetHolder::new(Widget::TextButton(TextButton {
182+
label: if is_enabled { "Disable" } else { "Enable" }.to_string(),
183+
on_update: WidgetCallback::new(move |_| NodeGraphMessage::SetSelectedEnabled { enabled: !is_enabled }.into()),
184+
..Default::default()
185+
}));
186+
widgets.push(enable_button);
187+
}
188+
189+
// If only one node is selected then show the preview or stop previewing button
190+
if self.selected_nodes.len() == 1 {
191+
let is_output = network.output == self.selected_nodes[0];
192+
// Don't show stop previewing on the output node
193+
if !(is_output && network.previous_output.filter(|&id| id != self.selected_nodes[0]).is_none()) {
194+
let output_button = WidgetHolder::new(Widget::TextButton(TextButton {
195+
label: if is_output { "Stop Previewing" } else { "Preview" }.to_string(),
196+
on_update: WidgetCallback::new(move |_| NodeGraphMessage::SetSelectedOutput { output: !is_output }.into()),
151197
..Default::default()
152-
}))],
153-
}])),
154-
layout_target: crate::messages::layout::utility_types::misc::LayoutTarget::NodeGraphBar,
198+
}));
199+
widgets.push(output_button);
200+
}
155201
}
156-
.into(),
157-
);
202+
203+
self.widgets[1] = LayoutGroup::Row { widgets };
204+
}
205+
self.send_node_bar_layout(responses);
158206
}
159207

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

246-
/// Updates the frontend's selection state inline with the backend
247-
fn update_selected(&self, responses: &mut VecDeque<Message>) {
296+
/// Updates the frontend's selection state in line with the backend
297+
fn update_selected(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
298+
self.update_selection_action_buttons(document, responses);
248299
responses.push_back(
249300
FrontendMessage::UpdateNodeGraphSelection {
250301
selected: self.selected_nodes.clone(),
@@ -388,6 +439,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
388439
)]
389440
.into_iter()
390441
.collect(),
442+
..Default::default()
391443
};
392444

393445
network.nodes.insert(
@@ -413,6 +465,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
413465
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
414466
}
415467
}
468+
self.update_selected(document, responses);
416469
}
417470
NodeGraphMessage::DeleteSelectedNodes => {
418471
if let Some(network) = self.get_active_network_mut(document) {
@@ -425,6 +478,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
425478
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
426479
}
427480
}
481+
self.update_selected(document, responses);
428482
}
429483
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
430484
let Some(network) = self.get_active_network_mut(document) else {
@@ -443,7 +497,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
443497
Self::send_graph(network, responses);
444498
}
445499
NodeGraphMessage::DoubleClickNode { node } => {
446-
self.selected_nodes = Vec::new();
500+
self.selected_nodes.clear();
447501
if let Some(network) = self.get_active_network_mut(document) {
448502
if network.nodes.get(&node).and_then(|node| node.implementation.get_network()).is_some() {
449503
self.nested_path.push(node);
@@ -453,7 +507,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
453507
Self::send_graph(network, responses);
454508
}
455509
self.collect_nested_addresses(document, responses);
456-
self.update_selected(responses);
510+
self.update_selected(document, responses);
457511
}
458512
NodeGraphMessage::DuplicateSelectedNodes => {
459513
if let Some(network) = self.get_active_network_mut(document) {
@@ -476,18 +530,19 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
476530
}
477531
self.selected_nodes = new_selected;
478532
Self::send_graph(network, responses);
479-
self.update_selected(responses);
533+
self.update_selected(document, responses);
480534
}
481535
}
482536
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
483-
self.selected_nodes = Vec::new();
537+
self.selected_nodes.clear();
484538
for _ in 0..depth_of_nesting {
485539
self.nested_path.pop();
486540
}
487541
if let Some(network) = self.get_active_network_mut(document) {
488542
Self::send_graph(network, responses);
489543
}
490544
self.collect_nested_addresses(document, responses);
545+
self.update_selected(document, responses);
491546
}
492547
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
493548
let Some(network) = self.get_active_network_mut(document) else{
@@ -542,6 +597,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
542597
responses.push_back(FrontendMessage::UpdateNodeTypes { node_types }.into());
543598
}
544599
self.collect_nested_addresses(document, responses);
600+
self.update_selected(document, responses);
545601
}
546602
NodeGraphMessage::PasteNodes { serialized_nodes } => {
547603
let Some(network) = self.get_active_network_mut(document) else{
@@ -567,10 +623,11 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
567623
}
568624

569625
Self::send_graph(network, responses);
570-
self.update_selected(responses);
626+
self.update_selected(document, responses);
571627
}
572628
NodeGraphMessage::SelectNodes { nodes } => {
573629
self.selected_nodes = nodes;
630+
self.update_selection_action_buttons(document, responses);
574631
responses.push_back(PropertiesPanelMessage::ResendActiveProperties.into());
575632
}
576633
NodeGraphMessage::SetInputValue { node, input_index, value } => {
@@ -615,6 +672,31 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
615672
}
616673
}
617674
}
675+
NodeGraphMessage::SetSelectedEnabled { enabled } => {
676+
if let Some(network) = self.get_active_network_mut(document) {
677+
if enabled {
678+
network.disabled.retain(|id| !self.selected_nodes.contains(id));
679+
} else {
680+
network.disabled.extend(&self.selected_nodes);
681+
}
682+
Self::send_graph(network, responses);
683+
}
684+
self.update_selection_action_buttons(document, responses);
685+
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
686+
}
687+
NodeGraphMessage::SetSelectedOutput { output } => {
688+
if let Some(network) = self.get_active_network_mut(document) {
689+
if output {
690+
network.previous_output = Some(network.previous_output.unwrap_or(network.output));
691+
network.output = self.selected_nodes[0];
692+
} else if let Some(output) = network.previous_output.take() {
693+
network.output = output
694+
}
695+
Self::send_graph(network, responses);
696+
}
697+
self.update_selection_action_buttons(document, responses);
698+
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
699+
}
618700
NodeGraphMessage::ShiftNode { node_id } => {
619701
let Some(network) = self.get_active_network_mut(document) else{
620702
warn!("No network");

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,30 @@ impl PortfolioMessageHandler {
657657
self.document_ids.iter().position(|id| id == &document_id).expect("Active document is missing from document ids")
658658
}
659659

660+
/// Execute the network by flattening it and creating a borrow stack. Casts the output to the generic `T`.
661+
fn execute_network<T: dyn_any::StaticType>(mut network: NodeNetwork, image: Image) -> Result<T, String> {
662+
for node_id in network.nodes.keys().copied().collect::<Vec<_>>() {
663+
network.flatten(node_id);
664+
}
665+
666+
let mut proto_network = network.into_proto_network();
667+
proto_network.reorder_ids();
668+
669+
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
670+
let stack = borrow_stack::FixedSizeStack::new(proto_network.nodes.len());
671+
for (_id, node) in proto_network.nodes {
672+
interpreted_executor::node_registry::push_node(node, &stack);
673+
}
674+
675+
use borrow_stack::BorrowStack;
676+
use dyn_any::IntoDynAny;
677+
use graphene_core::Node;
678+
679+
let boxed = unsafe { stack.get().last().unwrap().eval(image.into_dyn()) };
680+
681+
dyn_any::downcast::<T>(boxed).map(|v| *v)
682+
}
683+
660684
/// Computes an input for a node in the graph
661685
fn compute_input<T: dyn_any::StaticType>(old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, image: Cow<Image>) -> Result<T, String> {
662686
let mut network = old_network.clone();
@@ -694,26 +718,7 @@ impl PortfolioMessageHandler {
694718
}
695719
}
696720

697-
let stack = borrow_stack::FixedSizeStack::new(256);
698-
for node_id in old_network.nodes.keys() {
699-
network.flatten(*node_id);
700-
}
701-
702-
let mut proto_network = network.into_proto_network();
703-
proto_network.reorder_ids();
704-
705-
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
706-
for (_id, node) in proto_network.nodes {
707-
interpreted_executor::node_registry::push_node(node, &stack);
708-
}
709-
710-
use borrow_stack::BorrowStack;
711-
use dyn_any::IntoDynAny;
712-
use graphene_core::Node;
713-
714-
let boxed = unsafe { stack.get().last().unwrap().eval(image.into_owned().into_dyn()) };
715-
716-
dyn_any::downcast::<T>(boxed).map(|v| *v)
721+
Self::execute_network(network, image.into_owned())
717722
}
718723

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

861866
// If no image was generated, use the input image
862867
if image.width == 0 || image.height == 0 {

editor/src/messages/tool/tool_messages/imaginate_tool.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ impl Fsm for ImaginateToolFsmState {
158158
)]
159159
.into_iter()
160160
.collect(),
161+
..Default::default()
161162
};
162163
let mut imaginate_inputs: Vec<NodeInput> = imaginate_node_type.inputs.iter().map(|input| input.default.clone()).collect();
163164
imaginate_inputs[0] = NodeInput::Node(0);
@@ -197,6 +198,7 @@ impl Fsm for ImaginateToolFsmState {
197198
]
198199
.into_iter()
199200
.collect(),
201+
..Default::default()
200202
};
201203

202204
responses.push_back(

editor/src/messages/tool/tool_messages/node_graph_frame_tool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ impl Fsm for NodeGraphToolFsmState {
163163
]
164164
.into_iter()
165165
.collect(),
166+
..Default::default()
166167
};
167168

168169
responses.push_back(

0 commit comments

Comments
 (0)