mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 22:28:11 +08:00
Change mouse to pointer events (#403)
* Change mouse to pointer events * Add `npm start` command * Change all mouse to pointer events; Fix `touch-action: none;` * Merge with master * Fix middle mouse click * Remove console.log * Delete the empty line * Re-add middle click auto-scroll blocking Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
583e0e87bc
commit
3b7a5548ae
@@ -214,7 +214,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
open: false,
|
open: false,
|
||||||
mouseStillDown: false,
|
pointerStillDown: false,
|
||||||
containerResizeObserver,
|
containerResizeObserver,
|
||||||
MenuDirection,
|
MenuDirection,
|
||||||
MenuType,
|
MenuType,
|
||||||
@@ -312,23 +312,23 @@ export default defineComponent({
|
|||||||
const floatingMenuContent = this.$refs.floatingMenuContent as HTMLElement;
|
const floatingMenuContent = this.$refs.floatingMenuContent as HTMLElement;
|
||||||
floatingMenuContent.style.minWidth = minWidth;
|
floatingMenuContent.style.minWidth = minWidth;
|
||||||
},
|
},
|
||||||
mouseMoveHandler(e: MouseEvent) {
|
pointerMoveHandler(e: PointerEvent) {
|
||||||
const MOUSE_STRAY_DISTANCE = 100;
|
const POINTER_STRAY_DISTANCE = 100;
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
const mouseOverFloatingMenuKeepOpen = target && (target.closest("[data-hover-menu-keep-open]") as HTMLElement);
|
const pointerOverFloatingMenuKeepOpen = target && (target.closest("[data-hover-menu-keep-open]") as HTMLElement);
|
||||||
const mouseOverFloatingMenuSpawner = target && (target.closest("[data-hover-menu-spawner]") as HTMLElement);
|
const pointerOverFloatingMenuSpawner = target && (target.closest("[data-hover-menu-spawner]") as HTMLElement);
|
||||||
// TODO: Simplify the following expression when optional chaining is supported by the build system
|
// TODO: Simplify the following expression when optional chaining is supported by the build system
|
||||||
const mouseOverOwnFloatingMenuSpawner =
|
const pointerOverOwnFloatingMenuSpawner =
|
||||||
mouseOverFloatingMenuSpawner && mouseOverFloatingMenuSpawner.parentElement && mouseOverFloatingMenuSpawner.parentElement.contains(this.$refs.floatingMenu as HTMLElement);
|
pointerOverFloatingMenuSpawner && pointerOverFloatingMenuSpawner.parentElement && pointerOverFloatingMenuSpawner.parentElement.contains(this.$refs.floatingMenu as HTMLElement);
|
||||||
|
|
||||||
// Swap this open floating menu with the one created by the floating menu spawner being hovered over
|
// Swap this open floating menu with the one created by the floating menu spawner being hovered over
|
||||||
if (mouseOverFloatingMenuSpawner && !mouseOverOwnFloatingMenuSpawner) {
|
if (pointerOverFloatingMenuSpawner && !pointerOverOwnFloatingMenuSpawner) {
|
||||||
this.setClosed();
|
this.setClosed();
|
||||||
mouseOverFloatingMenuSpawner.click();
|
pointerOverFloatingMenuSpawner.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the floating menu if the mouse has strayed far enough from its bounds
|
// Close the floating menu if the pointer has strayed far enough from its bounds
|
||||||
if (this.isMouseEventOutsideFloatingMenu(e, MOUSE_STRAY_DISTANCE) && !mouseOverOwnFloatingMenuSpawner && !mouseOverFloatingMenuKeepOpen) {
|
if (this.isPointerEventOutsideFloatingMenu(e, POINTER_STRAY_DISTANCE) && !pointerOverOwnFloatingMenuSpawner && !pointerOverFloatingMenuKeepOpen) {
|
||||||
// TODO: Extend this rectangle bounds check to all `data-hover-menu-keep-open` element bounds up the DOM tree since currently
|
// TODO: Extend this rectangle bounds check to all `data-hover-menu-keep-open` element bounds up the DOM tree since currently
|
||||||
// submenus disappear with zero stray distance if the cursor is further than the stray distance from only the top-level menu
|
// submenus disappear with zero stray distance if the cursor is further than the stray distance from only the top-level menu
|
||||||
this.setClosed();
|
this.setClosed();
|
||||||
@@ -336,31 +336,31 @@ export default defineComponent({
|
|||||||
|
|
||||||
const eventIncludesLmb = Boolean(e.buttons & 1);
|
const eventIncludesLmb = Boolean(e.buttons & 1);
|
||||||
|
|
||||||
// Clean up any messes from lost mouseup events
|
// Clean up any messes from lost pointerup events
|
||||||
if (!this.open && !eventIncludesLmb) {
|
if (!this.open && !eventIncludesLmb) {
|
||||||
this.mouseStillDown = false;
|
this.pointerStillDown = false;
|
||||||
window.removeEventListener("mouseup", this.mouseUpHandler);
|
window.removeEventListener("pointerup", this.pointerUpHandler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mouseDownHandler(e: MouseEvent) {
|
pointerDownHandler(e: PointerEvent) {
|
||||||
// Close the floating menu if the mouse clicked outside the floating menu (but within stray distance)
|
// Close the floating menu if the pointer clicked outside the floating menu (but within stray distance)
|
||||||
if (this.isMouseEventOutsideFloatingMenu(e)) {
|
if (this.isPointerEventOutsideFloatingMenu(e)) {
|
||||||
this.setClosed();
|
this.setClosed();
|
||||||
|
|
||||||
// Track if the left mouse button is now down so its later click event can be canceled
|
// Track if the left pointer button is now down so its later click event can be canceled
|
||||||
const eventIsForLmb = e.button === 0;
|
const eventIsForLmb = e.button === 0;
|
||||||
if (eventIsForLmb) this.mouseStillDown = true;
|
if (eventIsForLmb) this.pointerStillDown = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mouseUpHandler(e: MouseEvent) {
|
pointerUpHandler(e: PointerEvent) {
|
||||||
const eventIsForLmb = e.button === 0;
|
const eventIsForLmb = e.button === 0;
|
||||||
|
|
||||||
if (this.mouseStillDown && eventIsForLmb) {
|
if (this.pointerStillDown && eventIsForLmb) {
|
||||||
// Clean up self
|
// Clean up self
|
||||||
this.mouseStillDown = false;
|
this.pointerStillDown = false;
|
||||||
window.removeEventListener("mouseup", this.mouseUpHandler);
|
window.removeEventListener("pointerup", this.pointerUpHandler);
|
||||||
|
|
||||||
// Prevent the click event from firing, which would normally occur right after this mouseup event
|
// Prevent the click event from firing, which would normally occur right after this pointerup event
|
||||||
window.addEventListener("click", this.clickHandlerCapture, true);
|
window.addEventListener("click", this.clickHandlerCapture, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -371,12 +371,12 @@ export default defineComponent({
|
|||||||
// Clean up self
|
// Clean up self
|
||||||
window.removeEventListener("click", this.clickHandlerCapture, true);
|
window.removeEventListener("click", this.clickHandlerCapture, true);
|
||||||
},
|
},
|
||||||
isMouseEventOutsideFloatingMenu(e: MouseEvent, extraDistanceAllowed = 0): boolean {
|
isPointerEventOutsideFloatingMenu(e: PointerEvent, extraDistanceAllowed = 0): boolean {
|
||||||
// Considers all child menus as well as the top-level one.
|
// Considers all child menus as well as the top-level one.
|
||||||
const allContainedFloatingMenus = [...this.$el.querySelectorAll(".floating-menu-content")];
|
const allContainedFloatingMenus = [...this.$el.querySelectorAll(".floating-menu-content")];
|
||||||
return !allContainedFloatingMenus.find((element) => !this.isMouseEventOutsideMenuElement(e, element, extraDistanceAllowed));
|
return !allContainedFloatingMenus.find((element) => !this.isPointerEventOutsideMenuElement(e, element, extraDistanceAllowed));
|
||||||
},
|
},
|
||||||
isMouseEventOutsideMenuElement(e: MouseEvent, element: HTMLElement, extraDistanceAllowed = 0): boolean {
|
isPointerEventOutsideMenuElement(e: PointerEvent, element: HTMLElement, extraDistanceAllowed = 0): boolean {
|
||||||
const floatingMenuBounds = element.getBoundingClientRect();
|
const floatingMenuBounds = element.getBoundingClientRect();
|
||||||
if (floatingMenuBounds.left - e.clientX >= extraDistanceAllowed) return true;
|
if (floatingMenuBounds.left - e.clientX >= extraDistanceAllowed) return true;
|
||||||
if (e.clientX - floatingMenuBounds.right >= extraDistanceAllowed) return true;
|
if (e.clientX - floatingMenuBounds.right >= extraDistanceAllowed) return true;
|
||||||
@@ -389,14 +389,14 @@ export default defineComponent({
|
|||||||
open(newState: boolean, oldState: boolean) {
|
open(newState: boolean, oldState: boolean) {
|
||||||
// Switching from closed to open
|
// Switching from closed to open
|
||||||
if (newState && !oldState) {
|
if (newState && !oldState) {
|
||||||
// Close floating menu if mouse strays far enough away
|
// Close floating menu if pointer strays far enough away
|
||||||
window.addEventListener("mousemove", this.mouseMoveHandler);
|
window.addEventListener("pointermove", this.pointerMoveHandler);
|
||||||
|
|
||||||
// Close floating menu if mouse is outside (but within stray distance)
|
// Close floating menu if pointer is outside (but within stray distance)
|
||||||
window.addEventListener("mousedown", this.mouseDownHandler);
|
window.addEventListener("pointerdown", this.pointerDownHandler);
|
||||||
|
|
||||||
// Cancel the subsequent click event to prevent the floating menu from reopening if the floating menu's button is the click event target
|
// Cancel the subsequent click event to prevent the floating menu from reopening if the floating menu's button is the click event target
|
||||||
window.addEventListener("mouseup", this.mouseUpHandler);
|
window.addEventListener("pointerup", this.pointerUpHandler);
|
||||||
|
|
||||||
// Floating menu min-width resize observer
|
// Floating menu min-width resize observer
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@@ -410,8 +410,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
// Switching from open to closed
|
// Switching from open to closed
|
||||||
if (!newState && oldState) {
|
if (!newState && oldState) {
|
||||||
window.removeEventListener("mousemove", this.mouseMoveHandler);
|
window.removeEventListener("pointermove", this.pointerMoveHandler);
|
||||||
window.removeEventListener("mousedown", this.mouseDownHandler);
|
window.removeEventListener("pointerdown", this.pointerDownHandler);
|
||||||
|
|
||||||
this.containerResizeObserver.disconnect();
|
this.containerResizeObserver.disconnect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
class="row"
|
class="row"
|
||||||
:class="{ open: isMenuEntryOpen(entry), active: entry === activeEntry }"
|
:class="{ open: isMenuEntryOpen(entry), active: entry === activeEntry }"
|
||||||
@click="handleEntryClick(entry)"
|
@click="handleEntryClick(entry)"
|
||||||
@mouseenter="handleEntryMouseEnter(entry)"
|
@pointerenter="handleEntryPointerEnter(entry)"
|
||||||
@mouseleave="handleEntryMouseLeave(entry)"
|
@pointerleave="handleEntryPointerLeave(entry)"
|
||||||
:data-hover-menu-spawner-extend="entry.children && []"
|
:data-hover-menu-spawner-extend="entry.children && []"
|
||||||
>
|
>
|
||||||
<CheckboxInput v-if="entry.checkbox" v-model:checked="entry.checked" :outlineStyle="true" :class="'entry-checkbox'" />
|
<CheckboxInput v-if="entry.checkbox" v-model:checked="entry.checked" :outlineStyle="true" :class="'entry-checkbox'" />
|
||||||
@@ -184,13 +184,13 @@ const MenuList = defineComponent({
|
|||||||
|
|
||||||
this.$emit("update:activeEntry", menuEntry);
|
this.$emit("update:activeEntry", menuEntry);
|
||||||
},
|
},
|
||||||
handleEntryMouseEnter(menuEntry: MenuListEntry) {
|
handleEntryPointerEnter(menuEntry: MenuListEntry) {
|
||||||
if (!menuEntry.children || !menuEntry.children.length) return;
|
if (!menuEntry.children || !menuEntry.children.length) return;
|
||||||
|
|
||||||
if (menuEntry.ref) menuEntry.ref.setOpen();
|
if (menuEntry.ref) menuEntry.ref.setOpen();
|
||||||
else throw new Error("The menu bar floating menu has no associated ref");
|
else throw new Error("The menu bar floating menu has no associated ref");
|
||||||
},
|
},
|
||||||
handleEntryMouseLeave(menuEntry: MenuListEntry) {
|
handleEntryPointerLeave(menuEntry: MenuListEntry) {
|
||||||
if (!menuEntry.children || !menuEntry.children.length) return;
|
if (!menuEntry.children || !menuEntry.children.length) return;
|
||||||
|
|
||||||
if (menuEntry.ref) menuEntry.ref.setClosed();
|
if (menuEntry.ref) menuEntry.ref.setClosed();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="persistent-scrollbar" :class="direction.toLowerCase()">
|
<div class="persistent-scrollbar" :class="direction.toLowerCase()">
|
||||||
<button class="arrow decrease" @mousedown="changePosition(-50)"></button>
|
<button class="arrow decrease" @pointerdown="changePosition(-50)"></button>
|
||||||
<div class="scroll-track" ref="scrollTrack" @mousedown="grabArea">
|
<div class="scroll-track" ref="scrollTrack" @pointerdown="grabArea">
|
||||||
<div class="scroll-thumb" @mousedown="grabHandle" :class="{ dragging }" ref="handle" :style="[thumbStart, thumbEnd, sides]"></div>
|
<div class="scroll-thumb" @pointerdown="grabHandle" :class="{ dragging }" ref="handle" :style="[thumbStart, thumbEnd, sides]"></div>
|
||||||
</div>
|
</div>
|
||||||
<button class="arrow increase" @click="changePosition(50)"></button>
|
<button class="arrow increase" @click="changePosition(50)"></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +117,7 @@ const lerp = (x: number, y: number, a: number) => x * (1 - a) + y * a;
|
|||||||
// This includes the 1/2 handle length gap of the possible handle positionson each side so the end of the handle doesn't go off the track.
|
// This includes the 1/2 handle length gap of the possible handle positionson each side so the end of the handle doesn't go off the track.
|
||||||
const handleToTrack = (handleLen: number, handlePos: number) => lerp(handleLen / 2, 1 - handleLen / 2, handlePos);
|
const handleToTrack = (handleLen: number, handlePos: number) => lerp(handleLen / 2, 1 - handleLen / 2, handlePos);
|
||||||
|
|
||||||
const mousePosition = (direction: ScrollbarDirection, e: MouseEvent) => (direction === ScrollbarDirection.Vertical ? e.clientY : e.clientX);
|
const pointerPosition = (direction: ScrollbarDirection, e: PointerEvent) => (direction === ScrollbarDirection.Vertical ? e.clientY : e.clientX);
|
||||||
|
|
||||||
export enum ScrollbarDirection {
|
export enum ScrollbarDirection {
|
||||||
"Horizontal" = "Horizontal",
|
"Horizontal" = "Horizontal",
|
||||||
@@ -149,14 +149,12 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
ScrollbarDirection,
|
ScrollbarDirection,
|
||||||
dragging: false,
|
dragging: false,
|
||||||
mousePos: 0,
|
pointerPos: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener("mouseup", () => {
|
window.addEventListener("pointerup", this.pointerUp);
|
||||||
this.dragging = false;
|
window.addEventListener("pointermove", this.pointerMove);
|
||||||
});
|
|
||||||
window.addEventListener("mousemove", this.mouseMove);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
trackLength(): number {
|
trackLength(): number {
|
||||||
@@ -171,28 +169,28 @@ export default defineComponent({
|
|||||||
const clampedPosition = Math.min(Math.max(newPos, 0), 1);
|
const clampedPosition = Math.min(Math.max(newPos, 0), 1);
|
||||||
this.$emit("update:handlePosition", clampedPosition);
|
this.$emit("update:handlePosition", clampedPosition);
|
||||||
},
|
},
|
||||||
updateHandlePosition(e: MouseEvent) {
|
updateHandlePosition(e: PointerEvent) {
|
||||||
const position = mousePosition(this.direction, e);
|
const position = pointerPosition(this.direction, e);
|
||||||
this.clampHandlePosition(this.handlePosition + (position - this.mousePos) / (this.trackLength() * (1 - this.handleLength)));
|
this.clampHandlePosition(this.handlePosition + (position - this.pointerPos) / (this.trackLength() * (1 - this.handleLength)));
|
||||||
this.mousePos = position;
|
this.pointerPos = position;
|
||||||
},
|
},
|
||||||
grabHandle(e: MouseEvent) {
|
grabHandle(e: PointerEvent) {
|
||||||
if (!this.dragging) {
|
if (!this.dragging) {
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
this.mousePos = mousePosition(this.direction, e);
|
this.pointerPos = pointerPosition(this.direction, e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
grabArea(e: MouseEvent) {
|
grabArea(e: PointerEvent) {
|
||||||
if (!this.dragging) {
|
if (!this.dragging) {
|
||||||
const mousePos = mousePosition(this.direction, e);
|
const pointerPos = pointerPosition(this.direction, e);
|
||||||
const oldMouse = handleToTrack(this.handleLength, this.handlePosition) * this.trackLength() + this.trackOffset();
|
const oldPointer = handleToTrack(this.handleLength, this.handlePosition) * this.trackLength() + this.trackOffset();
|
||||||
this.$emit("pressTrack", mousePos - oldMouse);
|
this.$emit("pressTrack", pointerPos - oldPointer);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mouseUp() {
|
pointerUp() {
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
},
|
},
|
||||||
mouseMove(e: MouseEvent) {
|
pointerMove(e: PointerEvent) {
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
this.updateHandlePosition(e);
|
this.updateHandlePosition(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
.main-window {
|
.main-window {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-bar-row {
|
.title-bar-row {
|
||||||
|
|||||||
@@ -18,13 +18,16 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
{ target: window.document, eventName: "fullscreenchange", action: () => fullscreen.fullscreenModeChanged() },
|
{ target: window.document, eventName: "fullscreenchange", action: () => fullscreen.fullscreenModeChanged() },
|
||||||
{ target: window, eventName: "keyup", action: (e) => onKeyUp(e) },
|
{ target: window, eventName: "keyup", action: (e) => onKeyUp(e) },
|
||||||
{ target: window, eventName: "keydown", action: (e) => onKeyDown(e) },
|
{ target: window, eventName: "keydown", action: (e) => onKeyDown(e) },
|
||||||
{ target: window, eventName: "mousemove", action: (e) => onMouseMove(e) },
|
{ target: window, eventName: "pointermove", action: (e) => onPointerMove(e) },
|
||||||
|
{ target: window, eventName: "pointerdown", action: (e) => onPointerDown(e) },
|
||||||
|
{ target: window, eventName: "pointerup", action: (e) => onPointerUp(e) },
|
||||||
{ target: window, eventName: "mousedown", action: (e) => onMouseDown(e) },
|
{ target: window, eventName: "mousedown", action: (e) => onMouseDown(e) },
|
||||||
{ target: window, eventName: "mouseup", action: (e) => onMouseUp(e) },
|
|
||||||
{ target: window, eventName: "wheel", action: (e) => onMouseScroll(e), options: { passive: false } },
|
{ target: window, eventName: "wheel", action: (e) => onMouseScroll(e), options: { passive: false } },
|
||||||
];
|
];
|
||||||
|
|
||||||
let viewportMouseInteractionOngoing = false;
|
let viewportPointerInteractionOngoing = false;
|
||||||
|
|
||||||
|
// Keyboard events
|
||||||
|
|
||||||
const shouldRedirectKeyboardEventToBackend = (e: KeyboardEvent): boolean => {
|
const shouldRedirectKeyboardEventToBackend = (e: KeyboardEvent): boolean => {
|
||||||
// Don't redirect user input from text entry into HTML elements
|
// Don't redirect user input from text entry into HTML elements
|
||||||
@@ -81,42 +84,49 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
// Pointer events
|
||||||
if (!e.buttons) viewportMouseInteractionOngoing = false;
|
|
||||||
|
const onPointerMove = (e: PointerEvent) => {
|
||||||
|
if (!e.buttons) viewportPointerInteractionOngoing = false;
|
||||||
|
|
||||||
const modifiers = makeModifiersBitfield(e);
|
const modifiers = makeModifiersBitfield(e);
|
||||||
editor.instance.on_mouse_move(e.clientX, e.clientY, e.buttons, modifiers);
|
editor.instance.on_mouse_move(e.clientX, e.clientY, e.buttons, modifiers);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseDown = (e: MouseEvent) => {
|
const onPointerDown = (e: PointerEvent) => {
|
||||||
const { target } = e;
|
const { target } = e;
|
||||||
const inCanvas = target instanceof Element && target.closest(".canvas");
|
const inCanvas = target instanceof Element && target.closest(".canvas");
|
||||||
const inDialog = target instanceof Element && target.closest(".dialog-modal .floating-menu-content");
|
const inDialog = target instanceof Element && target.closest(".dialog-modal .floating-menu-content");
|
||||||
|
|
||||||
// Block middle mouse button auto-scroll mode
|
|
||||||
if (e.button === 1) e.preventDefault();
|
|
||||||
|
|
||||||
if (dialog.dialogIsVisible() && !inDialog) {
|
if (dialog.dialogIsVisible() && !inDialog) {
|
||||||
dialog.dismissDialog();
|
dialog.dismissDialog();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inCanvas) viewportMouseInteractionOngoing = true;
|
if (inCanvas) viewportPointerInteractionOngoing = true;
|
||||||
|
|
||||||
if (viewportMouseInteractionOngoing) {
|
if (viewportPointerInteractionOngoing) {
|
||||||
const modifiers = makeModifiersBitfield(e);
|
const modifiers = makeModifiersBitfield(e);
|
||||||
editor.instance.on_mouse_down(e.clientX, e.clientY, e.buttons, modifiers);
|
editor.instance.on_mouse_down(e.clientX, e.clientY, e.buttons, modifiers);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (e: MouseEvent) => {
|
const onPointerUp = (e: PointerEvent) => {
|
||||||
if (!e.buttons) viewportMouseInteractionOngoing = false;
|
if (!e.buttons) viewportPointerInteractionOngoing = false;
|
||||||
|
|
||||||
const modifiers = makeModifiersBitfield(e);
|
const modifiers = makeModifiersBitfield(e);
|
||||||
editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers);
|
editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Mouse events
|
||||||
|
|
||||||
|
const onMouseDown = (e: MouseEvent) => {
|
||||||
|
// Block middle mouse button auto-scroll mode (the circlar widget that appears and allows quick scrolling by moving the cursor above or below it)
|
||||||
|
// This has to be in `mousedown`, not `pointerdown`, to avoid blocking Vue's middle click detection on HTML elements
|
||||||
|
if (e.button === 1) e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseScroll = (e: WheelEvent) => {
|
const onMouseScroll = (e: WheelEvent) => {
|
||||||
const { target } = e;
|
const { target } = e;
|
||||||
const inCanvas = target instanceof Element && target.closest(".canvas");
|
const inCanvas = target instanceof Element && target.closest(".canvas");
|
||||||
@@ -134,6 +144,8 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Window events
|
||||||
|
|
||||||
const onWindowResize = (container: HTMLElement) => {
|
const onWindowResize = (container: HTMLElement) => {
|
||||||
const viewports = Array.from(container.querySelectorAll(".canvas"));
|
const viewports = Array.from(container.querySelectorAll(".canvas"));
|
||||||
const boundsOfViewports = viewports.map((canvas) => {
|
const boundsOfViewports = viewports.map((canvas) => {
|
||||||
@@ -155,6 +167,8 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Event bindings
|
||||||
|
|
||||||
const addListeners = () => {
|
const addListeners = () => {
|
||||||
listeners.forEach(({ target, eventName, action, options }) => target.addEventListener(eventName, action, options));
|
listeners.forEach(({ target, eventName, action, options }) => target.addEventListener(eventName, action, options));
|
||||||
};
|
};
|
||||||
@@ -173,6 +187,6 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
}
|
}
|
||||||
export type InputManager = ReturnType<typeof createInputManager>;
|
export type InputManager = ReturnType<typeof createInputManager>;
|
||||||
|
|
||||||
export function makeModifiersBitfield(e: MouseEvent | KeyboardEvent): number {
|
export function makeModifiersBitfield(e: WheelEvent | PointerEvent | KeyboardEvent): number {
|
||||||
return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2);
|
return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user