nuklear_gdi.h 26 KB

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