import AABB from '../AABB.js';
import Data from '../Data.js';
import createComponentClass from '../factory.js';
export default (function () {
return createComponentClass(/** @lends platypus.components.LogicButton.prototype */{
id: 'LogicButton',
properties: {
/**
* The event to trigger when pressed.
*
* @property onPress
* @type String
* @default ""
*/
"onPress": "",
/**
* The event to trigger when released.
*
* @property onRelease
* @type String
* @default ""
*/
"onRelease": "",
/**
* The event to trigger when cancelled.
*
* @property onCancel
* @type String
* @default ""
*/
"onCancel": "",
/**
* The event to trigger when the user mouses over the button
*
* @property hoverAudio
* @type String|String[]|Message[]
* @default ""
*/
"onHover": "",
/**
* Whether this button's actions should be limited to the initial press/release.
*
* @property useOnce
* @type Boolean
* @default false
*/
"useOnce": false,
/**
* Whether this button should start disabled.
*
* @property disabled
* @type Boolean
* @default false
*/
"disabled": false,
/**
* Determines whether this button should behave as a toggle.
*
* @property toggle
* @type Boolean
* @default false
*/
"toggle": false,
/**
* Specifies whether the button starts off 'pressed'; typically only useful for toggle buttons.
*
* @property pressed
* @type Boolean
* @default false
*/
"pressed": false
},
publicProperties: {
/**
* This sets the distance in world units from the bottom of the camera's world viewport. If set, it will override the entity's y coordinate. This property is accessible on the entity as `entity.bottom`.
*
* @property bottom
* @type Number
* @default null
*/
"bottom": null,
/**
* This sets the distance in world units from the left of the camera's world viewport. If set, it will override the entity's x coordinate. This property is accessible on the entity as `entity.left`.
*
* @property left
* @type Number
* @default null
*/
"left": null,
/**
* This sets the distance in world units from the right of the camera's world viewport. If set, it will override the entity's x coordinate. This property is accessible on the entity as `entity.right`.
*
* @property right
* @type Number
* @default null
*/
"right": null,
/**
* This sets the distance in world units from the top of the camera's world viewport. If set, it will override the entity's y coordinate. This property is accessible on the entity as `entity.top`.
*
* @property top
* @type Number
* @default null
*/
"top": null
},
/**
* Provides button functionality for a RenderSprite component.
*
* @memberof platypus.components
* @uses platypus.Component
* @constructs
* @listens platypus.Entity#camera-update
* @listens platypus.Entity#disable
* @listens platypus.Entity#enable
* @listens platypus.Entity#handle-logic
* @listens platypus.Entity#highlight
* @listens platypus.Entity#pointerdown
* @listens platypus.Entity#pointerout
* @listens platypus.Entity#pointerover
* @listens platypus.Entity#pressup
* @listens platypus.Entity#toggle-disabled
* @listens platypus.Entity#toggle-highlight
* @listens platypus.Entity#unhighlight
* @fires platypus.Entity#pressed
* @fires platypus.Entity#cancelled
* @fires platypus.Entity#released
*/
initialize: function () {
var state = this.owner.state;
this.aabb = AABB.setUp();
this.lastBottom = null;
this.lastLeft = null;
this.lastRight = null;
this.lastTop = null;
this.state = state;
state.set('disabled', this.disabled);
state.set('released', !this.pressed);
state.set('pressed', this.pressed);
state.set('highlighted', false);
this.owner.buttonMode = !this.disabled;
this.cancelled = false;
this.readyToToggle = false;
},
events: {
"handle-logic": function () {
var bottom = this.bottom,
left = this.left,
right = this.right,
top = this.top;
if ((this.lastBottom !== bottom) || (this.lastLeft !== left) || (this.lastRight !== right) || (this.lastTop !== top)) {
this.updatePosition(this.aabb);
this.lastBottom = bottom;
this.lastLeft = left;
this.lastRight = right;
this.lastTop = top;
}
},
"camera-update": function (camera) {
this.aabb.set(camera.viewport);
this.updatePosition(this.aabb);
},
"pointerdown": function (eventData) {
if (!this.state.get('disabled')) {
if (this.toggle) {
this.readyToToggle = true;
} else {
if (this.onPress) {
this.owner.trigger(this.onPress);
}
/**
* This event is triggered when the button is pressed to mimic keypress events. If the button is a toggle button, this only occurs on up-to-down.
*
* @event platypus.Entity#pressed
* @param buttonState {platypus.Data} The state of the button
* @param buttonState.pressed {Boolean} This is `true` for the 'pressed' event.
* @param buttonState.released {Boolean} This is `false` for the 'pressed' event.
* @param buttonState.triggered {Boolean} This is `true` for the 'pressed' event.
* @param buttonState.entity {platypus.Entity} The entity for which the original event occurred.
*/
this.updateStateAndTrigger('pressed');
if (eventData && eventData.pixiEvent && eventData.pixiEvent.stopPropagation) { // ensure a properly formed event has been sent
eventData.pixiEvent.stopPropagation();
}
// Doing this prevents the call from reccurring.
if (this.useOnce && this.removeEventListener) {
this.removeEventListener('pointerdown');
}
}
}
},
"pressup": function (eventData) {
var state = this.state;
if (!state.get('disabled')) {
if (this.cancelled) {
if (this.onCancel) {
this.owner.trigger(this.onCancel);
}
/**
* This event is triggered when the button is pressed and the mouse/touch is dragged off-target before release.
*
* @event platypus.Entity#cancelled
* @param buttonState {platypus.Data} The state of the button
* @param buttonState.pressed {Boolean} This is `false` for the 'cancelled' event.
* @param buttonState.released {Boolean} This is `true` for the 'cancelled' event.
* @param buttonState.triggered {Boolean} This is `false` for the 'cancelled' event.
* @param buttonState.entity {platypus.Entity} The entity for which the original event occurred.
*/
this.updateStateAndTrigger('cancelled');
} else if (this.toggle) {
if (this.readyToToggle) {
if (state.get('pressed')) {
this.updateStateAndTrigger('released');
} else {
this.updateStateAndTrigger('pressed');
}
}
} else {
if (this.onRelease) {
this.owner.trigger(this.onRelease);
}
/**
* This event is triggered when the button is released, or on the down-to-up change for toggle buttons.
*
* @event platypus.Entity#released
* @param buttonState {platypus.Data} The state of the button
* @param buttonState.pressed {Boolean} This is `false` for the 'released' event.
* @param buttonState.released {Boolean} This is `true` for the 'released' event.
* @param buttonState.triggered {Boolean} This is `false` for the 'released' event.
* @param buttonState.entity {platypus.Entity} The entity for which the original event occurred.
*/
this.updateStateAndTrigger('released');
}
if (eventData && eventData.pixiEvent && eventData.pixiEvent.stopPropagation) { // ensure a properly formed event has been sent
eventData.pixiEvent.stopPropagation();
}
// Doing this prevents the call from reccurring.
if (this.useOnce && this.removeEventListener) { //Second check is to ensure method exists which won't be the case if a result of the press is the button being destroyed.
this.removeEventListener('pressup');
this.state.set('disabled', true);
this.owner.buttonMode = false;
}
}
this.cancelled = false;
this.readyToToggle = false;
},
"pointerover": function () {
if (this.onHover) {
this.owner.trigger(this.onHover);
}
if (this.state.get('pressed')) {
this.cancelled = false;
}
},
"pointerout": function () {
if (this.state.get('pressed')) {
this.cancelled = true;
}
},
/**
* Disables the entity.
*
* @event platypus.Entity#disable
*/
"disable": function () {
this.state.set('disabled', true);
this.owner.buttonMode = false;
},
/**
* Enables the entity.
*
* @event platypus.Entity#enable
*/
"enable": function () {
this.state.set('disabled', false);
this.owner.buttonMode = true;
},
/**
* Toggles whether the entity is disabled.
*
* @event platypus.Entity#toggle-disabled
*/
"toggle-disabled": function () {
var value = this.state.get('disabled');
this.owner.buttonMode = value;
this.state.set('disabled', !value);
},
/**
* Sets the entity's highlighted state to `true`.
*
* @event platypus.Entity#highlight
*/
"highlight": function () {
this.state.set('highlighted', true);
},
/**
* Sets the entity's highlighted state to `false`.
*
* @event platypus.Entity#unhighlight
*/
"unhighlight": function () {
this.state.set('highlighted', false);
},
/**
* Toggles the entity's highlighted state.
*
* @event platypus.Entity#toggle-highlight
*/
"toggle-highlight": function () {
var state = this.state;
state.set('highlighted', !state.get('highlighted'));
}
},
methods: {
updatePosition: function (vp) {
var bottom = this.bottom,
left = this.left,
owner = this.owner,
right = this.right,
top = this.top;
if (typeof left === 'number') {
owner.x = vp.left + left;
} else if (typeof right === 'number') {
owner.x = vp.right - right;
}
if (typeof top === 'number') {
owner.y = vp.top + top;
} else if (typeof bottom === 'number') {
owner.y = vp.bottom - bottom;
}
},
updateStateAndTrigger: function (event) {
var message = null,
owner = this.owner,
state = this.state,
pressed = state.get('pressed'),
released = state.get('released'),
toggled = false;
if (released && (event === 'pressed')) {
state.set('pressed', true);
state.set('released', false);
toggled = true;
} else if (pressed && ((event === 'released') || (event === 'cancelled'))) {
state.set('pressed', false);
state.set('released', true);
toggled = true;
}
if (toggled) {
message = Data.setUp(
'released', pressed,
'pressed', released,
'triggered', released,
'entity', owner
);
owner.triggerEvent(event, message);
message.recycle();
}
},
destroy: function () {
this.aabb.recycle();
this.aabb = null;
this.owner.buttonMode = false;
this.state = null;
}
}
});
}());