Improve context menu data

This commit is contained in:
Adam
2025-11-15 17:36:14 -08:00
parent 6dfb685d17
commit 84fe7739a8
4 changed files with 40 additions and 65 deletions

View File

@@ -776,8 +776,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}
let context_menu_data = if let Some(node_id) = clicked_id {
let currently_is_node = !network_interface.is_layer(&node_id, selection_network_path);
ContextMenuData::ToggleLayer { node_id, currently_is_node }
let currently_is_node = !network_interface.is_layer(&node_id, breadcrumb_network_path);
let can_be_layer = network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path);
ContextMenuData::ModifyNode {
can_be_layer,
currently_is_node,
node_id,
}
} else {
ContextMenuData::CreateNode { compatible_type: None }
};
@@ -2594,24 +2599,24 @@ impl NodeGraphMessageHandler {
}
fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option<NodeGraphError> {
let error = network_interface
let graph_error = network_interface
.resolved_types
.node_graph_errors
.iter()
.filter(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len())
.next()?;
let error_node = error.node_path[breadcrumb_network_path.len()];
let error = if graph_error.node_path.len() == breadcrumb_network_path.len() + 1 {
format!("{:?}", graph_error.error)
} else {
"Node graph type error within this node".to_string()
};
let error_node = graph_error.node_path[breadcrumb_network_path.len()];
let mut position = network_interface.position(&error_node, breadcrumb_network_path)?;
// Convert to graph space
position *= 24;
if network_interface.is_layer(&error_node, breadcrumb_network_path) {
position += IVec2::new(12, -12)
}
let error = if error.node_path.len() == breadcrumb_network_path.len() + 1 {
format!("{:?}", error.error)
} else {
"Node graph type error within this node".to_string()
};
Some(NodeGraphError { position: position.into(), error })
}

View File

@@ -153,16 +153,18 @@ pub struct BoxSelection {
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
#[serde(tag = "type", content = "data")]
pub enum ContextMenuData {
ToggleLayer {
#[serde(rename = "nodeId")]
node_id: NodeId,
ModifyNode {
#[serde(rename = "canBeLayer")]
can_be_layer: bool,
#[serde(rename = "currentlyIsNode")]
currently_is_node: bool,
#[serde(rename = "nodeId")]
node_id: NodeId,
},
CreateNode {
#[serde(rename = "compatibleType")]
#[serde(default)]
compatible_type: Option<String>,
},
}

View File

@@ -27,9 +27,6 @@
let graph: HTMLDivElement | undefined;
// Key value is node id + input/output index
// Imports/Export are stored at a key value of 0
$: gridSpacing = calculateGridSpacing($nodeGraph.transform.scale);
$: gridDotRadius = 1 + Math.floor($nodeGraph.transform.scale - 0.5 + 0.001) / 2;
@@ -115,15 +112,6 @@
return iconMap[icon] || "NodeNodes";
}
function toggleLayerDisplay(displayAsLayer: boolean, toggleId: bigint) {
let node = $nodeGraph.nodes.get(toggleId);
if (node) editor.handle.setToNodeOrLayer(node.id, displayAsLayer);
}
function canBeToggledBetweenNodeAndLayer(toggleDisplayAsLayerNodeId: bigint) {
return $nodeGraph.nodes.get(toggleDisplayAsLayerNodeId)?.canBeLayer || false;
}
function createNode(nodeType: string) {
if ($nodeGraph.contextMenuInformation === undefined) return;
@@ -176,24 +164,24 @@
return `M-2,-2 L${nodeWidth + 2},-2 L${nodeWidth + 2},${nodeHeight + 2} L-2,${nodeHeight + 2}z ${rectangles.join(" ")}`;
}
function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string {
return `Data Type: ${value.resolvedType}`;
}
// function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string {
// return `Data Type: ${value.resolvedType}`;
// }
// function validTypesText(value: FrontendGraphInput): string {
// const validTypes = value.validTypes.length > 0 ? value.validTypes.map((x) => `• ${x}`).join("\n") : "None";
// return `Valid Types:\n${validTypes}`;
// }
function outputConnectedToText(output: FrontendGraphOutput): string {
if (output.connectedTo.length === 0) return "Connected to nothing";
// function outputConnectedToText(output: FrontendGraphOutput): string {
// if (output.connectedTo.length === 0) return "Connected to nothing";
return `Connected to:\n${output.connectedTo.join("\n")}`;
}
// return `Connected to:\n${output.connectedTo.join("\n")}`;
// }
function inputConnectedToText(input: FrontendGraphInput): string {
return `Connected to:\n${input.connectedTo}`;
}
// function inputConnectedToText(input: FrontendGraphInput): string {
// return `Connected to:\n${input.connectedTo}`;
// }
function zipWithUndefined(arr1: FrontendGraphInput[], arr2: FrontendGraphOutput[]) {
const maxLength = Math.max(arr1.length, arr2.length);
@@ -224,29 +212,26 @@
top: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates.y * $nodeGraph.transform.scale + $nodeGraph.transform.y}px`,
}}
>
{#if typeof $nodeGraph.contextMenuInformation.contextMenuData === "string" && $nodeGraph.contextMenuInformation.contextMenuData === "CreateNode"}
<NodeCatalog on:selectNodeType={(e) => createNode(e.detail)} />
{:else if $nodeGraph.contextMenuInformation.contextMenuData && "compatibleType" in $nodeGraph.contextMenuInformation.contextMenuData}
<NodeCatalog initialSearchTerm={$nodeGraph.contextMenuInformation.contextMenuData.compatibleType || ""} on:selectNodeType={(e) => createNode(e.detail)} />
{:else}
{@const contextMenuData = $nodeGraph.contextMenuInformation.contextMenuData}
{#if $nodeGraph.contextMenuInformation.contextMenuData.type == "CreateNode"}
<NodeCatalog initialSearchTerm={$nodeGraph.contextMenuInformation.contextMenuData.data.compatibleType || ""} on:selectNodeType={(e) => createNode(e.detail)} />
{:else if $nodeGraph.contextMenuInformation.contextMenuData.type == "ModifyNode"}
<LayoutRow class="toggle-layer-or-node">
<TextLabel>Display as</TextLabel>
<RadioInput
selectedIndex={contextMenuData.currentlyIsNode ? 0 : 1}
selectedIndex={$nodeGraph.contextMenuInformation.contextMenuData.data.currentlyIsNode ? 0 : 1}
entries={[
{
value: "node",
label: "Node",
action: () => toggleLayerDisplay(false, contextMenuData.nodeId),
action: () => editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, false),
},
{
value: "layer",
label: "Layer",
action: () => toggleLayerDisplay(true, contextMenuData.nodeId),
action: () => editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, true),
},
]}
disabled={!canBeToggledBetweenNodeAndLayer(contextMenuData.nodeId)}
disabled={!$nodeGraph.contextMenuInformation.contextMenuData.data.canBeLayer}
/>
</LayoutRow>
<Separator type="Section" direction="Vertical" />
@@ -264,7 +249,6 @@
style={`left: ${$nodeGraph.error.position.x}px;
top: ${$nodeGraph.error.position.y}px;`}
transition:fade={FADE_TRANSITION}
title=""
data-node-error>{$nodeGraph.error.error}</span
>
<span
@@ -272,7 +256,6 @@
style={`left: ${$nodeGraph.error.position.x}px;
top: ${$nodeGraph.error.position.y}px;`}
transition:fade={FADE_TRANSITION}
title=""
data-node-error>{$nodeGraph.error.error}</span
>
</div>
@@ -338,7 +321,6 @@
style:--offset-left={($nodeGraph.updateImportsExports.importPosition.x - 8) / 24}
style:--offset-top={($nodeGraph.updateImportsExports.importPosition.y - 8) / 24 + index}
>
<title>{`${dataTypeTooltip(frontendOutput)}\n\n${outputConnectedToText(frontendOutput)}`}</title>
{#if frontendOutput.connectedTo.length > 0}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
{:else}
@@ -382,7 +364,7 @@
}}
/>
{#if index > 0}
<div class="reorder-drag-grip" title="Reorder this export" />
<div class="reorder-drag-grip" />
{/if}
{/if}
</div>
@@ -410,7 +392,6 @@
style:--offset-left={($nodeGraph.updateImportsExports.exportPosition.x - 8) / 24}
style:--offset-top={($nodeGraph.updateImportsExports.exportPosition.y - 8) / 24 + index}
>
<title>{`${dataTypeTooltip(frontendInput)}\n\n${inputConnectedToText(frontendInput)}`}</title>
{#if frontendInput.connectedTo !== "nothing"}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
{:else}
@@ -428,7 +409,7 @@
>
{#if (hoveringExportIndex === index || editingNameExportIndex === index) && $nodeGraph.updateImportsExports.addImportExport}
{#if index > 0}
<div class="reorder-drag-grip" title="Reorder this export" />
<div class="reorder-drag-grip" />
{/if}
<IconButton
size={16}

View File

@@ -33,20 +33,7 @@ export class UpdateClickTargets extends JsMessage {
readonly clickTargets!: FrontendClickTargets | undefined;
}
const ContextTupleToVec2 = Transform((data) => {
if (data.obj.contextMenuInformation === undefined) return undefined;
const contextMenuCoordinates = data.obj.contextMenuInformation.contextMenuCoordinates;
let contextMenuData = data.obj.contextMenuInformation.contextMenuData;
if (contextMenuData.ToggleLayer !== undefined) {
contextMenuData = { nodeId: contextMenuData.ToggleLayer.nodeId, currentlyIsNode: contextMenuData.ToggleLayer.currentlyIsNode };
} else if (contextMenuData.CreateNode !== undefined) {
contextMenuData = { type: "CreateNode", compatibleType: contextMenuData.CreateNode.compatibleType };
}
return { contextMenuCoordinates, contextMenuData };
});
export class UpdateContextMenuInformation extends JsMessage {
@ContextTupleToVec2
readonly contextMenuInformation!: ContextMenuInformation | undefined;
}
@@ -183,7 +170,7 @@ export type FrontendClickTargets = {
export type ContextMenuInformation = {
contextMenuCoordinates: XY;
contextMenuData: "CreateNode" | { type: "CreateNode"; compatibleType: string } | { nodeId: bigint; currentlyIsNode: boolean };
contextMenuData: { type: "CreateNode"; data: { compatibleType: string | undefined } } | { type: "ModifyNode"; data: { canBeLayer: boolean; currentlyIsNode: boolean; nodeId: bigint } };
};
export type FrontendGraphDataType = "General" | "Number" | "Artboard" | "Graphic" | "Raster" | "Vector" | "Color" | "Invalid";