refactor node stateClasses and stylelist calculation
[potlatch2.git] / net / systemeD / halcyon / MapPaint.as
1 package net.systemeD.halcyon {
2
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.Node;
8         import net.systemeD.halcyon.connection.Way;
9         import net.systemeD.halcyon.styleparser.RuleSet;
10         import net.systemeD.halcyon.Globals;
11
12     public class MapPaint extends Sprite {
13
14                 public var map:Map;
15                 public var minlayer:int;
16                 public var maxlayer:int;
17                 public var ruleset:RuleSet;                                             // rules
18                 public var wayuis:Object=new Object();                  // sprites for ways and (POI/tagged) nodes
19                 public var nodeuis: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
22
23                 private const VERYBIG:Number=Math.pow(2,16);
24
25                 // Set up layering
26                 // [layer][3]                   - names
27                 // [layer][2][sublayer] - stroke
28                 // [layer][1]                   - casing
29                 // [layer][0]                   - fill
30
31                 public function MapPaint(map:Map,minlayer:int,maxlayer:int) {
32                         this.map=map;
33                         this.minlayer=minlayer;
34                         this.maxlayer=maxlayer;
35                         sublayerIndex[1]=0;
36
37                         for (var l:int=minlayer; l<=maxlayer; l++) {    // each layer (10 is +5, 0 is -5)
38                                 var s:Sprite = getHitSprite();                  //  |
39                                 s.addChild(getPaintSprite());                           //      | 0 fill
40                                 s.addChild(getPaintSprite());                           //      | 1 casing
41                                 var t:Sprite = getPaintSprite();                        //  | 2 stroke
42                                 t.addChild(getPaintSprite());                           //  |  | sublayer
43                                 s.addChild(t);                                                          //  |  |
44                                 s.addChild(getPaintSprite());                           //      | 3 names
45                                 s.addChild(getHitSprite());                                     //      | 4 way hit tests
46                                 s.addChild(getHitSprite());                                 //  | 5 node hit tests
47                                 addChild(s);                                                            //  |
48                         }
49                         addChild(getPaintSprite());                                     // name sprite
50                 }
51                 
52                 public function get ready():Boolean {
53                         if (!ruleset) { return false; }
54                         if (!ruleset.loaded) { return false; }
55                         return true;
56                 }
57
58                 public function sublayer(layer:int,sublayer:Number):Sprite {
59                         var l:DisplayObject;
60                         var o:DisplayObject;
61                         var index:String, ix:Number;
62                         if (!sublayerIndex.hasOwnProperty(sublayer)) {
63                                 // work out which position to add at
64                                 var lowestAbove:Number=VERYBIG;
65                                 var lowestAbovePos:int=-1;
66                                 var indexLength:uint=0;
67                                 for (index in sublayerIndex) {
68                                         ix=Number(index);
69                                         if (ix>sublayer && ix<lowestAbove) {
70                                                 lowestAbove=ix;
71                                                 lowestAbovePos=sublayerIndex[index];
72                                         }
73                                         indexLength++;
74                                 }
75                                 if (lowestAbovePos==-1) { lowestAbovePos=indexLength; }
76                         
77                                 // add sprites
78                                 for (var i:int=minlayer; i<=maxlayer; i++) {
79                                         l=getChildAt(i-minlayer);
80                                         o=(l as Sprite).getChildAt(2);
81                                         (o as Sprite).addChildAt(getPaintSprite(),lowestAbovePos);
82                                 }
83                         
84                                 // update index
85                                 // (we do it in this rather indirect way because if you alter sublayerIndex directly
86                                 //  within the loop, it confuses the iterator)
87                                 var toUpdate:Array=[];
88                                 for (index in sublayerIndex) {
89                                         ix=Number(index);
90                                         if (ix>sublayer) { toUpdate.push(index); }
91                                 }
92                                 for each (index in toUpdate) { sublayerIndex[index]++; }
93                                 sublayerIndex[sublayer]=lowestAbovePos;
94                         }
95
96                         l=getChildAt(layer-minlayer);
97                         o=(l as Sprite).getChildAt(2);
98                         return ((o as Sprite).getChildAt(sublayerIndex[sublayer]) as Sprite);
99                 }
100
101                 public function updateEntityUIs(o:Object, redraw:Boolean, remove:Boolean):void {
102                         var way:Way, node:Node;
103
104                         for each (way in o.waysInside) {
105                                 if (!wayuis[way.id]) { createWayUI(way); }
106                                 else if (redraw) { wayuis[way.id].recalculate(); wayuis[way.id].redraw(); }
107                         }
108
109                         if (remove) {
110                                 for each (way in o.waysOutside) {
111                                         if (wayuis[way.id] && !wayuis[way.id].purgable) {
112                                                 if (redraw) { wayuis[way.id].recalculate(); wayuis[way.id].redraw(); }
113                                         } else {
114                                                 deleteWayUI(way);
115                                         }
116                                 }
117                         }
118
119                         for each (node in o.nodesInside) {
120                                 if (!nodeuis[node.id]) { createNodeUI(node); }
121                                 else if (redraw) { nodeuis[node.id].redraw(); }
122                         }
123
124                         if (remove) {
125                                 for each (node in o.nodesOutside) { 
126                                         if (nodeuis[node.id] && !nodeuis[node.id].purgable) {
127                                                 if (redraw) { nodeuis[node.id].redraw(); }
128                                         } else {
129                                                 deleteNodeUI(node);
130                                         }
131                                 }
132                         }
133                 }
134
135                 public function createWayUI(way:Way):WayUI {
136                         if (!wayuis[way.id]) { wayuis[way.id]=new WayUI(way,this); }
137                         return wayuis[way.id];
138                 }
139
140                 public function createNodeUI(node:Node):NodeUI {
141                         if (!nodeuis[node.id]) { nodeuis[node.id]=new NodeUI(node,this,0); }
142                         return nodeuis[node.id];
143                 }
144
145                 public function deleteWayUI(way:Way):void {
146                         if (!wayuis[way.id]) { return; }
147                         wayuis[way.id].removeSprites();
148                         delete wayuis[way.id];
149                         for (var i:uint=0; i<way.length; i++) {
150                                 var node:Node=way.getNode(i);
151                                 if (nodeuis[node.id]) { deleteNodeUI(node); }
152                         }
153                 }
154
155                 public function deleteNodeUI(node:Node):void {
156                         if (!nodeuis[node.id]) { return; }
157                         if (!nodeuis[node.id].purgable) { return; }
158                         nodeuis[node.id].removeSprites();
159                         delete nodeuis[node.id];
160                 }
161                 
162                 public function renumberWayUI(way:Way,oldID:Number):void {
163                         if (!wayuis[oldID]) { return; }
164                         wayuis[way.id]=wayuis[oldID];
165                         delete wayuis[oldID];
166                 }
167
168                 public function renumberNodeUI(node:Node,oldID:Number):void {
169                         if (!nodeuis[oldID]) { return; }
170                         nodeuis[node.id]=nodeuis[oldID];
171                         delete nodeuis[oldID];
172                 }
173
174         private function getPaintSprite():Sprite {
175             var s:Sprite = new Sprite();
176             s.mouseEnabled = false;
177             s.mouseChildren = false;
178             return s;
179         }
180
181         private function getHitSprite():Sprite {
182             var s:Sprite = new Sprite();
183             return s;
184         }
185
186                 public function redraw():void {
187                         for each (var w:WayUI in wayuis) { w.recalculate(); w.redraw(); }
188                         for each (var p:NodeUI in nodeuis) { p.redraw(); }
189                 }
190
191                 public function redrawPOIs():void {
192                         for each (var p:NodeUI in nodeuis) { p.redraw(); }
193                 }
194                 
195                 public function findSource():VectorLayer {
196                         var v:VectorLayer;
197                         for each (v in map.vectorlayers) {
198                                 if (v.paint==this) { return v; }
199                         }
200                         return null;
201                 }
202         }
203 }