Menu

PopUpAnchor Spec

SourceForge Editorial Staff

Jason Szeto (Dev)
Jacob Goldstein (QA)

Functional and Design Specification


Glossary


dropDown component - general term referring to a component that contains an anchor button and a dropDown
popUp - refers to the DisplayObject displayed by the PopUpAnchor component

Summary and Background


The PopUpAnchor component is used to display a popUp in the context of a layout. The PopUpAnchor component itself has no visual appearance, but it has dimensions and can participate in layout.
The PopUpAnchor displays the popUp by adding it to the PopUpManager, then sizes and positions the popUp relative to itself.

Usage Scenarios


PopUpAnchor is useful for dropDown components, such as DropDownList or DropDownColorPicker. For DropDownList, PopUpAnchor is used to open and close the dropDown List. Since PopUpAnchor uses the PopUpManager to display its popUp, this ensures that the dropDown List appears above all other controls.

A video player requires a volume slider. The video player design calls for minimizing the space used by the interaction controls. The player has a small button with a volume icon. When the button is pressed, a VSlider slides down below the button. When a volume is selected on the slider, the VSlider slides back towards the button and is hidden.

Detailed Description


The popUp property is a UIComponent displayed by the PopUpManager. It is the default property and is often the only child tag of the PopUpAnchor tag. The popUp can be a Group, container, or a single component. For example, in a DropDownList, the popUp is a DataGroup which holds the item renderers.

Displaying PopUp

The displayPopUp property controls whether the popUp is displayed or not. If the value is true, then the popUp is added to the PopUpManager and then sized and positioned. If the value is false, then the popUp is removed from the PopUpManager.

Sizing PopUp

The popUp dimensions are determined in the following order:

Width:

  • If autoSizePopUpWidth is true, use the actual width of the PopUpAnchor
  • Use popUp's explicitWidth if specified
  • Use popUp's measuredWidth

Height:

  • If autoSizePopUpHeight is true, use the actual height of the PopUpAnchor
  • Use popUp's explicitHeight if specified
  • Use popUp's measuredHeight

The popUp dimensions are not affected by the popUp positioning.

Positioning PopUp

The popUpPosition property controls the position of the popUp. Sizing and positioning are independent of each other. This property can have the following values:

  • above
    • The bottom of the popUp is adjacent to the top of the PopUpAnchor.
    • The left edge of the popUp is vertically aligned with the left edge of the PopUpAnchor.
  • below
    • The top of the popUp is adjacent to the bottom of the PopUpAnchor.
    • The left edge of the popUp is vertically aligned with the left edge of the PopUpAnchor.
  • left
    • The right edge of the popUp is adjacent to the left edge of the PopUpAnchor.
    • The top edge of the popUp is horizontally aligned with the top edge of the PopUpAnchor.
  • right
    • The left edge of the popUp is adjacent to the right edge of the PopUpAnchor.
    • The top edge of the popUp is horizontally aligned with the top edge of the PopUpAnchor.
  • center
    • The horizontal and vertical center of the popUp is positioned at the horizontal and vertical center of the PopUpAnchor.
  • exact
    • The popUp is positioned at the same position as the PopUpAnchor.

The RelativePosition class is an enum class that contains static properties for each of the above positions.

If the popUp is not entirely on the stage at its given position, the PopUpAnchor will reposition the popUp to keep it on the stage. For example, if a PopUpAnchor with popUpPosition = "right" is located on the right edge of the application, its popUp will appear to the left of the PopUpAnchor.

Transforming PopUp

Since the popUp is not a display list child of the PopUpAnchor, it doesn't automatically have all of the transforms (scale, rotation, skew) or alpha applied to it. Thus is it necessary to apply the PopUpAnchor's concatenated transform matrix (which contains the combined transforms applied to the PopUp and its ancestors) to the popUp. The alpha property of the PopUpAnchor multiplied by the alpha properties of its ancestors is applied to the popUp's alpha property.

The transforms and alpha are applied to the popUp whenever it is displayed. If the PopUpAnchor transforms or alpha have changed while the popUp is displayed, the transforms and alpha will be reapplied to the popUp. If the PopUpAnchor ancestor's transforms or alphas are changed while the popUp is displayed, they will not be reapplied to the popUp. Instead, it will be up to the developer to call PopUpAnchor's updatePopUpTransform function when the PopUpAnchor ancestor's transforms or alphas have changed.

Animating PopUp

It will be common to animate the popUp when it is displayed and hidden. Effects can be run either upon the popUp directly, or upon the PopUpAnchor. Since transform changes on the PopUpAnchor are applied to the popUp, it is possible to animate the PopUpAnchor and have those effects affect the popUp. For example, effects like Move, Fade, Resize and Zoom can be applied to the PopUpAnchor. Applying the effects to the PopUpAnchor allows the effect to respect some of the PopUpAnchor's layout constraints. Mask effects and Shader effects should be run on the popUp since they require applying a mask to the target or taking a bitmap snapshot of the target.

If an effect modifies the ancestors of the PopUpAnchor, the effect can call updatePopUpTransform to reapply the transforms to the popUp while the effect is playing.

API Description


package spark.components
{

public class PopUpAnchor extends UIComponent
{
    /**
     *  If true, the popUp's height is set to the value of the PopUpAnchor's height.
     * 
     *  @default false
     */ 
    public function set autoSizePopUpHeight(value:Boolean):void;
    public function get autoSizePopUpHeight():Boolean;

   /**
    *  If true, the popUp's width is set to the value of the PopUpAnchor's width.
    *
    *  @default false
    */
    public function set autoSizePopUpWidth(value:Boolean):void;
    public function get autoSizePopUpWidth():Boolean;

    /**
     *  IUIComponent to add to the PopUpManager when the PopUpAnchor is opened.  
     *  If the popUp implements IFocusManagerContainer, the popUp will have its
     *  own FocusManager so that, if the user uses the TAB key to navigate between
     *  controls, only the controls in the popUp will be accessed.  
     */
    public function set popUp(value:IUIComponent):void;
    public function get popUp():IUIComponent;

    /**
     *  Position of the popUp when it is opened. 
     *  Possible values are "left", "right", "above", "below", "center", and "exact"
     * 
     *  @default "exact"
     */
    public function set popUpPosition(value:String):void;
    public function get popUpPosition():String;

    /**
     *  If true, add the popUp to the PopUpManager. If false, remove it.  
     *  
     *  @default false
     */
     public function set displayPopUp(value:Boolean):void;
     public function get displayPopUp():Boolean;

    /**
     *  This function is called when the popUp is positioned when it is displayed
     *  or when updatePopUpTransform() is called. Override this function to 
     *  alter the position of the popUp.  
     */
    protected function positionPopUp():void;

    /**
     *  Call this function to update the popUp's transform matrix. Typically 
     *  this would be called while performing an effect upon the PopUpAnchor. 
     */  
    public function updatePopUpTransform():void;
}

}




package spark.core
{

public class RelativePosition
{
    /**
     *  Positions the popUp to the left of the PopUpAnchor
     */
    public static const LEFT:String = "left";

    /**
     *  Positions the popUp to the right of the PopUpAnchor
     */
    public static const RIGHT:String = "right";

    /**
     *  Positions the popUp to above the PopUpAnchor
     */
    public static const ABOVE:String = "above";

    /**
     *  Positions the popUp to below the PopUpAnchor
     */
    public static const BELOW:String = "below";

    /**
     *  Positions the popUp in the center of the PopUpAnchor
     */
    public static const CENTER:String = "center";

    /**
     *  Positions the popUp at the exact position of the PopUpAnchor
     */
    public static const EXACT:String = "exact";
}
}

B Features


  • Add support for popUp to be an IDeferredInstance. If we don't implement this support, then developers can still use the state mechanism to achieve lazy instantiation.

Examples and Usage


Basic

The following example is a sample volume slider. When you roll over the anchor button, the slider appears on top of the anchor, centered both horizontally and vertically. When a volume is selected, the slider disappears. This example does not use any animation. Setting the horizontalCenter style on the PopUpAnchor allows the popUp to be centered horizontally relative to the anchor button.

<s:Group>
    <s:Button label="v" width="30" rollOver="slide.displayPopUp = true"/>
    <s:PopUpAnchor popUpPosition="center" horizontalCenter="0" top="0" bottom="0" width="18" id="slide">
        <s:Group>
            <s:Rect left="0" right="0" top="0" bottom="0">
                <s:fill>
                    <s:SolidColor color="0xc9c9c9"/>
                </s:fill>
                <s:stroke>
                    <s:SolidColorStroke color="0x111111"/>
                </s:stroke>
             </s:Rect>
            <s:VSlider top="4" right="4" left="4" bottom="4" maxHeight="40" valueCommit="slide.displayPopUp = false"/>
            <s:filters>
                <s:DropShadowFilter/>
            </s:filters>
        </s:Group>
    </s:PopUpAnchor>
</s:Group>

\

Effects

The following example display a search box to the right of the "Search" LinkButton. When the button is clicked, the search box opens up to the right. When the "Find" button in the search box is clicked, then the search box is closed back up. Animation is used to show and hide the search box. The animation is playing directly on the PopUpAnchor's popUp.

<fx:Style>
    .popUpBox
    {
        backgroundColor : #e9e9e9; 
        borderStyle : "solid";
        paddingTop : 2;
        paddingBottom : 2; 
        paddingLeft : 2; 
        paddingRight : 2;
    }
</fx:Style>

<fx:Declarations>
    <mx:Sequence id="hideSearch">
        <s:Scale target="{searchPopUp.popUp}" scaleXFrom="1" scaleXTo=".1" duration="200"/>
        <mx:SetPropertyAction target="{searchPopUp}" name="displayPopUp" value="false"/>
    </mx:Sequence>

    <mx:Sequence id="showSearch">
        <mx:SetPropertyAction target="{searchPopUp}" name="displayPopUp" value="true"/>
        <s:Scale target="{searchPopUp.popUp}" scaleXFrom=".1" scaleXTo="1" duration="200"/>
    </mx:Sequence>
</fx:Declarations>


<s:Group>
    <mx:LinkButton label="Search" click="showSearch.play() "/>
    <s:PopUpAnchor id="searchPopUp" left="0" right="0" popUpPosition="right" styleName="popUpBox">
        <mx:HBox horizontalScrollPolicy="off" verticalScrollPolicy="off">
            <s:TextInput width="80" id="searchField"/>
            <s:Button label="Find" click="hideSearch.play();"/>
        </mx:HBox>
    </s:PopUpAnchor>
</s:Group>

\

States and Transitions

The following example uses states to control when the PopUpAnchor's popUp is displayed. It uses transitions to play animations between states. When the "Email" LinkButton is pressed, it fades in an email form below it. Clicking on "Send" or "Cancel" will hide the email form, fading it back out. By only including the PopUpAnchor in the "open" state, the form is only instantiated when it is displayed.

<fx:Style>
    .popUpBox
    {
        backgroundColor : #e9e9e9; 
        borderStyle : "solid";
        paddingTop : 2;
        paddingBottom : 2; 
        paddingLeft : 2; 
        paddingRight : 2;
    }
</fx:Style>

<s:states>
    <s:State name="normal" />
    <s:State name="emailOpen" />
</s:states>

<s:transitions>
    <mx:Transition fromState="*" toState="*">
        <mx:Sequence>
            <s:Fade target="{emailPopUp.popUp}" duration="250"/>
        </mx:Sequence>
    </mx:Transition> 
</s:transitions>

<s:Group x="60">
    <mx:LinkButton label="Email" click="currentState = 'emailOpen'"/>
    <s:PopUpAnchor id="emailPopUp" left="0" bottom="0" popUpPosition="below" styleName="popUpBox" 
includeIn="emailOpen" displayPopUp.normal="false" displayPopUp.emailOpen="true">
        <mx:Form>
            <mx:FormItem label="From :">
                <s:TextInput/>
            </mx:FormItem>
            <mx:FormItem label="To :">
                <s:TextInput/>
            </mx:FormItem>
            <mx:FormItem label="Subject :">
                <s:TextInput/>
            </mx:FormItem>
            <mx:FormItem label="Message :">
                <s:TextArea width="100%" height="100" maxChars="120"/>
            </mx:FormItem>
            <mx:FormItem direction="horizontal">
                <s:Button label="Send" click="currentState = 'normal'"/>  
                <s:Button label="Cancel" click="currentState = 'normal'" />
            </mx:FormItem>
         </mx:Form>
    </s:PopUpAnchor>
</s:Group>

Additional Implementation Details


Prototype Work


Compiler Work


None

Web Tier Compiler Impact


None

Flex Feature Dependencies


None

Backwards Compatibility


None

Accessibility


None

Performance


None

Globalization


None

Localization


None

Issues and Recommendations


Open Issues

None

Resolved Issues

Should PopUpAnchor implement IVisualContainer? Scroller does. This seems like a similar case. Most of the implementation will throw RTEs.

The PopUpAnchor doesn't parent the popUp on its display list, so it doesn't really act as a container.

Should the PopUpAnchor support lazy creation of the popUp? Should the popUp only get instantiated when displayPopUp is true?

  • Using IDeferredInstance creates the popUp once the first time it is opened. It will have an API to destroy the instance. This is preferable to using IFactory because it is easy to interact with the popUp.
  • Using IFactory creates a new popUp instance each time it is opened. The downside is that some effects might not work or will be hard to apply. Additionally, accessing objects in the popUp is difficult and accessing outside objects from within the popUp is difficult.
  • Using the states mechanism means only including the PopUpAnchor in a state where you want the popUp to appear. The PopUpAnchor instance only exists when its includeIn state is the current state. This mechanism makes it easier to apply effects and code against the popUp. But it does mean that adding lazy creation requires some extra work for the developer.

Should the PopUpAnchor apply changes to its transform properties (scale, rotation, translation, skew) and alpha property to the popUp while it is displayed? Or should the developer be forced to call updatePopUpTransform if these properties are modified while the popUp is displayed? Playing an effect on the PopUp is a common way to modify the transform properties.

No, it should be sufficient to call updatePopUpTransform while an effect is playing

Should the PopUpAnchor dispatch open and close events? Setting the open property should immediately add the popUp to the displayList and make it visible, so I don't think events are necessary.

No, the popUp is opened immediately when the displayPopUp is set to true. If open and close animations delay the appearance of the popUp, it is up to the developer to listen for the effect end events.

What about naming PopUp -> PopUpAnchor and then renaming all of the contentX properties to popUpX? The PopUp component itself doesn't actually get popped up. People usually associate the term "popUp" with a visual window that is displayed above other controls. So it makes more sense to name the "content" as "popUp". The anchor is the area in the layout that determines the popUp's position and dimensions.

Renamed PopUp -> PopUpAnchor, and changed all contentX properties to popUpX properties.

Should the PopUp support the use case of providing a declarative way to add a popUp to the PopUpManager? In this use case, there is no anchor and thus no need to size and position the popUp relative to the anchor. The main purpose is to add a dialog box or floating window to the application. If we support this use case, then we would expose the modal flag and would just center the popUp in the application.

No, this is not a use case for an anchored popUp component.

How do we handle focus management for the popUp? Do we need something to implement the IFocusManagerContainer interface?

PopUpManager adds a FocusManager to a popUp that implements IFocusManagerContainer. Since the popUp property can be any IUIComponent, it is up to the developer to decide if they want focus management within their popUp. It would be a good idea to add this information to the ASDocs

Documentation


Documentation should include a lot of examples.

QA



Related

Wiki: Flex 4
Wiki: Spark TitleWindow

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.