1c15243c70d7356b31229f52f7f16a9451e75f86
[potlatch2.git] / net / systemeD / potlatch2 / controller / SelectedWay.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         import flash.geom.Point;
4         import flash.ui.Keyboard;
5         
6         import net.systemeD.halcyon.connection.*;
7         import net.systemeD.potlatch2.tools.Quadrilateralise;
8         import net.systemeD.potlatch2.tools.Simplify;
9
10     /** Behaviour that takes place while a way is selected includes: adding a node to the way, straightening/reshaping the way, dragging it. */
11     public class SelectedWay extends ControllerState {
12         /** The selected way itself. */
13         protected var initWay:Way;
14         private var clicked:Point;              // did the user enter this state by clicking at a particular point?
15                 private var wayList:Array;              // list of ways to cycle through with '/' keypress
16                 private var initIndex: int;     // index of last selected node if entered from SelectedWayNode
17         
18         /** 
19         * @param way The way that is now selected.
20         * @param point The location that was clicked.
21         * @param ways An ordered list of ways sharing a node, to make "way cycling" work. */
22         public function SelectedWay(way:Way, point:Point=null, ways:Array=null, index:int=0) {
23             initWay = way;
24                         clicked = point;
25                         wayList = ways;
26                         initIndex=index;
27         }
28
29         private function updateSelectionUI(e:Event):void {
30             controller.updateSelectionUIWithoutTagChange();
31         }
32
33         /** Tidy up UI as we transition to a new state without the current selection. */
34         protected function clearSelection(newState:ControllerState):void {
35             if ( selectCount ) {
36                 editableLayer.setHighlight(firstSelected, { selected: false, hover: false });
37                 editableLayer.setHighlightOnNodes(firstSelected as Way, { selectedway: false });
38                 selection = [];
39                 if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
40             }
41         }
42         
43         /** Behaviour includes: start drawing a new way, insert a node within this way, select an additional way */
44         override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
45                         if (event.type==MouseEvent.MOUSE_MOVE || event.type==MouseEvent.ROLL_OVER || event.type==MouseEvent.MOUSE_OUT) { return this; }
46             var focus:Entity = getTopLevelFocusEntity(entity);
47
48             if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey ) {
49                                 // start new way
50                                 var way:Way = entity.connection.createWay({}, [entity], MainUndoStack.getGlobalStack().addAction);
51                                 return new DrawWay(way, true, false);
52                         } else if ( event.type == MouseEvent.MOUSE_DOWN && entity is Way && focus==firstSelected && event.shiftKey) {
53                                 // insert node within way (shift-click)
54                 var d:DragWayNode=new DragWayNode(firstSelected as Way, -1, event, true);
55                                 d.forceDragStart();
56                                 return d;
57                         } else if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected) {
58                                 // multiple selection
59                                 return new SelectedMultiple([firstSelected,entity]);
60                         }
61                         var cs:ControllerState = sharedMouseEvents(event, entity);
62                         return cs ? cs : this;
63         }
64         
65                 /** Behaviour includes: parallel way, repeat tags, reverse direction, simplify, cycle way selection, delete */
66                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
67                         switch (event.keyCode) {
68                                 case 80:  /* P */           return new SelectedParallelWay(firstSelected as Way); 
69                                 case 81:  /* Q */           Quadrilateralise.quadrilateralise(firstSelected as Way, MainUndoStack.getGlobalStack().addAction); return this;
70                                 case 82:  /* R */           repeatTags(firstSelected); return this;
71                 case 86:  /* V */           Way(firstSelected).reverseNodes(MainUndoStack.getGlobalStack().addAction); return this;
72                 case 89:  /* Y */           Simplify.simplify(firstSelected as Way, controller.map, true); return this;
73                                 case 191: /* / */           return cycleWays();
74                                 case Keyboard.BACKSPACE:        
75                                 case Keyboard.DELETE:           if (event.shiftKey) { return deleteWay(); } break;
76                 case 188: /* , */           return new SelectedWayNode(initWay, initIndex); // allows navigating from one way to another by keyboard
77                 case 190: /* . */           return new SelectedWayNode(initWay, initIndex); //  using <, > and /           
78
79                         }
80                         var cs:ControllerState = sharedKeyboardEvents(event);
81                         return cs ? cs : this;
82                 }
83         
84                 private function cycleWays():ControllerState {
85                         if (!clicked || (wayList && wayList.length<2)) { return this; }
86
87                         if (!wayList) {
88                                 wayList=[initWay].concat(editableLayer.findWaysAtPoint(clicked.x,clicked.y,initWay));
89                         }
90                         wayList=wayList.slice(1).concat(wayList[0]);
91                         // Find the new way's index of the currently "selected" node, to facilitate keyboard navigation
92                         var newindex:int = Way(wayList[0]).indexOfNode(initWay.getNode(initIndex));
93                         return new SelectedWay(wayList[0], clicked, wayList, newindex);
94                 }
95
96                 /** Perform deletion of currently selected way. */
97                 public function deleteWay():ControllerState {
98                         editableLayer.setHighlightOnNodes(firstSelected as Way, {selectedway: false});
99                         selectedWay.remove(MainUndoStack.getGlobalStack().addAction);
100                         return new NoSelection();
101                 }
102
103         /** Officially enter this state by marking the previously nominated way as selected. */
104         override public function enterState():void {
105             if (firstSelected!=initWay) {
106                     clearSelection(this);
107                     editableLayer.setHighlight(initWay, { selected: true, hover: false });
108                     editableLayer.setHighlightOnNodes(initWay, { selectedway: true });
109                     selection = [initWay];
110                     controller.updateSelectionUI();
111                     initWay.addEventListener(Connection.WAY_REORDERED, updateSelectionUI, false, 0, true);
112                         }
113                         editableLayer.setPurgable(selection,false);
114         }
115         /** Officially leave the state, remembering the current way's tags for future repeats. */
116         // TODO: tweak this so that repeat tags aren't remembered if you only select a way in order to branch off it. (a la PL1) 
117         override public function exitState(newState:ControllerState):void {
118                         if (firstSelected.hasTags()) {
119               controller.clipboards['way']=firstSelected.getTagsCopy();
120             }
121                         editableLayer.setPurgable(selection,true);
122             firstSelected.removeEventListener(Connection.WAY_REORDERED, updateSelectionUI);
123             clearSelection(newState);
124         }
125
126         /** @return "SelectedWay" */
127         override public function toString():String {
128             return "SelectedWay";
129         }
130
131     }
132 }