Hook up layer tree structure with frontend (#372)

* Hook up layer tree structure with frontend (decoding and Vue are WIP)

* Fix off by one error

* Avoid leaking memory

* Parse layer structure into list of layers

* Fix thumbnail updates

* Correctly popagate deletions

* Fix selection state in layer tree

* Respect expansion during root serialization

* Allow expanding of subfolders

* Fix arrow direction

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Keavon Chambers 2021-09-11 17:15:51 -07:00
parent c5f44a8c1d
commit 225b46300d
19 changed files with 15777 additions and 336 deletions

View file

@ -18,8 +18,7 @@ export enum ResponseType {
ExportDocument = "ExportDocument",
SaveDocument = "SaveDocument",
OpenDocumentBrowse = "OpenDocumentBrowse",
ExpandFolder = "ExpandFolder",
CollapseFolder = "CollapseFolder",
DisplayFolderTreeStructure = "DisplayFolderTreeStructure",
UpdateLayer = "UpdateLayer",
SetActiveTool = "SetActiveTool",
SetActiveDocument = "SetActiveDocument",
@ -56,10 +55,8 @@ function parseResponse(responseType: string, data: any): Response {
switch (responseType) {
case "DocumentChanged":
return newDocumentChanged(data.DocumentChanged);
case "CollapseFolder":
return newCollapseFolder(data.CollapseFolder);
case "ExpandFolder":
return newExpandFolder(data.ExpandFolder);
case "DisplayFolderTreeStructure":
return newDisplayFolderTreeStructure(data.DisplayFolderTreeStructure);
case "SetActiveTool":
return newSetActiveTool(data.SetActiveTool);
case "SetActiveDocument":
@ -97,7 +94,7 @@ function parseResponse(responseType: string, data: any): Response {
}
}
export type Response = SetActiveTool | UpdateCanvas | UpdateScrollbars | DocumentChanged | CollapseFolder | ExpandFolder | UpdateWorkingColors | SetCanvasZoom | SetCanvasRotation;
export type Response = SetActiveTool | UpdateCanvas | UpdateScrollbars | UpdateLayer | DocumentChanged | DisplayFolderTreeStructure | UpdateWorkingColors | SetCanvasZoom | SetCanvasRotation;
export interface UpdateOpenDocumentsList {
open_documents: Array<string>;
@ -239,13 +236,61 @@ function newDocumentChanged(_: any): DocumentChanged {
return {};
}
export interface CollapseFolder {
path: BigUint64Array;
export interface DisplayFolderTreeStructure {
layerId: BigInt;
children: DisplayFolderTreeStructure[];
}
function newCollapseFolder(input: any): CollapseFolder {
return {
path: newPath(input.path),
};
function newDisplayFolderTreeStructure(input: any): DisplayFolderTreeStructure {
const { ptr, len } = input.data_buffer;
const wasmMemoryBuffer = (window as any).wasmMemory().buffer;
// Decode the folder structure encoding
const encoding = new DataView(wasmMemoryBuffer, ptr, len);
// 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, ptr + 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, ptr + 8 + structureSectionLength * 8);
let layersEncountered = 0;
let currentFolder: DisplayFolderTreeStructure = { 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(63);
// 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 = { 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);
// debugger;
// 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;
}
export interface UpdateLayer {
@ -259,17 +304,6 @@ function newUpdateLayer(input: any): UpdateLayer {
};
}
export interface ExpandFolder {
path: BigUint64Array;
children: Array<LayerPanelEntry>;
}
function newExpandFolder(input: any): ExpandFolder {
return {
path: newPath(input.path),
children: input.children.map((child: any) => newLayerPanelEntry(child)),
};
}
export interface SetCanvasZoom {
new_zoom: number;
}