egra: more agg mini cleanups (duplicated some code, because why not...)
[iv.d.git] / egra / test.d
blobe2d89f761121bbb9e21780022c62b676fed458ea
1 /* E-Mail Client
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module test /*is aliced*/;
19 import arsd.simpledisplay;
21 import iv.cmdcon;
22 import iv.cmdcongl;
23 import iv.strex;
24 import iv.utfutil;
25 import iv.vfs.io;
26 import iv.vfs.util;
28 import iv.egra;
31 // ////////////////////////////////////////////////////////////////////////// //
32 static immutable string TestStyle = `
33 MainPaneWindow {
34 grouplist-divline: white;
35 grouplist-back: #222;
37 threadlist-divline: white;
38 threadlist-back: #222;
41 TitlerWindow {
42 frame: white;
43 title-back: white;
44 title-text: black;
46 back: rgb(0, 92, 0);
47 text: #7f0;
48 hotline: #7f0;
53 // ////////////////////////////////////////////////////////////////////////// //
54 //__gshared int lastWinWidth, lastWinHeight;
57 // ////////////////////////////////////////////////////////////////////////// //
58 public class TitlerWindow : SubWindow {
59 public:
60 LineEditWidget edtTitle;
61 LineEditWidget fromName;
62 LineEditWidget fromMail;
64 protected:
65 dynstring name;
66 dynstring mail;
67 dynstring folder;
68 dynstring title;
70 bool delegate (dynstring name, dynstring mail, dynstring folder, dynstring title) onSelected;
72 override void createWidgets () {
73 new SpacerWidget(2);
75 version(none) {
76 fromName = new LineEditWidget("Name:");
77 fromName.flex = 1;
79 new SpacerWidget(1);
80 fromMail = new LineEditWidget("Mail:");
81 fromMail.flex = 1;
83 new SpacerWidget(1);
84 edtTitle = new LineEditWidget("Title:");
85 edtTitle.flex = 1;
86 } else {
87 (new HBoxWidget).enter{
88 with (new HotLabelWidget("&Name:", LabelWidget.HAlign.Right)) { width = width+2; hsizeId = "editors"; }
89 new SpacerWidget(4);
90 fromName = new LineEditWidget();
91 fromName.flex = 1;
92 }.flex = 1;
94 new SpacerWidget(1);
95 (new HBoxWidget).enter{
96 with (new HotLabelWidget("&Mail:", LabelWidget.HAlign.Right)) { width = width+2; hsizeId = "editors"; }
97 new SpacerWidget(4);
98 fromMail = new LineEditWidget();
99 fromMail.flex = 1;
100 }.flex = 1;
102 new SpacerWidget(1);
103 (new HBoxWidget).enter{
104 with (new HotLabelWidget("&Title:", LabelWidget.HAlign.Right)) { width = width+2; hsizeId = "editors"; }
105 new SpacerWidget(4);
106 edtTitle = new LineEditWidget();
107 edtTitle.flex = 1;
108 }.flex = 1;
111 new SpacerWidget(4);
112 (new HBoxWidget).enter{
113 new SpacerWidget(2);
114 new SpringWidget(1);
115 with (new ButtonWidget(" O&k ")) {
116 hsizeId = "okcancel";
117 deftype = Default.Accept;
118 onAction = delegate (self) {
119 if (onSelected !is null) {
120 if (!onSelected(fromName.str, fromMail.str, folder, edtTitle.str)) return;
122 close();
125 new SpacerWidget(2);
126 with (new ButtonWidget(" Cancel ")) {
127 hsizeId = "okcancel";
128 deftype = Default.Cancel;
129 onAction = delegate (self) {
130 close();
133 new SpringWidget(1);
134 new SpacerWidget(2);
136 new SpacerWidget(4);
138 fromName.str = name;
139 fromMail.str = mail;
140 edtTitle.str = title;
142 relayoutResize();
143 centerWindow();
145 edtTitle.focus();
148 this (const(char)[] aname, const(char)[] amail, const(char)[] afolder, const(char)[] atitle) {
149 dynstring caption = "Title for "~aname~" <"~amail~">";
150 name = aname;
151 mail = amail;
152 folder = afolder;
153 title = atitle;
154 super(caption);
159 // ////////////////////////////////////////////////////////////////////////// //
160 public class TagOptionsWindow : SubWindow {
161 dynstring tagname;
163 void delegate (const(char)[] tagname) onUpdated;
165 this (const(char)[] atagname) {
166 tagname = atagname;
167 dynstring caption = "options for '"~atagname~"'";
168 super(caption);
171 override void createWidgets () {
172 LabelWidget optPath = new LabelWidget("", LabelWidget.HAlign.Center);
173 optPath.flex = 1;
175 LineEditWidget optMonthes;
176 (new HBoxWidget).enter{
177 with (new HotLabelWidget("&Monthes:", LabelWidget.HAlign.Right)) { width = width+2; /*hsizeId = "editors";*/ }
178 new SpacerWidget(4);
179 optMonthes = new LineEditWidget();
180 //optMonthes.flex = 1;
181 optMonthes.width = gxTextWidthUtf("96669");
182 conwriteln("ISMYSEL: ", optMonthes.isMySelector(" Widget#. "));
183 conwriteln("ISMYSEL: ", optMonthes.isMySelector(" HBoxWidget LineEditWidget#. "));
184 conwriteln("ISMYSEL: ", optMonthes.isMySelector(" HBoxWidget> #. "));
185 conwriteln("ISMYSEL: ", optMonthes.isMySelector(" SubWindow HBoxWidget LineEditWidget#. "));
186 //new SpringWidget(1);
187 }.flex = 1;
189 CheckboxWidget optThreaded = new CheckboxWidget("&Threaded");
190 optThreaded.flex = 1;
192 CheckboxWidget optAttaches = new CheckboxWidget("&Attaches");
193 optAttaches.flex = 1;
195 new SpacerWidget(4);
196 (new HBoxWidget).enter{
197 new SpacerWidget(2);
198 new SpringWidget(1);
199 with (new ButtonWidget(" O&k ")) {
200 hsizeId = "okcancel";
201 deftype = Default.Accept;
202 onAction = delegate (self) {
203 if (onUpdated !is null) onUpdated(tagname);
204 close();
207 new SpacerWidget(4);
208 with (new ButtonWidget(" Cancel ")) {
209 hsizeId = "okcancel";
210 deftype = Default.Cancel;
211 onAction = delegate (self) {
212 close();
215 new SpacerWidget(4);
216 with (new ButtonWidget(" ... ")) {
217 hsizeId = "okcancel";
218 hotkey = "M-L";
219 onAction = delegate (self) {
220 (new SelectCompletionWindow("", buildAutoCompletion("/home/ketmar/"), aspath:true)).onSelected = (str) {
221 conwriteln("SELECTED: <", str.getData, ">");
223 //close();
226 new SpringWidget(1);
227 new SpacerWidget(2);
229 new SpacerWidget(4);
231 optMonthes.focus();
233 optPath.text = "booPath";
234 optMonthes.str = "666";
236 optThreaded.enabled = false;
237 optAttaches.enabled = true;
239 optMonthes.killTextOnChar = true;
241 relayoutResize();
242 centerWindow();
243 //add(); // for "focused"
245 forEachSelector("SubWindow > RootWidget CheckboxWidget", (EgraStyledClass w) {
246 import iv.vfs.io; writeln("LEW=", typeid(w).name, "; text=", (cast(CheckboxWidget)w).title.getData);
247 //return false;
250 forEachSelector("SubWindow > RootWidget :focused", (EgraStyledClass w) {
251 import iv.vfs.io; writeln("FOCUSED=", typeid(w).name);
252 //return false;
255 foreach (HotLabelWidget c; querySelectorAll!HotLabelWidget("SubWindow > RootWidget HotLabelWidget")) {
256 import iv.vfs.io;
257 writeln("LBL: <", c.text.getData, ">");
260 { import iv.vfs.io;
261 Widget qf = querySelector(":focused");
262 if (qf !is null) writeln("QFOCUSED=", typeid(qf).name); else writeln("FUCK!");
267 // ////////////////////////////////////////////////////////////////////////// //
268 void initConsole () {
269 // //////////////////////////////////////////////////////////////////// //
270 conRegFunc!(() {
271 import core.memory : GC;
272 conwriteln("starting GC collection...");
273 GC.collect();
274 GC.minimize();
275 conwriteln("GC collection complete.");
276 })("gc_collect", "force GC collection cycle");
279 // //////////////////////////////////////////////////////////////////// //
280 conRegFunc!(() {
281 auto qww = new YesNoWindow("Quit?", "Do you really want to quit?", true);
282 qww.onYes = () { concmd("quit"); };
283 qww.addModal();
284 })("quit_prompt", "quit with prompt");
286 conRegFunc!(() {
287 new TitlerWindow("name", "mail", "folder", "title");
288 })("window_titler", "titler window test");
290 conRegFunc!(() {
291 new TagOptionsWindow("xtag");
292 })("window_tagoptions", "tag options window test");
296 // ////////////////////////////////////////////////////////////////////////// //
297 __gshared MainPaneWindow mainPane;
300 final class MainPaneWindow : SubWindow {
301 ProgressBarWidget pbar;
302 int tessType = -1;
303 AGGTesselation deftess;
304 bool timetest;
305 int lastMX = -10000, lastMY = -10000;
307 this () {
308 super(null, GxPoint(0, 0), GxSize(screenWidth, screenHeight));
309 mType = Type.OnBottom;
311 pbar = new ProgressBarWidget(rootWidget, "progress bar");
312 pbar.setMinMax(0, 100);
313 pbar.width = clientWidth-64;
314 pbar.current = 50;
315 pbar.posy = clientHeight-pbar.height-8;
316 pbar.posx = (clientWidth-pbar.width)/2;
318 deftess = gxagg.tesselator;
320 add();
323 // //////////////////////////////////////////////////////////////////// //
324 override void onPaint () {
325 if (closed) return;
327 enum guiGroupListWidth = 128;
328 enum guiThreadListHeight = 520;
330 gxFillRect(0, 0, guiGroupListWidth, screenHeight, getColor("grouplist-back"));
331 gxVLine(guiGroupListWidth, 0, screenHeight, getColor("grouplist-divline"));
333 gxFillRect(guiGroupListWidth+1, 0, screenWidth, guiThreadListHeight, getColor("threadlist-back"));
334 gxHLine(guiGroupListWidth+1, guiThreadListHeight, screenWidth, getColor("threadlist-divline"));
336 version(all) {
337 import core.stdc.math : roundf;
339 if (tessType >= 0) {
340 if (tessType > AGGTesselation.max) tessType = AGGTesselation.max;
341 gxagg.tesselator = cast(AGGTesselation)tessType;
342 } else {
343 gxagg.tesselator = deftess;
346 gxagg.beginFrame();
347 gxagg.width = 1.4f;
348 //gxagg.width = 1.0f;
350 float baphx = roundf((screenWidth-gxagg.BaphometDims)*0.5f)+0.5f;
351 float baphy = roundf((screenHeight-gxagg.BaphometDims)*0.5f)+0.5f;
353 import iv.pxclock;
354 ulong estt;
355 ubyte hit = 0;
356 if (timetest) {
357 timetest = false;
358 estt = 0;
359 foreach (; 0..1000) {
360 gxagg.beginFrame();
361 immutable tstt = clockMicro();
362 gxagg.renderBaphomet(baphx, baphy);
363 estt += (clockMicro()-tstt);
365 estt /= 1000;
366 gxagg.beginFrame();
367 gxagg.renderBaphomet(baphx, baphy);
368 } else {
369 immutable tstt = clockMicro();
370 gxagg.renderBaphomet(baphx, baphy);
371 estt = clockMicro()-tstt;
374 version(none) {
375 gxagg
376 .moveTo(baphx-1, baphy-1)
377 .lineTo(baphx+gxagg.BaphometDims, baphy-1)
378 .lineTo(baphx+gxagg.BaphometDims, baphy+gxagg.BaphometDims)
379 .lineTo(baphx-1, baphy+gxagg.BaphometDims)
380 .lineTo(baphx-1, baphy-1);
382 version(all) {
383 gxagg.roundedRect(baphx-1, baphy-1, gxagg.BaphometDims+1, gxagg.BaphometDims+1, 16.0f);
385 gxagg.stroke();
386 //gxagg.contour();
387 //gxagg.fill();
389 version(none) {
390 gxagg
391 .beginPath();
392 .moveTo(10, 10);
393 .lineTo(30, 20);
394 .width = 1.0f;
395 gxagg.contour();
398 hit = gxagg.hitTest(lastMX, lastMY);
399 gxagg.endFrame(gxrgba(255, 0, 0, (tessType >= 0 ? 255 : 66)));
402 import std.format : format;
403 string s = "tess: %s level: %d; mcsecs: %s".format(gxagg.tesselator, gxagg.bezierLimit, estt);
404 gxDrawTextUtf(200, 20, s, GxColors.k8orange);
405 if (hit) {
406 s = "hit: %3s".format(hit);
407 gxDrawTextUtf(200, 40, s, GxColors.k8orange);
412 version(all) {
413 gxagg.beginFrame();
414 AGGMatrix tmt;
417 .rotate(deg2rad(35.0f))
418 .translate(20, 100);
422 .translate(0.5f, 0.5f)
423 .translate(-160, 0);
425 gxagg.withTransform(tmt, {
426 gxagg.moveTo(50, 50);
427 gxagg.lineTo(60, 60);
428 gxagg.moveTo(100, 100);
429 gxagg.lineTo(140, 120);
430 version(all) {
431 gxagg.moveTo(200, 200);
432 gxagg.lineTo(200, 100);
433 gxagg.lineTo(100, 100);
434 gxagg.lineTo(100, 200);
435 gxagg.lineTo(200, 200);
436 } else {
437 gxagg.moveTo(100, 100);
438 gxagg.lineTo(200, 100);
439 gxagg.lineTo(200, 200);
440 gxagg.lineTo(100, 200);
442 gxagg.closePoly();
443 //gxagg.dumpVertices();
446 version(all) {
447 gxagg.fill();
448 gxagg.render(gxrgba(0, 127, 0, 127));
450 version(all) {
451 //gxagg.dumpVertices();
452 gxagg.stroke();
453 gxagg.render(gxrgba(127, 0, 0, 255));
456 version(all) {
457 gxagg.resetDashes();
458 gxagg.addDash(4, 4);
459 gxagg.addDash(8, 8);
460 gxagg.dashStroke();
461 //gxagg.dashContour();
462 gxagg.render(gxrgba(255, 255, 0, 255));
465 version(none) {
466 // not working properly yet
467 gxagg.setupContour(6);
468 gxagg.contour();
469 gxagg.render(gxrgba(255, 255, 0, 255));
472 version(none) {
473 // not working properly yet
474 gxagg.setupContour(6);
475 gxagg.resetDashes();
476 gxagg.addDash(4, 4);
477 gxagg.dashContour();
478 gxagg.render(gxrgba(255, 255, 0, 255));
481 //gxagg.render(gxrgba(0, 127, 0, 127));
483 gxagg.endFrame();
486 version(test_round_rect) {
487 gxClipReset();
488 gxFillRoundedRect(lastMouseX-16, lastMouseY-16, 128, 96, rrad, /*gxSolidWhite*/gxRGBA!(0, 255, 0, 127));
489 //gxDrawRoundedRect(lastMouseX-16, lastMouseY-16, 128, 96, rrad, gxRGBA!(0, 255, 0, 127));
492 drawWidgets();
495 version(test_round_rect) {
496 int rrad = 16;
499 override bool onKeyBubble (KeyEvent event) {
500 if (event.pressed) {
501 version(test_round_rect) {
502 if (event == "Plus") { ++rrad; return true; }
503 if (event == "Minus") { --rrad; return true; }
505 if (event == "C-Q") { concmd("quit_prompt"); return true; }
506 if (event == "1") { concmd("window_titler"); return true; }
507 if (event == "2") { concmd("window_tagoptions"); return true; }
508 if (event == "Minus") { pbar.current = pbar.current-1; return true; }
509 if (event == "Plus") { pbar.current = pbar.current+1; return true; }
511 if (event == "Q") { if (gxagg.bezierLimit > 1) { --gxagg.bezierLimit; widgetChanged(); } return true; }
512 if (event == "W") { if (gxagg.bezierLimit < 1000) { ++gxagg.bezierLimit; widgetChanged(); } return true; }
514 if (event == "Z") { --tessType; if (tessType < -1) tessType = -1; widgetChanged(); return true; }
515 if (event == "X") { ++tessType; widgetChanged(); return true; }
517 if (event == "T") { timetest = true; widgetChanged(); return true; }
518 //if (dbg_dump_keynames) conwriteln("key: ", event.toStr, ": ", event.modifierState&ModifierState.windows);
519 //foreach (const ref kv; mainAppKeyBindings.byKeyValue) if (event == kv.key) concmd(kv.value);
521 return false;
524 // returning `false` to avoid screen rebuilding by dispatcher
525 override bool onMouseBubble (MouseEvent event) {
526 if (event.type == MouseEventType.buttonPressed || event.type == MouseEventType.buttonReleased) {
527 if (lastMX != event.x || lastMY != event.y) {
528 lastMX = event.x;
529 lastMY = event.y;
530 //widgetChanged();
532 widgetChanged();
533 } else if (event.modifierState) {
534 // for OpenGL, this rebuilds the whole screen anyway
535 lastMX = event.x;
536 lastMY = event.y;
537 widgetChanged();
539 return false;
544 // ////////////////////////////////////////////////////////////////////////// //
545 void main (string[] args) {
546 defaultColorStyle.parseStyle(TestStyle);
547 //egraDefaultFontSize = 48;
549 glconAllowOpenGLRender = false;
551 sdpyWindowClass = "EGUITest";
552 //glconShowKey = "M-Grave";
554 initConsole();
556 conProcessQueue();
557 conProcessArgs!true(args);
559 egraCreateSystemWindow("EGRA Test", allowResize:false);
561 vbwin.addEventListener((QuitEvent evt) {
562 if (vbwin.closed) return;
563 if (isQuitRequested) { vbwin.close(); return; }
564 vbwin.close();
567 static if (is(typeof(&vbwin.closeQuery))) {
568 vbwin.closeQuery = delegate () { concmd("quit"); egraPostDoConCommands(); };
571 mainPane = new MainPaneWindow();
572 //egraSkipScreenClear = true; // main pane is fullscreen
574 postScreenRebuild();
575 repostHideMouse();
577 vbwin.eventLoop(1000*10,
578 delegate () {
579 egraProcessConsole();
581 delegate (KeyEvent event) {
582 if (egraOnKey(event)) return;
584 delegate (MouseEvent event) {
585 if (egraOnMouse(event)) return;
587 delegate (dchar ch) {
588 if (egraOnChar(ch)) return;
592 flushGui();
593 conProcessQueue(int.max/4);