Nuklear
This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.
nuklear_context.c
1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3 
4 /* ==============================================================
5  *
6  * CONTEXT
7  *
8  * ===============================================================*/
9 NK_INTERN void
10 nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
11 {
12  NK_ASSERT(ctx);
13  if (!ctx) return;
14  nk_zero_struct(*ctx);
15  nk_style_default(ctx);
16  ctx->seq = 1;
17  if (font) ctx->style.font = font;
18 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
19  nk_draw_list_init(&ctx->draw_list);
20 #endif
21 }
22 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
23 NK_API nk_bool
24 nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
25 {
26  struct nk_allocator alloc;
27  alloc.userdata.ptr = 0;
28  alloc.alloc = nk_malloc;
29  alloc.free = nk_mfree;
30  return nk_init(ctx, &alloc, font);
31 }
32 #endif
33 NK_API nk_bool
34 nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
35  const struct nk_user_font *font)
36 {
37  NK_ASSERT(memory);
38  if (!memory) return 0;
39  nk_setup(ctx, font);
40  nk_buffer_init_fixed(&ctx->memory, memory, size);
41  ctx->use_pool = nk_false;
42  return 1;
43 }
44 NK_API nk_bool
45 nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
46  struct nk_buffer *pool, const struct nk_user_font *font)
47 {
48  NK_ASSERT(cmds);
49  NK_ASSERT(pool);
50  if (!cmds || !pool) return 0;
51 
52  nk_setup(ctx, font);
53  ctx->memory = *cmds;
54  if (pool->type == NK_BUFFER_FIXED) {
55  /* take memory from buffer and alloc fixed pool */
56  nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
57  } else {
58  /* create dynamic pool from buffer allocator */
59  struct nk_allocator *alloc = &pool->pool;
60  nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
61  }
62  ctx->use_pool = nk_true;
63  return 1;
64 }
65 NK_API nk_bool
66 nk_init(struct nk_context *ctx, const struct nk_allocator *alloc,
67  const struct nk_user_font *font)
68 {
69  NK_ASSERT(alloc);
70  if (!alloc) return 0;
71  nk_setup(ctx, font);
72  nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
73  nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
74  ctx->use_pool = nk_true;
75  return 1;
76 }
77 #ifdef NK_INCLUDE_COMMAND_USERDATA
78 NK_API void
79 nk_set_user_data(struct nk_context *ctx, nk_handle handle)
80 {
81  if (!ctx) return;
82  ctx->userdata = handle;
83  if (ctx->current)
84  ctx->current->buffer.userdata = handle;
85 }
86 #endif
87 NK_API void
88 nk_free(struct nk_context *ctx)
89 {
90  NK_ASSERT(ctx);
91  if (!ctx) return;
92  nk_buffer_free(&ctx->memory);
93  if (ctx->use_pool)
94  nk_pool_free(&ctx->pool);
95 
96  nk_zero(&ctx->input, sizeof(ctx->input));
97  nk_zero(&ctx->style, sizeof(ctx->style));
98  nk_zero(&ctx->memory, sizeof(ctx->memory));
99 
100  ctx->seq = 0;
101  ctx->build = 0;
102  ctx->begin = 0;
103  ctx->end = 0;
104  ctx->active = 0;
105  ctx->current = 0;
106  ctx->freelist = 0;
107  ctx->count = 0;
108 }
109 NK_API void
110 nk_clear(struct nk_context *ctx)
111 {
112  struct nk_window *iter;
113  struct nk_window *next;
114  NK_ASSERT(ctx);
115 
116  if (!ctx) return;
117  if (ctx->use_pool)
118  nk_buffer_clear(&ctx->memory);
119  else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
120 
121  ctx->build = 0;
122  ctx->memory.calls = 0;
123  ctx->last_widget_state = 0;
124  ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
125  NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
126 
127  /* garbage collector */
128  iter = ctx->begin;
129  while (iter) {
130  /* make sure valid minimized windows do not get removed */
131  if ((iter->flags & NK_WINDOW_MINIMIZED) &&
132  !(iter->flags & NK_WINDOW_CLOSED) &&
133  iter->seq == ctx->seq) {
134  iter = iter->next;
135  continue;
136  }
137  /* remove hotness from hidden or closed windows*/
138  if (((iter->flags & NK_WINDOW_HIDDEN) ||
139  (iter->flags & NK_WINDOW_CLOSED)) &&
140  iter == ctx->active) {
141  ctx->active = iter->prev;
142  ctx->end = iter->prev;
143  if (!ctx->end)
144  ctx->begin = 0;
145  if (ctx->active)
146  ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
147  }
148  /* free unused popup windows */
149  if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
150  nk_free_window(ctx, iter->popup.win);
151  iter->popup.win = 0;
152  }
153  /* remove unused window state tables */
154  {struct nk_table *n, *it = iter->tables;
155  while (it) {
156  n = it->next;
157  if (it->seq != ctx->seq) {
158  nk_remove_table(iter, it);
159  nk_zero(it, sizeof(union nk_page_data));
160  nk_free_table(ctx, it);
161  if (it == iter->tables)
162  iter->tables = n;
163  } it = n;
164  }}
165  /* window itself is not used anymore so free */
166  if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
167  next = iter->next;
168  nk_remove_window(ctx, iter);
169  nk_free_window(ctx, iter);
170  iter = next;
171  } else iter = iter->next;
172  }
173  ctx->seq++;
174 }
175 NK_LIB void
176 nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
177 {
178  NK_ASSERT(ctx);
179  NK_ASSERT(buffer);
180  if (!ctx || !buffer) return;
181  buffer->begin = ctx->memory.allocated;
182  buffer->end = buffer->begin;
183  buffer->last = buffer->begin;
184  buffer->clip = nk_null_rect;
185 }
186 NK_LIB void
187 nk_start(struct nk_context *ctx, struct nk_window *win)
188 {
189  NK_ASSERT(ctx);
190  NK_ASSERT(win);
191  nk_start_buffer(ctx, &win->buffer);
192 }
193 NK_LIB void
194 nk_start_popup(struct nk_context *ctx, struct nk_window *win)
195 {
196  struct nk_popup_buffer *buf;
197  NK_ASSERT(ctx);
198  NK_ASSERT(win);
199  if (!ctx || !win) return;
200 
201  /* save buffer fill state for popup */
202  buf = &win->popup.buf;
203  buf->begin = win->buffer.end;
204  buf->end = win->buffer.end;
205  buf->parent = win->buffer.last;
206  buf->last = buf->begin;
207  buf->active = nk_true;
208 }
209 NK_LIB void
210 nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
211 {
212  struct nk_popup_buffer *buf;
213  NK_ASSERT(ctx);
214  NK_ASSERT(win);
215  if (!ctx || !win) return;
216 
217  buf = &win->popup.buf;
218  buf->last = win->buffer.last;
219  buf->end = win->buffer.end;
220 }
221 NK_LIB void
222 nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
223 {
224  NK_ASSERT(ctx);
225  NK_ASSERT(buffer);
226  if (!ctx || !buffer) return;
227  buffer->end = ctx->memory.allocated;
228 }
229 NK_LIB void
230 nk_finish(struct nk_context *ctx, struct nk_window *win)
231 {
232  struct nk_popup_buffer *buf;
233  struct nk_command *parent_last;
234  void *memory;
235 
236  NK_ASSERT(ctx);
237  NK_ASSERT(win);
238  if (!ctx || !win) return;
239  nk_finish_buffer(ctx, &win->buffer);
240  if (!win->popup.buf.active) return;
241 
242  buf = &win->popup.buf;
243  memory = ctx->memory.memory.ptr;
244  parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
245  parent_last->next = buf->end;
246 }
247 NK_LIB void
248 nk_build(struct nk_context *ctx)
249 {
250  struct nk_window *it = 0;
251  struct nk_command *cmd = 0;
252  nk_byte *buffer = 0;
253 
254  /* draw cursor overlay */
255  if (!ctx->style.cursor_active)
256  ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
257  if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
258  struct nk_rect mouse_bounds;
259  const struct nk_cursor *cursor = ctx->style.cursor_active;
260  nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
261  nk_start_buffer(ctx, &ctx->overlay);
262 
263  mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
264  mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
265  mouse_bounds.w = cursor->size.x;
266  mouse_bounds.h = cursor->size.y;
267 
268  nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
269  nk_finish_buffer(ctx, &ctx->overlay);
270  }
271  /* build one big draw command list out of all window buffers */
272  it = ctx->begin;
273  buffer = (nk_byte*)ctx->memory.memory.ptr;
274  while (it != 0) {
275  struct nk_window *next = it->next;
276  if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||
277  it->seq != ctx->seq)
278  goto cont;
279 
280  cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);
281  while (next && ((next->buffer.last == next->buffer.begin) ||
282  (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))
283  next = next->next; /* skip empty command buffers */
284 
285  if (next) cmd->next = next->buffer.begin;
286  cont: it = next;
287  }
288  /* append all popup draw commands into lists */
289  it = ctx->begin;
290  while (it != 0) {
291  struct nk_window *next = it->next;
292  struct nk_popup_buffer *buf;
293  if (!it->popup.buf.active)
294  goto skip;
295 
296  buf = &it->popup.buf;
297  cmd->next = buf->begin;
298  cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
299  buf->active = nk_false;
300  skip: it = next;
301  }
302  if (cmd) {
303  /* append overlay commands */
304  if (ctx->overlay.end != ctx->overlay.begin)
305  cmd->next = ctx->overlay.begin;
306  else cmd->next = ctx->memory.allocated;
307  }
308 }
309 NK_API const struct nk_command*
310 nk__begin(struct nk_context *ctx)
311 {
312  struct nk_window *iter;
313  nk_byte *buffer;
314  NK_ASSERT(ctx);
315  if (!ctx) return 0;
316  if (!ctx->count) return 0;
317 
318  buffer = (nk_byte*)ctx->memory.memory.ptr;
319  if (!ctx->build) {
320  nk_build(ctx);
321  ctx->build = nk_true;
322  }
323  iter = ctx->begin;
324  while (iter && ((iter->buffer.begin == iter->buffer.end) ||
325  (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))
326  iter = iter->next;
327  if (!iter) return 0;
328  return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
329 }
330 
331 NK_API const struct nk_command*
332 nk__next(struct nk_context *ctx, const struct nk_command *cmd)
333 {
334  nk_byte *buffer;
335  const struct nk_command *next;
336  NK_ASSERT(ctx);
337  if (!ctx || !cmd || !ctx->count) return 0;
338  if (cmd->next >= ctx->memory.allocated) return 0;
339  buffer = (nk_byte*)ctx->memory.memory.ptr;
340  next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
341  return next;
342 }
343 
344 
main API and documentation file
NK_API void nk_free(struct nk_context *)
Frees all memory allocated by nuklear; Not needed if context was initialized with nk_init_fixed.
NK_API nk_bool nk_init_fixed(struct nk_context *, void *memory, nk_size size, const struct nk_user_font *)
@ NK_WINDOW_CLOSED
Directly closes and frees the window at the end of the frame.
Definition: nuklear.h:5495
@ NK_WINDOW_MINIMIZED
marks the window as minimized
Definition: nuklear.h:5496
@ NK_WINDOW_HIDDEN
Hides window and stops any window interaction and drawing.
Definition: nuklear.h:5494
@ NK_WINDOW_ROM
sets window widgets into a read only mode and does not allow input changes
Definition: nuklear.h:5492
NK_API void nk_draw_image(struct nk_command_buffer *, struct nk_rect, const struct nk_image *, struct nk_color)
misc
Definition: nuklear_draw.c:395
NK_API nk_bool nk_init_custom(struct nk_context *, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *)
Initializes a nk_context struct from two different either fixed or growing buffers.
NK_API const struct nk_command * nk__begin(struct nk_context *)
Returns a draw command list iterator to iterate all draw commands accumulated over one frame.
NK_API nk_bool nk_init(struct nk_context *, const struct nk_allocator *, const struct nk_user_font *)
NK_API const struct nk_command * nk__next(struct nk_context *, const struct nk_command *)
Returns draw command pointer pointing to the next command inside the draw command list.
NK_API void nk_clear(struct nk_context *)
Resets the context state at the end of the frame.
struct nk_allocator pool
!< buffer marker to free a buffer to a certain offset
Definition: nuklear.h:4191
struct nk_memory memory
!< memory management type
Definition: nuklear.h:4193
enum nk_allocation_type type
!< allocator callback for dynamic buffers
Definition: nuklear.h:4192
nk_size allocated
!< growing factor for dynamic memory management
Definition: nuklear.h:4195
nk_size calls
!< totally consumed memory given that enough memory is present
Definition: nuklear.h:4197
command base and header of every command inside the buffer
Definition: nuklear.h:4467
int build
windows
Definition: nuklear.h:5733
struct nk_command_buffer overlay
draw buffer used for overlay drawing operation like cursor
Definition: nuklear.h:5730