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