Getting Started - GimmickNG/AIRDock GitHub Wiki

Any basic docking mechanism makes use of the following:

  • IBasicDocker - This handles most of the docking operations;
  • IPanels - These are the panels which are to be docked, and
  • IContainers - These hold the panels which are to be docked.

A default configuration is already supplied in AIRDock by defaults; they are:

  • AIRDock - This is the default IBasicDocker and the ICustomizableDocker (more on that later) implementation class.
  • DefaultContainer - This is the default IContainer implementation.
  • DefaultPanel - This is the default IPanel implementation.

A Simple Docking Tutorial

At the end of this, you should have 3 default panels on the screen, each which can be docked to each others' windows by clicking and dragging on their bottom bars.

Step 1 - Setting up the AIRDock instance

Let's assume the document class is DockingTest.as. You should have the following (boilerplate) code:

package
{
    import flash.display.Sprite;
    public class DockingTest extends Sprite
    {
        public function DockingTest() { }
    }
}

First, create an ICustomizableDocker member variable; this will hold the AIRDock instance (let's call it docker). To initialize the AIRDock instance, it is recommended not to create it via the new() operator; the static function create() is available to create an AIRDock instance from a supplied DockConfig instance. This configures the AIRDock instance before any docking occurs. If an instance is created via new(), no error is thrown, but you may run into errors or other undefined behavior at runtime.

Since we're going with the defaults, we can just use the default DockConfig available to us in the DockDefaults class; (the DockDefaults class is an enumeration class which provides defaults for every parameter for a Docker instance) this is located in the package airdock.enums - we'll call DockDefaults.createDefaultOptions(), which returns a DockConfig with the default configuration. Note that this requires one parameter, and that's the main instance (of type DisplayObjectContainer which will be receiving the dock events. (Advanced users can listen to, and cancel, these events if required.)

IMPORTANT! Under the hood, the main instance which is supplied in the createDefaultOptions() method is required for capturing the native drag events which occur while a drag-dock operation is taking place. As a result, it is advised that you choose a DisplayObjectContainer instance which never disappears from the stage. Most often, the main instance passed is the stage itself, and that should usually be fine, with a caveat: The stage's nativeWindow should never become invisible. It can be transparent, but if it is hidden, or has its visible property set to false, then a few functions - such as dragging a container - may malfunction (the window of the container, when docked, will most likely end up in random positions, away from the mouse pointer).

(In short: Pass the stage as the DisplayObjectContainer for the createDefaultOptions() method, and you should be fine, provided you don't hide the window.)

You should have the following code so far:

package
{
    import airdock.AIRDock;
    import airdock.enums.DockDefaults;
    import flash.display.Sprite;
    public class DockingTest extends Sprite
    {
        private var docker:ICustomizableDocker;
        public function DockingTest() {
            docker = AIRDock.create(DockDefaults.createDefaultOptions(stage));
        }
    }
}

Step 2: Creating a Root Container

A bit of background is required here for this part. Before a panel can be recognized as part of the IBasicDocker instance, the setupPanel() method of the IBasicDocker instance has to be called on it. At this point, the panel is considered local to the IBasicDocker instance (local and non-local/foreign panels and containers are discussed in another topic); a NativeWindow and an IContainer instance are created for it, and the container is referred to as its parked container. It's referred to as a parked container because it never leaves the stage of the panel's auto-created window; when a panel is part of its parked container, or any other panel's parked container, it's said to be docked. When it's not part of any parked container (not even foreign parked containers), then it's said to be integrated.

A root container, hence, is just a non-parked container created by the user, onto which the panels appear if the user wants them to appear. In other words, you can skip this step if you don't want the panels to appear anywhere else except their own parked containers. However, for this tutorial we'd like to display them on the main window's stage, so we'll create a root container which will then be added to the stage.

A ContainerConfig instance is needed to create a container - this is because the IContainerFactory instance of the IBasicDocker accepts a ContainerConfig instance, which it uses in order to initialize a container. Since we're going with the defaults, and we're only going to create DefaultContainers, these need nothing except the width and the height of the container at the time of its initialization. Since the default IContainerFactory instance produces DefaultContainers, no extra effort is required - simply call the createContainer() method of the IBasicDocker instance from earlier, and pass in the container configuration.

After calling the createContainer() method, a reference to the new container is returned. Store that in a variable (e.g. rootContainer); add this to the stage. (Note: You can't add IContainers to the stage directly; a cast to DisplayObject is required.)

You should have something like this:

package
{
    import airdock.AIRDock;
    import airdock.enums.DockDefaults;
    import airdock.config.ContainerConfig;
    import flash.display.Sprite;
    public class DockingTest extends Sprite
    {
        private var docker:ICustomizableDocker;
        public function DockingTest()
        {
            var config:ContainerConfig;
            var rootContainer:IContainer;
            
            docker = AIRDock.create(DockDefaults.createDefaultOptions(stage));
            config = new ContainerConfig();
            config.width = config.height = 400;    //a 400x400 container
            rootContainer = docker.createContainer(config);
            stage.addChild(rootContainer as DisplayObject);
        }
    }
}

Step 3: Adding the Panels

So far, we've set up the IBasicDocker instance, and created a root container which was added to the stage. It still looks quite empty, though - let's solve that by adding some panels.

There are 2 ways of attaching panels to an IBasicDocker instance - either a panel can be created using the createPanel() method of the IBasicDocker, or the panel can be created externally, and the setupPanel() method of the IBasicDocker called with the panel passed into the function. The second option is more useful, although there are a few cases where the first is more appropriate; here, since we're only concerned with the defaults, we'll create a DefaultPanel and attach it to the root container.

Much like a container, a panel also requires a set of configuration options to be passed to the IBasicDocker; internally, this is used by the IBasicDocker's IPanelFactory to initialize the panel. Since the default panel factory produces DefaultPanels, no extra effort is needed - just creating a panel configuration and passing it. In this case, the default panel's configuration requires only the width and height; a color parameter is also present, which is the background color of the panel that's going to be created. If left blank, the background color of the panel will be black. We'll choose a more colorful layout, and so we'll also set the color parameter to be a random color each time (note that this is a 32-bit AARRGGBB color, and not a 24-bit RRGGBB color; passing a 24-bit integer will result in a transparent panel since its background color will have an alpha of 0.)

There are two things to note here:

  • A new PanelConfig instance need not be created for each panel - since the panel factory only requires it at the time of initialization, the same instance can be reused with different options each time.
  • A panel created via createPanel(), like the ones here, are already setup; it is not required (and indeed, not recommended) to call setupPanel() with them either.

After calling the createPanel() method, a new IPanel (in this case, a DefaultPanel) instance is returned. We're going to attach this to the root container, so keep a reference to it handy.

Step 3.5 Adding Panels to the Root Container

Adding a panel to a container is relatively straightforward: the IContainer interface defines the following function:

public function addToSide(side:int, panel:IPanel):IContainer

This function takes a side* (to which the panel is added), and the panel itself, and returns an IContainer instance, which is the container to which the panel has been added. This can be the same container (if the side is ContainerSide.FILL), or a subcontainer (if the side is any of the other 4.)

For now, we'll add the panel to the centre (that is, ContainerSide.FILL.) You should have the following code:

package
{
    import airdock.AIRDock;
    import airdock.enums.DockDefaults;
    import airdock.enums.ContainerSide;
    import airdock.config.ContainerConfig;
    import flash.display.Sprite;
    public class DockingTest extends Sprite
    {
        private var docker:ICustomizableDocker;
        public function DockingTest()
        {
            var config:ContainerConfig;
            var rootContainer:IContainer;
                        
            var panel:IPanel;
            var panelConfig:PanelConfig;
            
            panelConfig = new PanelConfig();
            panelConfig.color = Math.random() * 0xFFFFFFFF;    //32-bit AARRGGBB color
            panelConfig.width = panelConfig.height = 400;

            docker = AIRDock.create(DockDefaults.createDefaultOptions(stage));
            config = new ContainerConfig();
            config.width = config.height = 400;    //a 400x400 container
            rootContainer = docker.createContainer(config);
            
            panel = docker.createPanel(panelConfig);
            rootContainer.addToSide(ContainerSide.FILL, panel);
            
            stage.addChild(rootContainer as DisplayObject);
        }
    }
}

Repeat the panel creation section again; this time, we'll add it to the left (ContainerSide.LEFT) and the BOTTOM (ContainerSide.BOTTOM) side, just to see what the final layout looks like (for rules on container layouts, please see the Container Sides page); you should end up with:

package
{
    import airdock.AIRDock;
    import airdock.enums.DockDefaults;
    import airdock.enums.ContainerSide;
    import airdock.config.ContainerConfig;
    import flash.display.Sprite;
    public class DockingTest extends Sprite
    {
        private var docker:ICustomizableDocker;
        public function DockingTest()
        {
            var config:ContainerConfig;
            var rootContainer:IContainer;
                        
            var panel:IPanel;
            var panelConfig:PanelConfig;
            
            docker = AIRDock.create(DockDefaults.createDefaultOptions(stage));
            config = new ContainerConfig();
            config.width = config.height = 400;    //a 400x400 container
            rootContainer = docker.createContainer(config);
            
            panelConfig = new PanelConfig();
            panelConfig.color = Math.random() * 0xFFFFFFFF;    //32-bit AARRGGBB color
            panelConfig.width = panelConfig.height = 400;
            panel = docker.createPanel(panelConfig);
            rootContainer.addToSide(ContainerSide.FILL, panel);
            
            panelConfig.color = Math.random() * 0xFFFFFFFF;
            panel = docker.createPanel(panelConfig);
            rootContainer.addToSide(ContainerSide.LEFT, panel);
            
            panelConfig.color = Math.random() * 0xFFFFFFFF;
            panel = docker.createPanel(panelConfig);
            rootContainer.addToSide(ContainerSide.RIGHT, panel);
            
            stage.addChild(rootContainer as DisplayObject);
        }
    }
}

You should now see 3 panels on the stage's root container; play around with it! And with that, that's the end of this tutorial.

Notes

*There are 5 sides: TOP, BOTTOM, LEFT, RIGHT and FILL, as defined in the ContainerSide enumeration class. These attach the panel or container to the top, bottom, left, right or the entire container, respectively. Wasn't that easy? (A few caveats are underlined in the page Container Sides.)