nuklear_context.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include "nuklear.h"
  2. #include "nuklear_internal.h"
  3. /* ==============================================================
  4. *
  5. * CONTEXT
  6. *
  7. * ===============================================================*/
  8. NK_INTERN void
  9. nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
  10. {
  11. NK_ASSERT(ctx);
  12. if (!ctx) return;
  13. nk_zero_struct(*ctx);
  14. nk_style_default(ctx);
  15. ctx->seq = 1;
  16. if (font) ctx->style.font = font;
  17. #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
  18. nk_draw_list_init(&ctx->draw_list);
  19. #endif
  20. }
  21. #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
  22. NK_API nk_bool
  23. nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
  24. {
  25. struct nk_allocator alloc;
  26. alloc.userdata.ptr = 0;
  27. alloc.alloc = nk_malloc;
  28. alloc.free = nk_mfree;
  29. return nk_init(ctx, &alloc, font);
  30. }
  31. #endif
  32. NK_API nk_bool
  33. nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
  34. const struct nk_user_font *font)
  35. {
  36. NK_ASSERT(memory);
  37. if (!memory) return 0;
  38. nk_setup(ctx, font);
  39. nk_buffer_init_fixed(&ctx->memory, memory, size);
  40. ctx->use_pool = nk_false;
  41. return 1;
  42. }
  43. NK_API nk_bool
  44. nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
  45. struct nk_buffer *pool, const struct nk_user_font *font)
  46. {
  47. NK_ASSERT(cmds);
  48. NK_ASSERT(pool);
  49. if (!cmds || !pool) return 0;
  50. nk_setup(ctx, font);
  51. ctx->memory = *cmds;
  52. if (pool->type == NK_BUFFER_FIXED) {
  53. /* take memory from buffer and alloc fixed pool */
  54. nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
  55. } else {
  56. /* create dynamic pool from buffer allocator */
  57. struct nk_allocator *alloc = &pool->pool;
  58. nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
  59. }
  60. ctx->use_pool = nk_true;
  61. return 1;
  62. }
  63. NK_API nk_bool
  64. nk_init(struct nk_context *ctx, const struct nk_allocator *alloc,
  65. const struct nk_user_font *font)
  66. {
  67. NK_ASSERT(alloc);
  68. if (!alloc) return 0;
  69. nk_setup(ctx, font);
  70. nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
  71. nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
  72. ctx->use_pool = nk_true;
  73. return 1;
  74. }
  75. #ifdef NK_INCLUDE_COMMAND_USERDATA
  76. NK_API void
  77. nk_set_user_data(struct nk_context *ctx, nk_handle handle)
  78. {
  79. if (!ctx) return;
  80. ctx->userdata = handle;
  81. if (ctx->current)
  82. ctx->current->buffer.userdata = handle;
  83. }
  84. #endif
  85. NK_API void
  86. nk_free(struct nk_context *ctx)
  87. {
  88. NK_ASSERT(ctx);
  89. if (!ctx) return;
  90. nk_buffer_free(&ctx->memory);
  91. if (ctx->use_pool)
  92. nk_pool_free(&ctx->pool);
  93. nk_zero(&ctx->input, sizeof(ctx->input));
  94. nk_zero(&ctx->style, sizeof(ctx->style));
  95. nk_zero(&ctx->memory, sizeof(ctx->memory));
  96. ctx->seq = 0;
  97. ctx->build = 0;
  98. ctx->begin = 0;
  99. ctx->end = 0;
  100. ctx->active = 0;
  101. ctx->current = 0;
  102. ctx->freelist = 0;
  103. ctx->count = 0;
  104. }
  105. NK_API void
  106. nk_clear(struct nk_context *ctx)
  107. {
  108. struct nk_window *iter;
  109. struct nk_window *next;
  110. NK_ASSERT(ctx);
  111. if (!ctx) return;
  112. if (ctx->use_pool)
  113. nk_buffer_clear(&ctx->memory);
  114. else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
  115. ctx->build = 0;
  116. ctx->memory.calls = 0;
  117. ctx->last_widget_state = 0;
  118. ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
  119. NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
  120. /* garbage collector */
  121. iter = ctx->begin;
  122. while (iter) {
  123. /* make sure valid minimized windows do not get removed */
  124. if ((iter->flags & NK_WINDOW_MINIMIZED) &&
  125. !(iter->flags & NK_WINDOW_CLOSED) &&
  126. iter->seq == ctx->seq) {
  127. iter = iter->next;
  128. continue;
  129. }
  130. /* remove hotness from hidden or closed windows*/
  131. if (((iter->flags & NK_WINDOW_HIDDEN) ||
  132. (iter->flags & NK_WINDOW_CLOSED)) &&
  133. iter == ctx->active) {
  134. ctx->active = iter->prev;
  135. ctx->end = iter->prev;
  136. if (!ctx->end)
  137. ctx->begin = 0;
  138. if (ctx->active)
  139. ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
  140. }
  141. /* free unused popup windows */
  142. if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
  143. nk_free_window(ctx, iter->popup.win);
  144. iter->popup.win = 0;
  145. }
  146. /* remove unused window state tables */
  147. {struct nk_table *n, *it = iter->tables;
  148. while (it) {
  149. n = it->next;
  150. if (it->seq != ctx->seq) {
  151. nk_remove_table(iter, it);
  152. nk_zero(it, sizeof(union nk_page_data));
  153. nk_free_table(ctx, it);
  154. if (it == iter->tables)
  155. iter->tables = n;
  156. } it = n;
  157. }}
  158. /* window itself is not used anymore so free */
  159. if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
  160. next = iter->next;
  161. nk_remove_window(ctx, iter);
  162. nk_free_window(ctx, iter);
  163. iter = next;
  164. } else iter = iter->next;
  165. }
  166. ctx->seq++;
  167. }
  168. NK_LIB void
  169. nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
  170. {
  171. NK_ASSERT(ctx);
  172. NK_ASSERT(buffer);
  173. if (!ctx || !buffer) return;
  174. buffer->begin = ctx->memory.allocated;
  175. buffer->end = buffer->begin;
  176. buffer->last = buffer->begin;
  177. buffer->clip = nk_null_rect;
  178. }
  179. NK_LIB void
  180. nk_start(struct nk_context *ctx, struct nk_window *win)
  181. {
  182. NK_ASSERT(ctx);
  183. NK_ASSERT(win);
  184. nk_start_buffer(ctx, &win->buffer);
  185. }
  186. NK_LIB void
  187. nk_start_popup(struct nk_context *ctx, struct nk_window *win)
  188. {
  189. struct nk_popup_buffer *buf;
  190. NK_ASSERT(ctx);
  191. NK_ASSERT(win);
  192. if (!ctx || !win) return;
  193. /* save buffer fill state for popup */
  194. buf = &win->popup.buf;
  195. buf->begin = win->buffer.end;
  196. buf->end = win->buffer.end;
  197. buf->parent = win->buffer.last;
  198. buf->last = buf->begin;
  199. buf->active = nk_true;
  200. }
  201. NK_LIB void
  202. nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
  203. {
  204. struct nk_popup_buffer *buf;
  205. NK_ASSERT(ctx);
  206. NK_ASSERT(win);
  207. if (!ctx || !win) return;
  208. buf = &win->popup.buf;
  209. buf->last = win->buffer.last;
  210. buf->end = win->buffer.end;
  211. }
  212. NK_LIB void
  213. nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
  214. {
  215. NK_ASSERT(ctx);
  216. NK_ASSERT(buffer);
  217. if (!ctx || !buffer) return;
  218. buffer->end = ctx->memory.allocated;
  219. }
  220. NK_LIB void
  221. nk_finish(struct nk_context *ctx, struct nk_window *win)
  222. {
  223. struct nk_popup_buffer *buf;
  224. struct nk_command *parent_last;
  225. void *memory;
  226. NK_ASSERT(ctx);
  227. NK_ASSERT(win);
  228. if (!ctx || !win) return;
  229. nk_finish_buffer(ctx, &win->buffer);
  230. if (!win->popup.buf.active) return;
  231. buf = &win->popup.buf;
  232. memory = ctx->memory.memory.ptr;
  233. parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
  234. parent_last->next = buf->end;
  235. }
  236. NK_LIB void
  237. nk_build(struct nk_context *ctx)
  238. {
  239. struct nk_window *it = 0;
  240. struct nk_command *cmd = 0;
  241. nk_byte *buffer = 0;
  242. /* draw cursor overlay */
  243. if (!ctx->style.cursor_active)
  244. ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
  245. if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
  246. struct nk_rect mouse_bounds;
  247. const struct nk_cursor *cursor = ctx->style.cursor_active;
  248. nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
  249. nk_start_buffer(ctx, &ctx->overlay);
  250. mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
  251. mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
  252. mouse_bounds.w = cursor->size.x;
  253. mouse_bounds.h = cursor->size.y;
  254. nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
  255. nk_finish_buffer(ctx, &ctx->overlay);
  256. }
  257. /* build one big draw command list out of all window buffers */
  258. it = ctx->begin;
  259. buffer = (nk_byte*)ctx->memory.memory.ptr;
  260. while (it != 0) {
  261. struct nk_window *next = it->next;
  262. if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||
  263. it->seq != ctx->seq)
  264. goto cont;
  265. cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);
  266. while (next && ((next->buffer.last == next->buffer.begin) ||
  267. (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))
  268. next = next->next; /* skip empty command buffers */
  269. if (next) cmd->next = next->buffer.begin;
  270. cont: it = next;
  271. }
  272. /* append all popup draw commands into lists */
  273. it = ctx->begin;
  274. while (it != 0) {
  275. struct nk_window *next = it->next;
  276. struct nk_popup_buffer *buf;
  277. if (!it->popup.buf.active)
  278. goto skip;
  279. buf = &it->popup.buf;
  280. cmd->next = buf->begin;
  281. cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
  282. buf->active = nk_false;
  283. skip: it = next;
  284. }
  285. if (cmd) {
  286. /* append overlay commands */
  287. if (ctx->overlay.end != ctx->overlay.begin)
  288. cmd->next = ctx->overlay.begin;
  289. else cmd->next = ctx->memory.allocated;
  290. }
  291. }
  292. NK_API const struct nk_command*
  293. nk__begin(struct nk_context *ctx)
  294. {
  295. struct nk_window *iter;
  296. nk_byte *buffer;
  297. NK_ASSERT(ctx);
  298. if (!ctx) return 0;
  299. if (!ctx->count) return 0;
  300. buffer = (nk_byte*)ctx->memory.memory.ptr;
  301. if (!ctx->build) {
  302. nk_build(ctx);
  303. ctx->build = nk_true;
  304. }
  305. iter = ctx->begin;
  306. while (iter && ((iter->buffer.begin == iter->buffer.end) ||
  307. (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))
  308. iter = iter->next;
  309. if (!iter) return 0;
  310. return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
  311. }
  312. NK_API const struct nk_command*
  313. nk__next(struct nk_context *ctx, const struct nk_command *cmd)
  314. {
  315. nk_byte *buffer;
  316. const struct nk_command *next;
  317. NK_ASSERT(ctx);
  318. if (!ctx || !cmd || !ctx->count) return 0;
  319. if (cmd->next >= ctx->memory.allocated) return 0;
  320. buffer = (nk_byte*)ctx->memory.memory.ptr;
  321. next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
  322. return next;
  323. }