1 package net.systemeD.halcyon {
3 import flash.display.Sprite;
4 import flash.display.DisplayObject;
5 import net.systemeD.halcyon.NodeUI;
6 import net.systemeD.halcyon.WayUI;
7 import net.systemeD.halcyon.connection.*;
8 import net.systemeD.halcyon.styleparser.RuleSet;
9 import net.systemeD.halcyon.Globals;
11 public class MapPaint extends Sprite {
14 public var minlayer:int;
15 public var maxlayer:int;
16 public var ruleset:RuleSet; // rules
17 public var wayuis:Object=new Object(); // sprites for ways and (POI/tagged) nodes
18 public var nodeuis:Object=new Object(); // |
19 public var markeruis:Object=new Object();
20 public var isBackground:Boolean = true; // is it a background layer or the core paint object?
21 public var sublayerIndex:Object={}; // hash of index->position
23 private const VERYBIG:Number=Math.pow(2,16);
24 private static const NO_LAYER:int=-99999; // same as NodeUI
28 public function MapPaint(map:Map,minlayer:int,maxlayer:int) {
32 this.minlayer=minlayer;
33 this.maxlayer=maxlayer;
38 for (l=minlayer; l<=maxlayer; l++) { // each layer (10 is +5, 0 is -5)
39 s = getPaintSprite(); // |
40 s.addChild(getPaintSprite()); // | 0 fill
41 s.addChild(getPaintSprite()); // | 1 casing
42 var t:Sprite = getPaintSprite(); // | 2 stroke
43 t.addChild(getPaintSprite()); // | | sublayer
45 s.addChild(getPaintSprite()); // | 3 names
50 for (l=minlayer; l<=maxlayer; l++) { // each layer (21 is +5, 11 is -5)
51 s = getHitSprite(); // |
52 s.addChild(getHitSprite()); // | 0 way hit tests
53 s.addChild(getHitSprite()); // | 1 node hit tests
58 public function getPaintSpriteAt(l:int):Sprite {
59 return getChildAt(l-minlayer) as Sprite;
62 public function getHitSpriteAt(l:int):Sprite {
63 return getChildAt((l-minlayer) + (maxlayer-minlayer+1)) as Sprite;
66 public function get ready():Boolean {
67 if (!ruleset) { return false; }
68 if (!ruleset.loaded) { return false; }
72 public function sublayer(layer:int,sublayer:Number):Sprite {
75 var index:String, ix:Number;
76 if (!sublayerIndex.hasOwnProperty(sublayer)) {
77 // work out which position to add at
78 var lowestAbove:Number=VERYBIG;
79 var lowestAbovePos:int=-1;
80 var indexLength:uint=0;
81 for (index in sublayerIndex) {
83 if (ix>sublayer && ix<lowestAbove) {
85 lowestAbovePos=sublayerIndex[index];
89 if (lowestAbovePos==-1) { lowestAbovePos=indexLength; }
92 for (var i:int=minlayer; i<=maxlayer; i++) {
93 l=getChildAt(i-minlayer);
94 o=(l as Sprite).getChildAt(2);
95 (o as Sprite).addChildAt(getPaintSprite(),lowestAbovePos);
99 // (we do it in this rather indirect way because if you alter sublayerIndex directly
100 // within the loop, it confuses the iterator)
101 var toUpdate:Array=[];
102 for (index in sublayerIndex) {
104 if (ix>sublayer) { toUpdate.push(index); }
106 for each (index in toUpdate) { sublayerIndex[index]++; }
107 sublayerIndex[sublayer]=lowestAbovePos;
110 l=getChildAt(layer-minlayer);
111 o=(l as Sprite).getChildAt(2);
112 return ((o as Sprite).getChildAt(sublayerIndex[sublayer]) as Sprite);
116 * Update, and if necessary, create / remove UIs for the given objects.
117 * The object is effectively lists of objects split into inside/outside pairs, e.g.
118 * { waysInside: [], waysOutside: [] } where each is a array of entities either inside
119 * or outside this current view window. UIs for the entities on "inside" lists will be created if necessary.
120 * Flags control redrawing existing entities and removing UIs from entities no longer in view.
122 * @param o The object containing all the relevant entites.
123 * @param redraw If true, all UIs for entities on "inside" lists will be redrawn
124 * @param remove If true, all UIs for entites on "outside" lists will be removed. The purgable flag on UIs
125 can override this, for example for selected objects.
127 public function updateEntityUIs(o:Object, redraw:Boolean, remove:Boolean):void {
128 var way:Way, poi:Node, marker:Marker;
130 for each (way in o.waysInside) {
131 if (!wayuis[way.id]) { createWayUI(way); }
132 else if (redraw) { wayuis[way.id].recalculate(); wayuis[way.id].redraw(); }
136 for each (way in o.waysOutside) {
137 if (wayuis[way.id] && !wayuis[way.id].purgable) {
138 if (redraw) { wayuis[way.id].recalculate(); wayuis[way.id].redraw(); }
145 for each (poi in o.poisInside) {
146 if (!nodeuis[poi.id]) { createNodeUI(poi); }
147 else if (redraw) { nodeuis[poi.id].redraw(); }
151 for each (poi in o.poisOutside) {
152 if (nodeuis[poi.id] && !nodeuis[poi.id].purgable) {
153 if (redraw) { nodeuis[poi.id].redraw(); }
160 for each (marker in o.markersInside) {
161 if (!markeruis[marker.id]) { createMarkerUI(marker); }
162 else if (redraw) { markeruis[marker.id].redraw(); }
166 for each (marker in o.markersOutside) {
167 if (markeruis[marker.id] && !markeruis[marker.id].purgable) {
168 if (redraw) { markeruis[marker.id].redraw(); }
170 deleteMarkerUI(marker);
176 public function createWayUI(way:Way):WayUI {
177 if (!wayuis[way.id]) {
178 wayuis[way.id]=new WayUI(way,this);
179 way.addEventListener(Connection.WAY_DELETED, wayDeleted);
181 return wayuis[way.id];
184 public function wayDeleted(event:EntityEvent):void {
185 deleteWayUI(event.entity as Way);
188 public function deleteWayUI(way:Way):void {
189 way.removeEventListener(Connection.WAY_DELETED, wayDeleted);
190 if (wayuis[way.id]) {
191 wayuis[way.id].redrawMultis();
192 wayuis[way.id].removeSprites();
193 wayuis[way.id].removeEventListeners();
194 delete wayuis[way.id];
196 for (var i:uint=0; i<way.length; i++) {
197 var node:Node=way.getNode(i);
198 if (nodeuis[node.id]) { deleteNodeUI(node); }
202 public function createNodeUI(node:Node,rotation:Number=0,layer:int=NO_LAYER,stateClasses:Object=null):NodeUI {
203 if (!nodeuis[node.id]) {
204 nodeuis[node.id]=new NodeUI(node,this,rotation,layer,stateClasses);
205 node.addEventListener(Connection.NODE_DELETED, nodeDeleted);
207 for (var state:String in stateClasses) {
208 nodeuis[node.id].setStateClass(state,stateClasses[state]);
210 nodeuis[node.id].redraw();
212 return nodeuis[node.id];
215 public function nodeDeleted(event:EntityEvent):void {
216 deleteNodeUI(event.entity as Node);
219 public function deleteNodeUI(node:Node):void {
220 if (!nodeuis[node.id]) { return; }
221 node.removeEventListener(Connection.NODE_DELETED, nodeDeleted);
222 nodeuis[node.id].removeSprites();
223 nodeuis[node.id].removeEventListeners();
224 delete nodeuis[node.id];
227 public function createMarkerUI(marker:Marker,rotation:Number=0,layer:int=NO_LAYER,stateClasses:Object=null):MarkerUI {
228 if (!markeruis[marker.id]) {
229 markeruis[marker.id]=new MarkerUI(marker,this,rotation,layer,stateClasses);
230 marker.addEventListener(Connection.NODE_DELETED, markerDeleted);
232 for (var state:String in stateClasses) {
233 markeruis[marker.id].setStateClass(state,stateClasses[state]);
235 markeruis[marker.id].redraw();
237 return markeruis[marker.id];
240 public function markerDeleted(event:EntityEvent):void {
241 deleteMarkerUI(event.entity as Marker);
244 public function deleteMarkerUI(marker:Marker):void {
245 if (!markeruis[marker.id]) { return; }
246 marker.removeEventListener(Connection.NODE_DELETED, markerDeleted);
247 markeruis[marker.id].removeSprites();
248 markeruis[marker.id].removeEventListeners();
249 delete markeruis[marker.id];
252 public function renumberWayUI(way:Way,oldID:Number):void {
253 if (!wayuis[oldID]) { return; }
254 wayuis[way.id]=wayuis[oldID];
255 delete wayuis[oldID];
258 public function renumberNodeUI(node:Node,oldID:Number):void {
259 if (!nodeuis[oldID]) { return; }
260 nodeuis[node.id]=nodeuis[oldID];
261 delete nodeuis[oldID];
264 private function getPaintSprite():Sprite {
265 var s:Sprite = new Sprite();
266 s.mouseEnabled = false;
267 s.mouseChildren = false;
271 private function getHitSprite():Sprite {
272 var s:Sprite = new Sprite();
276 public function redraw():void {
277 for each (var w:WayUI in wayuis) { w.recalculate(); w.invalidateStyleList(); w.redraw(); }
278 /* sometimes (e.g. in Map.setStyle) Mappaint.redrawPOIs() is called immediately afterwards anyway. FIXME? */
279 for each (var p:NodeUI in nodeuis) { p.invalidateStyleList(); p.redraw(); }
282 public function redrawPOIs():void {
283 for each (var p:NodeUI in nodeuis) { p.invalidateStyleList(); p.redraw(); }
286 public function findSource():VectorLayer {
288 for each (v in map.vectorlayers) {
289 if (v.paint==this) { return v; }