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 }