345 lines
10 KiB
C
345 lines
10 KiB
C
|
#include "nuklear.h"
|
||
|
#include "nuklear_internal.h"
|
||
|
|
||
|
/* ==============================================================
|
||
|
*
|
||
|
* CONTEXT
|
||
|
*
|
||
|
* ===============================================================*/
|
||
|
NK_INTERN void
|
||
|
nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
|
||
|
{
|
||
|
NK_ASSERT(ctx);
|
||
|
if (!ctx) return;
|
||
|
nk_zero_struct(*ctx);
|
||
|
nk_style_default(ctx);
|
||
|
ctx->seq = 1;
|
||
|
if (font) ctx->style.font = font;
|
||
|
#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
|
||
|
nk_draw_list_init(&ctx->draw_list);
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
|
||
|
NK_API nk_bool
|
||
|
nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
|
||
|
{
|
||
|
struct nk_allocator alloc;
|
||
|
alloc.userdata.ptr = 0;
|
||
|
alloc.alloc = nk_malloc;
|
||
|
alloc.free = nk_mfree;
|
||
|
return nk_init(ctx, &alloc, font);
|
||
|
}
|
||
|
#endif
|
||
|
NK_API nk_bool
|
||
|
nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
|
||
|
const struct nk_user_font *font)
|
||
|
{
|
||
|
NK_ASSERT(memory);
|
||
|
if (!memory) return 0;
|
||
|
nk_setup(ctx, font);
|
||
|
nk_buffer_init_fixed(&ctx->memory, memory, size);
|
||
|
ctx->use_pool = nk_false;
|
||
|
return 1;
|
||
|
}
|
||
|
NK_API nk_bool
|
||
|
nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
|
||
|
struct nk_buffer *pool, const struct nk_user_font *font)
|
||
|
{
|
||
|
NK_ASSERT(cmds);
|
||
|
NK_ASSERT(pool);
|
||
|
if (!cmds || !pool) return 0;
|
||
|
|
||
|
nk_setup(ctx, font);
|
||
|
ctx->memory = *cmds;
|
||
|
if (pool->type == NK_BUFFER_FIXED) {
|
||
|
/* take memory from buffer and alloc fixed pool */
|
||
|
nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
|
||
|
} else {
|
||
|
/* create dynamic pool from buffer allocator */
|
||
|
struct nk_allocator *alloc = &pool->pool;
|
||
|
nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
|
||
|
}
|
||
|
ctx->use_pool = nk_true;
|
||
|
return 1;
|
||
|
}
|
||
|
NK_API nk_bool
|
||
|
nk_init(struct nk_context *ctx, struct nk_allocator *alloc,
|
||
|
const struct nk_user_font *font)
|
||
|
{
|
||
|
NK_ASSERT(alloc);
|
||
|
if (!alloc) return 0;
|
||
|
nk_setup(ctx, font);
|
||
|
nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
|
||
|
nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
|
||
|
ctx->use_pool = nk_true;
|
||
|
return 1;
|
||
|
}
|
||
|
#ifdef NK_INCLUDE_COMMAND_USERDATA
|
||
|
NK_API void
|
||
|
nk_set_user_data(struct nk_context *ctx, nk_handle handle)
|
||
|
{
|
||
|
if (!ctx) return;
|
||
|
ctx->userdata = handle;
|
||
|
if (ctx->current)
|
||
|
ctx->current->buffer.userdata = handle;
|
||
|
}
|
||
|
#endif
|
||
|
NK_API void
|
||
|
nk_free(struct nk_context *ctx)
|
||
|
{
|
||
|
NK_ASSERT(ctx);
|
||
|
if (!ctx) return;
|
||
|
nk_buffer_free(&ctx->memory);
|
||
|
if (ctx->use_pool)
|
||
|
nk_pool_free(&ctx->pool);
|
||
|
|
||
|
nk_zero(&ctx->input, sizeof(ctx->input));
|
||
|
nk_zero(&ctx->style, sizeof(ctx->style));
|
||
|
nk_zero(&ctx->memory, sizeof(ctx->memory));
|
||
|
|
||
|
ctx->seq = 0;
|
||
|
ctx->build = 0;
|
||
|
ctx->begin = 0;
|
||
|
ctx->end = 0;
|
||
|
ctx->active = 0;
|
||
|
ctx->current = 0;
|
||
|
ctx->freelist = 0;
|
||
|
ctx->count = 0;
|
||
|
}
|
||
|
NK_API void
|
||
|
nk_clear(struct nk_context *ctx)
|
||
|
{
|
||
|
struct nk_window *iter;
|
||
|
struct nk_window *next;
|
||
|
NK_ASSERT(ctx);
|
||
|
|
||
|
if (!ctx) return;
|
||
|
if (ctx->use_pool)
|
||
|
nk_buffer_clear(&ctx->memory);
|
||
|
else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
|
||
|
|
||
|
ctx->build = 0;
|
||
|
ctx->memory.calls = 0;
|
||
|
ctx->last_widget_state = 0;
|
||
|
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
|
||
|
NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
|
||
|
|
||
|
/* garbage collector */
|
||
|
iter = ctx->begin;
|
||
|
while (iter) {
|
||
|
/* make sure valid minimized windows do not get removed */
|
||
|
if ((iter->flags & NK_WINDOW_MINIMIZED) &&
|
||
|
!(iter->flags & NK_WINDOW_CLOSED) &&
|
||
|
iter->seq == ctx->seq) {
|
||
|
iter = iter->next;
|
||
|
continue;
|
||
|
}
|
||
|
/* remove hotness from hidden or closed windows*/
|
||
|
if (((iter->flags & NK_WINDOW_HIDDEN) ||
|
||
|
(iter->flags & NK_WINDOW_CLOSED)) &&
|
||
|
iter == ctx->active) {
|
||
|
ctx->active = iter->prev;
|
||
|
ctx->end = iter->prev;
|
||
|
if (!ctx->end)
|
||
|
ctx->begin = 0;
|
||
|
if (ctx->active)
|
||
|
ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
|
||
|
}
|
||
|
/* free unused popup windows */
|
||
|
if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
|
||
|
nk_free_window(ctx, iter->popup.win);
|
||
|
iter->popup.win = 0;
|
||
|
}
|
||
|
/* remove unused window state tables */
|
||
|
{struct nk_table *n, *it = iter->tables;
|
||
|
while (it) {
|
||
|
n = it->next;
|
||
|
if (it->seq != ctx->seq) {
|
||
|
nk_remove_table(iter, it);
|
||
|
nk_zero(it, sizeof(union nk_page_data));
|
||
|
nk_free_table(ctx, it);
|
||
|
if (it == iter->tables)
|
||
|
iter->tables = n;
|
||
|
} it = n;
|
||
|
}}
|
||
|
/* window itself is not used anymore so free */
|
||
|
if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
|
||
|
next = iter->next;
|
||
|
nk_remove_window(ctx, iter);
|
||
|
nk_free_window(ctx, iter);
|
||
|
iter = next;
|
||
|
} else iter = iter->next;
|
||
|
}
|
||
|
ctx->seq++;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
|
||
|
{
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(buffer);
|
||
|
if (!ctx || !buffer) return;
|
||
|
buffer->begin = ctx->memory.allocated;
|
||
|
buffer->end = buffer->begin;
|
||
|
buffer->last = buffer->begin;
|
||
|
buffer->clip = nk_null_rect;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_start(struct nk_context *ctx, struct nk_window *win)
|
||
|
{
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(win);
|
||
|
nk_start_buffer(ctx, &win->buffer);
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_start_popup(struct nk_context *ctx, struct nk_window *win)
|
||
|
{
|
||
|
struct nk_popup_buffer *buf;
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(win);
|
||
|
if (!ctx || !win) return;
|
||
|
|
||
|
/* save buffer fill state for popup */
|
||
|
buf = &win->popup.buf;
|
||
|
buf->begin = win->buffer.end;
|
||
|
buf->end = win->buffer.end;
|
||
|
buf->parent = win->buffer.last;
|
||
|
buf->last = buf->begin;
|
||
|
buf->active = nk_true;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
|
||
|
{
|
||
|
struct nk_popup_buffer *buf;
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(win);
|
||
|
if (!ctx || !win) return;
|
||
|
|
||
|
buf = &win->popup.buf;
|
||
|
buf->last = win->buffer.last;
|
||
|
buf->end = win->buffer.end;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
|
||
|
{
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(buffer);
|
||
|
if (!ctx || !buffer) return;
|
||
|
buffer->end = ctx->memory.allocated;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_finish(struct nk_context *ctx, struct nk_window *win)
|
||
|
{
|
||
|
struct nk_popup_buffer *buf;
|
||
|
struct nk_command *parent_last;
|
||
|
void *memory;
|
||
|
|
||
|
NK_ASSERT(ctx);
|
||
|
NK_ASSERT(win);
|
||
|
if (!ctx || !win) return;
|
||
|
nk_finish_buffer(ctx, &win->buffer);
|
||
|
if (!win->popup.buf.active) return;
|
||
|
|
||
|
buf = &win->popup.buf;
|
||
|
memory = ctx->memory.memory.ptr;
|
||
|
parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
|
||
|
parent_last->next = buf->end;
|
||
|
}
|
||
|
NK_LIB void
|
||
|
nk_build(struct nk_context *ctx)
|
||
|
{
|
||
|
struct nk_window *it = 0;
|
||
|
struct nk_command *cmd = 0;
|
||
|
nk_byte *buffer = 0;
|
||
|
|
||
|
/* draw cursor overlay */
|
||
|
if (!ctx->style.cursor_active)
|
||
|
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
|
||
|
if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
|
||
|
struct nk_rect mouse_bounds;
|
||
|
const struct nk_cursor *cursor = ctx->style.cursor_active;
|
||
|
nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
|
||
|
nk_start_buffer(ctx, &ctx->overlay);
|
||
|
|
||
|
mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
|
||
|
mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
|
||
|
mouse_bounds.w = cursor->size.x;
|
||
|
mouse_bounds.h = cursor->size.y;
|
||
|
|
||
|
nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
|
||
|
nk_finish_buffer(ctx, &ctx->overlay);
|
||
|
}
|
||
|
/* build one big draw command list out of all window buffers */
|
||
|
it = ctx->begin;
|
||
|
buffer = (nk_byte*)ctx->memory.memory.ptr;
|
||
|
while (it != 0) {
|
||
|
struct nk_window *next = it->next;
|
||
|
if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||
|
||
|
it->seq != ctx->seq)
|
||
|
goto cont;
|
||
|
|
||
|
cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);
|
||
|
while (next && ((next->buffer.last == next->buffer.begin) ||
|
||
|
(next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))
|
||
|
next = next->next; /* skip empty command buffers */
|
||
|
|
||
|
if (next) cmd->next = next->buffer.begin;
|
||
|
cont: it = next;
|
||
|
}
|
||
|
/* append all popup draw commands into lists */
|
||
|
it = ctx->begin;
|
||
|
while (it != 0) {
|
||
|
struct nk_window *next = it->next;
|
||
|
struct nk_popup_buffer *buf;
|
||
|
if (!it->popup.buf.active)
|
||
|
goto skip;
|
||
|
|
||
|
buf = &it->popup.buf;
|
||
|
cmd->next = buf->begin;
|
||
|
cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
|
||
|
buf->active = nk_false;
|
||
|
skip: it = next;
|
||
|
}
|
||
|
if (cmd) {
|
||
|
/* append overlay commands */
|
||
|
if (ctx->overlay.end != ctx->overlay.begin)
|
||
|
cmd->next = ctx->overlay.begin;
|
||
|
else cmd->next = ctx->memory.allocated;
|
||
|
}
|
||
|
}
|
||
|
NK_API const struct nk_command*
|
||
|
nk__begin(struct nk_context *ctx)
|
||
|
{
|
||
|
struct nk_window *iter;
|
||
|
nk_byte *buffer;
|
||
|
NK_ASSERT(ctx);
|
||
|
if (!ctx) return 0;
|
||
|
if (!ctx->count) return 0;
|
||
|
|
||
|
buffer = (nk_byte*)ctx->memory.memory.ptr;
|
||
|
if (!ctx->build) {
|
||
|
nk_build(ctx);
|
||
|
ctx->build = nk_true;
|
||
|
}
|
||
|
iter = ctx->begin;
|
||
|
while (iter && ((iter->buffer.begin == iter->buffer.end) ||
|
||
|
(iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))
|
||
|
iter = iter->next;
|
||
|
if (!iter) return 0;
|
||
|
return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
|
||
|
}
|
||
|
|
||
|
NK_API const struct nk_command*
|
||
|
nk__next(struct nk_context *ctx, const struct nk_command *cmd)
|
||
|
{
|
||
|
nk_byte *buffer;
|
||
|
const struct nk_command *next;
|
||
|
NK_ASSERT(ctx);
|
||
|
if (!ctx || !cmd || !ctx->count) return 0;
|
||
|
if (cmd->next >= ctx->memory.allocated) return 0;
|
||
|
buffer = (nk_byte*)ctx->memory.memory.ptr;
|
||
|
next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
|
||
|
return next;
|
||
|
}
|
||
|
|
||
|
|