Simplify the Layers panel tree structure Rust -> JS encoding (#3744)
* replace custom layer structure encoding with simple JSON tree * add leftover files * Renames --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
bb6fea95e4
commit
9ae13634d0
|
|
@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::{
|
use crate::messages::portfolio::document::node_graph::utility_types::{
|
||||||
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform,
|
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform,
|
||||||
};
|
};
|
||||||
use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer};
|
use crate::messages::portfolio::document::utility_types::nodes::{LayerPanelEntry, LayerStructureEntry};
|
||||||
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
|
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
|
|
@ -235,12 +235,8 @@ pub enum FrontendMessage {
|
||||||
data: LayerPanelEntry,
|
data: LayerPanelEntry,
|
||||||
},
|
},
|
||||||
UpdateDocumentLayerStructure {
|
UpdateDocumentLayerStructure {
|
||||||
#[serde(rename = "dataBuffer")]
|
#[serde(rename = "layerStructure")]
|
||||||
data_buffer: RawBuffer,
|
layer_structure: Vec<LayerStructureEntry>,
|
||||||
},
|
|
||||||
UpdateDocumentLayerStructureJs {
|
|
||||||
#[serde(rename = "dataBuffer")]
|
|
||||||
data_buffer: JsRawBuffer,
|
|
||||||
},
|
},
|
||||||
UpdateDocumentRulers {
|
UpdateDocumentRulers {
|
||||||
origin: (f64, f64),
|
origin: (f64, f64),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use super::node_graph::utility_types::Transform;
|
||||||
use super::utility_types::error::EditorError;
|
use super::utility_types::error::EditorError;
|
||||||
use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState};
|
use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState};
|
||||||
use super::utility_types::network_interface::{self, NodeNetworkInterface, TransactionStatus};
|
use super::utility_types::network_interface::{self, NodeNetworkInterface, TransactionStatus};
|
||||||
use super::utility_types::nodes::{CollapsedLayers, SelectedNodes};
|
use super::utility_types::nodes::{CollapsedLayers, LayerStructureEntry, SelectedNodes};
|
||||||
use crate::application::{GRAPHITE_GIT_COMMIT_HASH, generate_uuid};
|
use crate::application::{GRAPHITE_GIT_COMMIT_HASH, generate_uuid};
|
||||||
use crate::consts::{ASYMPTOTIC_EFFECT, COLOR_OVERLAY_GRAY, DEFAULT_DOCUMENT_NAME, FILE_EXTENSION, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
|
use crate::consts::{ASYMPTOTIC_EFFECT, COLOR_OVERLAY_GRAY, DEFAULT_DOCUMENT_NAME, FILE_EXTENSION, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL};
|
||||||
use crate::messages::input_mapper::utility_types::macros::action_shortcut;
|
use crate::messages::input_mapper::utility_types::macros::action_shortcut;
|
||||||
|
|
@ -19,7 +19,6 @@ use crate::messages::portfolio::document::properties_panel::properties_panel_mes
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, PTZ};
|
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, PTZ};
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate};
|
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate};
|
||||||
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
|
|
||||||
use crate::messages::portfolio::utility_types::{PanelType, PersistentData};
|
use crate::messages::portfolio::utility_types::{PanelType, PersistentData};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity};
|
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity};
|
||||||
|
|
@ -317,8 +316,8 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
DocumentMessage::ClearLayersPanel => {
|
DocumentMessage::ClearLayersPanel => {
|
||||||
// Send an empty layer list
|
// Send an empty layer list
|
||||||
if layers_panel_open {
|
if layers_panel_open {
|
||||||
let data_buffer: RawBuffer = Self::default().serialize_root();
|
let layer_structure = Self::default().build_layer_structure(LayerNodeIdentifier::ROOT_PARENT);
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { layer_structure });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the control bar
|
// Clear the control bar
|
||||||
|
|
@ -380,12 +379,12 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
DocumentMessage::DocumentStructureChanged => {
|
DocumentMessage::DocumentStructureChanged => {
|
||||||
if layers_panel_open {
|
if layers_panel_open {
|
||||||
self.network_interface.load_structure();
|
self.network_interface.load_structure();
|
||||||
let data_buffer: RawBuffer = self.serialize_root();
|
let layer_structure = self.build_layer_structure(LayerNodeIdentifier::ROOT_PARENT);
|
||||||
|
|
||||||
self.update_layers_panel_control_bar_widgets(layers_panel_open, responses);
|
self.update_layers_panel_control_bar_widgets(layers_panel_open, responses);
|
||||||
self.update_layers_panel_bottom_bar_widgets(layers_panel_open, responses);
|
self.update_layers_panel_bottom_bar_widgets(layers_panel_open, responses);
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { layer_structure });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentMessage::DrawArtboardOverlays { context: overlay_context } => {
|
DocumentMessage::DrawArtboardOverlays { context: overlay_context } => {
|
||||||
|
|
@ -1891,70 +1890,22 @@ impl DocumentMessageHandler {
|
||||||
Ok(document_message_handler)
|
Ok(document_message_handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called recursively by the entry function [`serialize_root`].
|
/// Recursively builds the layer structure tree for a folder.
|
||||||
fn serialize_structure(&self, folder: LayerNodeIdentifier, structure_section: &mut Vec<u64>, data_section: &mut Vec<u64>, path: &mut Vec<LayerNodeIdentifier>) {
|
fn build_layer_structure(&self, folder: LayerNodeIdentifier) -> Vec<LayerStructureEntry> {
|
||||||
let mut space = 0;
|
folder
|
||||||
for layer_node in folder.children(self.metadata()) {
|
.children(self.metadata())
|
||||||
data_section.push(layer_node.to_node().0);
|
.map(|layer_node| {
|
||||||
space += 1;
|
let children = if layer_node.has_children(self.metadata()) && !self.collapsed.0.contains(&layer_node) {
|
||||||
if layer_node.has_children(self.metadata()) && !self.collapsed.0.contains(&layer_node) {
|
self.build_layer_structure(layer_node)
|
||||||
path.push(layer_node);
|
} else {
|
||||||
|
Vec::new()
|
||||||
// TODO: Skip if folder is not expanded.
|
};
|
||||||
structure_section.push(space);
|
LayerStructureEntry {
|
||||||
self.serialize_structure(layer_node, structure_section, data_section, path);
|
layer_id: layer_node.to_node(),
|
||||||
space = 0;
|
children,
|
||||||
|
}
|
||||||
path.pop();
|
})
|
||||||
}
|
.collect()
|
||||||
}
|
|
||||||
structure_section.push(space | (1 << 63));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializes the layer structure into a condensed 1D structure.
|
|
||||||
///
|
|
||||||
/// # Format
|
|
||||||
/// It is a string of numbers broken into three sections:
|
|
||||||
///
|
|
||||||
/// | Data | Description | Length |
|
|
||||||
/// |------------------------------------------------------------------------------------------------------------------------------ |---------------------------------------------------------------|------------------|
|
|
||||||
/// | `4,` `2, 1, -2, -0,` `16533113728871998040,3427872634365736244,18115028555707261608,15878401910454357952,449479075714955186` | Encoded example data | |
|
|
||||||
/// | _____________________________________________________________________________________________________________________________ | _____________________________________________________________ | ________________ |
|
|
||||||
/// | **Length** section: `4` | Length of the **Structure** section (`L` = `structure.len()`) | First value |
|
|
||||||
/// | **Structure** section: `2, 1, -2, -0` | The **Structure** section | Next `L` values |
|
|
||||||
/// | **Data** section: `16533113728871998040, 3427872634365736244, 18115028555707261608, 15878401910454357952, 449479075714955186` | The **Data** section (layer IDs) | Remaining values |
|
|
||||||
///
|
|
||||||
/// The data section lists the layer IDs for all folders/layers in the tree as read from top to bottom.
|
|
||||||
/// The structure section lists signed numbers. The sign indicates a folder indentation change (`+` is down a level, `-` is up a level).
|
|
||||||
/// The numbers in the structure block encode the indentation. For example:
|
|
||||||
/// - `2` means read two elements from the data section, then place a `[`.
|
|
||||||
/// - `-x` means read `x` elements from the data section and then insert a `]`.
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// 2 V 1 V -2 A -0 A
|
|
||||||
/// 16533113728871998040,3427872634365736244, 18115028555707261608, 15878401910454357952,449479075714955186
|
|
||||||
/// 16533113728871998040,3427872634365736244,[ 18115028555707261608,[15878401910454357952,449479075714955186] ]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Resulting layer panel:
|
|
||||||
/// ```text
|
|
||||||
/// 16533113728871998040
|
|
||||||
/// 3427872634365736244
|
|
||||||
/// [3427872634365736244,18115028555707261608]
|
|
||||||
/// [3427872634365736244,18115028555707261608,15878401910454357952]
|
|
||||||
/// [3427872634365736244,18115028555707261608,449479075714955186]
|
|
||||||
/// ```
|
|
||||||
pub fn serialize_root(&self) -> RawBuffer {
|
|
||||||
let mut structure_section = vec![NodeId(0).0];
|
|
||||||
let mut data_section = Vec::new();
|
|
||||||
self.serialize_structure(LayerNodeIdentifier::ROOT_PARENT, &mut structure_section, &mut data_section, &mut vec![]);
|
|
||||||
|
|
||||||
// Remove the ROOT element. Prepend `L`, the length (excluding the ROOT) of the structure section (which happens to be where the ROOT element was).
|
|
||||||
structure_section[0] = structure_section.len() as u64 - 1;
|
|
||||||
// Append the data section to the end.
|
|
||||||
structure_section.extend(data_section);
|
|
||||||
|
|
||||||
structure_section.as_slice().into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo_with_history(&mut self, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) {
|
pub fn undo_with_history(&mut self, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) {
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,14 @@ use super::network_interface::NodeNetworkInterface;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use graph_craft::document::{NodeId, NodeNetwork};
|
use graph_craft::document::{NodeId, NodeNetwork};
|
||||||
use serde::ser::SerializeStruct;
|
|
||||||
|
|
||||||
|
/// Represents an entry in the layer tree hierarchy, sent to the frontend.
|
||||||
|
/// Each entry contains its layer ID and a list of its visible children.
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||||
pub struct RawBuffer(Vec<u8>);
|
pub struct LayerStructureEntry {
|
||||||
|
#[serde(rename = "layerId")]
|
||||||
impl From<&[u64]> for RawBuffer {
|
pub layer_id: NodeId,
|
||||||
fn from(iter: &[u64]) -> Self {
|
pub children: Vec<LayerStructureEntry>,
|
||||||
let v_from_raw: Vec<u8> = iter.iter().flat_map(|x| x.to_ne_bytes()).collect();
|
|
||||||
Self(v_from_raw)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
|
||||||
pub struct JsRawBuffer(Vec<u8>);
|
|
||||||
|
|
||||||
impl From<RawBuffer> for JsRawBuffer {
|
|
||||||
fn from(buffer: RawBuffer) -> Self {
|
|
||||||
Self(buffer.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl serde::Serialize for JsRawBuffer {
|
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
||||||
let mut buffer = serializer.serialize_struct("Buffer", 2)?;
|
|
||||||
buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?;
|
|
||||||
buffer.serialize_field("length", &(self.0.len()))?;
|
|
||||||
buffer.end()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
import {
|
import {
|
||||||
patchLayout,
|
patchLayout,
|
||||||
UpdateDocumentLayerDetails,
|
UpdateDocumentLayerDetails,
|
||||||
UpdateDocumentLayerStructureJs,
|
UpdateDocumentLayerStructure,
|
||||||
UpdateLayersPanelControlBarLeftLayout,
|
UpdateLayersPanelControlBarLeftLayout,
|
||||||
UpdateLayersPanelControlBarRightLayout,
|
UpdateLayersPanelControlBarRightLayout,
|
||||||
UpdateLayersPanelBottomBarLayout,
|
UpdateLayersPanelBottomBarLayout,
|
||||||
} from "@graphite/messages";
|
} from "@graphite/messages";
|
||||||
import type { DataBuffer, LayerPanelEntry, Layout } from "@graphite/messages";
|
import type { LayerPanelEntry, LayerStructureEntry, Layout } from "@graphite/messages";
|
||||||
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
||||||
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
||||||
import { pasteFile } from "@graphite/utility-functions/files";
|
import { pasteFile } from "@graphite/utility-functions/files";
|
||||||
|
|
@ -91,9 +91,8 @@
|
||||||
layersPanelBottomBarLayout = layersPanelBottomBarLayout;
|
layersPanelBottomBarLayout = layersPanelBottomBarLayout;
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerStructureJs, (data) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerStructure, (data) => {
|
||||||
const structure = newUpdateDocumentLayerStructure(data.dataBuffer);
|
rebuildLayerHierarchy(data.layerStructure);
|
||||||
rebuildLayerHierarchy(structure);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (data) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (data) => {
|
||||||
|
|
@ -117,7 +116,7 @@
|
||||||
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelControlBarLeftLayout);
|
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelControlBarLeftLayout);
|
||||||
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelControlBarRightLayout);
|
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelControlBarRightLayout);
|
||||||
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelBottomBarLayout);
|
editor.subscriptions.unsubscribeJsMessage(UpdateLayersPanelBottomBarLayout);
|
||||||
editor.subscriptions.unsubscribeJsMessage(UpdateDocumentLayerStructureJs);
|
editor.subscriptions.unsubscribeJsMessage(UpdateDocumentLayerStructure);
|
||||||
editor.subscriptions.unsubscribeJsMessage(UpdateDocumentLayerDetails);
|
editor.subscriptions.unsubscribeJsMessage(UpdateDocumentLayerDetails);
|
||||||
|
|
||||||
removeEventListener("pointerup", draggingPointerUp);
|
removeEventListener("pointerup", draggingPointerUp);
|
||||||
|
|
@ -130,65 +129,6 @@
|
||||||
removeEventListener("keyup", clippingKeyPress);
|
removeEventListener("keyup", clippingKeyPress);
|
||||||
});
|
});
|
||||||
|
|
||||||
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 toggleNodeVisibilityLayerPanel(id: bigint) {
|
function toggleNodeVisibilityLayerPanel(id: bigint) {
|
||||||
editor.handle.toggleNodeVisibilityLayerPanel(id);
|
editor.handle.toggleNodeVisibilityLayerPanel(id);
|
||||||
}
|
}
|
||||||
|
|
@ -515,7 +455,7 @@
|
||||||
dragInPanel = false;
|
dragInPanel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildLayerHierarchy(updateDocumentLayerStructure: DocumentLayerStructure) {
|
function rebuildLayerHierarchy(layerStructure: LayerStructureEntry[]) {
|
||||||
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
||||||
const layerIdWithNameBeingEdited = layerWithNameBeingEdited?.entry.id;
|
const layerIdWithNameBeingEdited = layerWithNameBeingEdited?.entry.id;
|
||||||
|
|
||||||
|
|
@ -523,24 +463,24 @@
|
||||||
layers = [];
|
layers = [];
|
||||||
|
|
||||||
// Build the new layer hierarchy
|
// Build the new layer hierarchy
|
||||||
const recurse = (folder: DocumentLayerStructure) => {
|
const recurse = (children: LayerStructureEntry[]) => {
|
||||||
folder.children.forEach((item, index) => {
|
children.forEach((item, index) => {
|
||||||
const mapping = layerCache.get(String(item.layerId));
|
const mapping = layerCache.get(String(item.layerId));
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
mapping.id = item.layerId;
|
mapping.id = item.layerId;
|
||||||
layers.push({
|
layers.push({
|
||||||
folderIndex: index,
|
folderIndex: index,
|
||||||
bottomLayer: index === folder.children.length - 1,
|
bottomLayer: index === children.length - 1,
|
||||||
entry: mapping,
|
entry: mapping,
|
||||||
editingName: layerIdWithNameBeingEdited === item.layerId,
|
editingName: layerIdWithNameBeingEdited === item.layerId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call self recursively if there are any children
|
// Call self recursively if there are any children
|
||||||
if (item.children.length >= 1) recurse(item);
|
if (item.children.length >= 1) recurse(item.children);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
recurse(updateDocumentLayerStructure);
|
recurse(layerStructure);
|
||||||
layers = layers;
|
layers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -796,13 +796,13 @@ export class TriggerSaveActiveDocument extends JsMessage {
|
||||||
|
|
||||||
export class DocumentChanged extends JsMessage {}
|
export class DocumentChanged extends JsMessage {}
|
||||||
|
|
||||||
export type DataBuffer = {
|
export type LayerStructureEntry = {
|
||||||
pointer: bigint;
|
layerId: bigint;
|
||||||
length: bigint;
|
children: LayerStructureEntry[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export class UpdateDocumentLayerStructureJs extends JsMessage {
|
export class UpdateDocumentLayerStructure extends JsMessage {
|
||||||
readonly dataBuffer!: DataBuffer;
|
readonly layerStructure!: LayerStructureEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TextAlign = "Left" | "Center" | "Right" | "JustifyLeft";
|
export type TextAlign = "Left" | "Center" | "Right" | "JustifyLeft";
|
||||||
|
|
@ -1717,7 +1717,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||||
UpdateDocumentArtwork,
|
UpdateDocumentArtwork,
|
||||||
UpdateDocumentBarLayout,
|
UpdateDocumentBarLayout,
|
||||||
UpdateDocumentLayerDetails,
|
UpdateDocumentLayerDetails,
|
||||||
UpdateDocumentLayerStructureJs,
|
UpdateDocumentLayerStructure,
|
||||||
UpdateDocumentRulers,
|
UpdateDocumentRulers,
|
||||||
UpdateDocumentScrollbars,
|
UpdateDocumentScrollbars,
|
||||||
UpdateExportReorderIndex,
|
UpdateExportReorderIndex,
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ impl EditorHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a FrontendMessage to JavaScript
|
// Sends a FrontendMessage to JavaScript
|
||||||
fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
|
fn send_frontend_message_to_js(&self, message: FrontendMessage) {
|
||||||
if let FrontendMessage::UpdateImageData { ref image_data } = message {
|
if let FrontendMessage::UpdateImageData { ref image_data } = message {
|
||||||
let new_hash = calculate_hash(image_data);
|
let new_hash = calculate_hash(image_data);
|
||||||
let prev_hash = IMAGE_DATA_HASH.load(Ordering::Relaxed);
|
let prev_hash = IMAGE_DATA_HASH.load(Ordering::Relaxed);
|
||||||
|
|
@ -166,10 +166,6 @@ impl EditorHandle {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let FrontendMessage::UpdateDocumentLayerStructure { data_buffer } = message {
|
|
||||||
message = FrontendMessage::UpdateDocumentLayerStructureJs { data_buffer: data_buffer.into() };
|
|
||||||
}
|
|
||||||
|
|
||||||
let message_type = message.to_discriminant().local_name();
|
let message_type = message.to_discriminant().local_name();
|
||||||
|
|
||||||
let serializer = serde_wasm_bindgen::Serializer::new().serialize_large_number_types_as_bigints(true);
|
let serializer = serde_wasm_bindgen::Serializer::new().serialize_large_number_types_as_bigints(true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue