Friday, April 17, 2009
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
public class UndoRedo extends MovieClip {
private var UndoHistory:Array=new Array();
private var RedoHistory:Array=new Array();
private var draging:Boolean=new Boolean();
private var presentSelectedObject:MovieClip;
private var newObj:MovieClip;
private var beforeDrag:Object;
public function UndoRedo():void {
stage.addEventListener(MouseEvent.MOUSE_DOWN,moveObject);
stage.addEventListener(MouseEvent.MOUSE_UP,stopMoveObject);
increase.addEventListener(MouseEvent.CLICK,increaseSize);
decrease.addEventListener(MouseEvent.CLICK,decreaseSize);
undo.addEventListener(MouseEvent.CLICK,undoAction);
redo.addEventListener(MouseEvent.CLICK,redoAction);
create.addEventListener(MouseEvent.CLICK,createNew);
remove.addEventListener(MouseEvent.CLICK,removeSelected);
}
private function createNew(event:MouseEvent):void {
newObj=new object();
newObj.name="obj";
addChild(newObj);
presentSelectedObject=newObj;
RedoHistory.splice(0,RedoHistory.length);
UndoHistory.push({target:presentSelectedObject,Action:"Created",oldValue:null,newValue:(getObjectProperties(presentSelectedObject))});
}
private function removeSelected(event:MouseEvent):void {
RedoHistory.splice(0, RedoHistory.length);
UndoHistory.push({target:presentSelectedObject,Action:"Distroyed",oldValue:(getObjectProperties(presentSelectedObject)),newValue:null});
removeChildAt(getChildIndex(presentSelectedObject));
}
private function increaseSize(event:MouseEvent):void {
var temp:Object=getObjectProperties(presentSelectedObject);
presentSelectedObject.width+=5;
presentSelectedObject.height+=5;
RedoHistory.splice(0,RedoHistory.length);
UndoHistory.push({target:presentSelectedObject,Action:"Edited",oldValue:temp,newValue:(getObjectProperties(presentSelectedObject))});
}
private function decreaseSize(event:MouseEvent):void {
presentSelectedObject.width-=5;
presentSelectedObject.height-=5;
}
private function moveObject(event:MouseEvent):void {
if (event.target.name.indexOf("obj")!=-1) {
presentSelectedObject=MovieClip(event.target);
beforeDrag=getObjectProperties(presentSelectedObject);
MovieClip(event.target).startDrag(false);
draging=true;
}
}
private function stopMoveObject(event:MouseEvent):void {
if (draging) {
presentSelectedObject.stopDrag();
draging=false;
RedoHistory.splice(0,RedoHistory.length);
UndoHistory.push({target:presentSelectedObject,Action:"Edited",oldValue:beforeDrag,newValue:(getObjectProperties(presentSelectedObject))});
}
}
private function getObjectProperties(target:MovieClip):Object {
var prop:Object=new Object();
prop.x=target.x;
prop.y=target.y;
prop.width=target.width;
prop.height=target.height;
prop.scaleX=target.scaleX;
prop.scaleY=target.scaleY;
prop.rotation=target.rotation;
return prop;
}
private function setObject(target:MovieClip,prop:Object):void {
target.x=prop.x;
target.y=prop.y;
target.width=prop.width;
target.height=prop.height;
target.scaleX=prop.scaleX;
target.scaleY=prop.scaleY;
}
private function undoAction(event:MouseEvent):void {
if (UndoHistory.length) {
switch (UndoHistory[UndoHistory.length-1].Action) {
case "Edited" :
setObject(MovieClip(UndoHistory[UndoHistory.length-1].target),UndoHistory[UndoHistory.length-1].oldValue);
break;
case "Created" :
removeChildAt(getChildIndex(MovieClip(UndoHistory[UndoHistory.length-1].target)));
break;
case "Distroyed" :
addChild(MovieClip(UndoHistory[UndoHistory.length-1].target));
setObject(MovieClip(UndoHistory[UndoHistory.length-1].target),UndoHistory[UndoHistory.length-1].oldValue);
break;
}
//RedoHistory.splice(0,RedoHistory.length);
RedoHistory.push(UndoHistory[UndoHistory.length-1]);
UndoHistory.pop();
}
}
private function redoAction(event:MouseEvent):void {
if (RedoHistory.length) {
switch (RedoHistory[RedoHistory.length-1].Action) {
case "Edited" :
setObject(MovieClip(RedoHistory[RedoHistory.length-1].target),RedoHistory[RedoHistory.length-1].newValue);
break;
case "Created" :
addChild(MovieClip(RedoHistory[RedoHistory.length-1].target));
break;
case "Distroyed" :
removeChildAt(getChildIndex(MovieClip(RedoHistory[RedoHistory.length-1].target)));
break;
}
UndoHistory.push(RedoHistory[RedoHistory.length-1]);
RedoHistory.pop();
}
}
}
}
Friday, March 27, 2009
Tips for learning ActionScript 3.0
- Note that declarations with no access specifier now default to
package internal
, notpublic
. The default access specifier for declarations is nowinternal
instead ofpublic
, meaning that the definition is visible only to the package containing the definition, not to all code. This is consistent with other languages such as Java. Because ActionScript 2.0 declarations defaulted topublic
, this change will likely be a common pitfall, so always put an access specifier on your declarations to make the intent crystal-clear. To encourage this best practice, the ActionScript 3.0 compiler will output a warning when no access specifier is used. - Note that classes are sealed by default, meaning properties cannot be added dynamically at runtime. Classes can now be either dynamic or sealed. Dynamic classes can add additional dynamic properties at runtime; sealed classes cannot. Sealed classes conserve memory because no internal hash table is needed to store dynamic properties, and the compiler can provide better error feedback. The declaration
class Foo
is sealed. To declare a class dynamic, use thedynamic
keyword—for example,dynamic class Foo
. -
Use
package
declarations to put a class definition into a package. Thepackage
keyword is new to ActionScript 3.0.ActionScript 2.0 code:
class mx.controls.Button { ... }
ActionScript 3.0 code:
package mx.controls { class Button { .. } }
As in ActionScript 2.0, a
public
class must be in a file with the same name as the class. Multiple classes may be declared in a single file, but only one class may be public, and its name must match the filename. -
Import classes, even if references to the class are fully qualified. To use a class
MyPackage.MyClass
, you must import it with:import MyPackage.MyClass;
This is true even if all references are fully qualified, that is using the full name
MyPackage.MyClass
. In ActionScript 3.0, theimport
statement indicates that you want to use a class definition from another package, whereas in ActionScript 2.0 it was only used to create shorthand names. In ActionScript 3.0, the full class name is only used for disambiguation, and is no longer a substitute for theimport
statement.It is also possible to import all of the definitions in a package using the * wildcard character:
import MyPackage.*;
It is considered best practice to import definitions individually, because it results in less ambiguity about which definitions your code uses.
- Always mark method overrides. The
override
keyword helps avoid common pitfalls of overriding methods, such as specifying the wrong name or method signature for an overridden method, or when the name of the overridden method changes. It also makes it clear when looking at the code that a method is being overridden. Because it knows whether a method is intended tooverride
another, the compiler can perform more useful validation. Theoverride
keyword in ActionScript 3.0 is inspired by the C#override
keyword. - Declare return types in your functions. It is considered best practice to declare a return type for a function. If you omit a return type, a warning will be displayed. This is done for type safety, so that you don't accidentally leave a return type off and get the default return type of Object. If a function doesn't return any value, declare its return type as
void
. -
Note that delegates are now built into the language, making event dispatching easier. In ActionScript 2.0, routing an event to a method required use of the
mx.utils.Delegate
class or other workarounds:import mx.utils.Delegate;
myButton.addEventListener("click", Delegate.create(this, onClick));In ActionScript 3.0, a reference to a method automatically remembers the object instance from which it was extracted. This is called a method closure. In essence, it is an automatic delegate. So, the code can simply be written as:
myButton.addEventListener("click", onClick);
- Note that dereferencing a null or undefined reference will now throw an exception. Dereferencing null or undefined in legacy ActionScript was ignored and evaluated to undefined. Now, a TypeError exception will be thrown. Watch out for code that casually dereferenced null or undefined, and depended on the silent failure behavior. The new exception-throwing behavior is compliant with the ECMAScript specification.
- Use the
-verbose-stacktraces
and-debug
options. Compiling with the command-line options-verbose-stacktraces
and-debug
causes filenames and line numbers to appear in the Flash Player runtime alerts. When a runtime error occurs, a dialog box describes the error and lists the call stack where it occurred. Using the-verbose-stacktraces
and-debug
options can make it easier to locate the source of an error in your code. - Explicitly declare properties to be bindable. Properties are no longer bindable by default. You must declare them to be bindable by using the
[Bindable]
metadata tag. - Note that the Flash Player API has been reorganized into packages. Formerly all classes and functions in the Flash Player API were global. Now there are many packages such as flash.display, flash.events, flash.ui, and so on. For example, MovieClip is now
flash.display.MovieClip
andgetTimer
andsetInterval
have been moved to the flash.utils package. - Use the new Timer class instead of setInterval/setTimeout. The new
Timer
class provides a cleaner mechanism for timer events than thesetInterval
andsetTimeout
functions. The newTimer
class has a number of advantages oversetInterval
, such as not having to deal with interval ID numbers, and a more modern, object-oriented interface. We regard usingTimer
instead ofsetInterval
andsetTimeout
as a best practice. Be sure to subclass events. Events are now strongly typed, and must be subclasses of the new
Event
base class. The newEvent
class makes the event system clearer and more efficient. However, this also means that you can no longer use a generic instance of classObject
when dispatching events, and you cannot use the object literal shorthand—for example,{type: 'customEvent' }
.Instead of creating a generic
Object
class, you now need to use theEvent
class (for example,dispatchEvent(new Event ('myCustomEventType'))
). You need to subclassEvent
if you want to pass additional properties. The motivation for not usingObject
is to achieve greater type safety and efficiency.- Note that visual elements must extend
DisplayObject
, and you can define them like any other class. Components are now created dynamically with new and added to the display list usingaddChild
. As a result,createChild
has been deprecated. Visual entities, includingTextField
, can be instantiated like any other object and simply added to a display list usingaddChild
oraddChildAt
. Note that this means certain APIs are gone, such ascreateEmptyMovieClip
andcreateTextField
. In order to create anew TextField
you usenew TextField
instead ofcreateTextField
. - Note that E4X (ECMAScript for XML) is now the recommended means of manipulating XML in Flash. E4X is far more powerful and better integrated into the language than the legacy Flash XML class, and provides a host of new capabilities. The legacy Flash XML class is still available for use. If you prefer the legacy XML API, renamed to XMLDocument, it is still available in the flash.xml package.
- Use the
toXMLString
method when using E4X. ThetoString
method does not necessarily return the complete XML markup for the object; to get that, use thetoXMLString
method. ThetoString
method returns a convenient string value for the XML object. It does not necessarily serialize the XML object in its entirety. To get the XML markup, call thetoXMLString
method. - Note that the
for...in
loop will no longer enumerate properties and methods declared by a class. It only enumerates dynamic properties of an object. ActionScript 3.0 features a new and more advanced mechanism for object introspection, calleddescribeType
. Use it to introspect objects in ActionScript 3.0. - Note that the root object of a SWF file can now be an instance of a custom class of your choice. In ActionScript 2.0, the root object of a SWF file was always of class
MovieClip
. In ActionScript 3.0, it may be any subclass of Sprite. You can set a class definition to be theDocumentRoot
of a SWF file. When it's loaded, the SWF file will instantiate that class to serve as its root object.
ACTION SCRIPT 3.0 OVERVIEW
ActionScript 3.0 is a powerful, object-oriented programming language that signifies an important step in the evolution of the capabilities of the Flash Player runtime. The motivation driving ActionScript 3.0 is to create a language ideally suited for rapidly building rich Internet applications, which have become an essential part of the web experience.
Earlier versions of ActionScript offered the power and flexibility required for creating truly engaging online experiences. ActionScript 3.0 now further advances the language, providing superb performance and ease of development to facilitate highly complex applications, large datasets, and object-oriented, reusable code bases. With ActionScript 3.0, developers can achieve excellent productivity and performance with content and applications that target Flash Player.
ActionScript 3.0 is based on ECMAScript, the international standardized programming language for scripting. ActionScript 3.0 is compliant with the ECMAScript Language Specification, Third Edition (ECMA-262). It also contains functionality based on ongoing work on ECMAScript Edition 4, occurring within the ECMA standards body.
ActionScript is executed by the ActionScript Virtual Machine (AVM) built into the Flash Player. AVM1, the virtual machine used to execute legacy ActionScript code, powers Flash Player today and makes possible a wide range of interactive media and rich Internet applications.
However, developers have started to push AVM1 to its limits; their project requirements now demand a major breakthrough. ActionScript 3.0 introduces a new highly optimized ActionScript Virtual Machine, AVM2, which dramatically exceeds the performance possible with AVM1. As a result, ActionScript 3.0 code executes up to 10 times faster than legacy ActionScript code.
The new AVM2 virtual machine is available in Flash Player 9, and will be the primary virtual machine for ActionScript execution going forward. The older AVM1 will continue to be supported by Flash Player for backwards compatibility with existing and legacy content.
There are numerous products that generate content and applications targeted at the Flash Player runtime. Often these products incorporate support for ActionScript to add interactivity and behavior to their output. In the Adobe product family, professional designers and developers might use ActionScript within several tools and servers—such as Flash, Flex, and Flash Media Server—to create content and applications for Flash Player. The Flex product family, including the new Eclipse-based Flex Builder 2 IDE, will be the first product line to access the new capabilities of ActionScript 3.0.
Goals of ActionScript 3.0
We wanted ActionScript 3.0 to deliver an improved, consistent programming model; compliance with industry standards; and performance an order of magnitude greater than what we delivered in the past. Although ActionScript 3.0 represents a new programming model for the runtime, it is one that will be familiar to developers with a basic knowledge of object-oriented programming.
ActionScript 3.0 is designed to address the following goals:
- Safety: The language supports type safety so developers can write unambiguous, easily maintainable code.
- Simplicity: The language is intuitive enough for developers to be able to read and write programs without constantly consulting a reference manual.
- Performance: The language enables developers to write complex programs that perform efficiently and responsively.
- Compatibility: The language provides a short backward and forward compatibility path and a significant overlap with industry standards. ActionScript 3.0 is a dialect of ECMAScript which formalizes the features of ActionScript 2.0, adds the capabilities of ECMAScript for XML (E4X), and unifies the language into a coherent whole.
Features of ActionScript 3.0
ActionScript 3.0 consists of two parts: the core language and the Flash Player API. The core language defines the basic building blocks of the programming language, such as statements, expressions, conditions, loops, and types. The Flash Player API is made up of classes that represent and provide access to Flash Player–specific functionality
ActionScript 3.0 contains a host of powerful new features that can greatly speed the development process. Regular expression support enables a variety of powerful operations on text. ECMAScript for XML (E4X) transforms XML into a native data type, dramatically simplifying XML processing. The new Display List API makes working with visual objects far more straightforward and consistent. The standardized DOM event model cements the way those objects talk and respond to each other at runtime. These are only a few of the many new capabilities of ActionScript 3.0.
Language features
ActionScript 3.0 brings the core language aspects of ActionScript 2.0 into compliance with the ECMAScript standard and introduces some areas of new or enhanced functionality.
Following is a high-level summary of the developer benefits and usage of some of the new features.
Runtime exceptions
In ActionScript 2.0, many runtime errors would fail in a graceful but silent fashion. This ensured that Flash Player would not display some inexplicable dialog box, which JavaScript did in early web browsers. On the other hand, this lack of error reporting made it more challenging to debug ActionScript programs.
ActionScript 3.0 introduces a variety of runtime exceptions for common error conditions, improving the debugging experience and enabling applications that handle errors robustly. Runtime errors can provide stack traces annotated with source file and line number information, helping to pinpoint errors quickly.
Runtime types
In ActionScript 2.0, type annotations were primarily an aid for developers; at runtime, all values were dynamically typed.
In ActionScript 3.0, type information is preserved at runtime and utilized for a number of purposes. Flash Player performs runtime type checking, improving the system's type safety. Type information is also used to represent variables in native machine representations, improving performance and reducing memory usage.
Sealed classes
ActionScript 3.0 introduces the concept of a sealed class. A sealed class possesses only the fixed set of properties and methods that were defined at compile-time; additional properties and methods cannot be added. This makes stricter compile-time checking possible, resulting in more robust programs. It also improves memory usage by not requiring an internal hash table for each object instance. Dynamic classes are also possible using the dynamic keyword.
Method closures
Event handling is simplified in ActionScript 3.0 thanks to method closures, which provide built-in event delegation. In ActionScript 2.0, a closure would not remember what object instance it was extracted from, leading to unexpected behavior when the closure was invoked. The mx.utils.Delegate class was a popular workaround; to use it, you would write code as follows:
myButton.addEventListener("click", Delegate.create(this, someMethod));
Delegate.create(this, someMethod)
This class is no longer needed because in ActionScript 3.0, a method closure will be generated when someMethod
is referenced. The method closure will automatically remember its original object instance. Now, one can simply write:
myButton.addEventListener("click", someMethod);
ECMAScript for XML (E4X)
ActionScript 3.0 features a full implementation of ECMAScript for XML (E4X), recently standardized as ECMA-357. E4X offers a natural, fluent set of language constructs for manipulating XML. Unlike traditional XML parsing APIs, E4X makes XML feel like a native data type of the language. E4X streamlines the development of applications that manipulate XML by drastically reducing the amount of code needed.
Regular expressions
ActionScript 3.0 includes native support for regular expressions so you can quickly search for and manipulate strings. ActionScript 3.0 implements the regular expressions defined in the ECMAScript Language Specification (ECMA-262).
Namespaces
Namespaces are an innovative new mechanism for controlling visibility of declarations. Similar to the traditional access specifiers used to control visibility of declarations (public, private, protected), namespaces are essentially custom access specifiers, which can have names of your choosing. The Flex framework, for example, uses an mx_internal namespace for its internal data. Namespaces are outfitted with a Universal Resource Identifier (URI) to avoid collisions, and are also used to represent XML namespaces when working with E4X.
New primitive types
ActionScript 2.0 had a single numeric type, Number
, a double-precision floating point number. One welcome addition to ActionScript 3.0 is the new int
type—a 32-bit signed integer that lets ActionScript code take advantage of the fast integer math capabilities of the CPU. The int
type is great for loop counters and almost anywhere a decimal point isn't needed. Another new type is uint
, an unsigned 32-bit integer type similar to int
.
Flash Player API features
The Flash Player API is a set of classes and functions that expose the capabilities of Flash Player to the ActionScript language. This functionality is the bridge between the ActionScript core language and the rest of the platform. It is the source of much of the power available to Flash applications and is a very important complement to the core language. Although there isn't space here to cover the APIs in detail, here is a short list of some of the new and interesting functionality available to developers:
DOM3 event model
The event model provides a standard way of generating and handling event messages so that objects within applications can interact and communicate, maintaining state and responding to change. Patterned after the W3C DOM3 Events specification, this model provides a clearer and more efficient mechanism than the event systems available in previous versions of ActionScript. The Flex application framework uses the same event model as the Flash Player API, so the event system is unified across the platform from top to bottom.
Display List API
The Display List API consists of a revamped set of classes for working with the visual primitives in Flash.
The new Sprite class is a lightweight building block, similar to MovieClip but more appropriate as a base class for UI components. The new Shape class represents raw vector shapes. These classes can be instantiated naturally with the new operator and can be dynamically re-parented at any time.
There is no longer any need to assign depth numbers to display list objects. Depth management is now automatic and built into Flash Player. New methods are provided for specifying and managing the z-order of objects.