Set the mouse cursor in the canvas based on the current tool and its state (#480)

* Add FrontendMouseCursor and DisplayMouseCursor

* Add update_cursor method to the Fsm trait and implement it for all tools

* Rename DisplayMouseCursor to UpdateMouseCursor

* Add 'To CSS Cursor Property' transform decorator and change the mouse cursor in the canvas based on the current tool and its state

* Implement update_cursor for Navigate tool properly

* Keep the cursor when dragging outside of the canvas

* Change the mouse cursor to 'zoom-in' when LMB dragging on canvas with Navigate tool

* Rename FrontendMouseCursor to MouseCursorIcon

* Rename 'event' to 'e' and replace v-on with @

* Change the definition of the MouseCursorIcon type in TS

* Replace switch with dictionary look-up

* Move the definition of MouseCursorIcon closer to where it's used
This commit is contained in:
asyncth 2022-01-16 12:57:03 +05:00 committed by Keavon Chambers
parent e877eea457
commit 0515cc4eca
17 changed files with 163 additions and 4 deletions

View file

@ -123,7 +123,7 @@
<CanvasRuler :origin="rulerOrigin.y" :majorMarkSpacing="rulerSpacing" :numberInterval="rulerInterval" :direction="'Vertical'" />
</LayoutCol>
<LayoutCol :class="'canvas-area'">
<div class="canvas" ref="canvas">
<div class="canvas" ref="canvas" :style="{ cursor: canvasCursor }" @pointerdown="(e: PointerEvent) => canvasPointerDown(e)">
<svg class="artboards" v-html="artboardSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
<svg class="artwork" v-html="artworkSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
<svg class="overlays" v-html="overlaysSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
@ -261,6 +261,7 @@ import {
UpdateCanvasRotation,
ToolName,
UpdateDocumentArtboards,
UpdateMouseCursor,
} from "@/dispatcher/js-messages";
import LayoutCol from "@/components/layout/LayoutCol.vue";
@ -338,6 +339,10 @@ export default defineComponent({
resetWorkingColors() {
this.editor.instance.reset_colors();
},
canvasPointerDown(e: PointerEvent) {
const canvas = this.$refs.canvas as HTMLElement;
canvas.setPointerCapture(e.pointerId);
},
},
mounted() {
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
@ -378,6 +383,10 @@ export default defineComponent({
this.documentRotation = (360 + (newRotation % 360)) % 360;
});
this.editor.dispatcher.subscribeJsMessage(UpdateMouseCursor, (updateMouseCursor) => {
this.canvasCursor = updateMouseCursor.cursor;
});
window.addEventListener("resize", this.viewportResize);
window.addEventListener("DOMContentLoaded", this.viewportResize);
},
@ -401,6 +410,7 @@ export default defineComponent({
overlaysSvg: "",
canvasSvgWidth: "100%",
canvasSvgHeight: "100%",
canvasCursor: "default",
activeTool: "Select" as ToolName,
activeToolOptions: {},
documentModeEntries,

View file

@ -201,6 +201,24 @@ export class UpdateDocumentRulers extends JsMessage {
readonly interval!: number;
}
export type MouseCursorIcon = "default" | "zoom-in" | "zoom-out" | "grabbing" | "crosshair";
const ToCssCursorProperty = Transform(({ value }) => {
const cssNames: Record<string, MouseCursorIcon> = {
ZoomIn: "zoom-in",
ZoomOut: "zoom-out",
Grabbing: "grabbing",
Crosshair: "crosshair",
};
return cssNames[value] || "default";
});
export class UpdateMouseCursor extends JsMessage {
@ToCssCursorProperty
readonly cursor!: MouseCursorIcon;
}
export class TriggerFileDownload extends JsMessage {
readonly document!: string;
@ -378,6 +396,7 @@ export const messageConstructors: Record<string, MessageMaker> = {
UpdateWorkingColors,
UpdateCanvasZoom,
UpdateCanvasRotation,
UpdateMouseCursor,
DisplayDialogError,
DisplayDialogPanic,
DisplayConfirmationToCloseDocument,