move way merge to a toolbox function rather than shift-click
authorRichard Fairhurst <richard@systemed.net>
Sun, 14 Nov 2010 19:52:51 +0000 (19:52 +0000)
committerRichard Fairhurst <richard@systemed.net>
Sun, 14 Nov 2010 19:52:51 +0000 (19:52 +0000)
embedded/merge.svg [new file with mode: 0644]
net/systemeD/potlatch2/EditController.as
net/systemeD/potlatch2/Toolbox.mxml
net/systemeD/potlatch2/controller/ControllerState.as
net/systemeD/potlatch2/controller/SelectedMultiple.as
net/systemeD/potlatch2/controller/SelectedWay.as

diff --git a/embedded/merge.svg b/embedded/merge.svg
new file mode 100644 (file)
index 0000000..d4f600a
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 11 Build 196, SVG Export Plug-In . SVG Version: 6.0.0 Build 78)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"    "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [
+       <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+       <!ENTITY ns_svg "http://www.w3.org/2000/svg">
+       <!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
+]>
+<svg  xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+        width="22.047" height="22.046" viewBox="0 0 22.047 22.046" overflow="visible" enable-background="new 0 0 22.047 22.046"
+        xml:space="preserve">
+               <g id="Layer_1">
+                       <path fill="#FFFFFF" stroke="#000000" stroke-width="1.5" d="M10.26,11.787c1.106,1.105,1.108,2.902,0,4.01l-3.373,3.373
+                               c-1.108,1.105-2.901,1.105-4.01,0l0,0c-1.106-1.109-1.106-2.902,0-4.01l3.373-3.373C7.358,10.68,9.153,10.68,10.26,11.787
+                               L10.26,11.787z"/>
+                       <path fill="#FFFFFF" stroke="#000000" stroke-width="1.5" d="M19.17,2.877c1.107,1.107,1.107,2.902,0.001,4.01l-3.375,3.373
+                               c-1.106,1.107-2.901,1.107-4.008,0l0,0c-1.108-1.107-1.108-2.902,0-4.01l3.372-3.373C16.268,1.77,18.062,1.77,19.17,2.877
+                               L19.17,2.877z"/>
+                       <line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" x1="8.383" y1="13.664" x2="13.665" y2="8.382"/>
+                       <line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" x1="1" y1="21.046" x2="6.282" y2="15.763"/>
+                       <line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" x1="15.766" y1="6.282" x2="21.047" y2="1"/>
+                       <line fill="none" stroke="#000000" stroke-width="1.5" stroke-linecap="round" x1="8.383" y1="13.664" x2="13.665" y2="8.382"/>
+                       <line fill="none" stroke="#000000" stroke-width="1.5" stroke-linecap="round" x1="1" y1="21.046" x2="6.282" y2="15.763"/>
+                       <line fill="none" stroke="#000000" stroke-width="1.5" stroke-linecap="round" x1="15.766" y1="6.282" x2="21.047" y2="1"/>
+               </g>
+       </svg>
index e799046..8315749 100644 (file)
@@ -115,6 +115,18 @@ package net.systemeD.potlatch2 {
             state.enterState();
         }
 
+               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]); }
+                       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);
+                       }
+               }
+
                public function setCursor(cursor:Class):void {
                        CursorManager.removeAllCursors();
                        if (cursor && cursorsEnabled) { CursorManager.setCursor(cursor,2,-4,0); }
index eb8ab09..e8315f8 100644 (file)
@@ -2,14 +2,16 @@
 <mx:Panel
        xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:potlatch2="net.systemeD.potlatch2.*"
-       height="46" width="219" 
+       height="76" width="129" 
        headerHeight="6" headerColors="[black, gray]" 
        borderThicknessRight="0" borderThicknessLeft="0" borderThicknessBottom="0" 
        paddingLeft="4" paddingTop="4" layout="absolute" >
 
                <mx:Image data="@Embed('../../../embedded/close_small.png')"
                        includeInLayout="false" id="toolboxClose" click="toggle();" 
-                       y="-6" x="205" />
+                       y="-6" x="115" />
+
+               <!-- Top row -->
 
                <mx:Button icon="@Embed('../../../embedded/delete.svg')"
                        click='doDelete();' 
                        toolTip="Reverse direction (V)" 
                        width="28" height="28" textAlign="left" y="4" x="36" paddingLeft="8" paddingRight="0" />
                <mx:Button icon="@Embed('../../../embedded/cut.svg')" 
-                          click='doSplit();'
+                       click='doSplit();'
                        enabled="{canDo('split')}" 
                        alpha="{getAlpha('split')}" 
                        toolTip="Split way (X)" 
                        width="28" height="28" textAlign="left" y="4" x="66" paddingLeft="8" paddingRight="0" />
+               <mx:Button icon="@Embed('../../../embedded/merge.svg')" 
+                       click='doMerge();'
+                       enabled="{canDo('merge')}" 
+                       alpha="{getAlpha('merge')}" 
+                       toolTip="Merge ways" 
+                       width="28" height="28" textAlign="left" y="4" x="96" paddingLeft="3" paddingRight="0" />
+
+               <!-- Second row -->
+
                <mx:Button icon="@Embed('../../../embedded/straighten.svg')" 
                        click='doStraighten();' 
                        enabled="{canDo('straighten')}" 
                        alpha="{getAlpha('straighten')}" 
                        toolTip="Straighten way" 
-                       width="28" height="28" textAlign="left" y="4" x="96" paddingLeft="5" paddingRight="0" />
+                       width="28" height="28" textAlign="left" y="34" x="6" paddingLeft="5" paddingRight="0" />
                <mx:Button icon="@Embed('../../../embedded/circle.svg')" 
                        click='doCircularise();' 
                        enabled="{canDo('circularise')}" 
                        alpha="{getAlpha('circularise')}" 
                        toolTip="Make circular" 
-                       width="28" height="28" textAlign="left" y="4" x="126" paddingLeft="4" paddingRight="0" />
+                       width="28" height="28" textAlign="left" y="34" x="36" paddingLeft="4" paddingRight="0" />
                <mx:Button icon="@Embed('../../../embedded/quadrilateralise.svg')" 
                        click='doQuadrilateralise();' 
                        enabled="{canDo('quadrilateralise')}" 
                        alpha="{getAlpha('quadrilateralise')}" 
                        toolTip="Make right-angled" 
-                       width="28" height="28" textAlign="left" y="4" x="156" paddingLeft="6" paddingRight="0" />
+                       width="28" height="28" textAlign="left" y="34" x="66" paddingLeft="6" paddingRight="0" />
                <mx:Button icon="@Embed('../../../embedded/parallel.svg')" 
                        click='doParallelise();' 
                        enabled="{canDo('parallelise')}" 
                        alpha="{getAlpha('parallelise')}" 
                        toolTip="Create parallel way (P)" 
-                       width="28" height="28" textAlign="left" y="4" x="186" paddingLeft="8" paddingRight="0" />
+                       width="28" height="28" textAlign="left" y="34" x="96" paddingLeft="8" paddingRight="0" />
 
        <mx:Script><![CDATA[
 
                import flash.events.Event;
                import flash.events.MouseEvent;
                import net.systemeD.halcyon.connection.*;
+               import net.systemeD.halcyon.connection.actions.*;
                import net.systemeD.potlatch2.controller.*;
                import net.systemeD.potlatch2.tools.*;
 
                                case 'circularise':                     return controller.state.hasSelectedAreas();
                                case 'split':                           return (controller.state is SelectedWayNode);
                                case 'parallelise':                     return (controller.state is SelectedWay);
+                               case 'merge':                           return controller.state.hasAdjoiningWays();
                        }
                        return false;
                }
                                controller.setState(new NoSelection());
                        }
                }
+               
+               public function doMerge():void {
+                       var changed:Boolean;
+                       var waylist:Array=controller.state.selectedWays;
+                       do {
+                               // ** FIXME - we should have one CompositeUndoableAction for the whole caboodle,
+                               // but that screws up the execution order and can make the merge not work
+                               var undo:CompositeUndoableAction = new CompositeUndoableAction("Merge ways");
+                               changed=tryMerge(waylist, undo);
+                               MainUndoStack.getGlobalStack().addAction(undo);
+                       } while (changed==true);
+                       controller.setState(controller.findStateForSelection(waylist));
+               }
+               
+               private function tryMerge(waylist:Array, undo:CompositeUndoableAction):Boolean {
+                       var way1:Way, way2:Way, del:uint;
+                       for (var i:uint=0; i<waylist.length; i++) {
+                               for (var j:uint=0; j<waylist.length; j++) {
+                                       if (waylist[i]!=waylist[j]) {
+
+                                               // Preserve positive IDs if we can
+                                               if (waylist[i].id < waylist[j].id && waylist[i].id >= 0) {
+                                                       way1=waylist[i]; way2=waylist[j]; del=j;
+                                               } else {
+                                                       way1=waylist[j]; way2=waylist[i]; del=i;
+                                               }
+
+                                               // Merge as appropriate
+                                               if (way1.getNode(0)==way2.getNode(0)) {
+                                                       waylist.splice(del,1);
+                                                       undo.push(new MergeWaysAction(way1,way2,0,0));
+                                                       return true;
+                                               } else if (way1.getNode(0)==way2.getLastNode()) { 
+                                                       waylist.splice(del,1);
+                                                       undo.push(new MergeWaysAction(way1,way2,0,way2.length-1));
+                                                       return true;
+                                               } else if (way1.getLastNode()==way2.getNode(0)) {
+                                                       waylist.splice(del,1);
+                                                       undo.push(new MergeWaysAction(way1,way2,way1.length-1,0));
+                                                       return true;
+                                               } else if (way1.getLastNode()==way2.getLastNode()) { 
+                                                       waylist.splice(del,1);
+                                                       undo.push(new MergeWaysAction(way1,way2,way1.length-1,way2.length-1));
+                                                       return true;
+                                               }
+                                       }
+                               }
+                       }
+                       return false;
+               }
 
                public function doReverseDirection():void {
                        var undo:CompositeUndoableAction = new CompositeUndoableAction("Reverse direction of objects");
index f40ecb1..d188544 100644 (file)
@@ -208,6 +208,20 @@ package net.systemeD.potlatch2.controller {
                        }
                        return false;
                }
+               
+               public function hasAdjoiningWays():Boolean {
+                       if (_selection.length<2) { return false; }
+                       var endNodes:Object={};
+                       for each (var item:Entity in _selection) {
+                               if (item is Way && !Way(item).isArea()) {
+                                       if (endNodes[Way(item).getNode(0).id]) return true;
+                                       if (endNodes[Way(item).getLastNode().id]) return true;
+                                       endNodes[Way(item).getNode(0).id]=true;
+                                       endNodes[Way(item).getLastNode().id]=true;
+                               }
+                       }
+                       return false;
+               }
                        
                // Selection setters
                
index 45cd47b..ea3db7c 100644 (file)
@@ -22,20 +22,10 @@ package net.systemeD.potlatch2.controller {
                        if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey ) {
                                // modify selection
                                controller.map.setHighlight(entity, { selected: toggleSelection(entity) });
+                               controller.updateSelectionUI();
 
-                               if      (selectCount> 1) { return this; }
-                               else if (selectCount==1) {
-                                       if (firstSelected is Way) {
-                                               return new SelectedWay(firstSelected as Way);
-                                       } else if (firstSelected is Node && Node(firstSelected).hasParentWays) {
-                                               var way:Way=firstSelected.parentWays[0] as Way;
-                                               return new SelectedWayNode(way, way.indexOfNode(firstSelected as Node));
-                                       } else {
-                                               return new SelectedPOINode(firstSelected as Node);
-                                       }
-                               } else {
-                                       return new NoSelection();
-                               }
+                               if (selectCount>1) { return this; }
+                               return controller.findStateForSelection(selection);
                        }
                        var cs:ControllerState = sharedMouseEvents(event, entity);
                        return cs ? cs : this;
index b753843..5c4b9bd 100644 (file)
@@ -51,9 +51,6 @@ package net.systemeD.potlatch2.controller {
                 var d:DragWayNode=new DragWayNode(firstSelected as Way, -1, event, true);
                                d.forceDragStart();
                                return d;
-                       } else if ( event.type == MouseEvent.MOUSE_DOWN && entity is Way && event.shiftKey ) {
-                               // merge way
-                               return mergeWith(entity as Way);
                        } else if ( event.type == MouseEvent.MOUSE_DOWN && event.ctrlKey && entity!=firstSelected) {
                                // multiple selection
                                return new SelectedMultiple([firstSelected,entity]);
@@ -74,28 +71,6 @@ package net.systemeD.potlatch2.controller {
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
                }
-
-               protected function mergeWith(otherWay:Way):ControllerState {
-                       var way1:Way;
-                       var way2:Way;
-                       if ( firstSelected.id < otherWay.id && firstSelected.id >= 0 ) {
-                           way1 = firstSelected as Way;
-                           way2 = otherWay;
-                       } else {
-                           way1 = otherWay;
-                           way2 = firstSelected as Way;
-                       }
-                       
-                       var undo:Function = MainUndoStack.getGlobalStack().addAction;
-                       
-                       // find common point
-                       if (way1 == way2) { return this; }
-                       if      (way1.getNode(0)   ==way2.getNode(0)   ) { way1.mergeWith(way2,0,0,undo); }
-                       else if (way1.getNode(0)   ==way2.getLastNode()) { way1.mergeWith(way2,0,way2.length-1,undo); }
-                       else if (way1.getLastNode()==way2.getNode(0)   ) { way1.mergeWith(way2,way1.length-1,0,undo); }
-                       else if (way1.getLastNode()==way2.getLastNode()) { way1.mergeWith(way2,way1.length-1,way2.length-1,undo); }
-                       return new SelectedWay(way1);
-               }
         
                public function deleteWay():ControllerState {
                        controller.map.setHighlightOnNodes(firstSelected as Way, {selectedway: false});