d6ac1e4d3f
Fix incorrect button drawing (wrong stroke, empty spaces in stroke line near the corners). Since there are quarters of circle in the angles then lines must be moved to R, not to D.
1007 lines
29 KiB
C
1007 lines
29 KiB
C
/*
|
|
* Nuklear - v1.17 - public domain
|
|
* no warrenty implied; use at your own risk.
|
|
* authored from 2015-2016 by Micha Mettke
|
|
*/
|
|
/*
|
|
* ==============================================================
|
|
*
|
|
* API
|
|
*
|
|
* ===============================================================
|
|
*/
|
|
#ifndef NK_GDIP_H_
|
|
#define NK_GDIP_H_
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
/* font */
|
|
typedef struct GdipFont GdipFont;
|
|
NK_API GdipFont* nk_gdipfont_create(const char *name, 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);
|
|
|
|
#endif
|
|
/*
|
|
* ==============================================================
|
|
*
|
|
* IMPLEMENTATION
|
|
*
|
|
* ===============================================================
|
|
*/
|
|
#ifdef NK_GDIP_IMPLEMENTATION
|
|
|
|
#include <stdlib.h>
|
|
#include <malloc.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);
|
|
|
|
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;
|
|
|
|
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, 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 = (WCHAR*)_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, font->handle, &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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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*)_alloca(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_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 = (HGLOBAL)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 = (char*)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 = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
|
|
if (!mem) {
|
|
CloseClipboard();
|
|
return;
|
|
}
|
|
|
|
wstr = (wchar_t*)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 = &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 '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);
|
|
}
|
|
|
|
#endif
|
|
|