tags:

views:

1091

answers:

4

I think there is a simple solution to this question, just not simple enough for me to find it.

Question: How do you constrain a TitleWindow in Flex 3 from being dragged off the screen/stage? Is there a way to restrict the TitleWindow to the viewing area?

Example: Let's say I have an application that take 100% of the screen. Next, I create a TitleWindow via the PopUpManager. I can then proceed to click and hold (drag) that window off the screen, then release the mouse button. That window is now lost off-screen somewhere. Is there a way to keep the window from being dragged beyond the viewing area?

Thanks for the help in advance.

+1  A: 

You can set its isPopUp property to false to prevent it from being dragged in the first place.

var popupWin:TitleWindow = PopUpManager.createPopUp(this, TitleWindow);
PopUpManager.centerPopUp(popupWin);
popupWin.isPopUp = false;

I don't know if the DragManager class in flex supports bounds checking, but if you really want to allow dragging but limit its bounds, you can still set isPopUp to false and implement the dragging code yourself so that the component never goes outside the limits specified by you. Check startDrag() method for an example. Bounds rectangle is the key.

Amarghosh
Thanks for the reply. Yes, I could set isPop property to false. But, I still want the window to be draggable if possible. Good suggestion. Thanks. I may have to go this route if there is no solution.
updated the post
Amarghosh
Their example adds mouseUp event to the dragged object - you might wanna change it to the `stage` so that it gets triggered even if the user releases the mouse outside the title window.
Amarghosh
Override TitleWindow class to get access to its protected `titleBar` property. Add mouseDown event to the titleBar, in the mouseDownHandler, call titlewindow.startDrag and add mouseUp listener to the stage. Call stopDrag from the mouseUpHandler.
Amarghosh
I was hoping I was overlooking a property on an object somewhere. But the solution you offered is quite promising. After some work, I went with your original solution; isPopUp = false. Thanks for your help.
A: 

Subclass the TitleWindow and add a canvas over the title bar as a drag proxy. Then you can explicity call startDrag with a boundary rectangle.

This is pretty skeletal, but should put you on the path...

The reason for the proxy is you may get some weird behavior when you click the titleBar label if you don't have the canvas over it.

public class MyTitleWindow extends TitleWindow
{
    public var titleBarOverlay:Canvas;

    override protected function createChildren():void
    {
        super.createChildren();

        if(!titleBarOverlay)
        {
         titleBarOverlay = new Canvas();
         titleBarOverlay.width = this.width;
         titleBarOverlay.height = this.titleBar.height;
         titleBarOverlay.alpha = 0;
         titleBarOverlay.setStyle("backgroundColor", 0x000000);
         rawChildren.addChild(titleBarOverlay);
        }

            addListeners();
    }

    override protected function updateDisplayList(w:Number, h:Number):void
    {
        super.updateDisplayList(w, h);

        titleBarOverlay.width = this.width;
        titleBarOverlay.height = this.titleBar.height;
    }

    private function addListeners():void
    {
        titleBarOverlay.addEventListener(MouseEvent.MOUSE_DOWN, onTitleBarPress, false, 0, true);
        titleBarOverlay.addEventListener(MouseEvent.MOUSE_UP, onTitleBarRelease, false, 0, true);
    }

    private function onTitleBarPress(event:MouseEvent):void
    {
        // Here you can set the boundary using owner, parent, parentApplication, etc.
        this.startDrag(false, new Rectangle(0, 0, parent.width - this.width, parent.height - this.height));
    }

    private function onTitleBarRelease(event:Event):void
    {
        this.stopDrag();
    }
}
daniel.reicher
what is the need for the overlay? Why not add the event listener to the titleBar directly?
Amarghosh
Thanks for the feedback Daniel I appreciate the effort and time you put in to responding.
+1  A: 

this is a very old post, but here's another way of doing it: Whether you are extending the component or not, in the TitleWindow definition add the following line: move:"doMove(event)" Import the Application library (import mx.core.Application;) and add the doMove function:

private function doMove(event:Event):void
{//keeps TW inside layout
    var appW:Number=Application.application.width;
    var appH:Number=Application.application.height;
    if(this.x+this.width>appW)
    {
     this.x=appW-this.width;
    }
    if(this.x<0)
    {
     this.x=0;
    }
    if(this.y+this.height>appH)
    {
     this.y=appH-this.height;
    }
    if(this.y<0)
    {
     this.y=0;
    }
}
Hector
Hector! You did it! You're the man! This is exactly what I was looking for. Thank you.
A: 

You could simply override the move function and prevent "illegal" movement (it is called internally by the Panel drag management).

I think that you also should listen on stage resize, because reducing it (e.g. if the user resize the browser window) could send your popup out of stage even without actually moving it.

public class MyTitleWindow extends TitleWindow {

    public function MyTitleWindow() {
        // use a weak listener, or remember to remove it
        stage.addEventListener(Event.RESIZE, onStageResize, 
                false, EventPriority.DEFAULT, true);
    }

    private function onStageResize(event:Event):void {
        restoreOutOfStage();
    }

    override public function move(x:Number, y:Number):void {
        super.move(x, y);
        restoreOutOfStage();
    }

    private function restoreOutOfStage():void {
        // avoid the popup from being positioned completely out of stage
        // (use the actual width/height of the popup instead of 50 if you
        // want to keep your *entire* popup on stage)
        var topContainer:DisplayObjectContainer =
                Application.application.parentDocument;
        var minX:int = 50 - width;
        var maxX:int = topContainer.width - 50;
        var minY:int = 0;
        var maxY:int = topContainer.height - 50;                
        if (x > maxX) 
            x = maxX
        else if (x < minX)
            x = minX;
        if (y > maxY) 
            y = maxY
        else if (y < minY)
            y = minY;
    }

}
Cosma Colanicchia