Adding support for mouse wheel events. cleaning up click handler to take functions

This commit is contained in:
Dustin Swan 2026-02-13 16:31:47 -07:00
parent 85451d24fb
commit 1961ac6249
No known key found for this signature in database
GPG key ID: 30D46587E2100467
6 changed files with 108 additions and 60 deletions

View file

@ -4,12 +4,13 @@ export type UIValue =
| { kind: 'text', content: string, color?: string }
| { kind: 'row', children: UIValue[], gap: number }
| { kind: 'column', children: UIValue[], gap: number }
| { kind: 'clickable', child: UIValue, event: any }
| { kind: 'padding', child: UIValue, amount: number }
| { kind: 'positioned', x: number, y: number, child: UIValue }
| { kind: 'opacity', child: UIValue, opacity: number }
| { kind: 'clip', child: UIValue, w: number, h: number }
| { kind: 'stack', children: UIValue[] }
| { kind: 'clickable', child: UIValue, onClick: any }
| { kind: 'scrollable', child: UIValue, w: number, h: number, scrollX: number, scrollY: number, onScroll: any }
| { kind: 'stateful', key: string, focusable: boolean, init: any, update: any, view: any }
type ClickRegion = {
@ -17,11 +18,21 @@ type ClickRegion = {
y: number;
width: number;
height: number;
event: any;
onClick: any;
};
let clickRegions: ClickRegion[] = [];
type ScrollRegion = {
x: number;
y: number;
width: number;
height: number;
onScroll: any;
};
let scrollRegions: ScrollRegion[] = [];
export function render(ui: UIValue, canvas: HTMLCanvasElement) {
const ctx = canvas.getContext('2d');
if (ctx) {
@ -32,6 +43,7 @@ export function render(ui: UIValue, canvas: HTMLCanvasElement) {
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
clickRegions = [];
scrollRegions = [];
renderUI(ui, ctx, 0, 0);
}
}
@ -88,7 +100,7 @@ function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: numb
case 'row': {
let offsetX = 0;
for (const child of ui.children) {
const size = measure(child);
// const size = measure(child);
renderUI(child, ctx, x + offsetX, y);
offsetX += measure(child).width + (ui.gap || 0);
}
@ -106,11 +118,22 @@ function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: numb
case 'clickable': {
const size = measure(ui.child);
clickRegions.push({ x, y, width: size.width, height: size.height, event: ui.event })
clickRegions.push({ x, y, width: size.width, height: size.height, onClick: ui.onClick })
renderUI(ui.child, ctx, x, y);
break;
}
case 'scrollable': {
ctx.save();
ctx.beginPath();
ctx.rect(x, y, ui.w, ui.h);
ctx.clip();
renderUI(ui.child, ctx, x - ui.scrollX, y - ui.scrollY);
ctx.restore();
scrollRegions.push({ x, y, width: ui.w, height: ui.h, onScroll: ui.onScroll })
break;
}
case 'padding':
renderUI(ui.child, ctx, x + ui.amount, y + ui.amount);
break;
@ -187,6 +210,9 @@ export function _measure(ui: UIValue): { width: number, height: number } {
case 'clickable':
return measure(ui.child);
case 'scrollable':
return { width: ui.w, height: ui.h };
case 'opacity':
return measure(ui.child);
@ -223,14 +249,14 @@ export function _measure(ui: UIValue): { width: number, height: number } {
}
}
export function hitTest(x: number, y: number): { event: any, relativeX: number, relativeY: number } | null {
export function hitTest(x: number, y: number): { onClick: any, relativeX: number, relativeY: number } | null {
for (let i = clickRegions.length - 1; i >= 0; i--) {
const region = clickRegions[i];
if (x >= region.x && x < region.x + region.width &&
y >= region.y && y < region.y + region.height) {
return {
event: region.event,
onClick: region.onClick,
relativeX: x - region.x,
relativeY: y - region.y,
};
@ -238,3 +264,14 @@ export function hitTest(x: number, y: number): { event: any, relativeX: number,
}
return null;
}
export function scrollHitTest(x: number, y: number): { onScroll: any } | null {
for (let i = scrollRegions.length - 1; i >= 0; i--) {
const region = scrollRegions[i];
if (x >= region.x && x < region.x + region.width &&
y >= region.y && y < region.y + region.height) {
return { onScroll: region.onScroll };
}
}
return null;
}