Blob Blame Raw

#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);
}