1 /// Plot style handler
2 module plot2d.style;
3 
4 import plot2d.types;
5 
6 ///
7 interface ValueHandler(Key, Value)
8 {
9     ///
10     Value opIndex(Key);
11     ///
12     void opIndexAssign(Value, Key);
13     ///
14     Value get(Key, lazy Value);
15     ///
16     void set(Key, Value);
17 }
18 
19 ///
20 interface Style
21 {
22     ///
23     alias SVH(T) = ValueHandler!(string, T);
24     ///
25     Style getSubstyle(string name);
26 
27     @property
28     {
29         ///
30         SVH!double number();
31         ///
32         SVH!Color  color();
33         ///
34         SVH!string strval();
35     }
36 }
37 
38 ///
39 interface Stylized
40 {
41     /// get sub style from root and set style
42     final void setRootStyle(Style root)
43     { setStyle(root.getSubstyle(styleName)); }
44     ///
45     void setStyle(Style);
46 
47     @property
48     {
49         ///
50         string styleName();
51         ///
52         Style style();
53     }
54 
55     ///
56     mixin template StylizedHelper(string NAME="")
57     {
58         import std.exception : enforce;
59 
60         protected Style __style;
61         public override
62         {
63             void setStyle(Style s)
64             { __style = enforce(s, "style is null"); }
65 
66             @property
67             {
68                 string styleName() { return NAME; }
69                 Style style()
70                 {
71                     if (__style is null)
72                         __style = new PlainStyle(null);
73                     return __style;
74                 }
75             }
76         }
77     }
78 }
79 
80 ///
81 class PlainStyle : Style
82 {
83 protected:
84     ///
85     Style parent;
86 
87     ///
88     string trName(string parameter)
89     { return parameter; }
90 
91     class SVHP(Value, string fld) : SVH!Value
92     {
93         Value defaultValue;
94         Value[string] data;
95 
96         this(Value dv) { defaultValue = dv; }
97 
98     override:
99         ///
100         Value opIndex(string p)
101         {
102             if (this.outer.parent !is null)
103                 mixin("return this.outer.parent."
104                         ~fld~".opIndex(trName(p));");
105             else return data.get(p, defaultValue);
106         }
107         ///
108         void opIndexAssign(Value val, string p)
109         {
110             if (this.outer.parent !is null)
111                 mixin("this.outer.parent."~fld~
112                         ".opIndexAssign(val, trName(p));");
113             else data[p] = val;
114         }
115         ///
116         Value get(string p, lazy Value val)
117         {
118             if (this.outer.parent !is null)
119                 mixin("return this.outer.parent."
120                         ~fld~".get(trName(p), val);");
121             else return data.get(p, val);
122         }
123         ///
124         void set(string p, Value val)
125         {
126             if (this.outer.parent !is null)
127                 mixin("this.outer.parent."
128                         ~fld~".set(trName(p), val);");
129             else data[p] = val;
130         }
131     }
132 
133     SVH!double _number;
134     SVH!Color _color;
135     SVH!string _strval;
136 
137 public:
138 
139     ///
140     this(Style p)
141     {
142         parent = p;
143         _number = new SVHP!(double, "number")(0.0);
144         _color = new SVHP!(Color, "color")(Color.init);
145         _strval = new SVHP!(string, "strval")("");
146     }
147 
148     override
149     {
150         ///
151         Style getSubstyle(string name)
152         { return new PlainStyle(this); }
153 
154         @property
155         {
156             SVH!double number() { return _number; }
157             SVH!Color color() { return _color; }
158             SVH!string strval() { return _strval; }
159         }
160     }
161 }
162 
163 ///
164 class NSStyle : PlainStyle
165 {
166 protected:
167     /// namespace
168     string ns;
169 
170     ///
171     override string trName(string p)
172     {
173         if (p[0] == '.')
174         {
175             if (parent !is null) return p;
176             else return p[1..$];
177         }
178         else return ns ~ "." ~ p;
179     }
180 
181 public:
182 
183     ///
184     this() { super(null); }
185 
186     ///
187     this(NSStyle p, string n)
188     {
189         super(p);
190         ns = n;
191     }
192 
193     ///
194     override Style getSubstyle(string name)
195     { return new NSStyle(this, name); }
196 }
197 
198 /+ TODO parser
199 `
200 gridlabel:
201     fontsize: 15
202     fontface: Monospace
203     color: rgba(0,0,0,.8)
204 
205 axis:
206     linewidth: 1.5
207     color: rgba(0,0,0,.7)
208 
209 grid:
210     linewidth: 1
211     color: rgba(0,0,0,.2)
212 
213 chart:
214     linewidth: 2
215 
216 trechart > chart:
217     limlinewidth: 1
218     limlinealpha: 0.4
219     limfillalpha: 0.3
220 `
221 +/