Skip to content

Commit cc0b5cd

Browse files
committed
Separate error popup from node
1 parent 548e0df commit cc0b5cd

File tree

6 files changed

+167
-94
lines changed

6 files changed

+167
-94
lines changed

editor/src/messages/frontend/frontend_message.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
22
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
33
use crate::messages::layout::utility_types::widget_prelude::*;
44
use crate::messages::portfolio::document::node_graph::utility_types::{
5-
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, Transform,
5+
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphError, Transform
66
};
77
use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer};
88
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
@@ -289,6 +289,9 @@ pub enum FrontendMessage {
289289
UpdateNodeGraphNodes {
290290
nodes: Vec<FrontendNode>,
291291
},
292+
UpdateNodeGraphError {
293+
error: Option<NodeGraphError>,
294+
},
292295
UpdateVisibleNodes {
293296
nodes: Vec<NodeId>,
294297
},

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

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
66
use crate::messages::portfolio::document::document_message_handler::navigation_controls;
77
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
88
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
9-
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
9+
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphError};
1010
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
1111
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
1212
use crate::messages::portfolio::document::utility_types::network_interface::{
@@ -793,10 +793,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
793793
DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x
794794
};
795795

796-
let context_menu_coordinates = ((node_graph_point.x + node_graph_shift.x) as i32, (node_graph_point.y + node_graph_shift.y) as i32);
797-
796+
let context_menu_coordinates = node_graph_point + node_graph_shift;
798797
self.context_menu = Some(ContextMenuInformation {
799-
context_menu_coordinates,
798+
context_menu_coordinates: context_menu_coordinates.into(),
800799
context_menu_data,
801800
});
802801

@@ -1220,9 +1219,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
12201219
let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x;
12211220

12221221
let compatible_type = network_interface.output_type(&output_connector, selection_network_path).add_node_string();
1222+
let context_menu_coordinates = point + node_graph_shift;
12231223

12241224
self.context_menu = Some(ContextMenuInformation {
1225-
context_menu_coordinates: ((point.x + node_graph_shift.x) as i32, (point.y + node_graph_shift.y) as i32),
1225+
context_menu_coordinates: context_menu_coordinates.into(),
12261226
context_menu_data: ContextMenuData::CreateNode { compatible_type },
12271227
});
12281228

@@ -1646,6 +1646,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
16461646
responses.add(FrontendMessage::UpdateNodeGraphNodes { nodes });
16471647
responses.add(NodeGraphMessage::UpdateVisibleNodes);
16481648

1649+
let error = self.node_graph_error(network_interface, breadcrumb_network_path);
1650+
responses.add(FrontendMessage::UpdateNodeGraphError { error });
16491651
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path);
16501652

16511653
responses.add(NodeGraphMessage::UpdateImportsExports);
@@ -2509,8 +2511,6 @@ impl NodeGraphMessageHandler {
25092511
};
25102512
let mut nodes = Vec::new();
25112513
for (node_id, visible) in network.nodes.iter().map(|(node_id, node)| (*node_id, node.visible)).collect::<Vec<_>>() {
2512-
let node_id_path = [breadcrumb_network_path, &[node_id]].concat();
2513-
25142514
let primary_input_connector = InputConnector::node(node_id, 0);
25152515

25162516
let primary_input = if network_interface
@@ -2552,20 +2552,6 @@ impl NodeGraphMessageHandler {
25522552

25532553
let locked = network_interface.is_locked(&node_id, breadcrumb_network_path);
25542554

2555-
let errors = network_interface
2556-
.resolved_types
2557-
.node_graph_errors
2558-
.iter()
2559-
.find(|error| error.node_path == node_id_path)
2560-
.map(|error| format!("{:?}", error.error.clone()))
2561-
.or_else(|| {
2562-
if network_interface.resolved_types.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
2563-
Some("Node graph type error within this node".to_string())
2564-
} else {
2565-
None
2566-
}
2567-
});
2568-
25692555
nodes.push(FrontendNode {
25702556
id: node_id,
25712557
is_layer: network_interface
@@ -2584,7 +2570,6 @@ impl NodeGraphMessageHandler {
25842570
previewed,
25852571
visible,
25862572
locked,
2587-
errors,
25882573
});
25892574
}
25902575

@@ -2606,6 +2591,28 @@ impl NodeGraphMessageHandler {
26062591
Some(subgraph_names)
26072592
}
26082593

2594+
fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option<NodeGraphError> {
2595+
let error = network_interface
2596+
.resolved_types
2597+
.node_graph_errors
2598+
.iter()
2599+
.filter(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len())
2600+
.next()?;
2601+
let error_node = error.node_path[breadcrumb_network_path.len()];
2602+
let error = if error.node_path.len() == breadcrumb_network_path.len() + 1 {
2603+
format!("{:?}", error.error)
2604+
} else {
2605+
"Node graph type error within this node".to_string()
2606+
};
2607+
let mut position = network_interface.position(&error_node, breadcrumb_network_path)?;
2608+
// Convert to graph space
2609+
position *= 24;
2610+
if network_interface.is_layer(&error_node, breadcrumb_network_path) {
2611+
position += IVec2::new(12, -12)
2612+
}
2613+
Some(NodeGraphError { position: position.into(), error })
2614+
}
2615+
26092616
fn update_layer_panel(network_interface: &NodeNetworkInterface, selection_network_path: &[NodeId], collapsed: &CollapsedLayers, layers_panel_open: bool, responses: &mut VecDeque<Message>) {
26102617
if !layers_panel_open {
26112618
return;

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

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use glam::IVec2;
1+
use glam::{DVec2, IVec2};
22
use graph_craft::document::NodeId;
33
use graph_craft::document::value::TaggedValue;
44
use graphene_std::Type;
@@ -98,7 +98,6 @@ pub struct FrontendNode {
9898
pub visible: bool,
9999
pub locked: bool,
100100
pub previewed: bool,
101-
pub errors: Option<String>,
102101
}
103102

104103
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
@@ -172,11 +171,17 @@ pub enum ContextMenuData {
172171
pub struct ContextMenuInformation {
173172
// Stores whether the context menu is open and its position in graph coordinates
174173
#[serde(rename = "contextMenuCoordinates")]
175-
pub context_menu_coordinates: (i32, i32),
174+
pub context_menu_coordinates: FrontendXY,
176175
#[serde(rename = "contextMenuData")]
177176
pub context_menu_data: ContextMenuData,
178177
}
179178

179+
#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
180+
pub struct NodeGraphError {
181+
pub position: FrontendXY,
182+
pub error: String,
183+
}
184+
180185
#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
181186
pub struct FrontendClickTargets {
182187
#[serde(rename = "nodeClickTargets")]
@@ -200,3 +205,22 @@ pub enum Direction {
200205
Left,
201206
Right,
202207
}
208+
209+
/// Stores node graph coordinates which are then transformed in svelte based on the node graph transform
210+
#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
211+
pub struct FrontendXY {
212+
pub x: i32,
213+
pub y: i32,
214+
}
215+
216+
impl From<DVec2> for FrontendXY {
217+
fn from(v: DVec2) -> Self {
218+
FrontendXY { x: v.x as i32, y: v.y as i32 }
219+
}
220+
}
221+
222+
impl From<IVec2> for FrontendXY {
223+
fn from(v: IVec2) -> Self {
224+
FrontendXY { x: v.x as i32, y: v.y as i32 }
225+
}
226+
}

frontend/src/components/views/Graph.svelte

Lines changed: 87 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,27 @@
257257
</LayoutCol>
258258
{/if}
259259

260+
{#if $nodeGraph.error}
261+
<div class="node-error-container" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}>
262+
<span
263+
class="node-error faded"
264+
style={`left: ${$nodeGraph.error.position.x}px;
265+
top: ${$nodeGraph.error.position.y}px;`}
266+
transition:fade={FADE_TRANSITION}
267+
title=""
268+
data-node-error>{$nodeGraph.error.error}</span
269+
>
270+
<span
271+
class="node-error hover"
272+
style={`left: ${$nodeGraph.error.position.x}px;
273+
top: ${$nodeGraph.error.position.y}px;`}
274+
transition:fade={FADE_TRANSITION}
275+
title=""
276+
data-node-error>{$nodeGraph.error.error}</span
277+
>
278+
</div>
279+
{/if}
280+
260281
<!-- Click target debug visualizations -->
261282
{#if $nodeGraph.clickTargets}
262283
<div class="click-targets" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}>
@@ -508,10 +529,6 @@
508529
title={`${node.displayName}\n\n${description || ""}`.trim() + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")}
509530
data-node={node.id}
510531
>
511-
{#if node.errors}
512-
<span class="node-error faded" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
513-
<span class="node-error hover" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
514-
{/if}
515532
<div class="thumbnail">
516533
{#if $nodeGraph.thumbnails.has(node.id)}
517534
{@html $nodeGraph.thumbnails.get(node.id)}
@@ -775,7 +792,6 @@
775792
</div>
776793

777794
<!-- Box selection widget -->
778-
<!-- TODO: Make its initial corner stay put (in graph space) when panning around -->
779795
{#if $nodeGraph.box}
780796
<div
781797
class="box-selection"
@@ -837,6 +853,72 @@
837853
}
838854
}
839855
856+
.node-error-container {
857+
position: absolute;
858+
z-index: 1;
859+
860+
.node-error {
861+
position: absolute;
862+
width: max-content;
863+
white-space: pre-wrap;
864+
max-width: 600px;
865+
line-height: 18px;
866+
color: var(--color-2-mildblack);
867+
background: var(--color-error-red);
868+
padding: 8px;
869+
border-radius: 4px;
870+
transition: opacity 0.2s;
871+
opacity: 0.5;
872+
transform: translateY(-100%);
873+
874+
// Tail
875+
&::after {
876+
content: "";
877+
position: absolute;
878+
left: 6px;
879+
bottom: -8px;
880+
width: 0;
881+
height: 0;
882+
border-style: solid;
883+
border-width: 8px 6px 0 6px;
884+
border-color: var(--color-error-red) transparent transparent transparent;
885+
}
886+
887+
&.hover {
888+
opacity: 0;
889+
z-index: 1;
890+
pointer-events: none;
891+
}
892+
893+
&.faded:hover + .hover {
894+
opacity: 1;
895+
}
896+
897+
&.faded:hover {
898+
z-index: 2;
899+
opacity: 1;
900+
-webkit-user-select: text;
901+
user-select: text;
902+
transition:
903+
opacity 0.2s,
904+
z-index 0s 0.2s;
905+
906+
&::selection {
907+
background-color: var(--color-e-nearwhite);
908+
909+
// Target only Safari
910+
@supports (background: -webkit-named-image(i)) {
911+
& {
912+
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
913+
// https://stackoverflow.com/a/71753552/775283
914+
background-color: rgba(var(--color-e-nearwhite-rgb), calc(254 / 255));
915+
}
916+
}
917+
}
918+
}
919+
}
920+
}
921+
840922
.click-targets {
841923
position: absolute;
842924
pointer-events: none;
@@ -1016,68 +1098,6 @@
10161098
// backdrop-filter: blur(4px);
10171099
background: rgba(var(--color-0-black-rgb), 0.33);
10181100
1019-
.node-error {
1020-
position: absolute;
1021-
width: max-content;
1022-
white-space: pre-wrap;
1023-
max-width: 600px;
1024-
line-height: 18px;
1025-
color: var(--color-2-mildblack);
1026-
background: var(--color-error-red);
1027-
padding: 8px;
1028-
border-radius: 4px;
1029-
bottom: calc(100% + 12px);
1030-
z-index: -1;
1031-
transition: opacity 0.2s;
1032-
opacity: 0.5;
1033-
1034-
// Tail
1035-
&::after {
1036-
content: "";
1037-
position: absolute;
1038-
left: 6px;
1039-
bottom: -8px;
1040-
width: 0;
1041-
height: 0;
1042-
border-style: solid;
1043-
border-width: 8px 6px 0 6px;
1044-
border-color: var(--color-error-red) transparent transparent transparent;
1045-
}
1046-
1047-
&.hover {
1048-
opacity: 0;
1049-
z-index: 1;
1050-
pointer-events: none;
1051-
}
1052-
1053-
&.faded:hover + .hover {
1054-
opacity: 1;
1055-
}
1056-
1057-
&.faded:hover {
1058-
z-index: 2;
1059-
opacity: 1;
1060-
-webkit-user-select: text;
1061-
user-select: text;
1062-
transition:
1063-
opacity 0.2s,
1064-
z-index 0s 0.2s;
1065-
1066-
&::selection {
1067-
background-color: var(--color-e-nearwhite);
1068-
1069-
// Target only Safari
1070-
@supports (background: -webkit-named-image(i)) {
1071-
& {
1072-
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
1073-
// https://stackoverflow.com/a/71753552/775283
1074-
background-color: rgba(var(--color-e-nearwhite-rgb), calc(254 / 255));
1075-
}
1076-
}
1077-
}
1078-
}
1079-
}
1080-
10811101
&::after {
10821102
content: "";
10831103
position: absolute;

0 commit comments

Comments
 (0)