#include <GL/gl.h>
#include "drawing.h"
#include "font.h"
#include "window.h"
#include "nuklear-heli.h"
#define NK_IMPLEMENTATION
#include "nuklear-full.inc.h"
static float nk_heli_text_width(nk_handle handle, float height, const char *text, int len) {
saveStateEx(STATE_TEXT_SIZE);
TextLayout l = createTextLayoutEx(text, len);
textSize(height);
//float w = textLayoutGetWidth(l);
float w = textLayoutCursorGetX(l, len);
textLayoutDestroy(l);
restoreState();
return w;
}
static void nk_heli_clipboard_paste(nk_handle handle, struct nk_text_edit *edit) {
const char *t = windowGetClipboardText();
if (*t) nk_textedit_paste(edit, t, nk_utf_len(t, strlen(t)));
}
static void nk_heli_clipboard_copy(nk_handle handle, const char *text, int len) {
int glyph_len;
nk_rune unicode;
int l = nk_utf_at(text, len*4, len, &unicode, &glyph_len) - text;
windowSetClipboardTextEx(text, l);
}
unsigned int nk_color_to_heli(struct nk_color c)
{ return colorByRGBA(c.r/255.0, c.g/255.0, c.b/255.0, c.a/255.0); }
struct nk_color nk_color_from_heli(unsigned int c)
{ struct nk_color cc = { c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff, c >> 24 }; return cc; }
nk_bool nk_heli_init(nk_heli *n, double fontSize) {
memset(n, 0, sizeof(*n));
n->font.height = fontSize;
n->font.width = &nk_heli_text_width;
if (!nk_init_default(&n->context, &n->font))
return 0;
struct nk_context *c = &n->context;
c->clip.paste = &nk_heli_clipboard_paste;
c->clip.copy = &nk_heli_clipboard_copy;
return 1;
}
void nk_heli_deinit(nk_heli *n)
{ nk_free(&n->context); }
struct nk_image nk_heli_image(Animation anim, int width, int height) {
struct nk_image img = nk_image_ptr(anim);
img.w = width;
img.h = height;
return img;
}
void nk_heli_input(nk_heli *n) {
struct {
enum nk_buttons nk;
const char *hl;
} buttons[] = {
{ NK_BUTTON_LEFT , "left" },
{ NK_BUTTON_MIDDLE , "middle" },
{ NK_BUTTON_RIGHT , "right" } };
const int buttonsCnt = sizeof(buttons)/sizeof(*buttons);
struct {
enum nk_keys nk;
const char *hl;
int ctrl;
} keys[] = {
{ NK_KEY_SHIFT , "any shift" },
{ NK_KEY_CTRL , "any ctrl" },
{ NK_KEY_DEL , "delete" },
{ NK_KEY_ENTER , "any return" },
{ NK_KEY_TAB , "tab" },
{ NK_KEY_BACKSPACE , "backspace" },
{ NK_KEY_COPY , "c", 1 },
{ NK_KEY_CUT , "x", 1 },
{ NK_KEY_PASTE , "v", 1 },
{ NK_KEY_UP , "up" },
{ NK_KEY_DOWN , "down" },
{ NK_KEY_LEFT , "left", -1 },
{ NK_KEY_RIGHT , "right", -1 },
{ NK_KEY_TEXT_LINE_START , "home", -1 },
{ NK_KEY_TEXT_LINE_END , "end", -1 },
{ NK_KEY_TEXT_START , "home", 1 },
{ NK_KEY_TEXT_END , "end", 1 },
{ NK_KEY_TEXT_UNDO , "z", 1 },
{ NK_KEY_TEXT_REDO , "y", 1 },
{ NK_KEY_TEXT_SELECT_ALL , "a", 1 },
{ NK_KEY_TEXT_WORD_LEFT , "left", 1 },
{ NK_KEY_TEXT_WORD_RIGHT , "right", 1 },
{ NK_KEY_SCROLL_START , "home", 1 },
{ NK_KEY_SCROLL_END , "end", 1 },
{ NK_KEY_SCROLL_DOWN , "page down" },
{ NK_KEY_SCROLL_UP , "page up" } };
const int keysCnt = sizeof(keys)/sizeof(*keys);
struct nk_context *c = &n->context;
double mx = mouseTransformedX();
double my = mouseTransformedY();
nk_input_begin(c);
nk_input_motion(c, mx, my);
struct nk_vec2 scroll = {};
scroll.x = mouseScrolledX();
scroll.y = mouseScrolledY();
if (scroll.x || scroll.y)
nk_input_scroll(c, scroll);
for(int i = 0; i < buttonsCnt; ++i) {
if (mouseWentDown(buttons[i].hl))
nk_input_button(c, buttons[i].nk, mx, my, 1);
if (mouseWentUp(buttons[i].hl))
nk_input_button(c, buttons[i].nk, mx, my, 0);
}
int modes[] = { KEYEVENT_KEY_WENTUP, KEYEVENT_KEY_WENTDOWN };
int ctrl = keyDown("any ctrl") || keyWentDown("any ctrl");
for(int down = 1; down >= 0; --down)
for(int i = 0; i < keyEventGetCount(modes[down]); ++i) {
const char *k = keyEventGet(modes[down], i);
for(int j = 0; j < keysCnt; ++j) {
int ct = keys[j].ctrl;
if ( (ct > 0 && !ctrl)
|| (ct < 0 && ctrl)
|| 0 != strcmp(k, keys[j].hl) )
continue;
nk_input_key(c, keys[j].nk, down);
}
}
const char *t = textInputGet();
while(*t) {
int len = (t[1] & 0xC0) == 0x80 ? 2
: (t[0] & 0xF0) == 0xE0
&& (t[1] & 0xC0) == 0x80
&& (t[2] & 0xC0) == 0x80 ? 3
: (t[0] & 0xF8) == 0xF0
&& (t[1] & 0xC0) == 0x80
&& (t[2] & 0xC0) == 0x80
&& (t[3] & 0xC0) == 0x80 ? 4 : 1;
nk_glyph g = {};
memcpy(g, t, len);
nk_input_glyph(c, g);
t += len;
}
textInputClear();
nk_input_end(c);
}
void nk_heli_draw(nk_heli *n) {
saveState();
struct nk_context *c = &n->context;
const struct nk_command *cmd;
nk_foreach(cmd, c) {
switch (cmd->type) {
case NK_COMMAND_SCISSOR: {
const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;
cliprect(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;
strokeWidth(l->line_thickness);
stroke( nk_color_to_heli(l->color) );
line(l->begin.x, l->begin.y, l->end.x, l->end.y);
} break;
case NK_COMMAND_RECT: {
const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
strokeWidth(r->line_thickness);
stroke( nk_color_to_heli(r->color) );
noFill();
rectRounded(r->x, r->y, r->w, r->h, r->rounding);
} break;
case NK_COMMAND_RECT_FILLED: {
const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
noStroke();
fill( nk_color_to_heli(r->color) );
rectRounded(r->x, r->y, r->w, r->h, r->rounding);
} break;
case NK_COMMAND_RECT_MULTI_COLOR: {
const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color *)cmd;
glBegin(GL_QUADS);
glColor4ubv( &r->left.r ); glVertex2i( r->x , r->y );
glColor4ubv( &r->top.r ); glVertex2i( r->x + r->w , r->y );
glColor4ubv( &r->right.r ); glVertex2i( r->x + r->w , r->y + r->h );
glColor4ubv( &r->bottom.r ); glVertex2i( r->x , r->y + r->h );
glEnd();
} break;
case NK_COMMAND_CIRCLE: {
const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
strokeWidth(c->line_thickness);
stroke( nk_color_to_heli(c->color) );
noFill();
ellipse(c->x, c->y, c->w, c->h);
} break;
case NK_COMMAND_CIRCLE_FILLED: {
const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
noStroke();
fill( nk_color_to_heli(c->color) );
ellipse(c->x, c->y, c->w, c->h);
} break;
case NK_COMMAND_ARC: {
const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;
strokeWidth(a->line_thickness);
stroke( nk_color_to_heli(a->color) );
noFill();
arc(a->cx - a->r, a->cy - a->r, a->r*2, a->r*2, a->a[0], a->a[1]);
} break;
case NK_COMMAND_ARC_FILLED: {
const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled *)cmd;
noStroke();
fill( nk_color_to_heli(a->color) );
moveTo(a->cx, a->cy);
arcPath(a->cx - a->r, a->cy - a->r, a->r*2, a->r*2, a->a[0], a->a[1]);
closePath();
} break;
case NK_COMMAND_TRIANGLE: {
const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
strokeWidth(t->line_thickness);
stroke( nk_color_to_heli(t->color) );
noFill();
moveTo(t->a.x, t->a.y);
lineTo(t->b.x, t->b.y);
lineTo(t->c.x, t->c.y);
closePath();
} break;
case NK_COMMAND_TRIANGLE_FILLED: {
const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
noStroke();
fill( nk_color_to_heli(t->color) );
moveTo(t->a.x, t->a.y);
lineTo(t->b.x, t->b.y);
lineTo(t->c.x, t->c.y);
closePath();
} break;
case NK_COMMAND_POLYGON: {
const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
strokeWidth(p->line_thickness);
stroke( nk_color_to_heli(p->color) );
noFill();
moveTo(p->points[0].x, p->points[0].y);
for(int i = 1; i < p->point_count; ++i)
lineTo(p->points[i].x, p->points[i].y);
closePath();
} break;
case NK_COMMAND_POLYGON_FILLED: {
const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
noStroke();
fill( nk_color_to_heli(p->color) );
moveTo(p->points[0].x, p->points[0].y);
for(int i = 1; i < p->point_count; ++i)
lineTo(p->points[i].x, p->points[i].y);
closePath();
} break;
case NK_COMMAND_POLYLINE: {
const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
strokeWidth(p->line_thickness);
stroke( nk_color_to_heli(p->color) );
noFill();
moveTo(p->points[0].x, p->points[0].y);
for(int i = 1; i < p->point_count; ++i)
lineTo(p->points[i].x, p->points[i].y);
strokePath();
} break;
case NK_COMMAND_TEXT: {
const struct nk_command_text *t = (const struct nk_command_text*)cmd;
//noStroke();
//fill( nk_color_to_heli(t->background) );
//rect( t->x, t->y, t->w, t->h );
stroke( nk_color_to_heli(t->foreground) );
noFill();
textSize(t->height);
textAlign(HALIGN_LEFT, VALIGN_TOP);
TextLayout l = createTextLayoutEx(t->string, t->length);
textLayoutDraw(l, t->x, t->y - 0.2*t->height);
textLayoutDestroy(l);
} break;
case NK_COMMAND_CURVE: {
const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
strokeWidth(q->line_thickness);
stroke( nk_color_to_heli(q->color) );
noFill();
line(q->begin.x, q->begin.y, q->end.x, q->end.y);
} break;
case NK_COMMAND_IMAGE: {
const struct nk_command_image *i = (const struct nk_command_image *)cmd;
noStroke();
fill( nk_color_to_heli(i->col) );
if (i->img.handle.ptr)
rectTextured((Animation)i->img.handle.ptr, i->x, i->y, i->w, i->h);
} break;
default: break;
}
}
nk_clear(c);
restoreState();
}
void nk_heli_process(nk_heli *n) {
nk_heli_input(n);
nk_heli_draw(n);
}