@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
143 lines (126 loc) • 3.54 kB
JavaScript
import domify from "../../DOM.js";
import View from "../../View.js";
class StackFrame {
/**
*
* @param {View} view
* @param {string} name
* @constructor
*/
constructor(view, name) {
/**
*
* @type {View}
*/
this.view = view;
/**
*
* @type {string}
*/
this.name = name;
}
}
export class ViewStack extends View {
/**
*
* @constructor
* @class
* @extends {View}
*/
constructor() {
super();
const $el = domify('div').css({
position: "absolute",
left: 0,
top: 0,
pointerEvents: "none"
});
const element = $el.el;
/*
To enable view to receive focus, it must have a tabindex, focus is required to handle keyboard events
*/
element.setAttribute('tabindex', 0);
this.el = element;
this.addClass('view-stack');
this.__stack = [];
/**
*
* @type {StackFrame | null}
* @private
*/
this.__activeFrame = null;
//automatically resize the active frame when own size changes
this.bindSignal(this.size.onChanged, this.updateActiveFrameSize.bind(this));
}
/**
* @private
*/
updateActiveFrameSize() {
const activeFrame = this.__activeFrame;
if (activeFrame !== null) {
activeFrame.view.size.copy(this.size);
}
}
link() {
super.link();
this.updateActiveFrameSize();
}
/**
* @private
* @param {int} index
*/
setActiveFrame(index) {
const stack = this.__stack;
if (index >= stack.length) {
throw new Error("Index is too high, stack overflow");
}
if (this.__activeFrame !== null) {
//clear old active frame
this.removeChild(this.__activeFrame.view);
}
if (index >= 0) {
const stackFrame = stack[index];
this.__activeFrame = stackFrame;
const child = stackFrame.view;
this.addChild(child);
//resize child
child.size.copy(this.size);
//ensure position is aligned o origin
child.position.set(0, 0);
} else {
this.__activeFrame = null;
}
}
/**
*
* @param {View} view
* @param {string} [name]
*/
push(view, name = '') {
const stack = this.__stack;
const stackFrame = new StackFrame(view, name);
stack.push(stackFrame);
const index = stack.length - 1;
this.setActiveFrame(index);
}
/**
* Works in the same way as "pop", keeps reducing stack size until it's size is equal to supplied size.
* @param {number} size desired stack size
* @returns {StackFrame[]} dropped frames
*/
unwind(size) {
const stack = this.__stack;
const originalStackSize = stack.length;
const droppedFrames = stack.splice(size, originalStackSize - size);
this.setActiveFrame(size - 1);
return droppedFrames;
}
/**
* Pops view from the stack
* @returns {StackFrame|undefined}
*/
pop() {
const droppedFrames = this.unwind(this.__stack.length - 1);
return droppedFrames[0];
}
}