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.*;
14 import flash.ui.Keyboard;
15 import flash.text.TextField;
16 import mx.controls.TextArea;
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 {
23 public var tagViewer:TagViewer;
24 private var toolbox:Toolbox;
26 /** The current ControllerState */
27 public var state:ControllerState;
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;
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;
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) {
46 setState(new NoSelection());
47 this.tagViewer = tagViewer;
48 this.tagViewer.controller = this;
49 this.toolbox = toolbox;
50 this.toolbox.init(this);
51 this.maximiseFunction = Globals.vars.flashvars["maximise_function"];
52 this.minimiseFunction = Globals.vars.flashvars["minimise_function"];
53 this.moveFunction = Globals.vars.flashvars["move_function"];
55 map.parent.addEventListener(MouseEvent.MOUSE_MOVE, mapMouseEvent);
56 map.parent.addEventListener(MouseEvent.MOUSE_UP, mapMouseEvent);
57 map.parent.addEventListener(MouseEvent.MOUSE_DOWN, mapMouseEvent);
58 map.parent.addEventListener(MouseEvent.MOUSE_WHEEL, mapMouseEvent);
59 map.parent.addEventListener(MouseEvent.CLICK, mapMouseEvent);
60 map.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
61 map.stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
63 if (this.moveFunction) {
64 map.addEventListener(MapEvent.MOVE, moveHandler);
68 public function setActive():void {
69 map.setController(this);
72 /** Accesses map object. */
73 public function get map():Map {
78 * Updates the various user interfaces that change when the selection changes.
79 * Currently this is the TagViewer and the Toolbox
81 * @param layer Optionally pass the layer of the currently selected entity, eg for BugLayers
83 public function updateSelectionUI(layer:MapPaint = null):void {
84 tagViewer.setEntity(state.selection, layer);
85 toolbox.updateSelectionUI();
88 public function updateSelectionUIWithoutTagChange():void {
89 toolbox.updateSelectionUI();
92 private function keyDownHandler(event:KeyboardEvent):void {
93 if ((event.target is TextField) || (event.target is TextArea)) return;
94 keys[event.keyCode]=true;
97 private function keyUpHandler(event:KeyboardEvent):void {
98 if (!keys[event.keyCode]) return;
99 delete keys[event.keyCode];
100 if ((event.target is TextField) || (event.target is TextArea)) return; // not meant for us
102 if (FunctionKeyManager.instance().handleKeypress(event.keyCode)) { return; }
104 if (event.keyCode == 77) { toggleSize(); } // 'M'
105 var newState:ControllerState = state.processKeyboardEvent(event);
109 /** Is the given key currently pressed? */
110 public function keyDown(key:Number):Boolean {
111 return Boolean(keys[key]);
114 private function mapMouseEvent(event:MouseEvent):void {
115 if (isInteractionEvent(event)) map.stage.focus = map.parent;
116 if (event.type==MouseEvent.MOUSE_UP && map.dragstate==map.DRAGGING) { return; }
118 var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
119 event.localX = mapLoc.x;
120 event.localY = mapLoc.y;
122 var newState:ControllerState = state.processMouseEvent(event, null);
126 public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
127 if (isInteractionEvent(event)) map.stage.focus = map.parent;
128 event.stopPropagation();
130 var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
131 event.localX = mapLoc.x;
132 event.localY = mapLoc.y;
134 var newState:ControllerState = state.processMouseEvent(event, entity);
138 private function isInteractionEvent(event:MouseEvent):Boolean {
139 switch (event.type) {
140 case MouseEvent.ROLL_OUT: return false;
141 case MouseEvent.ROLL_OVER: return false;
142 case MouseEvent.MOUSE_OUT: return false;
143 case MouseEvent.MOUSE_OVER: return false;
144 case MouseEvent.MOUSE_MOVE: return false;
149 /** Exit the current state and switch to a new one.
151 * @param newState The ControllerState to switch to. */
152 public function setState(newState:ControllerState):void {
153 if ( newState == state )
157 state.exitState(newState);
158 newState.setController(this);
159 newState.setPreviousState(state);
164 /** Given what is currently selected (or not), find the matching ControllerState. */
165 public function findStateForSelection(sel:Array):ControllerState {
166 if (sel.length==0) { return new NoSelection(); }
167 var layer:MapPaint=_map.getLayerForEntity(sel[0]);
169 if (sel.length>1) { return new SelectedMultiple(sel, layer); }
170 else if (sel[0] is Way) { return new SelectedWay(sel[0], layer); }
171 else if (sel[0] is Node && Node(sel[0]).hasParentWays) {
172 var way:Way=sel[0].parentWays[0] as Way;
173 return new SelectedWayNode(way, way.indexOfNode(sel[0] as Node));
175 return new SelectedPOINode(sel[0] as Node, layer);
179 /** Set a mouse pointer. */
180 public function setCursor(cursor:Class):void {
181 CursorManager.removeAllCursors();
182 if (cursor && cursorsEnabled) { CursorManager.setCursor(cursor,2,-4,0); }
185 private function toggleSize():void {
187 if (minimiseFunction) {
188 ExternalInterface.call(minimiseFunction);
193 if (maximiseFunction) {
194 ExternalInterface.call(maximiseFunction);
201 private function moveHandler(event:MapEvent):void {
202 ExternalInterface.call(this.moveFunction,
203 event.params.lon, event.params.lat, event.params.scale,
204 event.params.minlon, event.params.minlat,
205 event.params.maxlon, event.params.maxlat);