1 package net.systemeD.potlatch2.controller {
3 import flash.geom.Point;
4 import flash.ui.Keyboard;
6 import net.systemeD.halcyon.Globals;
7 import net.systemeD.halcyon.WayUI;
8 import net.systemeD.halcyon.connection.*;
9 import net.systemeD.halcyon.connection.actions.*;
10 import net.systemeD.potlatch2.tools.Quadrilateralise;
12 public class SelectedWayNode extends ControllerState {
13 private var parentWay:Way;
14 private var initIndex:int;
15 private var selectedIndex:int;
17 public function SelectedWayNode(way:Way,index:int) {
22 protected function selectNode(way:Way,index:int):void {
23 var node:Node=way.getNode(index);
24 if ( way == parentWay && node == firstSelected )
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;
36 protected function clearSelection(newState:ControllerState):void {
38 controller.map.setHighlight(parentWay, { selected: false });
39 controller.map.setHighlight(firstSelected, { selected: false });
40 controller.map.setHighlightOnNodes(parentWay, { selectedway: false });
42 if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
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);
50 if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey ) {
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);
64 var cs:ControllerState = sharedMouseEvents(event, entity);
65 return cs ? cs : this;
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();
80 var cs:ControllerState = sharedKeyboardEvents(event);
81 return cs ? cs : this;
84 override public function get selectedWay():Way {
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));
98 override public function enterState():void {
99 selectNode(parentWay,initIndex);
100 controller.map.setPurgable(selection,false);
101 Globals.vars.root.addDebug("**** -> "+this);
103 override public function exitState(newState:ControllerState):void {
104 if (firstSelected.hasTags()) {
105 controller.clipboards['node']=firstSelected.getTagsCopy();
107 controller.map.setPurgable(selection,true);
108 clearSelection(newState);
109 Globals.vars.root.addDebug("**** <- "+this);
112 override public function toString():String {
113 return "SelectedWayNode";
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);
125 return new DrawWay(selectedWay, isLast, true);
128 /** Splits a way into two separate ways, at the currently selected node. Handles simple loops and P-shapes. Untested for anything funkier. */
129 public function splitWay():ControllerState {
130 var n:Node=firstSelected as Node;
131 var ni:uint = parentWay.indexOfNode(n);
132 // abort if start or end
133 if (parentWay.isPShape() && !parentWay.hasOnceOnly(n)) {
134 // If P-shaped, we want to split at the midway point on the stem, not at the end of the loop
135 ni = parentWay.getPJunctionNodeIndex();
138 if (parentWay.getNode(0) == n) { return this; }
139 if (parentWay.getLastNode() == n) { return this; }
142 controller.map.setHighlightOnNodes(parentWay, { selectedway: false } );
143 controller.map.setPurgable([parentWay],true);
144 MainUndoStack.getGlobalStack().addAction(new SplitWayAction(parentWay, ni));
146 return new SelectedWay(parentWay);
149 public function removeNode():ControllerState {
150 if (firstSelected.numParentWays==1 && parentWay.hasOnceOnly(firstSelected as Node) && !(firstSelected as Node).hasInterestingTags()) {
153 parentWay.removeNodeByIndex(selectedIndex, MainUndoStack.getGlobalStack().addAction);
154 return new SelectedWay(parentWay);
157 public function deleteNode():ControllerState {
158 controller.map.setPurgable(selection,true);
159 firstSelected.remove(MainUndoStack.getGlobalStack().addAction);
160 return new SelectedWay(parentWay);
163 public function unjoin():ControllerState {
164 Node(firstSelected).unjoin(parentWay, MainUndoStack.getGlobalStack().addAction);
168 public function join():ControllerState {
169 // detect the ways that overlap this node
170 var p:Point = new Point(controller.map.lon2coord(Node(firstSelected).lon),
171 controller.map.latp2coord(Node(firstSelected).latp));
172 var q:Point = map.localToGlobal(p);
173 var ways:Array=[]; var w:Way;
174 for each (var wayui:WayUI in controller.map.paint.wayuis) {
175 w=wayui.hitTest(q.x, q.y);
176 if (w && w!=selectedWay) { ways.push(w); }
179 Node(firstSelected).join(ways,MainUndoStack.getGlobalStack().addAction);