Skip to content

Node 'Disable' and 'Preview' UX improvements #918

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 5 commits into from
Dec 28, 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
1 change: 1 addition & 0 deletions editor/src/messages/input_mapper/default_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub fn default_mapping() -> Mapping {
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut),
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy),
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes),
entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=NodeGraphMessage::ToggleHidden),
//
// TransformLayerMessage
entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,11 @@ pub enum NodeGraphMessage {
input_index: usize,
value: TaggedValue,
},
SetSelectedEnabled {
enabled: bool,
},
SetSelectedOutput {
output: bool,
},
ShiftNode {
node_id: NodeId,
},
ToggleHidden,
TogglePreview {
node_id: NodeId,
},
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
use crate::messages::layout::utility_types::widgets::button_widgets::{BreadcrumbTrailButtons, TextButton};
use crate::messages::prelude::*;
Expand Down Expand Up @@ -175,25 +176,40 @@ impl NodeGraphMessageHandler {
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()),
// Don't allow disabling input or output nodes
let mut selected_nodes = self.selected_nodes.iter().filter(|&&id| !network.inputs.contains(&id) && network.original_output() != id);

// If there is at least one other selected node then show the hide or show button
if selected_nodes.next().is_some() {
// Check if any of the selected nodes are disabled
let is_hidden = self.selected_nodes.iter().any(|id| network.disabled.contains(id));

// Check if multiple nodes are selected
let mutliple_nodes = selected_nodes.next().is_some();

// Generate the enable or disable button accordingly
let hide_button = WidgetHolder::new(Widget::TextButton(TextButton {
label: if is_hidden { "Show" } else { "Hide" }.to_string(),
tooltip: if is_hidden { "Show node" } else { "Hide node" }.to_string() + if mutliple_nodes { "s" } else { "" },
tooltip_shortcut: action_keys!(NodeGraphMessageDiscriminant::ToggleHidden),
on_update: WidgetCallback::new(move |_| NodeGraphMessage::ToggleHidden.into()),
..Default::default()
}));
widgets.push(enable_button);
widgets.push(hide_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
let node_id = self.selected_nodes[0];
// Is this node the current output
let is_output = network.output == node_id;

// Don't show stop previewing button on the origional 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()),
label: if is_output { "End Preview" } else { "Preview" }.to_string(),
tooltip: if is_output { "Restore preview to Output node" } else { "Preview node" }.to_string() + " (shortcut: Alt+click node)",
on_update: WidgetCallback::new(move |_| NodeGraphMessage::TogglePreview { node_id }.into()),
..Default::default()
}));
widgets.push(output_button);
Expand Down Expand Up @@ -675,31 +691,6 @@ 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 Expand Up @@ -747,12 +738,42 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
}
Self::send_graph(network, responses);
}
NodeGraphMessage::ToggleHidden => {
if let Some(network) = self.get_active_network_mut(document) {
// Check if any of the selected nodes are hidden
if self.selected_nodes.iter().any(|id| network.disabled.contains(id)) {
// Remove all selected nodes from the disabled list
network.disabled.retain(|id| !self.selected_nodes.contains(id));
} else {
let original_output = network.original_output();
// Add all selected nodes to the disabled list (excluding input or output nodes)
network.disabled.extend(self.selected_nodes.iter().filter(|&id| !network.inputs.contains(id) && original_output != *id));
}
Self::send_graph(network, responses);
}
self.update_selection_action_buttons(document, responses);
responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
NodeGraphMessage::TogglePreview { node_id } => {
if let Some(network) = self.get_active_network_mut(document) {
// Check if the node is not already
if network.output != node_id {
network.previous_output = Some(network.previous_output.unwrap_or(network.output));
network.output = node_id;
} 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());
}
}
}

fn actions(&self) -> ActionList {
if self.layer_path.is_some() && !self.selected_nodes.is_empty() {
actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes)
actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes, ToggleHidden)
} else {
actions!(NodeGraphMessageDiscriminant;)
}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/components/panels/NodeGraph.vue
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,10 @@ export default defineComponent({
},
// TODO: Move the event listener from the graph to the window so dragging outside the graph area (or even the browser window) works
pointerDown(e: PointerEvent) {
// Exit the add node popup by clicking elsewhere in the graph
if (this.nodeListLocation && !(e.target as HTMLElement).closest("[data-node-list]")) this.nodeListLocation = undefined;

// Handle the add node popup on right click
if (e.button === 2) {
const graphDiv: HTMLDivElement | undefined = (this.$refs.graph as typeof LayoutCol | undefined)?.$el;
const graph = graphDiv?.getBoundingClientRect() || new DOMRect();
Expand All @@ -558,6 +560,10 @@ export default defineComponent({
// If the user is clicking on the add nodes list, exit here
if (nodeList) return;

if (e.altKey && nodeId) {
this.editor.instance.togglePreview(BigInt(nodeId));
}

// Clicked on a port dot
if (port && node) {
const isOutput = Boolean(port.getAttribute("data-port") === "output");
Expand Down
7 changes: 7 additions & 0 deletions frontend/wasm/src/editor_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,13 @@ impl JsEditorHandle {
self.dispatch(message);
}

/// Toggle preview on node
#[wasm_bindgen(js_name = togglePreview)]
pub fn toggle_preview(&self, node_id: NodeId) {
let message = NodeGraphMessage::TogglePreview { node_id };
self.dispatch(message);
}

/// Pastes an image
#[wasm_bindgen(js_name = pasteImage)]
pub fn paste_image(&self, mime: String, image_data: Vec<u8>, mouse_x: Option<f64>, mouse_y: Option<f64>) {
Expand Down
5 changes: 5 additions & 0 deletions node-graph/graph-craft/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ impl NodeNetwork {
nodes,
}
}

/// Get the original output node of this network, ignoring any preview node
pub fn original_output(&self) -> NodeId {
self.previous_output.unwrap_or(self.output)
}
}

#[cfg(test)]
Expand Down