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