Update graph UI and improve simplicity and robustness of sending graph and layer panel updates (#1564)

* WIP

* Fix loading the structure of layers

* Fix broken indents

* Remove debugging stuff

* Fix displaying errors and node graph UI fixes/improvements

* Fix compilation failure

---------

Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
Keavon Chambers
2024-01-13 04:15:36 -08:00
committed by GitHub
co-authored by 0hypercube
parent 83116aa744
commit aab0fcf84c
33 changed files with 836 additions and 813 deletions
+76 -12
View File
@@ -2,10 +2,11 @@
import { getContext, onMount, tick } from "svelte";
import { beginDraggingElement } from "@graphite/io-managers/drag";
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
import { platformIsMac } from "@graphite/utility-functions/platform";
import type { Editor } from "@graphite/wasm-communication/editor";
import { defaultWidgetLayout, patchWidgetLayout, UpdateDocumentLayerDetails, UpdateDocumentLayerStructureJs, UpdateLayersPanelOptionsLayout } from "@graphite/wasm-communication/messages";
import type { LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages";
import type { DataBuffer, LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages";
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
@@ -20,8 +21,6 @@
entry: LayerPanelEntry;
};
let list: LayoutCol | undefined;
const RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT = 20;
const INSERT_MARK_OFFSET = 2;
@@ -35,6 +34,9 @@
};
const editor = getContext<Editor>("editor");
const nodeGraph = getContext<NodeGraphState>("nodeGraph");
let list: LayoutCol | undefined;
// Layer data
let layerCache = new Map<string, LayerPanelEntry>(); // TODO: replace with BigUint64Array as index
@@ -56,7 +58,8 @@
});
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerStructureJs, (updateDocumentLayerStructure) => {
rebuildLayerHierarchy(updateDocumentLayerStructure);
const structure = newUpdateDocumentLayerStructure(updateDocumentLayerStructure.dataBuffer);
rebuildLayerHierarchy(structure);
});
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
@@ -67,6 +70,65 @@
});
});
type DocumentLayerStructure = {
layerId: bigint;
children: DocumentLayerStructure[];
};
function newUpdateDocumentLayerStructure(dataBuffer: DataBuffer): DocumentLayerStructure {
const pointerNum = Number(dataBuffer.pointer);
const lengthNum = Number(dataBuffer.length);
const wasmMemoryBuffer = editor.raw.buffer;
// Decode the folder structure encoding
const encoding = new DataView(wasmMemoryBuffer, pointerNum, lengthNum);
// The structure section indicates how to read through the upcoming layer list and assign depths to each layer
const structureSectionLength = Number(encoding.getBigUint64(0, true));
const structureSectionMsbSigned = new DataView(wasmMemoryBuffer, pointerNum + 8, structureSectionLength * 8);
// The layer IDs section lists each layer ID sequentially in the tree, as it will show up in the panel
const layerIdsSection = new DataView(wasmMemoryBuffer, pointerNum + 8 + structureSectionLength * 8);
let layersEncountered = 0;
let currentFolder: DocumentLayerStructure = { layerId: BigInt(-1), children: [] };
const currentFolderStack = [currentFolder];
for (let i = 0; i < structureSectionLength; i += 1) {
const msbSigned = structureSectionMsbSigned.getBigUint64(i * 8, true);
const msbMask = BigInt(1) << BigInt(64 - 1);
// Set the MSB to 0 to clear the sign and then read the number as usual
const numberOfLayersAtThisDepth = msbSigned & ~msbMask;
// Store child folders in the current folder (until we are interrupted by an indent)
for (let j = 0; j < numberOfLayersAtThisDepth; j += 1) {
const layerId = layerIdsSection.getBigUint64(layersEncountered * 8, true);
layersEncountered += 1;
const childLayer: DocumentLayerStructure = { layerId, children: [] };
currentFolder.children.push(childLayer);
}
// Check the sign of the MSB, where a 1 is a negative (outward) indent
const subsequentDirectionOfDepthChange = (msbSigned & msbMask) === BigInt(0);
// Inward
if (subsequentDirectionOfDepthChange) {
currentFolderStack.push(currentFolder);
currentFolder = currentFolder.children[currentFolder.children.length - 1];
}
// Outward
else {
const popped = currentFolderStack.pop();
if (!popped) throw Error("Too many negative indents in the folder structure");
if (popped) currentFolder = popped;
}
}
return currentFolder;
}
function toggleLayerVisibility(id: bigint) {
editor.instance.toggleLayerVisibility(id);
}
@@ -222,11 +284,11 @@
async function dragStart(event: DragEvent, listing: LayerListingInfo) {
const layer = listing.entry;
dragInPanel = true;
if (!layer.selected) {
if (!$nodeGraph.selected.includes(layer.id)) {
fakeHighlight = layer.id;
}
const select = () => {
if (!layer.selected) selectLayer(listing, false, false);
if (!$nodeGraph.selected.includes(layer.id)) selectLayer(listing, false, false);
};
const target = (event.target instanceof HTMLElement && event.target) || undefined;
@@ -263,7 +325,7 @@
dragInPanel = false;
}
function rebuildLayerHierarchy(updateDocumentLayerStructure: UpdateDocumentLayerStructureJs) {
function rebuildLayerHierarchy(updateDocumentLayerStructure: DocumentLayerStructure) {
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
const layerIdWithNameBeingEdited = layerWithNameBeingEdited?.entry.id;
@@ -271,7 +333,7 @@
layers = [];
// Build the new layer hierarchy
const recurse = (folder: UpdateDocumentLayerStructureJs) => {
const recurse = (folder: DocumentLayerStructure) => {
folder.children.forEach((item, index) => {
const mapping = layerCache.get(String(item.layerId));
if (mapping) {
@@ -313,7 +375,7 @@
<LayoutRow
class="layer"
classes={{
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : listing.entry.selected,
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : $nodeGraph.selected.includes(listing.entry.id),
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertParentId === listing.entry.id,
}}
styles={{ "--layer-indent-levels": `${listing.entry.depth - 1}` }}
@@ -333,7 +395,9 @@
{/if}
{:else}
<div class="thumbnail">
{@html listing.entry.thumbnail}
{#if $nodeGraph.thumbnails.has(listing.entry.id)}
{@html $nodeGraph.thumbnails.get(listing.entry.id)}
{/if}
</div>
{/if}
<LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}>
@@ -353,8 +417,8 @@
class={"visibility"}
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
size={24}
icon={(() => true)() ? "EyeVisible" : "EyeHidden"}
tooltip={(() => true)() ? "Visible" : "Hidden"}
icon={listing.entry.disabled ? "EyeHidden" : "EyeVisible"}
tooltip={listing.entry.disabled ? "Disabled" : "Enabled"}
/>
</LayoutRow>
{/each}