1 module formoshlep.widget;
2 
3 import tags = dhtags.tags;
4 import attrs = dhtags.attrs;
5 import dhtags.tags.tag: HtmlTag, HtmlString, HtmlAttribute;
6 import vibe.http.server: HTTPServerRequest;
7 import std.conv: to;
8 import dlangui.core.events;
9 import openmethods;
10 mixin(registerMethods);
11 
12 package:
13 
14 struct FormoEvent
15 {
16     KeyEvent keyEvent;
17     MouseEvent mouseEvent;
18 }
19 
20 // Custom Widget methods:
21 void readState(virtual!Widget, HTTPServerRequest);
22 FormoEvent[] getEvents(virtual!Widget, HTTPServerRequest);
23 HtmlTag toHtml(virtual!Widget);
24 
25 void readWidgetsState(Widget w, HTTPServerRequest req)
26 {
27     if(!w.enabled)
28         return;
29 
30     w.readState(req);
31 
32     for(auto i = 0; i < w.childCount; i++)
33         w.child(i).readWidgetsState(req);
34 }
35 
36 void processEvents(Widget w, HTTPServerRequest req)
37 {
38     if(!w.enabled)
39         return;
40 
41     FormoEvent[] events = w.getEvents(req);
42 
43     foreach(e; events)
44     {
45         if(e.keyEvent !is null)
46             w.onKeyEvent(e.keyEvent);
47 
48         if(e.mouseEvent !is null)
49             w.onMouseEvent(e.mouseEvent);
50     }
51 
52     for(auto i = 0; i < w.childCount; i++)
53         w.child(i).processEvents(req);
54 }
55 
56 public:
57 
58 // Custom methods implementation:
59 import dlangui.widgets.widget: Widget;
60 @method void _readState(Widget w, HTTPServerRequest req) {}
61 @method FormoEvent[] _getEvents(Widget w, HTTPServerRequest req) { return null; }
62 @method HtmlTag _toHtml(Widget w) { assert(false, "HTML output isn't implemented"); }
63 
64 import dlangui.widgets.controls: TextWidget;
65 @method HtmlTag _toHtml(TextWidget w)
66 {
67     return tags.span(w.text.to!string).addStyle(w);
68 }
69 
70 import dlangui.widgets.editors: EditLine;
71 @method void _readState(EditLine w, HTTPServerRequest req)
72 {
73     if(req.form.get(w.id, "IMPOSSIBLE_VALUE") != "IMPOSSIBLE_VALUE") //FIXME: remove that shit
74         w.text = req.form.get(w.id).to!dstring;
75 }
76 @method FormoEvent[] _getEvents(EditLine w, HTTPServerRequest req)
77 {
78     import std.exception: enforce;
79 
80     enforce(w.action is null);
81 
82     return null;
83 }
84 @method HtmlTag _toHtml(EditLine w)
85 {
86     return tags.input(attrs.type="text", attrs.name=w.id, attrs.value=w.text.to!string).addStyle(w);
87 }
88 
89 import dlangui.widgets.controls: CheckBox;
90 @method void _readState(CheckBox w, HTTPServerRequest req)
91 {
92     w.checked = (req.form.get(w.id) == w.id);
93 }
94 @method FormoEvent[] _getEvents(CheckBox w, HTTPServerRequest req){ return null; }
95 @method HtmlTag _toHtml(CheckBox w)
96 {
97     import dhtags.attrs.attribute: HtmlAttribute;
98 
99     auto cbox = tags.input(attrs.type="checkbox", attrs.id=w.id, attrs.name=w.id, attrs.value=w.id);
100 
101     if(w.checked)
102         cbox.attrs ~= HtmlAttribute("checked", "checked");
103 
104     return
105         tags.div(attrs.style="width: auto; float: left")
106         (
107             cbox.addStyle(w),
108             tags.label(attrs.for_=w.id)(w.text.to!string).addStyle(w)
109         );
110 }
111 
112 import dlangui.widgets.controls: RadioButton;
113 @method void _readState(RadioButton w, HTTPServerRequest req)
114 {
115     if(w.checked != (req.form.get(w.parent.id) == w.id))
116     {
117         w.uncheckSiblings();
118         w.checked = true;
119     }
120 }
121 @method FormoEvent[] _getEvents(RadioButton w, HTTPServerRequest req){ return null; }
122 @method HtmlTag _toHtml(RadioButton w)
123 {
124     import dhtags.attrs.attribute: HtmlAttribute;
125 
126     auto box = tags.input(attrs.type="radio", attrs.id=w.id, attrs.name=w.parent.id, attrs.value=w.id);
127 
128     if(w.checked)
129         box.attrs ~= HtmlAttribute("checked", "checked");
130 
131     if(!w.enabled)
132         box.attrs ~= HtmlAttribute("disabled", "disabled");
133 
134     return
135         tags.div(attrs.style="width: auto; float: left")
136         (
137             box.addStyle(w),
138             tags.label(attrs.for_=w.id)(w.text.to!string).addStyle(w)
139         );
140 }
141 
142 import dlangui.widgets.controls: Button;
143 private FormoEvent[] checkIfButtonPressed(Widget w, HTTPServerRequest req)
144 {
145     if(req.form.get(w.id) is null)
146         return null;
147     else
148         return
149         [
150             FormoEvent(null, new MouseEvent(MouseAction.ButtonDown, MouseButton.Left, 0, -10, -10, 0)),
151             FormoEvent(null, new MouseEvent(MouseAction.ButtonUp,   MouseButton.Left, 0, -10, -10, 0))
152         ];
153 }
154 @method FormoEvent[] _getEvents(Button w, HTTPServerRequest req)
155 {
156     return checkIfButtonPressed(w, req);
157 }
158 @method HtmlTag _toHtml(Button w)
159 {
160     return tags.input(attrs.type="submit", attrs.name=w.id, attrs.value=w.text.to!string).addStyle(w);
161 }
162 
163 import dlangui.widgets.combobox: ComboBox;
164 @method void _readState(ComboBox w, HTTPServerRequest req)
165 {
166     auto r = req.form.get(w.id);
167 
168     if(r !is null)
169     {
170         auto i = r.to!int;
171 
172         if(i >= 0 && i < w.items.length)
173             w.selectedItemIndex = i;
174     }
175 }
176 @method HtmlTag _toHtml(ComboBox w)
177 {
178     HtmlTag[] opts;
179     //~ opts ~= tags.option(attrs.disabled="disabled", attrs.value="unselected");
180 
181     for(auto i = 0; i < w.items.length; i++)
182     {
183         opts ~= tags.option(attrs.value=i.to!string)(w.items.get(i).to!string);
184 
185         if(i == w.selectedItemIndex)
186             opts[$-1].attrs ~= HtmlAttribute("selected", "selected");
187     }
188 
189     return
190         tags.select(attrs.name=w.id)
191         (
192             w.items.length
193                 ? opts
194                 : [ new HtmlTag ]
195         );
196 }
197 
198 import dlangui.widgets.controls: ImageWidget;
199 @method HtmlTag _toHtml(ImageWidget w)
200 {
201     assert(w.drawable !is null);
202 
203     import dlangui.graphics.resources: drawableCache;
204 
205     auto d = w.drawable;
206 
207     return tags.img(attrs.src="/res/"~drawableCache._idToDrawableMap[w.drawableId]._filename, attrs.width=d.width, attrs.height=d.height);
208 }
209 
210 import dlangui.widgets.controls: ImageTextButton;
211 @method FormoEvent[] _getEvents(ImageTextButton w, HTTPServerRequest req)
212 {
213     return checkIfButtonPressed(w, req);
214 }
215 @method HtmlTag _toHtml(ImageTextButton w)
216 {
217     return
218         tags.button(attrs.type="submit", attrs.name=w.id, attrs.value=w.text.to!string)
219         (
220             (cast(LinearLayout) w)._toHtml
221         ).addStyle(w);
222 }
223 
224 import dlangui.widgets.layouts: LinearLayout, Orientation;
225 @method HtmlTag _toHtml(LinearLayout w)
226 {
227     HtmlTag[] sub;
228 
229     final switch(w.orientation)
230     {
231         case Orientation.Horizontal:
232             for(auto i = 0; i < w.childCount; i++)
233                 sub ~= w.child(i).toHtml;
234 
235             if(sub.length)
236                 return tags.div(attrs.style="width: auto; float: left")(sub);
237 
238             break;
239 
240         case Orientation.Vertical:
241             for(auto i = 0; i < w.childCount; i++)
242             {
243                 auto width_100 = w.child(i).toHtml;
244                 width_100.attrs ~= HtmlAttribute("class", "w100");
245 
246                 sub ~=
247                     tags.div(attrs.style="clear: both")
248                     (
249                         width_100
250                     );
251             }
252 
253             if(sub.length)
254                 return tags.div(attrs.style="float: left")(sub);
255 
256             break;
257     }
258 
259     return new HtmlTag;
260 }
261 
262 import dlangui.widgets.groupbox: GroupBox;
263 @method HtmlTag _toHtml(GroupBox w)
264 {
265     return
266         tags.fieldset
267         (
268             tags.legend(w.text.to!string),
269             (cast(LinearLayout) w)._toHtml
270         ).addStyle(w);
271 }
272 
273 private:
274 
275 static this()
276 {
277     updateMethods();
278 }
279 
280 string styleStr(Widget w)
281 {
282     import std.format;
283 
284     auto s = w.ownStyle;
285 
286     return
287         "color: "~s.textColor.format!"#%06X; "~
288         "font-size: "~s.fontSize.to!string~"px; "~
289         "font-weight: "~s.fontWeight.to!string;
290 }
291 
292 HtmlTag addStyle(HtmlTag tag, Widget w)
293 {
294     tag.attrs ~= HtmlAttribute("style", w.styleStr);
295 
296     if(!w.enabled)
297         tag.attrs ~= HtmlAttribute("disabled", "disabled");
298 
299     return tag;
300 }