Make quadralaterawhatsit work on selected waynodes, too. Add Q shortcut for both.
[potlatch2.git] / net / systemeD / potlatch2 / controller / SelectedWayNode.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         import flash.ui.Keyboard;
4         import flash.geom.Point;
5     import net.systemeD.potlatch2.EditController;
6     import net.systemeD.potlatch2.tools.Quadrilateralise;
7     import net.systemeD.halcyon.WayUI;
8     import net.systemeD.halcyon.connection.*;
9     import net.systemeD.halcyon.connection.actions.*;
10         import net.systemeD.halcyon.Globals;
11
12     public class SelectedWayNode extends ControllerState {
13                 private var parentWay:Way;
14                 private var initIndex:int;
15                 private var selectedIndex:int;
16         
17         public function SelectedWayNode(way:Way,index:int) {
18             parentWay = way;
19                         initIndex = index;
20         }
21  
22         protected function selectNode(way:Way,index:int):void {
23                         var node:Node=way.getNode(index);
24             if ( way == parentWay && node == firstSelected )
25                 return;
26
27             clearSelection(this);
28             controller.map.setHighlight(way, { hover: false });
29             controller.map.setHighlight(node, { selected: true });
30             controller.map.setHighlightOnNodes(way, { selectedway: true });
31             selection = [node]; parentWay = way;
32             controller.updateSelectionUI();
33                         selectedIndex = index; initIndex = index;
34         }
35                 
36         protected function clearSelection(newState:ControllerState):void {
37             if ( selectCount ) {
38                 controller.map.setHighlight(parentWay, { selected: false });
39                                 controller.map.setHighlight(firstSelected, { selected: false });
40                                 controller.map.setHighlightOnNodes(parentWay, { selectedway: false });
41                                 selection = [];
42                 if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
43             }
44         }
45         
46         override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
47                         if (event.type==MouseEvent.MOUSE_MOVE || event.type==MouseEvent.ROLL_OVER || event.type==MouseEvent.MOUSE_OUT) { return this; }
48             var focus:Entity = getTopLevelFocusEntity(entity);
49
50             if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey ) {
51                                 // start new way
52                 var way:Way = controller.connection.createWay({}, [entity],
53                     MainUndoStack.getGlobalStack().addAction);
54                 return new DrawWay(way, true, false);
55                         } else if ( event.type == MouseEvent.MOUSE_UP && entity is Node && focus == parentWay ) {
56                                 // select node within way
57                                 return selectOrEdit(parentWay, getNodeIndex(parentWay,Node(entity)));
58             } else if ( event.type == MouseEvent.MOUSE_DOWN && entity is Way && focus==parentWay && event.shiftKey) {
59                                 // insert node within way (shift-click)
60                         var d:DragWayNode=new DragWayNode(parentWay, -1, event, true);
61                                 d.forceDragStart();
62                                 return d;
63                         }
64                         var cs:ControllerState = sharedMouseEvents(event, entity);
65                         return cs ? cs : this;
66         }
67
68                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
69                         switch (event.keyCode) {
70                                 case 189:                                       return removeNode();                                    // '-'
71                                 case 88:                                        return splitWay();                                              // 'X'
72                 case 81:  /* Q */           Quadrilateralise.quadrilateralise(parentWay, MainUndoStack.getGlobalStack().addAction); return this;
73                                 case 82:                                        repeatTags(firstSelected); return this; // 'R'
74                                 case 87:                                        return new SelectedWay(parentWay);              // 'W'
75                                 case 191:                                       return cycleWays();                                             // '/'
76                 case 74:                    if (event.shiftKey) { return unjoin() }; return join();// 'J'
77                                 case Keyboard.BACKSPACE:        return deleteNode();
78                                 case Keyboard.DELETE:           return deleteNode();
79                         }
80                         var cs:ControllerState = sharedKeyboardEvents(event);
81                         return cs ? cs : this;
82                 }
83
84                 override public function get selectedWay():Way {
85                         return parentWay;
86                 }
87
88                 private function cycleWays():ControllerState {
89                         var wayList:Array=firstSelected.parentWays;
90                         if (wayList.length==1) { return this; }
91                         wayList.splice(wayList.indexOf(parentWay),1);
92                         return new SelectedWay(wayList[0],
93                                                new Point(controller.map.lon2coord(Node(firstSelected).lon),
94                                                          controller.map.latp2coord(Node(firstSelected).latp)),
95                                                wayList.concat(parentWay));
96                 }
97
98                 override public function enterState():void {
99             selectNode(parentWay,initIndex);
100                         controller.map.setPurgable(selection,false);
101                         Globals.vars.root.addDebug("**** -> "+this);
102         }
103                 override public function exitState(newState:ControllerState):void {
104             if (firstSelected.hasTags()) {
105               controller.clipboards['node']=firstSelected.getTagsCopy();
106             }
107                         controller.map.setPurgable(selection,true);
108             clearSelection(newState);
109                         Globals.vars.root.addDebug("**** <- "+this);
110         }
111
112         override public function toString():String {
113             return "SelectedWayNode";
114         }
115
116                 public static function selectOrEdit(selectedWay:Way, index:int):ControllerState {
117                         var isFirst:Boolean = false;
118                         var isLast:Boolean = false;
119                         var node:Node = selectedWay.getNode(index);
120                         isFirst = selectedWay.getNode(0) == node;
121                         isLast = selectedWay.getLastNode() == node;
122                         if ( isFirst == isLast )    // both == looped, none == central node 
123                             return new SelectedWayNode(selectedWay, index);
124                         else
125                             return new DrawWay(selectedWay, isLast, true);
126         }
127
128                 public function splitWay():ControllerState {
129                         // abort if start or end
130                         if (parentWay.getNode(0)    == firstSelected) { return this; }
131                         if (parentWay.getLastNode() == firstSelected) { return this; }
132
133                         controller.map.setHighlightOnNodes(parentWay, { selectedway: false } );
134                         controller.map.setPurgable([parentWay],true);
135             MainUndoStack.getGlobalStack().addAction(new SplitWayAction(parentWay, firstSelected as Node));
136
137                         return new SelectedWay(parentWay);
138                 }
139                 
140                 public function removeNode():ControllerState {
141                         if (firstSelected.numParentWays==1 && parentWay.hasOnceOnly(firstSelected as Node)) {
142                                 return deleteNode();
143                         }
144                         parentWay.removeNodeByIndex(selectedIndex, MainUndoStack.getGlobalStack().addAction);
145                         return new SelectedWay(parentWay);
146                 }
147                 
148                 public function deleteNode():ControllerState {
149                         controller.map.setPurgable(selection,true);
150                         firstSelected.remove(MainUndoStack.getGlobalStack().addAction);
151                         return new SelectedWay(parentWay);
152                 }
153
154         public function unjoin():ControllerState {
155             Node(firstSelected).unjoin(parentWay, MainUndoStack.getGlobalStack().addAction);
156             return this;
157         }
158
159         public function join():ControllerState {
160             // detect the ways that overlap this node
161             var p:Point = new Point(controller.map.lon2coord(Node(firstSelected).lon),
162                                              controller.map.latp2coord(Node(firstSelected).latp));
163             var q:Point = map.localToGlobal(p);
164             var ways:Array=[]; var w:Way;
165             for each (var wayui:WayUI in controller.map.paint.wayuis) {
166                 w=wayui.hitTest(q.x, q.y);
167                 if (w && w!=selectedWay) { ways.push(w); }
168             }
169
170             Node(firstSelected).join(ways,MainUndoStack.getGlobalStack().addAction);
171             return this;
172         }
173     }
174 }