Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[next] Return of the Stage #4586

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions packages/app/src/Application.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { settings } from '@pixi/settings';
import { Container } from '@pixi/display';
import { Stage } from '@pixi/display';
import { Renderer } from '@pixi/core';
import { Ticker, UPDATE_PRIORITY } from '@pixi/ticker';

Expand Down Expand Up @@ -50,6 +50,8 @@ export default class Application
* for devices with dual graphics card **webgl only**
* @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.Ticker.shared, `false` to create new ticker.
* @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.Loaders.shared, `false` to create new Loader.
* @param {PIXI.Container} {options.stage} - Pass existing stage or container
* @param {number} {options.animationDeltaMax} - How many frames will be processed by animation if user switches the tab
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

55-56 missing dots :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I think this can be addressed as separate PR, we can add this to CI or somewhere

*/
constructor(options, arg2, arg3, arg4, arg5)
{
Expand Down Expand Up @@ -86,7 +88,15 @@ export default class Application
* The root display container that's rendered.
* @member {PIXI.Container}
*/
this.stage = new Container();
this.stage = options.stage || new Stage();

/**
* How many frames will be processed by animation if user switches the tab
*
* @member {number}
* @default 5
*/
this.animationDeltaMax = options.animationDeltaMax || 5;

/**
* Internal reference to the ticker
Expand Down Expand Up @@ -140,8 +150,22 @@ export default class Application
/**
* Render the current stage.
*/
render()
render(delta)
{
if (this.stage.animate)
{
// Time travel animation fix
if (delta < 0)
{
delta = 0;
}
if (delta > this.animationDeltaMax)
{
delta = this.animationDeltaMax;
}
this.stage.onAnimate(delta);
}

this.renderer.render(this.stage);
}

Expand Down
191 changes: 158 additions & 33 deletions packages/display/src/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export default class Container extends DisplayObject
* @readonly
*/
this.children = [];

this.passParentStageToChildren = true;
}

/**
Expand All @@ -42,6 +44,22 @@ export default class Container extends DisplayObject
/* empty */
}

/**
* Returns stage that owns children. Depends on `passParentStageToChildren`
* and whether the container is actually a stage itself
*
* @returns {Container}
*/
getStageForChildren()
{
if (this.innerStage)
{
return this;
}

return this.passParentStageToChildren ? this.parentStage : null;
}

/**
* Adds one or more children to the container.
*
Expand All @@ -66,24 +84,26 @@ export default class Container extends DisplayObject
}
else
{
let newChildStage = this.getStageForChildren();

// if the child has a parent then lets remove it as PixiJS objects can only exist in one place
if (child.parent)
{
child.parent.removeChild(child);
if (child.parentStage !== newChildStage)
{
child.parent.removeChild(child);
}
else
{
child.parent.detachChild(child);
newChildStage = null;
}
}

child.parent = this;
// ensure child transform will be recalculated
child.transform._parentID = -1;

this.children.push(child);

// ensure bounds will be recalculated
this._boundsID++;
this._innerAddChild(child, newChildStage);

// TODO - lets either do all callbacks or all events.. not both!
this.onChildrenChange(this.children.length - 1);
child.emit('added', this);
}

return child;
Expand All @@ -103,25 +123,50 @@ export default class Container extends DisplayObject
throw new Error(`${child}addChildAt: The index ${index} supplied is out of bounds ${this.children.length}`);
}

let newChildStage = this.getStageForChildren();

if (child.parent)
{
child.parent.removeChild(child);
if (child.parentStage !== newChildStage)
{
child.parent.removeChild(child);
}
else
{
child.parent.detachChild(child);
newChildStage = null;
}
}

this.children.splice(index, 0, child);

this._innerAddChild(child, newChildStage);

this.onChildrenChange(index);

return child;
}

/**
* Inner workings of addChild and addChildAt
*
* @param child {PIXI.DisplayObject} new child
* @param newChildStage {PIXI.Stage} if child needs his stage changed
* @private
*/
_innerAddChild(child, newChildStage)
{
child.parent = this;
// ensure child transform will be recalculated
child.transform._parentID = -1;

this.children.splice(index, 0, child);

// ensure bounds will be recalculated
this._boundsID++;

// TODO - lets either do all callbacks or all events.. not both!
this.onChildrenChange(index);
child.emit('added', this);

return child;
if (newChildStage)
{
newChildStage.innerStage.addSubtree(child);
}
}

/**
Expand Down Expand Up @@ -226,17 +271,7 @@ export default class Container extends DisplayObject

if (index === -1) return null;

child.parent = null;
// ensure child transform will be recalculated
child.transform._parentID = -1;
removeItems(this.children, index, 1);

// ensure bounds will be recalculated
this._boundsID++;

// TODO - lets either do all callbacks or all events.. not both!
this.onChildrenChange(index);
child.emit('removed', this);
this._innerRemoveChild(index, child, false);
}

return child;
Expand All @@ -252,6 +287,20 @@ export default class Container extends DisplayObject
{
const child = this.getChildAt(index);

this._innerRemoveChild(index, child, false);

return child;
}

/**
* Inner workings of removeChild and removeChildAt
* @param index
* @param child
* @param detach
* @private
*/
_innerRemoveChild(index, child, detach)
{
// ensure child transform will be recalculated..
child.parent = null;
child.transform._parentID = -1;
Expand All @@ -262,7 +311,67 @@ export default class Container extends DisplayObject

// TODO - lets either do all callbacks or all events.. not both!
this.onChildrenChange(index);
child.emit('removed', this);

const childStage = this.getStageForChildren();

if (childStage)
{
if (detach)
{
childStage.innerStage.detachSubtree(child);
}
else
{
childStage.innerStage.removeSubtree(child);
}
}
}

/**
* Detaches one or more children from the container.
* Stage events woould not fire.
*
* @param {...PIXI.DisplayObject} child - The DisplayObject(s) to remove
* @return {PIXI.DisplayObject} The first child that was detached.
*/
detachChild(child)
{
const argumentsLength = arguments.length;

// if there is only one argument we can bypass looping through the them
if (argumentsLength > 1)
{
// loop through the arguments property and add all children
// use it the right way (.length and [i]) so that this function can still be optimised by JS runtimes
for (let i = 0; i < argumentsLength; i++)
{
this.detachChild(arguments[i]);
}
}
else
{
const index = this.children.indexOf(child);

if (index === -1) return null;

this._innerRemoveChild(index, child, true);
}

return child;
}

/**
* Detaches a child from the specified index position.
* Stage events woould not fire.
*
* @param {number} index - The index to get the child from
* @return {PIXI.DisplayObject} The child that was detached.
*/
detachChildAt(index)
{
const child = this.getChildAt(index);

this._innerRemoveChild(index, child, true);

return child;
}
Expand All @@ -272,9 +381,10 @@ export default class Container extends DisplayObject
*
* @param {number} [beginIndex=0] - The beginning position.
* @param {number} [endIndex=this.children.length] - The ending position. Default value is size of the container.
* @param {boolean} [detach=false] - Whether to fire stage events
* @returns {DisplayObject[]} List of removed children
*/
removeChildren(beginIndex = 0, endIndex)
removeChildren(beginIndex = 0, endIndex, detach)
{
const begin = beginIndex;
const end = typeof endIndex === 'number' ? endIndex : this.children.length;
Expand All @@ -298,9 +408,24 @@ export default class Container extends DisplayObject

this.onChildrenChange(beginIndex);

for (let i = 0; i < removed.length; ++i)
const childStage = this.getStageForChildren();

if (childStage)
{
removed[i].emit('removed', this);
if (detach)
{
for (let i = 0; i < removed.length; ++i)
{
childStage.innerStage.detachSubtree(removed[i]);
}
}
else
{
for (let i = 0; i < removed.length; ++i)
{
childStage.innerStage.removeSubtree(removed[i]);
}
}
}

return removed;
Expand Down
Loading