1 /*
2  * Nuklear - 1.32.0 - public domain
3  * no warrenty implied; use at your own risk.
4  * authored from 2015-2016 by Micha Mettke
5  */
6 /*
7  * ==============================================================
8  *
9  *                              API
10  *
11  * ===============================================================
12  */
13 #ifndef NK_GDI_H_
14 #define NK_GDI_H_
15 
16 #define WIN32_LEAN_AND_MEAN
17 #include <windows.h>
18 
19 typedef struct GdiFont GdiFont;
20 NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);
21 NK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
22 NK_API void nk_gdi_render(struct nk_color clear);
23 NK_API void nk_gdi_shutdown(void);
24 
25 /* font */
26 NK_API GdiFont* nk_gdifont_create(const char *name, int size);
27 NK_API void nk_gdifont_del(GdiFont *font);
28 NK_API void nk_gdi_set_font(GdiFont *font);
29 
30 #endif
31 
32 /*
33  * ==============================================================
34  *
35  *                          IMPLEMENTATION
36  *
37  * ===============================================================
38  */
39 #ifdef NK_GDI_IMPLEMENTATION
40 
41 #include <stdlib.h>
42 #include <malloc.h>
43 
44 struct GdiFont {
45     struct nk_user_font nk;
46     int height;
47     HFONT handle;
48     HDC dc;
49 };
50 
51 static struct {
52     HBITMAP bitmap;
53     HDC window_dc;
54     HDC memory_dc;
55     unsigned int width;
56     unsigned int height;
57     struct nk_context ctx;
58 } gdi;
59 
60 static void
nk_create_image(struct nk_image * image,const char * frame_buffer,const int width,const int height)61 nk_create_image(struct nk_image * image, const char * frame_buffer, const int width, const int height)
62 {
63     if (image && frame_buffer && (width > 0) && (height > 0))
64     {
65         const unsigned char * src = (const unsigned char *)frame_buffer;
66         INT row = ((width * 3 + 3) & ~3);
67         LPBYTE lpBuf, pb = NULL;
68         BITMAPINFO bi = { 0 };
69         HBITMAP hbm;
70         int v, i;
71 
72         image->w = width;
73         image->h = height;
74         image->region[0] = 0;
75         image->region[1] = 0;
76         image->region[2] = width;
77         image->region[3] = height;
78 
79         bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
80         bi.bmiHeader.biWidth = width;
81         bi.bmiHeader.biHeight = height;
82         bi.bmiHeader.biPlanes = 1;
83         bi.bmiHeader.biBitCount = 24;
84         bi.bmiHeader.biCompression = BI_RGB;
85         bi.bmiHeader.biSizeImage = row * height;
86 
87         hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);
88 
89         pb = lpBuf + row * height;
90         for (v = 0; v < height; v++)
91         {
92             pb -= row;
93             for (i = 0; i < row; i += 3)
94             {
95                 pb[i + 0] = src[0];
96                 pb[i + 1] = src[1];
97                 pb[i + 2] = src[2];
98                 src += 3;
99             }
100         }
101         SetDIBits(NULL, hbm, 0, height, lpBuf, &bi, DIB_RGB_COLORS);
102         image->handle.ptr = hbm;
103     }
104 }
105 
106 static void
nk_delete_image(struct nk_image * image)107 nk_delete_image(struct nk_image * image)
108 {
109     if (image && image->handle.id != 0)
110     {
111         HBITMAP hbm = (HBITMAP)image->handle.ptr;
112         DeleteObject(hbm);
113         memset(image, 0, sizeof(struct nk_image));
114     }
115 }
116 
117 static void
nk_gdi_draw_image(short x,short y,unsigned short w,unsigned short h,struct nk_image img,struct nk_color col)118 nk_gdi_draw_image(short x, short y, unsigned short w, unsigned short h,
119     struct nk_image img, struct nk_color col)
120 {
121     HBITMAP hbm = (HBITMAP)img.handle.ptr;
122     HDC     hDCBits;
123     BITMAP  bitmap;
124 
125     if (!gdi.memory_dc || !hbm)
126         return;
127 
128     hDCBits = CreateCompatibleDC(gdi.memory_dc);
129     GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap);
130     SelectObject(hDCBits, hbm);
131     StretchBlt(gdi.memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
132     DeleteDC(hDCBits);
133 }
134 
135 static COLORREF
convert_color(struct nk_color c)136 convert_color(struct nk_color c)
137 {
138     return c.r | (c.g << 8) | (c.b << 16);
139 }
140 
141 static void
nk_gdi_scissor(HDC dc,float x,float y,float w,float h)142 nk_gdi_scissor(HDC dc, float x, float y, float w, float h)
143 {
144     SelectClipRgn(dc, NULL);
145     IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1));
146 }
147 
148 static void
nk_gdi_stroke_line(HDC dc,short x0,short y0,short x1,short y1,unsigned int line_thickness,struct nk_color col)149 nk_gdi_stroke_line(HDC dc, short x0, short y0, short x1,
150     short y1, unsigned int line_thickness, struct nk_color col)
151 {
152     COLORREF color = convert_color(col);
153 
154     HPEN pen = NULL;
155     if (line_thickness == 1) {
156         SetDCPenColor(dc, color);
157     } else {
158         pen = CreatePen(PS_SOLID, line_thickness, color);
159         SelectObject(dc, pen);
160     }
161 
162     MoveToEx(dc, x0, y0, NULL);
163     LineTo(dc, x1, y1);
164 
165     if (pen) {
166         SelectObject(dc, GetStockObject(DC_PEN));
167         DeleteObject(pen);
168     }
169 }
170 
171 static void
nk_gdi_stroke_rect(HDC dc,short x,short y,unsigned short w,unsigned short h,unsigned short r,unsigned short line_thickness,struct nk_color col)172 nk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w,
173     unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
174 {
175     COLORREF color = convert_color(col);
176     HGDIOBJ br;
177     HPEN pen = NULL;
178 
179     if (line_thickness == 1) {
180         SetDCPenColor(dc, color);
181     } else {
182         pen = CreatePen(PS_SOLID, line_thickness, color);
183         SelectObject(dc, pen);
184     }
185 
186     br = SelectObject(dc, GetStockObject(NULL_BRUSH));
187     if (r == 0) {
188         Rectangle(dc, x, y, x + w, y + h);
189     } else {
190         RoundRect(dc, x, y, x + w, y + h, r, r);
191     }
192     SelectObject(dc, br);
193 
194     if (pen) {
195         SelectObject(dc, GetStockObject(DC_PEN));
196         DeleteObject(pen);
197     }
198 }
199 
200 static void
nk_gdi_fill_rect(HDC dc,short x,short y,unsigned short w,unsigned short h,unsigned short r,struct nk_color col)201 nk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w,
202     unsigned short h, unsigned short r, struct nk_color col)
203 {
204     COLORREF color = convert_color(col);
205 
206     if (r == 0) {
207         RECT rect;
208         SetRect(&rect, x, y, x + w, y + h);
209         SetBkColor(dc, color);
210         ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
211     } else {
212         SetDCPenColor(dc, color);
213         SetDCBrushColor(dc, color);
214         RoundRect(dc, x, y, x + w, y + h, r, r);
215     }
216 }
217 static void
nk_gdi_set_vertexColor(PTRIVERTEX tri,struct nk_color col)218 nk_gdi_set_vertexColor(PTRIVERTEX tri, struct nk_color col)
219 {
220     tri->Red   = col.r << 8;
221     tri->Green = col.g << 8;
222     tri->Blue  = col.b << 8;
223     tri->Alpha = 0xff << 8;
224 }
225 
226 static void
nk_gdi_rect_multi_color(HDC dc,short x,short y,unsigned short w,unsigned short h,struct nk_color left,struct nk_color top,struct nk_color right,struct nk_color bottom)227 nk_gdi_rect_multi_color(HDC dc, short x, short y, unsigned short w,
228     unsigned short h, struct nk_color left, struct nk_color top,
229     struct nk_color right, struct nk_color bottom)
230 {
231     BLENDFUNCTION alphaFunction;
232     GRADIENT_RECT gRect;
233     GRADIENT_TRIANGLE gTri[2];
234     TRIVERTEX vt[4];
235     alphaFunction.BlendOp = AC_SRC_OVER;
236     alphaFunction.BlendFlags = 0;
237     alphaFunction.SourceConstantAlpha = 0;
238     alphaFunction.AlphaFormat = AC_SRC_ALPHA;
239 
240     /* TODO: This Case Needs Repair.*/
241     /* Top Left Corner */
242     vt[0].x     = x;
243     vt[0].y     = y;
244     nk_gdi_set_vertexColor(&vt[0], left);
245     /* Top Right Corner */
246     vt[1].x     = x+w;
247     vt[1].y     = y;
248     nk_gdi_set_vertexColor(&vt[1], top);
249     /* Bottom Left Corner */
250     vt[2].x     = x;
251     vt[2].y     = y+h;
252     nk_gdi_set_vertexColor(&vt[2], right);
253 
254     /* Bottom Right Corner */
255     vt[3].x     = x+w;
256     vt[3].y     = y+h;
257     nk_gdi_set_vertexColor(&vt[3], bottom);
258 
259     gTri[0].Vertex1 = 0;
260     gTri[0].Vertex2 = 1;
261     gTri[0].Vertex3 = 2;
262     gTri[1].Vertex1 = 2;
263     gTri[1].Vertex2 = 1;
264     gTri[1].Vertex3 = 3;
265     GdiGradientFill(dc, vt, 4, gTri, 2 , GRADIENT_FILL_TRIANGLE);
266     AlphaBlend(gdi.window_dc,  x, y, x+w, y+h,gdi.memory_dc, x, y, x+w, y+h,alphaFunction);
267 
268 }
269 
270 static BOOL
SetPoint(POINT * p,LONG x,LONG y)271 SetPoint(POINT *p, LONG x, LONG y)
272 {
273     if (!p)
274         return FALSE;
275     p->x = x;
276     p->y = y;
277     return TRUE;
278 }
279 
280 static void
nk_gdi_fill_triangle(HDC dc,short x0,short y0,short x1,short y1,short x2,short y2,struct nk_color col)281 nk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1,
282     short y1, short x2, short y2, struct nk_color col)
283 {
284     COLORREF color = convert_color(col);
285     POINT points[3];
286 
287     SetPoint(&points[0], x0, y0);
288     SetPoint(&points[1], x1, y1);
289     SetPoint(&points[2], x2, y2);
290 
291     SetDCPenColor(dc, color);
292     SetDCBrushColor(dc, color);
293     Polygon(dc, points, 3);
294 }
295 
296 static void
nk_gdi_stroke_triangle(HDC dc,short x0,short y0,short x1,short y1,short x2,short y2,unsigned short line_thickness,struct nk_color col)297 nk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1,
298     short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
299 {
300     COLORREF color = convert_color(col);
301     POINT points[4];
302     HPEN pen = NULL;
303 
304     SetPoint(&points[0], x0, y0);
305     SetPoint(&points[1], x1, y1);
306     SetPoint(&points[2], x2, y2);
307     SetPoint(&points[3], x0, y0);
308 
309     if (line_thickness == 1) {
310         SetDCPenColor(dc, color);
311     } else {
312         pen = CreatePen(PS_SOLID, line_thickness, color);
313         SelectObject(dc, pen);
314     }
315 
316     Polyline(dc, points, 4);
317 
318     if (pen) {
319         SelectObject(dc, GetStockObject(DC_PEN));
320         DeleteObject(pen);
321     }
322 }
323 
324 static void
nk_gdi_fill_polygon(HDC dc,const struct nk_vec2i * pnts,int count,struct nk_color col)325 nk_gdi_fill_polygon(HDC dc, const struct nk_vec2i *pnts, int count, struct nk_color col)
326 {
327     int i = 0;
328     #define MAX_POINTS 64
329     POINT points[MAX_POINTS];
330     COLORREF color = convert_color(col);
331     SetDCBrushColor(dc, color);
332     SetDCPenColor(dc, color);
333     for (i = 0; i < count && i < MAX_POINTS; ++i) {
334         points[i].x = pnts[i].x;
335         points[i].y = pnts[i].y;
336     }
337     Polygon(dc, points, i);
338     #undef MAX_POINTS
339 }
340 
341 static void
nk_gdi_stroke_polygon(HDC dc,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color col)342 nk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i *pnts, int count,
343     unsigned short line_thickness, struct nk_color col)
344 {
345     COLORREF color = convert_color(col);
346     HPEN pen = NULL;
347     if (line_thickness == 1) {
348         SetDCPenColor(dc, color);
349     } else {
350         pen = CreatePen(PS_SOLID, line_thickness, color);
351         SelectObject(dc, pen);
352     }
353 
354     if (count > 0) {
355         int i;
356         MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
357         for (i = 1; i < count; ++i)
358             LineTo(dc, pnts[i].x, pnts[i].y);
359         LineTo(dc, pnts[0].x, pnts[0].y);
360     }
361 
362     if (pen) {
363         SelectObject(dc, GetStockObject(DC_PEN));
364         DeleteObject(pen);
365     }
366 }
367 
368 static void
nk_gdi_stroke_polyline(HDC dc,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color col)369 nk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i *pnts,
370     int count, unsigned short line_thickness, struct nk_color col)
371 {
372     COLORREF color = convert_color(col);
373     HPEN pen = NULL;
374     if (line_thickness == 1) {
375         SetDCPenColor(dc, color);
376     } else {
377         pen = CreatePen(PS_SOLID, line_thickness, color);
378         SelectObject(dc, pen);
379     }
380 
381     if (count > 0) {
382         int i;
383         MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
384         for (i = 1; i < count; ++i)
385             LineTo(dc, pnts[i].x, pnts[i].y);
386     }
387 
388     if (pen) {
389         SelectObject(dc, GetStockObject(DC_PEN));
390         DeleteObject(pen);
391     }
392 }
393 
394 static void
nk_gdi_fill_circle(HDC dc,short x,short y,unsigned short w,unsigned short h,struct nk_color col)395 nk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w,
396     unsigned short h, struct nk_color col)
397 {
398     COLORREF color = convert_color(col);
399     SetDCBrushColor(dc, color);
400     SetDCPenColor(dc, color);
401     Ellipse(dc, x, y, x + w, y + h);
402 }
403 
404 static void
nk_gdi_stroke_circle(HDC dc,short x,short y,unsigned short w,unsigned short h,unsigned short line_thickness,struct nk_color col)405 nk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w,
406     unsigned short h, unsigned short line_thickness, struct nk_color col)
407 {
408     COLORREF color = convert_color(col);
409     HPEN pen = NULL;
410     if (line_thickness == 1) {
411         SetDCPenColor(dc, color);
412     } else {
413         pen = CreatePen(PS_SOLID, line_thickness, color);
414         SelectObject(dc, pen);
415     }
416 
417     SetDCBrushColor(dc, OPAQUE);
418     Ellipse(dc, x, y, x + w, y + h);
419 
420     if (pen) {
421         SelectObject(dc, GetStockObject(DC_PEN));
422         DeleteObject(pen);
423     }
424 }
425 
426 static void
nk_gdi_stroke_curve(HDC dc,struct nk_vec2i p1,struct nk_vec2i p2,struct nk_vec2i p3,struct nk_vec2i p4,unsigned short line_thickness,struct nk_color col)427 nk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1,
428     struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
429     unsigned short line_thickness, struct nk_color col)
430 {
431     COLORREF color = convert_color(col);
432     POINT p[4];
433     HPEN pen = NULL;
434 
435     SetPoint(&p[0], p1.x, p1.y);
436     SetPoint(&p[1], p2.x, p2.y);
437     SetPoint(&p[2], p3.x, p3.y);
438     SetPoint(&p[3], p4.x, p4.y);
439 
440     if (line_thickness == 1) {
441         SetDCPenColor(dc, color);
442     } else {
443         pen = CreatePen(PS_SOLID, line_thickness, color);
444         SelectObject(dc, pen);
445     }
446 
447     SetDCBrushColor(dc, OPAQUE);
448     PolyBezier(dc, p, 4);
449 
450     if (pen) {
451         SelectObject(dc, GetStockObject(DC_PEN));
452         DeleteObject(pen);
453     }
454 }
455 
456 static void
nk_gdi_draw_text(HDC dc,short x,short y,unsigned short w,unsigned short h,const char * text,int len,GdiFont * font,struct nk_color cbg,struct nk_color cfg)457 nk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h,
458     const char *text, int len, GdiFont *font, struct nk_color cbg, struct nk_color cfg)
459 {
460     int wsize;
461     WCHAR* wstr;
462 
463     if(!text || !font || !len) return;
464 
465     wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
466     wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
467     MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
468 
469     SetBkColor(dc, convert_color(cbg));
470     SetTextColor(dc, convert_color(cfg));
471 
472     SelectObject(dc, font->handle);
473     ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL);
474 }
475 
476 static void
nk_gdi_clear(HDC dc,struct nk_color col)477 nk_gdi_clear(HDC dc, struct nk_color col)
478 {
479     COLORREF color = convert_color(col);
480     RECT rect;
481     SetRect(&rect, 0, 0, gdi.width, gdi.height);
482     SetBkColor(dc, color);
483 
484     ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
485 }
486 
487 static void
nk_gdi_blit(HDC dc)488 nk_gdi_blit(HDC dc)
489 {
490     BitBlt(dc, 0, 0, gdi.width, gdi.height, gdi.memory_dc, 0, 0, SRCCOPY);
491 
492 }
493 
494 GdiFont*
nk_gdifont_create(const char * name,int size)495 nk_gdifont_create(const char *name, int size)
496 {
497     TEXTMETRICW metric;
498     GdiFont *font = (GdiFont*)calloc(1, sizeof(GdiFont));
499     if (!font)
500         return NULL;
501     font->dc = CreateCompatibleDC(0);
502     font->handle = CreateFontA(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);
503     SelectObject(font->dc, font->handle);
504     GetTextMetricsW(font->dc, &metric);
505     font->height = metric.tmHeight;
506     return font;
507 }
508 
509 static float
nk_gdifont_get_text_width(nk_handle handle,float height,const char * text,int len)510 nk_gdifont_get_text_width(nk_handle handle, float height, const char *text, int len)
511 {
512     GdiFont *font = (GdiFont*)handle.ptr;
513     SIZE size;
514     int wsize;
515     WCHAR* wstr;
516     if (!font || !text)
517         return 0;
518 
519     wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
520     wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
521     MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
522     if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size))
523         return (float)size.cx;
524     return -1.0f;
525 }
526 
527 void
nk_gdifont_del(GdiFont * font)528 nk_gdifont_del(GdiFont *font)
529 {
530     if(!font) return;
531     DeleteObject(font->handle);
532     DeleteDC(font->dc);
533     free(font);
534 }
535 
536 static void
nk_gdi_clipboard_paste(nk_handle usr,struct nk_text_edit * edit)537 nk_gdi_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
538 {
539     (void)usr;
540     if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
541     {
542         HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
543         if (mem)
544         {
545             SIZE_T size = GlobalSize(mem) - 1;
546             if (size)
547             {
548                 LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
549                 if (wstr)
550                 {
551                     int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
552                     if (utf8size)
553                     {
554                         char* utf8 = (char*)malloc(utf8size);
555                         if (utf8)
556                         {
557                             WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);
558                             nk_textedit_paste(edit, utf8, utf8size);
559                             free(utf8);
560                         }
561                     }
562                     GlobalUnlock(mem);
563                 }
564             }
565         }
566         CloseClipboard();
567     }
568 }
569 
570 static void
nk_gdi_clipboard_copy(nk_handle usr,const char * text,int len)571 nk_gdi_clipboard_copy(nk_handle usr, const char *text, int len)
572 {
573     if (OpenClipboard(NULL))
574     {
575         int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
576         if (wsize)
577         {
578             HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
579             if (mem)
580             {
581                 wchar_t* wstr = (wchar_t*)GlobalLock(mem);
582                 if (wstr)
583                 {
584                     MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
585                     wstr[wsize] = 0;
586                     GlobalUnlock(mem);
587 
588                     SetClipboardData(CF_UNICODETEXT, mem);
589                 }
590             }
591         }
592         CloseClipboard();
593     }
594 }
595 
596 NK_API struct nk_context*
nk_gdi_init(GdiFont * gdifont,HDC window_dc,unsigned int width,unsigned int height)597 nk_gdi_init(GdiFont *gdifont, HDC window_dc, unsigned int width, unsigned int height)
598 {
599     struct nk_user_font *font = &gdifont->nk;
600     font->userdata = nk_handle_ptr(gdifont);
601     font->height = (float)gdifont->height;
602     font->width = nk_gdifont_get_text_width;
603 
604     gdi.bitmap = CreateCompatibleBitmap(window_dc, width, height);
605     gdi.window_dc = window_dc;
606     gdi.memory_dc = CreateCompatibleDC(window_dc);
607     gdi.width = width;
608     gdi.height = height;
609     SelectObject(gdi.memory_dc, gdi.bitmap);
610 
611     nk_init_default(&gdi.ctx, font);
612     gdi.ctx.clip.copy = nk_gdi_clipboard_copy;
613     gdi.ctx.clip.paste = nk_gdi_clipboard_paste;
614     return &gdi.ctx;
615 }
616 
617 NK_API void
nk_gdi_set_font(GdiFont * gdifont)618 nk_gdi_set_font(GdiFont *gdifont)
619 {
620     struct nk_user_font *font = &gdifont->nk;
621     font->userdata = nk_handle_ptr(gdifont);
622     font->height = (float)gdifont->height;
623     font->width = nk_gdifont_get_text_width;
624     nk_style_set_font(&gdi.ctx, font);
625 }
626 
627 NK_API int
nk_gdi_handle_event(HWND wnd,UINT msg,WPARAM wparam,LPARAM lparam)628 nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
629 {
630     switch (msg)
631     {
632     case WM_SIZE:
633     {
634         unsigned width = LOWORD(lparam);
635         unsigned height = HIWORD(lparam);
636         if (width != gdi.width || height != gdi.height)
637         {
638             DeleteObject(gdi.bitmap);
639             gdi.bitmap = CreateCompatibleBitmap(gdi.window_dc, width, height);
640             gdi.width = width;
641             gdi.height = height;
642             SelectObject(gdi.memory_dc, gdi.bitmap);
643         }
644         break;
645     }
646 
647     case WM_PAINT:
648     {
649         PAINTSTRUCT paint;
650         HDC dc = BeginPaint(wnd, &paint);
651         nk_gdi_blit(dc);
652         EndPaint(wnd, &paint);
653         return 1;
654     }
655 
656     case WM_KEYDOWN:
657     case WM_KEYUP:
658     case WM_SYSKEYDOWN:
659     case WM_SYSKEYUP:
660     {
661         int down = !((lparam >> 31) & 1);
662         int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
663 
664         switch (wparam)
665         {
666         case VK_SHIFT:
667         case VK_LSHIFT:
668         case VK_RSHIFT:
669             nk_input_key(&gdi.ctx, NK_KEY_SHIFT, down);
670             return 1;
671 
672         case VK_DELETE:
673             nk_input_key(&gdi.ctx, NK_KEY_DEL, down);
674             return 1;
675 
676         case VK_RETURN:
677             nk_input_key(&gdi.ctx, NK_KEY_ENTER, down);
678             return 1;
679 
680         case VK_TAB:
681             nk_input_key(&gdi.ctx, NK_KEY_TAB, down);
682             return 1;
683 
684         case VK_LEFT:
685             if (ctrl)
686                 nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_LEFT, down);
687             else
688                 nk_input_key(&gdi.ctx, NK_KEY_LEFT, down);
689             return 1;
690 
691         case VK_RIGHT:
692             if (ctrl)
693                 nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
694             else
695                 nk_input_key(&gdi.ctx, NK_KEY_RIGHT, down);
696             return 1;
697 
698         case VK_BACK:
699             nk_input_key(&gdi.ctx, NK_KEY_BACKSPACE, down);
700             return 1;
701 
702         case VK_HOME:
703             nk_input_key(&gdi.ctx, NK_KEY_TEXT_START, down);
704             nk_input_key(&gdi.ctx, NK_KEY_SCROLL_START, down);
705             return 1;
706 
707         case VK_END:
708             nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, down);
709             nk_input_key(&gdi.ctx, NK_KEY_SCROLL_END, down);
710             return 1;
711 
712         case VK_NEXT:
713             nk_input_key(&gdi.ctx, NK_KEY_SCROLL_DOWN, down);
714             return 1;
715 
716         case VK_PRIOR:
717             nk_input_key(&gdi.ctx, NK_KEY_SCROLL_UP, down);
718             return 1;
719 
720         case 'C':
721             if (ctrl) {
722                 nk_input_key(&gdi.ctx, NK_KEY_COPY, down);
723                 return 1;
724             }
725             break;
726 
727         case 'V':
728             if (ctrl) {
729                 nk_input_key(&gdi.ctx, NK_KEY_PASTE, down);
730                 return 1;
731             }
732             break;
733 
734         case 'X':
735             if (ctrl) {
736                 nk_input_key(&gdi.ctx, NK_KEY_CUT, down);
737                 return 1;
738             }
739             break;
740 
741         case 'Z':
742             if (ctrl) {
743                 nk_input_key(&gdi.ctx, NK_KEY_TEXT_UNDO, down);
744                 return 1;
745             }
746             break;
747 
748         case 'R':
749             if (ctrl) {
750                 nk_input_key(&gdi.ctx, NK_KEY_TEXT_REDO, down);
751                 return 1;
752             }
753             break;
754         }
755         return 0;
756     }
757 
758     case WM_CHAR:
759         if (wparam >= 32)
760         {
761             nk_input_unicode(&gdi.ctx, (nk_rune)wparam);
762             return 1;
763         }
764         break;
765 
766     case WM_LBUTTONDOWN:
767         nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
768         SetCapture(wnd);
769         return 1;
770 
771     case WM_LBUTTONUP:
772         nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
773         nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
774         ReleaseCapture();
775         return 1;
776 
777     case WM_RBUTTONDOWN:
778         nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
779         SetCapture(wnd);
780         return 1;
781 
782     case WM_RBUTTONUP:
783         nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
784         ReleaseCapture();
785         return 1;
786 
787     case WM_MBUTTONDOWN:
788         nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
789         SetCapture(wnd);
790         return 1;
791 
792     case WM_MBUTTONUP:
793         nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
794         ReleaseCapture();
795         return 1;
796 
797     case WM_MOUSEWHEEL:
798         nk_input_scroll(&gdi.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
799         return 1;
800 
801     case WM_MOUSEMOVE:
802         nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
803         return 1;
804 
805     case WM_LBUTTONDBLCLK:
806         nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
807         return 1;
808     }
809 
810     return 0;
811 }
812 
813 NK_API void
nk_gdi_shutdown(void)814 nk_gdi_shutdown(void)
815 {
816     DeleteObject(gdi.memory_dc);
817     DeleteObject(gdi.bitmap);
818     nk_free(&gdi.ctx);
819 }
820 
821 NK_API void
nk_gdi_render(struct nk_color clear)822 nk_gdi_render(struct nk_color clear)
823 {
824     const struct nk_command *cmd;
825 
826     HDC memory_dc = gdi.memory_dc;
827     SelectObject(memory_dc, GetStockObject(DC_PEN));
828     SelectObject(memory_dc, GetStockObject(DC_BRUSH));
829     nk_gdi_clear(memory_dc, clear);
830 
831     nk_foreach(cmd, &gdi.ctx)
832     {
833         switch (cmd->type) {
834         case NK_COMMAND_NOP: break;
835         case NK_COMMAND_SCISSOR: {
836             const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
837             nk_gdi_scissor(memory_dc, s->x, s->y, s->w, s->h);
838         } break;
839         case NK_COMMAND_LINE: {
840             const struct nk_command_line *l = (const struct nk_command_line *)cmd;
841             nk_gdi_stroke_line(memory_dc, l->begin.x, l->begin.y, l->end.x,
842                 l->end.y, l->line_thickness, l->color);
843         } break;
844         case NK_COMMAND_RECT: {
845             const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
846             nk_gdi_stroke_rect(memory_dc, r->x, r->y, r->w, r->h,
847                 (unsigned short)r->rounding, r->line_thickness, r->color);
848         } break;
849         case NK_COMMAND_RECT_FILLED: {
850             const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
851             nk_gdi_fill_rect(memory_dc, r->x, r->y, r->w, r->h,
852                 (unsigned short)r->rounding, r->color);
853         } break;
854         case NK_COMMAND_CIRCLE: {
855             const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
856             nk_gdi_stroke_circle(memory_dc, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
857         } break;
858         case NK_COMMAND_CIRCLE_FILLED: {
859             const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
860             nk_gdi_fill_circle(memory_dc, c->x, c->y, c->w, c->h, c->color);
861         } break;
862         case NK_COMMAND_TRIANGLE: {
863             const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
864             nk_gdi_stroke_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,
865                 t->c.x, t->c.y, t->line_thickness, t->color);
866         } break;
867         case NK_COMMAND_TRIANGLE_FILLED: {
868             const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
869             nk_gdi_fill_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,
870                 t->c.x, t->c.y, t->color);
871         } break;
872         case NK_COMMAND_POLYGON: {
873             const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
874             nk_gdi_stroke_polygon(memory_dc, p->points, p->point_count, p->line_thickness,p->color);
875         } break;
876         case NK_COMMAND_POLYGON_FILLED: {
877             const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
878             nk_gdi_fill_polygon(memory_dc, p->points, p->point_count, p->color);
879         } break;
880         case NK_COMMAND_POLYLINE: {
881             const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
882             nk_gdi_stroke_polyline(memory_dc, p->points, p->point_count, p->line_thickness, p->color);
883         } break;
884         case NK_COMMAND_TEXT: {
885             const struct nk_command_text *t = (const struct nk_command_text*)cmd;
886             nk_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h,
887                 (const char*)t->string, t->length,
888                 (GdiFont*)t->font->userdata.ptr,
889                 t->background, t->foreground);
890         } break;
891         case NK_COMMAND_CURVE: {
892             const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
893             nk_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1],
894                 q->end, q->line_thickness, q->color);
895         } break;
896         case NK_COMMAND_RECT_MULTI_COLOR: {
897             const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color *)cmd;
898             nk_gdi_rect_multi_color(memory_dc, r->x, r->y,r->w, r->h, r->left, r->top, r->right, r->bottom);
899         } break;
900         case NK_COMMAND_IMAGE: {
901             const struct nk_command_image *i = (const struct nk_command_image *)cmd;
902             nk_gdi_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);
903         } break;
904         case NK_COMMAND_ARC:
905         case NK_COMMAND_ARC_FILLED:
906         default: break;
907         }
908     }
909     nk_gdi_blit(gdi.window_dc);
910     nk_clear(&gdi.ctx);
911 }
912 
913 #endif
914 
915