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.*;
13 import flash.ui.Keyboard;
15 /** Controller for the main map editing window itself. The logic that responds to mouse and keyboard events is all
16 * buried in various ControllerState classes. */
17 public class EditController implements MapController {
20 public var tagViewer:TagViewer;
21 private var toolbox:Toolbox;
23 public var state:ControllerState;
24 private var _connection:Connection;
26 private var keys:Object={};
27 public var clipboards:Object={};
28 public var cursorsEnabled:Boolean=true;
29 private var maximised:Boolean=false;
30 private var maximiseFunction:String;
31 private var minimiseFunction:String;
32 private var moveFunction:String;
34 [Embed(source="../../../embedded/pen.png")] public var pen:Class;
35 [Embed(source="../../../embedded/pen_x.png")] public var pen_x:Class;
36 [Embed(source="../../../embedded/pen_o.png")] public var pen_o:Class;
37 [Embed(source="../../../embedded/pen_so.png")] public var pen_so:Class;
38 [Embed(source="../../../embedded/pen_plus.png")] public var pen_plus:Class;
40 /** Constructor function: needs the map information, a panel to edit tags with, and the toolbox to manipulate ways with. */
41 public function EditController(map:Map, tagViewer:TagViewer, toolbox:Toolbox) {
43 setState(new NoSelection());
44 this.tagViewer = tagViewer;
45 this.toolbox = toolbox;
46 this.toolbox.init(this);
47 this.maximiseFunction = Connection.getParam("maximise_function", null);
48 this.minimiseFunction = Connection.getParam("minimise_function", null);
49 this.moveFunction = Connection.getParam("move_function", null);
51 map.parent.addEventListener(MouseEvent.MOUSE_MOVE, mapMouseEvent);
52 map.parent.addEventListener(MouseEvent.MOUSE_UP, mapMouseEvent);
53 map.parent.addEventListener(MouseEvent.MOUSE_DOWN, mapMouseEvent);
54 map.parent.addEventListener(MouseEvent.MOUSE_WHEEL, mapMouseEvent);
55 map.parent.addEventListener(MouseEvent.CLICK, mapMouseEvent);
56 map.parent.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
57 map.parent.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
59 if (this.moveFunction) {
60 map.addEventListener(MapEvent.MOVE, moveHandler);
64 public function setActive():void {
65 map.setController(this);
66 _connection = map.connection;
69 /** Accesses map object. */
70 public function get map():Map {
74 /** Accesss connection object. */
75 public function get connection():Connection {
80 * Updates the various user interfaces that change when the selection changes.
81 * Currently this is the TagViewer and the Toolbox
83 * @param layer Optionally pass the layer of the currently selected entity, eg for BugLayers
85 public function updateSelectionUI(layer:VectorLayer = null):void {
86 tagViewer.setEntity(state.selection, layer);
87 toolbox.updateSelectionUI();
90 public function updateSelectionUIWithoutTagChange():void {
91 toolbox.updateSelectionUI();
94 private function keyDownHandler(event:KeyboardEvent):void {
95 keys[event.keyCode]=true;
98 private function keyUpHandler(event:KeyboardEvent):void {
99 trace("key code "+event.keyCode);
100 if (keys[event.keyCode]) { delete keys[event.keyCode]; }
101 if (FunctionKeyManager.instance().handleKeypress(event.keyCode)) { return; }
103 if (event.keyCode == 77) { toggleSize(); } // 'M'
104 var newState:ControllerState = state.processKeyboardEvent(event);
108 /** Is the given key currently pressed? */
109 public function keyDown(key:Number):Boolean {
110 return Boolean(keys[key]);
113 private function mapMouseEvent(event:MouseEvent):void {
114 if (isInteractionEvent(event)) map.stage.focus = map.parent;
115 if (event.type==MouseEvent.MOUSE_UP && map.dragstate==map.DRAGGING) { return; }
117 var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
118 event.localX = mapLoc.x;
119 event.localY = mapLoc.y;
121 var newState:ControllerState = state.processMouseEvent(event, null);
125 public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
126 if (isInteractionEvent(event)) map.stage.focus = map.parent;
127 event.stopPropagation();
129 var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
130 event.localX = mapLoc.x;
131 event.localY = mapLoc.y;
133 var newState:ControllerState = state.processMouseEvent(event, entity);
137 private function isInteractionEvent(event:MouseEvent):Boolean {
138 switch (event.type) {
139 case MouseEvent.ROLL_OUT: return false;
140 case MouseEvent.ROLL_OVER: return false;
141 case MouseEvent.MOUSE_OUT: return false;
142 case MouseEvent.MOUSE_OVER: return false;
143 case MouseEvent.MOUSE_MOVE: return false;
148 /** Exit the current state and switch to a new one. */
149 public function setState(newState:ControllerState):void {
150 if ( newState == state )
154 state.exitState(newState);
155 newState.setController(this);
156 newState.setPreviousState(state);
161 /** Given what is currently selected (or not), find the matching ControllerState. */
162 public function findStateForSelection(sel:Array):ControllerState {
163 if (sel.length==0) { return new NoSelection(); }
164 else if (sel.length>1) { return new SelectedMultiple(sel); }
165 else if (sel[0] is Way) { return new SelectedWay(sel[0]); }
166 else if (sel[0] is Node && Node(sel[0]).hasParentWays) {
167 var way:Way=sel[0].parentWays[0] as Way;
168 return new SelectedWayNode(way, way.indexOfNode(sel[0] as Node));
170 return new SelectedPOINode(sel[0] as Node);
174 /** Set a mouse pointer. */
175 public function setCursor(cursor:Class):void {
176 CursorManager.removeAllCursors();
177 if (cursor && cursorsEnabled) { CursorManager.setCursor(cursor,2,-4,0); }
180 private function toggleSize():void {
182 if (minimiseFunction) {
183 ExternalInterface.call(minimiseFunction);
188 if (maximiseFunction) {
189 ExternalInterface.call(maximiseFunction);
196 private function moveHandler(event:MapEvent):void {
197 ExternalInterface.call(this.moveFunction,
198 event.params.lon, event.params.lat, event.params.scale,
199 event.params.minlon, event.params.minlat,
200 event.params.maxlon, event.params.maxlat);