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