add a feature selector to the simple view
authorDave Stubbs <osm@randomjunk.co.uk>
Sun, 26 Jul 2009 15:59:00 +0000 (15:59 +0000)
committerDave Stubbs <osm@randomjunk.co.uk>
Sun, 26 Jul 2009 15:59:00 +0000 (15:59 +0000)
net/systemeD/halcyon/CategorySelector.mxml [new file with mode: 0644]
net/systemeD/halcyon/TagViewer.mxml
net/systemeD/halcyon/connection/Entity.as
net/systemeD/halcyon/mapfeatures/Category.as [new file with mode: 0644]
net/systemeD/halcyon/mapfeatures/Feature.as [new file with mode: 0644]
net/systemeD/halcyon/mapfeatures/MapFeatures.as
resources/map_features.xml

diff --git a/net/systemeD/halcyon/CategorySelector.mxml b/net/systemeD/halcyon/CategorySelector.mxml
new file mode 100644 (file)
index 0000000..4957b35
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:VBox
+       xmlns:mx="http://www.adobe.com/2006/mxml" 
+       xmlns:halcyon="net.systemeD.halcyon.*">
+
+  <mx:HBox horizontalGap="0"> 
+  <mx:ToggleButtonBar height="100%" dataProvider="{categoryStack}" direction="vertical"/>
+  <mx:ViewStack id="categoryStack" width="100%" height="100%">
+      <mx:Repeater id="catRep" dataProvider="{MapFeatures.getInstance().categories}">
+          <mx:VBox label="{catRep.currentItem.name}">
+          <mx:TileList dataProvider="{catRep.currentItem.features}"
+                       width="100%" height="100%" change="itemSelected(event);">
+              <mx:itemRenderer>
+                  <mx:Component>
+                      <mx:VBox width="100" height="75"
+                          horizontalScrollPolicy="off" verticalScrollPolicy="off"
+                          horizontalAlign="center" verticalGap="0">
+                          <mx:Image source="{data.image}" height="100%" verticalAlign="middle"/>
+                          <mx:Text text="{data.name}"/>
+                      </mx:VBox>
+                  </mx:Component>
+              </mx:itemRenderer>
+          </mx:TileList>
+          </mx:VBox>
+      </mx:Repeater>
+  </mx:ViewStack>
+  </mx:HBox>
+  
+  <mx:Label id="hoverInfo" text="Hover Info goes here"/>
+  
+  <mx:Script><![CDATA[
+      import net.systemeD.halcyon.connection.*;
+      import net.systemeD.halcyon.mapfeatures.*;
+
+      import mx.controls.*;
+      
+      private var _selectedType:Feature;
+      
+      [Bindable(event="selectedType")]
+      public function get selectedType():Feature {
+          return _selectedType;
+      }
+      
+      private function itemSelected(event:Event):void {
+          _selectedType = Feature(TileList(event.currentTarget).selectedItem);
+          dispatchEvent(new Event("selectedType"));
+      }
+  ]]></mx:Script>
+</mx:VBox>
+
index da789ed597e4f842e4a0b31d3bfb1fe8ab4aa9f1..e185ae32c7c6ff693ae163843e44c9d17003a0e6 100644 (file)
@@ -6,11 +6,13 @@
     creationComplete="loadFeatures()">
 
   <mx:ViewStack id="stack" width="100%" height="100%">
-
   <mx:VBox width="100%" height="100%" label="Simple">
     <mx:HBox borderStyle="inset" verticalAlign="middle" width="100%" paddingLeft="3" id="iconContainer">
         <mx:Image id="iconImage"/>
-        <mx:Text condenseWhite="true" width="100%" id="iconText"/>
+        <mx:VBox width="100%" verticalGap="1">
+          <mx:PopUpButton id="popupChange" creationComplete="initFeatureBox()" openAlways="true" width="100%"/>
+          <mx:Text condenseWhite="true" width="100%" id="iconText"/>
+        </mx:VBox>
         <mx:LinkButton label="?" click="openDescription()" id="helpLabel"/>
     </mx:HBox>
   </mx:VBox>
       import net.systemeD.halcyon.connection.*;
       import net.systemeD.halcyon.mapfeatures.*;
 
-      import mx.collections.*
-
+      import mx.collections.*;
+      import mx.containers.*;
+      import mx.events.*;
+      import mx.core.*;
+      import mx.managers.PopUpManager;
+      import flash.geom.Point;
+      
       private var mapFeatures:MapFeatures;
       private var selectedEntity:Entity;
-      private var variablesPattern:RegExp = /[$][{]([^}]+)[}]/g;
       private var collection:ArrayCollection;
+      private var tw:CategorySelector = null;
+      private var feature:Feature = null;
 
       public function setEntity(entity:Entity):void {
           if ( selectedEntity != entity ) {
       }
 
       private function refreshFeatureIcon():void {
-          var feature:XML = mapFeatures.findMatchingFeature(selectedEntity);
+          feature = mapFeatures.findMatchingFeature(selectedEntity);
           if ( feature != null )
               setFeatureIcon(selectedEntity, feature);
           else
               blankFeatureIcon(selectedEntity);
       }
 
-      private function setFeatureIcon(entity:Entity, feature:XML):void {
+      private function setFeatureIcon(entity:Entity, feature:Feature):void {
           blankFeatureIcon(entity);
+          
+          iconImage.source = feature.image;
 
-          var icon:XMLList = feature.icon;
-          if ( icon.length == 0 )
-              return;
-
-          if ( icon[0].hasOwnProperty("@image") ) {
-              iconImage.source = icon.@image;
-          }
-
-          var txt:String = icon.children().toXMLString();
-          var replaceTag:Function = function():String {
-              var value:String = entity.getTag(arguments[1]);
-              return value == null ? "" : value;
-          };
-          txt = txt.replace(variablesPattern, replaceTag);
-          iconText.htmlText = "<i>"+feature.@name+"</i><br/>" + txt;
+          var txt:String = feature.htmlDetails(entity);
+          iconText.htmlText = txt;
+          popupChange.label = feature.name;
       }
 
       private function blankFeatureIcon(entity:Entity):void {
@@ -95,6 +93,7 @@
           iconText.htmlText = entity == null ?
                "<i>Nothing selected</i>" :
                "<b>Not recognised</b><br/>Try looking at the tags under the advanced properties";
+          popupChange.label = "unknown";
       }
 
       private function checkAdvanced():void {
           var k:String = advancedTagGrid.selectedItem.key;
           selectedEntity.setTag(k, null);
       }
+      
+      public function initFeatureBox():void {
+          tw = new CategorySelector();
+          tw.addEventListener("selectedType", changeFeatureType);
+          popupChange.popUp = tw;
+      }
+      
+      public function changeFeatureType(event:Event):void {
+          if ( selectedEntity == null )
+              return;
+
+          // remove tags from the current feature
+          if ( feature != null ) {
+              for each( var tag:Object in feature.tags ) {
+                  selectedEntity.setTag(tag["k"], null);
+              }
+          }
+          
+          // set tags for new feature
+          for each( var tag:Object in tw.selectedType.tags ) {
+              selectedEntity.setTag(tag["k"], tag["v"]);
+          }
+          
+          trace("w000t "+tw.selectedType);
+          popupChange.close();
+      }
   ]]></mx:Script>
 </mx:VBox>
 
index cb6b74283dfea04d071c3f45731ff072558454ff..b8204b1c28868cf3817de8081bbb84438c0ac1f3 100644 (file)
@@ -6,11 +6,13 @@ package net.systemeD.halcyon.connection {
         private var _id:Number;
         private var _version:uint;
         private var tags:Object = {};
+        private var modified:Boolean = false;
 
         public function Entity(id:Number, version:uint, tags:Object) {
             this._id = id;
             this._version = version;
             this.tags = tags;
+            modified = id < 0;
         }
 
         public function get id():Number {
@@ -38,6 +40,7 @@ package net.systemeD.halcyon.connection {
                     delete tags[key];
                 else
                     tags[key] = value;
+                modified = true;
                 dispatchEvent(new TagEvent(Connection.TAG_CHANGE, this, key, key, old, value));
             }
         }
@@ -47,6 +50,7 @@ package net.systemeD.halcyon.connection {
             if ( oldKey != newKey ) {
                 delete tags[oldKey];
                 tags[newKey] = value;
+                modified = true;
                 dispatchEvent(new TagEvent(Connection.TAG_CHANGE, this, oldKey, newKey, value, value));
             }
         }
@@ -69,9 +73,21 @@ package net.systemeD.halcyon.connection {
             return copy;
         }
 
-               public function getType():String {
-                       return '';
-               }
+        public function get isDirty():Boolean {
+            return modified;
+        }
+
+        public function markClean():void {
+            modified = false;
+        }
+
+        protected function markDirty():void {
+            modified = true;
+        }
+
+        public function getType():String {
+            return '';
+        }
 
     }
 
diff --git a/net/systemeD/halcyon/mapfeatures/Category.as b/net/systemeD/halcyon/mapfeatures/Category.as
new file mode 100644 (file)
index 0000000..14d0d28
--- /dev/null
@@ -0,0 +1,40 @@
+package net.systemeD.halcyon.mapfeatures {
+
+    import flash.events.EventDispatcher;
+    import flash.events.Event;
+
+       public class Category extends EventDispatcher {
+        private var mapFeatures:MapFeatures;
+        private var _name:String;
+        private var _id:String;
+        private var _features:Array;
+
+        public function Category(mapFeatures:MapFeatures, name:String, id:String) {
+            this.mapFeatures = mapFeatures;
+            this._name = name;
+            this._id = id;
+            
+            _features = new Array();
+            for each( var feature:Feature in mapFeatures.features ) {
+                if ( feature.isInCategory(id) )
+                    _features.push(feature);
+            }
+        }
+
+        public function get id():String {
+            return _id;
+        }
+
+        [Bindable(event="categoryChange")]
+        public function get name():String {
+            return _name;
+        }
+        
+        [Bindable(event="featuresChanged")]
+        public function get features():Array {
+            return _features;
+        }
+    }
+}
+
+
diff --git a/net/systemeD/halcyon/mapfeatures/Feature.as b/net/systemeD/halcyon/mapfeatures/Feature.as
new file mode 100644 (file)
index 0000000..abc3bde
--- /dev/null
@@ -0,0 +1,75 @@
+package net.systemeD.halcyon.mapfeatures {
+
+    import flash.events.EventDispatcher;
+    import flash.events.Event;
+    import net.systemeD.halcyon.connection.Entity;
+
+       public class Feature extends EventDispatcher {
+        private var mapFeatures:MapFeatures;
+        private var _xml:XML;
+        private static var variablesPattern:RegExp = /[$][{]([^}]+)[}]/g;
+        private var _tags:Array;
+
+        public function Feature(_xml:XML) {
+            this._xml = _xml;
+            _tags = new Array();
+            
+            for each(var tag:XML in definition.tag) {
+                var tagObj:Object = new Object();
+                tagObj["k"] = tag.@k;
+                tagObj["v"] = tag.@v;
+                _tags.push(tagObj);
+            }
+
+        }
+        
+        public function get definition():XML {
+            return _xml;
+        }
+    
+        [Bindable(event="nameChanged")]
+        public function get name():String {
+            return _xml.@name;
+        }
+    
+        [Bindable(event="imageChanged")]
+        public function get image():String {
+            var icon:XMLList = _xml.icon;
+
+            if ( icon.length() > 0 && icon[0].hasOwnProperty("@image") )
+                return icon[0].@image;
+            else
+                return null;
+        }
+        
+        public function htmlDetails(entity:Entity):String {
+            var icon:XMLList = _xml.icon;
+            if ( icon == null )
+                return "";
+
+            var txt:String = icon.children().toXMLString();
+            var replaceTag:Function = function():String {
+                var value:String = entity.getTag(arguments[1]);
+                return value == null ? "" : value;
+            };
+            txt = txt.replace(variablesPattern, replaceTag);
+            return txt;
+        }
+        
+        public function isInCategory(category:String):Boolean {
+            var cats:XMLList = _xml.category;
+            if ( cats.length() == 0 )
+                return false;
+                
+            for each( var cat:XML in cats )
+                if ( cat.text()[0] == category )
+                    return true;
+            return false;
+        }
+        
+        public function get tags():Array {
+            return _tags;
+        }
+    }
+}
+
index 82b114cbb7ea56b3b6c8c257a6cf9d54b646ddc4..42859ccd9f19aff2a741bb7750485417434a247b 100644 (file)
@@ -1,5 +1,6 @@
 package net.systemeD.halcyon.mapfeatures {
 
+    import flash.events.EventDispatcher;
     import flash.events.Event;
     import flash.net.URLLoader;
     import flash.net.URLRequest;
@@ -10,7 +11,7 @@ package net.systemeD.halcyon.mapfeatures {
     import net.systemeD.halcyon.connection.*;
 
 
-       public class MapFeatures {
+       public class MapFeatures extends EventDispatcher {
         private static var instance:MapFeatures;
 
         public static function getInstance():MapFeatures {
@@ -24,6 +25,8 @@ package net.systemeD.halcyon.mapfeatures {
 
 
         private var xml:XML = null;
+        private var _features:Array = null;
+        private var _categories:Array = null;
 
         protected function loadFeatures():void {
             var request:URLRequest = new URLRequest("map_features.xml");
@@ -34,22 +37,33 @@ package net.systemeD.halcyon.mapfeatures {
 
         private function onFeatureLoad(event:Event):void {
             xml = new XML(URLLoader(event.target).data);
+            
+            _features = new Array();
+            for each(var feature:XML in xml.feature) {
+                _features.push(new Feature(feature));
+            }            
+            _categories = new Array();
+            for each(var catXML:XML in xml.category) {
+                if ( catXML.child("category").length() == 0 )
+                  _categories.push(new Category(this, catXML.@name, catXML.@id));
+            }
+            dispatchEvent(new Event("featuresLoaded"));
         }
 
         public function hasLoaded():Boolean {
             return xml != null;
         }
 
-        public function findMatchingFeature(entity:Entity):XML {
+        public function findMatchingFeature(entity:Entity):Feature {
             if ( xml == null )
                 return null;
 
-            for each(var feature:XML in xml.feature) {
+            for each(var feature:Feature in features) {
                 // check for matching tags
                 var match:Boolean = true;
-                for each(var tag:XML in feature.tag) {
-                    var entityTag:String = entity.getTag(tag.@k);
-                    match = entityTag == tag.@v || (entityTag != null && tag.@v == "*");
+                for each(var tag:Object in feature.tags) {
+                    var entityTag:String = entity.getTag(tag.k);
+                    match = entityTag == tag.v || (entityTag != null && tag.v == "*");
                     if ( !match ) break;
                 }
                 if ( match )
@@ -57,6 +71,21 @@ package net.systemeD.halcyon.mapfeatures {
             }
             return null;
         }
+        
+        [Bindable(event="featuresLoaded")]
+        public function get categories():Array {
+            if ( xml == null )
+                return null;            
+            return _categories;
+        }
+
+        [Bindable(event="featuresLoaded")]
+        public function get features():Array {
+            if ( xml == null )
+                return null;            
+            return _features;
+        }
+
     }
 
 }
index 099d104dbd3916efa0bb3cff6544bc5c1d70fdec..55dee80b86f376630a7ced3f9b3b650a525f6a5e 100644 (file)
@@ -2,9 +2,30 @@
 
 <mapFeatures>
 
+  <!-- Categories -->
+  
+  <category name="Roads" id="roads">
+  </category>
+
+  <category name="Paths" id="paths">
+  </category>
+
+  <category name="Transport" id="transport">
+  </category>
+
+  <category name="Water" id="water">
+  </category>
+
+  <category name="Natural" id="natural">
+  </category>
+
+  <category name="Admin" id="admin">
+  </category>
+
   <!-- Roads -->
 
   <feature name="Motorway">
+    <category>roads</category>
     <icon image="features/highway__motorway.png">
       <font size="16pt"><b>${ref}</b></font><br/>
     </icon>
   </feature>
 
   <feature name="Motorway link" icon="features/motorway_link.png">
+    <category>roads</category>
     <line/>
     <tag k="highway" v="motorway_link"/>
   </feature>
 
   <feature name="Trunk Road">
+    <category>roads</category>
     <icon image="features/highway__trunk.png">
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
@@ -29,6 +52,7 @@
   </feature>
 
   <feature name="Primary Road">
+    <category>roads</category>
     <icon>
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
@@ -39,6 +63,7 @@
   </feature>
 
   <feature name="Secondary Road">
+    <category>roads</category>
     <icon>
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
@@ -49,6 +74,7 @@
   </feature>
 
   <feature name="Tertiary Road">
+    <category>roads</category>
     <icon>
       <font size="14pt"><b>${name}</b></font><br/>
       <font size="10pt">${ref}</font>
@@ -59,6 +85,7 @@
   </feature>
 
   <feature name="Residential Road">
+    <category>roads</category>
     <icon image="features/highway__residential.png">
       <font size="14pt"><b>${name}</b></font><br/>
       <font size="6pt">${postal_code}</font>
@@ -69,6 +96,7 @@
   </feature>
 
   <feature name="Road">
+    <category>roads</category>
     <icon image="features/highway__unclassified.png">
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Service Road">
+    <category>roads</category>
     <icon image="features/highway__service.png">
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Unknown Road">
+    <category>roads</category>
     <icon>
       <font size="10pt">This road has not been given a specific type. It's a road, and that's all that's known.</font>
     </icon>
   </feature>
 
   <feature name="Living Street">
+    <category>roads</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Track">
+    <category>roads</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Pedestrian Road">
+    <category>roads</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   <!-- Paths -->
 
   <feature name="Cycle Path">
+    <category>paths</category>
     <icon>
       ${name} <i>${ncn_ref} ${rcn_ref} ${lcn_ref} ${ref}</i>
     </icon>
   </feature>
 
   <feature name="Foot Path">
+    <category>paths</category>
     <icon>
       ${name} <i>${ref}</i>
     </icon>
   </feature>
 
   <feature name="Bridleway">
+    <category>paths</category>
     <icon>
     </icon>
 
   </feature>
 
   <feature name="Steps">
+    <category>paths</category>
     <icon>
     </icon>
 
   <!-- Waterway -->
 
   <feature name="Stream">
+    <category>water</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="River">
+    <category>water</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Canal">
+    <category>water</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Dam">
+    <category>water</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   <!-- Railways -->
 
   <feature name="Railway Line">
+    <category>transport</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Tram Line">
+    <category>transport</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
   </feature>
 
   <feature name="Subway Line">
+    <category>transport</category>
     <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
     <tag k="railway" v="subway"/>
   </feature>
 
-  <feature name="Tram Line">
-    <icon>
-      <font size="14pt"><b>${name}</b></font>
-    </icon>
-
-    <line/>
-    <tag k="railway" v="tram"/>
-  </feature>
-
 
   <!-- building -->