From f82d41f1c35e4a6e44ff4e777264c32c646807e4 Mon Sep 17 00:00:00 2001 From: Pihkaal Date: Thu, 13 Nov 2025 00:37:05 +0100 Subject: [PATCH] feat: implement useScreenClick --- .../Home/BottomScreen/Buttons/Buttons.vue | 18 ++++++++++++ app/components/Screen.vue | 28 +++++++++++++++++++ app/composables/useScreenClick.ts | 18 ++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 app/composables/useScreenClick.ts diff --git a/app/components/Home/BottomScreen/Buttons/Buttons.vue b/app/components/Home/BottomScreen/Buttons/Buttons.vue index b6035d8..b35fb1c 100644 --- a/app/components/Home/BottomScreen/Buttons/Buttons.vue +++ b/app/components/Home/BottomScreen/Buttons/Buttons.vue @@ -26,6 +26,24 @@ const nextBottomButton = ref<"downloadPlay" | "pictochat">("pictochat"); const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]); +useScreenClick((x: number, y: number) => { + for (const [buttonName, config] of Object.entries(BUTTONS_CONFIG)) { + if ( + x >= config.sx && + x <= config.sx + config.sw && + y >= config.sy && + y <= config.sy + config.sh + ) { + selectedButton.value = buttonName as ButtonType; + + if (buttonName === "pictochat" || buttonName === "downloadPlay") { + nextBottomButton.value = buttonName; + } + break; + } + } +}); + const handleKeyPress = (event: KeyboardEvent) => { switch (event.key) { case "ArrowUp": diff --git a/app/components/Screen.vue b/app/components/Screen.vue index 202d722..61f6e2b 100644 --- a/app/components/Screen.vue +++ b/app/components/Screen.vue @@ -3,6 +3,7 @@ const canvas = useTemplateRef("canvas"); const updateCallbacks = new Set(); const renderCallbacks = new Set(); +const screenClickCallbacks = new Set(); let ctx: CanvasRenderingContext2D | null = null; let animationFrameId: number | null = null; @@ -19,6 +20,26 @@ const registerRenderCallback = (callback: RenderCallback) => { return () => renderCallbacks.delete(callback); }; +const registerScreenClickCallback = (callback: ScreenClickCallback) => { + screenClickCallbacks.add(callback); + return () => screenClickCallbacks.delete(callback); +}; + +const handleCanvasClick = (event: MouseEvent) => { + if (!canvas.value) return; + + const rect = canvas.value.getBoundingClientRect(); + const scaleX = SCREEN_WIDTH / rect.width; + const scaleY = SCREEN_HEIGHT / rect.height; + + const x = (event.clientX - rect.left) * scaleX; + const y = (event.clientY - rect.top) * scaleY; + + for (const callback of screenClickCallbacks) { + callback(x, y); + } +}; + const renderFrame = (timestamp: number) => { if (!ctx) return; @@ -56,6 +77,9 @@ onMounted(() => { provide("registerUpdateCallback", registerUpdateCallback); provide("registerRenderCallback", registerRenderCallback); + provide("registerScreenClickCallback", registerScreenClickCallback); + + canvas.value.addEventListener("click", handleCanvasClick); animationFrameId = requestAnimationFrame(renderFrame); }); @@ -64,6 +88,10 @@ onUnmounted(() => { if (animationFrameId !== null) { cancelAnimationFrame(animationFrameId); } + + if (canvas.value) { + canvas.value.removeEventListener("click", handleCanvasClick); + } }); diff --git a/app/composables/useScreenClick.ts b/app/composables/useScreenClick.ts new file mode 100644 index 0000000..248754b --- /dev/null +++ b/app/composables/useScreenClick.ts @@ -0,0 +1,18 @@ +export type ScreenClickCallback = (x: number, y: number) => void; + +export const useScreenClick = (callback: ScreenClickCallback) => { + const registerScreenClickCallback = inject< + (callback: ScreenClickCallback) => () => void + >("registerScreenClickCallback"); + + onMounted(() => { + if (!registerScreenClickCallback) { + throw new Error( + "Missing registerScreenClickCallback - useScreenClick must be used within a Screen component", + ); + } + + const unregister = registerScreenClickCallback(callback); + onUnmounted(unregister); + }); +};