1 package net.systemeD.potlatch2.controller {
4 import flash.ui.Keyboard;
5 import net.systemeD.potlatch2.EditController;
6 import net.systemeD.halcyon.connection.*;
7 import net.systemeD.halcyon.Elastic;
8 import net.systemeD.halcyon.Globals;
10 public class DrawWay extends SelectedWay {
11 private var elastic:Elastic;
12 private var editEnd:Boolean;
13 private var leaveNodeSelected:Boolean;
14 private var lastClick:Entity=null;
15 private var lastClickTime:Date;
16 private var hoverEntity:Entity; // keep track of the currently rolled-over object, because
17 // Flash can fire a mouseDown from the map even if you
18 // haven't rolled out of the way
20 public function DrawWay(way:Way, editEnd:Boolean, leaveNodeSelected:Boolean) {
22 this.editEnd = editEnd;
23 this.leaveNodeSelected = leaveNodeSelected;
24 if (way.length==1 && way.getNode(0).parentWays.length==1) {
25 // drawing new way, so keep track of click in case creating a POI
26 lastClick=way.getNode(0);
27 lastClickTime=new Date();
31 override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
34 if (entity == null && hoverEntity) { entity=hoverEntity; }
35 var focus:Entity = getTopLevelFocusEntity(entity);
37 if ( event.type == MouseEvent.MOUSE_UP ) {
38 if ( entity == null ) {
39 node = createAndAddNode(event);
42 } else if ( entity is Node ) {
43 if (entity==lastClick && (new Date().getTime()-lastClickTime.getTime())<1000) {
44 if (selectedWay.length==1 && selectedWay.getNode(0).parentWays.length==1) {
45 // double-click to create new POI
46 node=selectedWay.getNode(0);
48 node.setDeletedState(false); // has just been deleted by stopDrawing
49 controller.connection.registerPOI(node);
50 return new SelectedPOINode(node);
52 // double-click at end of way
56 appendNode(entity as Node, MainUndoStack.getGlobalStack().addAction);
57 controller.map.setHighlight(focus, { showNodesHover: false });
58 controller.map.setHighlight(selectedWay, { showNodes: true });
59 resetElastic(entity as Node);
61 if (selectedWay.getNode(0)==selectedWay.getNode(selectedWay.length-1)) {
62 return new SelectedWay(selectedWay);
65 } else if ( entity is Way ) {
66 node = createAndAddNode(event);
67 Way(entity).insertNodeAtClosestPosition(node, true,
68 MainUndoStack.getGlobalStack().addAction);
71 controller.map.setHighlight(entity, { showNodesHover: false });
72 controller.map.setHighlight(selectedWay, { showNodes: true });
74 lastClickTime=new Date();
75 } else if ( event.type == MouseEvent.MOUSE_MOVE ) {
77 controller.map.coord2lon(event.localX),
78 controller.map.coord2latp(event.localY));
80 } else if ( event.type == MouseEvent.ROLL_OVER ) {
81 if (focus!=selectedWay) {
83 controller.map.setHighlight(focus, { showNodesHover: true });
85 if (entity is Node && focus is Way && Way(focus).endsWith(Node(entity))) {
86 if (focus==selectedWay) { controller.setCursor(controller.pen_so); }
87 else { controller.setCursor(controller.pen_o); }
88 } else if (entity is Node) {
89 controller.setCursor(controller.pen_x);
91 controller.setCursor(controller.pen_plus);
93 } else if ( event.type == MouseEvent.MOUSE_OUT ) {
94 if (focus!=selectedWay) {
96 controller.map.setHighlight(focus, { showNodesHover: false });
97 controller.map.setHighlight(selectedWay, { showNodes: true });
98 // ** this call to setHighlight(selectedWay) is necessary in case the hovered way (blue nodes)
99 // shares any nodes with the selected way (red nodes): if they do, they'll be wiped out by the
101 // Ultimately we should fix this by referring to 'way :selected nodes' instead of 'nodes :selectedway'.
102 // But this will do for now.
103 // We could do with an optional way of calling WayUI.redraw to only do the nodes, which would be a
104 // useful optimisation.
106 controller.setCursor(controller.pen);
112 protected function resetElastic(node:Node):void {
113 var mouse:Point = new Point(node.lon, node.latp);
114 elastic.start = mouse;
118 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
119 switch (event.keyCode) {
120 case 13: return stopDrawing();
121 case 27: return stopDrawing();
122 case Keyboard.BACKSPACE: return backspaceNode(MainUndoStack.getGlobalStack().addAction);
123 case 82: repeatTags(selectedWay); return this;
125 var cs:ControllerState = sharedKeyboardEvents(event);
126 return cs ? cs : this;
129 protected function stopDrawing():ControllerState {
130 if ( selectedWay.length<2) {
131 controller.map.setHighlight(selectedWay, { showNodes: false });
132 selectedWay.remove(MainUndoStack.getGlobalStack().addAction);
133 // delete controller.map.ways[selectedWay.id];
134 return new NoSelection();
135 } else if ( leaveNodeSelected ) {
136 return new SelectedWayNode(selectedWay, editEnd ? selectedWay.length - 1 : 0);
138 return new SelectedWay(selectedWay);
143 public function createAndAddNode(event:MouseEvent):Node {
144 var undo:CompositeUndoableAction = new CompositeUndoableAction("Add node");
146 var lat:Number = controller.map.coord2lat(event.localY);
147 var lon:Number = controller.map.coord2lon(event.localX);
148 var node:Node = controller.connection.createNode({}, lat, lon, undo.push);
149 appendNode(node, undo.push);
151 MainUndoStack.getGlobalStack().addAction(undo);
155 protected function appendNode(node:Node, performAction:Function):void {
157 selectedWay.appendNode(node, performAction);
159 selectedWay.insertNode(0, node, performAction);
162 protected function backspaceNode(performAction:Function):ControllerState {
164 var undo:CompositeUndoableAction = new CompositeUndoableAction("Remove node");
167 node=selectedWay.getNode(selectedWay.length-1);
168 selectedWay.removeNodeByIndex(selectedWay.length-1, undo.push);
169 newDraw=selectedWay.length-2;
171 node=selectedWay.getNode(0);
172 selectedWay.removeNodeByIndex(0, undo.push);
175 if (node.numParentWays==1) {
176 controller.connection.unregisterPOI(node);
177 node.remove(undo.push);
179 MainUndoStack.getGlobalStack().addAction(undo);
181 if (newDraw>=0 && newDraw<=selectedWay.length-1) {
182 var mouse:Point = new Point(selectedWay.getNode(newDraw).lon, selectedWay.getNode(newDraw).latp);
183 elastic.start = mouse;
186 return new NoSelection();
190 override public function enterState():void {
193 var node:Node = selectedWay.getNode(editEnd ? selectedWay.length - 1 : 0);
194 var start:Point = new Point(node.lon, node.latp);
195 elastic = new Elastic(controller.map, start, start);
196 controller.setCursor(controller.pen);
197 Globals.vars.root.addDebug("**** -> "+this);
199 override public function exitState():void {
201 controller.setCursor(null);
202 elastic.removeSprites();
204 Globals.vars.root.addDebug("**** <- "+this);
206 override public function toString():String {