Give "create multipolygon" a toolbox icon
authorRichard Fairhurst <richard@systemeD.net>
Sun, 2 Oct 2011 12:41:23 +0000 (13:41 +0100)
committerRichard Fairhurst <richard@systemeD.net>
Sun, 2 Oct 2011 12:41:23 +0000 (13:41 +0100)
embedded/multipolygon.svg [new file with mode: 0644]
net/systemeD/potlatch2/Toolbox.mxml
net/systemeD/potlatch2/controller/ControllerState.as
net/systemeD/potlatch2/controller/SelectedMultiple.as

diff --git a/embedded/multipolygon.svg b/embedded/multipolygon.svg
new file mode 100644 (file)
index 0000000..330298c
--- /dev/null
@@ -0,0 +1,26 @@
+<?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="14.999" height="15" viewBox="0 0 14.999 15" overflow="visible" enable-background="new 0 0 14.999 15"
+        xml:space="preserve">
+       <g id="Layer_1">
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="14.271" x2="14.012" y2="1.034"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="3.174" y1="14.271" x2="14.386" y2="3.061"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="11.872" x2="12.069" y2="0.577"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="9.472" x2="9.681" y2="0.565"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="7.071" x2="7.272" y2="0.573"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="4.671" x2="4.845" y2="0.601"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="0.774" y1="2.271" x2="2.476" y2="0.569"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="5.574" y1="14.271" x2="14.418" y2="5.428"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="7.975" y1="14.271" x2="14.388" y2="7.858"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="10.374" y1="14.271" x2="14.42" y2="10.225"/>
+               <line fill="none" stroke="#7F7F7F" stroke-width="0.5" x1="12.774" y1="14.271" x2="14.373" y2="12.673"/>
+               <rect x="4.499" y="4.971" fill="#FFFFFF" stroke="#000000" width="7.2" height="6.401"/> 
+               <rect x="0.6" y="0.6" fill="none" stroke="#000000" stroke-width="1.2" width="13.8" height="13.799"/> 
+       </g>
+</svg>
index 0657976..5ed66ea 100644 (file)
                        alpha="{getAlpha('split')}" 
                        toolTip="Split way (X)" 
                        width="28" height="28" y="4" x="66" />
                        alpha="{getAlpha('split')}" 
                        toolTip="Split way (X)" 
                        width="28" height="28" y="4" x="66" />
-               <s:Button icon="@Embed('../../../embedded/merge.svg')"
+               <s:Button 
                        id="mergeButton"
                        click='doMerge();'
                        id="mergeButton"
                        click='doMerge();'
-                       enabled="{canDo('merge')}" 
-                       alpha="{getAlpha('merge')}" 
                        toolTip="Merge ways" 
                        width="28" height="28" y="4" x="96" />
 
                        toolTip="Merge ways" 
                        width="28" height="28" y="4" x="96" />
 
         public var deleteWay:String = "Delete Way (Shift+Delete)";
         public var deleteItem:String = "Delete Item"; // When nothing is selected
 
         public var deleteWay:String = "Delete Way (Shift+Delete)";
         public var deleteItem:String = "Delete Item"; // When nothing is selected
 
+       [Bindable] [Embed(source="../../../embedded/merge.svg"       )] private var mergeIcon:Class;
+       [Bindable] [Embed(source="../../../embedded/multipolygon.svg")] private var multipolygonIcon:Class;
+
                public function init(controller:EditController):void {
                        this.controller=controller;
                        /* check if the toolbox was explictly turned off in a previous session */
                public function init(controller:EditController):void {
                        this.controller=controller;
                        /* check if the toolbox was explictly turned off in a previous session */
                        dispatchEvent(new Event("updateSkin"));
                        dispatchEvent(new Event("updateAlpha"));
                        updateDirectionArrow();
                        dispatchEvent(new Event("updateSkin"));
                        dispatchEvent(new Event("updateAlpha"));
                        updateDirectionArrow();
+                       updateMergeIcon();
                }
 
                private function handleDown(e:Event):void {
                }
 
                private function handleDown(e:Event):void {
                                case 'circularise':                     return controller.state.hasSelectedAreas();
                                case 'split':                           return (controller.state is SelectedWayNode);
                                case 'parallelise':                     return (controller.state is SelectedWay);
                                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;
                }
                        }
                        return false;
                }
             }
         }
 
             }
         }
 
+               private function updateMergeIcon():void {
+                       var multi:Object=controller.state.multipolygonMembers();
+                       if (multi.outer) {
+                               mergeButton.setStyle("icon",multipolygonIcon);
+                               mergeButton.alpha=1;
+                               mergeButton.enabled=true;
+                       } else if (controller.state.hasAdjoiningWays()) {
+                               mergeButton.setStyle("icon",mergeIcon);
+                               mergeButton.alpha=1;
+                               mergeButton.enabled=true;
+                       } else {
+                               mergeButton.setStyle("icon",mergeIcon);
+                               mergeButton.alpha=0.5;
+                               mergeButton.enabled=false;
+                       }
+               }
+
         private function reverseClicked():void {
             if(canDo('reverseDirection')) {
                 doReverseDirection();
         private function reverseClicked():void {
             if(canDo('reverseDirection')) {
                 doReverseDirection();
                }
                
                public function doMerge():void {
                }
                
                public function doMerge():void {
-                       controller.setState(SelectedMultiple(controller.state).mergeWays());
+                       var multi:Object=controller.state.multipolygonMembers();
+                       if (multi.outer) {
+                               controller.setState(SelectedMultiple(controller.state).createMultipolygon());
+                       } else {
+                               controller.setState(SelectedMultiple(controller.state).mergeWays());
+                       }
                }
 
                public function doReverseDirection():void {
                }
 
                public function doReverseDirection():void {
index 8c7b32c..5002c58 100644 (file)
@@ -303,6 +303,51 @@ package net.systemeD.potlatch2.controller {
                        return false;
                }
 
                        return false;
                }
 
+               /** Identify the inners and outer from the current selection for making a multipolygon. */
+               
+               public function multipolygonMembers():Object {
+                       if (_selection.length<2) { return {}; }
+
+                       var entity:Entity;
+                       var relation:Relation;
+                       var outer:Way;
+                       var inners:Array=[];
+
+                       // If there's an existing outer in the selection, use that
+                       for each (entity in selection) {
+                               if (!entity is Way) return {};
+                               var r:Array=entity.findParentRelationsOfType('multipolygon','outer');
+                               if (r.length) { outer=Way(entity); relation=r[0]; }
+                       }
+
+                       // Otherwise, find the way with the biggest area
+                       var largest:Number=0;
+                       if (!outer) {
+                               for each (entity in selection) {
+                                       if (!entity is Way) return {};
+                                       if (!Way(entity).isArea()) return {};
+                                       var props:Object=layer.wayUIProperties(entity as Way);
+                                       if (props.patharea>largest) { outer=Way(entity); largest=props.patharea; }
+                               }
+                       }
+                       if (!outer) return {};
+                       
+                       // Identify the inners
+                       for each (entity in selection) {
+                               if (entity==outer) continue;
+                               if (!entity is Way) return {};
+                               if (!Way(entity).isArea()) return {};
+                               var node:Node=Way(entity).getFirstNode();
+                               if (outer.pointWithin(node.lon,node.lat)) inners.push(entity);
+                       }
+                       if (inners.length==0) return {};
+                       
+                       return { outer: outer,
+                                inners: inners,
+                                relation: relation }
+               }
+
+
                // Selection setters
 
                public function set selection(items:Array):void {
                // Selection setters
 
                public function set selection(items:Array):void {
index c6ab833..f78d0d3 100644 (file)
@@ -34,8 +34,8 @@ package net.systemeD.potlatch2.controller {
                }
 
                override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
                }
 
                override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
-                       if (event.keyCode==74) return mergeWays();      // 'J'
-                       if (event.keyCode==75) return createMultipolygon();
+                       if (event.keyCode==74) return mergeWays();                      // 'J' (join)
+                       if (event.keyCode==72) return createMultipolygon();     // 'H' (hole)
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
                }
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
                }
@@ -109,69 +109,33 @@ package net.systemeD.potlatch2.controller {
                /** Create multipolygon from selection, or add to existing multipolygon. */
                
                public function createMultipolygon():ControllerState {
                /** Create multipolygon from selection, or add to existing multipolygon. */
                
                public function createMultipolygon():ControllerState {
-                       var entity:Entity;
-                       var relation:Relation;
-                       var outer:Way;
                        var inner:Way;
                        var inner:Way;
-                       var inners:Array=[];
-
-                       // If there's an existing outer in the selection, use that
-                       for each (entity in selection) {
-                               if (!entity is Way) continue;
-                               var r:Array=entity.findParentRelationsOfType('multipolygon','outer');
-                               if (r.length) { outer=Way(entity); relation=r[0]; }
-                       }
-
-                       // Otherwise, find the way with the biggest area
-                       var largest:Number=0;
-                       if (!outer) {
-                               for each (entity in selection) {
-                                       if (!entity is Way) continue;
-                                       if (!Way(entity).isArea()) continue;
-                                       var props:Object=layer.wayUIProperties(entity as Way);
-                                       if (props.patharea>largest) { outer=Way(entity); }
-                               }
-                       }
-                       
-                       // If we still don't have an outer, then squawk
-                       if (!outer) {
-                               controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "No areas selected"));
-                               return this;
-                       }
-                       
-                       // Identify the inners
-                       for each (entity in selection) {
-                               if (entity==outer) continue;
-                               if (!entity is Way) continue;
-                               if (!Way(entity).isArea()) continue;
-                               var node:Node=Way(entity).getFirstNode();
-                               if (outer.pointWithin(node.lon,node.lat)) inners.push(entity);
-                       }
-                       if (inners.length==0) {
-                controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "Couldn't identify inner areas"));
+                       var multi:Object=multipolygonMembers();
+                       if (!multi.outer) {
+                               controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "Couldn't make the multipolygon"));
                                return this;
                        }
 
                        // If relation exists, add any inners that aren't currently present
                                return this;
                        }
 
                        // If relation exists, add any inners that aren't currently present
-                       if (relation) {
+                       if (multi.relation) {
                                var action:CompositeUndoableAction = new CompositeUndoableAction("Add to multipolygon");
                                var action:CompositeUndoableAction = new CompositeUndoableAction("Add to multipolygon");
-                               for each (inner in inners) {
-                                       if (!relation.hasMemberInRole(inner,'inner'))
-                                               relation.appendMember(new RelationMember(inner,'inner'),action.push);
+                               for each (inner in multi.inners) {
+                                       if (!multi.relation.hasMemberInRole(inner,'inner'))
+                                               multi.relation.appendMember(new RelationMember(inner,'inner'),action.push);
                                }
                                MainUndoStack.getGlobalStack().addAction(action);
                                
                        // Otherwise, create whole new relation
                        } else {
                                }
                                MainUndoStack.getGlobalStack().addAction(action);
                                
                        // Otherwise, create whole new relation
                        } else {
-                               var memberlist:Array=[new RelationMember(outer,'outer')];
-                               for each (inner in inners) 
+                               var memberlist:Array=[new RelationMember(multi.outer,'outer')];
+                               for each (inner in multi.inners) 
                                        memberlist.push(new RelationMember(inner,'inner'));
                                        memberlist.push(new RelationMember(inner,'inner'));
-                               relation = entity.connection.createRelation( { type: 'multipolygon' }, memberlist, MainUndoStack.getGlobalStack().addAction);
+                               layer.connection.createRelation( { type: 'multipolygon' }, memberlist, MainUndoStack.getGlobalStack().addAction);
                        }
 
                        }
 
-                       return new SelectedWay(outer);
+                       return new SelectedWay(multi.outer);
                }
                }
-
+               
                override public function enterState():void {
                        selection=initSelection.concat();
                        for each (var entity:Entity in selection) {
                override public function enterState():void {
                        selection=initSelection.concat();
                        for each (var entity:Entity in selection) {