Merge branch 'master' into history
[potlatch2.git] / net / systemeD / halcyon / styleparser / StyleChooser.as
1 package net.systemeD.halcyon.styleparser {
2
3         import net.systemeD.halcyon.connection.Entity;
4     import net.systemeD.halcyon.ImageBank;
5
6         public class StyleChooser {
7
8                 /*
9                         A StyleChooser object is equivalent to one CSS selector+declaration.
10
11                         Its ruleChains property is an array of all the selectors, which would
12                         traditionally be comma-separated. For example:
13                                 h1, h2, h3 em
14                         is three RuleChains.
15                         
16                         Each RuleChain is itself an array of nested selectors. So the above 
17                         example would roughly be encoded as:
18                                 [[h1],[h2],[h3,em]]
19                                   ^^   ^^   ^^ ^^   each of these is a Rule
20                                  ^^^^ ^^^^ ^^^^^^^  each of these is a RuleChain
21                                 
22                         The styles property is an array of all the style objects to be drawn
23                         if any of the ruleChains evaluate to true.
24
25                 */
26
27                 public var ruleChains:Array;                            // array of RuleChains (each one an array of Rules)
28                 public var styles:Array=[];                                     // array of ShapeStyle/ShieldStyle/TextStyle/PointStyle
29                 public var zoomSpecific:Boolean=false;          // are any of the rules zoom-specific?
30
31                 private var rcpos:uint;
32                 private var stylepos:uint=0;
33
34                 public function StyleChooser():void {
35                         ruleChains=[new RuleChain()];
36                         rcpos=0;
37                 }
38
39                 public function get currentChain():RuleChain {
40                         return ruleChains[rcpos];
41                 }
42                 
43                 // Update the current StyleList from this StyleChooser
44
45                 public function updateStyles(obj:Entity, tags:Object, sl:StyleList, zoom:uint):void {
46                         if (zoomSpecific) { sl.validAt=zoom; }
47
48                         // Are any of the ruleChains fulfilled?
49                         var w:Number;
50                         for each (var c:RuleChain in ruleChains) {
51                                 if (c.test(-1,obj,tags,zoom)) {
52                                         sl.addSubpart(c.subpart);
53
54                                         // Update StyleList
55                                         for (var i:uint=0; i<styles.length; i++) {
56                                                 var r:Style=styles[i];
57                                                 var a:Object;
58                                                 if (r is ShapeStyle) {
59                                                         a=sl.shapeStyles;
60                                                         if (ShapeStyle(r).width>sl.maxwidth && !r.evals['width']) { sl.maxwidth=ShapeStyle(r).width; }
61                                                 } else if (r is ShieldStyle) {
62                                                         a=sl.shieldStyles;
63                                                 } else if (r is TextStyle) { 
64                                                         a=sl.textStyles;
65                                                 } else if (r is PointStyle) { 
66                                                         a=sl.pointStyles;
67                                                         w=0;
68                                                         if (PointStyle(r).icon_width && !PointStyle(r).evals['icon_width']) {
69                                                                 // ** FIXME: we should check this is the bit being used for 'square', 'circle' etc.
70                                                                 w=PointStyle(r).icon_width;
71                                                         } else if (PointStyle(r).icon_image && ImageBank.getInstance().hasImage(PointStyle(r).icon_image)) {
72                                                                 w=ImageBank.getInstance().getWidth(PointStyle(r).icon_image);
73                                                         }
74                                                         if (w>sl.maxwidth) { sl.maxwidth=w; }
75                                                 } else if (r is InstructionStyle) {
76                                                         if (InstructionStyle(r).breaker) { return; }
77                                                         InstructionStyle(r).assignSetTags(tags);
78                                                         continue;
79                                                 }
80                                                 if (r.drawn) { tags[':drawn']='yes'; }
81                                                 tags['_width']=sl.maxwidth;
82                                 
83                                                 r.runEvals(tags);
84                                                 if (a[c.subpart]) {
85                                                         // If there's already a style on this sublayer, then merge them
86                                                         // (making a deep copy if necessary to avoid altering the root style)
87                                                         if (!a[c.subpart].merged) { a[c.subpart]=a[c.subpart].deepCopy(); }
88                                                         a[c.subpart].mergeWith(r);
89                                                 } else {
90                                                         // Otherwise, just assign it
91                                                         a[c.subpart]=r;
92                                                 }
93                                         }
94                                 }
95                         }
96                 }
97                 
98                 /** Cut-down version of updateStyles that runs InstructionStyles only - for CSSTransform usage. */
99
100                 public function runInstructions(obj:Entity, tags:Object):Object {
101                         for each (var c:RuleChain in ruleChains) {
102                                 if (c.test(-1,obj,tags,10)) {
103                                         for (var i:uint=0; i<styles.length; i++) {
104                                                 var r:Style=styles[i];
105                                                 if (r is InstructionStyle) {
106                                                         if (InstructionStyle(r).breaker) { return tags; }
107                                                         InstructionStyle(r).assignSetTags(tags);
108                                                 }
109                                                 r.runEvals(tags);
110                                         }
111                                 }
112                         }
113                         return tags;
114                 }
115                 
116                 
117                 // ---------------------------------------------------------------------------------------------
118                 // Methods to add properties (used by parsers such as MapCSS)
119                 
120                 // newRuleChain         <- starts a new ruleChain in this.ruleChains
121                 public function newRuleChain():void {
122                         if (ruleChains[rcpos].length>0) {
123                                 ruleChains[++rcpos]=new RuleChain();
124                         }
125                 }
126
127                 public function addStyles(a:Array):void {
128                         styles=styles.concat(a);
129                 }
130
131         }
132 }