瀏覽代碼

Created demo using Win32 GDI+ for rendering. Uses VS2015 for compiler.

Martins Mozeiko 9 年之前
父節點
當前提交
c4cf1ad23e
共有 4 個文件被更改,包括 1108 次插入0 次删除
  1. 5 0
      demo/gdip/build.bat
  2. 127 0
      demo/gdip/main.c
  3. 958 0
      demo/gdip/nuklear_gdip.c
  4. 18 0
      demo/gdip/nuklear_gdip.h

+ 5 - 0
demo/gdip/build.bat

@@ -0,0 +1,5 @@
+@echo off
+
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /nologo /W3 /WX /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdiplus.lib /link /incremental:no

+ 127 - 0
demo/gdip/main.c

@@ -0,0 +1,127 @@
+/* nuklear - v1.00 - public domain */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#include "nuklear_gdip.h"
+#include "nuklear_gdip.c"
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        return 0;
+    }
+
+    if (nk_gdip_handle_event(wnd, msg, wparam, lparam))
+        return 0;
+
+    return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+    GdipFont* font;
+    struct nk_context *ctx;
+
+    WNDCLASSW wc;
+    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+    DWORD style = WS_OVERLAPPEDWINDOW;
+    DWORD exstyle = WS_EX_APPWINDOW;
+    HWND wnd;
+    int running = 1;
+    int needs_refresh = 1;
+
+    /* Win32 */
+    memset(&wc, 0, sizeof(wc));
+    wc.lpfnWndProc = WindowProc;
+    wc.hInstance = GetModuleHandleW(0);
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.lpszClassName = L"NuklearWindowClass";
+    RegisterClassW(&wc);
+
+    AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+        rect.right - rect.left, rect.bottom - rect.top,
+        NULL, NULL, wc.hInstance, NULL);
+
+    /* GUI */
+    ctx = nk_gdip_init(wnd, WINDOW_WIDTH, WINDOW_HEIGHT);
+    font = nk_gdipfont_create("Arial", 12);
+    nk_gdip_set_font(font);
+    while (running)
+    {
+        MSG msg;
+
+        /* Input */
+        nk_input_begin(ctx);
+        if (needs_refresh == 0)
+        {
+            if (GetMessageW(&msg, NULL, 0, 0) <= 0)
+            {
+                running = 0;
+            }
+            else
+            {
+                TranslateMessage(&msg);
+                DispatchMessageW(&msg);
+            }
+            needs_refresh = 1;
+        }
+        else
+        {
+            needs_refresh = 0;
+        }
+        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+        {
+            if (msg.message == WM_QUIT)
+                running = 0;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+            needs_refresh = 1;
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        {struct nk_panel layout;
+        if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 200, 200),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+        }
+        nk_end(ctx);}
+        if (nk_window_is_closed(ctx, "Demo")) break;
+
+        /* Draw */
+        nk_gdip_render(NK_ANTI_ALIASING_ON, nk_rgb(30,30,30));
+    }
+
+    nk_gdipfont_del(font);
+    nk_gdip_shutdown();
+    UnregisterClassW(wc.lpszClassName, wc.hInstance);
+    return 0;
+}

+ 958 - 0
demo/gdip/nuklear_gdip.c

@@ -0,0 +1,958 @@
+#include <stdlib.h>
+#include <malloc.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define NK_IMPLEMENTATION
+#include "nuklear_gdip.h"
+#include "../../nuklear.h"
+
+/* 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);
+
+/* 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);
+
+/* 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
+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
+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);
+
+
+static struct {
+    ULONG_PTR token;
+
+    GpGraphics *window;
+    GpGraphics *memory;
+    GpImage *bitmap;
+    GpPen *pen;
+    GpSolidFill *brush;
+    GpStringFormat *format;
+
+    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 + d, y, x + w - d, y);
+        GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90);
+        GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + d, x + w, y + h - d);
+        GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90);
+        GdipDrawLineI(gdip.memory, gdip.pen, x, y + d, x + w, y + h - d);
+        GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90);
+        GdipDrawLineI(gdip.memory, gdip.pen, x + d, y + h, x + w - d, 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, w, 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 void
+nk_gdip_fill_triangle(short x0, short y0, short x1,
+    short y1, short x2, short y2, struct nk_color col)
+{
+    POINT points[] = {
+        { x0, y0 },
+        { x1, y1 },
+        { 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[] = {
+        { x0, y0 },
+        { x1, y1 },
+        { x2, y2 },
+        { 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_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 = { (FLOAT)x, (FLOAT)y, (FLOAT)w, (FLOAT)h };
+
+    if(!text || !font || !len) return;
+
+    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+    wstr = _alloca(wsize * sizeof(wchar_t));
+    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+    GdipSetSolidFillColor(gdip.brush, convert_color(cbg));
+    GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);
+    GdipSetSolidFillColor(gdip.brush, convert_color(cfg));
+    GdipDrawString(gdip.memory, wstr, wsize, (GpFont *)font, &layout, gdip.format, gdip.brush);
+}
+
+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);
+}
+
+GdipFont*
+nk_gdipfont_create(const char *name, int size)
+{
+    GpFont* font;
+    GpFontFamily *family;
+
+    int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+    WCHAR* wname = _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);
+    GdipDeleteFontFamily(family);
+
+    return (GdipFont *)font;
+}
+
+static float
+nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+    GpFont *font = (GpFont *)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 = _alloca(wsize * sizeof(wchar_t));
+    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+    GdipMeasureString(gdip.memory, wstr, wsize, font, &layout, gdip.format, &bbox, NULL, NULL);
+    return bbox.Width;
+}
+
+void
+nk_gdipfont_del(GdipFont *font)
+{
+    if(!font) return;
+    GdipDeleteFont((GpFont *)font);
+}
+
+static void
+nk_gdip_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    HGLOBAL mem;
+    SIZE_T size;
+    LPCWSTR wstr;
+    int utf8size;
+    char* utf8;
+    (void)usr;
+
+    if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+        return;
+
+    mem = GetClipboardData(CF_UNICODETEXT);
+    if (!mem) {
+        CloseClipboard();
+        return;
+    }
+
+    size = GlobalSize(mem) - 1;
+    if (!size) {
+        CloseClipboard();
+        return;
+    }
+
+    wstr = (LPCWSTR)GlobalLock(mem);
+    if (!wstr) {
+        CloseClipboard();
+        return;
+    }
+
+    utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
+    if (!utf8size) {
+        GlobalUnlock(mem);
+        CloseClipboard();
+        return;
+    }
+
+    utf8 = malloc(utf8size);
+    if (!utf8) {
+        GlobalUnlock(mem);
+        CloseClipboard();
+        return;
+    }
+
+    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_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+    HGLOBAL mem;
+    wchar_t* wstr;
+    int wsize;
+    (void)usr;
+
+    if (!OpenClipboard(NULL))
+        return;
+
+    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+    if (!wsize) {
+        CloseClipboard();
+        return;
+    }
+
+    mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+    if (!mem) {
+        CloseClipboard();
+        return;
+    }
+
+    wstr = GlobalLock(mem);
+    if (!wstr) {
+        GlobalFree(mem);
+        CloseClipboard();
+        return;
+    }
+
+    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+    wstr[wsize] = 0;
+    GlobalUnlock(mem);
+
+    if (!SetClipboardData(CF_UNICODETEXT, mem))
+        GlobalFree(mem);
+
+    CloseClipboard();
+}
+
+NK_API struct nk_context*
+nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height)
+{
+    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);
+
+    nk_init_default(&gdip.ctx, NULL);
+    gdip.ctx.clip.copy = nk_gdip_clipbard_copy;
+    gdip.ctx.clip.paste = nk_gdip_clipbard_paste;
+    return &gdip.ctx;
+}
+
+NK_API void
+nk_gdip_set_font(GdipFont *gdipfont)
+{
+    struct nk_user_font font;
+    font.userdata = nk_handle_ptr(gdipfont);
+    GdipGetFontSize((GpFont *)gdipfont, &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);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down);
+            return 1;
+
+        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_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, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+        return 1;
+
+    case WM_MOUSEMOVE:
+        nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+        return 1;
+    }
+
+    return 0;
+}
+
+NK_API void
+nk_gdip_shutdown(void)
+{
+    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_render(enum nk_anti_aliasing AA, struct nk_color clear)
+{
+    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_gdip_clear(clear);
+
+    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_RECT_MULTI_COLOR:
+        case NK_COMMAND_IMAGE:
+        case NK_COMMAND_ARC:
+        case NK_COMMAND_ARC_FILLED:
+        default: break;
+        }
+    }
+    nk_gdip_blit(gdip.window);
+    nk_clear(&gdip.ctx);
+}

+ 18 - 0
demo/gdip/nuklear_gdip.h

@@ -0,0 +1,18 @@
+#ifndef NK_GDI_H_
+#define NK_GDI_H_
+
+#include "../../nuklear.h"
+
+typedef struct GdipFont GdipFont;
+
+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);
+
+/* font */
+NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
+NK_API void nk_gdipfont_del(GdipFont *font);
+
+#endif