Enlarge requested bbox by 20% on each side to make for easier panning; keep list...
[potlatch2.git] / net / systemeD / halcyon / MarkerUI.as
1 package net.systemeD.halcyon {
2
3     import flash.display.*;
4     import flash.events.*;
5     import flash.text.AntiAliasType;
6     import flash.text.GridFitType;
7     import flash.text.TextField;
8     import flash.text.TextFormat;
9     import flash.geom.Matrix;
10     import flash.geom.Point;
11     import net.systemeD.halcyon.styleparser.*;
12     import net.systemeD.halcyon.connection.*;
13
14     public class MarkerUI extends EntityUI {
15
16         public var loaded:Boolean=false;
17         private var iconnames:Object={};            // name of icon on each sublayer
18         private var heading:Number=0;               // heading within way
19         private var rotation:Number=0;              // rotation applied to this POI
20         private static const NO_LAYER:int=-99999;
21
22         public function MarkerUI(marker:Marker, paint:MapPaint, heading:Number=0, layer:int=NO_LAYER, stateClasses:Object=null) {
23             super(marker,paint);
24             if (layer==NO_LAYER) { this.layer=paint.maxlayer; } else { this.layer=layer; }
25             this.heading = heading;
26             if (stateClasses) {
27                 for (var state:String in stateClasses) {
28                     if (stateClasses[state]) { this.stateClasses[state]=stateClasses[state]; }
29                 }
30             }
31             entity.addEventListener(Connection.NODE_MOVED, markerMoved, false, 0, true);
32             entity.addEventListener(Connection.NODE_ALTERED, markerAltered, false, 0, true);
33             attachRelationListeners();
34             redraw();
35         }
36
37         public function removeEventListeners():void {
38             removeGenericEventListeners();
39             entity.removeEventListener(Connection.NODE_MOVED, markerMoved);
40             entity.removeEventListener(Connection.NODE_ALTERED, markerAltered);
41         }
42
43         public function markerMoved(event:Event):void {
44             updatePosition();
45         }
46
47         private function markerAltered(event:Event):void {
48             redraw();
49         }
50
51         override public function doRedraw():Boolean {
52             if (!paint.ready) { return false; }
53             if (entity.deleted) { return false; }
54
55             var tags:Object = entity.getTagsCopy();
56             setStateClass('poi', !entity.hasParentWays);
57             setStateClass('hasTags', entity.hasInterestingTags());
58             tags=applyStateClasses(tags);
59             if (!styleList || !styleList.isValidAt(paint.map.scale)) {
60                 styleList=paint.ruleset.getStyles(entity,tags,paint.map.scale);
61             }
62
63             var suggestedLayer:Number=styleList.layerOverride();
64             if (!isNaN(suggestedLayer)) { layer=suggestedLayer; }
65
66             var inWay:Boolean=entity.hasParentWays;
67             var hasStyles:Boolean=styleList.hasStyles();
68
69             removeSprites(); iconnames={};
70             return renderFromStyle(tags);
71         }
72
73         private function renderFromStyle(tags:Object):Boolean {
74             var r:Boolean=false;            // ** rendered
75             var maxwidth:Number=4;          // biggest width
76             var w:Number;
77             var icon:Sprite;
78             interactive=false;
79             for each (var sublayer:Number in styleList.sublayers) {
80
81                 if (styleList.pointStyles[sublayer]) {
82                     var s:PointStyle=styleList.pointStyles[sublayer];
83                     interactive||=s.interactive;
84                     r=true;
85                     if (s.rotation) { rotation=s.rotation; }
86                     if (s.icon_image!=iconnames[sublayer]) {
87                         if (s.icon_image=='square') {
88                             // draw square
89                             icon=new Sprite();
90                             addToLayer(icon,STROKESPRITE,sublayer);
91                             w=styleIcon(icon,sublayer);
92                             icon.graphics.drawRect(0,0,w,w);
93                             if (s.interactive) { maxwidth=Math.max(w,maxwidth); }
94                             iconnames[sublayer]='_square';
95
96                         } else if (s.icon_image=='circle') {
97                             // draw circle
98                             icon=new Sprite();
99                             addToLayer(icon,STROKESPRITE,sublayer);
100                             w=styleIcon(icon,sublayer);
101                             icon.graphics.drawCircle(w,w,w);
102                             if (s.interactive) { maxwidth=Math.max(w,maxwidth); }
103                             iconnames[sublayer]='_circle';
104
105                         } else if (paint.ruleset.images[s.icon_image]) {
106                             // 'load' icon (actually just from library)
107                             var loader:ExtendedLoader = new ExtendedLoader();
108                             loader.info['sublayer']=sublayer;
109                             loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadedIcon, false, 0, true);
110                             loader.loadBytes(paint.ruleset.images[s.icon_image]);
111                             iconnames[sublayer]=s.icon_image;
112                         }
113                     }
114                 }
115
116                 // name sprite
117                 var a:String='', t:TextStyle;
118                 if (styleList.textStyles[sublayer]) {
119                     t=styleList.textStyles[sublayer];
120                     interactive||=t.interactive;
121                     a=tags[t.text];
122                 }
123
124                 if (a) {
125                     var name:Sprite=new Sprite();
126                     addToLayer(name,NAMESPRITE);
127                     t.writeNameLabel(name,a,0,0);
128                     loaded=true;
129                 }
130             }
131             if (!r) { return false; }
132             if (interactive) { addHitSprite(maxwidth); }
133             updatePosition();
134             return true;
135         }
136
137
138         private function styleIcon(icon:Sprite, sublayer:Number):Number {
139             loaded=true;
140
141             // get colours
142             if (styleList.shapeStyles[sublayer]) {
143                 var s:ShapeStyle=styleList.shapeStyles[sublayer];
144                 if (!isNaN(s.color)) { icon.graphics.beginFill(s.color);
145                     }
146                 if (s.casing_width || !isNaN(s.casing_color)) {
147                     icon.graphics.lineStyle(s.casing_width ? s.casing_width : 1,
148                                             s.casing_color ? s.casing_color : 0,
149                                             s.casing_opacity ? s.casing_opacity : 1);
150                 }
151             }
152
153             // return width
154             return styleList.pointStyles[sublayer].icon_width;
155         }
156
157         private function addHitSprite(w:uint):void {
158             hitzone = new Sprite();
159             hitzone.graphics.lineStyle(4, 0x000000, 1, false, "normal", CapsStyle.ROUND, JointStyle.ROUND);
160             hitzone.graphics.beginFill(0);
161             hitzone.graphics.drawRect(0,0,w,w);
162             hitzone.visible = false;
163             setListenSprite();
164         }
165
166         private function loadedIcon(event:Event):void {
167             var icon:Sprite=new Sprite();
168             var sublayer:Number=event.target.loader.info['sublayer'];
169             addToLayer(icon,STROKESPRITE,sublayer);
170             icon.addChild(Bitmap(event.target.content));
171             addHitSprite(icon.width);
172             loaded=true;
173             updatePosition();
174         }
175
176         private function updatePosition():void {
177             if (!loaded) { return; }
178
179             for (var i:uint=0; i<sprites.length; i++) {
180                 var d:DisplayObject=sprites[i];
181                 d.x=0; d.y=0; d.rotation=0;
182
183                 var m:Matrix=new Matrix();
184                 m.translate(-d.width/2,-d.height/2);
185                 m.rotate(rotation);
186                 m.translate(paint.map.lon2coord(Marker(entity).lon),paint.map.latp2coord(Marker(entity).latp));
187                 d.transform.matrix=m;
188             }
189         }
190     }
191 }