nuklear_gdi.h 28 KB

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