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
;
32 // ////////////////////////////////////////////////////////////////////////// //
33 static immutable string TestStyle
= `
35 grouplist-divline: white;
38 threadlist-divline: white;
39 threadlist-back: #222;
54 // ////////////////////////////////////////////////////////////////////////// //
55 //__gshared int lastWinWidth, lastWinHeight;
58 // ////////////////////////////////////////////////////////////////////////// //
59 public class TitlerWindow
: SubWindow
{
61 LineEditWidget edtTitle
;
62 LineEditWidget fromName
;
63 LineEditWidget fromMail
;
71 bool delegate (dynstring name
, dynstring mail
, dynstring folder
, dynstring title
) onSelected
;
73 override void createWidgets () {
77 fromName
= new LineEditWidget("Name:");
81 fromMail
= new LineEditWidget("Mail:");
85 edtTitle
= new LineEditWidget("Title:");
88 (new HBoxWidget
).enter{
89 with (new HotLabelWidget("&Name:", LabelWidget
.HAlign
.Right
)) { width
= width
+2; hsizeId
= "editors"; }
91 fromName
= new LineEditWidget();
96 (new HBoxWidget
).enter{
97 with (new HotLabelWidget("&Mail:", LabelWidget
.HAlign
.Right
)) { width
= width
+2; hsizeId
= "editors"; }
99 fromMail
= new LineEditWidget();
104 (new HBoxWidget
).enter{
105 with (new HotLabelWidget("&Title:", LabelWidget
.HAlign
.Right
)) { width
= width
+2; hsizeId
= "editors"; }
107 edtTitle
= new LineEditWidget();
113 (new HBoxWidget
).enter{
116 with (new ButtonWidget(" O&k ")) {
117 hsizeId
= "okcancel";
118 deftype
= Default
.Accept
;
119 onAction
= delegate (self
) {
120 if (onSelected
!is null) {
121 if (!onSelected(fromName
.str, fromMail
.str, folder
, edtTitle
.str)) return;
127 with (new ButtonWidget(" Cancel ")) {
128 hsizeId
= "okcancel";
129 deftype
= Default
.Cancel
;
130 onAction
= delegate (self
) {
135 with (new ButtonWidget(" ... ")) {
136 hsizeId
= "okcancel";
147 edtTitle
.str = title
;
155 this (const(char)[] aname
, const(char)[] amail
, const(char)[] afolder
, const(char)[] atitle
) {
156 dynstring caption
= "Title for "~aname
~" <"~amail
~">";
166 // ////////////////////////////////////////////////////////////////////////// //
167 public class TagOptionsWindow
: SubWindow
{
170 void delegate (const(char)[] tagname
) onUpdated
;
172 this (const(char)[] atagname
) {
174 dynstring caption
= "options for '"~atagname
~"'";
178 override void createWidgets () {
179 LabelWidget optPath
= new LabelWidget("", LabelWidget
.HAlign
.Center
);
182 LineEditWidget optMonthes
;
183 (new HBoxWidget
).enter{
184 with (new HotLabelWidget("&Monthes:", LabelWidget
.HAlign
.Right
)) { width
= width
+2; /*hsizeId = "editors";*/ }
186 optMonthes
= new LineEditWidget();
187 //optMonthes.flex = 1;
188 optMonthes
.width
= gxTextWidthUtf("96669");
189 conwriteln("ISMYSEL: ", optMonthes
.isMySelector(" Widget#. "));
190 conwriteln("ISMYSEL: ", optMonthes
.isMySelector(" HBoxWidget LineEditWidget#. "));
191 conwriteln("ISMYSEL: ", optMonthes
.isMySelector(" HBoxWidget> #. "));
192 conwriteln("ISMYSEL: ", optMonthes
.isMySelector(" SubWindow HBoxWidget LineEditWidget#. "));
193 //new SpringWidget(1);
196 CheckboxWidget optThreaded
= new CheckboxWidget("&Threaded");
197 optThreaded
.flex
= 1;
199 CheckboxWidget optAttaches
= new CheckboxWidget("&Attaches");
200 optAttaches
.flex
= 1;
202 with (new RadioWidget("Radio &1")) {
208 with (new RadioWidget("Radio &2")) {
216 (new HBoxWidget
).enter{
219 with (new ButtonWidget(" O&k ")) {
220 hsizeId
= "okcancel";
221 deftype
= Default
.Accept
;
222 onAction
= delegate (self
) {
223 if (onUpdated
!is null) onUpdated(tagname
);
225 auto rw
= self
.getSelectedRadio("rg1");
226 if (rw
!is null) conwriteln("SELECTED RADIO: <", rw
.id
, ">");
230 with (new ButtonWidget(" Cancel ")) {
231 hsizeId
= "okcancel";
232 deftype
= Default
.Cancel
;
233 onAction
= delegate (self
) {
238 with (new ButtonWidget(" ... ")) {
239 hsizeId
= "okcancel";
241 onAction
= delegate (self
) {
242 (new SelectCompletionWindow("", buildAutoCompletion("/home/ketmar/"), aspath
:true)).onSelected
= (str) {
243 conwriteln("SELECTED: <", str.getData
, ">");
256 optPath
.text
= "booPath";
257 optMonthes
.str = "666";
259 optThreaded
.enabled
= false;
260 optAttaches
.enabled
= true;
262 optMonthes
.killTextOnChar
= true;
266 //add(); // for "focused"
268 forEachSelector("SubWindow > RootWidget CheckboxWidget", (EgraStyledClass w
) {
269 import iv
.vfs
.io
; writeln("LEW=", typeid(w
).name
, "; text=", (cast(CheckboxWidget
)w
).title
.getData
);
273 forEachSelector("SubWindow > RootWidget :focused", (EgraStyledClass w
) {
274 import iv
.vfs
.io
; writeln("FOCUSED=", typeid(w
).name
);
278 foreach (HotLabelWidget c
; querySelectorAll
!HotLabelWidget("SubWindow > RootWidget HotLabelWidget")) {
280 writeln("LBL: <", c
.text
.getData
, ">");
284 Widget qf
= querySelector(":focused");
285 if (qf
!is null) writeln("QFOCUSED=", typeid(qf
).name
); else writeln("FUCK!");
290 // ////////////////////////////////////////////////////////////////////////// //
291 void initConsole () {
292 // //////////////////////////////////////////////////////////////////// //
294 import core
.memory
: GC
;
295 conwriteln("starting GC collection...");
298 conwriteln("GC collection complete.");
299 })("gc_collect", "force GC collection cycle");
302 // //////////////////////////////////////////////////////////////////// //
304 auto qww
= new YesNoWindow("Quit?", "Do you really want to quit?", true);
305 qww
.onYes
= () { concmd("quit"); };
307 })("quit_prompt", "quit with prompt");
310 new TitlerWindow("name", "mail", "folder", "title");
311 })("window_titler", "titler window test");
314 new TagOptionsWindow("xtag");
315 })("window_tagoptions", "tag options window test");
319 // ////////////////////////////////////////////////////////////////////////// //
320 __gshared MainPaneWindow mainPane
;
323 final class MainPaneWindow
: SubWindow
{
324 ProgressBarWidget pbar
;
326 AGGTesselation deftess
;
328 int lastMX
= -10000, lastMY
= -10000;
331 super(null, GxPoint(0, 0), GxSize(screenWidth
, screenHeight
));
332 mType
= Type
.OnBottom
;
334 pbar
= new ProgressBarWidget(rootWidget
, "progress bar");
335 pbar
.setMinMax(0, 100);
336 pbar
.width
= clientWidth
-64;
338 pbar
.posy
= clientHeight
-pbar
.height
-8;
339 pbar
.posx
= (clientWidth
-pbar
.width
)/2;
341 deftess
= gxagg
.tesselator
;
346 // //////////////////////////////////////////////////////////////////// //
347 override void onPaint () {
350 enum guiGroupListWidth
= 128;
351 enum guiThreadListHeight
= 520;
353 gxFillRect(0, 0, guiGroupListWidth
, screenHeight
, getColor("grouplist-back"));
354 gxVLine(guiGroupListWidth
, 0, screenHeight
, getColor("grouplist-divline"));
356 gxFillRect(guiGroupListWidth
+1, 0, screenWidth
, guiThreadListHeight
, getColor("threadlist-back"));
357 gxHLine(guiGroupListWidth
+1, guiThreadListHeight
, screenWidth
, getColor("threadlist-divline"));
360 import core
.stdc
.math
: roundf
;
363 if (tessType
> AGGTesselation
.max
) tessType
= AGGTesselation
.max
;
364 gxagg
.tesselator
= cast(AGGTesselation
)tessType
;
366 gxagg
.tesselator
= deftess
;
370 gxagg
.params
.width
= 1.4f;
371 //gxagg.width = 1.0f;
373 float baphx
= roundf((screenWidth
-gxagg
.BaphometDims
)*0.5f)+0.5f;
374 float baphy
= roundf((screenHeight
-gxagg
.BaphometDims
)*0.5f)+0.5f;
382 foreach (; 0..1000) {
384 immutable tstt
= clockMicro();
385 gxagg
.renderBaphomet(baphx
, baphy
);
386 estt
+= (clockMicro()-tstt
);
390 gxagg
.renderBaphomet(baphx
, baphy
);
392 immutable tstt
= clockMicro();
393 gxagg
.renderBaphomet(baphx
, baphy
);
394 estt
= clockMicro()-tstt
;
399 .moveTo(baphx
-1, baphy
-1)
400 .lineTo(baphx
+gxagg
.BaphometDims
, baphy
-1)
401 .lineTo(baphx
+gxagg
.BaphometDims
, baphy
+gxagg
.BaphometDims
)
402 .lineTo(baphx
-1, baphy
+gxagg
.BaphometDims
)
403 .lineTo(baphx
-1, baphy
-1);
406 gxagg
.roundedRect(baphx
-1, baphy
-1, gxagg
.BaphometDims
+1, gxagg
.BaphometDims
+1, 16.0f);
421 hit
= gxagg
.hitTest(lastMX
, lastMY
);
424 immutable rstt
= clockMicro();
425 gxagg
.render(gxrgba(255, 0, 0, (tessType
>= 0 ?
255 : 66)));
426 immutable fstt
= clockMicro()-rstt
;
427 import core
.stdc
.stdio
; printf("total Baphomet render microsecs: %u\n", cast(uint)fstt
);
430 //gxagg.endFrame(gxrgba(255, 0, 0, (tessType >= 0 ? 255 : 66)));
434 import std
.format
: format
;
435 string s
= "tess: %s level: %d; mcsecs: %s".format(gxagg
.tesselator
, gxagg
.bezierLimit
, estt
);
436 gxDrawTextUtf(200, 20, s
, GxColors
.k8orange
);
438 s
= "hit: %3s".format(hit
);
439 gxDrawTextUtf(200, 40, s
, GxColors
.k8orange
);
444 ulong accstt
= 0, fstt
;
451 .rotate(deg2rad(35.0f))
453 assert(!tmt
.isIdentity
);
457 .translate(0.5f, 0.5f)
460 gxagg
.withTransform(tmt
, {
461 gxagg
.moveTo(50, 50);
462 gxagg
.lineTo(60, 60);
463 gxagg
.moveTo(100, 100);
464 gxagg
.lineTo(140, 120);
466 // CW (because logical coords are upwards)
467 gxagg
.moveTo(200, 200);
468 gxagg
.lineTo(200, 100);
469 gxagg
.lineTo(100, 100);
470 gxagg
.lineTo(100, 200);
471 gxagg
.lineTo(200, 200);
473 // CCW (because logical coords are upwards)
474 gxagg
.moveTo(100, 100);
475 gxagg
.lineTo(200, 100);
476 gxagg
.lineTo(200, 200);
477 gxagg
.lineTo(100, 200);
480 //gxagg.flipOrientation = true;
481 //gxagg.dumpVertices();
487 gxagg
.render(gxrgba(0, 127, 0, 127));
488 accstt
+= clockMicro()-fstt
;
491 //gxagg.dumpVertices();
494 gxagg
.render(gxrgba(127, 0, 0, 255));
495 accstt
+= clockMicro()-fstt
;
503 //gxagg.dashContour();
505 gxagg
.render(gxrgba(255, 255, 0, 255));
506 accstt
+= clockMicro()-fstt
;
510 gxagg
.paramsContour
.width
= 6;
513 gxagg
.render(gxrgba(255, 255, 255, 255));
514 accstt
+= clockMicro()-fstt
;
518 gxagg
.flipOrientation
= true;
521 gxagg
.render(gxrgba(0, 255, 0, 255));
522 accstt
+= clockMicro()-fstt
;
523 gxagg
.flipOrientation
= false;
526 { import core
.stdc
.stdio
; printf("total rect render microsecs: %u\n", cast(uint)accstt
); }
528 //gxagg.render(gxrgba(0, 127, 0, 127));
534 .roundedRect(400.5f, 600.5f, 96, 28, 8)
536 //.render(gxRGB!(192, 192, 192));
538 .render(AGGVGradient3(gxagg.rasterMinY, gxRGB!(127, 127, 127),
539 gxagg.rasterMaxY, gxRGB!(142, 142, 142),
540 20, gxRGB!(196, 196, 196)));
543 .render(AGGVGradient3(gxagg.rasterMinY, gxRGB!(255, 0, 0),
544 gxagg.rasterMaxY, gxRGB!(0, 255, 0),
545 20, gxRGB!(0, 0, 255)));
547 .render(AGGHGradient(gxagg
.rasterMinX
, gxRGBA
!(255, 0, 0, 127),
548 gxagg
.rasterMaxX
, gxRGBA
!(0, 255, 0, 90)));
555 if (gxFontCharPathBounds(dch
, bounds
[])) {
556 //conwriteln("bounds: (", bounds[0], ",", bounds[1], ")-(", bounds[2], ",", bounds[3], ")");
558 immutable float gwdt
= bounds
[2]-bounds
[0];
559 immutable float ghgt
= bounds
[3]-bounds
[1];
560 float scale
= desthgt
/ghgt
;
564 .translate(-bounds
[0]*scale
+100.5f, -bounds
[1]*scale
+100.5f);
565 gxagg
.withTransform(tmx
, {
569 if (gxFontCharToPath(dch
)) {
573 //.render(GxColors.k8orange);
576 gxagg
.render(AGGVGradient3(gxagg
.rasterMinY
, gxRGB
!(200, 73, 0),
577 gxagg
.rasterMaxY
, gxRGB
!(255, 128, 0)));
578 accstt
+= clockMicro()-fstt
;
580 int emb
= cast(int)(4/scale
);
584 if (gxFontCharPathEmboldenBounds(dch
, emb
, ebounds
[])) {
585 immutable float ewdt
= ebounds
[2]-ebounds
[0];
586 immutable float ehgt
= ebounds
[3]-ebounds
[1];
587 gxagg
.transform
.translate(-(ewdt
-gwdt
)*0.5f*scale
, (ehgt
-ghgt
)*0.5f*scale
);
588 if (gxFontCharToPathEmbolden(dch
, emb
)) {
593 gxagg
.render(GxColors
.green
);
594 accstt
+= clockMicro()-fstt
;
598 { import core
.stdc
.stdio
; printf("total glyph render microsecs: %u\n", cast(uint)accstt
); }
602 static if (is(typeof({immutable string s
= import("xbnd.d");}))) {
603 mixin(import("xbnd.d"));
606 enum hasxbnd
= false;
612 if (gxFontCharPathBounds(gdch
, gbounds
[])) {
614 immutable float gwdt
= gbounds
[2]-gbounds
[0];
615 immutable float ghgt
= gbounds
[3]-gbounds
[1];
616 float scale
= desthgt
/ghgt
;
620 .translate(-bounds
[0]*scale
+200.5f, -bounds
[1]*scale
+200.5f);
621 gxagg
.withTransform(tmx
, {
622 gxagg
.resetParams().beginPath();
623 if (gxFontCharToPath(gdch
)) {
624 //gxagg.flipOrientation = true;
625 gxagg
.paramsContour
.width
= 8;
627 //gxagg.render(gxrgba(0, 155, 0, 255));
628 gxagg
.render(gxagg
.vgradient(gxrgb(0, 38, 0), gxrgb(0, 98, 0)));
629 gxagg
.flipOrientation
= false;
631 gxagg
.resetParams().beginPath();
632 if (gxFontCharToPath(gdch
)) {
634 static if (hasxbnd
) {
635 gxagg
.render(AGGImgFill(0, 0, 32));
637 gxagg
.render(gxagg
.vgradient(gxrgb(255, 127, 0), gxrgb(155, 27, 0)));
644 static if (hasxbnd
) xbnd();
649 version(test_round_rect
) {
651 gxFillRoundedRect(lastMouseX
-16, lastMouseY
-16, 128, 96, rrad
, /*gxSolidWhite*/gxRGBA
!(0, 255, 0, 127));
652 //gxDrawRoundedRect(lastMouseX-16, lastMouseY-16, 128, 96, rrad, gxRGBA!(0, 255, 0, 127));
658 version(test_round_rect
) {
662 override bool onKeyBubble (KeyEvent event
) {
664 version(test_round_rect
) {
665 if (event
== "Plus") { ++rrad
; return true; }
666 if (event
== "Minus") { --rrad
; return true; }
668 if (event
== "C-Q") { concmd("quit_prompt"); return true; }
669 if (event
== "1") { concmd("window_titler"); return true; }
670 if (event
== "2") { concmd("window_tagoptions"); return true; }
671 if (event
== "Minus") { pbar
.current
= pbar
.current
-1; return true; }
672 if (event
== "Plus") { pbar
.current
= pbar
.current
+1; return true; }
674 if (event
== "Q") { if (gxagg
.bezierLimit
> 1) { --gxagg
.bezierLimit
; widgetChanged(); } return true; }
675 if (event
== "W") { if (gxagg
.bezierLimit
< 1000) { ++gxagg
.bezierLimit
; widgetChanged(); } return true; }
677 if (event
== "Z") { --tessType
; if (tessType
< -1) tessType
= -1; widgetChanged(); return true; }
678 if (event
== "X") { ++tessType
; widgetChanged(); return true; }
680 if (event
== "T") { timetest
= true; widgetChanged(); return true; }
681 //if (dbg_dump_keynames) conwriteln("key: ", event.toStr, ": ", event.modifierState&ModifierState.windows);
682 //foreach (const ref kv; mainAppKeyBindings.byKeyValue) if (event == kv.key) concmd(kv.value);
687 // returning `false` to avoid screen rebuilding by dispatcher
688 override bool onMouseBubble (MouseEvent event
) {
689 if (event
.type
== MouseEventType
.buttonPressed || event
.type
== MouseEventType
.buttonReleased
) {
690 if (lastMX
!= event
.x || lastMY
!= event
.y
) {
696 } else if (event
.modifierState
) {
697 // for OpenGL, this rebuilds the whole screen anyway
707 // ////////////////////////////////////////////////////////////////////////// //
708 void main (string
[] args
) {
709 //egraFontName = "PT Sans:pixelsize=16";
711 defaultColorStyle
.parseStyle(TestStyle
);
712 //egraDefaultFontSize = 48;
714 glconAllowOpenGLRender
= false;
716 sdpyWindowClass
= "EGRATest";
717 //glconShowKey = "M-Grave";
722 conProcessArgs
!true(args
);
724 egraCreateSystemWindow("EGRA Test", allowResize
:false);
726 vbwin
.addEventListener((QuitEvent evt
) {
727 if (vbwin
.closed
) return;
728 if (isQuitRequested
) { vbwin
.close(); return; }
732 static if (is(typeof(&vbwin
.closeQuery
))) {
733 vbwin
.closeQuery
= delegate () { concmd("quit"); egraPostDoConCommands(); };
736 mainPane
= new MainPaneWindow();
737 //egraSkipScreenClear = true; // main pane is fullscreen
742 vbwin
.eventLoop(1000*10,
744 egraProcessConsole();
746 delegate (KeyEvent event
) {
747 if (egraOnKey(event
)) return;
749 delegate (MouseEvent event
) {
750 if (egraOnMouse(event
)) return;
752 delegate (dchar ch
) {
753 if (egraOnChar(ch
)) return;
758 conProcessQueue(int.max
/4);