Dim toolbox icons on opening app
[potlatch2.git] / net / systemeD / potlatch2 / EditController.as
1 package net.systemeD.potlatch2 {
2     import net.systemeD.halcyon.Map;
3     import net.systemeD.halcyon.MapPaint;
4     import net.systemeD.halcyon.MapController;
5     import net.systemeD.halcyon.MapEvent;
6     import net.systemeD.halcyon.connection.*;
7     import net.systemeD.halcyon.Globals;
8     import net.systemeD.potlatch2.controller.*;
9     import net.systemeD.potlatch2.FunctionKeyManager;
10         import mx.managers.CursorManager;
11     import flash.external.ExternalInterface;
12     import flash.events.*;
13         import flash.geom.*;
14         import flash.ui.Keyboard;
15         import flash.text.TextField;
16     import mx.controls.TextArea;
17
18     /** Controller for the main map editing window itself. The logic that responds to mouse and keyboard events is all 
19     * buried in various ControllerState classes. */
20     public class EditController extends EventDispatcher implements MapController {
21
22         private var _map:Map;
23         public var tagViewer:TagViewer;
24                 private var toolbox:Toolbox;
25
26         /** The current ControllerState */
27         public var state:ControllerState;
28         
29                 private var keys:Object={};
30                 public var clipboards:Object={};
31                 public var cursorsEnabled:Boolean=true;
32         private var maximised:Boolean=false;
33         private var maximiseFunction:String;
34         private var minimiseFunction:String;
35         private var moveFunction:String;
36
37                 [Embed(source="../../../embedded/pen.png")]             public var pen:Class;
38                 [Embed(source="../../../embedded/pen_x.png")]           public var pen_x:Class;
39                 [Embed(source="../../../embedded/pen_o.png")]           public var pen_o:Class;
40                 [Embed(source="../../../embedded/pen_so.png")]          public var pen_so:Class;
41                 [Embed(source="../../../embedded/pen_plus.png")]        public var pen_plus:Class;
42                 
43         /** Constructor function: needs the map information, a panel to edit tags with, and the toolbox to manipulate ways with. */
44         public function EditController(map:Map, tagViewer:TagViewer, toolbox:Toolbox) {
45             this._map = map;
46             setState(new NoSelection());
47             this.tagViewer = tagViewer;
48             this.tagViewer.controller = this;
49                         this.toolbox = toolbox;
50                         this.toolbox.init(this);
51                         this.toolbox.updateSelectionUI();
52             this.maximiseFunction = Globals.vars.flashvars["maximise_function"];
53             this.minimiseFunction = Globals.vars.flashvars["minimise_function"];
54             this.moveFunction     = Globals.vars.flashvars["move_function"];
55
56             map.parent.addEventListener(MouseEvent.MOUSE_MOVE, mapMouseEvent);
57             map.parent.addEventListener(MouseEvent.MOUSE_UP, mapMouseEvent);
58             map.parent.addEventListener(MouseEvent.MOUSE_DOWN, mapMouseEvent);
59             map.parent.addEventListener(MouseEvent.MOUSE_WHEEL, mapMouseEvent);
60             map.parent.addEventListener(MouseEvent.CLICK, mapMouseEvent);
61             map.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
62             map.stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
63
64             if (this.moveFunction) {
65                 map.addEventListener(MapEvent.MOVE, moveHandler);
66             }
67         }
68
69         public function setActive():void {
70             map.setController(this);
71         }
72
73         /** Accesses map object. */
74         public function get map():Map {
75             return _map;
76         }
77         
78         /**
79         * Updates the various user interfaces that change when the selection changes.
80         * Currently this is the TagViewer and the Toolbox
81         *
82         * @param layer Optionally pass the layer of the currently selected entity, eg for BugLayers
83         */
84                 public function updateSelectionUI(layer:MapPaint = null):void {
85                         tagViewer.setEntity(state.selection, layer);
86                         toolbox.updateSelectionUI();
87                 }
88
89                 public function updateSelectionUIWithoutTagChange():void {
90                         toolbox.updateSelectionUI();
91                 }
92         
93         private function keyDownHandler(event:KeyboardEvent):void {
94                         if ((event.target is TextField) || (event.target is TextArea)) return;
95                         keys[event.keyCode]=true;
96                 }
97
98         private function keyUpHandler(event:KeyboardEvent):void {
99             if (!keys[event.keyCode]) return;
100             delete keys[event.keyCode];
101             if ((event.target is TextField) || (event.target is TextArea)) return;                              // not meant for us
102
103                         if (FunctionKeyManager.instance().handleKeypress(event.keyCode)) { return; }
104             
105             if (event.keyCode == 77) { toggleSize(); } // 'M'
106             var newState:ControllerState = state.processKeyboardEvent(event);
107             setState(newState);            
108                 }
109
110                 /** Is the given key currently pressed? */
111                 public function keyDown(key:Number):Boolean {
112                         return Boolean(keys[key]);
113                 }
114
115         private function mapMouseEvent(event:MouseEvent):void {
116             if (isInteractionEvent(event)) map.stage.focus = map.parent;
117             if (event.type==MouseEvent.MOUSE_UP && map.dragstate==map.DRAGGING) { return; }
118             
119             var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
120             event.localX = mapLoc.x;
121             event.localY = mapLoc.y;
122
123             var newState:ControllerState = state.processMouseEvent(event, null);
124             setState(newState);
125         }
126         
127         public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
128             if (isInteractionEvent(event)) map.stage.focus = map.parent;
129             event.stopPropagation();
130                 
131             var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
132             event.localX = mapLoc.x;
133             event.localY = mapLoc.y;
134
135             var newState:ControllerState = state.processMouseEvent(event, entity);
136             setState(newState);
137         }
138
139                 private function isInteractionEvent(event:MouseEvent):Boolean {
140                         switch (event.type) {
141                                 case MouseEvent.ROLL_OUT:       return false;
142                                 case MouseEvent.ROLL_OVER:      return false;
143                                 case MouseEvent.MOUSE_OUT:      return false;
144                                 case MouseEvent.MOUSE_OVER:     return false;
145                                 case MouseEvent.MOUSE_MOVE:     return false;
146                 }
147                         return true;
148                 }
149
150         /** Exit the current state and switch to a new one.
151         *
152         *   @param newState The ControllerState to switch to. */
153         public function setState(newState:ControllerState):void {
154             if ( newState == state )
155                 return;
156                 
157             if ( state != null )
158                 state.exitState(newState);
159             newState.setController(this);
160             newState.setPreviousState(state);
161             state = newState;
162             state.enterState();
163         }
164
165                 /** Given what is currently selected (or not), find the matching ControllerState. */
166                 public function findStateForSelection(sel:Array):ControllerState {
167                         if (sel.length==0) { return new NoSelection(); }
168                         var layer:MapPaint=_map.getLayerForEntity(sel[0]);
169                         
170                         if (sel.length>1) { return new SelectedMultiple(sel, layer); }
171                         else if (sel[0] is Way) { return new SelectedWay(sel[0], layer); }
172                         else if (sel[0] is Node && Node(sel[0]).hasParentWays) {
173                                 var way:Way=sel[0].parentWays[0] as Way;
174                                 return new SelectedWayNode(way, way.indexOfNode(sel[0] as Node));
175                         } else {
176                                 return new SelectedPOINode(sel[0] as Node, layer);
177                         }
178                 }
179
180                 /** Set a mouse pointer. */
181                 public function setCursor(cursor:Class):void {
182                         CursorManager.removeAllCursors();
183                         if (cursor && cursorsEnabled) { CursorManager.setCursor(cursor,2,-4,0); }
184                 }
185
186         private function toggleSize():void {
187             if (maximised) {
188                 if (minimiseFunction) {
189                     ExternalInterface.call(minimiseFunction);
190                 }
191
192                 maximised = false;
193             } else {
194                 if (maximiseFunction) {
195                     ExternalInterface.call(maximiseFunction);
196                 }
197
198                 maximised = true;
199             }
200         }
201
202                 private function moveHandler(event:MapEvent):void {
203                         ExternalInterface.call(this.moveFunction,
204                                    event.params.lon, event.params.lat, event.params.scale,
205                                    event.params.minlon, event.params.minlat,
206                                    event.params.maxlon, event.params.maxlat);
207                 }
208
209     }
210     
211 }