make it look purty
[potlatch2.git] / net / systemeD / potlatch2 / Toolbox.mxml
index 3e3850e..6007b5f 100644 (file)
@@ -2,75 +2,84 @@
 <mx:Panel
        xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:potlatch2="net.systemeD.potlatch2.*"
-       height="46" width="219" 
-       headerHeight="6" headerColors="[black, gray]" 
-       borderThicknessRight="0" borderThicknessLeft="0" borderThicknessBottom="0" 
-       paddingLeft="4" paddingTop="4" layout="absolute" >
+       height="76" width="129" layout="absolute"
+       styleName="theToolBox">
 
                <mx:Image data="@Embed('../../../embedded/close_small.png')"
-                   includeInLayout="false" id="toolboxClose" click="toggle();" 
-                   y="-6" x="205" />
+                       includeInLayout="false" id="toolboxClose" click="toggle();" 
+                       y="-6" x="115" />
 
-        <mx:Button icon="@Embed('../../../embedded/delete.svg')"
+               <!-- Top row -->
+
+               <mx:Button icon="@Embed('../../../embedded/delete.svg')"
                        click='doDelete();' 
                        enabled="{canDo('delete')}" 
                        alpha="{getAlpha('delete')}" 
                        toolTip="{deleteToolTipText()}" 
                        width="28" height="28" textAlign="left" y="4" x="6" paddingLeft="6" paddingRight="0" />
-        <mx:Button icon="@Embed('../../../embedded/direction.svg')" 
-            click='doReverseDirection();'
+               <mx:Button icon="@Embed('../../../embedded/direction.svg')" 
+                       click='doReverseDirection();'
                        enabled="{canDo('reverseDirection')}" 
                        alpha="{getAlpha('reverseDirection')}" 
                        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();'
+               <mx:Button icon="@Embed('../../../embedded/cut.svg')" 
+                       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/straighten.svg')" 
+               <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" />
-        <mx:Button icon="@Embed('../../../embedded/circle.svg')" 
+                       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" />
-        <mx:Button icon="@Embed('../../../embedded/quadrilateralise.svg')" 
+                       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" />
-        <mx:Button icon="@Embed('../../../embedded/parallel.svg')" 
+                       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.potlatch2.controller.*;
-           import net.systemeD.potlatch2.tools.*;
+               import net.systemeD.halcyon.connection.actions.*;
+               import net.systemeD.potlatch2.controller.*;
+               import net.systemeD.potlatch2.tools.*;
 
-               private var entity:Entity;
                private var controller:EditController;
 
                public function init(controller:EditController):void {
                        this.controller=controller;
-            /* check if the toolbox was explictly turned off in a previous session */
-            if( SharedObject.getLocal("user_state").data['toolbox_visible'] == false) {
-              this.visible = false;
-            }
+                       /* check if the toolbox was explictly turned off in a previous session */
+                       if( SharedObject.getLocal("user_state").data['toolbox_visible'] == false) {
+                         this.visible = false;
+                       }
                }
 
                override protected function createChildren():void {
@@ -79,8 +88,7 @@
                        super.titleBar.addEventListener(MouseEvent.MOUSE_UP,handleUp);
                }
 
-               public function setEntity(entity:Entity):void {
-                       this.entity=entity;
+               public function updateSelectionUI():void {
                        dispatchEvent(new Event("updateSkin"));
                        dispatchEvent(new Event("updateAlpha"));
                }
                
                public function toggle():void {
                        this.visible=!this.visible;
-            var obj:SharedObject = SharedObject.getLocal("user_state");
-            obj.setProperty("toolbox_visible",this.visible);
-            obj.flush();
+                       var obj:SharedObject = SharedObject.getLocal("user_state");
+                       obj.setProperty("toolbox_visible",this.visible);
+                       obj.flush();
                }
                
                // --------------------------------------------------------------------------------
                // Enable/disable toolbox buttons
                // (ideally we'd use CSS to set alpha in disabled state, but Flex's CSS
-               //  capabilities aren't up to it)
+               //      capabilities aren't up to it)
                
-        [Bindable(event="updateSkin")]
+               [Bindable(event="updateSkin")]
                public function canDo(op:String):Boolean {
+                       if (controller.state.selectCount==0) return false;
+
                        switch (op) {
-                               case 'delete':                          return (entity is Way || entity is Node);
-                               case 'reverseDirection':        return (entity is Way);
-                               case 'quadrilateralise':        return (entity is Way && Way(entity).isArea());
-                               case 'straighten':                      return (entity is Way && !Way(entity).isArea());
-                               case 'circularise':                     return (entity is Way && Way(entity).isArea());
-                               case 'split':                           return (entity is Node && controller.state is SelectedWayNode);
-                               case 'parallelise':                     return (entity is Way);
+                               case 'delete':                          return true;
+                               case 'reverseDirection':        return controller.state.hasSelectedWays();
+                               case 'quadrilateralise':        return controller.state.hasSelectedAreas();
+                               case 'straighten':                      return controller.state.hasSelectedUnclosedWays();
+                               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;
                }
 
-        [Bindable(event="updateAlpha")]
+               [Bindable(event="updateAlpha")]
                public function getAlpha(op:String):Number {
                        if (canDo(op)) { return 1; }
                        return 0.5;
                }
 
-        [Bindable(event="updateSkin")]
-        private function deleteToolTipText():String {
-            if (entity is Node) { return "Delete Node (Delete)"; }
-            if (entity is Way && Way(entity).isArea()) { return "Delete Area (Shift+Delete)"; }
-            if (entity is Way) { return "Delete Way (Shift+Delete)"; }
-            return "Delete Item"; // When nothing is selected
-        }
+               [Bindable(event="updateSkin")]
+               private function deleteToolTipText():String {
+                       var entity:Entity=controller.state.firstSelected;
+                       if (entity is Node) { return "Delete Node (Delete)"; }
+                       if (entity is Way && Way(entity).isArea()) { return "Delete Area (Shift+Delete)"; }
+                       if (entity is Way) { return "Delete Way (Shift+Delete)"; }
+                       return "Delete Item"; // When nothing is selected
+               }
 
                // --------------------------------------------------------------------------------
                // Individual toolbox actions
 
                public function doDelete():void {
-                       if (entity is Node) { controller.connection.unregisterPOI(Node(entity)); }
-                       entity.remove(MainUndoStack.getGlobalStack().addAction);
+                       var undo:CompositeUndoableAction = new CompositeUndoableAction("Delete objects");
+                       for each (var entity:Entity in controller.state.selection) {
+                               if (entity is Node) { controller.connection.unregisterPOI(Node(entity)); }
+                               entity.remove(undo.push);
+                       }
+                       MainUndoStack.getGlobalStack().addAction(undo);
 
                        if (controller.state is SelectedWayNode) {
                                controller.setState(new SelectedWay(SelectedWayNode(controller.state).selectedWay));
                                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 {
-            if (entity is Way) { 
-                Way(entity).reverseNodes(MainUndoStack.getGlobalStack().addAction);
-            }
-        }
+               public function doReverseDirection():void {
+                       var undo:CompositeUndoableAction = new CompositeUndoableAction("Reverse direction of objects");
+                       for each (var way:Way in controller.state.selectedWays) {
+                               way.reverseNodes(undo.push);
+                       }
+                       MainUndoStack.getGlobalStack().addAction(undo);
+               }
 
                public function doQuadrilateralise():void {
-                       if (entity is Way) {
-                               Quadrilateralise.quadrilateralise(Way(entity));
+                       var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects right-angled");
+                       for each (var way:Way in controller.state.selectedWays) {
+                               Quadrilateralise.quadrilateralise(way, undo.push);
                        }
+                       MainUndoStack.getGlobalStack().addAction(undo);
                }
 
                public function doStraighten():void {
-                       if (entity is Way) {
-                               Straighten.straighten(Way(entity),controller.map);
+                       var undo:CompositeUndoableAction = new CompositeUndoableAction("Straighten objects");
+                       for each (var way:Way in controller.state.selectedWays) {
+                               Straighten.straighten(way, controller.map, undo.push);
                        }
+                       MainUndoStack.getGlobalStack().addAction(undo);
                }
 
                public function doCircularise():void {
-                       if (entity is Way) {
-                               Circularise.circularise(Way(entity),controller.map);
+                       var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects circular ");
+                       for each (var way:Way in controller.state.selectedWays) {
+                               Circularise.circularise(way, controller.map, undo.push);
                        }
+                       MainUndoStack.getGlobalStack().addAction(undo);
                }
 
                public function doSplit():void {
-                       if (entity is Node && controller.state is SelectedWayNode) {
+                       if (controller.state is SelectedWayNode) {
                                controller.setState(SelectedWayNode(controller.state).splitWay());
                        }
                }
                
                public function doParallelise():void {
-                       if (entity is Way) {
-                               controller.setState(new SelectedParallelWay(Way(entity)));
+                       if (controller.state is SelectedWay) {
+                               controller.setState(new SelectedParallelWay(Way(controller.state.firstSelected)));
                        }
                }
 
 
-    ]]>
+       ]]>
 </mx:Script>   
 </mx:Panel>