Allow a javascript function to be called when the map is moved
[potlatch2.git] / net / systemeD / potlatch2 / EditController.as
1 package net.systemeD.potlatch2 {
2     import net.systemeD.halcyon.Map;
3     import net.systemeD.halcyon.MapController;
4     import net.systemeD.halcyon.MapEvent;
5     import net.systemeD.halcyon.connection.*;
6     import net.systemeD.halcyon.VectorLayer;
7     import net.systemeD.potlatch2.controller.*;
8     import net.systemeD.potlatch2.FunctionKeyManager;
9         import mx.managers.CursorManager;
10     import flash.external.ExternalInterface;
11     import flash.events.*;
12         import flash.geom.*;
13
14     public class EditController implements MapController {
15
16         private var _map:Map;
17         public var tagViewer:TagViewer;
18                 private var toolbox:Toolbox;
19         
20         public var state:ControllerState;
21         private var _connection:Connection;
22         
23                 private var keys:Object={};
24                 public var clipboards:Object={};
25                 public var cursorsEnabled:Boolean=true;
26         private var maximised:Boolean=false;
27         private var maximiseFunction:String;
28         private var minimiseFunction:String;
29         private var moveFunction:String;
30
31                 [Embed(source="../../../embedded/pen.png")]             public var pen:Class;
32                 [Embed(source="../../../embedded/pen_x.png")]           public var pen_x:Class;
33                 [Embed(source="../../../embedded/pen_o.png")]           public var pen_o:Class;
34                 [Embed(source="../../../embedded/pen_so.png")]          public var pen_so:Class;
35                 [Embed(source="../../../embedded/pen_plus.png")]        public var pen_plus:Class;
36                 
37         public function EditController(map:Map, tagViewer:TagViewer, toolbox:Toolbox) {
38             this._map = map;
39             setState(new NoSelection());
40             this.tagViewer = tagViewer;
41                         this.toolbox = toolbox;
42                         this.toolbox.init(this);
43             this.maximiseFunction = Connection.getParam("maximise_function", null);
44             this.minimiseFunction = Connection.getParam("minimise_function", null);
45             this.moveFunction = Connection.getParam("move_function", null);
46
47             map.parent.addEventListener(MouseEvent.MOUSE_MOVE, mapMouseEvent);
48             map.parent.addEventListener(MouseEvent.MOUSE_UP, mapMouseEvent);
49             map.parent.addEventListener(MouseEvent.MOUSE_DOWN, mapMouseEvent);
50             map.parent.addEventListener(MouseEvent.MOUSE_WHEEL, mapMouseEvent);
51             map.parent.addEventListener(MouseEvent.CLICK, mapMouseEvent);
52             map.parent.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
53             map.parent.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
54
55             if (this.moveFunction) {
56                 map.addEventListener(MapEvent.MOVE, moveHandler);
57             }
58         }
59
60         public function setActive():void {
61             map.setController(this);
62             _connection = map.connection;
63         }
64
65         public function get map():Map {
66             return _map;
67         }
68         
69         public function get connection():Connection {
70             return _connection;
71         }
72
73         /**
74         * Updates the various user interfaces that change when the selection changes.
75         * Currently this is the TagViewer and the Toolbox
76         *
77         * @param layer Optionally pass the layer of the currently selected entity, eg for BugLayers
78         */
79                 public function updateSelectionUI(layer:VectorLayer = null):void {
80                         tagViewer.setEntity(state.selection, layer);
81                         toolbox.updateSelectionUI();
82                 }
83         
84         private function keyDownHandler(event:KeyboardEvent):void {
85                         keys[event.keyCode]=true;
86                 }
87
88         private function keyUpHandler(event:KeyboardEvent):void {
89             trace("key code "+event.keyCode);
90                         if (keys[event.keyCode]) { delete keys[event.keyCode]; }
91                         if (FunctionKeyManager.instance().handleKeypress(event.keyCode)) { return; }
92             if (event.keyCode == 77) { toggleSize(); }
93             var newState:ControllerState = state.processKeyboardEvent(event);
94             setState(newState);            
95                 }
96
97                 public function keyDown(key:Number):Boolean {
98                         return Boolean(keys[key]);
99                 }
100
101         private function mapMouseEvent(event:MouseEvent):void {
102             if (event.type!=MouseEvent.ROLL_OVER) map.stage.focus = map.parent;
103             if (event.type==MouseEvent.MOUSE_UP && map.dragstate==map.DRAGGING) { return; }
104             
105             var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
106             event.localX = mapLoc.x;
107             event.localY = mapLoc.y;
108
109             var newState:ControllerState = state.processMouseEvent(event, null);
110             setState(newState);
111         }
112         
113         public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
114             if (event.type!=MouseEvent.ROLL_OVER) map.stage.focus = map.parent;
115             //if ( event.type == MouseEvent.MOUSE_DOWN )
116             event.stopPropagation();
117                 
118             var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
119             event.localX = mapLoc.x;
120             event.localY = mapLoc.y;
121
122             var newState:ControllerState = state.processMouseEvent(event, entity);
123             setState(newState);
124         }
125         
126         public function setState(newState:ControllerState):void {
127             if ( newState == state )
128                 return;
129                 
130             if ( state != null )
131                 state.exitState(newState);
132             newState.setController(this);
133             newState.setPreviousState(state);
134             state = newState;
135             state.enterState();
136         }
137
138                 public function findStateForSelection(sel:Array):ControllerState {
139                         if (sel.length==0) { return new NoSelection(); }
140                         else if (sel.length>1) { return new SelectedMultiple(sel); }
141                         else if (sel[0] is Way) { return new SelectedWay(sel[0]); }
142                         else if (sel[0] is Node && Node(sel[0]).hasParentWays) {
143                                 var way:Way=sel[0].parentWays[0] as Way;
144                                 return new SelectedWayNode(way, way.indexOfNode(sel[0] as Node));
145                         } else {
146                                 return new SelectedPOINode(sel[0] as Node);
147                         }
148                 }
149
150                 public function setCursor(cursor:Class):void {
151                         CursorManager.removeAllCursors();
152                         if (cursor && cursorsEnabled) { CursorManager.setCursor(cursor,2,-4,0); }
153                 }
154
155         private function toggleSize():void {
156             if (maximised) {
157                 if (minimiseFunction) {
158                     ExternalInterface.call(minimiseFunction);
159                 }
160
161                 maximised = false;
162             } else {
163                 if (maximiseFunction) {
164                     ExternalInterface.call(maximiseFunction);
165                 }
166
167                 maximised = true;
168             }
169         }
170
171                 private function moveHandler(event:MapEvent):void {
172                         ExternalInterface.call(this.moveFunction,
173                                    event.params.lon, event.params.lat, event.params.scale,
174                                    event.params.minlon, event.params.minlat,
175                                    event.params.maxlon, event.params.maxlat);
176                 }
177
178     }
179     
180 }