fa4696be91bd640a20946cf8c76c5eb7f06cb5b5
[potlatch2.git] / net / systemeD / potlatch2 / controller / DrawWay.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         import flash.geom.*;
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;
9
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                 
17                 public function DrawWay(way:Way, editEnd:Boolean, leaveNodeSelected:Boolean) {
18                         super(way);
19                         this.editEnd = editEnd;
20                         this.leaveNodeSelected = leaveNodeSelected;
21                         if (way.length==1 && way.getNode(0).parentWays.length==1) {
22                                 // drawing new way, so keep track of click in case creating a POI
23                                 lastClick=way.getNode(0);
24                                 lastClickTime=new Date();
25                         }
26                 }
27                 
28                 override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
29                         var mouse:Point;
30                         var node:Node;
31                         var focus:Entity = getTopLevelFocusEntity(entity);
32
33                         if ( event.type == MouseEvent.MOUSE_UP ) {
34                                 if ( entity == null ) {
35                                         node = createAndAddNode(event);
36                                         resetElastic(node);
37                                         lastClick=node;
38                                 } else if ( entity is Node ) {
39                                         if (entity==lastClick && (new Date().getTime()-lastClickTime.getTime())<1000) {
40                                                 if (selectedWay.length==1 && selectedWay.getNode(0).parentWays.length==1) {
41                                                         // double-click to create new POI
42                                                         node=selectedWay.getNode(0);
43                                                         stopDrawing();
44                                                         controller.connection.registerPOI(node);
45                                                         return new SelectedPOINode(node);
46                                                 } else {
47                                                         // double-click at end of way
48                                                         return stopDrawing();
49                                                 }
50                                         } else {
51                                                 appendNode(entity as Node, MainUndoStack.getGlobalStack().addAction);
52                                                 controller.map.setHighlight(focus, { showNodesHover: false });
53                                                 controller.map.setHighlight(selectedWay, { showNodes: true });
54                                                 resetElastic(entity as Node);
55                                                 lastClick=entity;
56                                                 if (selectedWay.getNode(0)==selectedWay.getNode(selectedWay.length-1)) {
57                                                         return new SelectedWay(selectedWay);
58                                                 }
59                                         }
60                                 } else if ( entity is Way ) {
61                                         node = createAndAddNode(event);
62                                         Way(entity).insertNodeAtClosestPosition(node, true,
63                                             MainUndoStack.getGlobalStack().addAction);
64                                         resetElastic(node);
65                                         lastClick=node;
66                                         controller.map.setHighlight(entity, { showNodesHover: false });
67                                         controller.map.setHighlight(selectedWay, { showNodes: true });
68                                 }
69                                 lastClickTime=new Date();
70                         } else if ( event.type == MouseEvent.MOUSE_MOVE ) {
71                                 mouse = new Point(
72                                                   controller.map.coord2lon(event.localX),
73                                                   controller.map.coord2latp(event.localY));
74                                 elastic.end = mouse;
75                         } else if ( event.type == MouseEvent.ROLL_OVER && focus!=selectedWay) {
76                                 controller.map.setHighlight(focus, { showNodesHover: true });
77                         } else if ( event.type == MouseEvent.MOUSE_OUT  && focus!=selectedWay) {
78                                 controller.map.setHighlight(focus, { showNodesHover: false });
79                                 controller.map.setHighlight(selectedWay, { showNodes: true });
80                                 // ** this call to setHighlight(selectedWay) is necessary in case the hovered way (blue nodes)
81                                 // shares any nodes with the selected way (red nodes): if they do, they'll be wiped out by the
82                                 // first call.
83                                 // Ultimately we should fix this by referring to 'way :selected nodes' instead of 'nodes :selectedway'.
84                                 // But this will do for now.
85                                 // We could do with an optional way of calling WayUI.redraw to only do the nodes, which would be a
86                                 // useful optimisation.
87                         }
88
89                         return this;
90                 }
91                 
92                 protected function resetElastic(node:Node):void {
93                         var mouse:Point = new Point(node.lon, node.latp);
94                         elastic.start = mouse;
95                         elastic.end = mouse;
96                 }
97
98                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
99                         if ( event.keyCode == 13 || event.keyCode == 27 ) { return stopDrawing(); }
100                         else if (event.keyCode == Keyboard.BACKSPACE) { return backspaceNode(MainUndoStack.getGlobalStack().addAction); }
101                         var cs:ControllerState = sharedKeyboardEvents(event);
102                         return cs ? cs : this;
103                 }
104                 
105                 protected function stopDrawing():ControllerState {
106                         if ( selectedWay.length<2) {
107                                 controller.map.setHighlight(selectedWay, { showNodes: false });
108                                 selectedWay.remove(MainUndoStack.getGlobalStack().addAction);
109                                 // delete controller.map.ways[selectedWay.id];
110                                 return new NoSelection();
111                         } else if ( leaveNodeSelected ) {
112                             return new SelectedWayNode(selectedWay, editEnd ? selectedWay.length - 1 : 0);
113                         } else {
114                             return new SelectedWay(selectedWay);
115                         }
116                         return this;
117                 }
118
119                 public function createAndAddNode(event:MouseEvent):Node {
120                     var undo:CompositeUndoableAction = new CompositeUndoableAction("Add node");
121                     
122                         var lat:Number = controller.map.coord2lat(event.localY);
123                         var lon:Number = controller.map.coord2lon(event.localX);
124                         var node:Node = controller.connection.createNode({}, lat, lon, undo.push);
125                         appendNode(node, undo.push);
126                         
127                         MainUndoStack.getGlobalStack().addAction(undo);
128                         return node;
129                 }
130                 
131                 protected function appendNode(node:Node, performAction:Function):void {
132                         if ( editEnd )
133                                 selectedWay.appendNode(node, performAction);
134                         else
135                                 selectedWay.insertNode(0, node, performAction);
136                 }
137                 
138                 protected function backspaceNode(performAction:Function):ControllerState {
139                         var node:Node;
140                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Remove node");
141                         var newDraw:int;
142                         if (editEnd) {
143                                 node=selectedWay.getNode(selectedWay.length-1);
144                                 selectedWay.removeNodeByIndex(selectedWay.length-1, undo.push);
145                                 newDraw=selectedWay.length-2;
146                         } else {
147                                 node=selectedWay.getNode(0);
148                                 selectedWay.removeNodeByIndex(0, undo.push);
149                                 newDraw=0;
150                         }
151                         if (node.numParentWays==1) {
152                                 controller.connection.unregisterPOI(node);
153                                 node.remove(undo.push);
154                         }
155                         MainUndoStack.getGlobalStack().addAction(undo);
156
157                         if (newDraw>=0 && newDraw<=selectedWay.length-1) {
158                                 var mouse:Point = new Point(selectedWay.getNode(newDraw).lon, selectedWay.getNode(newDraw).latp);
159                                 elastic.start = mouse;
160                                 return this;
161                         } else {
162                                 return new NoSelection();
163                         }
164                 }
165                 
166                 override public function enterState():void {
167                         super.enterState();
168                         
169                         var node:Node = selectedWay.getNode(editEnd ? selectedWay.length - 1 : 0);
170                         var start:Point = new Point(node.lon, node.latp);
171                         elastic = new Elastic(controller.map, start, start);
172                         Globals.vars.root.addDebug("**** -> "+this);
173                 }
174                 override public function exitState():void {
175                         super.exitState();
176                         elastic.removeSprites();
177                         elastic = null;
178                         Globals.vars.root.addDebug("**** <- "+this);
179                 }
180                 override public function toString():String {
181                         return "DrawWay";
182                 }
183         }
184 }