Merge branch 'master' into history
[potlatch2.git] / net / systemeD / potlatch2 / controller / DragSelection.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         import flash.geom.Point;
4     import flash.ui.Keyboard;
5     import net.systemeD.potlatch2.EditController;
6     import net.systemeD.halcyon.MapPaint;
7     import net.systemeD.halcyon.connection.*;
8     import net.systemeD.halcyon.connection.actions.*;
9
10     /** The state of moving a selection around with the mouse. */
11     public class DragSelection extends ControllerState {
12         private var isDraggingStarted:Boolean = false;
13                 private var enterTime:Number;
14
15         private var downX:Number;
16         private var downY:Number;
17                 private var dragstate:uint=NOT_MOVED;
18                 private var initialMouseEvent:MouseEvent;
19                 private var wayList:Array;
20                 /** Not used? */
21                 private const NOT_DRAGGING:uint=0;
22                 
23                 /** "Dragging" but hasn't actually moved yet. */
24                 private const NOT_MOVED:uint=1;
25                 
26                 /** While moving. */
27                 private const DRAGGING:uint=2;
28         
29         /** Start the drag by recording the dragged way, where it started, and when. */
30         public function DragSelection(sel:Array, event:MouseEvent, ways:Array = null) {
31             selection = sel.concat();
32             downX = event.localX;
33             downY = event.localY;
34             wayList = ways;
35                         enterTime = (new Date()).getTime();
36                         initialMouseEvent = event;
37         }
38  
39        /** Handle dragging and end drag events. Filters out very short or quick drags. */
40        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
41             if (event.type==MouseEvent.MOUSE_UP) {
42                 if (dragstate==DRAGGING) { 
43                                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Move items");
44                                         var lonDelta:Number = controller.map.coord2lon(downX)-controller.map.coord2lon(event.localX);
45                                         var latDelta:Number = controller.map.coord2lat(downY)-controller.map.coord2lat(event.localY);
46                                         var moved:Object = {};
47                                         for each (var entity:Entity in selection) {
48                                                 if (entity is Node) {
49                                                         var node:Node=Node(entity);
50                                                         node.setLatLon(node.lat-latDelta, node.lon-lonDelta, undo.push);
51                                                         moved[node.id]=true;
52                                                 } else if (entity is Way) {
53                                                         undo.push(new MoveWayAction(Way(entity), latDelta, lonDelta, moved));
54                                                 }
55                                         }
56                                         MainUndoStack.getGlobalStack().addAction(undo);
57                 }
58                                 return controller.findStateForSelection(selection);
59
60                         } else if ( event.type == MouseEvent.MOUSE_MOVE) {
61                                 // dragging
62                                 if (dragstate==NOT_DRAGGING) {
63                                         return this;
64                                 } else if (dragstate==NOT_MOVED && 
65                                                ((Math.abs(downX - event.localX) < 3 && Math.abs(downY - event.localY) < 3) ||
66                                                 (new Date().getTime()-enterTime)<300)) {
67                                         return this;
68                                 }
69                                 dragstate=DRAGGING;
70                 return dragTo(event);
71
72                         } else {
73                                 // event not handled
74                 return this;
75                         }
76         }
77
78                 /** Abort dragging if ESC pressed. */
79                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
80             if (event.keyCode==Keyboard.SPACE) { return cycleAllWays(initialMouseEvent); }
81                         if (event.keyCode==Keyboard.ESCAPE) {
82                                 for each (var entity:Entity in selection) {
83                                         entity.dispatchEvent(new EntityDraggedEvent(Connection.ENTITY_DRAGGED, entity, 0, 0));
84                                 }
85                                 return controller.findStateForSelection(selection);
86                         }
87                         return this;
88                 }
89
90         private function dragTo(event:MouseEvent):ControllerState {
91                         for each (var entity:Entity in selection) {
92                                 entity.dispatchEvent(new EntityDraggedEvent(Connection.ENTITY_DRAGGED, entity, event.localX-downX, event.localY-downY));
93                         }
94             return this;
95         }
96         
97                 public function forceDragStart():void {
98                         dragstate=NOT_MOVED;
99                 }
100
101         private function cycleAllWays(event:MouseEvent):ControllerState {
102             if (!(downX && downY) || (wayList && wayList.length<2) || selection.length != 1) { return this; }
103             if (!wayList) {
104                 wayList=selection
105                 for each (var l:MapPaint in controller.map.getLayers()) {
106 //                  trace("Layer "+l.connection.name);
107 //                  trace(l.findWaysAtPoint(event.stageX, event.stageY).length);
108                     wayList = wayList.concat(l.findWaysAtPoint(event.stageX, event.stageY,selection[0]));
109                 }
110             }
111 //          for each (var way:Way in wayList) { trace(way + "::" + way.connection.name); }
112             wayList=wayList.slice(1).concat(wayList[0]);
113             // Find the new way's index of the currently "selected" node, to facilitate keyboard navigation
114             return new DragSelection([wayList[0]], event, wayList);
115         }
116
117         /** Highlight the dragged selection. */
118         override public function enterState():void {
119                         for each (var entity:Entity in selection) {
120                                 layer.setHighlight(entity, { selected: true });
121                         }
122         }
123         
124         /** Un-highlight the dragged selection. */
125         override public function exitState(newState:ControllerState):void {
126                         for each (var entity:Entity in selection) {
127                                 layer.setHighlight(entity, { selected: false });
128                         }
129         }
130         /** "DragSelection" */
131         override public function toString():String {
132             return "DragSelection";
133         }
134
135
136     }
137 }