mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 02:58:11 +08:00
Welcome screen, refactor to allow zero documents, and add TS typing to widgets (#702)
* unfinished implementation * Add frontend for the empty panel screen * Add an icon for Folder based on NodeFolder * fixed messages causing peicees of ui not to render on new document * Standardize nextTick syntax * WIP generisization of component subscriptions (not compiling yet) * Fix crash when loading font and there is no active document * Only advertise tool actions with a document * Fix failure to create new document * Initalise the properties panel * Fix highlight tab, canvas jump, warns and layer tree * Fix tests * Possibly fix some things? * Move WorkingColors layout definition to backend * Standardize action macro formatting * Provide typing for widgets in TS/Vue and associated cleanup * Fix viewport positioning initialization * Fix menu bar init at startup not document creation * Fix no viewport bounds bug * Change !=0 to >0 * Simplify the init system Closes #656 Co-authored-by: Keavon Chambers <keavon@keavon.com> Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
co-authored by
Keavon Chambers
0hypercube
parent
b6793517e2
commit
010ba5a568
@@ -17,12 +17,7 @@
|
||||
<LayoutCol class="spacer"></LayoutCol>
|
||||
|
||||
<LayoutCol class="working-colors">
|
||||
<SwatchPairInput />
|
||||
<LayoutRow class="swap-and-reset">
|
||||
<!-- TODO: Remember to make these tooltip input hints customized to macOS also -->
|
||||
<IconButton :action="swapWorkingColors" :icon="'Swap'" title="Swap (Shift+X)" :size="16" />
|
||||
<IconButton :action="resetWorkingColors" :icon="'ResetColors'" title="Reset (Ctrl+Shift+X)" :size="16" />
|
||||
</LayoutRow>
|
||||
<WidgetLayout :layout="workingColorsLayout" />
|
||||
</LayoutCol>
|
||||
</LayoutCol>
|
||||
<LayoutCol class="viewport">
|
||||
@@ -135,8 +130,16 @@
|
||||
.working-colors {
|
||||
flex: 0 0 auto;
|
||||
|
||||
.swap-and-reset {
|
||||
flex: 0 0 auto;
|
||||
.widget-row {
|
||||
min-height: 0;
|
||||
|
||||
.swatch-pair {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
--widget-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,55 +225,26 @@ import { defineComponent, nextTick } from "vue";
|
||||
|
||||
import { textInputCleanup } from "@/utility-functions/keyboard-entry";
|
||||
import {
|
||||
UpdateDocumentArtwork,
|
||||
UpdateDocumentOverlays,
|
||||
UpdateDocumentScrollbars,
|
||||
UpdateDocumentRulers,
|
||||
UpdateDocumentArtboards,
|
||||
UpdateMouseCursor,
|
||||
UpdateDocumentModeLayout,
|
||||
UpdateToolOptionsLayout,
|
||||
UpdateToolShelfLayout,
|
||||
UpdateWorkingColorsLayout,
|
||||
defaultWidgetLayout,
|
||||
UpdateDocumentBarLayout,
|
||||
UpdateImageData,
|
||||
TriggerTextCommit,
|
||||
TriggerViewportResize,
|
||||
DisplayRemoveEditableTextbox,
|
||||
DisplayEditableTextbox,
|
||||
MouseCursorIcon,
|
||||
XY,
|
||||
} from "@/wasm-communication/messages";
|
||||
|
||||
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
||||
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
||||
import IconButton from "@/components/widgets/buttons/IconButton.vue";
|
||||
import SwatchPairInput from "@/components/widgets/inputs/SwatchPairInput.vue";
|
||||
import CanvasRuler from "@/components/widgets/metrics/CanvasRuler.vue";
|
||||
import PersistentScrollbar from "@/components/widgets/metrics/PersistentScrollbar.vue";
|
||||
import WidgetLayout from "@/components/widgets/WidgetLayout.vue";
|
||||
|
||||
export default defineComponent({
|
||||
inject: ["editor"],
|
||||
inject: ["editor", "panels"],
|
||||
methods: {
|
||||
viewportResize() {
|
||||
// Resize the canvas
|
||||
|
||||
const canvas = this.$refs.canvas as HTMLElement;
|
||||
|
||||
// Get the width and height rounded up to the nearest even number because resizing is centered and dividing an odd number by 2 for centering causes antialiasing
|
||||
let width = Math.ceil(parseFloat(getComputedStyle(canvas).width));
|
||||
if (width % 2 === 1) width += 1;
|
||||
let height = Math.ceil(parseFloat(getComputedStyle(canvas).height));
|
||||
if (height % 2 === 1) height += 1;
|
||||
|
||||
this.canvasSvgWidth = `${width}px`;
|
||||
this.canvasSvgHeight = `${height}px`;
|
||||
|
||||
// Resize the rulers
|
||||
const rulerHorizontal = this.$refs.rulerHorizontal as typeof CanvasRuler;
|
||||
const rulerVertical = this.$refs.rulerVertical as typeof CanvasRuler;
|
||||
rulerHorizontal?.resize();
|
||||
rulerVertical?.resize();
|
||||
},
|
||||
pasteFile(e: DragEvent) {
|
||||
const { dataTransfer } = e;
|
||||
if (!dataTransfer) return;
|
||||
@@ -304,12 +278,6 @@ export default defineComponent({
|
||||
const move = delta < 0 ? 1 : -1;
|
||||
this.editor.instance.translate_canvas_by_fraction(0, move);
|
||||
},
|
||||
swapWorkingColors() {
|
||||
this.editor.instance.swap_colors();
|
||||
},
|
||||
resetWorkingColors() {
|
||||
this.editor.instance.reset_colors();
|
||||
},
|
||||
canvasPointerDown(e: PointerEvent) {
|
||||
const onEditbox = e.target instanceof HTMLDivElement && e.target.contentEditable;
|
||||
if (!onEditbox) {
|
||||
@@ -317,76 +285,65 @@ export default defineComponent({
|
||||
canvas.setPointerCapture(e.pointerId);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
|
||||
this.artworkSvg = UpdateDocumentArtwork.svg;
|
||||
// Update rendered SVGs
|
||||
async updateDocumentArtwork(svg: string) {
|
||||
this.artworkSvg = svg;
|
||||
|
||||
nextTick((): void => {
|
||||
if (this.textInput) {
|
||||
const canvas = this.$refs.canvas as HTMLElement;
|
||||
const foreignObject = canvas.getElementsByTagName("foreignObject")[0] as SVGForeignObjectElement;
|
||||
if (foreignObject.children.length > 0) return;
|
||||
await nextTick();
|
||||
|
||||
const addedInput = foreignObject.appendChild(this.textInput);
|
||||
|
||||
nextTick((): void => {
|
||||
// Necessary to select contenteditable: https://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element/6150060#6150060
|
||||
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(addedInput);
|
||||
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
addedInput.focus();
|
||||
addedInput.click();
|
||||
});
|
||||
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("modifyinputfield", {
|
||||
detail: addedInput,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentOverlays, (updateDocumentOverlays) => {
|
||||
this.overlaysSvg = updateDocumentOverlays.svg;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentArtboards, (updateDocumentArtboards) => {
|
||||
this.artboardSvg = updateDocumentArtboards.svg;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentScrollbars, (updateDocumentScrollbars) => {
|
||||
this.scrollbarPos = updateDocumentScrollbars.position;
|
||||
this.scrollbarSize = updateDocumentScrollbars.size;
|
||||
this.scrollbarMultiplier = updateDocumentScrollbars.multiplier;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentRulers, (updateDocumentRulers) => {
|
||||
this.rulerOrigin = updateDocumentRulers.origin;
|
||||
this.rulerSpacing = updateDocumentRulers.spacing;
|
||||
this.rulerInterval = updateDocumentRulers.interval;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateMouseCursor, (updateMouseCursor) => {
|
||||
this.canvasCursor = updateMouseCursor.cursor;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(TriggerTextCommit, () => {
|
||||
if (this.textInput) {
|
||||
const textCleaned = textInputCleanup(this.textInput.innerText);
|
||||
this.editor.instance.on_change_text(textCleaned);
|
||||
}
|
||||
});
|
||||
const canvas = this.$refs.canvas as HTMLElement;
|
||||
const foreignObject = canvas.getElementsByTagName("foreignObject")[0] as SVGForeignObjectElement;
|
||||
if (foreignObject.children.length > 0) return;
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(DisplayEditableTextbox, (displayEditableTextbox) => {
|
||||
const addedInput = foreignObject.appendChild(this.textInput);
|
||||
window.dispatchEvent(new CustomEvent("modifyinputfield", { detail: addedInput }));
|
||||
|
||||
await nextTick();
|
||||
|
||||
// Necessary to select contenteditable: https://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element/6150060#6150060
|
||||
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(addedInput);
|
||||
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
addedInput.focus();
|
||||
addedInput.click();
|
||||
}
|
||||
},
|
||||
updateDocumentOverlays(svg: string) {
|
||||
this.overlaysSvg = svg;
|
||||
},
|
||||
updateDocumentArtboards(svg: string) {
|
||||
this.artboardSvg = svg;
|
||||
},
|
||||
// Update scrollbars and rulers
|
||||
updateDocumentScrollbars(position: XY, size: XY, multiplier: XY) {
|
||||
this.scrollbarPos = position;
|
||||
this.scrollbarSize = size;
|
||||
this.scrollbarMultiplier = multiplier;
|
||||
},
|
||||
updateDocumentRulers(origin: XY, spacing: number, interval: number) {
|
||||
this.rulerOrigin = origin;
|
||||
this.rulerSpacing = spacing;
|
||||
this.rulerInterval = interval;
|
||||
},
|
||||
// Update mouse cursor icon
|
||||
updateMouseCursor(cursor: MouseCursorIcon) {
|
||||
this.canvasCursor = cursor;
|
||||
},
|
||||
// Text entry
|
||||
triggerTextCommit() {
|
||||
if (!this.textInput) return;
|
||||
const textCleaned = textInputCleanup(this.textInput.innerText);
|
||||
this.editor.instance.on_change_text(textCleaned);
|
||||
},
|
||||
displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) {
|
||||
this.textInput = document.createElement("DIV") as HTMLDivElement;
|
||||
|
||||
if (displayEditableTextbox.text === "") this.textInput.textContent = "";
|
||||
@@ -399,49 +356,52 @@ export default defineComponent({
|
||||
this.textInput.style.color = displayEditableTextbox.color.toRgbaCSS();
|
||||
|
||||
this.textInput.oninput = (): void => {
|
||||
if (this.textInput) this.editor.instance.update_bounds(textInputCleanup(this.textInput.innerText));
|
||||
if (!this.textInput) return;
|
||||
this.editor.instance.update_bounds(textInputCleanup(this.textInput.innerText));
|
||||
};
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(DisplayRemoveEditableTextbox, () => {
|
||||
},
|
||||
displayRemoveEditableTextbox() {
|
||||
this.textInput = undefined;
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("modifyinputfield", {
|
||||
detail: undefined,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentModeLayout, (updateDocumentModeLayout) => {
|
||||
window.dispatchEvent(new CustomEvent("modifyinputfield", { detail: undefined }));
|
||||
},
|
||||
// Update layouts
|
||||
updateDocumentModeLayout(updateDocumentModeLayout: UpdateDocumentModeLayout) {
|
||||
this.documentModeLayout = updateDocumentModeLayout;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateToolOptionsLayout, (updateToolOptionsLayout) => {
|
||||
},
|
||||
updateToolOptionsLayout(updateToolOptionsLayout: UpdateToolOptionsLayout) {
|
||||
this.toolOptionsLayout = updateToolOptionsLayout;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentBarLayout, (updateDocumentBarLayout) => {
|
||||
},
|
||||
updateDocumentBarLayout(updateDocumentBarLayout: UpdateDocumentBarLayout) {
|
||||
this.documentBarLayout = updateDocumentBarLayout;
|
||||
});
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateToolShelfLayout, (updateToolShelfLayout) => {
|
||||
},
|
||||
updateToolShelfLayout(updateToolShelfLayout: UpdateToolShelfLayout) {
|
||||
this.toolShelfLayout = updateToolShelfLayout;
|
||||
});
|
||||
},
|
||||
updateWorkingColorsLayout(updateWorkingColorsLayout: UpdateWorkingColorsLayout) {
|
||||
this.workingColorsLayout = updateWorkingColorsLayout;
|
||||
},
|
||||
// Resize elements to render the new viewport size
|
||||
viewportResize() {
|
||||
// Resize the canvas
|
||||
// Width and height are rounded up to the nearest even number because resizing is centered, and dividing an odd number by 2 for centering causes antialiasing
|
||||
const canvas = this.$refs.canvas as HTMLElement;
|
||||
const width = Math.ceil(parseFloat(getComputedStyle(canvas).width));
|
||||
const height = Math.ceil(parseFloat(getComputedStyle(canvas).height));
|
||||
this.canvasSvgWidth = `${width % 2 === 1 ? width + 1 : width}px`;
|
||||
this.canvasSvgHeight = `${height % 2 === 1 ? height + 1 : height}px`;
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(TriggerViewportResize, this.viewportResize);
|
||||
// Resize the rulers
|
||||
const rulerHorizontal = this.$refs.rulerHorizontal as typeof CanvasRuler;
|
||||
const rulerVertical = this.$refs.rulerVertical as typeof CanvasRuler;
|
||||
rulerHorizontal?.resize();
|
||||
rulerVertical?.resize();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.panels.registerPanel("Document", this);
|
||||
|
||||
this.editor.subscriptions.subscribeJsMessage(UpdateImageData, (updateImageData) => {
|
||||
updateImageData.image_data.forEach(async (element) => {
|
||||
// Using updateImageData.image_data.buffer returns undefined for some reason?
|
||||
const blob = new Blob([new Uint8Array(element.image_data.values()).buffer], { type: element.mime });
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const image = await createImageBitmap(blob);
|
||||
|
||||
this.editor.instance.set_image_blob_url(element.path, url, image.width, image.height);
|
||||
});
|
||||
});
|
||||
// Once this component is mounted, we want to resend the document bounds to the backend via the resize event handler which does that
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -449,39 +409,38 @@ export default defineComponent({
|
||||
textInput: undefined as undefined | HTMLDivElement,
|
||||
|
||||
// CSS properties
|
||||
canvasSvgWidth: "100%",
|
||||
canvasSvgHeight: "100%",
|
||||
canvasCursor: "default",
|
||||
canvasSvgWidth: "100%" as string,
|
||||
canvasSvgHeight: "100%" as string,
|
||||
canvasCursor: "default" as MouseCursorIcon,
|
||||
|
||||
// Scrollbars
|
||||
scrollbarPos: { x: 0.5, y: 0.5 },
|
||||
scrollbarSize: { x: 0.5, y: 0.5 },
|
||||
scrollbarMultiplier: { x: 0, y: 0 },
|
||||
scrollbarPos: { x: 0.5, y: 0.5 } as XY,
|
||||
scrollbarSize: { x: 0.5, y: 0.5 } as XY,
|
||||
scrollbarMultiplier: { x: 0, y: 0 } as XY,
|
||||
|
||||
// Rulers
|
||||
rulerOrigin: { x: 0, y: 0 },
|
||||
rulerSpacing: 100,
|
||||
rulerInterval: 100,
|
||||
rulerOrigin: { x: 0, y: 0 } as XY,
|
||||
rulerSpacing: 100 as number,
|
||||
rulerInterval: 100 as number,
|
||||
|
||||
// Rendered SVG viewport data
|
||||
artworkSvg: "",
|
||||
artboardSvg: "",
|
||||
overlaysSvg: "",
|
||||
artworkSvg: "" as string,
|
||||
artboardSvg: "" as string,
|
||||
overlaysSvg: "" as string,
|
||||
|
||||
// Layouts
|
||||
documentModeLayout: defaultWidgetLayout(),
|
||||
toolOptionsLayout: defaultWidgetLayout(),
|
||||
documentBarLayout: defaultWidgetLayout(),
|
||||
toolShelfLayout: defaultWidgetLayout(),
|
||||
workingColorsLayout: defaultWidgetLayout(),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
LayoutRow,
|
||||
LayoutCol,
|
||||
SwatchPairInput,
|
||||
PersistentScrollbar,
|
||||
CanvasRuler,
|
||||
IconButton,
|
||||
WidgetLayout,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
:title="`${listing.entry.name}\n${devMode ? 'Layer Path: ' + listing.entry.path.join(' / ') : ''}`.trim() || null"
|
||||
>
|
||||
<LayoutRow class="layer-type-icon">
|
||||
<IconLabel v-if="listing.entry.layer_type === 'Folder'" :icon="'NodeFolder'" :style="'node'" title="Folder" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Image'" :icon="'NodeImage'" :style="'node'" title="Image" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Shape'" :icon="'NodeShape'" :style="'node'" title="Shape" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Text'" :icon="'NodeText'" :style="'node'" title="Path" />
|
||||
<IconLabel v-if="listing.entry.layer_type === 'Folder'" :icon="'NodeFolder'" :iconStyle="'Node'" title="Folder" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Image'" :icon="'NodeImage'" :iconStyle="'Node'" title="Image" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Shape'" :icon="'NodeShape'" :iconStyle="'Node'" title="Shape" />
|
||||
<IconLabel v-else-if="listing.entry.layer_type === 'Text'" :icon="'NodeText'" :iconStyle="'Node'" title="Path" />
|
||||
</LayoutRow>
|
||||
<LayoutRow class="layer-name" @dblclick="() => onEditLayerName(listing)">
|
||||
<input
|
||||
@@ -261,7 +261,7 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { defineComponent, nextTick } from "vue";
|
||||
|
||||
import { defaultWidgetLayout, UpdateDocumentLayerTreeStructure, UpdateDocumentLayerDetails, UpdateLayerTreeOptionsLayout, LayerPanelEntry } from "@/wasm-communication/messages";
|
||||
|
||||
@@ -313,16 +313,16 @@ export default defineComponent({
|
||||
handleExpandArrowClick(path: BigUint64Array) {
|
||||
this.editor.instance.toggle_layer_expansion(path);
|
||||
},
|
||||
onEditLayerName(listing: LayerListingInfo) {
|
||||
async onEditLayerName(listing: LayerListingInfo) {
|
||||
if (listing.editingName) return;
|
||||
|
||||
this.draggable = false;
|
||||
|
||||
listing.editingName = true;
|
||||
const tree: HTMLElement = (this.$refs.layerTreeList as typeof LayoutCol).$el;
|
||||
this.$nextTick(() => {
|
||||
(tree.querySelector("[data-text-input]:not([disabled])") as HTMLInputElement).select();
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
(tree.querySelector("[data-text-input]:not([disabled])") as HTMLInputElement).select();
|
||||
},
|
||||
onEditLayerNameChange(listing: LayerListingInfo, inputElement: EventTarget | null) {
|
||||
// Eliminate duplicate events
|
||||
@@ -334,13 +334,13 @@ export default defineComponent({
|
||||
listing.editingName = false;
|
||||
this.editor.instance.set_layer_name(listing.entry.path, name);
|
||||
},
|
||||
onEditLayerNameDeselect(listing: LayerListingInfo) {
|
||||
async onEditLayerNameDeselect(listing: LayerListingInfo) {
|
||||
this.draggable = true;
|
||||
|
||||
listing.editingName = false;
|
||||
this.$nextTick(() => {
|
||||
window.getSelection()?.removeAllRanges();
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
window.getSelection()?.removeAllRanges();
|
||||
},
|
||||
async selectLayer(clickedLayer: LayerPanelEntry, ctrl: boolean, shift: boolean) {
|
||||
this.editor.instance.select_layer(clickedLayer.path, ctrl, shift);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeImage'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeImage'" :iconStyle="'Node'" />
|
||||
<TextLabel>Image</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -42,7 +42,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeImage'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeImage'" :iconStyle="'Node'" />
|
||||
<TextLabel>Mask</TextLabel>
|
||||
</div>
|
||||
<div class="arguments">
|
||||
@@ -69,7 +69,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeTransform'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeTransform'" :iconStyle="'Node'" />
|
||||
<TextLabel>Transform</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,7 +83,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeMotionBlur'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeMotionBlur'" :iconStyle="'Node'" />
|
||||
<TextLabel>Motion Blur</TextLabel>
|
||||
</div>
|
||||
<div class="arguments">
|
||||
@@ -110,7 +110,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeShape'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeShape'" :iconStyle="'Node'" />
|
||||
<TextLabel>Shape</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,7 +124,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeBrushwork'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeBrushwork'" :iconStyle="'Node'" />
|
||||
<TextLabel>Brushwork</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,7 +138,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeBlur'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeBlur'" :iconStyle="'Node'" />
|
||||
<TextLabel>Blur</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,7 +152,7 @@
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<IconLabel :icon="'NodeGradient'" :style="'node'" />
|
||||
<IconLabel :icon="'NodeGradient'" :iconStyle="'Node'" />
|
||||
<TextLabel>Gradient</TextLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user