Peter Hansen is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

microcode / playbook-air http://microcode.ca/playbook-air

Example code for PlayBook development using the Tablet OS SDK for Adobe AIR.

Clone this repository (size: 26.9 KB): HTTPS / SSH
hg clone https://bitbucket.org/microcode/playbook-air
hg clone ssh://hg@bitbucket.org/microcode/playbook-air

playbook-air / studies / ca / microcode / menu / TopSwipeMenu.as

Branch
default
//--------------------------------------------------------------
// PlayBook top-swipe menu
//
// Copyright 2011 Peter Hansen
// Made available under the MIT License (http://www.opensource.org/licenses/mit-license)
//
// Please give credit in your "About" dialog, documentation, or similar place.
// See http://peterhansen.ca/blog/playbook-top-swipe-menu.html for background.

package ca.microcode.menu {
    import caurina.transitions.Tweener;

    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    import qnx.events.QNXApplicationEvent;
    import qnx.system.QNXApplication;
    import qnx.ui.text.Label;

    public class TopSwipeMenu extends Sprite {
        // minimize distance to swipe before menu slides open by itself
        public var swipe_region:int = 21;

        // duration in seconds for full slide (e.g. when closing)
        public var slide_time:Number = 0.3;

        public function TopSwipeMenu(width:int, height:int, bgcolor:int=0xcccccc) {
            var bg:Shape = new Shape();
            bg.graphics.beginFill(bgcolor, 1);
            bg.graphics.drawRect(0, 0, width, height);
            addChild(bg);

            this.y = -height;

            QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_START, onEvent);
        }

        private var state:int;
        private const ST_IDLE:int = 0;
        private const ST_SWIPE_START:int = 1;
        private const ST_FIRST_DOWN:int = 2;
        private const ST_SWIPING:int = 3;
        private const ST_OPENING:int = 4;
        private const ST_OPEN:int = 5;
        private const ST_CLOSING:int = 6;

        private var swipe_start_pos:Point;

        private function onEvent(event:Event):void {
            var prev_state:int = state;
            var p:Point = new Point(stage.mouseX, stage.mouseY);
            trace(state, event.type, "@", p);

            switch (state) {
                case ST_IDLE:
                    if (event.type == QNXApplicationEvent.SWIPE_START)
                        state = ST_SWIPE_START;
                    break;

                case ST_SWIPE_START:
                    if (event.type == MouseEvent.MOUSE_MOVE) {
                        swipe_start_pos = new Point(stage.mouseX, stage.mouseY);
                        state = ST_FIRST_DOWN;
                    }
                    // anything but mouseMove
                    else
                        state = ST_IDLE;
                    break;

                case ST_FIRST_DOWN:
                    if (event.type == MouseEvent.MOUSE_DOWN) {
                        // check whether pos is same as it was for first move
                        var pos:Point = new Point(stage.mouseX, stage.mouseY);
                        if (pos.equals(swipe_start_pos))
                            state = ST_SWIPING;
                        else // not a top-swipe if positions don't match
                            state = ST_IDLE;
                    }
                    else if (event.type == QNXApplicationEvent.SWIPE_START)
                        state = ST_SWIPE_START;
                    else
                        state = ST_IDLE;
                    break;

                case ST_SWIPING:
                    if (event.type == MouseEvent.MOUSE_UP) {
                        if (stage.mouseY > swipe_region)
                            state = ST_OPENING;
                        else
                            state = ST_CLOSING;
                    }
                    break;

                case ST_OPENING:
                    if (event.type == Event.COMPLETE)
                        state = ST_OPEN;
                    else if (event.type == Event.CLOSE)
                        state = ST_CLOSING;
                    break;

                case ST_OPEN:
                    if (event.type == Event.CLOSE)
                        state = ST_CLOSING;
                    else if (event.type == QNXApplicationEvent.SWIPE_START)
                        state = ST_SWIPE_START;
                    break;

                case ST_CLOSING:
                    if (event.type == Event.COMPLETE)
                        state = ST_IDLE;
                    else if (event.type == QNXApplicationEvent.SWIPE_START)
                        state = ST_SWIPE_START;
                    break;
            }

            // handle state change
            if (state != prev_state) {
                trace(prev_state, "-->", state);
                var duration:Number;
                var slide_closed:Boolean;

                // leaving state
                switch (prev_state) {
                    case ST_FIRST_DOWN:
                        stage.removeEventListener(MouseEvent.MOUSE_MOVE, onEvent);
                        stage.removeEventListener(MouseEvent.MOUSE_DOWN, onEvent);
                        break;

                    case ST_SWIPING:
                        stage.removeEventListener(MouseEvent.MOUSE_UP, onEvent);
                        stage.removeEventListener(Event.ENTER_FRAME, onSwiping);
                        break;

                    case ST_OPEN:
                        stage.removeEventListener(MouseEvent.MOUSE_DOWN, outsideClick, true);
                        slide_closed = true;
                        break;
                }

                // entering state
                switch (state) {
                    case ST_SWIPE_START:
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, onEvent);
                        break;

                    case ST_FIRST_DOWN:
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, onEvent);
                        break;

                    case ST_SWIPING:
                        stage.addEventListener(MouseEvent.MOUSE_UP, onEvent);
                        stage.addEventListener(Event.ENTER_FRAME, onSwiping);
                        break;

                    case ST_OPENING:
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, outsideClick, true);
                        duration = slide_time * -this.y / height;
                        Tweener.addTween(this, {y: 0, time: duration, transition: "linear",
                            onComplete: onEvent,
                            onCompleteParams: [new Event(Event.COMPLETE)]
                            });
                        break;

                    case ST_CLOSING:
                        stage.removeEventListener(MouseEvent.MOUSE_DOWN, outsideClick, true);
                        slide_closed = true;
                        break;
                }

                if (slide_closed) {
                    duration = slide_time * (height + this.y) / height;
                    Tweener.addTween(this, {y: -height, time: duration, transition: "linear",
                        onComplete: onEvent,
                        onCompleteParams: [new Event(Event.COMPLETE)]
                        });
                }
            }
        }

        private function onSwiping(e:Event):void {
            var y:int = stage.mouseY;
            if (y >= height)
                y = height;

            this.y = y - height;
        }

        private function outsideClick(e:MouseEvent):void {
            if (stage.mouseY > this.y + this.height)
                onEvent(new Event(Event.CLOSE));
        }

        public function close():void {
            onEvent(new Event(Event.CLOSE));
        }
    }
}