1 package net.systemeD.potlatch2.controller {
3 import flash.geom.Point;
4 import flash.ui.Keyboard;
6 import net.systemeD.halcyon.connection.*;
7 import net.systemeD.potlatch2.tools.Quadrilateralise;
8 import net.systemeD.potlatch2.tools.Simplify;
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
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) {
29 private function updateSelectionUI(e:Event):void {
30 controller.updateSelectionUIWithoutTagChange();
33 /** Tidy up UI as we transition to a new state without the current selection. */
34 protected function clearSelection(newState:ControllerState):void {
36 editableLayer.setHighlight(firstSelected, { selected: false, hover: false });
37 editableLayer.setHighlightOnNodes(firstSelected as Way, { selectedway: false });
39 if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
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);
48 if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey ) {
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);
57 } else if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected) {
59 return new SelectedMultiple([firstSelected,entity]);
61 var cs:ControllerState = sharedMouseEvents(event, entity);
62 return cs ? cs : this;
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 /
80 var cs:ControllerState = sharedKeyboardEvents(event);
81 return cs ? cs : this;
84 private function cycleWays():ControllerState {
85 if (!clicked || (wayList && wayList.length<2)) { return this; }
88 wayList=[initWay].concat(editableLayer.findWaysAtPoint(clicked.x,clicked.y,initWay));
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);
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();
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);
113 editableLayer.setPurgable(selection,false);
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();
121 editableLayer.setPurgable(selection,true);
122 firstSelected.removeEventListener(Connection.WAY_REORDERED, updateSelectionUI);
123 clearSelection(newState);
126 /** @return "SelectedWay" */
127 override public function toString():String {
128 return "SelectedWay";