@dcl/ecs
Version:
Decentraland ECS
158 lines (157 loc) • 6.58 kB
JavaScript
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
};
}