/* * Nuklear - 1.40.8 - public domain * no warrenty implied; use at your own risk. * authored from 2015-2017 by Micha Mettke */ /* * ============================================================== * * API * * =============================================================== */ #ifndef NK_GDIP_H_ #define NK_GDIP_H_ #define WIN32_LEAN_AND_MEAN #include #include /* font */ typedef struct GdipFont GdipFont; NK_API GdipFont* nk_gdipfont_create(const char *name, int size); NK_API GdipFont* nk_gdipfont_create_from_file(const WCHAR* filename, int size); NK_API GdipFont* nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size); NK_API void nk_gdipfont_del(GdipFont *font); NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height); NK_API void nk_gdip_set_font(GdipFont *font); NK_API int nk_gdip_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear); NK_API void nk_gdip_shutdown(void); /* image */ NK_API struct nk_image nk_gdip_load_image_from_file(const WCHAR* filename); NK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, nk_uint membufSize); NK_API void nk_gdip_image_free(struct nk_image image); #endif /* * ============================================================== * * IMPLEMENTATION * * =============================================================== */ #ifdef NK_GDIP_IMPLEMENTATION #include #include #define _USE_MATH_DEFINES #include /* manually declare everything GDI+ needs, because GDI+ headers are not usable from C */ #define WINGDIPAPI __stdcall #define GDIPCONST const typedef struct GpGraphics GpGraphics; typedef struct GpImage GpImage; typedef struct GpPen GpPen; typedef struct GpBrush GpBrush; typedef struct GpStringFormat GpStringFormat; typedef struct GpFont GpFont; typedef struct GpFontFamily GpFontFamily; typedef struct GpFontCollection GpFontCollection; typedef GpImage GpBitmap; typedef GpBrush GpSolidFill; typedef int Status; typedef Status GpStatus; typedef float REAL; typedef DWORD ARGB; typedef POINT GpPoint; typedef enum { TextRenderingHintSystemDefault = 0, TextRenderingHintSingleBitPerPixelGridFit = 1, TextRenderingHintSingleBitPerPixel = 2, TextRenderingHintAntiAliasGridFit = 3, TextRenderingHintAntiAlias = 4, TextRenderingHintClearTypeGridFit = 5 } TextRenderingHint; typedef enum { StringFormatFlagsDirectionRightToLeft = 0x00000001, StringFormatFlagsDirectionVertical = 0x00000002, StringFormatFlagsNoFitBlackBox = 0x00000004, StringFormatFlagsDisplayFormatControl = 0x00000020, StringFormatFlagsNoFontFallback = 0x00000400, StringFormatFlagsMeasureTrailingSpaces = 0x00000800, StringFormatFlagsNoWrap = 0x00001000, StringFormatFlagsLineLimit = 0x00002000, StringFormatFlagsNoClip = 0x00004000 } StringFormatFlags; typedef enum { QualityModeInvalid = -1, QualityModeDefault = 0, QualityModeLow = 1, QualityModeHigh = 2 } QualityMode; typedef enum { SmoothingModeInvalid = QualityModeInvalid, SmoothingModeDefault = QualityModeDefault, SmoothingModeHighSpeed = QualityModeLow, SmoothingModeHighQuality = QualityModeHigh, SmoothingModeNone, SmoothingModeAntiAlias, SmoothingModeAntiAlias8x4 = SmoothingModeAntiAlias, SmoothingModeAntiAlias8x8 } SmoothingMode; typedef enum { FontStyleRegular = 0, FontStyleBold = 1, FontStyleItalic = 2, FontStyleBoldItalic = 3, FontStyleUnderline = 4, FontStyleStrikeout = 8 } FontStyle; typedef enum { FillModeAlternate, FillModeWinding } FillMode; typedef enum { CombineModeReplace, CombineModeIntersect, CombineModeUnion, CombineModeXor, CombineModeExclude, CombineModeComplement } CombineMode; typedef enum { UnitWorld, UnitDisplay, UnitPixel, UnitPoint, UnitInch, UnitDocument, UnitMillimeter } Unit; typedef struct { FLOAT X; FLOAT Y; FLOAT Width; FLOAT Height; } RectF; typedef enum { DebugEventLevelFatal, DebugEventLevelWarning } DebugEventLevel; typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message); typedef struct { UINT32 GdiplusVersion; DebugEventProc DebugEventCallback; BOOL SuppressBackgroundThread; BOOL SuppressExternalCodecs; } GdiplusStartupInput; typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token); typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token); typedef struct { NotificationHookProc NotificationHook; NotificationUnhookProc NotificationUnhook; } GdiplusStartupOutput; /* startup & shutdown */ Status WINAPI GdiplusStartup( OUT ULONG_PTR *token, const GdiplusStartupInput *input, OUT GdiplusStartupOutput *output); VOID WINAPI GdiplusShutdown(ULONG_PTR token); /* image */ GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height, GpGraphics* target, GpBitmap** bitmap); GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image); GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics); GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width); GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height); GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename, GpImage **image); GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image); /* pen */ GpStatus WINGDIPAPI GdipCreatePen1(ARGB color, REAL width, Unit unit, GpPen **pen); GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen); GpStatus WINGDIPAPI GdipSetPenWidth(GpPen *pen, REAL width); GpStatus WINGDIPAPI GdipSetPenColor(GpPen *pen, ARGB argb); /* brush */ GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **brush); GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush); GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *brush, ARGB color); /* font */ GpStatus WINGDIPAPI GdipCreateFont( GDIPCONST GpFontFamily *fontFamily, REAL emSize, INT style, Unit unit, GpFont **font ); GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font); GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size); GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, GpFontCollection *fontCollection, GpFontFamily **fontFamily); GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *fontFamily); GpStatus WINGDIPAPI GdipStringFormatGetGenericTypographic(GpStringFormat **format); GpStatus WINGDIPAPI GdipSetStringFormatFlags(GpStringFormat *format, INT flags); GpStatus WINGDIPAPI GdipDeleteStringFormat(GpStringFormat *format); GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, GDIPCONST void* memory, INT length); GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection, GDIPCONST WCHAR* filename); GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection** fontCollection); GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection** fontCollection); GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList(GpFontCollection* fontCollection, INT numSought, GpFontFamily* gpfamilies[], INT* numFound); GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount(GpFontCollection* fontCollection, INT* numFound); /* graphics */ GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics); GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics); GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics); GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode); GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, CombineMode combineMode); GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2); GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle); GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle); GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle); GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height); GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height); GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count, FillMode fillMode); GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count); GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height); GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height); GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4); GpStatus WINGDIPAPI GdipDrawString( GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, GDIPCONST GpBrush *brush ); GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color); GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, INT y); GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, INT x, INT y, INT width, INT height); GpStatus WINGDIPAPI GdipMeasureString( GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, RectF *boundingBox, INT *codepointsFitted, INT *linesFilled ); GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics, TextRenderingHint mode); LWSTDAPI_(IStream *) SHCreateMemStream(const BYTE *pInit, _In_ UINT cbInit); struct GdipFont { struct nk_user_font nk; GpFont* handle; }; static struct { ULONG_PTR token; GpGraphics *window; GpGraphics *memory; GpImage *bitmap; GpPen *pen; GpSolidFill *brush; GpStringFormat *format; GpFontCollection *fontCollection[10]; INT curFontCollection; struct nk_context ctx; } gdip; static ARGB convert_color(struct nk_color c) { return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b; } static void nk_gdip_scissor(float x, float y, float w, float h) { GdipSetClipRectI(gdip.memory, (INT)x, (INT)y, (INT)(w + 1), (INT)(h + 1), CombineModeReplace); } static void nk_gdip_stroke_line(short x0, short y0, short x1, short y1, unsigned int line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); GdipDrawLineI(gdip.memory, gdip.pen, x0, y0, x1, y1); } static void nk_gdip_stroke_rect(short x, short y, unsigned short w, unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); if (r == 0) { GdipDrawRectangleI(gdip.memory, gdip.pen, x, y, w, h); } else { INT d = 2 * r; GdipDrawArcI(gdip.memory, gdip.pen, x, y, d, d, 180, 90); GdipDrawLineI(gdip.memory, gdip.pen, x + r, y, x + w - r, y); GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90); GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + r, x + w, y + h - r); GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90); GdipDrawLineI(gdip.memory, gdip.pen, x, y + r, x, y + h - r); GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90); GdipDrawLineI(gdip.memory, gdip.pen, x + r, y + h, x + w - r, y + h); } } static void nk_gdip_fill_rect(short x, short y, unsigned short w, unsigned short h, unsigned short r, struct nk_color col) { GdipSetSolidFillColor(gdip.brush, convert_color(col)); if (r == 0) { GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h); } else { INT d = 2 * r; GdipFillRectangleI(gdip.memory, gdip.brush, x + r, y, w - d, h); GdipFillRectangleI(gdip.memory, gdip.brush, x, y + r, r, h - d); GdipFillRectangleI(gdip.memory, gdip.brush, x + w - r, y + r, r, h - d); GdipFillPieI(gdip.memory, gdip.brush, x, y, d, d, 180, 90); GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y, d, d, 270, 90); GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y + h - d, d, d, 0, 90); GdipFillPieI(gdip.memory, gdip.brush, x, y + h - d, d, d, 90, 90); } } static BOOL SetPoint(POINT *p, LONG x, LONG y) { if (!p) return FALSE; p->x = x; p->y = y; return TRUE; } static void nk_gdip_fill_triangle(short x0, short y0, short x1, short y1, short x2, short y2, struct nk_color col) { POINT points[3]; SetPoint(&points[0], x0, y0); SetPoint(&points[1], x1, y1); SetPoint(&points[2], x2, y2); GdipSetSolidFillColor(gdip.brush, convert_color(col)); GdipFillPolygonI(gdip.memory, gdip.brush, points, 3, FillModeAlternate); } static void nk_gdip_stroke_triangle(short x0, short y0, short x1, short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col) { POINT points[4]; SetPoint(&points[0], x0, y0); SetPoint(&points[1], x1, y1); SetPoint(&points[2], x2, y2); SetPoint(&points[3], x0, y0); GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); GdipDrawPolygonI(gdip.memory, gdip.pen, points, 4); } static void nk_gdip_fill_polygon(const struct nk_vec2i *pnts, int count, struct nk_color col) { int i = 0; #define MAX_POINTS 64 POINT points[MAX_POINTS]; GdipSetSolidFillColor(gdip.brush, convert_color(col)); for (i = 0; i < count && i < MAX_POINTS; ++i) { points[i].x = pnts[i].x; points[i].y = pnts[i].y; } GdipFillPolygonI(gdip.memory, gdip.brush, points, i, FillModeAlternate); #undef MAX_POINTS } static void nk_gdip_stroke_polygon(const struct nk_vec2i *pnts, int count, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); if (count > 0) { int i; for (i = 1; i < count; ++i) GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); GdipDrawLineI(gdip.memory, gdip.pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y); } } static void nk_gdip_stroke_polyline(const struct nk_vec2i *pnts, int count, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); if (count > 0) { int i; for (i = 1; i < count; ++i) GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); } } static void nk_gdip_fill_circle(short x, short y, unsigned short w, unsigned short h, struct nk_color col) { GdipSetSolidFillColor(gdip.brush, convert_color(col)); GdipFillEllipseI(gdip.memory, gdip.brush, x, y, w, h); } static void nk_gdip_stroke_circle(short x, short y, unsigned short w, unsigned short h, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); GdipDrawEllipseI(gdip.memory, gdip.pen, x, y, w, h); } static void nk_gdip_stroke_curve(struct nk_vec2i p1, struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); GdipDrawBezierI(gdip.memory, gdip.pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); } static void nk_gdip_fill_arc(short cx, short cy, unsigned short r, float amin, float adelta, struct nk_color col) { GdipSetSolidFillColor(gdip.brush, convert_color(col)); GdipFillPieI(gdip.memory, gdip.brush, cx - r, cy - r, r * 2, r * 2, amin * (180/M_PI), adelta * (180/M_PI)); } static void nk_gdip_stroke_arc(short cx, short cy, unsigned short r, float amin, float adelta, unsigned short line_thickness, struct nk_color col) { GdipSetPenWidth(gdip.pen, (REAL)line_thickness); GdipSetPenColor(gdip.pen, convert_color(col)); GdipDrawPieI(gdip.memory, gdip.pen, cx - r, cy - r, r * 2, r * 2, amin * (180/M_PI), adelta * (180/M_PI)); } static void nk_gdip_draw_text(short x, short y, unsigned short w, unsigned short h, const char *text, int len, GdipFont *font, struct nk_color cbg, struct nk_color cfg) { int wsize; WCHAR* wstr; RectF layout; layout.X = x; layout.Y = y; layout.Width = w; layout.Height = h; if(!text || !font || !len) return; wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); GdipSetSolidFillColor(gdip.brush, convert_color(cfg)); GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush); } static void nk_gdip_draw_image(short x, short y, unsigned short w, unsigned short h, struct nk_image img, struct nk_color col) { GpImage *image = img.handle.ptr; GdipDrawImageRectI(gdip.memory, image, x, y, w, h); } static void nk_gdip_clear(struct nk_color col) { GdipGraphicsClear(gdip.memory, convert_color(col)); } static void nk_gdip_blit(GpGraphics *graphics) { GdipDrawImageI(graphics, gdip.bitmap, 0, 0); } static struct nk_image nk_gdip_image_to_nk(GpImage *image) { struct nk_image img; UINT uwidth, uheight; img = nk_image_ptr( (void*)image ); GdipGetImageHeight(image, &uheight); GdipGetImageWidth(image, &uwidth); img.h = uheight; img.w = uwidth; return img; } struct nk_image nk_gdip_load_image_from_file(const WCHAR *filename) { GpImage *image; if (GdipLoadImageFromFile(filename, &image)) return nk_image_id(0); return nk_gdip_image_to_nk(image); } struct nk_image nk_gdip_load_image_from_memory(const void *membuf, nk_uint membufSize) { GpImage* image; GpStatus status; IStream *stream = SHCreateMemStream((const BYTE*)membuf, membufSize); if (!stream) return nk_image_id(0); status = GdipLoadImageFromStream(stream, &image); stream->lpVtbl->Release(stream); if (status) return nk_image_id(0); return nk_gdip_image_to_nk(image); } void nk_gdip_image_free(struct nk_image image) { if (!image.handle.ptr) return; GdipDisposeImage(image.handle.ptr); } GdipFont* nk_gdipfont_create(const char *name, int size) { GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont)); GpFontFamily *family; int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); WCHAR* wname = (WCHAR*)_alloca((wsize + 1) * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, wsize); wname[wsize] = 0; GdipCreateFontFamilyFromName(wname, NULL, &family); GdipCreateFont(family, (REAL)size, FontStyleRegular, UnitPixel, &font->handle); GdipDeleteFontFamily(family); return font; } GpFontCollection* nk_gdip_getCurFontCollection(){ return gdip.fontCollection[gdip.curFontCollection]; } GdipFont* nk_gdipfont_create_from_collection(int size){ GpFontFamily **families; INT count; GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont)); if( GdipGetFontCollectionFamilyCount(nk_gdip_getCurFontCollection(), &count) ) return NULL; families = (GpFontFamily**)calloc(1, sizeof(GpFontFamily*)); if( !families ) return NULL; if( GdipGetFontCollectionFamilyList(nk_gdip_getCurFontCollection(), count, families, &count) ) return NULL; if( count < 1 ) return NULL; if( GdipCreateFont(families[count-1], (REAL)size, FontStyleRegular, UnitPixel, &font->handle) ) return NULL; free(families); gdip.curFontCollection++; return font; } GdipFont* nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size) { if( !nk_gdip_getCurFontCollection() ) if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL; if( GdipPrivateAddMemoryFont(nk_gdip_getCurFontCollection(), membuf, membufSize) ) return NULL; return nk_gdipfont_create_from_collection(size); } GdipFont* nk_gdipfont_create_from_file(const WCHAR* filename, int size) { if( !nk_gdip_getCurFontCollection() ) if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL; if( GdipPrivateAddFontFile(nk_gdip_getCurFontCollection(), filename) ) return NULL; return nk_gdipfont_create_from_collection(size); } static float nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len) { GdipFont *font = (GdipFont *)handle.ptr; RectF layout = { 0.0f, 0.0f, 65536.0f, 65536.0f }; RectF bbox; int wsize; WCHAR* wstr; if (!font || !text) return 0; (void)height; wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); wstr = (WCHAR*)_malloca(wsize * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); GdipMeasureString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, &bbox, NULL, NULL); return bbox.Width; } void nk_gdipfont_del(GdipFont *font) { if(!font) return; GdipDeleteFont(font->handle); free(font); } static void nk_gdip_clipboard_paste(nk_handle usr, struct nk_text_edit* edit) { (void)usr; if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); if (mem) { SIZE_T size = GlobalSize(mem) - 1; if (size) { LPCWSTR wstr = (LPCWSTR)GlobalLock(mem); if (wstr) { int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL); if (utf8size) { char* utf8 = (char*)malloc(utf8size); if (utf8) { WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL); nk_textedit_paste(edit, utf8, utf8size); free(utf8); } } GlobalUnlock(mem); } } } CloseClipboard(); } } static void nk_gdip_clipboard_copy(nk_handle usr, const char* text, int len) { if (OpenClipboard(NULL)) { int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); if (wsize) { HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t)); if (mem) { wchar_t* wstr = (wchar_t*)GlobalLock(mem); if (wstr) { MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); wstr[wsize] = 0; GlobalUnlock(mem); SetClipboardData(CF_UNICODETEXT, mem); } } } CloseClipboard(); } } NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height) { int i; GdiplusStartupInput startup = { 1, NULL, FALSE, TRUE }; GdiplusStartup(&gdip.token, &startup, NULL); GdipCreateFromHWND(hwnd, &gdip.window); GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap); GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory); GdipCreatePen1(0, 1.0f, UnitPixel, &gdip.pen); GdipCreateSolidFill(0, &gdip.brush); GdipStringFormatGetGenericTypographic(&gdip.format); GdipSetStringFormatFlags(gdip.format, StringFormatFlagsNoFitBlackBox | StringFormatFlagsMeasureTrailingSpaces | StringFormatFlagsNoWrap | StringFormatFlagsNoClip); for(i=0; i< sizeof(gdip.fontCollection)/sizeof(gdip.fontCollection[0]); i++) gdip.fontCollection[i] = NULL; nk_init_default(&gdip.ctx, NULL); gdip.ctx.clip.copy = nk_gdip_clipboard_copy; gdip.ctx.clip.paste = nk_gdip_clipboard_paste; gdip.curFontCollection = 0; return &gdip.ctx; } NK_API void nk_gdip_set_font(GdipFont *gdipfont) { struct nk_user_font *font = &gdipfont->nk; font->userdata = nk_handle_ptr(gdipfont); GdipGetFontSize(gdipfont->handle, &font->height); font->width = nk_gdipfont_get_text_width; nk_style_set_font(&gdip.ctx, font); } NK_API int nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_SIZE: if (gdip.window) { unsigned int width = LOWORD(lparam); unsigned int height = HIWORD(lparam); GdipDeleteGraphics(gdip.window); GdipDeleteGraphics(gdip.memory); GdipDisposeImage(gdip.bitmap); GdipCreateFromHWND(wnd, &gdip.window); GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap); GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory); } break; case WM_PAINT: { PAINTSTRUCT paint; HDC dc = BeginPaint(wnd, &paint); GpGraphics *graphics; GdipCreateFromHDC(dc, &graphics); nk_gdip_blit(graphics); GdipDeleteGraphics(graphics); EndPaint(wnd, &paint); return 1; } case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: { int down = !((lparam >> 31) & 1); int ctrl = GetKeyState(VK_CONTROL) & (1 << 15); switch (wparam) { case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: nk_input_key(&gdip.ctx, NK_KEY_SHIFT, down); return 1; case VK_DELETE: nk_input_key(&gdip.ctx, NK_KEY_DEL, down); return 1; case VK_RETURN: nk_input_key(&gdip.ctx, NK_KEY_ENTER, down); return 1; case VK_TAB: nk_input_key(&gdip.ctx, NK_KEY_TAB, down); return 1; case VK_LEFT: if (ctrl) nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_LEFT, down); else nk_input_key(&gdip.ctx, NK_KEY_LEFT, down); return 1; case VK_RIGHT: if (ctrl) nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_RIGHT, down); else nk_input_key(&gdip.ctx, NK_KEY_RIGHT, down); return 1; case VK_BACK: nk_input_key(&gdip.ctx, NK_KEY_BACKSPACE, down); return 1; case VK_HOME: nk_input_key(&gdip.ctx, NK_KEY_TEXT_START, down); nk_input_key(&gdip.ctx, NK_KEY_SCROLL_START, down); return 1; case VK_END: nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down); nk_input_key(&gdip.ctx, NK_KEY_SCROLL_END, down); return 1; case VK_NEXT: nk_input_key(&gdip.ctx, NK_KEY_SCROLL_DOWN, down); return 1; case VK_PRIOR: nk_input_key(&gdip.ctx, NK_KEY_SCROLL_UP, down); return 1; case 'A': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_TEXT_SELECT_ALL, down); return 1; } break; case 'C': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_COPY, down); return 1; } break; case 'V': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_PASTE, down); return 1; } break; case 'X': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_CUT, down); return 1; } break; case 'Z': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_TEXT_UNDO, down); return 1; } break; case 'R': if (ctrl) { nk_input_key(&gdip.ctx, NK_KEY_TEXT_REDO, down); return 1; } break; } return 0; } case WM_CHAR: if (wparam >= 32) { nk_input_unicode(&gdip.ctx, (nk_rune)wparam); return 1; } break; case WM_LBUTTONDOWN: nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); SetCapture(wnd); return 1; case WM_LBUTTONUP: nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); ReleaseCapture(); return 1; case WM_RBUTTONDOWN: nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); SetCapture(wnd); return 1; case WM_RBUTTONUP: nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); ReleaseCapture(); return 1; case WM_MBUTTONDOWN: nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); SetCapture(wnd); return 1; case WM_MBUTTONUP: nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); ReleaseCapture(); return 1; case WM_MOUSEWHEEL: nk_input_scroll(&gdip.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA)); return 1; case WM_MOUSEMOVE: nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam)); return 1; case WM_LBUTTONDBLCLK: nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); return 1; } return 0; } NK_API void nk_gdip_shutdown(void) { int i; for(i=0; i< gdip.curFontCollection; i++) GdipDeletePrivateFontCollection( &gdip.fontCollection[i] ); GdipDeleteGraphics(gdip.window); GdipDeleteGraphics(gdip.memory); GdipDisposeImage(gdip.bitmap); GdipDeletePen(gdip.pen); GdipDeleteBrush(gdip.brush); GdipDeleteStringFormat(gdip.format); GdiplusShutdown(gdip.token); nk_free(&gdip.ctx); } NK_API void nk_gdip_prerender_gui(enum nk_anti_aliasing AA) { const struct nk_command *cmd; GdipSetTextRenderingHint(gdip.memory, AA != NK_ANTI_ALIASING_OFF ? TextRenderingHintClearTypeGridFit : TextRenderingHintSingleBitPerPixelGridFit); GdipSetSmoothingMode(gdip.memory, AA != NK_ANTI_ALIASING_OFF ? SmoothingModeHighQuality : SmoothingModeNone); nk_foreach(cmd, &gdip.ctx) { switch (cmd->type) { case NK_COMMAND_NOP: break; case NK_COMMAND_SCISSOR: { const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; nk_gdip_scissor(s->x, s->y, s->w, s->h); } break; case NK_COMMAND_LINE: { const struct nk_command_line *l = (const struct nk_command_line *)cmd; nk_gdip_stroke_line(l->begin.x, l->begin.y, l->end.x, l->end.y, l->line_thickness, l->color); } break; case NK_COMMAND_RECT: { const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; nk_gdip_stroke_rect(r->x, r->y, r->w, r->h, (unsigned short)r->rounding, r->line_thickness, r->color); } break; case NK_COMMAND_RECT_FILLED: { const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; nk_gdip_fill_rect(r->x, r->y, r->w, r->h, (unsigned short)r->rounding, r->color); } break; case NK_COMMAND_CIRCLE: { const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; nk_gdip_stroke_circle(c->x, c->y, c->w, c->h, c->line_thickness, c->color); } break; case NK_COMMAND_CIRCLE_FILLED: { const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; nk_gdip_fill_circle(c->x, c->y, c->w, c->h, c->color); } break; case NK_COMMAND_TRIANGLE: { const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; nk_gdip_stroke_triangle(t->a.x, t->a.y, t->b.x, t->b.y, t->c.x, t->c.y, t->line_thickness, t->color); } break; case NK_COMMAND_TRIANGLE_FILLED: { const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; nk_gdip_fill_triangle(t->a.x, t->a.y, t->b.x, t->b.y, t->c.x, t->c.y, t->color); } break; case NK_COMMAND_POLYGON: { const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; nk_gdip_stroke_polygon(p->points, p->point_count, p->line_thickness,p->color); } break; case NK_COMMAND_POLYGON_FILLED: { const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; nk_gdip_fill_polygon(p->points, p->point_count, p->color); } break; case NK_COMMAND_POLYLINE: { const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; nk_gdip_stroke_polyline(p->points, p->point_count, p->line_thickness, p->color); } break; case NK_COMMAND_TEXT: { const struct nk_command_text *t = (const struct nk_command_text*)cmd; nk_gdip_draw_text(t->x, t->y, t->w, t->h, (const char*)t->string, t->length, (GdipFont*)t->font->userdata.ptr, t->background, t->foreground); } break; case NK_COMMAND_CURVE: { const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; nk_gdip_stroke_curve(q->begin, q->ctrl[0], q->ctrl[1], q->end, q->line_thickness, q->color); } break; case NK_COMMAND_IMAGE: { const struct nk_command_image *i = (const struct nk_command_image *)cmd; nk_gdip_draw_image(i->x, i->y, i->w, i->h, i->img, i->col); } break; case NK_COMMAND_ARC: { const struct nk_command_arc *i = (const struct nk_command_arc *)cmd; nk_gdip_stroke_arc(i->cx, i->cy, i->r, i->a[0], i->a[1], i->line_thickness, i->color); } break; case NK_COMMAND_ARC_FILLED: { const struct nk_command_arc_filled *i = (const struct nk_command_arc_filled *)cmd; nk_gdip_fill_arc(i->cx, i->cy, i->r, i->a[0], i->a[1], i->color); } break; case NK_COMMAND_RECT_MULTI_COLOR: default: break; } } } NK_API void nk_gdip_render_gui(enum nk_anti_aliasing AA) { nk_gdip_prerender_gui(AA); nk_gdip_blit(gdip.window); nk_clear(&gdip.ctx); } NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear) { nk_gdip_clear(clear); nk_gdip_render_gui(AA); } #endif