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.params.width = 1.01f;
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 foreach (int y
; -16..+17) {
445 foreach (int x
; -16..+17) {
446 GxColor c
= gxGetPixel(lastMX
+x
, lastMY
+y
)|gxAlphaMask
;
447 int rx
= (x
+16)*rwdt
+rxofs
;
448 int ry
= (y
+16)*rwdt
+ryofs
;
449 gxFillRect(rx
, ry
, rwdt
, rwdt
, c
);
452 gxVLine(rxofs
+16*rwdt
+rwdt
/2-1, ryofs
, 32*rwdt
, GxColors
.white
);
453 gxHLine(rxofs
, ryofs
+16*rwdt
+rwdt
/2-1, 32*rwdt
, GxColors
.white
);
457 ulong accstt
= 0, fstt
;
464 .rotate(deg2rad(35.0f))
466 assert(!tmt
.isIdentity
);
470 .translate(0.5f, 0.5f)
473 gxagg
.withTransform(tmt
, {
474 gxagg
.moveTo(50, 50);
475 gxagg
.lineTo(60, 60);
476 gxagg
.moveTo(100, 100);
477 gxagg
.lineTo(140, 120);
479 // CW (because logical coords are upwards)
480 gxagg
.moveTo(200, 200);
481 gxagg
.lineTo(200, 100);
482 gxagg
.lineTo(100, 100);
483 gxagg
.lineTo(100, 200);
484 gxagg
.lineTo(200, 200);
486 // CCW (because logical coords are upwards)
487 gxagg
.moveTo(100, 100);
488 gxagg
.lineTo(200, 100);
489 gxagg
.lineTo(200, 200);
490 gxagg
.lineTo(100, 200);
493 //gxagg.flipOrientation = true;
494 //gxagg.dumpVertices();
500 gxagg
.render(gxrgba(0, 127, 0, 127));
501 accstt
+= clockMicro()-fstt
;
504 //gxagg.dumpVertices();
507 gxagg
.render(gxrgba(127, 0, 0, 255));
508 accstt
+= clockMicro()-fstt
;
516 //gxagg.dashContour();
518 gxagg
.render(gxrgba(255, 255, 0, 255));
519 accstt
+= clockMicro()-fstt
;
523 gxagg
.paramsContour
.width
= 6;
526 gxagg
.render(gxrgba(255, 255, 255, 255));
527 accstt
+= clockMicro()-fstt
;
531 gxagg
.flipOrientation
= true;
534 gxagg
.render(gxrgba(0, 255, 0, 255));
535 accstt
+= clockMicro()-fstt
;
536 gxagg
.flipOrientation
= false;
539 { import core
.stdc
.stdio
; printf("total rect render microsecs: %u\n", cast(uint)accstt
); }
541 //gxagg.render(gxrgba(0, 127, 0, 127));
547 .roundedRect(400.5f, 600.5f, 96, 28, 8)
549 //.render(gxRGB!(192, 192, 192));
551 .render(AGGVGradient3(gxagg.rasterMinY, gxRGB!(127, 127, 127),
552 gxagg.rasterMaxY, gxRGB!(142, 142, 142),
553 20, gxRGB!(196, 196, 196)));
556 .render(AGGVGradient3(gxagg.rasterMinY, gxRGB!(255, 0, 0),
557 gxagg.rasterMaxY, gxRGB!(0, 255, 0),
558 20, gxRGB!(0, 0, 255)));
560 .render(AGGHGradient(gxagg
.rasterMinX
, gxRGBA
!(255, 0, 0, 127),
561 gxagg
.rasterMaxX
, gxRGBA
!(0, 255, 0, 90)));
568 if (gxFontCharPathBounds(dch
, bounds
[])) {
569 //conwriteln("bounds: (", bounds[0], ",", bounds[1], ")-(", bounds[2], ",", bounds[3], ")");
571 immutable float gwdt
= bounds
[2]-bounds
[0];
572 immutable float ghgt
= bounds
[3]-bounds
[1];
573 float scale
= desthgt
/ghgt
;
577 .translate(-bounds
[0]*scale
+100.5f, -bounds
[1]*scale
+100.5f);
578 gxagg
.withTransform(tmx
, {
582 if (gxFontCharToPath(dch
)) {
586 //.render(GxColors.k8orange);
589 gxagg
.render(AGGVGradient3(gxagg
.rasterMinY
, gxRGB
!(200, 73, 0),
590 gxagg
.rasterMaxY
, gxRGB
!(255, 128, 0)));
591 accstt
+= clockMicro()-fstt
;
593 int emb
= cast(int)(4/scale
);
597 if (gxFontCharPathEmboldenBounds(dch
, emb
, ebounds
[])) {
598 immutable float ewdt
= ebounds
[2]-ebounds
[0];
599 immutable float ehgt
= ebounds
[3]-ebounds
[1];
600 gxagg
.transform
.translate(-(ewdt
-gwdt
)*0.5f*scale
, (ehgt
-ghgt
)*0.5f*scale
);
601 if (gxFontCharToPathEmbolden(dch
, emb
)) {
606 gxagg
.render(GxColors
.green
);
607 accstt
+= clockMicro()-fstt
;
611 { import core
.stdc
.stdio
; printf("total glyph render microsecs: %u\n", cast(uint)accstt
); }
615 static if (is(typeof({immutable string s
= import("xbnd.d");}))) {
616 mixin(import("xbnd.d"));
619 enum hasxbnd
= false;
625 if (gxFontCharPathBounds(gdch
, gbounds
[])) {
627 immutable float gwdt
= gbounds
[2]-gbounds
[0];
628 immutable float ghgt
= gbounds
[3]-gbounds
[1];
629 float scale
= desthgt
/ghgt
;
633 .translate(-bounds
[0]*scale
+200.5f, -bounds
[1]*scale
+200.5f);
634 gxagg
.withTransform(tmx
, {
635 gxagg
.resetParams().beginPath();
636 if (gxFontCharToPath(gdch
)) {
637 //gxagg.flipOrientation = true;
638 gxagg
.paramsContour
.width
= 8;
640 //gxagg.render(gxrgba(0, 155, 0, 255));
641 gxagg
.render(gxagg
.vgradient(gxrgb(0, 38, 0), gxrgb(0, 98, 0)));
642 gxagg
.flipOrientation
= false;
644 gxagg
.resetParams().beginPath();
645 if (gxFontCharToPath(gdch
)) {
647 static if (hasxbnd
) {
648 gxagg
.render(AGGImgFill(0, 0, 32));
650 gxagg
.render(gxagg
.vgradient(gxrgb(255, 127, 0), gxrgb(155, 27, 0)));
657 static if (hasxbnd
) xbnd();
662 version(test_round_rect
) {
664 gxFillRoundedRect(lastMouseX
-16, lastMouseY
-16, 128, 96, rrad
, /*gxSolidWhite*/gxRGBA
!(0, 255, 0, 127));
665 //gxDrawRoundedRect(lastMouseX-16, lastMouseY-16, 128, 96, rrad, gxRGBA!(0, 255, 0, 127));
671 version(test_round_rect
) {
675 override bool onKeyBubble (KeyEvent event
) {
677 version(test_round_rect
) {
678 if (event
== "Plus") { ++rrad
; return true; }
679 if (event
== "Minus") { --rrad
; return true; }
681 if (event
== "C-Q") { concmd("quit_prompt"); return true; }
682 if (event
== "1") { concmd("window_titler"); return true; }
683 if (event
== "2") { concmd("window_tagoptions"); return true; }
684 if (event
== "Minus") { pbar
.current
= pbar
.current
-1; return true; }
685 if (event
== "Plus") { pbar
.current
= pbar
.current
+1; return true; }
687 if (event
== "Q") { if (gxagg
.bezierLimit
> 1) { --gxagg
.bezierLimit
; widgetChanged(); } return true; }
688 if (event
== "W") { if (gxagg
.bezierLimit
< 1000) { ++gxagg
.bezierLimit
; widgetChanged(); } return true; }
690 if (event
== "Z") { --tessType
; if (tessType
< -1) tessType
= -1; widgetChanged(); return true; }
691 if (event
== "X") { ++tessType
; widgetChanged(); return true; }
693 if (event
== "T") { timetest
= true; widgetChanged(); return true; }
694 //if (dbg_dump_keynames) conwriteln("key: ", event.toStr, ": ", event.modifierState&ModifierState.windows);
695 //foreach (const ref kv; mainAppKeyBindings.byKeyValue) if (event == kv.key) concmd(kv.value);
700 // returning `false` to avoid screen rebuilding by dispatcher
701 override bool onMouseBubble (MouseEvent event
) {
702 if (event
.type
== MouseEventType
.buttonPressed || event
.type
== MouseEventType
.buttonReleased
) {
703 if (lastMX
!= event
.x || lastMY
!= event
.y
) {
709 } else if (event
.modifierState
) {
710 // for OpenGL, this rebuilds the whole screen anyway
720 // ////////////////////////////////////////////////////////////////////////// //
721 void main (string
[] args
) {
722 //egraFontName = "PT Sans:pixelsize=16";
724 defaultColorStyle
.parseStyle(TestStyle
);
725 //egraDefaultFontSize = 48;
727 glconAllowOpenGLRender
= false;
729 sdpyWindowClass
= "EGRATest";
730 //glconShowKey = "M-Grave";
735 conProcessArgs
!true(args
);
737 egraCreateSystemWindow("EGRA Test", allowResize
:false);
739 vbwin
.addEventListener((QuitEvent evt
) {
740 if (vbwin
.closed
) return;
741 if (isQuitRequested
) { vbwin
.close(); return; }
745 static if (is(typeof(&vbwin
.closeQuery
))) {
746 vbwin
.closeQuery
= delegate () { concmd("quit"); egraPostDoConCommands(); };
749 mainPane
= new MainPaneWindow();
750 //egraSkipScreenClear = true; // main pane is fullscreen
755 vbwin
.eventLoop(1000*10,
757 egraProcessConsole();
759 delegate (KeyEvent event
) {
760 if (egraOnKey(event
)) return;
762 delegate (MouseEvent event
) {
763 if (egraOnMouse(event
)) return;
765 delegate (dchar ch
) {
766 if (egraOnChar(ch
)) return;
771 conProcessQueue(int.max
/4);