~eda-qa/dhlib/main

« back to all changes in this revision

Viewing changes to lib/ui/Modal.hx

  • Committer: edA-qa mort-ora-y
  • Date: 2010-02-16 05:36:32 UTC
  • Revision ID: eda-qa@disemia.com-20100216053632-60lt7fndfi3fgblw
first

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* <license>
 
2
 * This file is part of the dis-Emi-A HaXe Library. Copyright Â© edA-qa mort-ora-y
 
3
 * For full copyright and license information please refer to doc/license.txt.
 
4
 * </license> 
 
5
 */
 
6
package ui;
 
7
 
 
8
import DrawBasicTypes;
 
9
 
 
10
#if neash
 
11
import neash.display.DisplayObject;
 
12
import neash.events.Event;
 
13
import neash.events.MouseEvent;
 
14
import neash.events.KeyboardEvent;
 
15
#elseif flash
 
16
import flash.display.DisplayObject;
 
17
import flash.events.Event;
 
18
import flash.events.MouseEvent;
 
19
import flash.events.KeyboardEvent;
 
20
#end
 
21
 
 
22
/**
 
23
 * Executes an display as a modal display.  This will be modal to the
 
24
 * program as a whole (the stage) such that no other window, other
 
25
 * than what is provided here, can be accessed.
 
26
 *
 
27
 * Note that exactly when the completionAction is sent cannot be guaranteed as there
 
28
 * are many minor paths by which the modal can end.  In particular you cannot assume
 
29
 * that when it is done that something like a Popup menu has processed, or even yet
 
30
 * dispatched the associated menu event.  Though other classes may choose to provide
 
31
 * guarantees (like Dialog)
 
32
 */
 
33
/*final*/ class Modal
 
34
{
 
35
        // Parent will be covered with a gray box during processing (only makes sense when Stage is parent)
 
36
        var grayParent : Bool;
 
37
        var grayParentObj : Box;
 
38
        
 
39
        static var modalEvents = [ 
 
40
                MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_UP, 
 
41
                MouseEvent.CLICK, MouseEvent.DOUBLE_CLICK,
 
42
                MouseEvent.MOUSE_WHEEL,
 
43
                
 
44
                //In a decent system these should be fine since they shouldn't change the display tree
 
45
                //MouseEvent.MOUSE_MOVE, MouseEvent.MOUSE_OVER, MouseEvent.MOUSE_OUT,
 
46
                //MouseEvent.ROLL_OUT, MouseEvent.ROLL_OVER,
 
47
                
 
48
                KeyboardEvent.KEY_DOWN, KeyboardEvent.KEY_UP
 
49
                ];
 
50
                
 
51
        /** 
 
52
         * Constructs a default Modal handler.
 
53
         *
 
54
         * grayParent = true
 
55
         */
 
56
        public function new()
 
57
        {
 
58
                grayParent = true;
 
59
                grayParentObj = Box.plain( Brush.solid(Color.rgb(0.5,0.5,0.5)) );
 
60
                //grayParentObj.alpha = 0.5;
 
61
                grayParentObj.blendMode = flash.display.BlendMode.MULTIPLY;
 
62
        }
 
63
        
 
64
        var dObject : Window;
 
65
        var dParent : NativeObject;
 
66
        var active : Bool;
 
67
                
 
68
        /**
 
69
         * A standard execution path to execute the window as modal against the
 
70
         * entire stage.
 
71
         */
 
72
        static public function asStageModal( obj : Window, ?onCompletion : ui.Action,
 
73
                ?grayParent : Bool = true ) : Modal
 
74
        {
 
75
                var m = new Modal();
 
76
                m.setCompletionAction( onCompletion );
 
77
                m.grayParent = grayParent;
 
78
                m.exec( null, obj );
 
79
                return m;
 
80
        }
 
81
        
 
82
        /**
 
83
         * Executres the obj in a Modal faction.
 
84
         *
 
85
         * @param       parent [in] of which object this will be a child, 0 indicates to use the stage
 
86
         * @param       obj [in] which window to display
 
87
         */
 
88
        public function exec( parent : NativeObject, obj : Window )
 
89
        {
 
90
                Assert.isTrue( !active );
 
91
                
 
92
                dObject = obj;
 
93
                dParent = if( parent == null ) flash.Lib.current.stage else parent;
 
94
                
 
95
                //setup listeners to know when we are (planned or otherwise)
 
96
                dObject.getNative().addEventListener( Event.REMOVED, onRemoved );
 
97
                dObject.setCloseListener( Action.bind( onClose ) );
 
98
                
 
99
                //gray of parent if desired
 
100
                if( grayParent )
 
101
                {
 
102
                        grayParentObj.resize( dParent.width, dParent.height );
 
103
                        dParent.addChild( grayParentObj );
 
104
                }
 
105
                
 
106
                //finally add target window to parent, or run FX
 
107
                dParent.addChild( dObject.getNative() );
 
108
                if( __beginFX != null )
 
109
                {
 
110
                        ui.anim.FXBuilder.beginWidget( dObject.getWidget(), __beginFX, Action.bind( __endBeginFX ) );
 
111
                }
 
112
                else
 
113
                {
 
114
                        dObject.exec( dParent );
 
115
                        active = true;
 
116
                }
 
117
                
 
118
                //then setup the events to make use Modal in nature
 
119
                //just guess that 100 is a high enough priority to override other events...?
 
120
                for( evt in modalEvents )
 
121
                        flash.Lib.current.stage.addEventListener( evt, capturePhase, true, 100 );
 
122
                
 
123
                /*as nothing has the focus often the keyboard events start at the stage, and thus
 
124
                 *do not go through a capture stage (as they are at their target).  For this reason
 
125
                 * we also need to listen in non-capture mode as well.
 
126
                 * NOTE: as we assume the stage is never empty this is not true for mouse events
 
127
                 */
 
128
                flash.Lib.current.stage.addEventListener( KeyboardEvent.KEY_DOWN, capturePhase, false, 100 );
 
129
                flash.Lib.current.stage.addEventListener( KeyboardEvent.KEY_UP, capturePhase, false, 100 );
 
130
        }
 
131
        
 
132
        /*hidden*/ function __endBeginFX()
 
133
        {
 
134
                dObject.exec( dParent );
 
135
                active = true;
 
136
        }
 
137
        
 
138
        /*hidden*/ function capturePhase( evt : Event )
 
139
        {
 
140
                //do before further propogation (so that focus in modal doesn't block the escape)
 
141
                if( evt.type == KeyboardEvent.KEY_UP )
 
142
                {
 
143
                        if( cast( evt, KeyboardEvent ).keyCode == flash.ui.Keyboard.ESCAPE ) 
 
144
                        {
 
145
                                evt.stopPropagation();
 
146
                                goEnd(false);   //cancel the menu
 
147
                                return;
 
148
                        }
 
149
                }
 
150
                
 
151
                //children of the display object can process such items
 
152
                if( dObject.getNative().contains( cast( evt.target, DisplayObject ) ) )
 
153
                        return;
 
154
                
 
155
                //stop it
 
156
                evt.stopPropagation();
 
157
        }
 
158
        
 
159
        function onRemoved( evt : Event )
 
160
        {
 
161
                if( evt.target != dObject )
 
162
                        return;
 
163
                        
 
164
                //in case something else removes us
 
165
                goEnd(true);
 
166
        }
 
167
        
 
168
        /**
 
169
         * Ends the Modal state and closes the widget.
 
170
         */
 
171
        public function endClose()
 
172
        {
 
173
                goEnd( false );
 
174
        }
 
175
        
 
176
        function onClose() 
 
177
        {
 
178
                goEnd( false );
 
179
        }
 
180
        
 
181
        function goEnd( removed : Bool )
 
182
        {
 
183
                //active applies both during startup and shutdown if FX are being applied
 
184
                if( !active )
 
185
                        return;
 
186
                        
 
187
                if( grayParent )
 
188
                        dParent.removeChild( grayParentObj );
 
189
                        
 
190
                //set active first to false to prevent removal recursion
 
191
                active = false;
 
192
                
 
193
                for( evt in modalEvents )
 
194
                        flash.Lib.current.stage.removeEventListener( evt, capturePhase, true );
 
195
                flash.Lib.current.stage.removeEventListener( KeyboardEvent.KEY_DOWN, capturePhase, false );
 
196
                flash.Lib.current.stage.removeEventListener( KeyboardEvent.KEY_UP, capturePhase, false );
 
197
                dObject.getNative().removeEventListener( Event.REMOVED, onRemoved );
 
198
        
 
199
                //root popup needs to remove itself (ensure parent hasn't changed however)
 
200
                if( !removed && dObject.getNative().parent == dParent )
 
201
                {
 
202
                        if( __endFX != null )
 
203
                                ui.anim.FXBuilder.endWidget( dObject.getWidget(), __endFX );
 
204
                        else
 
205
                                dParent.removeChild( dObject.getNative() );
 
206
                }
 
207
                        
 
208
                dObject = null;
 
209
                var p = dParent;
 
210
                dParent = null;
 
211
                
 
212
                //signal completion (NOTE: Do absolutely last so this modal could technically be used again)
 
213
                if( completionAction != null )
 
214
                        Action.handle( p, completionAction );
 
215
        }
 
216
        
 
217
        /*hidden*/ var __endFX : ui.anim.FXDescriptor;
 
218
        /*hidden*/ var __beginFX : ui.anim.FXDescriptor;
 
219
        
 
220
        /**
 
221
         * Sets the effect to use on completion of the Modal item
 
222
         */
 
223
        public function setEndFX( fx : ui.anim.FXDescriptor )
 
224
        {
 
225
                __endFX = fx;
 
226
        }
 
227
        
 
228
        public function setBeginFX( fx : ui.anim.FXDescriptor )
 
229
        {
 
230
                __beginFX = fx;
 
231
        }
 
232
        
 
233
        /**
 
234
         * Allows an action to be executed when the Modal is completed.
 
235
         *
 
236
         * @action      [in] action to fire when done, may be null to indicate none (which
 
237
         *              is the default)
 
238
         */
 
239
        var completionAction : Dynamic;
 
240
        public function setCompletionAction( action : Dynamic )
 
241
        {
 
242
                completionAction = action;
 
243
        }
 
244
}
 
 
b'\\ No newline at end of file'