import { IDisplayObjectAdapter, MovieClip as AwayMovieClip, Sprite as AwaySprite, DisplayObject as AwayDisplayObject, IMovieClipAdapter, SceneGraphPartition, Timeline, FrameScriptManager } from "@awayjs/scene";
import { Sprite } from "./Sprite";
import { Matrix3D } from '@awayjs/core';
import { constructClassFromSymbol } from '../../avm2/constructClassFromSymbol';
import { Event } from "../events/Event";
var includeString: string = '';//TODO
declare var __framescript__;
/**
* The MovieClip class inherits from the following classes: Sprite, DisplayObjectContainer,
* InteractiveObject, DisplayObject, and EventDispatcher.
*
*
Unlike the Sprite object, a MovieClip object has a timeline.
>In Flash Professional, the methods for the MovieClip class provide the same functionality
* as actions that target movie clips. Some additional methods do not have equivalent
* actions in the Actions toolbox in the Actions panel in the Flash authoring tool.
Children instances placed on the Stage in Flash Professional cannot be accessed by code from within the
* constructor of a parent instance since they have not been created at that ponumber in code execution.
* Before accessing the child, the parent must instead either create the child instance
* by code or delay access to a callback that listens for the child to dispatch
* its Event.ADDED_TO_STAGE event.
If you modify any of the following properties of a MovieClip object that contains a motion tween,
* the playhead is stopped in that MovieClip object: alpha, blendMode,
* filters, height, opaqueBackground, rotation,
* scaleX, scaleY, scale9Grid, scrollRect,
* transform, visible, width, x,
* or y. However, it does not stop the playhead in any child MovieClip objects of that
* MovieClip object.
Note:Flash Lite 4 supports the MovieClip.opaqueBackground property only if
* FEATURE_BITMAPCACHE is defined. The default configuration of Flash Lite 4 does not define
* FEATURE_BITMAPCACHE. To enable the MovieClip.opaqueBackground property for a suitable device,
* define FEATURE_BITMAPCACHE in your project.
*/
export class MovieClip extends Sprite implements IMovieClipAdapter {
private static _movieClips: Array = new Array();
// executed directly after a MC has been constructed via Object.create,
// befre the actual constructors have been run
public applySymbol() {}
public static getNewMovieClip(adaptee: AwayMovieClip): MovieClip {
if (MovieClip._movieClips.length) {
var movieClip: MovieClip = MovieClip._movieClips.pop();
movieClip.adaptee = adaptee;
return movieClip;
}
return new MovieClip();
}
//forAVM1:
public _getAbsFrameNumber(param1: any, param2: any): number {
return 0;
}
public callFrame(param1: any) {
}
public _callFrame(param1: any) {
}
public addScript(param1: any) {
return param1;
}
public executeScript(scripts: any) {
if (scripts){
for (let k = 0; k < scripts.length; k++) {
scripts[k].setReceiver(this);
scripts[k].axCall(this);
}
}
}
public initAdapter(): void {
if ((this).executeConstructor) {
FrameScriptManager.queue_as3_constructor(this.adaptee);
}
}
/**
* Creates a new MovieClip instance. After creating the MovieClip, call the
* addChild() or addChildAt() method of a
* display object container that is onstage.
*/
constructor() {
super();
}
protected createAdaptee():AwayDisplayObject{
var adaptee=AwayMovieClip.getNewMovieClip();
(adaptee).timelineMC=true;
adaptee.reset();
//console.log("createAdaptee AwayMovieClip");
(this).noReset=true;
//FrameScriptManager.execute_queue();
return adaptee;
}
// --------------------- stuff needed because of implementing the existing IMovieClipAdapter
public clearPropsDic(){
this["$Bg__setPropDict"].map= new WeakMap();
}
public evalScript(str: string): Function {
var tag: HTMLScriptElement = document.createElement('script');
tag.text = 'var __framescript__ = function() {\n' + includeString + str + '\n}';
//add and remove script tag to dom to trigger compilation
var sibling = document.scripts[0];
sibling.parentNode.insertBefore(tag, sibling).parentNode.removeChild(tag);
var script = __framescript__;
window['__framescript__'] = null;
return script;
}
public freeFromScript(): void {
//this.stopAllSounds();
super.freeFromScript();
}
public clone(): MovieClip {
if(!(this)._symbol){
throw("_symbol not defined when cloning movieclip")
}
//var clone: MovieClip = MovieClip.getNewMovieClip(AwayMovieClip.getNewMovieClip((this.adaptee).timeline));
var newMC:MovieClip=constructClassFromSymbol((this)._symbol, (this)._symbol.symbolClass);
//console.log("clone", (this)._symbol, (this)._symbol.symbolClass);
var adaptee=new AwayMovieClip((this.adaptee).timeline);
//console.log("clone mc", newMC, adaptee, adaptee.id, (this)._symbol, (this)._symbol.symbolClass)
this.adaptee.copyTo(adaptee);
newMC.adaptee=adaptee;
newMC._stage = this.activeStage;
(newMC).executeConstructor=()=>{
(newMC.adaptee).timeline.resetScripts();
//console.log("executeConstructor mc", newMC, newMC.adaptee.id);
var events=(newMC).getQueuedEvents();
(newMC).axInitializer();
if(events){
for(var i=0; inewMC).dispatchEvent(events[i]);
}
}
}
// if this is a custom class (not a plain MC or Sprite)
// make sure that the clone will not be reused on the timeline.
// it must reclone for every new instance thats added to scene, so that the as3 constructor (axInitializer) will run again...
// (if cloneForEveryInstance is true, the awayjs-mc will not cache the instance on the potentialinstance-list)
if((this)._symbol.className){
(newMC.adaptee).cloneForEveryInstance=true;
}
if((newMC.adaptee).timeline){
// hack to BadIceCreamFont compiledClip:
// the compiledClip "BadIcecreamFont" seem to behave different to other classes
// it seem to always stick to frame 0,
if((this)._symbol.className && (this)._symbol.className=="BadIcecreamFont"){
(newMC.adaptee).adaptee.timeline.frame_command_indices=[(newMC.adaptee).timeline.frame_command_indices[0]];
(newMC.adaptee).adaptee.timeline.frame_recipe=[(newMC.adaptee).timeline.frame_recipe[0]];
(newMC.adaptee).adaptee.timeline.keyframe_constructframes=[(newMC.adaptee).timeline.keyframe_constructframes[0]];
(newMC.adaptee).adaptee.timeline.keyframe_durations=[(newMC.adaptee).timeline.keyframe_durations[0]];
(newMC.adaptee).adaptee.timeline.keyframe_firstframes=[(newMC.adaptee).timeline.keyframe_firstframes[0]];
(newMC.adaptee).adaptee.timeline.keyframe_indices=[(newMC.adaptee).timeline.keyframe_indices[0]];
}
}
return newMC;
}
/**
* @inheritDoc
*/
public dispose(): void {
this.disposeValues();
//MovieClip._movieClips.push(this);
}
//---------------------------original as3 properties / methods:
/**
* Specifies the number of the frame in which the playhead is located in the timeline of
* the MovieClip instance. If the movie clip has multiple scenes, this value is the
* frame number in the current scene.
*/
public get currentFrame(): number {
return (this._adaptee).currentFrameIndex + 1;
}
/**
* The label at the current frame in the timeline of the MovieClip instance.
* If the current frame has no label, currentLabel is null.
*/
public get currentFrameLabel(): string {
return (this.adaptee).timeline.getCurrentFrameLabel(this.adaptee);
}
/**
* The current label in which the playhead is located in the timeline of the MovieClip instance.
* If the current frame has no label, currentLabel is set to the name of the previous frame
* that includes a label. If the current frame and previous frames do not include a label,
* currentLabel returns null.
*/
public get currentLabel(): string {
return (this.adaptee).timeline.getCurrentLabel(this.adaptee);
}
/**
* Returns an array of FrameLabel objects from the current scene. If the MovieClip instance does
* not use scenes, the array includes all frame labels from the entire MovieClip instance.
*/
public get currentLabels(): any[] {
//todo
console.log("currentFrameLabel not implemented yet in flash/MovieClip");
return [];
}
/**
* The current scene in which the playhead is located in the timeline of the MovieClip instance.
*/
public get currentScene(): any {
//todo
console.log("currentScene not implemented yet in flash/MovieClip");
return null;
}
/**
* A boolean value that indicates whether a movie clip is enabled. The default value of enabled
* is true. If enabled is set to false, the movie clip's
* Over, Down, and Up frames are disabled. The movie clip
* continues to receive events (for example, mouseDown,
* mouseUp, keyDown, and keyUp).
*
* The enabled property governs only the button-like properties of a movie clip. You
* can change the enabled property at any time; the modified movie clip is immediately
* enabled or disabled. If enabled is set to false, the object is not
* included in automatic tab ordering.
*/
public get enabled(): boolean {
//todo
//console.log("enabled not implemented yet in flash/MovieClip");
return false;
}
public set enabled(value: boolean) {
//todo
//console.log("enabled not implemented yet in flash/MovieClip");
}
/**
* The number of frames that are loaded from a streaming SWF file. You can use the framesLoaded
* property to determine whether the contents of a specific frame and all the frames before it
* loaded and are available locally in the browser. You can also use it to monitor the downloading
* of large SWF files. For example, you might want to display a message to users indicating that
* the SWF file is loading until a specified frame in the SWF file finishes loading.
*
* If the movie clip contains multiple scenes, the framesLoaded property returns the number
* of frames loaded for all scenes in the movie clip.
*/
public get framesLoaded(): number {
//todo
console.log("framesLoaded not implemented yet in flash/MovieClip");
return 0;
}
public get isPlaying(): boolean {
//todo
console.log("isPlaying not implemented yet in flash/MovieClip");
return false;
}
/**
* An array of Scene objects, each listing the name, the number of frames,
* and the frame labels for a scene in the MovieClip instance.
*/
public get scenes(): any[] {
//todo
console.log("scenes not implemented yet in flash/MovieClip");
return [];
}
/**
* The total number of frames in the MovieClip instance.
*
* If the movie clip contains multiple frames, the totalFrames property returns
* the total number of frames in all scenes in the movie clip.
*/
public get totalFrames(): number {
return (this._adaptee).numFrames;
}
/**
* Indicates whether other display objects that are SimpleButton or MovieClip objects can receive
* mouse release events or other user input release events. The trackAsMenu property lets you create menus. You
* can set the trackAsMenu property on any SimpleButton or MovieClip object.
* The default value of the trackAsMenu property is false.
*
* You can change the trackAsMenu property at any time; the modified movie
* clip immediately uses the new behavior.
*/
public get trackAsMenu(): boolean {
//todo
console.log("trackAsMenu not implemented yet in flash/MovieClip");
return false;
}
public set trackAsMenu(value: boolean) {
//todo
console.log("trackAsMenu not implemented yet in flash/MovieClip");
}
public addFrameScript(...args) {
// arguments are pairs of frameIndex and script/function
// frameIndex is in range 0..totalFrames-1
var numArgs = arguments.length;
if (numArgs & 1) {
this.sec.throwError('ArgumentError TooFewArgumentsError', numArgs,
numArgs + 1);
}
for (var i = 0; i < numArgs; i += 2) {
var frameNum = (arguments[i] | 0);
var fn = arguments[i + 1];
(this.adaptee).timeline.add_framescript(fn, frameNum);
// if the mc was already added to scene before the construcor was run,
// no framescript was defined, and therefore we might need to add scripts for the current frame manually
// todo: make sure that this is correctly behaving in case constructor navigates the mc to another frame
/*if(this.adaptee.parent && frameNum==0){//(this.adaptee).currentFrameIndex==frameNum){
FrameScriptManager.add_script_to_queue_pass2(this.adaptee, [fn]);
}*/
}
}
/**
* Starts playing the SWF file at the specified frame. This happens after all
* remaining actions in the frame have finished executing. To specify a scene
* as well as a frame, specify a value for the scene parameter.
* @param frame A number representing the frame number, or a string representing the label of the
* frame, to which the playhead is sent. If you specify a number, it is relative to the
* scene you specify. If you do not specify a scene, the current scene determines the global frame number to play. If you do specify a scene, the playhead
* jumps to the frame number in the specified scene.
* @param scene The name of the scene to play. This parameter is optional.
*/
public gotoAndPlay(frame: any, scene: string = null) {
if (frame == null)
return;
if (typeof frame === "string") {
// todo: only do toLowerCase if FP version <=9
frame=frame.toLowerCase();
if ((this.adaptee).timeline._labels[frame] == null) {
frame = parseInt(frame);
if (!isNaN(frame)) {
(this.adaptee).currentFrameIndex = (frame) - 1;
(this.adaptee).play();
}
return;
}
}
if (typeof frame === "number" && frame <= 0)
return;
this.play();
this._gotoFrame(frame);
FrameScriptManager.execute_as3_constructors();
this.dispatchStaticBroadCastEvent(Event.FRAME_CONSTRUCTED);
FrameScriptManager.execute_queue();
}
/**
* Brings the playhead to the specified frame of the movie clip and stops it there. This happens after all
* remaining actions in the frame have finished executing. If you want to specify a scene in addition to a frame,
* specify a scene parameter.
* @param frame A number representing the frame number, or a string representing the label of the
* frame, to which the playhead is sent. If you specify a number, it is relative to the
* scene you specify. If you do not specify a scene, the current scene determines the global frame number at which to go to and stop. If you do specify a scene,
* the playhead goes to the frame number in the specified scene and stops.
* @param scene The name of the scene. This parameter is optional.
* @throws ArgumentError If the scene or frame specified are
* not found in this movie clip.
*/
public gotoAndStop(frame: any, scene: string = null) {
// in FP for frame==null, we need to stop the mc
if (frame == null){
this.stop();
return;
}
if (typeof frame === "string") {
// todo: only do toLowerCase if FP version <=9
frame=frame.toLowerCase();
if ((this.adaptee).timeline._labels[frame] == null) {
frame = parseInt(frame);
if (!isNaN(frame)) {
(this.adaptee).currentFrameIndex = (frame) - 1;
(this.adaptee).stop();
}
return;
}
}
if (typeof frame === "number" && frame <= 0)
return;
this.stop();
this._gotoFrame(frame);
FrameScriptManager.execute_as3_constructors();
this.dispatchStaticBroadCastEvent(Event.FRAME_CONSTRUCTED);
FrameScriptManager.execute_queue();
}
private _gotoFrame(frame: any): void {
if (typeof frame === "string") {
(this._adaptee).jumpToLabel(frame);
return;
}
if (typeof frame === "number" && frame <= 0)
return;
(this._adaptee).currentFrameIndex = (frame) - 1;
}
/**
* Sends the playhead to the next frame and stops it. This happens after all
* remaining actions in the frame have finished executing.
*/
public nextFrame() {
//todo
console.log("nextFrame not implemented yet in flash/MovieClip");
}
/**
* Moves the playhead to the next scene of the MovieClip instance. This happens after all
* remaining actions in the frame have finished executing.
*/
public nextScene() {
//todo
console.log("nextScene not implemented yet in flash/MovieClip");
}
/**
* Moves the playhead in the timeline of the movie clip.
*/
public play() {
return (this._adaptee).play();
}
/**
* Sends the playhead to the previous frame and stops it. This happens after all
* remaining actions in the frame have finished executing.
*/
public prevFrame() {
if ((this._adaptee).currentFrameIndex > 0) {
(this._adaptee).currentFrameIndex = (this._adaptee).currentFrameIndex - 1;
}
}
/**
* Moves the playhead to the previous scene of the MovieClip instance. This happens after all
* remaining actions in the frame have finished executing.
*/
public prevScene() {
//todo
console.log("prevScene not implemented yet in flash/MovieClip");
}
/**
* Stops the playhead in the movie clip.
*/
public stop() {
return (this._adaptee).stop();
}
}