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