mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 21:08:11 +08:00
Generalize layers as merge nodes to enable adjustment layers (#1712)
* WIP, backward traversal issues * Fix some tool issues * Remove debugging * Change some indices * WIP: new artboard node * WIP: add artboard node * WIP: Artboard node and create_artboard * WIP: Artboard node implementation complete * WIP: Artboards input for output node * Complete Artboard node * Generalize LayerNodeIdentifier, monitor_nodes support for Artboard node, adjust ResizeArtboard/ClearArtboards, move alias validation to Rust * Fix misaligned artboard click targets * Generalize/clarify create_layer and insert_between * non-negative dimensions for resize_artboard * Show artboards in layer panel * Generalize create_layer for layer output node * Generalize delete_layer/delete_artboard to NodeGraphMessage::DeleteNodes. Fixed upstream flow Iter * remove old primary_input function * Vertical node visuals, remove is_layer function, rename Layer node to Merge node, toggle display as layer exposed_value_count type fix Vertical node visuals, remove is_layer function, rename Layer node to Merge node, toggle display as layer * Fix demo artwork * Layer display context menu * Automatically select artboard, fix warnings * Improvements to context menu and layer invariant enforcement * Remove display_as_layer and update load_structure * Improve load_structure to show more layers, improve FlowIter, improve layer naming, layer rearrangement validation. * Clean up demo artwork using generalized layers * Improve design of Layers panel and graph nodes * MoveSelectedLayersTo rewrite to support generalized layer nodes * Include artboards in deepest_common_ancestor, fix resize_artboard/delete_artboard, sync artboard tool to layer panel * MoveSelectedLayersTo adjustments * Sync non layer node visibility with metadata * Include non layer nodes when moving/creating layer * Fix group layers and get_post_node_with_index * Include non layer nodes in UngroupSelectedLayers * GroupSelected for all selected nodes, UnGroupSelected position adjustments * Add grouping for layers in different folders * Fix hidden layers * Prevent node from connecting to itself, fix undo automatic node insertion, * Fix undo CreateEmptyFolder, fix grouping nested layer nodes * Formatting * Remove test and check if node is layer from network * Fix undo group layers * Check off roadmap * MoveUpstreamSiblingsToChild adjustments * Replace tabs with spaces, remove mut from argument * Final code review pass --------- Co-authored-by: 0hypercube <0hypercube@gmail.com> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
0hypercube
Keavon Chambers
parent
beb88d280c
commit
8d83fa7079
@@ -6,7 +6,7 @@
|
||||
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 { DataBuffer, LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages";
|
||||
import type { DataBuffer, LayerPanelEntry } from "@graphite/wasm-communication/messages";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
@@ -165,7 +165,7 @@
|
||||
|
||||
const name = (e.target instanceof HTMLInputElement && e.target.value) || "";
|
||||
editor.handle.setLayerName(listing.entry.id, name);
|
||||
listing.entry.name = name;
|
||||
listing.entry.alias = name;
|
||||
}
|
||||
|
||||
async function onEditLayerNameDeselect(listing: LayerListingInfo) {
|
||||
@@ -174,7 +174,7 @@
|
||||
layers = layers;
|
||||
|
||||
// Set it back to the original name if the user didn't enter a new name
|
||||
if (document.activeElement instanceof HTMLInputElement) document.activeElement.value = listing.entry.name;
|
||||
if (document.activeElement instanceof HTMLInputElement) document.activeElement.value = listing.entry.alias;
|
||||
|
||||
// Deselect the text so it doesn't appear selected while the input field becomes disabled and styled to look like regular text
|
||||
window.getSelection()?.removeAllRanges();
|
||||
@@ -203,10 +203,6 @@
|
||||
editor.handle.deselectAllLayers();
|
||||
}
|
||||
|
||||
function isNestingLayer(layerClassification: LayerClassification) {
|
||||
return layerClassification === "Folder" || layerClassification === "Artboard";
|
||||
}
|
||||
|
||||
function calculateDragIndex(tree: LayoutCol, clientY: number, select?: () => void): DraggingData {
|
||||
const treeChildren = tree.div()?.children;
|
||||
const treeOffset = tree.div()?.getBoundingClientRect().top;
|
||||
@@ -248,7 +244,7 @@
|
||||
}
|
||||
// Inserting below current row
|
||||
else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) {
|
||||
if (isNestingLayer(layer.layerClassification)) {
|
||||
if (layer.childrenAllowed) {
|
||||
insertParentId = layer.id;
|
||||
insertDepth = layer.depth;
|
||||
insertIndex = 0;
|
||||
@@ -381,7 +377,6 @@
|
||||
classes={{
|
||||
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : $nodeGraph.selected.includes(listing.entry.id),
|
||||
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertParentId === listing.entry.id,
|
||||
"nesting-layer": isNestingLayer(listing.entry.layerClassification),
|
||||
}}
|
||||
styles={{ "--layer-indent-levels": `${listing.entry.depth - 1}` }}
|
||||
data-layer
|
||||
@@ -391,32 +386,29 @@
|
||||
on:dragstart={(e) => draggable && dragStart(e, listing)}
|
||||
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
||||
>
|
||||
{#if isNestingLayer(listing.entry.layerClassification)}
|
||||
{#if listing.entry.childrenAllowed}
|
||||
<button
|
||||
class="expand-arrow"
|
||||
class:expanded={listing.entry.expanded}
|
||||
disabled={!listing.entry.hasChildren}
|
||||
disabled={!listing.entry.childrenPresent}
|
||||
on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.id)}
|
||||
tabindex="0"
|
||||
/>
|
||||
{#if listing.entry.layerClassification === "Artboard"}
|
||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||
{:else if listing.entry.layerClassification === "Folder"}
|
||||
<IconLabel icon="Folder" class={"layer-type-icon"} />
|
||||
{/if}
|
||||
<div class="thumbnail">
|
||||
{#if $nodeGraph.thumbnails.has(listing.entry.id)}
|
||||
{@html $nodeGraph.thumbnails.get(listing.entry.id)}
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="thumbnail">
|
||||
{#if $nodeGraph.thumbnails.has(listing.entry.id)}
|
||||
{@html $nodeGraph.thumbnails.get(listing.entry.id)}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if listing.entry.name === "Artboard"}
|
||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||
{/if}
|
||||
<LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}>
|
||||
<input
|
||||
data-text-input
|
||||
type="text"
|
||||
value={listing.entry.name}
|
||||
placeholder={listing.entry.layerClassification}
|
||||
value={listing.entry.alias}
|
||||
placeholder={listing.entry.name}
|
||||
disabled={!listing.editingName}
|
||||
on:blur={() => onEditLayerNameDeselect(listing)}
|
||||
on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)}
|
||||
@@ -503,11 +495,7 @@
|
||||
border-radius: 2px;
|
||||
height: 32px;
|
||||
margin: 0 4px;
|
||||
padding-left: calc(4px + var(--layer-indent-levels) * 16px);
|
||||
|
||||
&.nesting-layer {
|
||||
padding-left: calc(var(--layer-indent-levels) * 16px);
|
||||
}
|
||||
padding-left: calc(var(--layer-indent-levels) * 16px);
|
||||
|
||||
&.selected {
|
||||
background: var(--color-4-dimgray);
|
||||
@@ -557,17 +545,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.layer-type-icon {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
width: 36px;
|
||||
height: 24px;
|
||||
background: white;
|
||||
margin-left: 4px;
|
||||
border-radius: 2px;
|
||||
flex: 0 0 auto;
|
||||
background: var(--color-transparent-checkered-background);
|
||||
background-size: var(--color-transparent-checkered-background-size-mini);
|
||||
background-position: var(--color-transparent-checkered-background-position-mini);
|
||||
|
||||
&:first-child {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: calc(100% - 4px);
|
||||
@@ -576,6 +566,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.layer-type-icon {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 8px;
|
||||
margin-right: -4px;
|
||||
}
|
||||
|
||||
.layer-name {
|
||||
flex: 1 1 100%;
|
||||
margin: 0 8px;
|
||||
|
||||
Reference in New Issue
Block a user