UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

143 lines (126 loc) 3.54 kB
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]; } }