Update all layers when jumping to a place, and mark updateCoord methods as private...
[potlatch2.git] / net / systemeD / halcyon / EntityUI.as
1 package net.systemeD.halcyon {
2
3         import flash.display.*;
4         import flash.events.MouseEvent;
5         import flash.text.AntiAliasType;
6         import flash.text.GridFitType;
7         import net.systemeD.halcyon.styleparser.StyleList;
8     import net.systemeD.halcyon.connection.*;
9
10         /** Parent class of representations of map Entities, with properties about how they should be drawn. */ 
11         public class EntityUI {
12
13                 /** The entity represented by this class. */
14                 protected var entity:Entity;
15                 /** Current StyleList for this entity. */
16                 protected var styleList:StyleList;
17                 /** Instances in display list */
18                 protected var sprites:Array=new Array();
19                 /** The clickable sprite that will receive events. */
20                 protected var listenSprite:Sprite=new Sprite();
21                 /** Hitzone for the sprite - must be set by subclass-specific code. */
22                 protected var hitzone:Sprite;
23                 /** Special context-sensitive classes such as :hover. */
24                 protected var stateClasses:Object=new Object();
25                 /** Map layer */
26                 protected var layer:Number=0;
27                 /** Is drawing suspended? */
28                 protected var suspended:Boolean=false;  
29                 /** Redraw called while suspended? */
30                 protected var redrawDue:Boolean=false;
31                 /** Sprite to clear back to */
32                 protected var clearLimit:uint=0;
33                 /** Reference to parent MapPaint */
34                 public var paint:MapPaint;      
35                 /** Does object respond to clicks? */
36                 public var interactive:Boolean=true;
37                 /** Can it be deleted when offscreen? */
38                 public var purgable:Boolean=true;
39
40                 protected const FILLSPRITE:uint=0;
41                 protected const CASINGSPRITE:uint=1;
42                 protected const STROKESPRITE:uint=2;
43                 protected const NAMESPRITE:uint=3;
44                 protected const WAYCLICKSPRITE:uint=0;
45                 protected const NODECLICKSPRITE:uint=1;
46
47                 public static const DEFAULT_TEXTFIELD_PARAMS:Object = {
48                         embedFonts: true,
49                         antiAliasType: AntiAliasType.ADVANCED,
50                         gridFitType: GridFitType.NONE
51                 };
52
53                 /** Constructor function, adds a bunch of event listeners. */
54                 public function EntityUI(entity:Entity, paint:MapPaint) {
55                         this.entity=entity;
56                         this.paint=paint;
57             entity.addEventListener(Connection.TAG_CHANGED, tagChanged, false, 0, true);
58             entity.addEventListener(Connection.STATUS_CHANGED, statusChanged, false, 0, true);
59                         entity.addEventListener(Connection.ADDED_TO_RELATION, relationAdded, false, 0, true);
60                         entity.addEventListener(Connection.REMOVED_FROM_RELATION, relationRemoved, false, 0, true);
61                         entity.addEventListener(Connection.SUSPEND_REDRAW, suspendRedraw, false, 0, true);
62                         entity.addEventListener(Connection.RESUME_REDRAW, resumeRedraw, false, 0, true);
63                         listenSprite.addEventListener(MouseEvent.CLICK, mouseEvent, false, 0, true);
64                         listenSprite.addEventListener(MouseEvent.DOUBLE_CLICK, mouseEvent, false, 0, true);
65                         listenSprite.addEventListener(MouseEvent.ROLL_OVER, mouseEvent, false, 0, true);
66                         listenSprite.addEventListener(MouseEvent.MOUSE_OUT, mouseEvent, false, 0, true);
67                         listenSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseEvent, false, 0, true);
68                         listenSprite.addEventListener(MouseEvent.MOUSE_UP, mouseEvent, false, 0, true);
69                         listenSprite.addEventListener(MouseEvent.MOUSE_MOVE, mouseEvent, false, 0, true);
70                 }
71
72                 /** Remove the default event listeners. */
73                 protected function removeGenericEventListeners():void {
74             entity.removeEventListener(Connection.TAG_CHANGED, tagChanged);
75             entity.removeEventListener(Connection.STATUS_CHANGED, statusChanged);
76                         entity.removeEventListener(Connection.ADDED_TO_RELATION, relationAdded);
77                         entity.removeEventListener(Connection.REMOVED_FROM_RELATION, relationRemoved);
78                         entity.removeEventListener(Connection.SUSPEND_REDRAW, suspendRedraw);
79                         entity.removeEventListener(Connection.RESUME_REDRAW, resumeRedraw);
80                         listenSprite.removeEventListener(MouseEvent.CLICK, mouseEvent);
81                         listenSprite.removeEventListener(MouseEvent.DOUBLE_CLICK, mouseEvent);
82                         listenSprite.removeEventListener(MouseEvent.ROLL_OVER, mouseEvent);
83                         listenSprite.removeEventListener(MouseEvent.MOUSE_OUT, mouseEvent);
84                         listenSprite.removeEventListener(MouseEvent.MOUSE_DOWN, mouseEvent);
85                         listenSprite.removeEventListener(MouseEvent.MOUSE_UP, mouseEvent);
86                         listenSprite.removeEventListener(MouseEvent.MOUSE_MOVE, mouseEvent);
87                 }
88
89                 // -----------------------------------------------------------------
90                 // Event listeners
91                 
92                 protected function attachRelationListeners():void {
93                     var relations:Array = entity.parentRelations;
94             for each(var relation:Relation in relations ) {
95                 relation.addEventListener(Connection.TAG_CHANGED, relationTagChanged, false, 0, true);
96             }
97                 }
98
99                 protected function removeRelationListeners():void {
100                         var relations:Array = entity.parentRelations;
101             for each(var relation:Relation in relations) {
102                 relation.removeEventListener(Connection.TAG_CHANGED, relationTagChanged);
103             }
104                 }
105
106                 protected function relationAdded(event:RelationMemberEvent):void {
107                     event.relation.addEventListener(Connection.TAG_CHANGED, relationTagChanged, false, 0, true);
108                         invalidateStyleList();
109                     redraw();
110                 }
111                 
112                 protected function relationRemoved(event:RelationMemberEvent):void {
113                     event.relation.removeEventListener(Connection.TAG_CHANGED, relationTagChanged);
114                         invalidateStyleList();
115                     redraw();
116                 }
117                 
118         protected function tagChanged(event:TagEvent):void {
119                         invalidateStyleList();
120             redraw();
121         }
122
123         protected function relationTagChanged(event:TagEvent):void {
124                         invalidateStyleList();
125             redraw();
126         }
127                 
128         protected function statusChanged(event:EntityEvent):void {
129                         invalidateStyleList();
130             redraw();
131         }
132
133         protected function mouseEvent(event:MouseEvent):void {
134                         paint.map.entityMouseEvent(event, entity);
135         }
136
137
138                 // -----------------------------------------------------------------
139
140                 /** Add object (stroke/fill/roadname) to layer sprite*/
141                 
142                 protected function addToLayer(s:DisplayObject,spritetype:uint,sublayer:int=-1):void {
143                         var l:Sprite, o:Sprite;
144                         if (sublayer!=-1) {
145                                 o=paint.sublayer(layer,spritetype,sublayer);
146                         } else {
147                                 l=paint.getPaintSpriteAt(layer);
148                                 o=l.getChildAt(spritetype) as Sprite;
149                         }
150                         o.addChild(s);
151                         if (sprites.indexOf(s)==-1) { sprites.push(s); }
152             if ( s is Sprite ) {
153                 Sprite(s).mouseChildren = false;
154                 Sprite(s).mouseEnabled = false;
155             }
156                 }
157
158                 protected function setListenSprite():void {
159                         var l:Sprite=paint.getHitSpriteAt(layer);
160                         var s:Sprite;
161                         if (entity is Way) { s=l.getChildAt(0) as Sprite; }
162                                       else { s=l.getChildAt(1) as Sprite; }
163                         
164                         if (hitzone) {
165                                 if (!listenSprite.parent) { s.addChild(listenSprite); if (sprites.indexOf(listenSprite)==-1) { sprites.push(listenSprite); } }
166                                 if (!hitzone.parent)      { s.addChild(hitzone     ); if (sprites.indexOf(hitzone     )==-1) { sprites.push(hitzone     ); } }
167                                 listenSprite.hitArea = hitzone;
168                                 listenSprite.buttonMode = true;
169                                 listenSprite.mouseChildren = true;
170                                 listenSprite.mouseEnabled = true;
171                         } else if (listenSprite.parent) { 
172                                 listenSprite.parent.removeChild(listenSprite);
173                         }
174                 }
175
176                 /** Remove all sprites associated with this entity, and clear hitzone. */
177                 public function removeSprites():void {
178                         while (sprites.length>clearLimit) {
179                                 var d:DisplayObject=sprites.pop();
180                                 if (d.parent) { d.parent.removeChild(d); }
181                         }
182                         if (clearLimit==0) {
183                                 listenSprite.hitArea=null;
184                                 hitzone=null;
185                         }
186                 }
187                 
188                 public function removeListenSprite():void {
189                         if (listenSprite && listenSprite.parent) listenSprite.parent.removeChild(listenSprite);
190                         if (hitzone && hitzone.parent) hitzone.parent.removeChild(hitzone);
191                         listenSprite=null;
192                         hitzone=null;
193                 }
194                 
195                 public function protectSprites():void { clearLimit=sprites.length; }
196                 public function unprotectSprites():void { clearLimit=0; }
197
198                 protected function offsetSprites(x:Number, y:Number):void {
199                         for each (var d:DisplayObject in sprites) {
200                                 d.x=x; d.y=y;
201                         }
202                 }
203
204         public function setHighlight(settings:Object):void {
205                         var changed:Boolean=false;
206                         for (var stateType:String in settings) {
207                                 if (setStateClass(stateType, settings[stateType])) { changed=true; }
208                         }
209                         if (changed) redraw();
210         }
211
212         /**
213         * Sets a state class (eg :hover, :dupe) for this entityUI. If the state class has changed it will
214         * invalidate the style list to force the style to be recalculated during redraw.
215         */
216         public function setStateClass(stateType:String, isOn:*):Boolean {
217                         if ( isOn == true ) { isOn='yes'; }
218             if ( isOn && stateClasses[stateType] != isOn ) {
219                 stateClasses[stateType] = isOn;
220                                 invalidateStyleList();
221                                 return true;
222             } else if ( !isOn && stateClasses[stateType] != null ) {
223                 delete stateClasses[stateType];
224                                 invalidateStyleList();
225                                 return true;
226             }
227                         return false;
228         }
229
230         /**
231         * applies the state classes (eg :hover, :area) for this entityUI to the given list of 'real' tags.
232         * This then gives you a modified list of tags used for styling the entityUI.
233         */
234                 public function applyStateClasses(tags:Object):Object {
235             for (var stateKey:String in stateClasses) {
236                 tags[":"+stateKey] = 'yes';
237             }
238                         return tags;
239                 }
240                 
241                 public function toString():String {
242                         return "[EntityUI "+entity+"]";
243                 }
244
245                 /** Request redraw */
246                 
247                 public function redraw():Boolean {
248                         if (suspended) { redrawDue=true; return false; }
249                         return doRedraw();
250                 }
251                 
252                 /** Actually do the redraw. To be overwritten. */
253                 public function doRedraw():Boolean {
254                         return false;
255                 }
256                 
257                 /** Temporarily suspend redrawing of object. */
258                 public function suspendRedraw(event:EntityEvent):void {
259                         suspended=true;
260                         redrawDue=false;
261                 }
262                 
263                 /** Resume redrawing. */
264                 public function resumeRedraw(event:EntityEvent):void {
265                         suspended=false;
266                         if (redrawDue) { 
267                                 doRedraw();
268                                 redrawDue=false;
269                         }
270                 }
271                 
272                 public function invalidateStyleList():void {
273                         styleList=null;
274                 }
275                 
276         }
277
278 }