|Revision 1.0 DRAFT||10/22/2006||jd|
Initial version of this document.
Flash Doctors Dose User Guide
Dose is a set of actionscript objects that are used to represent a foundation of GUI concepts
Table of Contents
List of Examples
Dose can be described as a package of objects that represent low level GUI concepts. It is used as the foundation on which complex, highly designed GUI applications can be built. Dose is *not* a component library and should not be confused with the macromedia/adobe component library or any other third-party component library.
Dose provides very simple, yet powerful interfaces that,
when used together, can accomplish complex GUI scenarios. At the
heart of dose are the
interfaces. (described later). Apart from the actionscript code,
Dose makes use of very simple "templates" that are
MovieClips and/or fla files with
Because dose is not a component framework, it's not meant to be used to create reusable components that can be compiled as swc files and dropped into the components palette inside of the FlashIDE. Instead dose was created to facilitate the creation of highly designed, custom user interfaces.
The easiest way to describe this is by using a simple button metaphor: in dose anything can be a button. This is because in dose, a button is simply something that can be displayed and interacted with using a mouse. This leaves the actual design of the "button" up to the designer... it could be a photo, a line, an entire animation, etc. Dose decouples the functionality from the design, leaving a designer complete freedom while providing the developer a standard way to handle functionality.
Nothing. (for the most-part)... Because every application
is different and has different needs when it comes to
functionality (even on a component level) dose only implements
the bare minimum functionality it needs to work at a low level.
However, dose provides methods for adding any
to objects when it makes sense. Essentially, this allows the
developer to only have to concentrate on what the UI objects are
actually trying to accomplish instead of the mechanism that makes
them work. This will be described throughout the documentation
By itself, dose cannot and does not create or display GUI components directly, instead it wraps movie clips and other displayable entities to provide their GUI functionality. Another way to think about this is "Asset Injection", meaning the actual assets are "injected" into dose objects which in turn can provide functionality to the assets.
This brings us to the concept of "displayables".
A displayable is any dose object that can have a visible stage
asset injected into it. Displayables are the basis for all
visible GUI objects in dose and every displayable dose object
class is provided, which all displayables should extend, as well
concrete class that can be used for most simple assets. There are
a couple of other abstract and concrete displayable classes that
will be described later.
Injecting assets into a displayable is pretty easy and can be done multiple ways:
Simply set the asset
with a setter
Set the asset using it's instance name
Dynamically create a named placeholder clip and load an asset into it
Attach the asset using it's linkageID
Injecting the asset with a setter is the simplest way to inject an asset. To do this, you just need an asset on the stage.
Example 2.1. Creating a displayable and setting it's stage asset
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setStageAsset(_root.someClip);
Injecting the asset using it's instance name is just as easy. To do this you just need a named asset on the stage.
Example 2.2. Creating a displayable and setting it's stage asset by name
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setStageAssetByName("myInstanceName");
Injecting the asset by creating a named placeholder and
loading an asset into it is a bit more tricky, but not much.
First, we need to create the place holder clip. This can be done
getStageAsset() on any
displayable that has not yet had an asset injected into it. When
getStageAsset() is called, it checks to
see if the displayable's asset is null, if it is, an empty
MovieClip is created and named using the
displayable's name property.
Example 2.3. Creating a displayable and dynamically generating it's stage asset
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); var myMC:MovieClip = disp.getStageAsset(); trace(myMC); //traces: _level0.myDisplayable
That was pretty easy, but suppose you need to nest your
displayable's stage asset under another clip or a mask. This
is where the
setContainer() method comes
in. A displayable's
method can be called before calling
getStageAsset() to set the path to the
generated MovieClip. The string passed to the setContainer method
should not include _root or _level0 as it's assumed. Be
aware that if the container path passed to setContainer does not
exist at the time
called, the container will default to _level0;
Example 2.4. Creating a displayable and dynamically generating it's stage asset with a container
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setContainer("clip1.mask"); var myMC:MovieClip = disp.getStageAsset(); trace(myMC); //traces: _level0.clip1.mask.myDisplayable
The next example shows how displayable assets can be nested.
Example 2.5. Nesting displayable stage assets
var disp1:IDisplayable = new Displayable(); disp1.setName("myDisp1"); var myMC1:MovieClip = disp.getStageAsset(); disp2:Displayable = new Displayable(); disp2.setName("myDisp2"); disp2.setContainer("myDisp1"); var myMC2:MovieClip = disp2.getStageAsset(); var disp3:IDisplayable = new Displayable(); disp3.setName("myDisp3"); disp3.setContainer("myDisp1.myDisp2"); var myMC3:MovieClip = disp3.getStageAsset(); trace(myMC1); //traces: _level0.myDisp1 trace(myMC2); //traces: _level0.myDisp1.myDisp2 trace(myMC3); //traces: _level0.myDisp1.myDisp2.myDisp3
Example 2.6. Loading an asset into a displayable
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setContainer("clip1.mask"); var myMC:MovieClip = disp.getStageAsset(); myMC.loadMovie("myAsset.swf");
Injecting the asset using it's linkageID is also very easy. To do this, you just need an asset in the library with a linkageID set. When the setStageAssetByLinkage is called, it uses the container value as the parent MovieClip and uses the name value as the name for the new clip.
Example 2.7. Creating a displayable and attaching it's stage asset
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setStageAssetByLinkage("myLinkageID"); trace(disp.getStageAsset()); //traces: _level0.myDisplayable.myLinkageID
Now that we can get assets into displayables the only thing left is to move the displayable. This is simply done by setting the x and y properties of the displayable.
Example 2.8. Moving a displayable
var disp:IDisplayable = new Displayable(); disp.setName("myDisplayable"); disp.setStageAsset(_root.myClip); disp.setX(10); disp.setY(20);
When the x and y
properties are set on the displayable, the stage asset is moved
immediately. This is important to note because when
setY() are called, they make a call to
getStageAsset(). This means that if
setY() is called before a stage asset is
set, the displayable will auto generate the asset based on the
displayable's name. Care should be taken to make sure
setContainer() is called (if needed)
Although any displayable object in dose can be positioned simply by setting it's x and y properties, layout managers provide an easy yet powerful way to layout entire applications or sections of applications. All layout managers implement the ILayoutManager interface and should extend AbstractLayoutManager.
In general, layout managers take a List of IDisplayables, and a starting position. The starting position is set simply by calling the layout manager's setX() and setY() methods. From there the calculateLayout() method can be called which will return a Layout object which can be looped through to get the end positions of all of the IDisplayables. Although this may be useful in some cases, it's more common to just call the layoutItems() method which will calculate the layout and also position all of the IDisplayables immediately. Keep in mind that the x and y properties are relative to any containers the items may be within.
Dose provides two concrete implementations of ILayoutManager: LinearLayoutManager and StackedLayoutManager
The LinearLayoutManager class is used to layout IDisplayables either horizontally or vertically with equal spacing between each item. To set which type of layout is to be used we simply call the setType() method and pass it one of the type constants: LinearLayoutManager.HORIZONTAL or LinearLayoutManager.VERTICAL (as a shortcut for syringe users, the previous can also be passed in as strings "H" or "V"). If no type is set on the layout manager it defaults to horizontal. The amount of spacing between each item in pixels is set by calling the setSpacing() method. The LinearLayoutManager also has options for setting the horizontal and vertical alignments of the layout which will be discussed later.
Example 3.1. Simple Horizontal Layout with LinearLayoutManager
var disp1:IDisplayable = new Displayable(); disp1.setName("myDisp1"); disp1.setStageAsset(_root.myClip1); var disp2:IDisplayable = new Displayable(); disp2.setName("myDisp2"); disp2.setStageAsset(_root.myClip2); var disp3:IDisplayable = new Displayable(); disp3.setName("myDisp3"); disp3.setStageAsset(_root.myClip3); var layoutMan:LinearLayoutManager = new LinearLayoutManager(); layoutMan.addItem(disp1); layoutMan.addItem(disp2); layoutMan.addItem(disp3); layoutMan.setX(10); layoutMan.setY(10); layoutMan.setSpacing(2); layoutMan.layoutItems();
Laying out items vertically is exactly the same with the exception of setting the type of layout.
Example 3.2. Simple Horizontal Layout with LinearLayoutManager
//create displayables ... var layoutMan:LinearLayoutManager = new LinearLayoutManager(); layoutMan.setType(LinearLayoutManager.VERTICAL); layoutMan.addItem(disp1); layoutMan.addItem(disp2); layoutMan.addItem(disp3); layoutMan.setX(10); layoutMan.setY(10); layoutMan.setSpacing(2); layoutMan.layoutItems();
As mentioned before, there are also options for setting the alignment of items. This is done through the setHalign() and setValign() methods. The possible alignment options are listed below and have different results depending on the type of the layout manager.
The haligh and valign properties are used together to set both the build order and the baseline for the layout manager. When working with type HORIZONTAL the halign sets the builder order and the valign sets the baseline, visa-versa for type VERTICAL.
The build order dictates if the items should be layed out from the beginning or the end of the list as well as if the position set via the x/y properties should be used as the starting or ending position. For HORIZONTAL, halign LEFT assumes the position is the starting position and the items should be layed out beginning to end. RIGHT has the opposite effect. For VERTICAL, TOP and BOTTOM are used in the same way.
Example 3.3. Horizontal Alignment with LinearLayoutManager
//create layoutmanager and add displayables to it here ... layoutMan.setType(LinearLayoutManager.HORIZONTAL); layoutMan.setX(0); layoutMan.setHalign(LinearLayoutManager.LEFT); layoutMan.layoutItems(); //or to align right layoutMan.setType(LinearLayoutManager.HORIZONTAL); layoutMan.setX(100); layoutMan.setHalign(LinearLayoutManager.RIGHT); layoutMan.layoutItems();
Table of Contents
A TabGroup extends AbstractGroup and Implements IGroup. AbstractGroup defaults to using a LinearLayoutManager in HORIZONTAL mode, but can be overridden by calling setLayoutManager.
All groups accept IGroupable objects via addItem() or setItems(). Whenever setLayoutManager(), setItems(), or addItem() is called on the group, the items are automatically added to the group's layout manager. TabGroup exists because it automatically adds the basic mouse interaction commands to each TabButton when it is added to the group.
Every TabButton stage asset should be built following the TabButton movie template. This is simply any movie clip with the following named frames: "disabled", "over", "off", "down", "active". The frame following each of these named frames (or at the end of the state change animation) should have and action frame that includes stop(); This is due to the fact that Dose uses gotoAndPlay(stateFrame) when changing the states of a button. Also, "disabled" should always be the first named frame so that assets are defaulted to the disabled state.
Example 4.1. Creating and Displaying a TabGroup
var btn1:IDisplayable = new TabButton(); btn1.setName("btn1"); btn1.setX(-100); //set the x so the asset loads off stage //use above docs to load in the stage asset ... //repeat for n buttons ... //create our tabgroup var tg:TabGroup = new TabGroup(); //tell it where to start drawing var lm:LinearLayoutManager = LinearLayoutManager(tg.getLayoutManager); lm.setX(10); lm.setY(10); lm.setSpacing(2); tg.addItem(IGroupable(btn1)); tg.addItem(IGroupable(btn1)); tg.addItem(IGroupable(btn1)); //tell the layoutmanager to layout the items lm.layoutItems(); //in syringe, you can use inner beans/lists to set the tabs to the group //the order in which tabs are added to the group are the order in which they display /* syringe use: <bean id="tabGroup" class="com.flashdoctors.dose.ui.group.TabGroup"> <property name="layoutManager"> <bean class="com.flashdoctors.dose.ui.layout.LinearLayoutManager"> <property name="x" value="10"/> <property name="y" value="10"/> <property name="spacing" value="2"/> </bean> </property> <property name="items"> <list> <ref bean="btn1"/> <ref bean="btn2"/> <ref bean="btn3"/> </list> </property> </bean> */