/*
* Director
*
* Copyright (c) 2014 Renato de Pontes Pereira.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* @module Creatine
**/
// namespace:
this.creatine = this.creatine || {};
(function() {
"use strict";
/**
* Director is the class which controls the scenes of the application, that
* involves storing the current scene which is running, receiving the next
* scene which will replace the current one, and applying the transition
* effect between the old and the new scenes. When the current scene is
* replaced by a new one, the Director will automatically remove the old scene
* from stage and add the new scene to it.
*
* Only a single scene can be active at a time, however, Director can handle a
* scene stack, allowing the addition of a new scene keeping the old one in the
* stack, thus, allowing the two scenes to be drawing. This feature is
* specially useful to overlap scene and create, for example, a
* semi-transparent pause scene.
*
* It is possible to specify a transition effect in any action of adding or
* removing scenes, making possible to slide a new scene to the screen or to
* make the old scene fade away. To know more about transitions, consult the
* module creatine.transitions.
*
* Notice that, when using the Director, it is assumed that all display objects
* will be added through scenes, so it is not advisable to manually add display
* objects to stage.
*
Example
*
* // Create the Director
* var director = new creatine.Director(stage);
*
* // Adds the first scene
* director.push(new MyCustomScene());
*
* // Replaces the current scene
* director.replace(new OtherCustomScene());
*
* @class Director
* @constructor
* @param {createjs.Stage} stage A createjs.Stage object.
**/
var Director = function(stage) {
this.initialize(stage);
}
var p = Director.prototype;
/**
* The createjs.Stage instance.
*
* @property stage
* @type {createjs.Stage}
* @private
**/
p.stage = null;
/**
* The active scene. This variable can be viewed as the top of the scene
* stack.
*
* @property scene
* @type {Scene}
* @readonly
**/
p.scene = null;
/**
* The next scene which will replace the actual one. This variable is
* required to store the next scene until the transition effect is done.
*
* @property nextScene
* @type {Scene}
* @readonly
**/
p.nextScene = null;
/**
* The stack of scenes. This list only stores the inactive scenes, use the
* {{#crossLink "Director/scene:property"}}{{/crossLink}} to access the
* active scene.
*
* @property sceneStack
* @type {list}
* @readonly
**/
p.sceneStack = null;
/**
* Indicates if a transition effect is running or not.
*
* @property sceneStack
* @type boolean
* @readonly
**/
p.inTransition = false;
/**
* Initialization method.
*
* @method initialize
* @param {createjs.Stage} stage A createjs.Stage object.
* @protected
**/
p.initialize = function(stage) {
this.stage = stage;
this.scene = null;
this.nextScene = null;
this.sceneStack = [];
this.inTransition = null;
}
/**
* Pauses the current scene and send it to the stack. The new scene will
* replace the current one.
*
* If transition is provided, the transition effect will be applied before
* replacing scenes.
*
* @method push
* @param {Scene} scene The new scene.
* @param {Transition} transition A transition effect.
**/
p.push = function(scene, transition) {
if (this.scene) {
this.scene.dispatchEvent('scenepause');
this.sceneStack.push(this.scene);
// this.scene.paused = true;
}
this.nextScene = scene;
this.stage.addChild(scene);
var this_ = this;
var setScene = function() {
this_.inTransition = false;
this_.scene = this_.nextScene;
this_.scene.dispatchEvent('sceneenter');
this_.nextScene = null;
}
if (transition) {
this.inTransition = true;
transition.run(this, this.scene||{}, this.nextScene, setScene);
} else {
setScene();
}
}
/**
* Removes the current scene and reactive the scene at the top of the
* stack.
*
* If transition is provided, the transition effect will be applied before
* replacing scenes.
*
* @method pop
* @param {Transition} transition A transition effect.
**/
p.pop = function(transition) {
if (this.sceneStack.length == 0) return;
var scene = this.sceneStack.pop();
this.nextScene = scene;
var this_ = this;
var setScene = function() {
this_.inTransition = false;
if (this_.scene) {
this_.scene.dispatchEvent('sceneexit');
this_.stage.removeChild(this_.scene);
}
this_.scene = this_.nextScene;
this_.scene.dispatchEvent('sceneresume');
this_.nextScene = null;
}
if (transition) {
this.inTransition = true;
transition.run(this, this.scene||{}, this.nextScene, setScene);
} else {
setScene();
}
}
/**
* Replaces the current scene by a new one.
*
* If transition is provided, the transition effect will be applied before
* replacing scenes.
*
* @method replace
* @param {Scene} scene The new scene.
* @param {Transition} transition A transition effect.
**/
p.replace = function(scene, transition) {
this.stage.addChild(scene);
this.nextScene = scene;
var this_ = this;
var setScene = function() {
this_.inTransition = false;
if (this_.scene) {
this_.scene.dispatchEvent('sceneexit');
this_.stage.removeChild(this_.scene);
}
this_.scene = this_.nextScene;
this_.scene.dispatchEvent('sceneenter');
this_.nextScene = null;
}
if (transition) {
this.inTransition = true;
transition.run(this, this.scene||{}, this.nextScene, setScene);
} else {
setScene();
}
}
/**
* Swap the position of {{#crossLink "Director/scene:property"}}{{/crossLink}}
* and {{#crossLink "Director/nextScene:property"}}{{/crossLink}} in the
* stage. This method is used in transitions to change the z-index of
* scenes.
*
* @method swapScenes
* @protected
**/
p.swapScenes = function() {
this.stage.swapChildrenAt(
this.stage.getChildIndex(this.scene),
this.stage.getChildIndex(this.nextScene)
);
}
/**
* Removes all scenes from the stack, without transitions.
*
* @method clearStack
**/
p.clearStack = function() {
for (var i=0; i