Clean up camelCase and snake_case in frontend code

This commit is contained in:
Keavon Chambers 2022-08-23 13:36:27 -07:00
parent 71f12db1e6
commit 1a90a4db86
30 changed files with 317 additions and 162 deletions

View file

@ -295,7 +295,7 @@ export default defineComponent({
// Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready
const platform = operatingSystem();
this.editor.instance.init_after_frontend_ready(platform);
this.editor.instance.initAfterFrontendReady(platform);
},
beforeUnmount() {
// Call the destructor for each manager

View file

@ -256,27 +256,27 @@ export default defineComponent({
const buffer = await file.arrayBuffer();
const u8Array = new Uint8Array(buffer);
this.editor.instance.paste_image(file.type, u8Array, e.clientX, e.clientY);
this.editor.instance.pasteImage(file.type, u8Array, e.clientX, e.clientY);
}
});
},
translateCanvasX(newValue: number) {
const delta = newValue - this.scrollbarPos.x;
this.scrollbarPos.x = newValue;
this.editor.instance.translate_canvas(-delta * this.scrollbarMultiplier.x, 0);
this.editor.instance.translateCanvas(-delta * this.scrollbarMultiplier.x, 0);
},
translateCanvasY(newValue: number) {
const delta = newValue - this.scrollbarPos.y;
this.scrollbarPos.y = newValue;
this.editor.instance.translate_canvas(0, -delta * this.scrollbarMultiplier.y);
this.editor.instance.translateCanvas(0, -delta * this.scrollbarMultiplier.y);
},
pageX(delta: number) {
const move = delta < 0 ? 1 : -1;
this.editor.instance.translate_canvas_by_fraction(move, 0);
this.editor.instance.translateCanvasByFraction(move, 0);
},
pageY(delta: number) {
const move = delta < 0 ? 1 : -1;
this.editor.instance.translate_canvas_by_fraction(0, move);
this.editor.instance.translateCanvasByFraction(0, move);
},
canvasPointerDown(e: PointerEvent) {
const onEditbox = e.target instanceof HTMLDivElement && e.target.contentEditable;
@ -341,7 +341,7 @@ export default defineComponent({
triggerTextCommit() {
if (!this.textInput) return;
const textCleaned = textInputCleanup(this.textInput.innerText);
this.editor.instance.on_change_text(textCleaned);
this.editor.instance.onChangeText(textCleaned);
},
displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) {
this.textInput = document.createElement("DIV") as HTMLDivElement;
@ -350,14 +350,14 @@ export default defineComponent({
else this.textInput.textContent = `${displayEditableTextbox.text}\n`;
this.textInput.contentEditable = "true";
this.textInput.style.width = displayEditableTextbox.line_width ? `${displayEditableTextbox.line_width}px` : "max-content";
this.textInput.style.width = displayEditableTextbox.lineWidth ? `${displayEditableTextbox.lineWidth}px` : "max-content";
this.textInput.style.height = "auto";
this.textInput.style.fontSize = `${displayEditableTextbox.font_size}px`;
this.textInput.style.fontSize = `${displayEditableTextbox.fontSize}px`;
this.textInput.style.color = displayEditableTextbox.color.toRgbaCSS();
this.textInput.oninput = (): void => {
if (!this.textInput) return;
this.editor.instance.update_bounds(textInputCleanup(this.textInput.innerText));
this.editor.instance.updateBounds(textInputCleanup(this.textInput.innerText));
};
},
displayRemoveEditableTextbox() {

View file

@ -23,16 +23,16 @@
<div class="indent" :style="{ marginLeft: layerIndent(listing.entry) }"></div>
<button
v-if="listing.entry.layer_type === 'Folder'"
v-if="listing.entry.layerType === 'Folder'"
class="expand-arrow"
:class="{ expanded: listing.entry.layer_metadata.expanded }"
:class="{ expanded: listing.entry.layerMetadata.expanded }"
@click.stop="handleExpandArrowClick(listing.entry.path)"
></button>
<LayoutRow
class="layer"
:class="{ selected: listing.entry.layer_metadata.selected }"
:class="{ selected: listing.entry.layerMetadata.selected }"
:data-index="index"
:title="`${listing.entry.name}${devMode ? '\nLayer Path: ' + listing.entry.path.join(' / ') : ''}` || null"
:title="listing.entry.tooltip"
:draggable="draggable"
@dragstart="(e) => draggable && dragStart(e, listing)"
@click.exact="(e) => selectLayer(false, false, false, listing, e)"
@ -45,17 +45,17 @@
@click.alt="(e) => e.stopPropagation()"
>
<LayoutRow class="layer-type-icon">
<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" />
<IconLabel v-if="listing.entry.layerType === 'Folder'" :icon="'NodeFolder'" :iconStyle="'Node'" title="Folder" />
<IconLabel v-else-if="listing.entry.layerType === 'Image'" :icon="'NodeImage'" :iconStyle="'Node'" title="Image" />
<IconLabel v-else-if="listing.entry.layerType === 'Shape'" :icon="'NodeShape'" :iconStyle="'Node'" title="Shape" />
<IconLabel v-else-if="listing.entry.layerType === 'Text'" :icon="'NodeText'" :iconStyle="'Node'" title="Path" />
</LayoutRow>
<LayoutRow class="layer-name" @dblclick="() => onEditLayerName(listing)">
<input
data-text-input
type="text"
:value="listing.entry.name"
:placeholder="listing.entry.layer_type"
:placeholder="listing.entry.layerType"
:disabled="!listing.editingName"
@blur="() => onEditLayerNameDeselect(listing)"
@keydown.esc="onEditLayerNameDeselect(listing)"
@ -292,7 +292,6 @@ export default defineComponent({
// Layer data
layerCache: new Map() as Map<string, LayerPanelEntry>, // TODO: replace with BigUint64Array as index
layers: [] as LayerListingInfo[],
devMode: process.env.NODE_ENV === "development",
// Interactive dragging
draggable: true,
@ -313,10 +312,10 @@ export default defineComponent({
return `${height}px`;
},
toggleLayerVisibility(path: BigUint64Array) {
this.editor.instance.toggle_layer_visibility(path);
this.editor.instance.toggleLayerVisibility(path);
},
handleExpandArrowClick(path: BigUint64Array) {
this.editor.instance.toggle_layer_expansion(path);
this.editor.instance.toggleLayerExpansion(path);
},
async onEditLayerName(listing: LayerListingInfo) {
if (listing.editingName) return;
@ -337,7 +336,7 @@ export default defineComponent({
const name = (inputElement as HTMLInputElement).value;
listing.editingName = false;
this.editor.instance.set_layer_name(listing.entry.path, name);
this.editor.instance.setLayerName(listing.entry.path, name);
},
async onEditLayerNameDeselect(listing: LayerListingInfo) {
this.draggable = true;
@ -354,14 +353,14 @@ export default defineComponent({
// Pressing the Ctrl key on a Mac, or the Cmd key on another platform, is a violation of the `.exact` qualifier so we filter it out here
const opposite = platformIsMac() ? ctrl : cmd;
if (!opposite) this.editor.instance.select_layer(listing.entry.path, ctrlOrCmd, shift);
if (!opposite) this.editor.instance.selectLayer(listing.entry.path, ctrlOrCmd, shift);
// We always want to stop propagation so the click event doesn't pass through the layer and cause a deselection by clicking the layer panel background
// This is also why we cover the remaining cases not considered by the `.exact` qualifier, in the last two bindings on the layer element, with a `stopPropagation()` call
event.stopPropagation();
},
async deselectAllLayers() {
this.editor.instance.deselect_all_layers();
this.editor.instance.deselectAllLayers();
},
calculateDragIndex(tree: HTMLElement, clientY: number): DraggingData {
const treeChildren = tree.children;
@ -405,9 +404,9 @@ export default defineComponent({
}
// Inserting below current row
else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) {
insertFolder = layer.layer_type === "Folder" ? layer.path : layer.path.slice(0, layer.path.length - 1);
insertIndex = layer.layer_type === "Folder" ? 0 : folderIndex + 1;
highlightFolder = layer.layer_type === "Folder";
insertFolder = layer.layerType === "Folder" ? layer.path : layer.path.slice(0, layer.path.length - 1);
insertIndex = layer.layerType === "Folder" ? 0 : folderIndex + 1;
highlightFolder = layer.layerType === "Folder";
closest = -distance;
markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom;
}
@ -426,7 +425,7 @@ export default defineComponent({
},
async dragStart(event: DragEvent, listing: LayerListingInfo) {
const layer = listing.entry;
if (!layer.layer_metadata.selected) this.selectLayer(event.ctrlKey, event.metaKey, event.shiftKey, listing, event);
if (!layer.layerMetadata.selected) this.selectLayer(event.ctrlKey, event.metaKey, event.shiftKey, listing, event);
// Set style of cursor for drag
if (event.dataTransfer) {
@ -448,7 +447,7 @@ export default defineComponent({
if (this.draggingData) {
const { insertFolder, insertIndex } = this.draggingData;
this.editor.instance.move_layer_in_tree(insertFolder, insertIndex);
this.editor.instance.moveLayerInTree(insertFolder, insertIndex);
this.draggingData = undefined;
}

View file

@ -2,7 +2,7 @@
<template>
<div class="widget-layout">
<component :is="LayoutGroupType(layoutRow)" :widgetData="layoutRow" :layoutTarget="layout.layout_target" v-for="(layoutRow, index) in layout.layout" :key="index" />
<component :is="LayoutGroupType(layoutRow)" :widgetData="layoutRow" :layoutTarget="layout.layoutTarget" v-for="(layoutRow, index) in layout.layout" :key="index" />
</div>
</template>

View file

@ -122,7 +122,7 @@ export default defineComponent({
},
methods: {
updateLayout(widgetId: bigint, value: unknown) {
this.editor.instance.update_layout(this.layoutTarget, widgetId, value);
this.editor.instance.updateLayout(this.layoutTarget, widgetId, value);
},
withoutValue(props: Record<string, unknown>): Record<string, unknown> {
const { value: _, ...rest } = props;

View file

@ -94,7 +94,7 @@ const WidgetSection = defineComponent({
}),
methods: {
updateLayout(widgetId: bigint, value: unknown) {
this.editor.instance.update_layout(this.layoutTarget, widgetId, value);
this.editor.instance.updateLayout(this.layoutTarget, widgetId, value);
},
layoutGroupType(layoutGroup: LayoutGroup): unknown {
if (isWidgetRow(layoutGroup)) return WidgetRow;

View file

@ -24,7 +24,7 @@
:direction="'Bottom'"
:minWidth="240"
:drawIcon="true"
:defaultAction="() => editor.instance.request_coming_soon_dialog()"
:defaultAction="() => editor.instance.requestComingSoonDialog()"
:ref="(ref: typeof MenuList) => ref && (entry.ref = ref)"
/>
</div>
@ -111,7 +111,7 @@ export default defineComponent({
group.map((entry) => ({
...entry,
children: entry.children ? menuEntryToFrontendMenuEntry(entry.children) : undefined,
action: (): void => this.editor.instance.update_layout(updateMenuBarLayout.layout_target, entry.action.widgetId, undefined),
action: (): void => this.editor.instance.updateLayout(updateMenuBarLayout.layoutTarget, entry.action.widgetId, undefined),
shortcutRequiresLock: entry.shortcut ? shortcutRequiresLock(entry.shortcut.keys) : undefined,
}))
);

View file

@ -105,11 +105,11 @@ export default defineComponent({
},
primaryColorChanged(color: RGBA) {
const newColor = rgbaToDecimalRgba(color);
this.editor.instance.update_primary_color(newColor.r, newColor.g, newColor.b, newColor.a);
this.editor.instance.updatePrimaryColor(newColor.r, newColor.g, newColor.b, newColor.a);
},
secondaryColorChanged(color: RGBA) {
const newColor = rgbaToDecimalRgba(color);
this.editor.instance.update_secondary_color(newColor.r, newColor.g, newColor.b, newColor.a);
this.editor.instance.updateSecondaryColor(newColor.r, newColor.g, newColor.b, newColor.a);
},
},
});

View file

@ -70,7 +70,7 @@ export default defineComponent({
},
mounted() {
this.editor.subscriptions.subscribeJsMessage(UpdateInputHints, (updateInputHints) => {
this.hintData = updateInputHints.hint_data;
this.hintData = updateInputHints.hintData;
});
},
components: {

View file

@ -252,10 +252,10 @@ export default defineComponent({
},
methods: {
newDocument() {
this.editor.instance.new_document_dialog();
this.editor.instance.newDocumentDialog();
},
openDocument() {
this.editor.instance.document_open();
this.editor.instance.documentOpen();
},
platformModifiers(reservedKey: boolean): KeysGroup {
// TODO: Remove this by properly feeding these keys from a layout provided by the backend

View file

@ -8,8 +8,8 @@
:tabCloseButtons="true"
:tabMinWidths="true"
:tabLabels="portfolio.state.documents.map((doc) => doc.displayName)"
:clickAction="(tabIndex) => editor.instance.select_document(portfolio.state.documents[tabIndex].id)"
:closeAction="(tabIndex) => editor.instance.close_document_with_confirmation(portfolio.state.documents[tabIndex].id)"
:clickAction="(tabIndex) => editor.instance.selectDocument(portfolio.state.documents[tabIndex].id)"
:closeAction="(tabIndex) => editor.instance.closeDocumentWithConfirmation(portfolio.state.documents[tabIndex].id)"
:tabActiveIndex="portfolio.state.activeDocumentIndex"
ref="documentsPanel"
/>

View file

@ -4,15 +4,15 @@ import { UpdateImageData } from "@/wasm-communication/messages";
export function createBlobManager(editor: Editor): void {
// Subscribe to process backend event
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 });
updateImageData.imageData.forEach(async (element) => {
// Using updateImageData.imageData.buffer returns undefined for some reason?
const blob = new Blob([new Uint8Array(element.imageData.values()).buffer], { type: element.mime });
const url = URL.createObjectURL(blob);
const image = await createImageBitmap(blob);
editor.instance.set_image_blob_url(element.path, url, image.width, image.height);
editor.instance.setImageBlobUrl(element.path, url, image.width, image.height);
});
});
}

View file

@ -5,6 +5,6 @@ export function createClipboardManager(editor: Editor): void {
// Subscribe to process backend event
editor.subscriptions.subscribeJsMessage(TriggerTextCopy, (triggerTextCopy) => {
// If the Clipboard API is supported in the browser, copy text to the clipboard
navigator.clipboard?.writeText?.(triggerTextCopy.copy_text);
navigator.clipboard?.writeText?.(triggerTextCopy.copyText);
});
}

View file

@ -106,7 +106,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (await shouldRedirectKeyboardEventToBackend(e)) {
e.preventDefault();
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_key_down(key, modifiers);
editor.instance.onKeyDown(key, modifiers);
return;
}
@ -121,7 +121,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (await shouldRedirectKeyboardEventToBackend(e)) {
e.preventDefault();
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_key_up(key, modifiers);
editor.instance.onKeyUp(key, modifiers);
}
}
@ -146,7 +146,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
}
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_mouse_move(e.clientX, e.clientY, e.buttons, modifiers);
editor.instance.onMouseMove(e.clientX, e.clientY, e.buttons, modifiers);
}
function onPointerDown(e: PointerEvent): void {
@ -162,13 +162,13 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
}
if (!inTextInput) {
if (textInput) editor.instance.on_change_text(textInputCleanup(textInput.innerText));
if (textInput) editor.instance.onChangeText(textInputCleanup(textInput.innerText));
else viewportPointerInteractionOngoing = isTargetingCanvas instanceof Element;
}
if (viewportPointerInteractionOngoing) {
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_mouse_down(e.clientX, e.clientY, e.buttons, modifiers);
editor.instance.onMouseDown(e.clientX, e.clientY, e.buttons, modifiers);
}
}
@ -177,7 +177,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (!textInput) {
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers);
editor.instance.onMouseUp(e.clientX, e.clientY, e.buttons, modifiers);
}
}
@ -186,7 +186,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (!textInput) {
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_double_click(e.clientX, e.clientY, e.buttons, modifiers);
editor.instance.onDoubleClick(e.clientX, e.clientY, e.buttons, modifiers);
}
}
@ -213,7 +213,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (isTargetingCanvas) {
e.preventDefault();
const modifiers = makeKeyboardModifiersBitfield(e);
editor.instance.on_wheel_scroll(e.clientX, e.clientY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers);
editor.instance.onWheelScroll(e.clientX, e.clientY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers);
}
}
@ -233,20 +233,20 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
const flattened = boundsOfViewports.flat();
const data = Float64Array.from(flattened);
if (boundsOfViewports.length > 0) editor.instance.bounds_of_viewports(data);
if (boundsOfViewports.length > 0) editor.instance.boundsOfViewports(data);
}
function onBeforeUnload(e: BeforeUnloadEvent): void {
const activeDocument = document.state.documents[document.state.activeDocumentIndex];
if (!activeDocument.is_saved) editor.instance.trigger_auto_save(activeDocument.id);
if (!activeDocument.isSaved) editor.instance.triggerAutoSave(activeDocument.id);
// Skip the message if the editor crashed, since work is already lost
if (editor.instance.has_crashed()) return;
if (editor.instance.hasCrashed()) return;
// Skip the message during development, since it's annoying when testing
if (process.env.NODE_ENV === "development") return;
const allDocumentsSaved = document.state.documents.reduce((acc, doc) => acc && doc.is_saved, true);
const allDocumentsSaved = document.state.documents.reduce((acc, doc) => acc && doc.isSaved, true);
if (!allDocumentsSaved) {
e.returnValue = "Unsaved work will be lost if the web browser tab is closed. Close anyway?";
e.preventDefault();
@ -262,7 +262,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
if (item.type === "text/plain") {
item.getAsString((text) => {
if (text.startsWith("graphite/layer: ")) {
editor.instance.paste_serialized_data(text.substring(16, text.length));
editor.instance.pasteSerializedData(text.substring(16, text.length));
}
});
}
@ -272,7 +272,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
file.arrayBuffer().then((buffer): void => {
const u8Array = new Uint8Array(buffer);
editor.instance.paste_image(file.type, u8Array);
editor.instance.pasteImage(file.type, u8Array);
});
}
});
@ -305,7 +305,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
const text = reader.result as string;
if (text.startsWith("graphite/layer: ")) {
editor.instance.paste_serialized_data(text.substring(16, text.length));
editor.instance.pasteSerializedData(text.substring(16, text.length));
}
};
reader.readAsText(blob);
@ -319,7 +319,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
reader.onload = (): void => {
const u8Array = new Uint8Array(reader.result as ArrayBuffer);
editor.instance.paste_image(imageType, u8Array);
editor.instance.pasteImage(imageType, u8Array);
};
reader.readAsArrayBuffer(blob);
}
@ -343,7 +343,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo
};
const message = Object.entries(matchMessage).find(([key]) => String(err).includes(key))?.[1] || String(err);
editor.instance.error_dialog("Cannot access clipboard", message);
editor.instance.errorDialog("Cannot access clipboard", message);
}
});

View file

@ -19,7 +19,7 @@ export function createLocalizationManager(editor: Editor): void {
// Subscribe to process backend event
editor.subscriptions.subscribeJsMessage(TriggerAboutGraphiteLocalizedCommitDate, (triggerAboutGraphiteLocalizedCommitDate) => {
const localized = localizeTimestamp(triggerAboutGraphiteLocalizedCommitDate.commit_date);
editor.instance.request_about_graphite_dialog_with_localized_commit_date(localized);
const localized = localizeTimestamp(triggerAboutGraphiteLocalizedCommitDate.commitDate);
editor.instance.requestAboutGraphiteDialogWithLocalizedCommitDate(localized);
});
}

View file

@ -13,7 +13,7 @@ export function createPanicManager(editor: Editor, dialogState: DialogState): vo
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(Error as any).stackTraceLimit = Infinity;
const stackTrace = new Error().stack || "";
const panicDetails = `${displayDialogPanic.panic_info}${stackTrace ? `\n\n${stackTrace}` : ""}`;
const panicDetails = `${displayDialogPanic.panicInfo}${stackTrace ? `\n\n${stackTrace}` : ""}`;
// eslint-disable-next-line no-console
console.error(panicDetails);
@ -29,8 +29,7 @@ function preparePanicDialog(header: string, details: string, panicDetails: strin
{ rowWidgets: [new Widget({ kind: "TextLabel", value: header, bold: true, italic: false, tableAlign: false, multiline: false }, 0n)] },
{ rowWidgets: [new Widget({ kind: "TextLabel", value: details, bold: false, italic: false, tableAlign: false, multiline: true }, 1n)] },
],
// eslint-disable-next-line camelcase
layout_target: null,
layoutTarget: null,
};
const reloadButton: TextButtonWidget = {

View file

@ -36,7 +36,7 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo
storeDocumentOrder();
});
editor.subscriptions.subscribeJsMessage(TriggerIndexedDbRemoveDocument, async (removeAutoSaveDocument) => {
removeDocument(removeAutoSaveDocument.document_id);
removeDocument(removeAutoSaveDocument.documentId);
});
// Open the IndexedDB database connection and save it to this variable, which is a promise that resolves once the connection is open
@ -61,7 +61,7 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo
Error on opening IndexDB:
${dbOpenRequest.error}
`;
editor.instance.error_dialog("Document auto-save doesn't work in this browser", errorText);
editor.instance.errorDialog("Document auto-save doesn't work in this browser", errorText);
};
dbOpenRequest.onsuccess = (): void => {
@ -82,10 +82,10 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo
.map((id) => previouslySavedDocuments.find((autoSave) => autoSave.details.id === id))
.filter((x) => x !== undefined) as TriggerIndexedDbWriteDocument[];
const currentDocumentVersion = editor.instance.graphite_document_version();
const currentDocumentVersion = editor.instance.graphiteDocumentVersion();
orderedSavedDocuments.forEach((doc: TriggerIndexedDbWriteDocument) => {
if (doc.version === currentDocumentVersion) {
editor.instance.open_auto_saved_document(BigInt(doc.details.id), doc.details.name, doc.details.is_saved, doc.document);
editor.instance.openAutoSavedDocument(BigInt(doc.details.id), doc.details.name, doc.details.isSaved, doc.document);
} else {
removeDocument(doc.details.id);
}

View file

@ -48,12 +48,12 @@ export function createFontsState(editor: Editor) {
// Subscribe to process backend events
editor.subscriptions.subscribeJsMessage(TriggerFontLoad, async (triggerFontLoad) => {
const url = await getFontFileUrl(triggerFontLoad.font.font_family, triggerFontLoad.font.font_style);
const url = await getFontFileUrl(triggerFontLoad.font.fontFamily, triggerFontLoad.font.fontStyle);
if (url) {
const response = await (await fetch(url)).arrayBuffer();
editor.instance.on_font_load(triggerFontLoad.font.font_family, triggerFontLoad.font.font_style, url, new Uint8Array(response), triggerFontLoad.is_default);
editor.instance.onFontLoad(triggerFontLoad.font.fontFamily, triggerFontLoad.font.fontStyle, url, new Uint8Array(response), triggerFontLoad.isDefault);
} else {
editor.instance.error_dialog("Failed to load font", `The font ${triggerFontLoad.font.font_family} with style ${triggerFontLoad.font.font_style} does not exist`);
editor.instance.errorDialog("Failed to load font", `The font ${triggerFontLoad.font.fontFamily} with style ${triggerFontLoad.font.fontStyle} does not exist`);
}
});

View file

@ -15,21 +15,21 @@ export function createPortfolioState(editor: Editor) {
// Set up message subscriptions on creation
editor.subscriptions.subscribeJsMessage(UpdateOpenDocumentsList, (updateOpenDocumentList) => {
state.documents = updateOpenDocumentList.open_documents;
state.documents = updateOpenDocumentList.openDocuments;
});
editor.subscriptions.subscribeJsMessage(UpdateActiveDocument, (updateActiveDocument) => {
// Assume we receive a correct document id
const activeId = state.documents.findIndex((doc) => doc.id === updateActiveDocument.document_id);
const activeId = state.documents.findIndex((doc) => doc.id === updateActiveDocument.documentId);
state.activeDocumentIndex = activeId;
});
editor.subscriptions.subscribeJsMessage(TriggerOpenDocument, async () => {
const extension = editor.instance.file_save_suffix();
const extension = editor.instance.fileSaveSuffix();
const data = await upload(extension, "text");
editor.instance.open_document_file(data.filename, data.content);
editor.instance.openDocumentFile(data.filename, data.content);
});
editor.subscriptions.subscribeJsMessage(TriggerImport, async () => {
const data = await upload("image/*", "data");
editor.instance.paste_image(data.type, Uint8Array.from(data.content));
editor.instance.pasteImage(data.type, Uint8Array.from(data.content));
});
editor.subscriptions.subscribeJsMessage(TriggerFileDownload, (triggerFileDownload) => {
download(triggerFileDownload.name, triggerFileDownload.document);

View file

@ -19,7 +19,7 @@ export async function initWasm(): Promise<void> {
// Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers
const randomSeed = BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
wasmImport?.set_random_seed(randomSeed);
wasmImport?.setRandomSeed(randomSeed);
}
// Should be called after running `initWasm()` and its promise resolving

View file

@ -1,4 +1,3 @@
/* eslint-disable camelcase */
/* eslint-disable max-classes-per-file */
import { Transform, Type, plainToClass } from "class-transformer";
@ -26,7 +25,7 @@ export class UpdateNodeGraphVisibility extends JsMessage {
export class UpdateOpenDocumentsList extends JsMessage {
@Type(() => FrontendDocumentDetails)
readonly open_documents!: FrontendDocumentDetails[];
readonly openDocuments!: FrontendDocumentDetails[];
}
// Allows the auto save system to use a string for the id rather than a BigInt.
@ -36,12 +35,12 @@ export class UpdateOpenDocumentsList extends JsMessage {
export abstract class DocumentDetails {
readonly name!: string;
readonly is_saved!: boolean;
readonly isSaved!: boolean;
readonly id!: bigint | string;
get displayName(): string {
return `${this.name}${this.is_saved ? "" : "*"}`;
return `${this.name}${this.isSaved ? "" : "*"}`;
}
}
@ -66,12 +65,12 @@ export class IndexedDbDocumentDetails extends DocumentDetails {
export class TriggerIndexedDbRemoveDocument extends JsMessage {
// Use a string since IndexedDB can not use BigInts for keys
@Transform(({ value }: { value: bigint }) => value.toString())
document_id!: string;
documentId!: string;
}
export class UpdateInputHints extends JsMessage {
@Type(() => HintInfo)
readonly hint_data!: HintData;
readonly hintData!: HintData;
}
export type HintData = HintGroup[];
@ -137,11 +136,11 @@ export class Color {
}
export class UpdateActiveDocument extends JsMessage {
readonly document_id!: bigint;
readonly documentId!: bigint;
}
export class DisplayDialogPanic extends JsMessage {
readonly panic_info!: string;
readonly panicInfo!: string;
readonly header!: string;
@ -245,11 +244,11 @@ interface DataBuffer {
length: bigint;
}
export function newUpdateDocumentLayerTreeStructure(input: { data_buffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerTreeStructure {
const pointerNum = Number(input.data_buffer.pointer);
const lengthNum = Number(input.data_buffer.length);
export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerTreeStructure {
const pointerNum = Number(input.dataBuffer.pointer);
const lengthNum = Number(input.dataBuffer.length);
const wasmMemoryBuffer = wasm.wasm_memory().buffer;
const wasmMemoryBuffer = wasm.wasmMemory().buffer;
// Decode the folder structure encoding
const encoding = new DataView(wasmMemoryBuffer, pointerNum, lengthNum);
@ -302,9 +301,9 @@ export function newUpdateDocumentLayerTreeStructure(input: { data_buffer: DataBu
export class DisplayEditableTextbox extends JsMessage {
readonly text!: string;
readonly line_width!: undefined | number;
readonly lineWidth!: undefined | number;
readonly font_size!: number;
readonly fontSize!: number;
@Type(() => Color)
readonly color!: Color;
@ -312,7 +311,7 @@ export class DisplayEditableTextbox extends JsMessage {
export class UpdateImageData extends JsMessage {
@Type(() => ImageData)
readonly image_data!: ImageData[];
readonly imageData!: ImageData[];
}
export class DisplayRemoveEditableTextbox extends JsMessage {}
@ -327,13 +326,13 @@ export class LayerPanelEntry {
visible!: boolean;
layer_type!: LayerType;
layerType!: LayerType;
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
path!: BigUint64Array;
@Type(() => LayerMetadata)
layer_metadata!: LayerMetadata;
layerMetadata!: LayerMetadata;
thumbnail!: string;
}
@ -351,22 +350,22 @@ export class ImageData {
readonly mime!: string;
readonly image_data!: Uint8Array;
readonly imageData!: Uint8Array;
}
export class DisplayDialogDismiss extends JsMessage {}
export class Font {
font_family!: string;
fontFamily!: string;
font_style!: string;
fontStyle!: string;
}
export class TriggerFontLoad extends JsMessage {
@Type(() => Font)
font!: Font;
is_default!: boolean;
isDefault!: boolean;
}
export class TriggerVisitLink extends JsMessage {
@ -376,11 +375,11 @@ export class TriggerVisitLink extends JsMessage {
export class TriggerTextCommit extends JsMessage {}
export class TriggerTextCopy extends JsMessage {
readonly copy_text!: string;
readonly copyText!: string;
}
export class TriggerAboutGraphiteLocalizedCommitDate extends JsMessage {
readonly commit_date!: string;
readonly commitDate!: string;
}
export class TriggerViewportResize extends JsMessage {}
@ -647,13 +646,13 @@ function hoistWidgetHolders(widgetHolders: any[]): Widget[] {
// WIDGET LAYOUT
export interface WidgetLayout {
layout_target: unknown;
layoutTarget: unknown;
layout: LayoutGroup[];
}
export function defaultWidgetLayout(): WidgetLayout {
return {
layout_target: null,
layoutTarget: null,
layout: [],
};
}
@ -708,7 +707,7 @@ function createWidgetLayout(widgetLayout: any[]): LayoutGroup[] {
// WIDGET LAYOUTS
export class UpdateDialogDetails extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -717,7 +716,7 @@ export class UpdateDialogDetails extends JsMessage implements WidgetLayout {
}
export class UpdateDocumentModeLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -726,7 +725,7 @@ export class UpdateDocumentModeLayout extends JsMessage implements WidgetLayout
}
export class UpdateToolOptionsLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -735,7 +734,7 @@ export class UpdateToolOptionsLayout extends JsMessage implements WidgetLayout {
}
export class UpdateDocumentBarLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -744,7 +743,7 @@ export class UpdateDocumentBarLayout extends JsMessage implements WidgetLayout {
}
export class UpdateToolShelfLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -753,7 +752,7 @@ export class UpdateToolShelfLayout extends JsMessage implements WidgetLayout {
}
export class UpdateWorkingColorsLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -762,7 +761,7 @@ export class UpdateWorkingColorsLayout extends JsMessage implements WidgetLayout
}
export class UpdatePropertyPanelOptionsLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -771,7 +770,7 @@ export class UpdatePropertyPanelOptionsLayout extends JsMessage implements Widge
}
export class UpdatePropertyPanelSectionsLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -780,7 +779,7 @@ export class UpdatePropertyPanelSectionsLayout extends JsMessage implements Widg
}
export class UpdateLayerTreeOptionsLayout extends JsMessage implements WidgetLayout {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -789,7 +788,7 @@ export class UpdateLayerTreeOptionsLayout extends JsMessage implements WidgetLay
}
export class UpdateMenuBarLayout extends JsMessage {
layout_target!: unknown;
layoutTarget!: unknown;
// TODO: Replace `any` with correct typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View file

@ -11,7 +11,7 @@ module.exports = {
chainWebpack: (config) => {
// WASM Pack Plugin integrates compiled Rust code (.wasm) and generated wasm-bindgen code (.js) with the webpack bundle
// Use this JS to import the bundled Rust entry points: const wasm = import("@/../wasm/pkg").then(panicProxy);
// Then call WASM functions with: (await wasm).function_name()
// Then call WASM functions with: (await wasm).functionName()
// https://github.com/wasm-tool/wasm-pack-plugin
config
// https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-plugin

View file

@ -23,13 +23,13 @@ use wasm_bindgen::prelude::*;
/// Set the random seed used by the editor by calling this from JS upon initialization.
/// This is necessary because WASM doesn't have a random number generator.
#[wasm_bindgen]
#[wasm_bindgen(js_name = setRandomSeed)]
pub fn set_random_seed(seed: u64) {
editor::application::set_uuid_seed(seed);
}
/// Provides a handle to access the raw WASM memory
#[wasm_bindgen]
#[wasm_bindgen(js_name = wasmMemory)]
pub fn wasm_memory() -> JsValue {
wasm_bindgen::memory()
}
@ -111,6 +111,7 @@ impl JsEditorHandle {
// the backend from the web frontend.
// ========================================================================
#[wasm_bindgen(js_name = initAfterFrontendReady)]
pub fn init_after_frontend_ready(&self, platform: String) {
let platform = match platform.as_str() {
"Windows" => Platform::Windows,
@ -124,29 +125,32 @@ impl JsEditorHandle {
}
/// Displays a dialog with an error message
#[wasm_bindgen(js_name = errorDialog)]
pub fn error_dialog(&self, title: String, description: String) {
let message = DialogMessage::DisplayDialogError { title, description };
self.dispatch(message);
}
/// Answer whether or not the editor has crashed
#[wasm_bindgen(js_name = hasCrashed)]
pub fn has_crashed(&self) -> bool {
EDITOR_HAS_CRASHED.load(Ordering::SeqCst)
}
/// Get the constant `FILE_SAVE_SUFFIX`
#[wasm_bindgen]
#[wasm_bindgen(js_name = fileSaveSuffix)]
pub fn file_save_suffix(&self) -> String {
FILE_SAVE_SUFFIX.into()
}
/// Get the constant `GRAPHITE_DOCUMENT_VERSION`
#[wasm_bindgen]
#[wasm_bindgen(js_name = graphiteDocumentVersion)]
pub fn graphite_document_version(&self) -> String {
GRAPHITE_DOCUMENT_VERSION.to_string()
}
/// Update layout of a given UI
#[wasm_bindgen(js_name = updateLayout)]
pub fn update_layout(&self, layout_target: JsValue, widget_id: u64, value: JsValue) -> Result<(), JsValue> {
match (from_value(layout_target), from_value(value)) {
(Ok(layout_target), Ok(value)) => {
@ -158,21 +162,25 @@ impl JsEditorHandle {
}
}
#[wasm_bindgen(js_name = selectDocument)]
pub fn select_document(&self, document_id: u64) {
let message = PortfolioMessage::SelectDocument { document_id };
self.dispatch(message);
}
#[wasm_bindgen(js_name = newDocumentDialog)]
pub fn new_document_dialog(&self) {
let message = DialogMessage::RequestNewDocumentDialog;
self.dispatch(message);
}
#[wasm_bindgen(js_name = documentOpen)]
pub fn document_open(&self) {
let message = PortfolioMessage::OpenDocument;
self.dispatch(message);
}
#[wasm_bindgen(js_name = openDocumentFile)]
pub fn open_document_file(&self, document_name: String, document_serialized_content: String) {
let message = PortfolioMessage::OpenDocumentFile {
document_name,
@ -181,6 +189,7 @@ impl JsEditorHandle {
self.dispatch(message);
}
#[wasm_bindgen(js_name = openAutoSavedDocument)]
pub fn open_auto_saved_document(&self, document_id: u64, document_name: String, document_is_saved: bool, document_serialized_content: String) {
let message = PortfolioMessage::OpenDocumentFileWithId {
document_id,
@ -191,21 +200,25 @@ impl JsEditorHandle {
self.dispatch(message);
}
#[wasm_bindgen(js_name = triggerAutoSave)]
pub fn trigger_auto_save(&self, document_id: u64) {
let message = PortfolioMessage::AutoSaveDocument { document_id };
self.dispatch(message);
}
#[wasm_bindgen(js_name = closeDocumentWithConfirmation)]
pub fn close_document_with_confirmation(&self, document_id: u64) {
let message = PortfolioMessage::CloseDocumentWithConfirmation { document_id };
self.dispatch(message);
}
#[wasm_bindgen(js_name = requestAboutGraphiteDialogWithLocalizedCommitDate)]
pub fn request_about_graphite_dialog_with_localized_commit_date(&self, localized_commit_date: String) {
let message = DialogMessage::RequestAboutGraphiteDialogWithLocalizedCommitDate { localized_commit_date };
self.dispatch(message);
}
#[wasm_bindgen(js_name = requestComingSoonDialog)]
pub fn request_coming_soon_dialog(&self, issue: Option<i32>) {
let message = DialogMessage::RequestComingSoonDialog { issue };
self.dispatch(message);
@ -213,6 +226,7 @@ impl JsEditorHandle {
/// Send new bounds when document panel viewports get resized or moved within the editor
/// [left, top, right, bottom]...
#[wasm_bindgen(js_name = boundsOfViewports)]
pub fn bounds_of_viewports(&self, bounds_of_viewports: &[f64]) {
let chunked: Vec<_> = bounds_of_viewports.chunks(4).map(ViewportBounds::from_slice).collect();
@ -221,6 +235,7 @@ impl JsEditorHandle {
}
/// Mouse movement within the screenspace bounds of the viewport
#[wasm_bindgen(js_name = onMouseMove)]
pub fn on_mouse_move(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
@ -231,6 +246,7 @@ impl JsEditorHandle {
}
/// Mouse scrolling within the screenspace bounds of the viewport
#[wasm_bindgen(js_name = onWheelScroll)]
pub fn on_wheel_scroll(&self, x: f64, y: f64, mouse_keys: u8, wheel_delta_x: i32, wheel_delta_y: i32, wheel_delta_z: i32, modifiers: u8) {
let mut editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z);
@ -242,6 +258,7 @@ impl JsEditorHandle {
}
/// A mouse button depressed within screenspace the bounds of the viewport
#[wasm_bindgen(js_name = onMouseDown)]
pub fn on_mouse_down(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
@ -252,6 +269,7 @@ impl JsEditorHandle {
}
/// A mouse button released
#[wasm_bindgen(js_name = onMouseUp)]
pub fn on_mouse_up(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
@ -262,6 +280,7 @@ impl JsEditorHandle {
}
/// Mouse double clicked
#[wasm_bindgen(js_name = onDoubleClick)]
pub fn on_double_click(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) {
let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into());
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
@ -271,6 +290,7 @@ impl JsEditorHandle {
}
/// A keyboard button depressed within screenspace the bounds of the viewport
#[wasm_bindgen(js_name = onKeyDown)]
pub fn on_key_down(&self, name: String, modifiers: u8) {
let key = translate_key(&name);
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
@ -282,6 +302,7 @@ impl JsEditorHandle {
}
/// A keyboard button released
#[wasm_bindgen(js_name = onKeyUp)]
pub fn on_key_up(&self, name: String, modifiers: u8) {
let key = translate_key(&name);
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
@ -293,6 +314,7 @@ impl JsEditorHandle {
}
/// A text box was committed
#[wasm_bindgen(js_name = onChangeText)]
pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> {
let message = TextToolMessage::TextChange { new_text };
self.dispatch(message);
@ -301,6 +323,7 @@ impl JsEditorHandle {
}
/// A font has been downloaded
#[wasm_bindgen(js_name = onFontLoad)]
pub fn on_font_load(&self, font_family: String, font_style: String, preview_url: String, data: Vec<u8>, is_default: bool) -> Result<(), JsValue> {
let message = PortfolioMessage::FontLoaded {
font_family,
@ -315,6 +338,7 @@ impl JsEditorHandle {
}
/// A text box was changed
#[wasm_bindgen(js_name = updateBounds)]
pub fn update_bounds(&self, new_text: String) -> Result<(), JsValue> {
let message = TextToolMessage::UpdateBounds { new_text };
self.dispatch(message);
@ -323,6 +347,7 @@ impl JsEditorHandle {
}
/// Update primary color
#[wasm_bindgen(js_name = updatePrimaryColor)]
pub fn update_primary_color(&self, red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> {
let primary_color = match Color::from_rgbaf32(red, green, blue, alpha) {
Some(color) => color,
@ -336,6 +361,7 @@ impl JsEditorHandle {
}
/// Update secondary color
#[wasm_bindgen(js_name = updateSecondaryColor)]
pub fn update_secondary_color(&self, red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> {
let secondary_color = match Color::from_rgbaf32(red, green, blue, alpha) {
Some(color) => color,
@ -349,24 +375,28 @@ impl JsEditorHandle {
}
/// Paste layers from a serialized json representation
#[wasm_bindgen(js_name = pasteSerializedData)]
pub fn paste_serialized_data(&self, data: String) {
let message = PortfolioMessage::PasteSerializedData { data };
self.dispatch(message);
}
/// Modify the layer selection based on the layer which is clicked while holding down the <kbd>Ctrl</kbd> and/or <kbd>Shift</kbd> modifier keys used for range selection behavior
#[wasm_bindgen(js_name = selectLayer)]
pub fn select_layer(&self, layer_path: Vec<LayerId>, ctrl: bool, shift: bool) {
let message = DocumentMessage::SelectLayer { layer_path, ctrl, shift };
self.dispatch(message);
}
/// Deselect all layers
#[wasm_bindgen(js_name = deselectAllLayers)]
pub fn deselect_all_layers(&self) {
let message = DocumentMessage::DeselectAllLayers;
self.dispatch(message);
}
/// Move a layer to be next to the specified neighbor
#[wasm_bindgen(js_name = moveLayerInTree)]
pub fn move_layer_in_tree(&self, folder_path: Vec<LayerId>, insert_index: isize) {
let message = DocumentMessage::MoveSelectedLayersTo {
folder_path,
@ -377,24 +407,28 @@ impl JsEditorHandle {
}
/// Set the name for the layer
#[wasm_bindgen(js_name = setLayerName)]
pub fn set_layer_name(&self, layer_path: Vec<LayerId>, name: String) {
let message = DocumentMessage::SetLayerName { layer_path, name };
self.dispatch(message);
}
/// Translates document (in viewport coords)
#[wasm_bindgen(js_name = translateCanvas)]
pub fn translate_canvas(&self, delta_x: f64, delta_y: f64) {
let message = NavigationMessage::TranslateCanvas { delta: (delta_x, delta_y).into() };
self.dispatch(message);
}
/// Translates document (in viewport coords)
#[wasm_bindgen(js_name = translateCanvasByFraction)]
pub fn translate_canvas_by_fraction(&self, delta_x: f64, delta_y: f64) {
let message = NavigationMessage::TranslateCanvasByViewportFraction { delta: (delta_x, delta_y).into() };
self.dispatch(message);
}
/// Sends the blob url generated by js
#[wasm_bindgen(js_name = setImageBlobUrl)]
pub fn set_image_blob_url(&self, path: Vec<LayerId>, blob_url: String, width: f64, height: f64) {
let dimensions = (width, height);
let message = Operation::SetImageBlobUrl { path, blob_url, dimensions };
@ -402,6 +436,7 @@ impl JsEditorHandle {
}
/// Pastes an image
#[wasm_bindgen(js_name = pasteImage)]
pub fn paste_image(&self, mime: String, image_data: Vec<u8>, mouse_x: Option<f64>, mouse_y: Option<f64>) {
let mouse = mouse_x.and_then(|x| mouse_y.map(|y| (x, y)));
let message = DocumentMessage::PasteImage { mime, image_data, mouse };
@ -409,12 +444,14 @@ impl JsEditorHandle {
}
/// Toggle visibility of a layer from the layer list
#[wasm_bindgen(js_name = toggleLayerVisibility)]
pub fn toggle_layer_visibility(&self, layer_path: Vec<LayerId>) {
let message = DocumentMessage::ToggleLayerVisibility { layer_path };
self.dispatch(message);
}
/// Toggle expansions state of a layer from the layer list
#[wasm_bindgen(js_name = toggleLayerExpansion)]
pub fn toggle_layer_expansion(&self, layer_path: Vec<LayerId>) {
let message = DocumentMessage::ToggleLayerExpansion { layer_path };
self.dispatch(message);