Unify selection ControllerStates so they can work on either background or editable...
authorRichard Fairhurst <richard@systemeD.net>
Wed, 15 Jun 2011 22:28:18 +0000 (23:28 +0100)
committerRichard Fairhurst <richard@systemeD.net>
Wed, 15 Jun 2011 22:28:18 +0000 (23:28 +0100)
12 files changed:
net/systemeD/halcyon/Map.as
net/systemeD/halcyon/MapPaint.as
net/systemeD/halcyon/connection/actions/RemoveNodeByIndexAction.as
net/systemeD/potlatch2/EditController.as
net/systemeD/potlatch2/controller/ControllerState.as
net/systemeD/potlatch2/controller/SelectArea.as
net/systemeD/potlatch2/controller/SelectedBackgroundNode.as [deleted file]
net/systemeD/potlatch2/controller/SelectedBackgroundWay.as [deleted file]
net/systemeD/potlatch2/controller/SelectedMultiple.as
net/systemeD/potlatch2/controller/SelectedPOINode.as
net/systemeD/potlatch2/controller/SelectedWay.as
net/systemeD/potlatch2/controller/SelectedWayNode.as

index 1377d44..8a45b07 100644 (file)
@@ -291,6 +291,14 @@ package net.systemeD.halcyon {
                        return editableLayer;
                }
 
+               /** Find which paint object an entity will be displayed on. */
+               public function getLayerForEntity(entity:Entity):MapPaint {
+                       for (var i:uint=0; i<paintContainer.numChildren; i++) {
+                               if (getLayerAt(i).sameConnection(entity)) return getLayerAt(i);
+                       }
+                       return null;
+               }
+
                // ------------------------------------------------------------------------------------------
                // Redraw all items, zoom in and out
                
index c1fb5a6..a340f60 100644 (file)
@@ -363,6 +363,11 @@ package net.systemeD.halcyon {
                        ruleset.loadFromCSS(url);
         }
 
+               /** Does an entity belong to this layer? */
+               public function sameConnection(entity:Entity):Boolean {
+                       return entity.connection==this.connection;
+               }
+
                // ==================== Start of code moved from Map.as
 
                // Listeners for Connection events
index 7021379..9f2303d 100644 (file)
@@ -23,7 +23,7 @@ package net.systemeD.halcyon.connection.actions {
                        var node:Node=nodeList[index];
                        removed=[];
 
-                       while (nodeList[index]==node || nodeList[index]==preceding) {
+                       while (nodeList[index]==node || (nodeList[index]==preceding && preceding!=null)) {
                                var removedNode:Node=nodeList.splice(index, 1)[0];
                                removed.push(removedNode);
                                if (nodeList.indexOf(removedNode)==-1) { removedNode.removeParent(way); }
index 492077c..6afad6e 100644 (file)
@@ -163,13 +163,15 @@ package net.systemeD.potlatch2 {
                /** Given what is currently selected (or not), find the matching ControllerState. */
                public function findStateForSelection(sel:Array):ControllerState {
                        if (sel.length==0) { return new NoSelection(); }
-                       else if (sel.length>1) { return new SelectedMultiple(sel); }
-                       else if (sel[0] is Way) { return new SelectedWay(sel[0]); }
+                       var layer:MapPaint=_map.getLayerForEntity(sel[0]);
+                       
+                       if (sel.length>1) { return new SelectedMultiple(sel, layer); }
+                       else if (sel[0] is Way) { return new SelectedWay(sel[0], layer); }
                        else if (sel[0] is Node && Node(sel[0]).hasParentWays) {
                                var way:Way=sel[0].parentWays[0] as Way;
                                return new SelectedWayNode(way, way.indexOfNode(sel[0] as Node));
                        } else {
-                               return new SelectedPOINode(sel[0] as Node);
+                               return new SelectedPOINode(sel[0] as Node, layer);
                        }
                }
 
index 3c02e1b..416216d 100644 (file)
@@ -108,20 +108,23 @@ package net.systemeD.potlatch2.controller {
                        if ( paint && paint.isBackground ) {
                                if (event.type == MouseEvent.MOUSE_DOWN && ((event.shiftKey && event.ctrlKey) || event.altKey) ) {
                                        // alt-click to pull data out of vector background layer
-                                       paint.setHighlight(entity, { hover:false, selected: false });
-                                       if (entity is Way) paint.setHighlightOnNodes(Way(entity), { selectedway: false });
-                                       var newEntity:Entity=paint.pullThrough(entity,controller.map.editableLayer);
-                                       if      (entity is Way ) { return new SelectedWay(newEntity as Way); }
-                                       else if (entity is Node) { return new SelectedPOINode(newEntity as Node); }
+                                       var newSelection:Array=[];
+                                       if (selection.indexOf(entity)==-1) { selection=[entity]; }
+                                       for each (var entity:Entity in selection) {
+                                               paint.setHighlight(entity, { hover:false, selected: false });
+                                               if (entity is Way) paint.setHighlightOnNodes(Way(entity), { selectedway: false });
+                                               newSelection.push(paint.pullThrough(entity,controller.map.editableLayer));
+                                       }
+                                       return controller.findStateForSelection(newSelection);
                                } else if (!paint.interactive) {
                                        return null;
                                } else if (event.type == MouseEvent.MOUSE_DOWN && paint.interactive) {
-                                       if      (entity is Way   ) { return new SelectedBackgroundWay(entity as Way, paint); }
-                                       else if (entity is Node  ) { return new SelectedBackgroundNode(entity as Node, paint); }
+                                       if      (entity is Way   ) { return new SelectedWay(entity as Way, paint); }
+                                       else if (entity is Node  ) { if (!entity.hasParentWays) return new SelectedPOINode(entity as Node, paint); }
                                        else if (entity is Marker) { return new SelectedMarker(entity as Marker, paint); }
-                               } else if ( event.type == MouseEvent.MOUSE_UP) {
+                               } else if ( event.type == MouseEvent.MOUSE_UP && !event.ctrlKey) {
                                        return (this is NoSelection) ? null : new NoSelection();
-                               } else if ( event.type == MouseEvent.CLICK && focus == null && map.dragstate!=map.DRAGGING) {
+                               } else if ( event.type == MouseEvent.CLICK && focus == null && map.dragstate!=map.DRAGGING && !event.ctrlKey) {
                                        return (this is NoSelection) ? null : new NoSelection();
                                }
                                        
@@ -139,11 +142,11 @@ package net.systemeD.potlatch2.controller {
                                        return new DragSelection(selection, event);
                                } else if (entity) {
                                        return new DragSelection([entity], event);
-                               } else if (event.ctrlKey) {
-                                       return new SelectArea(event.localX,event.localY);
+                               } else if (event.ctrlKey && !layer.isBackground) {
+                                       return new SelectArea(event.localX,event.localY,selection);
                                }
 
-            } else if ( (event.type==MouseEvent.CLICK || event.type==MouseEvent.MOUSE_UP) && focus == null && map.dragstate!=map.DRAGGING) {
+            } else if ( (event.type==MouseEvent.CLICK || event.type==MouseEvent.MOUSE_UP) && focus == null && map.dragstate!=map.DRAGGING && !event.ctrlKey) {
                 return (this is NoSelection) ? null : new NoSelection();
             }
                        return null;
index 1a0ad60..b00b944 100644 (file)
@@ -12,8 +12,11 @@ package net.systemeD.potlatch2.controller {
                private var endY:Number;
                private var box:Shape;
                private const TOLERANCE:uint=4;
+               private var originalSelection:Array;
 
-               public function SelectArea(x:Number,y:Number) {
+               public function SelectArea(x:Number,y:Number,sel:Array) {
+                       selection = sel.concat();
+                       originalSelection = sel.concat();
                        startX=endX=x;
                        startY=endY=y;
                }
@@ -29,7 +32,7 @@ package net.systemeD.potlatch2.controller {
                                var a:Number;
                                if (startX>endX) { a=startX; startX=endX; endX=a; }
                                if (startY>endY) { a=startY; startY=endY; endY=a; }
-                               if (endX-startX<TOLERANCE && endY-startY<TOLERANCE) { return new NoSelection(); }
+                               if (endX-startX<TOLERANCE && endY-startY<TOLERANCE) { return controller.findStateForSelection(originalSelection); }
                                var left:Number=controller.map.coord2lon(startX);
                                var right:Number=controller.map.coord2lon(endX);
                                var top:Number=controller.map.coord2lat(startY);
@@ -50,6 +53,9 @@ package net.systemeD.potlatch2.controller {
                }
                
                override public function enterState():void {
+                       for each (var entity:Entity in selection) {
+                               layer.setHighlight(entity, { selected: true });
+                       }
                        box=new Shape();
                        var l:DisplayObject=layer.getPaintSpriteAt(layer.maxlayer);
                        var o:DisplayObject=Sprite(l).getChildAt(3);
@@ -57,6 +63,9 @@ package net.systemeD.potlatch2.controller {
                        controller.map.draggable=false;
                }
                override public function exitState(newState:ControllerState):void {
+                       for each (var entity:Entity in originalSelection) {
+                               layer.setHighlight(entity, { selected: false });
+                       }
                        box.parent.removeChild(box);
                        controller.map.draggable=true;
                        if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
diff --git a/net/systemeD/potlatch2/controller/SelectedBackgroundNode.as b/net/systemeD/potlatch2/controller/SelectedBackgroundNode.as
deleted file mode 100644 (file)
index 33ab41c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-package net.systemeD.potlatch2.controller {
-       import flash.events.*;
-       import flash.ui.Keyboard;
-    import net.systemeD.potlatch2.EditController;
-    import net.systemeD.halcyon.connection.*;
-    import net.systemeD.halcyon.MapPaint;
-
-    public class SelectedBackgroundNode extends ControllerState {
-        protected var initNode:Node;
-
-        public function SelectedBackgroundNode(node:Node, layer:MapPaint) {
-            initNode = node;
-            this.layer = layer;
-        }
-
-        protected function selectNode(node:Node):void {
-            if ( firstSelected is Node && Node(firstSelected)==node )
-                return;
-
-            clearSelection(this);
-            layer.setHighlight(node, { selected: true });
-            selection = [node];
-            controller.updateSelectionUI(layer);
-            initNode = node;
-        }
-
-        protected function clearSelection(newState:ControllerState):void {
-            if ( selectCount ) {
-                layer.setHighlight(firstSelected, { selected: false });
-                selection = [];
-                if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
-            }
-        }
-
-        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
-                       if (event.type==MouseEvent.MOUSE_MOVE) { return this; }
-            if (event.type==MouseEvent.MOUSE_UP) { return this; }
-                       var cs:ControllerState = sharedMouseEvents(event, entity);
-                       return cs ? cs : this;
-        }
-
-               override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
-                       switch (event.keyCode) {
-                       }
-                       var cs:ControllerState = sharedKeyboardEvents(event);
-                       return cs ? cs : this;
-               }
-
-               public function deletePOI():ControllerState {
-                       return new NoSelection();
-               }
-
-        override public function enterState():void {
-            selectNode(initNode);
-                       layer.setPurgable(selection,false);
-        }
-
-        override public function exitState(newState:ControllerState):void {
-                       layer.setPurgable(selection,true);
-            clearSelection(newState);
-        }
-
-        override public function toString():String {
-            return "SelectedBackgroundNode";
-        }
-
-    }
-}
diff --git a/net/systemeD/potlatch2/controller/SelectedBackgroundWay.as b/net/systemeD/potlatch2/controller/SelectedBackgroundWay.as
deleted file mode 100644 (file)
index 6ce097f..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-package net.systemeD.potlatch2.controller {
-       import flash.events.*;
-       import flash.geom.Point;
-       import flash.ui.Keyboard;
-       
-       import net.systemeD.halcyon.WayUI;
-       import net.systemeD.halcyon.connection.*;
-    import net.systemeD.halcyon.MapPaint;
-
-    /** Behaviour that takes place while a way is selected includes: adding a node to the way, straightening/reshaping the way, dragging it. */
-    public class SelectedBackgroundWay extends ControllerState {
-        /** The selected way itself. */
-        protected var initWay:Way;
-        private var clicked:Point;             // did the user enter this state by clicking at a particular point?
-               private var wayList:Array;              // list of ways to cycle through with '/' keypress
-               private var initIndex: int;     // index of last selected node if entered from SelectedWayNode
-        
-        /** 
-        * @param way The way that is now selected.
-        * @param point The location that was clicked.
-        * @param ways An ordered list of ways sharing a node, to make "way cycling" work. */
-        public function SelectedBackgroundWay(way:Way, layer:MapPaint, point:Point=null, ways:Array=null, index:int=0) {
-            initWay = way;
-                       clicked = point;
-                       wayList = ways;
-                       initIndex=index;
-                       this.layer = layer;
-        }
-
-        private function updateSelectionUI(e:Event):void {
-            controller.updateSelectionUIWithoutTagChange();
-        }
-
-        /** Tidy up UI as we transition to a new state without the current selection. */
-        protected function clearSelection(newState:ControllerState):void {
-            if ( selectCount ) {
-               layer.setHighlight(firstSelected, { selected: false, hover: false });
-               layer.setHighlightOnNodes(firstSelected as Way, { selectedway: false });
-                selection = [];
-                if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
-            }
-        }
-        
-        /** The only things we want to do here are deselect and stay selected */
-        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
-            if (event.type==MouseEvent.MOUSE_MOVE) { return this; }
-            if (event.type==MouseEvent.MOUSE_UP) { return this; }
-            var cs:ControllerState = sharedMouseEvents(event, entity);
-            return cs ? cs : this;
-        }
-        
-               /** TODO - key press for "completing" a way */
-               override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
-                       switch (event.keyCode) {
-
-
-            }
-                       var cs:ControllerState = sharedKeyboardEvents(event);
-                       return cs ? cs : this;
-               }
-
-        /** Officially enter this state by marking the previously nominated way as selected. */
-        override public function enterState():void {
-            if (firstSelected!=initWay) {
-                clearSelection(this);
-                layer.setHighlight(initWay, { selected: true, hover: false });
-                   layer.setHighlightOnNodes(initWay, { selectedway: true });
-                   selection = [initWay];
-                   controller.updateSelectionUI();
-                       }
-                       layer.setPurgable(selection,false);
-        }
-        
-        /** Officially leave the state */
-        override public function exitState(newState:ControllerState):void {
-            layer.setPurgable(selection,true);
-            clearSelection(newState);
-        }
-
-        /** @return "SelectedWay" */
-        override public function toString():String {
-            return "SelectedBackgroundWay";
-        }
-
-    }
-}
index 3b0a012..1b34c2b 100644 (file)
@@ -4,12 +4,13 @@ package net.systemeD.potlatch2.controller {
        import net.systemeD.halcyon.AttentionEvent;
        import net.systemeD.halcyon.connection.*;
        import net.systemeD.halcyon.connection.actions.MergeWaysAction;
-    
+    import net.systemeD.halcyon.MapPaint;
 
        public class SelectedMultiple extends ControllerState {
                protected var initSelection:Array;
                
-               public function SelectedMultiple(sel:Array) {
+               public function SelectedMultiple(sel:Array, layer:MapPaint=null) {
+                       if (layer) this.layer=layer;
                        initSelection=sel.concat();
                }
 
@@ -24,6 +25,9 @@ package net.systemeD.potlatch2.controller {
 
                                if (selectCount>1) { return this; }
                                return controller.findStateForSelection(selection);
+
+                       } else if ( event.type == MouseEvent.MOUSE_UP && selection.indexOf(focus)>-1 ) {
+                               return this;
                        }
                        var cs:ControllerState = sharedMouseEvents(event, entity);
                        return cs ? cs : this;
index 2e6af17..b327950 100644 (file)
@@ -1,13 +1,16 @@
 package net.systemeD.potlatch2.controller {
        import flash.events.*;
+       import flash.display.*;
        import flash.ui.Keyboard;
     import net.systemeD.potlatch2.EditController;
     import net.systemeD.halcyon.connection.*;
+    import net.systemeD.halcyon.MapPaint;
 
     public class SelectedPOINode extends ControllerState {
         protected var initNode:Node;
 
-        public function SelectedPOINode(node:Node) {
+        public function SelectedPOINode(node:Node, layer:MapPaint=null) {
+                       if (layer) this.layer=layer;
             initNode = node;
         }
  
@@ -32,11 +35,14 @@ package net.systemeD.potlatch2.controller {
         
         override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
                        if (event.type==MouseEvent.MOUSE_MOVE) { return this; }
-                       if (event.type==MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected) {
-                               return new SelectedMultiple([firstSelected,entity]);
-                       }
-                       if (event.type==MouseEvent.MOUSE_DOWN && event.shiftKey && !entity) {
+                       var paint:MapPaint = getMapPaint(DisplayObject(event.target));
+
+                       if (event.type==MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected && paint==layer) {
+                               return new SelectedMultiple([firstSelected,entity],layer);
+                       } else if (event.type==MouseEvent.MOUSE_DOWN && event.shiftKey && !entity && !layer.isBackground) {
                                return new DrawQuadrilateral(firstSelected as Node);
+                       } else if ( event.type == MouseEvent.MOUSE_UP && entity==firstSelected ) {
+                               return this;
                        }
                        var cs:ControllerState = sharedMouseEvents(event, entity);
                        return cs ? cs : this;
index fd978be..192e241 100644 (file)
@@ -1,8 +1,10 @@
 package net.systemeD.potlatch2.controller {
+       import flash.display.*;
        import flash.events.*;
        import flash.geom.Point;
        import flash.ui.Keyboard;
        
+       import net.systemeD.halcyon.MapPaint;
        import net.systemeD.halcyon.connection.*;
        import net.systemeD.potlatch2.tools.Quadrilateralise;
        import net.systemeD.potlatch2.tools.Simplify;
@@ -19,7 +21,8 @@ package net.systemeD.potlatch2.controller {
         * @param way The way that is now selected.
         * @param point The location that was clicked.
         * @param ways An ordered list of ways sharing a node, to make "way cycling" work. */
-        public function SelectedWay(way:Way, point:Point=null, ways:Array=null, index:int=0) {
+        public function SelectedWay(way:Way, layer:MapPaint=null, point:Point=null, ways:Array=null, index:int=0) {
+                       if (layer) this.layer=layer;
             initWay = way;
                        clicked = point;
                        wayList = ways;
@@ -43,20 +46,23 @@ package net.systemeD.potlatch2.controller {
         /** Behaviour includes: start drawing a new way, insert a node within this way, select an additional way */
         override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
                        if (event.type==MouseEvent.MOUSE_MOVE || event.type==MouseEvent.ROLL_OVER || event.type==MouseEvent.MOUSE_OUT) { return this; }
+                       var paint:MapPaint = getMapPaint(DisplayObject(event.target));
             var focus:Entity = getTopLevelFocusEntity(entity);
 
-            if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey ) {
+            if ( event.type == MouseEvent.MOUSE_UP && entity is Node && event.shiftKey && !layer.isBackground ) {
                                // start new way
                                var way:Way = entity.connection.createWay({}, [entity], MainUndoStack.getGlobalStack().addAction);
                                return new DrawWay(way, true, false);
-                       } else if ( event.type == MouseEvent.MOUSE_DOWN && entity is Way && focus==firstSelected && event.shiftKey) {
+                       } else if ( event.type == MouseEvent.MOUSE_DOWN && entity is Way && focus==firstSelected && event.shiftKey && !layer.isBackground ) {
                                // insert node within way (shift-click)
                 var d:DragWayNode=new DragWayNode(firstSelected as Way, -1, event, true);
                                d.forceDragStart();
                                return d;
-                       } else if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected) {
+                       } else if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey && entity && entity!=firstSelected && paint==layer) {
                                // multiple selection
-                               return new SelectedMultiple([firstSelected,entity]);
+                               return new SelectedMultiple([firstSelected,entity],layer);
+                       } else if ( event.type == MouseEvent.MOUSE_UP && focus==firstSelected ) {
+                               return this;
                        }
                        var cs:ControllerState = sharedMouseEvents(event, entity);
                        return cs ? cs : this;
@@ -65,17 +71,20 @@ package net.systemeD.potlatch2.controller {
                /** Behaviour includes: parallel way, repeat tags, reverse direction, simplify, cycle way selection, delete */
                override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
                        switch (event.keyCode) {
-                               case 80:  /* P */           return new SelectedParallelWay(firstSelected as Way); 
-                               case 81:  /* Q */           Quadrilateralise.quadrilateralise(firstSelected as Way, MainUndoStack.getGlobalStack().addAction); return this;
                                case 82:  /* R */           repeatTags(firstSelected); return this;
-                case 86:  /* V */           Way(firstSelected).reverseNodes(MainUndoStack.getGlobalStack().addAction); return this;
-                case 89:  /* Y */           Simplify.simplify(firstSelected as Way, controller.map, true); return this;
                                case 191: /* / */           return cycleWays();
                                case Keyboard.BACKSPACE:        
                                case Keyboard.DELETE:           if (event.shiftKey) { return deleteWay(); } break;
-                case 188: /* , */           return new SelectedWayNode(initWay, initIndex); // allows navigating from one way to another by keyboard
-                case 190: /* . */           return new SelectedWayNode(initWay, initIndex); //  using <, > and /           
-
+                       }
+                       if (!layer.isBackground) {
+                               switch (event.keyCode) {
+                                       case 80:  /* P */       return new SelectedParallelWay(firstSelected as Way); 
+                                       case 81:  /* Q */       Quadrilateralise.quadrilateralise(firstSelected as Way, MainUndoStack.getGlobalStack().addAction); return this;
+                                       case 86:  /* V */       Way(firstSelected).reverseNodes(MainUndoStack.getGlobalStack().addAction); return this;
+                                       case 89:  /* Y */       Simplify.simplify(firstSelected as Way, controller.map, true); return this;
+                                       case 188: /* , */       return new SelectedWayNode(initWay, initIndex); // allows navigating from one way to another by keyboard
+                                       case 190: /* . */       return new SelectedWayNode(initWay, initIndex); //  using <, > and /           
+                               }
                        }
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
@@ -90,7 +99,7 @@ package net.systemeD.potlatch2.controller {
                        wayList=wayList.slice(1).concat(wayList[0]);
                        // Find the new way's index of the currently "selected" node, to facilitate keyboard navigation
                        var newindex:int = Way(wayList[0]).indexOfNode(initWay.getNode(initIndex));
-                       return new SelectedWay(wayList[0], clicked, wayList, newindex);
+                       return new SelectedWay(wayList[0], layer, clicked, wayList, newindex);
                }
 
                /** Perform deletion of currently selected way. */
index 03ba21c..86766c2 100644 (file)
@@ -97,7 +97,7 @@ package net.systemeD.potlatch2.controller {
                        wayList.splice(wayList.indexOf(parentWay),1);
             // find index of this node in the newly selected way, to maintain state for keyboard navigation
             var newindex:int = Way(wayList[0]).indexOfNode(parentWay.getNode(initIndex));
-                       return new SelectedWay(wayList[0],
+                       return new SelectedWay(wayList[0], layer,
                                               new Point(controller.map.lon2coord(Node(firstSelected).lon),
                                                         controller.map.latp2coord(Node(firstSelected).latp)),
                                               wayList.concat(parentWay),