initial work on tag editor
authorDave Stubbs <osm@randomjunk.co.uk>
Sat, 13 Jun 2009 19:41:42 +0000 (19:41 +0000)
committerDave Stubbs <osm@randomjunk.co.uk>
Sat, 13 Jun 2009 19:41:42 +0000 (19:41 +0000)
15 files changed:
features/highway__motorway.png [new file with mode: 0644]
features/highway__residential.png [new file with mode: 0644]
features/highway__service.png [new file with mode: 0644]
features/highway__trunk.png [new file with mode: 0644]
features/highway__unclassified.png [new file with mode: 0644]
halcyon.mxml
map_features.xml [new file with mode: 0644]
net/systemeD/halcyon/EditController.as [new file with mode: 0644]
net/systemeD/halcyon/Map.as
net/systemeD/halcyon/MapController.as [new file with mode: 0644]
net/systemeD/halcyon/TagViewer.mxml [new file with mode: 0644]
net/systemeD/halcyon/WayUI.as
net/systemeD/halcyon/connection/Entity.as
net/systemeD/halcyon/connection/Tag.as [new file with mode: 0644]
net/systemeD/halcyon/mapfeatures/MapFeatures.as [new file with mode: 0644]

diff --git a/features/highway__motorway.png b/features/highway__motorway.png
new file mode 100644 (file)
index 0000000..0a12e18
Binary files /dev/null and b/features/highway__motorway.png differ
diff --git a/features/highway__residential.png b/features/highway__residential.png
new file mode 100644 (file)
index 0000000..d481aab
Binary files /dev/null and b/features/highway__residential.png differ
diff --git a/features/highway__service.png b/features/highway__service.png
new file mode 100644 (file)
index 0000000..0fdd441
Binary files /dev/null and b/features/highway__service.png differ
diff --git a/features/highway__trunk.png b/features/highway__trunk.png
new file mode 100644 (file)
index 0000000..b8e1e0b
Binary files /dev/null and b/features/highway__trunk.png differ
diff --git a/features/highway__unclassified.png b/features/highway__unclassified.png
new file mode 100644 (file)
index 0000000..9359af2
Binary files /dev/null and b/features/highway__unclassified.png differ
index 23d8a72..cb1c456 100755 (executable)
@@ -8,11 +8,12 @@
 
     <mx:HDividedBox width="100%" height="100%">
 
-      <mx:VBox height="50%">
+      <mx:VBox height="100%" width="25%">
         <mx:Button label="+" click="theMap.zoomIn();"/>
         <mx:Button label="-" click="theMap.zoomOut();"/>
+        <halcyon:TagViewer width="100%" height="100%" id="tagViewer"/>
       </mx:VBox>
-      <mx:Canvas id="map_area" clipContent="true"/>
+      <mx:Canvas id="map_area" width="75%"/>
     </mx:HDividedBox>
 
        <mx:Script><![CDATA[
                        var _root:IChildList=map_area.rawChildren;              // convenient local shorthand
 
                        // map backdrop object
-            var b:Canvas = new Canvas();
+            var b:Sprite = new Sprite();
             b.height=200; b.width=200;
-            b.setStyle("backgroundColor", 0xFFFFEA);
+            b.graphics.beginFill(0xFFFFEA,100); 
+            b.graphics.drawRect(0,0,200,200); 
+            b.graphics.endFill();
                        _root.addChild(b);
 
                        // add map
@@ -81,6 +84,9 @@
                        t.multiline=true;
                        _root.addChild(t);
                        Globals.vars.debug=t;
+
+            var controller:EditController = new EditController(theMap, tagViewer);
+            controller.setActive();
                }
 
        ]]></mx:Script>
diff --git a/map_features.xml b/map_features.xml
new file mode 100644 (file)
index 0000000..b581b73
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<mapFeatures>
+
+  <feature name="Motorway">
+    <icon background="blue" image="features/highway__motorway.png">
+      <font size="16pt"><b>${ref}</b></font><br/>
+    </icon>
+
+    <line/>
+    <tag k="highway" v="motorway"/>
+  </feature>
+
+  <feature name="Motorway link" icon="features/motorway_link.png">
+    <line/>
+    <tag k="highway" v="motorway_link"/>
+  </feature>
+
+  <feature name="Trunk Road">
+    <icon background="green" image="features/highway__trunk.png">
+      <font size="16pt"><b>${ref}</b></font><br/>
+      <font size="10pt">${name}</font>
+    </icon>
+
+    <line/>
+    <tag k="highway" v="trunk"/>
+  </feature>
+
+  <feature name="Residential Road">
+    <icon background="white" image="features/highway__residential.png">
+      <font size="14pt"><b>${name}</b></font><br/>
+      <font size="6pt">${postal_code}</font>
+    </icon>
+
+    <line/>
+    <tag k="highway" v="residential"/>
+  </feature>
+
+  <feature name="Unclassified Road">
+    <icon background="white" image="features/highway__unclassified.png">
+      <font size="14pt"><b>${name}</b></font><br/>
+      Road
+    </icon>
+
+    <line/>
+    <tag k="highway" v="unclassified"/>
+  </feature>
+
+  <feature name="Service Road">
+    <icon background="white" image="features/highway__service.png">
+      <font size="14pt"><b>${name}</b></font><br/>
+      Service Road
+    </icon>
+    <description>
+      Access roads
+    </description>
+
+    <line/>
+    <tag k="highway" v="service"/>
+  </feature>
+
+  <feature name="Building">
+    <icon background="white">
+      <b>${name} ${addr:housename}</b><br/>
+      ${addr:housenumber} ${addr:street} ${addr:postcode}
+    </icon>
+
+    <line/>
+    <tag k="building" v="*"/>
+  </feature>
+
+</mapFeatures>
+
diff --git a/net/systemeD/halcyon/EditController.as b/net/systemeD/halcyon/EditController.as
new file mode 100644 (file)
index 0000000..11d4dab
--- /dev/null
@@ -0,0 +1,32 @@
+package net.systemeD.halcyon {
+    import net.systemeD.halcyon.connection.*;
+       import flash.events.*;
+
+    public class EditController implements MapController {
+
+        private var map:Map;
+        private var tagViewer:TagViewer;
+
+        public function EditController(map:Map, tagViewer:TagViewer) {
+            this.map = map;
+            this.tagViewer = tagViewer;
+        }
+
+        public function setActive():void {
+            map.setController(this);
+        }
+
+        public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
+            if ( event.type == MouseEvent.CLICK )
+                tagViewer.setEntity(entity);
+            else if ( event.type == MouseEvent.MOUSE_OVER )
+                map.setHighlight(entity, true);
+            else if ( event.type == MouseEvent.MOUSE_OUT )
+                map.setHighlight(entity, false);
+
+        }
+
+    }
+
+}
+
index e202306..1336784 100755 (executable)
@@ -72,18 +72,18 @@ package net.systemeD.halcyon {
                        // [layer][0]                   - fill
 
                        for (var l:int=0; l<13; l++) {                          // 11 layers (10 is +5, 0 is -5)
-                               var s:Sprite=new Sprite();                              //  |
-                               s.addChild(new Sprite());                               //      | 0 fill
-                               var t:Sprite=new Sprite();                              //  | 1 stroke
+                               var s:Sprite = getPaintSprite();                //  |
+                               s.addChild(getPaintSprite());                   //      | 0 fill
+                               var t:Sprite = getPaintSprite();                //  | 1 stroke
                                for (var j:int=0; j<11; j++) {                  //      |  | ten sublayers
-                                       t.addChild(new Sprite());                       //  |  |  |
+                                       t.addChild(getPaintSprite());           //  |  |  |
                                }                                                                               //  |  |  |
                                s.addChild(t);                                                  //  |  |
-                               s.addChild(new Sprite());                               //      | 2 names
+                               s.addChild(getPaintSprite());                   //      | 2 names
                                addChild(s);                                                    //  |
                        }
-                       s=new Sprite(); addChild(s);                            // 11 - POIs
-                       s=new Sprite(); addChild(s);                            // 12 - shields and POI names
+                       s=getPaintSprite(); addChild(s);                        // 11 - POIs
+                       s=getPaintSprite(); addChild(s);                        // 12 - shields and POI names
 
                        connection= Connection.getConnection();
             connection.addEventListener(Connection.NEW_WAY, newWayCreated);
@@ -92,6 +92,12 @@ package net.systemeD.halcyon {
 
         }
 
+        private function getPaintSprite():Sprite {
+            var s:Sprite = new Sprite();
+            s.mouseEnabled = false;
+            return s;
+        }
+
                public function gotEnvironment(r:Object):void {
                        init(53.09465,-2.56495,17);
                }
@@ -178,32 +184,7 @@ package net.systemeD.halcyon {
                        connection.loadBbox(edge_l,edge_r,edge_t,edge_b);
                }
 
-/*
-               public function gotBbox(r:Object):void {
-                       addDebug("got whichways");
-                       var code:uint         =r.shift(); if (code) { connectionError(); return; }
-                       var message:String    =r.shift();
-                       var waylist:Array     =r[0];
-                       var pointlist:Array   =r[1];
-                       var relationlist:Array=r[2];
-                       var i:uint, v:uint;
-
-                       for each (var w:Array in waylist) {
-                               i=w[0]; v=w[1];
-                               if (ways[i] && ways[i].version==v) { continue; }
-                               ways[i]=new Way(i,v,this);
-                               ways[i].load(connection);
-                       }
 
-                       for each (var p:Array in pointlist) {
-                               i=p[0]; v=p[4];
-                               if (pois[i] && pois[i].version==v) { continue; }
-                               pois[i]=new POI(i,v,p[1],p[2],p[3],this);
-                       }
-
-                       addDebug("waylist is "+waylist);
-               }
-*/
 
         private function newWayCreated(event:EntityEvent):void {
             var way:Way = event.entity as Way;
@@ -215,6 +196,26 @@ package net.systemeD.halcyon {
             pois[node.id] = new POI(node, this);
         }
 
+        public function setHighlight(entity:Entity, highlight:Boolean):void {
+            if ( entity is Way ) {
+                var wayUI:WayUI = ways[entity.id];
+                if ( wayUI != null )
+                    wayUI.setHighlight(highlight);
+            }
+        }
+
+        // Handle mouse events on ways/nodes
+        private var mapController:MapController = null;
+
+        public function setController(controller:MapController):void {
+            this.mapController = controller;
+        }
+
+        public function wayMouseEvent(event:MouseEvent, way:Way):void {
+            if ( mapController != null )
+                mapController.entityMouseEvent(event, way);
+        }
+
                // ------------------------------------------------------------------------------------------
                // Redraw all items, zoom in and out
                
diff --git a/net/systemeD/halcyon/MapController.as b/net/systemeD/halcyon/MapController.as
new file mode 100644 (file)
index 0000000..0905c28
--- /dev/null
@@ -0,0 +1,12 @@
+package net.systemeD.halcyon {
+    import net.systemeD.halcyon.connection.*;
+       import flash.events.*;
+
+    public interface MapController {
+
+        function entityMouseEvent(event:MouseEvent, entity:Entity):void;
+
+    }
+
+}
+
diff --git a/net/systemeD/halcyon/TagViewer.mxml b/net/systemeD/halcyon/TagViewer.mxml
new file mode 100644 (file)
index 0000000..7283484
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:VBox
+       xmlns:mx="http://www.adobe.com/2006/mxml" 
+       xmlns:halcyon="net.systemeD.halcyon.*"
+    backgroundColor="white"
+    creationComplete="loadFeatures()">
+
+  <mx:ViewStack id="stack" width="100%" height="100%">
+
+  <mx:VBox width="100%" height="100%" label="Simple">
+    <mx:HBox borderStyle="solid" verticalAlign="middle" width="100%" paddingLeft="3">
+        <mx:Image id="iconImage"/>
+        <mx:Text condenseWhite="true" width="100%" id="iconText"/>
+        <mx:LinkButton label="?" click="openDescription()" id="helpLabel"/>
+    </mx:HBox>
+  </mx:VBox>
+
+  <mx:VBox width="100%" height="100%" label="Advanced" initialize="checkAdvanced()">
+    <mx:Label id="advancedID">
+      <mx:htmlText><![CDATA[<i>No Selection</i>]]></mx:htmlText>
+    </mx:Label>
+
+    <mx:DataGrid width="100%" height="100%" id="advancedTagGrid">
+            <mx:columns>
+                <mx:DataGridColumn dataField="key" headerText="Key"/>
+                <mx:DataGridColumn dataField="value" headerText="Value"/>
+            </mx:columns>
+    </mx:DataGrid>
+
+    <mx:Label text="Key: {advancedTagGrid.selectedItem.key}"/>
+    <mx:Label text="Value: {advancedTagGrid.selectedItem.value}"/>
+  </mx:VBox>
+
+  </mx:ViewStack>
+
+  <mx:LinkBar dataProvider="{stack}"/>
+
+  <mx:Script><![CDATA[
+      import net.systemeD.halcyon.connection.*;
+      import net.systemeD.halcyon.mapfeatures.*;
+
+      private var mapFeatures:MapFeatures;
+      private var selectedEntity:Entity;
+      private var variablesPattern:RegExp = /[$][{]([^}]+)[}]/g;
+
+      public function setEntity(entity:Entity):void {
+          this.selectedEntity = entity;
+
+          if ( advancedID != null )
+              setupAdvanced(entity);
+
+          var feature:XML = mapFeatures.findMatchingFeature(entity);
+          if ( feature != null )
+              setFeatureIcon(entity, feature);
+          else
+              blankFeatureIcon(entity);
+      }
+
+      private function setFeatureIcon(entity:Entity, feature:XML):void {
+          blankFeatureIcon(entity);
+
+          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;
+      }
+
+      private function blankFeatureIcon(entity:Entity):void {
+          iconImage.source = null;
+          iconText.htmlText = entity == null ? "<i>Nothing selected</i>" : "<b>Not recognised</b><br/>Try looking at advanced";
+      }
+
+      private function checkAdvanced():void {
+          if ( selectedEntity != null )
+             setupAdvanced(selectedEntity);
+      }
+
+      private function setupAdvanced(entity:Entity):void {
+          var entityText:String = "xx";
+          if ( entity is Node ) entityText = "Node";
+          else if ( entity is Way ) entityText = "Way";
+          else if ( entity is Relation ) entityText = "Relation";
+          advancedID.htmlText = entityText+": <b>"+entity.id+"</b>";
+          advancedTagGrid.dataProvider = entity.getTagArray();
+      }
+
+      public function loadFeatures():void {
+          mapFeatures = MapFeatures.getInstance();
+      }
+
+      public function openDescription():void {
+          trace("open description here");
+      }
+  ]]></mx:Script>
+</mx:VBox>
+
index e1f20d1..4cf6f8a 100755 (executable)
@@ -8,6 +8,7 @@ package net.systemeD.halcyon {
        import flash.text.GridFitType;
        import flash.text.TextField;
        import flash.text.TextFormat;
+       import flash.events.*;
        import net.systemeD.halcyon.styleparser.*;
     import net.systemeD.halcyon.connection.*;
 
@@ -21,6 +22,7 @@ package net.systemeD.halcyon {
                public var layer:int=0;                                         // map layer
                public var map:Map;                                                     // reference to parent map
                public var sprites:Array=new Array();           // instances in display list
+        private var hitzone:Sprite;
 
                public static const DEFAULT_TEXTFIELD_PARAMS:Object = {
                        embedFonts: true,
@@ -89,7 +91,7 @@ package net.systemeD.halcyon {
 
                        // remove all currently existing sprites
                        while (sprites.length>0) {
-                               var d:Sprite=sprites.pop(); d.parent.removeChild(d);
+                               var d:DisplayObject=sprites.pop(); d.parent.removeChild(d);
                        }
 
                        // which layer?
@@ -102,14 +104,14 @@ package net.systemeD.halcyon {
                        for each (var s:* in styles) {
 
                                if (s is ShapeStyle) {
-                                       var stroke:Sprite, fill:Sprite, roadname:Sprite, f:Graphics, g:Graphics;
+                                       var stroke:Shape, fill:Shape, roadname:Sprite, f:Graphics, g:Graphics;
                                        var doStroke:Boolean=false, doDashed:Boolean=false;
                                        var doFill:Boolean=false, fill_colour:uint, fill_opacity:Number;
                                        var doCasing:Boolean=false, doDashedCasing:Boolean=false;
 
                                        // Set stroke style
                                        if (s.isStroked)  {
-                                               stroke=new Sprite(); addToLayer(stroke,1,s.sublayer); g=stroke.graphics;
+                                               stroke=new Shape(); addToLayer(stroke,1,s.sublayer); g=stroke.graphics;
                                g.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp));
                                                g.lineStyle(s.stroke_width, s.stroke_colour, s.stroke_opacity/100,
                                                                        false, "normal", s.stroke_linecap, s.stroke_linejoin);
@@ -117,7 +119,7 @@ package net.systemeD.halcyon {
 
                                        // Set fill and casing style
                                        if (s.isFilled || s.isCased) {
-                                               fill=new Sprite(); addToLayer(fill,0); f=fill.graphics;
+                                               fill=new Shape(); addToLayer(fill,0); f=fill.graphics;
                                f.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp));
                                                if (s.isCased)  { f.lineStyle(s.casing_width, s.casing_colour, s.casing_opacity/100,
                                                                                  false, "normal", s.stroke_linecap, s.stroke_linejoin); }
@@ -151,6 +153,32 @@ package net.systemeD.halcyon {
                                        // ** to do
                                }
                        }
+
+            if ( styles.length == 0 ) {
+                // there's no styles... so add a thin trace
+                var def:Sprite = new Sprite();
+                def.graphics.lineStyle(0.5, 0x808080, 1, false, "normal");
+                solidLine(def.graphics);
+                addToLayer(def, 1);
+            }
+
+            // create a generic "way" hitzone sprite
+            hitzone = new Sprite();
+            hitzone.graphics.lineStyle(4, 0x000000, 1, false, "normal", CapsStyle.ROUND, JointStyle.ROUND);
+            solidLine(hitzone.graphics);
+            addToLayer(hitzone, 2);
+            hitzone.visible = false;
+
+            var listenSprite:Sprite = new Sprite();
+            listenSprite.hitArea = hitzone;
+            addToLayer(listenSprite, 2);
+            listenSprite.buttonMode = true;
+            listenSprite.mouseEnabled = true;
+            listenSprite.addEventListener(MouseEvent.CLICK, mouseEvent);
+            listenSprite.addEventListener(MouseEvent.DOUBLE_CLICK, mouseEvent);
+            listenSprite.addEventListener(MouseEvent.MOUSE_OVER, mouseEvent);
+            listenSprite.addEventListener(MouseEvent.MOUSE_OUT, mouseEvent);
+
                }
                
                // ------------------------------------------------------------------------------------------
@@ -284,6 +312,8 @@ package net.systemeD.halcyon {
                private function rotatedLetter(char:String, t:Number, w:Number, h:Number, a:Number, o:Number):TextField {
                        var tf:TextField = new TextField();
                        tf.embedFonts = true;
+            tf.mouseEnabled = false;
+            tf.mouseWheelEnabled = false;
                        tf.defaultTextFormat = nameformat;
                        tf.text = char;
                        tf.width = tf.textWidth+4;
@@ -301,12 +331,21 @@ package net.systemeD.halcyon {
                
                // Add object (stroke/fill/roadname) to layer sprite
                
-               private function addToLayer(s:Sprite,t:uint,sublayer:int=-1):void {
+               private function addToLayer(s:DisplayObject,t:uint,sublayer:int=-1):void {
                        var l:DisplayObject=Map(map).getChildAt(layer);
                        var o:DisplayObject=Sprite(l).getChildAt(t);
                        if (sublayer!=-1) { o=Sprite(o).getChildAt(sublayer); }
                        Sprite(o).addChild(s);
                        sprites.push(s);
+            if ( s is Sprite ) Sprite(s).mouseEnabled = false;
                }
+
+        private function mouseEvent(event:MouseEvent):void {
+            map.wayMouseEvent(event, way);
+        }
+
+        public function setHighlight(highlight:Boolean):void {
+            hitzone.visible = highlight;
+        }
        }
 }
index 7078ad7..1836fa0 100644 (file)
@@ -44,6 +44,13 @@ package net.systemeD.halcyon.connection {
             return copy;
         }
 
+        public function getTagArray():Array {
+            var copy:Array = [];
+            for (var key:String in tags )
+                copy.push(new Tag(key, tags[key]));
+            return copy;
+        }
+
     }
 
 }
diff --git a/net/systemeD/halcyon/connection/Tag.as b/net/systemeD/halcyon/connection/Tag.as
new file mode 100644 (file)
index 0000000..76eee32
--- /dev/null
@@ -0,0 +1,15 @@
+package net.systemeD.halcyon.connection {
+
+    public class Tag {
+        public var key:String;
+        public var value:String;
+
+        public function Tag(key:String, value:String) {
+            this.key = key;
+            this.value = value;
+        }
+    }
+
+
+}
+
diff --git a/net/systemeD/halcyon/mapfeatures/MapFeatures.as b/net/systemeD/halcyon/mapfeatures/MapFeatures.as
new file mode 100644 (file)
index 0000000..82b114c
--- /dev/null
@@ -0,0 +1,64 @@
+package net.systemeD.halcyon.mapfeatures {
+
+    import flash.events.Event;
+    import flash.net.URLLoader;
+    import flash.net.URLRequest;
+
+       import flash.system.Security;
+       import flash.net.*;
+
+    import net.systemeD.halcyon.connection.*;
+
+
+       public class MapFeatures {
+        private static var instance:MapFeatures;
+
+        public static function getInstance():MapFeatures {
+            if ( instance == null ) {
+                instance = new MapFeatures();
+                instance.loadFeatures();
+            }
+            return instance;
+        }
+
+
+
+        private var xml:XML = null;
+
+        protected function loadFeatures():void {
+            var request:URLRequest = new URLRequest("map_features.xml");
+            var loader:URLLoader = new URLLoader();
+            loader.addEventListener(Event.COMPLETE, onFeatureLoad);
+            loader.load(request);
+        }
+
+        private function onFeatureLoad(event:Event):void {
+            xml = new XML(URLLoader(event.target).data);
+        }
+
+        public function hasLoaded():Boolean {
+            return xml != null;
+        }
+
+        public function findMatchingFeature(entity:Entity):XML {
+            if ( xml == null )
+                return null;
+
+            for each(var feature:XML in xml.feature) {
+                // 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 == "*");
+                    if ( !match ) break;
+                }
+                if ( match )
+                    return feature;
+            }
+            return null;
+        }
+    }
+
+}
+
+