2 // Copyright (c) 2013 Mikko Mononen memon@inside.org
4 // This software is provided 'as-is', without any express or implied
5 // warranty. In no event will the authors be held liable for any damages
6 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
10 // 1. The origin of this software must not be misrepresented; you must not
11 // claim that you wrote the original software. If you use this software
12 // in a product, an acknowledgment in the product documentation would be
13 // appreciated but is not required.
14 // 2. Altered source versions must be plainly marked as such, and must not be
15 // misrepresented as being the original software.
16 // 3. This notice may not be removed or altered from any source distribution.
20 //import std.datetime;
22 import arsd
.simpledisplay
;
28 import iv
.nanovega
.blendish
;
29 import iv
.nanovega
.perf
;
32 version(nanovg_demo_shitfonts
) {
34 version = nanovg_demo_msfonts
;
39 // ////////////////////////////////////////////////////////////////////////// //
40 public class RepaintEvent
{} ///
42 __gshared RepaintEvent evRepaint
;
44 shared static this () {
45 evRepaint
= new RepaintEvent();
49 // ////////////////////////////////////////////////////////////////////////// //
55 enum WidgetIdBlendish
= 2;
58 // ////////////////////////////////////////////////////////////////////////// //
59 void fatal (string msg
) {
61 stderr
.writeln("FATAL: ", msg
);
67 // ////////////////////////////////////////////////////////////////////////// //
74 // ////////////////////////////////////////////////////////////////////////// //
76 int fontNormal
, fontBold
, fontIcons
;
79 @disable this (this); // no copies
83 // ////////////////////////////////////////////////////////////////////////// //
84 // blendish window position and flags
89 bool bndMoving
= false;
91 // "raw widget" position and flags
96 bool wgMoving
= false;
98 // common "raw widget" and blendish flags
102 // ////////////////////////////////////////////////////////////////////////// //
103 bool loadDemoData (NVGContext nvg
, ref DemoData data
) {
105 import std
.string
: format
;
107 if (nvg
is null) return false;
109 foreach (immutable idx
, ref NVGImage img
; data
.images
[]) {
110 img
= nvg
.createImage("data/images/image%u.jpg".format(idx
+1));
111 if (!img
.valid
) { stderr
.writeln("Could not load image #", idx
+1, "."); return false; }
114 data
.fontIcons
= nvg
.createFont("icons", "data/entypo.ttf");
115 if (data
.fontIcons
== FONS_INVALID
) { stderr
.writeln("Could not add font icons."); return false; }
117 version(nanovg_demo_msfonts
) {
118 enum FNN
= "Tahoma:noaa";
119 enum FNB
= "Tahoma:bold:noaa";
121 enum FNN
= "data/Roboto-Regular.ttf";
122 enum FNB
= "data/Roboto-Bold.ttf";
125 data
.fontNormal
= nvg
.createFont("sans", FNN
);
126 if (data
.fontNormal
== FONS_INVALID
) { stderr
.writeln("Could not add font italic."); return false; }
127 data
.fontBold
= nvg
.createFont("sans-bold", FNB
);
128 if (data
.fontBold
== FONS_INVALID
) { stderr
.writeln("Could not add font bold."); return false; }
130 //bndSetFont(vg.createFont("droidsans", "data/DroidSans.ttf"));
131 bndSetFont(data
.fontNormal
);
132 auto icons
= nvg
.createImage("data/images/blender_icons16.png");
133 if (!icons
.valid
) { stderr
.writeln("Could not load icons image."); return false; }
134 bndSetIconImage(icons
);
140 void freeDemoData (NVGContext nvg
, ref DemoData data
) {
141 if (nvg
== null) return;
142 foreach (ref NVGImage img
; data
.images
[]) img
.clear();
147 // ////////////////////////////////////////////////////////////////////////// //
149 enum ICON_SEARCH
= "\u1F50";
150 enum ICON_CIRCLED_CROSS
= "\u2716";
151 enum ICON_CHEVRON_RIGHT
= "\uE75E";
152 enum ICON_CHECK
= "\u2713";
153 enum ICON_LOGIN
= "\uE740";
154 enum ICON_TRASH
= "\uE729";
157 // ////////////////////////////////////////////////////////////////////////// //
158 void renderDemo (NVGContext nvg
, float mx
, float my
, float width
, float height
, float t
, int blowup
, ref DemoData data
) {
159 drawEyes(nvg
, width
-250, 50, 150, 100, mx
, my
, t
);
160 drawParagraph(nvg
, width
-450, 50, 150, 100, mx
, my
);
161 drawGraph(nvg
, 0, height
/2, width
, height
/2, t
);
162 drawColorWheel(nvg
, width
-300, height
-300, 250.0f, 250.0f, t
);
165 drawLines(nvg
, 120, height
-50, 600, 50, t
);
168 drawWidths(nvg
, 10, 50, 30);
171 drawCaps(nvg
, 10, 300, 30);
173 drawScissor(nvg
, 50, height
-80, t
);
176 scope(exit
) nvg
.restore();
179 import core
.stdc
.math
: sinf
;
180 nvg
.rotate(sinf(t
*0.3f)*5.0f/180.0f*NVG_PI
);
181 nvg
.scale(2.0f, 2.0f);
186 scope(exit
) nvg
.restore();
188 nvg
.translate(wgX
-50, wgY
-50);
189 nvg
.globalAlpha(wgMoving ?
0.4 : 0.9);
192 drawWindow(nvg
, "Widgets `n Stuff", 50, 50, 300, 400);
195 drawSearchBox(nvg
, "Search", x
, y
, 280, 25); y
+= 40;
197 drawDropDown(nvg
, "Effects", x
, y
, 280, 28); y
+= 45;
200 drawLabel(nvg
, "Login", x
, y
, 280, 20); y
+= 25;
201 drawEditBox(nvg
, "Email", x
, y
, 280, 28); y
+= 35;
202 drawEditBox(nvg
, "Password", x
, y
, 280, 28); y
+= 38;
203 drawCheckBox(nvg
, "Remember me", x
, y
, 140, 28);
204 drawButton(nvg
, ICON_LOGIN
, "Sign in", x
+138, y
, 140, 28, nvgRGBA(0, 96, 128, 255)); y
+= 45;
207 drawLabel(nvg
, "Diameter", x
, y
, 280, 20); y
+= 25;
208 drawEditBoxNum(nvg
, "123.00", "px", x
+180, y
, 100, 28);
209 drawSlider(nvg
, 0.4f, x
, y
, 170, 28); y
+= 55;
211 drawButton(nvg
, ICON_TRASH
, "Delete", x
, y
, 160, 28, nvgRGBA(128, 16, 8, 255));
212 drawButton(nvg
, ICON_NONE
, "Cancel", x
+170, y
, 110, 28, nvgRGBA(0, 0, 0, 0));
215 drawThumbnails(nvg
, 365, popy
-30, 160, 300, data
.images
[], t
);
219 drawBlendish(nvg
, bndX
, bndY
, bndW
, bndH
, t
);
222 if (wgOnTop
) { drawBnd(); drawWidget(); } else { drawWidget(); drawBnd(); }
224 nvg
.pickid
= NVGNoPick
;
228 // ////////////////////////////////////////////////////////////////////////// //
229 void drawWindow (NVGContext nvg
, const(char)[] title
, float x
, float y
, float w
, float h
) {
230 enum cornerRadius
= 3.0f;
233 scope(exit
) nvg
.restore();
237 nvg
.roundedRect(x
, y
, w
, h
, cornerRadius
);
238 nvg
.currFillPickId
= WidgetIdRaw
;
239 nvg
.fillColor
= nvgRGBA(28, 30, 34, 192);
240 //vg.fillColor(nvgRGBA(0, 0, 0, 128));
245 nvg
.rect(x
-10, y
-10, w
+20, h
+30);
246 nvg
.roundedRect(x
, y
, w
, h
, cornerRadius
);
247 nvg
.pathWinding
= NVGSolidity
.Hole
;
248 nvg
.fillPaint
= nvg
.boxGradient(x
, y
+2, w
, h
, cornerRadius
*2, 10, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
253 nvg
.roundedRect(x
+1, y
+1, w
-2, 30, cornerRadius
-1);
254 nvg
.fillPaint
= nvg
.linearGradient(x
, y
, x
, y
+15, nvgRGBA(255, 255, 255, 8), nvgRGBA(0, 0, 0, 16));
258 nvg
.moveTo(x
+0.5f, y
+0.5f+30);
259 nvg
.lineTo(x
+0.5f+w
-1, y
+0.5f+30);
260 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 32);
263 nvg
.fontSize
= 18.0f;
264 nvg
.fontFace
= "sans-bold";
265 nvg
.textAlign(NVGTextAlign
.H
.Center
, NVGTextAlign
.V
.Middle
);
268 nvg
.fillColor
= nvgRGBA(0, 0, 0, 128);
269 nvg
.text(x
+w
/2, y
+16+1, title
);
272 nvg
.fillColor
= nvgRGBA(220, 220, 220, 160);
273 nvg
.text(x
+w
/2, y
+16, title
);
277 void drawSearchBox (NVGContext nvg
, const(char)[] text
, float x
, float y
, float w
, float h
) {
278 immutable float cornerRadius
= h
/2-1;
282 nvg
.roundedRect(x
, y
, w
, h
, cornerRadius
);
283 nvg
.fillPaint
= nvg
.boxGradient(x
, y
+1.5f, w
, h
, h
/2, 5, nvgRGBA(0, 0, 0, 16), nvgRGBA(0, 0, 0, 92));
288 vg.roundedRect(x+0.5f, y+0.5f, w-1, h-1, cornerRadius-0.5f);
289 vg.strokeColor = nvgRGBA(0, 0, 0, 48);
293 nvg
.fontSize
= h
*1.3f;
294 nvg
.fontFace
= "icons";
295 nvg
.fillColor
= nvgRGBA(255, 255, 255, 64);
296 nvg
.textAlign
= NVGTextAlign
.V
.Middle
;
297 nvg
.textAlign
= NVGTextAlign
.H
.Center
;
298 nvg
.text(x
+h
*0.55f, y
+h
*0.55f, ICON_SEARCH
);
300 nvg
.fontSize
= 20.0f;
301 nvg
.fontFace
= "sans";
302 nvg
.fillColor
= nvgRGBA(255, 255, 255, 32);
303 nvg
.textAlign
= NVGTextAlign
.H
.Left
;
304 nvg
.text(x
+h
*1.05f, y
+h
*0.5f, text
);
306 nvg
.fontSize
= h
*1.3f;
307 nvg
.fontFace
= "icons";
308 nvg
.fillColor
= nvgRGBA(255, 255, 255, 32);
309 nvg
.textAlign
= NVGTextAlign
.H
.Center
;
310 nvg
.text(x
+w
-h
*0.55f, y
+h
*0.55f, ICON_CIRCLED_CROSS
);
314 void drawDropDown (NVGContext nvg
, const(char)[] text
, float x
, float y
, float w
, float h
) {
315 enum cornerRadius
= 4.0f;
318 nvg
.roundedRect(x
+1, y
+1, w
-2, h
-2, cornerRadius
-1);
319 nvg
.fillPaint
= nvg
.linearGradient(x
, y
, x
, y
+h
, nvgRGBA(255, 255, 255, 16), nvgRGBA(0, 0, 0, 16));
323 nvg
.roundedRect(x
+0.5f, y
+0.5f, w
-1, h
-1, cornerRadius
-0.5f);
324 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 48);
327 nvg
.fontSize
= 20.0f;
328 nvg
.fontFace
= "sans";
329 nvg
.fillColor
= nvgRGBA(255, 255, 255, 160);
330 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
331 nvg
.text(x
+h
*0.3f, y
+h
*0.5f, text
);
333 nvg
.fontSize
= h
*1.3f;
334 nvg
.fontFace
= "icons";
335 nvg
.fillColor
= nvgRGBA(255, 255, 255, 64);
336 nvg
.textAlign
= NVGTextAlign
.H
.Center
;
337 nvg
.text(x
+w
-h
*0.5f, y
+h
*0.5f, ICON_CHEVRON_RIGHT
);
341 void drawLabel (NVGContext nvg
, const(char)[] text
, float x
, float y
, float w
, float h
) {
342 nvg
.fontSize
= 18.0f;
343 nvg
.fontFace
= "sans";
344 nvg
.fillColor
= nvgRGBA(255, 255, 255, 128);
346 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
347 nvg
.text(x
, y
+h
*0.5f, text
);
351 void drawEditBoxBase (NVGContext nvg
, float x
, float y
, float w
, float h
) {
354 nvg
.roundedRect(x
+1, y
+1, w
-2, h
-2, 4-1);
355 nvg
.fillPaint
= nvg
.boxGradient(x
+1, y
+1+1.5f, w
-2, h
-2, 3, 4, nvgRGBA(255, 255, 255, 32), nvgRGBA(32, 32, 32, 32));
359 nvg
.roundedRect(x
+0.5f, y
+0.5f, w
-1, h
-1, 4-0.5f);
360 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 48);
365 void drawEditBox (NVGContext nvg
, const(char)[] text
, float x
, float y
, float w
, float h
) {
366 drawEditBoxBase(nvg
, x
, y
, w
, h
);
367 nvg
.fontSize
= 20.0f;
368 nvg
.fontFace
= "sans";
369 nvg
.fillColor
= nvgRGBA(255, 255, 255, 64);
370 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
371 nvg
.text(x
+h
*0.3f, y
+h
*0.5f, text
);
375 public void drawEditBoxNum (NVGContext nvg
, const(char)[] text
, const(char)[] units
, float x
, float y
, float w
, float h
) {
376 drawEditBoxBase(nvg
, x
, y
, w
, h
);
378 immutable float uw
= nvg
.textBounds(0, 0, units
, null);
380 nvg
.fontSize
= 18.0f;
381 nvg
.fontFace
= "sans";
382 nvg
.fillColor
= nvgRGBA(255, 255, 255, 64);
383 nvg
.textAlign(NVGTextAlign
.H
.Right
, NVGTextAlign
.V
.Middle
);
384 nvg
.text(x
+w
-h
*0.3f, y
+h
*0.5f, units
);
386 nvg
.fontSize
= 20.0f;
387 nvg
.fontFace
= "sans";
388 nvg
.fillColor
= nvgRGBA(255, 255, 255, 128);
389 nvg
.text(x
+w
-uw
-h
*0.5f, y
+h
*0.5f, text
);
393 void drawCheckBox (NVGContext nvg
, const(char)[] text
, float x
, float y
, float w
, float h
) {
394 nvg
.fontSize
= 18.0f;
395 nvg
.fontFace
= "sans";
396 nvg
.fillColor
= nvgRGBA(255, 255, 255, 160);
398 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
399 nvg
.text(x
+28, y
+h
*0.5f, text
);
402 nvg
.roundedRect(x
+1, y
+cast(int)(h
*0.5f)-9, 18, 18, 3);
403 nvg
.fillPaint
= nvg
.boxGradient(x
+1, y
+cast(int)(h
*0.5f)-9+1, 18, 18, 3, 3, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 92));
407 nvg
.fontFace
= "icons";
408 nvg
.fillColor
= nvgRGBA(255, 255, 255, 128);
409 nvg
.textAlign
= NVGTextAlign
.H
.Center
;
410 nvg
.text(x
+9+2, y
+h
*0.5f, ICON_CHECK
);
414 void drawButton (NVGContext nvg
, const(char)[] preicon
, const(char)[] text
, float x
, float y
, float w
, float h
, NVGColor col
) {
415 enum float cornerRadius
= 4.0f;
418 nvg
.roundedRect(x
+1, y
+1, w
-2, h
-2, cornerRadius
-1);
419 if (!col
.isTransparent
) {
423 nvg
.fillPaint
= nvg
.linearGradient(x
, y
, x
, y
+h
, nvgRGBA(255, 255, 255, col
.isTransparent ?
16 : 32), nvgRGBA(0, 0, 0, col
.isTransparent ?
16 : 32));
427 nvg
.roundedRect(x
+0.5f, y
+0.5f, w
-1, h
-1, cornerRadius
-0.5f);
428 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 48);
431 nvg
.fontSize
= 20.0f;
432 nvg
.fontFace
= "sans-bold";
434 immutable float tw
= nvg
.textBounds(0, 0, text
, null);
437 if (preicon
.length
) {
438 nvg
.fontSize
= h
*1.3f;
439 nvg
.fontFace
= "icons";
440 iw
= nvg
.textBounds(0, 0, preicon
, null);
444 if (preicon
.length
) {
445 nvg
.fontSize
= h
*1.3f;
446 nvg
.fontFace
= "icons";
447 nvg
.fillColor
= nvgRGBA(255, 255, 255, 96);
448 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
449 nvg
.text(x
+w
*0.5f-tw
*0.5f-iw
*0.75f, y
+h
*0.5f, preicon
);
452 nvg
.fontSize
= 20.0f;
453 nvg
.fontFace
= "sans-bold";
454 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Middle
);
455 nvg
.fillColor
= nvgRGBA(0, 0, 0, 160);
456 nvg
.text(x
+w
*0.5f-tw
*0.5f+iw
*0.25f, y
+h
*0.5f-1, text
);
457 nvg
.fillColor
= nvgRGBA(255, 255, 255, 160);
458 nvg
.text(x
+w
*0.5f-tw
*0.5f+iw
*0.25f, y
+h
*0.5f, text
);
462 void drawSlider (NVGContext nvg
, float pos
, float x
, float y
, float w
, float h
) {
463 immutable float cy
= y
+cast(int)(h
*0.5f);
464 immutable float kr
= cast(int)(h
*0.25f);
467 scope(exit
) nvg
.restore();
471 nvg
.roundedRect(x
, cy
-2, w
, 4, 2);
472 nvg
.fillPaint
= nvg
.boxGradient(x
, cy
-2+1, w
, 4, 2, 2, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 128));
477 nvg
.rect(x
+cast(int)(pos
*w
)-kr
-5, cy
-kr
-5, kr
*2+5+5, kr
*2+5+5+3);
478 nvg
.circle(x
+cast(int)(pos
*w
), cy
, kr
);
479 nvg
.pathWinding
= NVGSolidity
.Hole
;
480 nvg
.fillPaint
= nvg
.radialGradient(x
+cast(int)(pos
*w
), cy
+1, kr
-3, kr
+3, nvgRGBA(0, 0, 0, 64), nvgRGBA(0, 0, 0, 0));
485 nvg
.circle(x
+cast(int)(pos
*w
), cy
, kr
-1);
486 nvg
.fillColor
= nvgRGBA(40, 43, 48, 255);
488 nvg
.fillPaint
= nvg
.linearGradient(x
, cy
-kr
, x
, cy
+kr
, nvgRGBA(255, 255, 255, 16), nvgRGBA(0, 0, 0, 16));
492 nvg
.circle(x
+cast(int)(pos
*w
), cy
, kr
-0.5f);
493 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 92);
498 void drawEyes (NVGContext nvg
, float x
, float y
, float w
, float h
, float mx
, float my
, float t
) {
499 import core
.stdc
.math
: pow
, sinf
, sqrtf
;
501 immutable float ex
= w
*0.23f;
502 immutable float ey
= h
*0.5f;
503 immutable float lx
= x
+ex
;
504 immutable float ly
= y
+ey
;
505 immutable float rx
= x
+w
-ex
;
506 immutable float ry
= y
+ey
;
507 immutable float br
= (ex
< ey ? ex
: ey
)*0.5f;
508 immutable float blink
= 1-pow(sinf(t
*0.5f), 200)*0.8f;
511 nvg
.ellipse(lx
+3.0f, ly
+16.0f, ex
, ey
);
512 nvg
.ellipse(rx
+3.0f, ry
+16.0f, ex
, ey
);
513 nvg
.fillPaint
= nvg
.linearGradient(x
, y
+h
*0.5f, x
+w
*0.1f, y
+h
, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 16));
517 nvg
.ellipse(lx
, ly
, ex
, ey
);
518 nvg
.ellipse(rx
, ry
, ex
, ey
);
519 nvg
.fillPaint
= nvg
.linearGradient(x
, y
+h
*0.25f, x
+w
*0.1f, y
+h
, nvgRGBA(220, 220, 220, 255), nvgRGBA(128, 128, 128, 255));
522 void drawPupil (in float px
, in float py
) {
523 float dx
= (mx
-px
)/(ex
*10);
524 float dy
= (my
-py
)/(ey
*10);
525 immutable float d
= sqrtf(dx
*dx
+dy
*dy
);
526 if (d
> 1.0f) { dx
/= d
; dy
/= d
; }
530 nvg
.ellipse(px
+dx
, py
+dy
+ey
*0.25f*(1-blink
), br
, br
*blink
);
531 nvg
.fillColor
= nvgRGBA(32, 32, 32, 255);
539 nvg
.ellipse(lx
, ly
, ex
, ey
);
540 nvg
.fillPaint
= nvg
.radialGradient(lx
-ex
*0.25f, ly
-ey
*0.5f, ex
*0.1f, ex
*0.75f, nvgRGBA(255, 255, 255, 128), nvgRGBA(255, 255, 255, 0));
544 nvg
.ellipse(rx
, ry
, ex
, ey
);
545 nvg
.fillPaint
= nvg
.radialGradient(rx
-ex
*0.25f, ry
-ey
*0.5f, ex
*0.1f, ex
*0.75f, nvgRGBA(255, 255, 255, 128), nvgRGBA(255, 255, 255, 0));
550 void drawGraph (NVGContext nvg
, float x
, float y
, float w
, float h
, float t
) {
551 import core
.stdc
.math
: cosf
, sinf
;
553 immutable float[6] samples
= [
554 (1+sinf(t
*1.2345f+cosf(t
*0.33457f)*0.44f))*0.5f,
555 (1+sinf(t
*0.68363f+cosf(t
*1.3f)*1.55f))*0.5f,
556 (1+sinf(t
*1.1642f+cosf(t
*0.33457)*1.24f))*0.5f,
557 (1+sinf(t
*0.56345f+cosf(t
*1.63f)*0.14f))*0.5f,
558 (1+sinf(t
*1.6245f+cosf(t
*0.254f)*0.3f))*0.5f,
559 (1+sinf(t
*0.345f+cosf(t
*0.03f)*0.6f))*0.5f,
562 immutable float dx
= w
/5.0f;
564 foreach (immutable i
, immutable float sm
; samples
[]) {
571 nvg
.moveTo(sx
[0], sy
[0]);
572 foreach (immutable i
; 1..6) nvg
.bezierTo(sx
[i
-1]+dx
*0.5f, sy
[i
-1], sx
[i
]-dx
*0.5f, sy
[i
], sx
[i
], sy
[i
]);
573 nvg
.lineTo(x
+w
, y
+h
);
575 nvg
.fillPaint
= nvg
.linearGradient(x
, y
, x
, y
+h
, nvgRGBA(0, 160, 192, 0), nvgRGBA(0, 160, 192, 64));
580 nvg
.moveTo(sx
[0], sy
[0]+2);
581 foreach (immutable i
; 1..6) nvg
.bezierTo(sx
[i
-1]+dx
*0.5f, sy
[i
-1]+2, sx
[i
]-dx
*0.5f, sy
[i
]+2, sx
[i
], sy
[i
]+2);
582 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 32);
583 nvg
.strokeWidth
= 3.0f;
587 nvg
.moveTo(sx
[0], sy
[0]);
588 foreach (immutable i
; 1..6) nvg
.bezierTo(sx
[i
-1]+dx
*0.5f, sy
[i
-1], sx
[i
]-dx
*0.5f, sy
[i
], sx
[i
], sy
[i
]);
589 nvg
.strokeColor
= nvgRGBA(0, 160, 192, 255);
590 nvg
.strokeWidth
= 3.0f;
594 foreach (immutable i
; 0..6) {
596 nvg
.rect(sx
[i
]-10, sy
[i
]-10+2, 20, 20);
597 nvg
.fillPaint
= nvg
.radialGradient(sx
[i
], sy
[i
]+2, 3.0f, 8.0f, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 0));
602 foreach (immutable i
; 0..6) nvg
.circle(sx
[i
], sy
[i
], 4.0f);
603 nvg
.fillColor
= nvgRGBA(0, 160, 192, 255);
607 foreach (immutable i
; 0..6) nvg
.circle(sx
[i
], sy
[i
], 2.0f);
608 nvg
.fillColor
= nvgRGBA(220, 220, 220, 255);
611 nvg
.strokeWidth
= 1.0f;
615 void drawSpinner (NVGContext nvg
, float cx
, float cy
, float r
, float t
) {
616 import core
.stdc
.math
: cosf
, sinf
;
618 immutable float a0
= 0.0f+t
*6;
619 immutable float a1
= NVG_PI
+t
*6;
620 immutable float r0
= r
;
621 immutable float r1
= r
*0.75f;
624 scope(exit
) nvg
.restore();
627 nvg
.arc(NVGWinding
.CW
, cx
, cy
, r0
, a0
, a1
);
628 nvg
.arc(NVGWinding
.CCW
, cx
, cy
, r1
, a1
, a0
);
631 immutable float ax
= cx
+cosf(a0
)*(r0
+r1
)*0.5f;
632 immutable float ay
= cy
+sinf(a0
)*(r0
+r1
)*0.5f;
633 immutable float bx
= cx
+cosf(a1
)*(r0
+r1
)*0.5f;
634 immutable float by
= cy
+sinf(a1
)*(r0
+r1
)*0.5f;
635 nvg
.fillPaint
= nvg
.linearGradient(ax
, ay
, bx
, by
, nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 128));
640 void drawThumbnails (NVGContext nvg
, float x
, float y
, float w
, float h
, NVGImage
[] images
, float t
) {
641 import core
.stdc
.math
: cosf
;
643 enum cornerRadius
= 3.0f;
644 //float ix, iy, iw, ih;
648 immutable float stackh
= (images
.length
/2)*(thumb
+10)+10;
649 immutable float u
= (1+cosf(t
*0.5f))*0.5f;
650 immutable float u2
= (1-cosf(t
*0.2f))*0.5f;
654 scope(exit
) nvg
.restore();
658 nvg
.rect(x
-10, y
-10, w
+20, h
+30);
659 nvg
.roundedRect(x
, y
, w
, h
, cornerRadius
);
660 nvg
.pathWinding
= NVGSolidity
.Hole
;
661 nvg
.fillPaint
= nvg
.boxGradient(x
, y
+4, w
, h
, cornerRadius
*2, 20, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
666 nvg
.roundedRect(x
, y
, w
, h
, cornerRadius
);
667 nvg
.moveTo(x
-10, y
+arry
);
668 nvg
.lineTo(x
+1, y
+arry
-11);
669 nvg
.lineTo(x
+1, y
+arry
+11);
671 nvg
.currFillPickId
= WidgetIdRaw
;
672 nvg
.fillColor
= nvgRGBA(200, 200, 200, 255);
677 scope(exit
) nvg
.restore();
679 nvg
.scissor(x
, y
, w
, h
);
680 nvg
.translate(0, -(stackh
-h
)*u
);
682 immutable float dv
= 1.0f/cast(float)(images
.length
-1);
684 foreach (immutable int i
; 0..cast(int)images
.length
) {
687 tx
+= (i
%2)*(thumb
+10);
688 ty
+= (i
/2)*(thumb
+10);
690 float iw
, ih
, ix
, iy
;
691 int imgw
= images
[i
].width
;
692 int imgh
= images
[i
].height
;
695 ih
= iw
*cast(float)imgh
/cast(float)imgw
;
697 iy
= -(ih
-thumb
)*0.5f;
700 iw
= ih
*cast(float)imgw
/cast(float)imgh
;
701 ix
= -(iw
-thumb
)*0.5f;
705 immutable float v
= i
*dv
;
706 immutable float a
= nvg__clamp((u2
-v
)/dv
, 0, 1);
708 if (a
< 1.0f) drawSpinner(nvg
, tx
+thumb
/2, ty
+thumb
/2, thumb
*0.25f, t
);
711 nvg
.roundedRect(tx
, ty
, thumb
, thumb
, 5);
712 nvg
.fillPaint
= nvg
.imagePattern(tx
+ix
, ty
+iy
, iw
, ih
, 0.0f/180.0f*NVG_PI
, images
[i
], a
);
716 nvg
.rect(tx
-5, ty
-5, thumb
+10, thumb
+10);
717 nvg
.roundedRect(tx
, ty
, thumb
, thumb
, 6);
718 nvg
.pathWinding
= NVGSolidity
.Hole
;
719 nvg
.fillPaint
= nvg
.boxGradient(tx
-1, ty
, thumb
+2, thumb
+2, 5, 3, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
723 nvg
.roundedRect(tx
+0.5f, ty
+0.5f, thumb
-1, thumb
-1, 4-0.5f);
724 nvg
.strokeWidth
= 1.0f;
725 nvg
.strokeColor
= nvgRGBA(255, 255, 255, 192);
732 nvg
.rect(x
+4, y
, w
-8, 6);
733 nvg
.fillPaint
= nvg
.linearGradient(x
, y
, x
, y
+6, nvgRGBA(200, 200, 200, 255), nvgRGBA(200, 200, 200, 0));
737 nvg
.rect(x
+4, y
+h
-6, w
-8, 6);
738 nvg
.fillPaint
= nvg
.linearGradient(x
, y
+h
, x
, y
+h
-6, nvgRGBA(200, 200, 200, 255), nvgRGBA(200, 200, 200, 0));
743 nvg
.roundedRect(x
+w
-12, y
+4, 8, h
-8, 3);
744 nvg
.fillPaint
= nvg
.boxGradient(x
+w
-12+1, y
+4+1, 8, h
-8, 3, 4, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 92));
745 //vg.fillColor = nvgRGBA(255, 0, 0, 128);
748 immutable float scrollh
= (h
/stackh
)*(h
-8);
750 nvg
.roundedRect(x
+w
-12+1, y
+4+1+(h
-8-scrollh
)*u
, 8-2, scrollh
-2, 2);
751 nvg
.fillPaint
= nvg
.boxGradient(x
+w
-12-1, y
+4+(h
-8-scrollh
)*u
-1, 8, scrollh
, 3, 4, nvgRGBA(220, 220, 220, 255), nvgRGBA(128, 128, 128, 255));
752 //vg.fillColor = nvgRGBA(0, 0, 0, 128);
757 void drawColorWheel (NVGContext nvg
, float x
, float y
, float w
, float h
, float t
) {
758 import core
.stdc
.math
: cosf
, sinf
;
760 immutable float hue
= sinf(t
*0.12f);
763 scope(exit
) nvg
.restore();
768 vg.fillColor(nvgRGBA(255, 0, 0, 128));
772 immutable float cx
= x
+w
*0.5f;
773 immutable float cy
= y
+h
*0.5f;
774 immutable float r1
= (w
< h ? w
: h
)*0.5f-5.0f;
775 immutable float r0
= r1
-20.0f;
776 immutable float aeps
= 0.5f/r1
; // half a pixel arc length in radians (2pi cancels out).
778 foreach (immutable int i
; 0..6) {
779 float a0
= cast(float)i
/6.0f*NVG_PI
*2.0f-aeps
;
780 float a1
= cast(float)(i
+1.0f)/6.0f*NVG_PI
*2.0f+aeps
;
782 nvg
.arc(NVGWinding
.CW
, cx
, cy
, r0
, a0
, a1
);
783 nvg
.arc(NVGWinding
.CCW
, cx
, cy
, r1
, a1
, a0
);
785 immutable float ax
= cx
+cosf(a0
)*(r0
+r1
)*0.5f;
786 immutable float ay
= cy
+sinf(a0
)*(r0
+r1
)*0.5f;
787 immutable float bx
= cx
+cosf(a1
)*(r0
+r1
)*0.5f;
788 immutable float by
= cy
+sinf(a1
)*(r0
+r1
)*0.5f;
789 nvg
.fillPaint
= nvg
.linearGradient(ax
, ay
, bx
, by
, nvgHSLA(a0
/(NVG_PI
*2), 1.0f, 0.55f, 255), nvgHSLA(a1
/(NVG_PI
*2), 1.0f, 0.55f, 255));
794 nvg
.circle(cx
, cy
, r0
-0.5f);
795 nvg
.circle(cx
, cy
, r1
+0.5f);
796 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 64);
797 nvg
.strokeWidth
= 1.0f;
803 scope(exit
) nvg
.restore();
805 nvg
.translate(cx
, cy
);
806 nvg
.rotate(hue
*NVG_PI
*2);
809 nvg
.strokeWidth
= 2.0f;
811 nvg
.rect(r0
-1, -3, r1
-r0
+2, 6);
812 nvg
.strokeColor
= nvgRGBA(255, 255, 255, 192);
816 nvg
.rect(r0
-2-10, -4-10, r1
-r0
+4+20, 8+20);
817 nvg
.rect(r0
-2, -4, r1
-r0
+4, 8);
818 nvg
.pathWinding
= NVGSolidity
.Hole
;
819 nvg
.fillPaint
= nvg
.boxGradient(r0
-3, -5, r1
-r0
+6, 10, 2, 4, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
823 immutable float r
= r0
-6;
824 immutable float ax
= cosf(120.0f/180.0f*NVG_PI
)*r
;
825 immutable float ay
= sinf(120.0f/180.0f*NVG_PI
)*r
;
826 immutable float bx
= cosf(-120.0f/180.0f*NVG_PI
)*r
;
827 immutable float by
= sinf(-120.0f/180.0f*NVG_PI
)*r
;
834 nvg
.fillPaint
= nvg
.linearGradient(r
, 0, ax
, ay
, nvgHSLA(hue
, 1.0f, 0.5f, 255), nvgRGBA(255, 255, 255, 255));
836 nvg
.fillPaint
= nvg
.linearGradient((r
+ax
)*0.5f, (0+ay
)*0.5f, bx
, by
, nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255));
838 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 64);
841 // Select circle on triangle
842 immutable float aax
= cosf(120.0f/180.0f*NVG_PI
)*r
*0.3f;
843 immutable float aay
= sinf(120.0f/180.0f*NVG_PI
)*r
*0.4f;
844 nvg
.strokeWidth
= 2.0f;
846 nvg
.circle(aax
, aay
, 5);
847 nvg
.strokeColor
= nvgRGBA(255, 255, 255, 192);
851 nvg
.rect(aax
-20, aay
-20, 40, 40);
852 nvg
.circle(aax
, aay
, 7);
853 nvg
.pathWinding
= NVGSolidity
.Hole
;
854 nvg
.fillPaint
= nvg
.radialGradient(aax
, aay
, 7, 9, nvgRGBA(0, 0, 0, 64), nvgRGBA(0, 0, 0, 0));
860 void drawLines (NVGContext nvg
, float x
, float y
, float w
, float h
, float t
) {
861 import core
.stdc
.math
: cosf
, sinf
;
863 static immutable NVGLineCap
[3] joins
= [NVGLineCap
.Miter
, NVGLineCap
.Round
, NVGLineCap
.Bevel
];
864 static immutable NVGLineCap
[3] caps
= [NVGLineCap
.Butt
, NVGLineCap
.Round
, NVGLineCap
.Square
];
867 immutable float s
= w
/9.0f-pad
*2;
870 scope(exit
) nvg
.restore();
872 immutable float[4*2] pts
= [
873 -s
*0.25f+cosf(t
*0.3f)*s
*0.5f,
879 s
*0.25f+cosf(-t
*0.3f)*s
*0.5f,
880 sinf(-t
*0.3f)*s
*0.5f,
883 foreach (immutable int i
; 0..3) {
884 foreach (immutable int j
; 0..3) {
885 immutable float fx
= x
+s
*0.5f+(i
*3+j
)/9.0f*w
+pad
;
886 immutable float fy
= y
-s
*0.5f+pad
;
888 nvg
.lineCap
= caps
[i
];
889 nvg
.lineJoin
= joins
[j
];
891 nvg
.strokeWidth
= s
*0.3f;
892 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 160);
894 nvg
.moveTo(fx
+pts
[0], fy
+pts
[1]);
895 nvg
.lineTo(fx
+pts
[2], fy
+pts
[3]);
896 nvg
.lineTo(fx
+pts
[4], fy
+pts
[5]);
897 nvg
.lineTo(fx
+pts
[6], fy
+pts
[7]);
900 nvg
.lineCap
= NVGLineCap
.Butt
;
901 nvg
.lineJoin
= NVGLineCap
.Bevel
;
903 nvg
.strokeWidth
= 1.0f;
904 nvg
.strokeColor
= nvgRGBA(0, 192, 255, 255);
906 nvg
.moveTo(fx
+pts
[0], fy
+pts
[1]);
907 nvg
.lineTo(fx
+pts
[2], fy
+pts
[3]);
908 nvg
.lineTo(fx
+pts
[4], fy
+pts
[5]);
909 nvg
.lineTo(fx
+pts
[6], fy
+pts
[7]);
916 void drawParagraph (NVGContext nvg
, float x
, float y
, float width
, float height
, float mx
, float my
) {
917 static immutable string text
= "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
927 scope(exit
) nvg
.restore();
929 nvg
.fontSize
= 18.0f;
930 nvg
.fontFace
= "sans";
931 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Top
);
932 nvg
.textMetrics(null, null, &lineh
);
934 float gx
= 0, gy
= 0;
936 nvg
.textBreakLines(text
, width
, (in ref NVGTextRow
!char row
) {
937 NVGGlyphPosition
[100] glyphs
= void;
938 immutable bool hit
= (mx
> x
&& mx
< x
+width
&& my
>= y
&& my
< y
+lineh
);
941 nvg
.fillColor(nvgRGBA(255, 255, 255, (hit ?
64 : 16)));
942 nvg
.rect(x
, y
, row
.width
, lineh
);
945 nvg
.fillColor(nvgRGBA(255, 255, 255, 255));
946 nvg
.text(x
, y
, row
.row
);
949 float caretx
= (mx
< x
+row
.width
/2 ? x
: x
+row
.width
);
951 auto rglyphs
= nvg
.textGlyphPositions(x
, y
, row
.row
, glyphs
[]);
952 foreach (immutable j
, const ref glx
; rglyphs
) {
954 float x1
= (j
+1 < rglyphs
.length ? glyphs
[j
+1].x
: x
+row
.width
);
955 float gx_
= x0
*0.3f+x1
*0.7f;
956 if (mx
>= px
&& mx
< gx_
) caretx
= glx
.x
;
960 nvg
.rect(caretx
, y
, 1, lineh
);
961 nvg
.fillColor
= nvgRGBA(255, 192, 0, 255);
970 // return false; // to stop
976 import core
.stdc
.stdio
: snprintf
;
978 auto len
= snprintf(txt
.ptr
, (txt
).sizeof
, "%d", gutter
);
980 nvg
.fontSize
= 13.0f;
981 nvg
.textAlign(NVGTextAlign
.H
.Right
, NVGTextAlign
.V
.Middle
);
982 nvg
.textBounds(gx
, gy
, txt
[0..len
], bounds
[]);
985 nvg
.roundedRect(cast(int)bounds
[0]-4, cast(int)bounds
[1]-2, cast(int)(bounds
[2]-bounds
[0])+8, cast(int)(bounds
[3]-bounds
[1])+4, (cast(int)(bounds
[3]-bounds
[1])+4)/2-1);
986 nvg
.fillColor
= nvgRGBA(255, 192, 0, 255);
989 nvg
.fillColor
= nvgRGBA(32, 32, 32, 255);
990 nvg
.text(gx
, gy
, txt
[0..len
]);
995 nvg
.fontSize
= 13.0f;
996 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Top
);
997 nvg
.textLineHeight
= 1.2f;
999 nvg
.textBoxBounds(x
, y
, 150, "Hover your mouse over the text to see calculated caret position.", bounds
[]);
1001 // Fade the tooltip out when close to it.
1003 immutable float ggx
= nvg__absf((mx
-(bounds
[0]+bounds
[2])*0.5f)/(bounds
[0]-bounds
[2]));
1004 immutable float ggy
= nvg__absf((my
-(bounds
[1]+bounds
[3])*0.5f)/(bounds
[1]-bounds
[3]));
1006 immutable float a
= nvg__clamp(nvg__max(ggx
, ggy
)-0.5f, 0, 1);
1010 nvg
.fillColor
= nvgRGBA(220, 220, 220, 255);
1011 nvg
.roundedRect(bounds
[0]-2, bounds
[1]-2, cast(int)(bounds
[2]-bounds
[0])+4, cast(int)(bounds
[3]-bounds
[1])+4, 3);
1012 immutable int px
= cast(int)((bounds
[2]+bounds
[0])/2);
1013 nvg
.moveTo(px
, bounds
[1]-10);
1014 nvg
.lineTo(px
+7, bounds
[1]+1);
1015 nvg
.lineTo(px
-7, bounds
[1]+1);
1018 nvg
.fillColor
= nvgRGBA(0, 0, 0, 220);
1019 nvg
.textBox(x
, y
, 150, "Hover your mouse over the text to see calculated caret position.");
1024 void drawWidths(NVGContext nvg
, float x
, float y
, float width
) {
1026 scope(exit
) nvg
.restore();
1028 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 255);
1029 foreach (int i
; 0..20) {
1030 nvg
.strokeWidth
= (i
+0.5f)*0.1f;
1033 nvg
.lineTo(x
+width
, y
+width
*0.3f);
1040 void drawCaps (NVGContext nvg
, float x
, float y
, float width
) {
1041 static immutable NVGLineCap
[3] caps
= [NVGLineCap
.Butt
, NVGLineCap
.Round
, NVGLineCap
.Square
];
1042 enum lineWidth
= 8.0f;
1045 scope(exit
) nvg
.restore();
1048 nvg
.rect(x
-lineWidth
/2, y
, width
+lineWidth
, 40);
1049 nvg
.fillColor
= nvgRGBA(255, 255, 255, 32);
1053 nvg
.rect(x
, y
, width
, 40);
1054 nvg
.fillColor
= nvgRGBA(255, 255, 255, 32);
1057 nvg
.strokeWidth
= lineWidth
;
1058 foreach (int i
; 0..3) {
1059 nvg
.lineCap
= caps
[i
];
1060 nvg
.strokeColor
= nvgRGBA(0, 0, 0, 255);
1062 nvg
.moveTo(x
, y
+i
*10+5);
1063 nvg
.lineTo(x
+width
, y
+i
*10+5);
1069 void drawScissor (NVGContext nvg
, float x
, float y
, float t
) {
1071 scope(exit
) nvg
.restore();
1073 // Draw first rect and set scissor to it's area.
1074 nvg
.translate(x
, y
);
1075 nvg
.rotate(5.nvgDegrees
);
1077 nvg
.rect(-20, -20, 60, 40);
1078 nvg
.fillColor
= nvgRGBA(255, 0, 0, 255);
1080 nvg
.scissor(-20, -20, 60, 40);
1082 // Draw second rectangle with offset and rotation.
1083 nvg
.translate(40, 0);
1086 // Draw the intended second rectangle without any scissoring.
1089 scope(exit
) nvg
.restore();
1092 nvg
.rect(-20, -10, 60, 30);
1093 nvg
.fillColor
= nvgRGBA(255, 128, 0, 64);
1097 // Draw second rectangle with combined scissoring.
1098 nvg
.intersectScissor(-20, -10, 60, 30);
1100 nvg
.rect(-20, -10, 60, 30);
1101 nvg
.fillColor
= nvgRGBA(255, 128, 0, 255);
1106 // ////////////////////////////////////////////////////////////////////////// //
1107 void drawBlendish (NVGContext nvg
, float _x
, float _y
, float _w
, float _h
, float _t
) {
1108 import core
.stdc
.math
: fmodf
, cosf
, sinf
;
1109 import core
.stdc
.stdio
: printf
, snprintf
;
1114 version(nanovega_debug_clipping
) {
1115 nvg
.nvgClipDumpOn();
1116 scope(exit
) nvg
.nvgClipDumpOff();
1117 //{ import core.stdc.stdio; printf("==========================\n"); }
1121 scope(exit
) nvg
.restore();
1125 //nvg.rect(_x+50, _y+80, 160, 140);
1126 //nvg.roundedRect(_x+50, _y+80, 160, 140, 8);
1127 nvg
.ellipse(_x
+150, _y
+180, 120, 90);
1133 nvg
.ellipse(_x
+150, _y
+180, 90, 120);
1134 nvg
.clip(NVGClipMode
.Union
);
1139 scope(exit
) nvg
.restore();
1142 nvg
.ellipse(_x
+150, _y
+180, 60, 160);
1143 nvg
.clip(NVGClipMode
.Xor
);
1147 nvg.rect(0, 0, 1000, 1000);
1148 nvg.fillColor = NVGColor.yellow;
1155 //nvg.rect(_x+50, _y+80, 160, 140);
1156 //nvg.roundedRect(_x+50, _y+80, 160, 140, 8);
1157 //nvg.ellipse(_x+150, _y+180, 120, 90);
1158 nvg
.rect(_x
+30, _y
+30, 400, 400);
1160 nvg
.strokeWidth
= 1;
1161 nvg
.strokeColor
= NVGColor
.yellow
;
1164 nvg
.fillColor
= NVGColor
.yellow
;
1170 nvg
.globalAlpha(bndMoving ?
0.4 : 0.9);
1172 nvg
.bndBackground(_x
-10.0f, _y
-10.0f, _w
, _h
);
1173 nvg
.currFillPickId
= WidgetIdBlendish
;
1175 nvg
.bndToolButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, BND_ICONID
!(6, 3), "Default"); y
+= 25.0f;
1176 nvg
.bndToolButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, BND_ICONID
!(6, 3), "Hovered item"); y
+= 25.0f;
1177 nvg
.bndToolButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, BND_ICONID
!(6, 3), "Active"); y
+= 40.0f;
1179 nvg
.bndRadioButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, -1, "Default"); y
+= 25.0f;
1180 nvg
.bndRadioButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, -1, "Hovered item"); y
+= 25.0f;
1181 nvg
.bndRadioButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, -1, "Active"); y
+= 25.0f;
1183 nvg
.bndLabel(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, -1, "Label:"); y
+= BND_WIDGET_HEIGHT
;
1184 nvg
.bndChoiceButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, -1, "Default"); y
+= 25.0f;
1185 nvg
.bndChoiceButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, -1, "Hovered item"); y
+= 25.0f;
1186 nvg
.bndChoiceButton(x
, y
, 80.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, -1, "Active"); y
+= 25.0f;
1193 nvg
.bndOptionButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_DEFAULT
, "Default"); y
+= 25.0f;
1194 nvg
.bndOptionButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_HOVER
, "Hovered item"); y
+= 25.0f;
1195 nvg
.bndOptionButton(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_ACTIVE
, "Active"); y
+= 40.0f;
1197 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_DOWN
, BND_DEFAULT
, "Top", "100"); y
+= BND_WIDGET_HEIGHT
-2.0f;
1198 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, "Center", "100"); y
+= BND_WIDGET_HEIGHT
-2.0f;
1199 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_TOP
, BND_DEFAULT
, "Bottom", "100");
1205 nvg
.bndMenuBackground(mx
, my
, mw
, 120.0f, BND_CORNER_TOP
);
1206 nvg
.bndMenuLabel(mx
, my
, mw
, BND_WIDGET_HEIGHT
, -1, "Menu Title"); my
+= BND_WIDGET_HEIGHT
-2.0f;
1207 nvg
.bndMenuItem(mx
, my
, mw
, BND_WIDGET_HEIGHT
, BND_DEFAULT
, BND_ICONID
!(17, 3), "Default"); my
+= BND_WIDGET_HEIGHT
-2.0f;
1208 nvg
.bndMenuItem(mx
, my
, mw
, BND_WIDGET_HEIGHT
, BND_HOVER
, BND_ICONID
!(18, 3), "Hovered item!"); my
+= BND_WIDGET_HEIGHT
-2.0f;
1209 nvg
.bndMenuItem(mx
, my
, mw
, BND_WIDGET_HEIGHT
, BND_ACTIVE
, BND_ICONID
!(19, 3), "Active");
1214 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, "Default", "100"); y
+= 25.0f;
1215 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, "Hovered", "100"); y
+= 25.0f;
1216 nvg
.bndNumberField(x
, y
, 120.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, "Active", "100"); y
+= 40.0f;
1218 nvg
.bndRadioButton(x
, y
, 60.0f, BND_WIDGET_HEIGHT
, BND_CORNER_RIGHT
, BND_DEFAULT
, -1, "One"); x
+= 60.0f-1.0f;
1219 nvg
.bndRadioButton(x
, y
, 60.0f, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, -1, "Two"); x
+= 60.0f-1.0f;
1220 nvg
.bndRadioButton(x
, y
, 60.0f, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, -1, "Three"); x
+= 60.0f-1.0f;
1221 nvg
.bndRadioButton(x
, y
, 60.0f, BND_WIDGET_HEIGHT
, BND_CORNER_LEFT
, BND_ACTIVE
, -1, "Butts");
1225 float progress_value
= fmodf(_t
/10.0f, 1.0f);
1226 char[32] progressLabel
;
1227 int len
= cast(int)snprintf(progressLabel
.ptr
, progressLabel
.length
, "%d%%", cast(int)(progress_value
*100+0.5f));
1229 nvg
.bndSlider(x
, y
, 240, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, progress_value
, "Default", progressLabel
[0..len
]); y
+= 25.0f;
1230 nvg
.bndSlider(x
, y
, 240, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, progress_value
, "Hovered", progressLabel
[0..len
]); y
+= 25.0f;
1231 nvg
.bndSlider(x
, y
, 240, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, progress_value
, "Active", progressLabel
[0..len
]);
1233 float rw
= x
+240.0f-rx
;
1234 float s_offset
= sinf(_t
/2.0f)*0.5f+0.5f;
1235 float s_size
= cosf(_t
/3.11f)*0.5f+0.5f;
1237 nvg
.bndScrollBar(rx
, ry
, rw
, BND_SCROLLBAR_HEIGHT
, BND_DEFAULT
, s_offset
, s_size
); ry
+= 20.0f;
1238 nvg
.bndScrollBar(rx
, ry
, rw
, BND_SCROLLBAR_HEIGHT
, BND_HOVER
, s_offset
, s_size
); ry
+= 20.0f;
1239 nvg
.bndScrollBar(rx
, ry
, rw
, BND_SCROLLBAR_HEIGHT
, BND_ACTIVE
, s_offset
, s_size
);
1241 static immutable string edit_text
= "The quick brown fox";
1242 int textlen
= cast(int)edit_text
.length
+1;
1243 int t
= cast(int)(_t
*2);
1244 int idx1
= (t
/textlen
)%textlen
;
1245 int idx2
= idx1
+(t
%(textlen
-idx1
));
1248 nvg
.bndTextField(rx
, ry
, 240.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_DEFAULT
, -1, edit_text
, idx1
, idx2
); ry
+= 25.0f;
1249 nvg
.bndTextField(rx
, ry
, 240.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_HOVER
, -1, edit_text
, idx1
, idx2
); ry
+= 25.0f;
1250 nvg
.bndTextField(rx
, ry
, 240.0f, BND_WIDGET_HEIGHT
, BND_CORNER_NONE
, BND_ACTIVE
, -1, edit_text
, idx1
, idx2
);
1254 nvg
.bndScrollBar(rx
, ry
, BND_SCROLLBAR_WIDTH
, 240.0f, BND_DEFAULT
, s_offset
, s_size
); rx
+= 20.0f;
1255 nvg
.bndScrollBar(rx
, ry
, BND_SCROLLBAR_WIDTH
, 240.0f, BND_HOVER
, s_offset
, s_size
); rx
+= 20.0f;
1256 nvg
.bndScrollBar(rx
, ry
, BND_SCROLLBAR_WIDTH
, 240.0f, BND_ACTIVE
, s_offset
, s_size
);
1260 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_RIGHT
, BND_DEFAULT
, BND_ICONID
!(0, 10), null); x
+= BND_TOOL_WIDTH
-1;
1261 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(1, 10), null); x
+= BND_TOOL_WIDTH
-1;
1262 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(2, 10), null); x
+= BND_TOOL_WIDTH
-1;
1263 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(3, 10), null); x
+= BND_TOOL_WIDTH
-1;
1264 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(4, 10), null); x
+= BND_TOOL_WIDTH
-1;
1265 nvg
.bndToolButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_LEFT
, BND_DEFAULT
, BND_ICONID
!(5, 10), null); x
+= BND_TOOL_WIDTH
-1;
1268 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_RIGHT
, BND_DEFAULT
, BND_ICONID
!(0, 11), null); x
+= BND_TOOL_WIDTH
-1;
1269 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(1, 11), null); x
+= BND_TOOL_WIDTH
-1;
1270 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(2, 11), null); x
+= BND_TOOL_WIDTH
-1;
1271 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_DEFAULT
, BND_ICONID
!(3, 11), null); x
+= BND_TOOL_WIDTH
-1;
1272 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_ALL
, BND_ACTIVE
, BND_ICONID
!(4, 11), null); x
+= BND_TOOL_WIDTH
-1;
1273 nvg
.bndRadioButton(x
, y
, BND_TOOL_WIDTH
, BND_WIDGET_HEIGHT
, BND_CORNER_LEFT
, BND_DEFAULT
, BND_ICONID
!(5, 11), null);
1277 // ////////////////////////////////////////////////////////////////////////// //
1282 NVGContext nvg
= null;
1285 double mx
= 0, my
= 0;
1286 bool doQuit
= false;
1287 int fps
= 30, prevfps
= 0;
1288 auto nextFrameTime
= MonoTime
.currTime
;
1290 setOpenGLContextVersion(3, 0); // it's enough
1292 sdpyWindowClass
= "NANOVEGA_EXAMPLE";
1293 auto sdwindow
= new SimpleWindow(GWidth
, GHeight
, "NanoVega", OpenGlOptions
.yes
, Resizability
.fixedSize
);
1295 void postRepaint (int tout
=0) {
1296 if (sdwindow
!is null && !sdwindow
.eventQueued
!RepaintEvent
) {
1297 if (tout
< 0) tout
= 0;
1298 sdwindow
.postTimeout(evRepaint
, tout
);
1302 void postNextFrame () {
1303 if (sdwindow
is null || sdwindow
.eventQueued
!RepaintEvent
) return;
1306 auto stt
= MonoTime
.currTime
;
1308 nextFrameTime
= stt
+(1000/fps
).msecs
;
1309 } else if (nextFrameTime
<= stt
) {
1310 while (nextFrameTime
<= stt
) nextFrameTime
+= (1000/fps
).msecs
;
1311 //nextFrameTime = stt+(1000/fps).msecs;
1313 tout
= cast(int)((nextFrameTime
-stt
).total
!"msecs");
1316 //conwriteln("prevfps=", prevfps, "; fps=", fps, "; tout=", tout);
1318 sdwindow
.postTimeout(evRepaint
, tout
);
1321 version(X11
) sdwindow
.closeQuery
= delegate () { doQuit
= true; };
1323 sdwindow
.onClosing
= delegate () {
1325 freeDemoData(nvg
, data
);
1326 bndClearIconImage();
1331 auto stt
= MonoTime
.currTime
;
1332 auto prevt
= MonoTime
.currTime
;
1334 sdwindow
.visibleForTheFirstTime
= delegate () {
1335 sdwindow
.vsync
= false;
1337 nvg
= nvgCreateContext(NVGContextFlag
.Default
, NVGContextFlag
.Debug
);
1338 if (nvg
is null) fatal("cannot init NanoVega");
1339 if (!nvg
.loadDemoData(data
)) fatal("cannot load demo data");
1341 fpsStats
= new PerfGraph("Frame Time", PerfGraph
.Style
.FPS
, "sans");
1344 int frc
= 0, totalFrames
= 0;
1346 sdwindow
.redrawOpenGlScene
= delegate () {
1347 if (fps
!= 0) postNextFrame();
1349 // Update and render
1350 glViewport(0, 0, sdwindow
.width
, sdwindow
.height
);
1351 if (premult
) glClearColor(0, 0, 0, 0); else glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
1352 glClear(glNVGClearFlags
);
1355 auto curt
= MonoTime
.currTime
;
1356 double dt = cast(double)((curt
-prevt
).total
!"msecs")/1000.0;
1357 double secs
= cast(double)((curt
-stt
).total
!"msecs")/1000.0;
1360 //{ import core.stdc.stdio; printf("frame time: %d\n", cast(int)(dt*1000)); }
1364 if (fpsStats
!is null) fpsStats
.update(dt);
1365 nvg
.beginFrame(GWidth
, GHeight
);
1366 scope(exit
) nvg
.endFrame();
1367 renderDemo(nvg
, mx
, my
, GWidth
, GHeight
, secs
, blowup
, data
);
1368 if (fpsStats
!is null) fpsStats
.render(nvg
, 5, 5);
1373 import core.stdc.stdio : snprintf;
1375 char[128] buf = void;
1376 auto t = buf[0..snprintf(buf.ptr, buf.length, "NanoVega: %d msecs per frame", cast(int)(secs*1000/totalFrames))].idup;
1383 sdwindow
.addEventListener((RepaintEvent evt
) {
1384 sdwindow
.redrawOpenGlSceneNow();
1387 sdwindow
.eventLoop(0,
1390 if (sdwindow.closed) return;
1391 if (doQuit) { sdwindow.close(); return; }
1392 sdwindow.redrawOpenGlSceneNow();
1396 delegate (KeyEvent event
) {
1397 if (sdwindow
.closed
) return;
1398 scope(exit
) if (event
.pressed
) postNextFrame();
1399 if (event
== "D-*-Q" || event
== "D-Escape") { sdwindow
.close(); return; }
1400 if (event
== "D-Space") { blowup
= !blowup
; return; }
1401 if (event
== "D-P") { premult
= !premult
; return; }
1402 if (event
== "D-T") {
1403 nvg
.tesselation
= cast(NVGTesselation
)(nvg
.tesselation
== NVGTesselation
.max ? NVGTesselation
.min
: nvg
.tesselation
+1);
1404 { import iv
.vfs
.io
; writeln("bezier tesselator: ", nvg
.tesselation
); }
1407 if (event
== "D-C") { cliptest
= !cliptest
; return; }
1409 if (event
== "D-1") newfps
= 10;
1410 if (event
== "D-2") newfps
= 20;
1411 if (event
== "D-3") newfps
= 30;
1412 if (event
== "D-6") newfps
= 60;
1413 if (event
== "D-9") newfps
= 120;
1414 if (event
== "D-0") newfps
= -1;
1415 if (event
== "D-X") newfps
= 0;
1416 if (newfps
== -666) return;
1418 conwriteln("FPS: ", fps
);
1419 totalFrames
= frc
= 0;
1422 delegate (MouseEvent event
) {
1423 scope(exit
) postNextFrame();
1428 int wid
= nvg
.hitTest(mx
, my
, NVGPickKind
.Fill
);
1430 if (event
== "RMB-Down") {
1431 if (wid
== WidgetIdRaw
) { wgOnTop
= true; wgMoving
= true; bndMoving
= false; }
1432 else if (wid
== WidgetIdBlendish
) { wgOnTop
= false; wgMoving
= false; bndMoving
= true; }
1435 if (event
== "RMB-Up") {
1440 if (event
== "LMB-Down") {
1441 if (wid
== WidgetIdRaw
) wgOnTop
= true;
1442 else if (wid
== WidgetIdBlendish
) wgOnTop
= false;
1445 if (event
== "Motion") {
1446 if (bndMoving
) { bndX
+= event
.dx
; bndY
+= event
.dy
; }
1447 if (wgMoving
) { wgX
+= event
.dx
; wgY
+= event
.dy
; }
1450 if (wid
== WidgetIdRaw || wid
== WidgetIdBlendish
) mx
= my
= -666;