playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
1,007 lines (1,006 loc) • 30.8 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { now } from "../../../core/time.js";
import { math } from "../../../core/math/math.js";
import { Color } from "../../../core/math/color.js";
import { Vec4 } from "../../../core/math/vec4.js";
import { GraphNode } from "../../../scene/graph-node.js";
import { Component } from "../component.js";
import { BUTTON_TRANSITION_MODE_SPRITE_CHANGE, BUTTON_TRANSITION_MODE_TINT } from "./constants.js";
import { ELEMENTTYPE_GROUP } from "../element/constants.js";
const VisualState = {
DEFAULT: "DEFAULT",
HOVER: "HOVER",
PRESSED: "PRESSED",
INACTIVE: "INACTIVE"
};
const STATES_TO_TINT_NAMES = {};
STATES_TO_TINT_NAMES[VisualState.DEFAULT] = "_defaultTint";
STATES_TO_TINT_NAMES[VisualState.HOVER] = "hoverTint";
STATES_TO_TINT_NAMES[VisualState.PRESSED] = "pressedTint";
STATES_TO_TINT_NAMES[VisualState.INACTIVE] = "inactiveTint";
const STATES_TO_SPRITE_ASSET_NAMES = {};
STATES_TO_SPRITE_ASSET_NAMES[VisualState.DEFAULT] = "_defaultSpriteAsset";
STATES_TO_SPRITE_ASSET_NAMES[VisualState.HOVER] = "hoverSpriteAsset";
STATES_TO_SPRITE_ASSET_NAMES[VisualState.PRESSED] = "pressedSpriteAsset";
STATES_TO_SPRITE_ASSET_NAMES[VisualState.INACTIVE] = "inactiveSpriteAsset";
const STATES_TO_SPRITE_FRAME_NAMES = {};
STATES_TO_SPRITE_FRAME_NAMES[VisualState.DEFAULT] = "_defaultSpriteFrame";
STATES_TO_SPRITE_FRAME_NAMES[VisualState.HOVER] = "hoverSpriteFrame";
STATES_TO_SPRITE_FRAME_NAMES[VisualState.PRESSED] = "pressedSpriteFrame";
STATES_TO_SPRITE_FRAME_NAMES[VisualState.INACTIVE] = "inactiveSpriteFrame";
class ButtonComponent extends Component {
/**
* Create a new ButtonComponent instance.
*
* @param {ButtonComponentSystem} system - The ComponentSystem that created this component.
* @param {Entity} entity - The entity that this component is attached to.
*/
constructor(system, entity) {
super(system, entity);
/** @private */
__publicField(this, "_active", true);
/** @private */
__publicField(this, "_hitPadding", new Vec4());
/** @private */
__publicField(this, "_transitionMode", BUTTON_TRANSITION_MODE_TINT);
/** @private */
__publicField(this, "_hoverTint", new Color(0.75, 0.75, 0.75));
/** @private */
__publicField(this, "_pressedTint", new Color(0.5, 0.5, 0.5));
/** @private */
__publicField(this, "_inactiveTint", new Color(0.25, 0.25, 0.25));
/** @private */
__publicField(this, "_fadeDuration", 0);
/**
* @type {Asset|null}
* @private
*/
__publicField(this, "_hoverSpriteAsset", null);
/** @private */
__publicField(this, "_hoverSpriteFrame", 0);
/**
* @type {Asset|null}
* @private
*/
__publicField(this, "_pressedSpriteAsset", null);
/** @private */
__publicField(this, "_pressedSpriteFrame", 0);
/**
* @type {Asset|null}
* @private
*/
__publicField(this, "_inactiveSpriteAsset", null);
/** @private */
__publicField(this, "_inactiveSpriteFrame", 0);
/** @private */
__publicField(this, "_visualState", VisualState.DEFAULT);
/** @private */
__publicField(this, "_isHovering", false);
/** @private */
__publicField(this, "_hoveringCounter", 0);
/** @private */
__publicField(this, "_isPressed", false);
/** @private */
__publicField(this, "_hasHitElementListeners", false);
/** @private */
__publicField(this, "_isApplyingTint", false);
/** @private */
__publicField(this, "_isApplyingSprite", false);
/**
* @type {{startTime: number, from: Color, to: Color, lerpColor: Color}|null}
* @private
*/
__publicField(this, "_tweenInfo", null);
/** @private */
__publicField(this, "_defaultTint", new Color(1, 1, 1, 1));
/** @private */
__publicField(this, "_defaultSpriteAsset", null);
/** @private */
__publicField(this, "_defaultSpriteFrame", 0);
/**
* @type {Entity|null}
* @private
*/
__publicField(this, "_imageEntity", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtElementAdd", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementAdd", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementRemove", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementColor", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementOpacity", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementSpriteAsset", null);
/**
* @type {EventHandle|null}
* @private
*/
__publicField(this, "_evtImageEntityElementSpriteFrame", null);
this._evtElementAdd = this.entity.on("element:add", this._onElementComponentAdd, this);
}
/**
* Sets the button's active state. If set to false, the button will be visible but will not
* respond to hover or touch interactions. Defaults to true.
*
* @type {boolean}
*/
set active(arg) {
if (this._active === arg) {
return;
}
this._active = arg;
this._updateVisualState();
}
/**
* Gets the button's active state.
*
* @type {boolean}
*/
get active() {
return this._active;
}
/**
* Sets the entity to be used as the button background. The entity must have an
* {@link ElementComponent} configured as an image element.
*
* @type {Entity|string|null}
*/
set imageEntity(arg) {
let newEntity;
if (arg instanceof GraphNode) {
newEntity = arg;
} else if (typeof arg === "string") {
newEntity = this.system.app.getEntityFromIndex(arg) ?? null;
} else {
newEntity = null;
}
if (this._imageEntity === newEntity) {
return;
}
if (this._imageEntity) {
this._imageEntityUnsubscribe();
}
this._imageEntity = newEntity;
if (newEntity) {
this._imageEntitySubscribe();
}
}
/**
* Gets the entity to be used as the button background.
*
* @type {Entity|null}
*/
get imageEntity() {
return this._imageEntity;
}
/**
* Sets the padding to be used in hit-test calculations. Can be used to expand the bounding box
* so that the button is easier to tap. Defaults to `[0, 0, 0, 0]`.
*
* @type {Vec4}
*/
set hitPadding(arg) {
if (!arg) {
this._hitPadding = arg;
} else if (arg instanceof Vec4) {
this._hitPadding = arg.clone();
} else {
this._hitPadding = new Vec4(arg[0], arg[1], arg[2], arg[3]);
}
}
/**
* Gets the padding to be used in hit-test calculations.
*
* @type {Vec4}
*/
get hitPadding() {
return this._hitPadding;
}
/**
* Sets the button transition mode. This controls how the button responds when the user hovers
* over it/presses it. Can be:
*
* - {@link BUTTON_TRANSITION_MODE_TINT}
* - {@link BUTTON_TRANSITION_MODE_SPRITE_CHANGE}
*
* Defaults to {@link BUTTON_TRANSITION_MODE_TINT}.
*
* @type {number}
*/
set transitionMode(arg) {
if (this._transitionMode === arg) {
return;
}
const oldMode = this._transitionMode;
this._transitionMode = arg;
this._cancelTween();
this._resetToDefaultVisualState(oldMode);
this._forceReapplyVisualState();
}
/**
* Gets the button transition mode.
*
* @type {number}
*/
get transitionMode() {
return this._transitionMode;
}
/**
* Sets the tint color to be used on the button image when the user hovers over it. Defaults to
* `[0.75, 0.75, 0.75]`.
*
* @type {Color}
*/
set hoverTint(arg) {
this._setTint("_hoverTint", arg);
}
/**
* Gets the tint color to be used on the button image when the user hovers over it.
*
* @type {Color}
*/
get hoverTint() {
return this._hoverTint;
}
/**
* Sets the tint color to be used on the button image when the user presses it. Defaults to
* `[0.5, 0.5, 0.5]`.
*
* @type {Color}
*/
set pressedTint(arg) {
this._setTint("_pressedTint", arg);
}
/**
* Gets the tint color to be used on the button image when the user presses it.
*
* @type {Color}
*/
get pressedTint() {
return this._pressedTint;
}
/**
* Sets the tint color to be used on the button image when the button is not interactive.
* Defaults to `[0.25, 0.25, 0.25]`.
*
* @type {Color}
*/
set inactiveTint(arg) {
this._setTint("_inactiveTint", arg);
}
/**
* Gets the tint color to be used on the button image when the button is not interactive.
*
* @type {Color}
*/
get inactiveTint() {
return this._inactiveTint;
}
/**
* Sets the duration to be used when fading between tints, in milliseconds. Defaults to 0.
*
* @type {number}
*/
set fadeDuration(arg) {
this._fadeDuration = arg;
}
/**
* Gets the duration to be used when fading between tints, in milliseconds.
*
* @type {number}
*/
get fadeDuration() {
return this._fadeDuration;
}
/**
* Sets the sprite to be used as the button image when the user hovers over it.
*
* @type {Asset|null}
*/
set hoverSpriteAsset(arg) {
this._setTransitionValue("_hoverSpriteAsset", arg);
}
/**
* Gets the sprite to be used as the button image when the user hovers over it.
*
* @type {Asset|null}
*/
get hoverSpriteAsset() {
return this._hoverSpriteAsset;
}
/**
* Sets the frame to be used from the hover sprite.
*
* @type {number}
*/
set hoverSpriteFrame(arg) {
this._setTransitionValue("_hoverSpriteFrame", arg);
}
/**
* Gets the frame to be used from the hover sprite.
*
* @type {number}
*/
get hoverSpriteFrame() {
return this._hoverSpriteFrame;
}
/**
* Sets the sprite to be used as the button image when the user presses it.
*
* @type {Asset|null}
*/
set pressedSpriteAsset(arg) {
this._setTransitionValue("_pressedSpriteAsset", arg);
}
/**
* Gets the sprite to be used as the button image when the user presses it.
*
* @type {Asset|null}
*/
get pressedSpriteAsset() {
return this._pressedSpriteAsset;
}
/**
* Sets the frame to be used from the pressed sprite.
*
* @type {number}
*/
set pressedSpriteFrame(arg) {
this._setTransitionValue("_pressedSpriteFrame", arg);
}
/**
* Gets the frame to be used from the pressed sprite.
*
* @type {number}
*/
get pressedSpriteFrame() {
return this._pressedSpriteFrame;
}
/**
* Sets the sprite to be used as the button image when the button is not interactive.
*
* @type {Asset|null}
*/
set inactiveSpriteAsset(arg) {
this._setTransitionValue("_inactiveSpriteAsset", arg);
}
/**
* Gets the sprite to be used as the button image when the button is not interactive.
*
* @type {Asset|null}
*/
get inactiveSpriteAsset() {
return this._inactiveSpriteAsset;
}
/**
* Sets the frame to be used from the inactive sprite.
*
* @type {number}
*/
set inactiveSpriteFrame(arg) {
this._setTransitionValue("_inactiveSpriteFrame", arg);
}
/**
* Gets the frame to be used from the inactive sprite.
*
* @type {number}
*/
get inactiveSpriteFrame() {
return this._inactiveSpriteFrame;
}
/**
* Sets one of the state tint fields, mirroring the old schema-driven `type: 'rgba'`
* conversion in ComponentSystem.convertValue: pass falsy values through untouched, clone a
* Color input (so caller mutations do not leak into component state), and treat anything else
* as indexable to support `[r, g, b, a]` arrays from JSON-loaded scenes. The visual state is
* only reapplied when the tint actually changes in value, as reapplying cancels any in-flight
* fade tween.
*
* @param {string} name - The name of the private tint field to set.
* @param {Color|number[]|null} arg - The new tint value.
* @private
*/
_setTint(name, arg) {
const oldValue = this[name];
let value;
if (!arg) {
value = arg;
} else if (arg instanceof Color) {
value = arg.clone();
} else {
value = new Color(arg[0], arg[1], arg[2], arg[3]);
}
this[name] = value;
if (oldValue === value || oldValue instanceof Color && value instanceof Color && oldValue.equals(value)) {
return;
}
this._forceReapplyVisualState();
}
/**
* Sets one of the state sprite asset/frame fields, reapplying the visual state on change.
*
* @param {string} name - The name of the private field to set.
* @param {Asset|number|null} arg - The new value.
* @private
*/
_setTransitionValue(name, arg) {
if (this[name] === arg) {
return;
}
this[name] = arg;
this._forceReapplyVisualState();
}
_imageEntitySubscribe() {
this._evtImageEntityElementAdd = this._imageEntity.on("element:add", this._onImageElementGain, this);
if (this._imageEntity.element) {
this._onImageElementGain();
}
}
_imageEntityUnsubscribe() {
this._evtImageEntityElementAdd?.off();
this._evtImageEntityElementAdd = null;
if (this._imageEntity?.element) {
this._onImageElementLose();
}
}
_imageEntityElementSubscribe() {
const element = this._imageEntity.element;
this._evtImageEntityElementRemove = element.once("beforeremove", this._onImageElementLose, this);
this._evtImageEntityElementColor = element.on("set:color", this._onSetColor, this);
this._evtImageEntityElementOpacity = element.on("set:opacity", this._onSetOpacity, this);
this._evtImageEntityElementSpriteAsset = element.on("set:spriteAsset", this._onSetSpriteAsset, this);
this._evtImageEntityElementSpriteFrame = element.on("set:spriteFrame", this._onSetSpriteFrame, this);
}
_imageEntityElementUnsubscribe() {
this._evtImageEntityElementRemove?.off();
this._evtImageEntityElementRemove = null;
this._evtImageEntityElementColor?.off();
this._evtImageEntityElementColor = null;
this._evtImageEntityElementOpacity?.off();
this._evtImageEntityElementOpacity = null;
this._evtImageEntityElementSpriteAsset?.off();
this._evtImageEntityElementSpriteAsset = null;
this._evtImageEntityElementSpriteFrame?.off();
this._evtImageEntityElementSpriteFrame = null;
}
_onElementComponentRemove() {
this._toggleHitElementListeners("off");
}
_onElementComponentAdd() {
this._toggleHitElementListeners("on");
}
_onImageElementLose() {
this._imageEntityElementUnsubscribe();
this._cancelTween();
this._resetToDefaultVisualState(this.transitionMode);
}
_onImageElementGain() {
this._imageEntityElementSubscribe();
this._storeDefaultVisualState();
this._forceReapplyVisualState();
}
_toggleHitElementListeners(onOrOff) {
if (this.entity.element) {
const isAdding = onOrOff === "on";
if (isAdding && this._hasHitElementListeners) {
return;
}
this.entity.element[onOrOff]("beforeremove", this._onElementComponentRemove, this);
this.entity.element[onOrOff]("mouseenter", this._onMouseEnter, this);
this.entity.element[onOrOff]("mouseleave", this._onMouseLeave, this);
this.entity.element[onOrOff]("mousedown", this._onMouseDown, this);
this.entity.element[onOrOff]("mouseup", this._onMouseUp, this);
this.entity.element[onOrOff]("touchstart", this._onTouchStart, this);
this.entity.element[onOrOff]("touchend", this._onTouchEnd, this);
this.entity.element[onOrOff]("touchleave", this._onTouchLeave, this);
this.entity.element[onOrOff]("touchcancel", this._onTouchCancel, this);
this.entity.element[onOrOff]("selectstart", this._onSelectStart, this);
this.entity.element[onOrOff]("selectend", this._onSelectEnd, this);
this.entity.element[onOrOff]("selectenter", this._onSelectEnter, this);
this.entity.element[onOrOff]("selectleave", this._onSelectLeave, this);
this.entity.element[onOrOff]("click", this._onClick, this);
this._hasHitElementListeners = isAdding;
}
}
_storeDefaultVisualState() {
const element = this._imageEntity?.element;
if (!element || element.type === ELEMENTTYPE_GROUP) {
return;
}
this._storeDefaultColor(element.color);
this._storeDefaultOpacity(element.opacity);
this._storeDefaultSpriteAsset(element.spriteAsset);
this._storeDefaultSpriteFrame(element.spriteFrame);
}
_storeDefaultColor(color) {
this._defaultTint.r = color.r;
this._defaultTint.g = color.g;
this._defaultTint.b = color.b;
}
_storeDefaultOpacity(opacity) {
this._defaultTint.a = opacity;
}
_storeDefaultSpriteAsset(spriteAsset) {
this._defaultSpriteAsset = spriteAsset;
}
_storeDefaultSpriteFrame(spriteFrame) {
this._defaultSpriteFrame = spriteFrame;
}
_onSetColor(color) {
if (!this._isApplyingTint) {
this._storeDefaultColor(color);
this._forceReapplyVisualState();
}
}
_onSetOpacity(opacity) {
if (!this._isApplyingTint) {
this._storeDefaultOpacity(opacity);
this._forceReapplyVisualState();
}
}
_onSetSpriteAsset(spriteAsset) {
if (!this._isApplyingSprite) {
this._storeDefaultSpriteAsset(spriteAsset);
this._forceReapplyVisualState();
}
}
_onSetSpriteFrame(spriteFrame) {
if (!this._isApplyingSprite) {
this._storeDefaultSpriteFrame(spriteFrame);
this._forceReapplyVisualState();
}
}
_onMouseEnter(event) {
this._isHovering = true;
this._updateVisualState();
this._fireIfActive("mouseenter", event);
}
_onMouseLeave(event) {
this._isHovering = false;
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("mouseleave", event);
}
_onMouseDown(event) {
this._isPressed = true;
this._updateVisualState();
this._fireIfActive("mousedown", event);
}
_onMouseUp(event) {
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("mouseup", event);
}
_onTouchStart(event) {
this._isPressed = true;
this._updateVisualState();
this._fireIfActive("touchstart", event);
}
_onTouchEnd(event) {
event.event.preventDefault();
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("touchend", event);
}
_onTouchLeave(event) {
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("touchleave", event);
}
_onTouchCancel(event) {
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("touchcancel", event);
}
_onSelectStart(event) {
this._isPressed = true;
this._updateVisualState();
this._fireIfActive("selectstart", event);
}
_onSelectEnd(event) {
this._isPressed = false;
this._updateVisualState();
this._fireIfActive("selectend", event);
}
_onSelectEnter(event) {
this._hoveringCounter++;
if (this._hoveringCounter === 1) {
this._isHovering = true;
this._updateVisualState();
}
this._fireIfActive("selectenter", event);
}
_onSelectLeave(event) {
this._hoveringCounter--;
if (this._hoveringCounter === 0) {
this._isHovering = false;
this._isPressed = false;
this._updateVisualState();
}
this._fireIfActive("selectleave", event);
}
_onClick(event) {
this._fireIfActive("click", event);
}
_fireIfActive(name, event) {
if (this._active) {
this.fire(name, event);
}
}
_updateVisualState(force) {
const oldVisualState = this._visualState;
const newVisualState = this._determineVisualState();
if ((oldVisualState !== newVisualState || force) && this.enabled) {
this._visualState = newVisualState;
if (oldVisualState === VisualState.HOVER) {
this._fireIfActive("hoverend");
}
if (oldVisualState === VisualState.PRESSED) {
this._fireIfActive("pressedend");
}
if (newVisualState === VisualState.HOVER) {
this._fireIfActive("hoverstart");
}
if (newVisualState === VisualState.PRESSED) {
this._fireIfActive("pressedstart");
}
switch (this.transitionMode) {
case BUTTON_TRANSITION_MODE_TINT: {
const tintName = STATES_TO_TINT_NAMES[this._visualState];
const tintColor = this[tintName];
this._applyTint(tintColor);
break;
}
case BUTTON_TRANSITION_MODE_SPRITE_CHANGE: {
const spriteAssetName = STATES_TO_SPRITE_ASSET_NAMES[this._visualState];
const spriteFrameName = STATES_TO_SPRITE_FRAME_NAMES[this._visualState];
const spriteAsset = this[spriteAssetName];
const spriteFrame = this[spriteFrameName];
this._applySprite(spriteAsset, spriteFrame);
break;
}
}
}
}
// Called when a property changes that mean the visual state must be reapplied,
// even if the state enum has not changed. Examples of this are when the tint
// value for one of the states is changed via the editor.
_forceReapplyVisualState() {
this._updateVisualState(true);
}
// Called before the image entity changes, in order to restore the previous
// image back to its original tint. Note that this happens immediately, i.e.
// without any animation.
_resetToDefaultVisualState(transitionMode) {
if (!this._imageEntity?.element) {
return;
}
switch (transitionMode) {
case BUTTON_TRANSITION_MODE_TINT:
this._cancelTween();
this._applyTintImmediately(this._defaultTint);
break;
case BUTTON_TRANSITION_MODE_SPRITE_CHANGE:
this._applySprite(this._defaultSpriteAsset, this._defaultSpriteFrame);
break;
}
}
_determineVisualState() {
if (!this.active) {
return VisualState.INACTIVE;
} else if (this._isPressed) {
return VisualState.PRESSED;
} else if (this._isHovering) {
return VisualState.HOVER;
}
return VisualState.DEFAULT;
}
_applySprite(spriteAsset, spriteFrame) {
const element = this._imageEntity?.element;
if (!element) {
return;
}
spriteFrame = spriteFrame || 0;
this._isApplyingSprite = true;
if (element.spriteAsset !== spriteAsset) {
element.spriteAsset = spriteAsset;
}
if (element.spriteFrame !== spriteFrame) {
element.spriteFrame = spriteFrame;
}
this._isApplyingSprite = false;
}
_applyTint(tintColor) {
this._cancelTween();
if (this.fadeDuration === 0) {
this._applyTintImmediately(tintColor);
} else {
this._applyTintWithTween(tintColor);
}
}
_applyTintImmediately(tintColor) {
const element = this._imageEntity?.element;
if (!tintColor || !element || element.type === ELEMENTTYPE_GROUP) {
return;
}
const color3 = toColor3(tintColor);
this._isApplyingTint = true;
if (!color3.equals(element.color)) {
element.color = color3;
}
if (element.opacity !== tintColor.a) {
element.opacity = tintColor.a;
}
this._isApplyingTint = false;
}
_applyTintWithTween(tintColor) {
const element = this._imageEntity?.element;
if (!tintColor || !element || element.type === ELEMENTTYPE_GROUP) {
return;
}
const color3 = toColor3(tintColor);
const color = element.color;
const opacity = element.opacity;
if (color3.equals(color) && tintColor.a === opacity) return;
this._tweenInfo = {
startTime: now(),
from: new Color(color.r, color.g, color.b, opacity),
to: tintColor.clone(),
lerpColor: new Color()
};
}
_updateTintTween() {
const elapsedTime = now() - this._tweenInfo.startTime;
let elapsedProportion = this.fadeDuration === 0 ? 1 : elapsedTime / this.fadeDuration;
elapsedProportion = math.clamp(elapsedProportion, 0, 1);
if (Math.abs(elapsedProportion - 1) > 1e-5) {
const lerpColor = this._tweenInfo.lerpColor;
lerpColor.lerp(this._tweenInfo.from, this._tweenInfo.to, elapsedProportion);
this._applyTintImmediately(
new Color(lerpColor.r, lerpColor.g, lerpColor.b, lerpColor.a)
);
} else {
this._applyTintImmediately(this._tweenInfo.to);
this._cancelTween();
}
}
_cancelTween() {
this._tweenInfo = null;
}
onUpdate() {
if (this._tweenInfo) {
this._updateTintTween();
}
}
onEnable() {
this._isHovering = false;
this._hoveringCounter = 0;
this._isPressed = false;
this._toggleHitElementListeners("on");
this._forceReapplyVisualState();
}
onDisable() {
this._toggleHitElementListeners("off");
this._resetToDefaultVisualState(this.transitionMode);
}
onBeforeRemove() {
this._imageEntityUnsubscribe();
this._evtElementAdd?.off();
this._evtElementAdd = null;
this.onDisable();
}
resolveDuplicatedEntityReferenceProperties(oldButton, duplicatedIdsMap) {
if (oldButton.imageEntity) {
this.imageEntity = duplicatedIdsMap[oldButton.imageEntity.guid];
}
}
}
/**
* Fired when the mouse is pressed while the cursor is on the component. The handler is passed
* a {@link ElementMouseEvent}.
*
* @event
* @example
* entity.button.on('mousedown', (event) => {
* console.log(`Mouse down on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_MOUSEDOWN", "mousedown");
/**
* Fired when the mouse is released while the cursor is on the component. The handler is passed
* a {@link ElementMouseEvent}.
*
* @event
* @example
* entity.button.on('mouseup', (event) => {
* console.log(`Mouse up on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_MOUSEUP", "mouseup");
/**
* Fired when the mouse cursor enters the component. The handler is passed a
* {@link ElementMouseEvent}.
*
* @event
* @example
* entity.button.on('mouseenter', (event) => {
* console.log(`Mouse entered entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_MOUSEENTER", "mouseenter");
/**
* Fired when the mouse cursor leaves the component. The handler is passed a
* {@link ElementMouseEvent}.
*
* @event
* @example
* entity.button.on('mouseleave', (event) => {
* console.log(`Mouse left entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_MOUSELEAVE", "mouseleave");
/**
* Fired when the mouse is pressed and released on the component or when a touch starts and ends on
* the component. The handler is passed a {@link ElementMouseEvent} or {@link ElementTouchEvent}.
*
* @event
* @example
* entity.button.on('click', (event) => {
* console.log(`Clicked entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_CLICK", "click");
/**
* Fired when a touch starts on the component. The handler is passed a {@link ElementTouchEvent}.
*
* @event
* @example
* entity.button.on('touchstart', (event) => {
* console.log(`Touch started on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_TOUCHSTART", "touchstart");
/**
* Fired when a touch ends on the component. The handler is passed a {@link ElementTouchEvent}.
*
* @event
* @example
* entity.button.on('touchend', (event) => {
* console.log(`Touch ended on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_TOUCHEND", "touchend");
/**
* Fired when a touch is canceled on the component. The handler is passed a
* {@link ElementTouchEvent}.
*
* @event
* @example
* entity.button.on('touchcancel', (event) => {
* console.log(`Touch canceled on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_TOUCHCANCEL", "touchcancel");
/**
* Fired when a touch leaves the component. The handler is passed a {@link ElementTouchEvent}.
*
* @event
* @example
* entity.button.on('touchleave', (event) => {
* console.log(`Touch left entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_TOUCHLEAVE", "touchleave");
/**
* Fired when a xr select starts on the component. The handler is passed a
* {@link ElementSelectEvent}.
*
* @event
* @example
* entity.button.on('selectstart', (event) => {
* console.log(`Select started on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_SELECTSTART", "selectstart");
/**
* Fired when a xr select ends on the component. The handler is passed a
* {@link ElementSelectEvent}.
*
* @event
* @example
* entity.button.on('selectend', (event) => {
* console.log(`Select ended on entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_SELECTEND", "selectend");
/**
* Fired when a xr select now hovering over the component. The handler is passed a
* {@link ElementSelectEvent}.
*
* @event
* @example
* entity.button.on('selectenter', (event) => {
* console.log(`Select entered entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_SELECTENTER", "selectenter");
/**
* Fired when a xr select not hovering over the component. The handler is passed a
* {@link ElementSelectEvent}.
*
* @event
* @example
* entity.button.on('selectleave', (event) => {
* console.log(`Select left entity ${entity.name}`);
* });
*/
__publicField(ButtonComponent, "EVENT_SELECTLEAVE", "selectleave");
/**
* Fired when the button changes state to be hovered.
*
* @event
* @example
* entity.button.on('hoverstart', () => {
* console.log(`Entity ${entity.name} hovered`);
* });
*/
__publicField(ButtonComponent, "EVENT_HOVERSTART", "hoverstart");
/**
* Fired when the button changes state to be not hovered.
*
* @event
* @example
* entity.button.on('hoverend', () => {
* console.log(`Entity ${entity.name} unhovered`);
* });
*/
__publicField(ButtonComponent, "EVENT_HOVEREND", "hoverend");
/**
* Fired when the button changes state to be pressed.
*
* @event
* @example
* entity.button.on('pressedstart', () => {
* console.log(`Entity ${entity.name} pressed`);
* });
*/
__publicField(ButtonComponent, "EVENT_PRESSEDSTART", "pressedstart");
/**
* Fired when the button changes state to be not pressed.
*
* @event
* @example
* entity.button.on('pressedend', () => {
* console.log(`Entity ${entity.name} unpressed`);
* });
*/
__publicField(ButtonComponent, "EVENT_PRESSEDEND", "pressedend");
function toColor3(color4) {
return new Color(color4.r, color4.g, color4.b);
}
export {
ButtonComponent
};