UNPKG

@dcl/ecs

Version:
158 lines (157 loc) • 6.58 kB
import * as components from '../components'; import { EntityState } from '../engine/entity'; import { checkNotThenable } from '../runtime/invariant'; export const getDefaultOpts = (opts = {}) => ({ button: 3 /* InputAction.IA_ANY */, ...opts }); /** * @public * ___DO NOT USE___ use pointerEventsSystem instead */ export function createPointerEventsSystem(engine, inputSystem) { const PointerEvents = components.PointerEvents(engine); let EventType; (function (EventType) { EventType[EventType["Click"] = 0] = "Click"; EventType[EventType["Down"] = 1] = "Down"; EventType[EventType["Up"] = 2] = "Up"; EventType[EventType["HoverEnter"] = 3] = "HoverEnter"; EventType[EventType["HoverLeave"] = 4] = "HoverLeave"; })(EventType || (EventType = {})); const eventsMap = new Map(); function getEvent(entity) { return eventsMap.get(entity) || eventsMap.set(entity, new Map()).get(entity); } function setPointerEvent(entity, type, opts) { const pointerEvent = PointerEvents.getMutableOrNull(entity) || PointerEvents.create(entity); pointerEvent.pointerEvents.push({ eventType: type, eventInfo: { button: opts.button, showFeedback: opts.showFeedback, showHighlight: opts.showHighlight, hoverText: opts.hoverText, maxDistance: opts.maxDistance } }); } function removePointerEvent(entity, type, button) { const pointerEvent = PointerEvents.getMutableOrNull(entity); if (!pointerEvent) return; pointerEvent.pointerEvents = pointerEvent.pointerEvents.filter((pointer) => !(pointer.eventInfo?.button === button && pointer.eventType === type)); } function getPointerEvent(eventType) { if (eventType === EventType.Up) { return 0 /* PointerEventType.PET_UP */; } else if (eventType === EventType.HoverLeave) { return 3 /* PointerEventType.PET_HOVER_LEAVE */; } else if (eventType === EventType.HoverEnter) { return 2 /* PointerEventType.PET_HOVER_ENTER */; } return 1 /* PointerEventType.PET_DOWN */; } function removeEvent(entity, type) { const event = getEvent(entity); const pointerEvent = event.get(type); if (pointerEvent?.opts.hoverText) { removePointerEvent(entity, getPointerEvent(type), pointerEvent.opts.button); } event.delete(type); } engine.addSystem(function EventSystem() { for (const [entity, event] of eventsMap) { if (engine.getEntityState(entity) === EntityState.Removed) { eventsMap.delete(entity); continue; } for (const [eventType, { cb, opts }] of event) { if (eventType === EventType.Click) { const command = inputSystem.getClick(opts.button, entity); if (command) checkNotThenable(cb(command.up), 'Click event returned a thenable. Only synchronous functions are allowed'); } if (eventType === EventType.Down || eventType === EventType.Up || eventType === EventType.HoverEnter || eventType === EventType.HoverLeave) { const command = inputSystem.getInputCommand(opts.button, getPointerEvent(eventType), entity); if (command) { checkNotThenable(cb(command), 'Event handler returned a thenable. Only synchronous functions are allowed'); } } } } }); const onPointerDown = (...args) => { const [data, cb, maybeOpts] = args; if (typeof data === 'number') { return onPointerDown({ entity: data, opts: maybeOpts ?? {} }, cb); } const { entity, opts } = data; const options = getDefaultOpts(opts); removeEvent(entity, EventType.Down); getEvent(entity).set(EventType.Down, { cb, opts: options }); setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options); }; const onPointerUp = (...args) => { const [data, cb, maybeOpts] = args; if (typeof data === 'number') { return onPointerUp({ entity: data, opts: maybeOpts ?? {} }, cb); } const { entity, opts } = data; const options = getDefaultOpts(opts); removeEvent(entity, EventType.Up); getEvent(entity).set(EventType.Up, { cb, opts: options }); setPointerEvent(entity, 0 /* PointerEventType.PET_UP */, options); }; const onPointerHoverEnter = (...args) => { const [data, cb] = args; const { entity, opts } = data; const options = getDefaultOpts(opts); removeEvent(entity, EventType.HoverEnter); getEvent(entity).set(EventType.HoverEnter, { cb, opts: options }); setPointerEvent(entity, 2 /* PointerEventType.PET_HOVER_ENTER */, options); }; const onPointerHoverLeave = (...args) => { const [data, cb] = args; const { entity, opts } = data; const options = getDefaultOpts(opts); removeEvent(entity, EventType.HoverLeave); getEvent(entity).set(EventType.HoverLeave, { cb, opts: options }); setPointerEvent(entity, 3 /* PointerEventType.PET_HOVER_LEAVE */, options); }; return { removeOnClick(entity) { removeEvent(entity, EventType.Click); }, removeOnPointerDown(entity) { removeEvent(entity, EventType.Down); }, removeOnPointerUp(entity) { removeEvent(entity, EventType.Up); }, removeOnPointerHoverEnter(entity) { removeEvent(entity, EventType.HoverEnter); }, removeOnPointerHoverLeave(entity) { removeEvent(entity, EventType.HoverLeave); }, onClick(value, cb) { const { entity } = value; const options = getDefaultOpts(value.opts); // Clear previous event with over feedback included removeEvent(entity, EventType.Click); // Set new event getEvent(entity).set(EventType.Click, { cb, opts: options }); setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options); }, onPointerDown, onPointerUp, onPointerHoverEnter, onPointerHoverLeave }; }