comparison nuklear_ui/nuklear.h @ 1474:c5c022c7aa54 nuklear_ui

Initial work on Nuklear-based UI
author Michael Pavone <pavone@retrodev.com>
date Tue, 21 Nov 2017 19:07:43 -0800
parents
children 5d10b8494b02 13abdc98379e
comparison
equal deleted inserted replaced
1473:152a60c6787e 1474:c5c022c7aa54
1 /*
2 Nuklear - 2.00.0 - public domain
3 no warranty implied; use at your own risk.
4 authored from 2015-2017 by Micha Mettke
5
6 ABOUT:
7 This is a minimal state graphical user interface single header toolkit
8 written in ANSI C and licensed under public domain.
9 It was designed as a simple embeddable user interface for application and does
10 not have any dependencies, a default renderbackend or OS window and input handling
11 but instead provides a very modular library approach by using simple input state
12 for input and draw commands describing primitive shapes as output.
13 So instead of providing a layered library that tries to abstract over a number
14 of platform and render backends it only focuses on the actual UI.
15
16 VALUES:
17 - Graphical user interface toolkit
18 - Single header library
19 - Written in C89 (a.k.a. ANSI C or ISO C90)
20 - Small codebase (~18kLOC)
21 - Focus on portability, efficiency and simplicity
22 - No dependencies (not even the standard library if not wanted)
23 - Fully skinnable and customizable
24 - Low memory footprint with total memory control if needed or wanted
25 - UTF-8 support
26 - No global or hidden state
27 - Customizable library modules (you can compile and use only what you need)
28 - Optional font baker and vertex buffer output
29
30 USAGE:
31 This library is self contained in one single header file and can be used either
32 in header only mode or in implementation mode. The header only mode is used
33 by default when included and allows including this header in other headers
34 and does not contain the actual implementation.
35
36 The implementation mode requires to define the preprocessor macro
37 NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.:
38
39 #define NK_IMPLEMENTATION
40 #include "nuklear.h"
41
42 Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
43 below in header and implementation mode if you want to use additional functionality
44 or need more control over the library.
45 IMPORTANT: Every time you include "nuklear.h" you have to define the same flags.
46 This is very important not doing it either leads to compiler errors
47 or even worse stack corruptions.
48
49 FEATURES:
50 - Absolutely no platform dependent code
51 - Memory management control ranging from/to
52 - Ease of use by allocating everything from standard library
53 - Control every byte of memory inside the library
54 - Font handling control ranging from/to
55 - Use your own font implementation for everything
56 - Use this libraries internal font baking and handling API
57 - Drawing output control ranging from/to
58 - Simple shapes for more high level APIs which already have drawing capabilities
59 - Hardware accessible anti-aliased vertex buffer output
60 - Customizable colors and properties ranging from/to
61 - Simple changes to color by filling a simple color table
62 - Complete control with ability to use skinning to decorate widgets
63 - Bendable UI library with widget ranging from/to
64 - Basic widgets like buttons, checkboxes, slider, ...
65 - Advanced widget like abstract comboboxes, contextual menus,...
66 - Compile time configuration to only compile what you need
67 - Subset which can be used if you do not want to link or use the standard library
68 - Can be easily modified to only update on user input instead of frame updates
69
70 OPTIONAL DEFINES:
71 NK_PRIVATE
72 If defined declares all functions as static, so they can only be accessed
73 inside the file that contains the implementation
74
75 NK_INCLUDE_FIXED_TYPES
76 If defined it will include header <stdint.h> for fixed sized types
77 otherwise nuklear tries to select the correct type. If that fails it will
78 throw a compiler error and you have to select the correct types yourself.
79 <!> If used needs to be defined for implementation and header <!>
80
81 NK_INCLUDE_DEFAULT_ALLOCATOR
82 if defined it will include header <stdlib.h> and provide additional functions
83 to use this library without caring for memory allocation control and therefore
84 ease memory management.
85 <!> Adds the standard library with malloc and free so don't define if you
86 don't want to link to the standard library <!>
87 <!> If used needs to be defined for implementation and header <!>
88
89 NK_INCLUDE_STANDARD_IO
90 if defined it will include header <stdio.h> and provide
91 additional functions depending on file loading.
92 <!> Adds the standard library with fopen, fclose,... so don't define this
93 if you don't want to link to the standard library <!>
94 <!> If used needs to be defined for implementation and header <!>
95
96 NK_INCLUDE_STANDARD_VARARGS
97 if defined it will include header <stdarg.h> and provide
98 additional functions depending on variable arguments
99 <!> Adds the standard library with va_list and so don't define this if
100 you don't want to link to the standard library<!>
101 <!> If used needs to be defined for implementation and header <!>
102
103 NK_INCLUDE_VERTEX_BUFFER_OUTPUT
104 Defining this adds a vertex draw command list backend to this
105 library, which allows you to convert queue commands into vertex draw commands.
106 This is mainly if you need a hardware accessible format for OpenGL, DirectX,
107 Vulkan, Metal,...
108 <!> If used needs to be defined for implementation and header <!>
109
110 NK_INCLUDE_FONT_BAKING
111 Defining this adds `stb_truetype` and `stb_rect_pack` implementation
112 to this library and provides font baking and rendering.
113 If you already have font handling or do not want to use this font handler
114 you don't have to define it.
115 <!> If used needs to be defined for implementation and header <!>
116
117 NK_INCLUDE_DEFAULT_FONT
118 Defining this adds the default font: ProggyClean.ttf into this library
119 which can be loaded into a font atlas and allows using this library without
120 having a truetype font
121 <!> Enabling this adds ~12kb to global stack memory <!>
122 <!> If used needs to be defined for implementation and header <!>
123
124 NK_INCLUDE_COMMAND_USERDATA
125 Defining this adds a userdata pointer into each command. Can be useful for
126 example if you want to provide custom shaders depending on the used widget.
127 Can be combined with the style structures.
128 <!> If used needs to be defined for implementation and header <!>
129
130 NK_BUTTON_TRIGGER_ON_RELEASE
131 Different platforms require button clicks occurring either on buttons being
132 pressed (up to down) or released (down to up).
133 By default this library will react on buttons being pressed, but if you
134 define this it will only trigger if a button is released.
135 <!> If used it is only required to be defined for the implementation part <!>
136
137 NK_ZERO_COMMAND_MEMORY
138 Defining this will zero out memory for each drawing command added to a
139 drawing queue (inside nk_command_buffer_push). Zeroing command memory
140 is very useful for fast checking (using memcmp) if command buffers are
141 equal and avoid drawing frames when nothing on screen has changed since
142 previous frame.
143
144 NK_ASSERT
145 If you don't define this, nuklear will use <assert.h> with assert().
146 <!> Adds the standard library so define to nothing of not wanted <!>
147 <!> If used needs to be defined for implementation and header <!>
148
149 NK_BUFFER_DEFAULT_INITIAL_SIZE
150 Initial buffer size allocated by all buffers while using the default allocator
151 functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't
152 want to allocate the default 4k memory then redefine it.
153 <!> If used needs to be defined for implementation and header <!>
154
155 NK_MAX_NUMBER_BUFFER
156 Maximum buffer size for the conversion buffer between float and string
157 Under normal circumstances this should be more than sufficient.
158 <!> If used needs to be defined for implementation and header <!>
159
160 NK_INPUT_MAX
161 Defines the max number of bytes which can be added as text input in one frame.
162 Under normal circumstances this should be more than sufficient.
163 <!> If used it is only required to be defined for the implementation part <!>
164
165 NK_MEMSET
166 You can define this to 'memset' or your own memset implementation
167 replacement. If not nuklear will use its own version.
168 <!> If used it is only required to be defined for the implementation part <!>
169
170 NK_MEMCPY
171 You can define this to 'memcpy' or your own memcpy implementation
172 replacement. If not nuklear will use its own version.
173 <!> If used it is only required to be defined for the implementation part <!>
174
175 NK_SQRT
176 You can define this to 'sqrt' or your own sqrt implementation
177 replacement. If not nuklear will use its own slow and not highly
178 accurate version.
179 <!> If used it is only required to be defined for the implementation part <!>
180
181 NK_SIN
182 You can define this to 'sinf' or your own sine implementation
183 replacement. If not nuklear will use its own approximation implementation.
184 <!> If used it is only required to be defined for the implementation part <!>
185
186 NK_COS
187 You can define this to 'cosf' or your own cosine implementation
188 replacement. If not nuklear will use its own approximation implementation.
189 <!> If used it is only required to be defined for the implementation part <!>
190
191 NK_STRTOD
192 You can define this to `strtod` or your own string to double conversion
193 implementation replacement. If not defined nuklear will use its own
194 imprecise and possibly unsafe version (does not handle nan or infinity!).
195 <!> If used it is only required to be defined for the implementation part <!>
196
197 NK_DTOA
198 You can define this to `dtoa` or your own double to string conversion
199 implementation replacement. If not defined nuklear will use its own
200 imprecise and possibly unsafe version (does not handle nan or infinity!).
201 <!> If used it is only required to be defined for the implementation part <!>
202
203 NK_VSNPRINTF
204 If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO`
205 and want to be safe define this to `vsnprintf` on compilers supporting
206 later versions of C or C++. By default nuklear will check for your stdlib version
207 in C as well as compiler version in C++. if `vsnprintf` is available
208 it will define it to `vsnprintf` directly. If not defined and if you have
209 older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
210 <!> If used it is only required to be defined for the implementation part <!>
211
212 NK_BYTE
213 NK_INT16
214 NK_UINT16
215 NK_INT32
216 NK_UINT32
217 NK_SIZE_TYPE
218 NK_POINTER_TYPE
219 If you compile without NK_USE_FIXED_TYPE then a number of standard types
220 will be selected and compile time validated. If they are incorrect you can
221 define the correct types by overloading these type defines.
222
223 CREDITS:
224 Developed by Micha Mettke and every direct or indirect contributor.
225
226 Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain)
227 Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
228
229 Big thank you to Omar Cornut (ocornut@github) for his imgui library and
230 giving me the inspiration for this library, Casey Muratori for handmade hero
231 and his original immediate mode graphical user interface idea and Sean
232 Barret for his amazing single header libraries which restored my faith
233 in libraries and brought me to create some of my own.
234
235 LICENSE:
236 This software is dual-licensed to the public domain and under the following
237 license: you are granted a perpetual, irrevocable license to copy, modify,
238 publish and distribute this file as you see fit.
239 */
240 #ifndef NK_NUKLEAR_H_
241 #define NK_NUKLEAR_H_
242
243 #ifdef __cplusplus
244 extern "C" {
245 #endif
246 /*
247 * ==============================================================
248 *
249 * CONSTANTS
250 *
251 * ===============================================================
252 */
253 #define NK_UNDEFINED (-1.0f)
254 #define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */
255 #define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/
256 #ifndef NK_INPUT_MAX
257 #define NK_INPUT_MAX 16
258 #endif
259 #ifndef NK_MAX_NUMBER_BUFFER
260 #define NK_MAX_NUMBER_BUFFER 64
261 #endif
262 #ifndef NK_SCROLLBAR_HIDING_TIMEOUT
263 #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f
264 #endif
265 /*
266 * ==============================================================
267 *
268 * HELPER
269 *
270 * ===============================================================
271 */
272 #ifndef NK_API
273 #ifdef NK_PRIVATE
274 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L))
275 #define NK_API static inline
276 #elif defined(__cplusplus)
277 #define NK_API static inline
278 #else
279 #define NK_API static
280 #endif
281 #else
282 #define NK_API extern
283 #endif
284 #endif
285
286 #define NK_INTERN static
287 #define NK_STORAGE static
288 #define NK_GLOBAL static
289
290 #define NK_FLAG(x) (1 << (x))
291 #define NK_STRINGIFY(x) #x
292 #define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x)
293 #define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2
294 #define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2)
295 #define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2)
296
297 #ifdef _MSC_VER
298 #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__)
299 #else
300 #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__)
301 #endif
302
303 #ifndef NK_STATIC_ASSERT
304 #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1]
305 #endif
306
307 #ifndef NK_FILE_LINE
308 #ifdef _MSC_VER
309 #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__)
310 #else
311 #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__)
312 #endif
313 #endif
314
315 #define NK_MIN(a,b) ((a) < (b) ? (a) : (b))
316 #define NK_MAX(a,b) ((a) < (b) ? (b) : (a))
317 #define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i))
318 /*
319 * ===============================================================
320 *
321 * BASIC
322 *
323 * ===============================================================
324 */
325 #ifdef NK_INCLUDE_FIXED_TYPES
326 #include <stdint.h>
327 #define NK_INT8 int8_t
328 #define NK_UINT8 uint8_t
329 #define NK_INT16 int16_t
330 #define NK_UINT16 uint16_t
331 #define NK_INT32 int32_t
332 #define NK_UINT32 uint32_t
333 #define NK_SIZE_TYPE uintptr_t
334 #define NK_POINTER_TYPE uintptr_t
335 #else
336 #ifndef NK_INT8
337 #define NK_INT8 char
338 #endif
339 #ifndef NK_UINT8
340 #define NK_UINT8 unsigned char
341 #endif
342 #ifndef NK_INT16
343 #define NK_INT16 signed short
344 #endif
345 #ifndef NK_UINT16
346 #define NK_UINT16 unsigned short
347 #endif
348 #ifndef NK_INT32
349 #if defined(_MSC_VER)
350 #define NK_INT32 __int32
351 #else
352 #define NK_INT32 signed int
353 #endif
354 #endif
355 #ifndef NK_UINT32
356 #if defined(_MSC_VER)
357 #define NK_UINT32 unsigned __int32
358 #else
359 #define NK_UINT32 unsigned int
360 #endif
361 #endif
362 #ifndef NK_SIZE_TYPE
363 #if defined(_WIN64) && defined(_MSC_VER)
364 #define NK_SIZE_TYPE unsigned __int64
365 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
366 #define NK_SIZE_TYPE unsigned __int32
367 #elif defined(__GNUC__) || defined(__clang__)
368 #if defined(__x86_64__) || defined(__ppc64__)
369 #define NK_SIZE_TYPE unsigned long
370 #else
371 #define NK_SIZE_TYPE unsigned int
372 #endif
373 #else
374 #define NK_SIZE_TYPE unsigned long
375 #endif
376 #endif
377 #ifndef NK_POINTER_TYPE
378 #if defined(_WIN64) && defined(_MSC_VER)
379 #define NK_POINTER_TYPE unsigned __int64
380 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
381 #define NK_POINTER_TYPE unsigned __int32
382 #elif defined(__GNUC__) || defined(__clang__)
383 #if defined(__x86_64__) || defined(__ppc64__)
384 #define NK_POINTER_TYPE unsigned long
385 #else
386 #define NK_POINTER_TYPE unsigned int
387 #endif
388 #else
389 #define NK_POINTER_TYPE unsigned long
390 #endif
391 #endif
392 #endif
393
394 typedef NK_INT8 nk_char;
395 typedef NK_UINT8 nk_uchar;
396 typedef NK_UINT8 nk_byte;
397 typedef NK_INT16 nk_short;
398 typedef NK_UINT16 nk_ushort;
399 typedef NK_INT32 nk_int;
400 typedef NK_UINT32 nk_uint;
401 typedef NK_SIZE_TYPE nk_size;
402 typedef NK_POINTER_TYPE nk_ptr;
403
404 typedef nk_uint nk_hash;
405 typedef nk_uint nk_flags;
406 typedef nk_uint nk_rune;
407
408 /* Make sure correct type size:
409 * This will fire with a negative subscript error if the type sizes
410 * are set incorrectly by the compiler, and compile out if not */
411 NK_STATIC_ASSERT(sizeof(nk_short) == 2);
412 NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
413 NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
414 NK_STATIC_ASSERT(sizeof(nk_int) == 4);
415 NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
416 NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
417 NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
418 NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
419 NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*));
420
421 /* ============================================================================
422 *
423 * API
424 *
425 * =========================================================================== */
426 struct nk_buffer;
427 struct nk_allocator;
428 struct nk_command_buffer;
429 struct nk_draw_command;
430 struct nk_convert_config;
431 struct nk_style_item;
432 struct nk_text_edit;
433 struct nk_draw_list;
434 struct nk_user_font;
435 struct nk_panel;
436 struct nk_context;
437 struct nk_draw_vertex_layout_element;
438 struct nk_style_button;
439 struct nk_style_toggle;
440 struct nk_style_selectable;
441 struct nk_style_slide;
442 struct nk_style_progress;
443 struct nk_style_scrollbar;
444 struct nk_style_edit;
445 struct nk_style_property;
446 struct nk_style_chart;
447 struct nk_style_combo;
448 struct nk_style_tab;
449 struct nk_style_window_header;
450 struct nk_style_window;
451
452 enum {nk_false, nk_true};
453 struct nk_color {nk_byte r,g,b,a;};
454 struct nk_colorf {float r,g,b,a;};
455 struct nk_vec2 {float x,y;};
456 struct nk_vec2i {short x, y;};
457 struct nk_rect {float x,y,w,h;};
458 struct nk_recti {short x,y,w,h;};
459 typedef char nk_glyph[NK_UTF_SIZE];
460 typedef union {void *ptr; int id;} nk_handle;
461 struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];};
462 struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};
463 struct nk_scroll {nk_uint x, y;};
464
465 enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT};
466 enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER};
467 enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true};
468 enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL};
469 enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true};
470 enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true};
471 enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX};
472 enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02};
473 enum nk_color_format {NK_RGB, NK_RGBA};
474 enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};
475 enum nk_layout_format {NK_DYNAMIC, NK_STATIC};
476 enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB};
477
478 typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);
479 typedef void (*nk_plugin_free)(nk_handle, void *old);
480 typedef int(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);
481 typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*);
482 typedef void(*nk_plugin_copy)(nk_handle, const char*, int len);
483
484 struct nk_allocator {
485 nk_handle userdata;
486 nk_plugin_alloc alloc;
487 nk_plugin_free free;
488 };
489 enum nk_symbol_type {
490 NK_SYMBOL_NONE,
491 NK_SYMBOL_X,
492 NK_SYMBOL_UNDERSCORE,
493 NK_SYMBOL_CIRCLE_SOLID,
494 NK_SYMBOL_CIRCLE_OUTLINE,
495 NK_SYMBOL_RECT_SOLID,
496 NK_SYMBOL_RECT_OUTLINE,
497 NK_SYMBOL_TRIANGLE_UP,
498 NK_SYMBOL_TRIANGLE_DOWN,
499 NK_SYMBOL_TRIANGLE_LEFT,
500 NK_SYMBOL_TRIANGLE_RIGHT,
501 NK_SYMBOL_PLUS,
502 NK_SYMBOL_MINUS,
503 NK_SYMBOL_MAX
504 };
505 /* =============================================================================
506 *
507 * CONTEXT
508 *
509 * =============================================================================*/
510 /* Contexts are the main entry point and the majestro of nuklear and contain all required state.
511 * They are used for window, memory, input, style, stack, commands and time management and need
512 * to be passed into all nuklear GUI specific functions.
513 *
514 * Usage
515 * -------------------
516 * To use a context it first has to be initialized which can be achieved by calling
517 * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`.
518 * Each takes in a font handle and a specific way of handling memory. Memory control
519 * hereby ranges from standard library to just specifying a fixed sized block of memory
520 * which nuklear has to manage itself from.
521 *
522 * struct nk_context ctx;
523 * nk_init_xxx(&ctx, ...);
524 * while (1) {
525 * [...]
526 * nk_clear(&ctx);
527 * }
528 * nk_free(&ctx);
529 *
530 * Reference
531 * -------------------
532 * nk_init_default - Initializes context with standard library memory allocation (malloc,free)
533 * nk_init_fixed - Initializes context from single fixed size memory block
534 * nk_init - Initializes context with memory allocator callbacks for alloc and free
535 * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations
536 * nk_clear - Called at the end of the frame to reset and prepare the context for the next frame
537 * nk_free - Shutdown and free all memory allocated inside the context
538 * nk_set_user_data - Utility function to pass user data to draw command
539 */
540 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
541 /* nk_init_default - Initializes a `nk_context` struct with a default standard library allocator.
542 * Should be used if you don't want to be bothered with memory management in nuklear.
543 * Parameters:
544 * @ctx must point to an either stack or heap allocated `nk_context` struct
545 * @font must point to a previously initialized font handle for more info look at font documentation
546 * Return values:
547 * true(1) on success
548 * false(0) on failure */
549 NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*);
550 #endif
551 /* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block
552 * Should be used if you want complete control over nuklear's memory management.
553 * Especially recommended for system with little memory or systems with virtual memory.
554 * For the later case you can just allocate for example 16MB of virtual memory
555 * and only the required amount of memory will actually be committed.
556 * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands`
557 * Parameters:
558 * @ctx must point to an either stack or heap allocated `nk_context` struct
559 * @memory must point to a previously allocated memory block
560 * @size must contain the total size of @memory
561 * @font must point to a previously initialized font handle for more info look at font documentation
562 * Return values:
563 * true(1) on success
564 * false(0) on failure */
565 NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*);
566 /* nk_init - Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate
567 * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation
568 * interface to nuklear. Can be useful for cases like monitoring memory consumption.
569 * Parameters:
570 * @ctx must point to an either stack or heap allocated `nk_context` struct
571 * @alloc must point to a previously allocated memory allocator
572 * @font must point to a previously initialized font handle for more info look at font documentation
573 * Return values:
574 * true(1) on success
575 * false(0) on failure */
576 NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*);
577 /* nk_init_custom - Initializes a `nk_context` struct from two different either fixed or growing
578 * buffers. The first buffer is for allocating draw commands while the second buffer is
579 * used for allocating windows, panels and state tables.
580 * Parameters:
581 * @ctx must point to an either stack or heap allocated `nk_context` struct
582 * @cmds must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into
583 * @pool must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables
584 * @font must point to a previously initialized font handle for more info look at font documentation
585 * Return values:
586 * true(1) on success
587 * false(0) on failure */
588 NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*);
589 /* nk_clear - Resets the context state at the end of the frame. This includes mostly
590 * garbage collector tasks like removing windows or table not called and therefore
591 * used anymore.
592 * Parameters:
593 * @ctx must point to a previously initialized `nk_context` struct */
594 NK_API void nk_clear(struct nk_context*);
595 /* nk_free - Frees all memory allocated by nuklear. Not needed if context was
596 * initialized with `nk_init_fixed`.
597 * Parameters:
598 * @ctx must point to a previously initialized `nk_context` struct */
599 NK_API void nk_free(struct nk_context*);
600 #ifdef NK_INCLUDE_COMMAND_USERDATA
601 /* nk_set_user_data - Sets the currently passed userdata passed down into each draw command.
602 * Parameters:
603 * @ctx must point to a previously initialized `nk_context` struct
604 * @data handle with either pointer or index to be passed into every draw commands */
605 NK_API void nk_set_user_data(struct nk_context*, nk_handle handle);
606 #endif
607 /* =============================================================================
608 *
609 * INPUT
610 *
611 * =============================================================================*/
612 /* The input API is responsible for holding the current input state composed of
613 * mouse, key and text input states.
614 * It is worth noting that no direct os or window handling is done in nuklear.
615 * Instead all input state has to be provided by platform specific code. This in one hand
616 * expects more work from the user and complicates usage but on the other hand
617 * provides simple abstraction over a big number of platforms, libraries and other
618 * already provided functionality.
619 *
620 * Usage
621 * -------------------
622 * Input state needs to be provided to nuklear by first calling `nk_input_begin`
623 * which resets internal state like delta mouse position and button transistions.
624 * After `nk_input_begin` all current input state needs to be provided. This includes
625 * mouse motion, button and key pressed and released, text input and scrolling.
626 * Both event- or state-based input handling are supported by this API
627 * and should work without problems. Finally after all input state has been
628 * mirrored `nk_input_end` needs to be called to finish input process.
629 *
630 * struct nk_context ctx;
631 * nk_init_xxx(&ctx, ...);
632 * while (1) {
633 * Event evt;
634 * nk_input_begin(&ctx);
635 * while (GetEvent(&evt)) {
636 * if (evt.type == MOUSE_MOVE)
637 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
638 * else if (evt.type == ...) {
639 * ...
640 * }
641 * }
642 * nk_input_end(&ctx);
643 * [...]
644 * nk_clear(&ctx);
645 * }
646 * nk_free(&ctx);
647 *
648 * Reference
649 * -------------------
650 * nk_input_begin - Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls
651 * nk_input_motion - Mirrors mouse cursor position
652 * nk_input_key - Mirrors key state with either pressed or released
653 * nk_input_button - Mirrors mouse button state with either pressed or released
654 * nk_input_scroll - Mirrors mouse scroll values
655 * nk_input_char - Adds a single ASCII text character into an internal text buffer
656 * nk_input_glyph - Adds a single multi-byte UTF-8 character into an internal text buffer
657 * nk_input_unicode - Adds a single unicode rune into an internal text buffer
658 * nk_input_end - Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call
659 */
660 enum nk_keys {
661 NK_KEY_NONE,
662 NK_KEY_SHIFT,
663 NK_KEY_CTRL,
664 NK_KEY_DEL,
665 NK_KEY_ENTER,
666 NK_KEY_TAB,
667 NK_KEY_BACKSPACE,
668 NK_KEY_COPY,
669 NK_KEY_CUT,
670 NK_KEY_PASTE,
671 NK_KEY_UP,
672 NK_KEY_DOWN,
673 NK_KEY_LEFT,
674 NK_KEY_RIGHT,
675 /* Shortcuts: text field */
676 NK_KEY_TEXT_INSERT_MODE,
677 NK_KEY_TEXT_REPLACE_MODE,
678 NK_KEY_TEXT_RESET_MODE,
679 NK_KEY_TEXT_LINE_START,
680 NK_KEY_TEXT_LINE_END,
681 NK_KEY_TEXT_START,
682 NK_KEY_TEXT_END,
683 NK_KEY_TEXT_UNDO,
684 NK_KEY_TEXT_REDO,
685 NK_KEY_TEXT_SELECT_ALL,
686 NK_KEY_TEXT_WORD_LEFT,
687 NK_KEY_TEXT_WORD_RIGHT,
688 /* Shortcuts: scrollbar */
689 NK_KEY_SCROLL_START,
690 NK_KEY_SCROLL_END,
691 NK_KEY_SCROLL_DOWN,
692 NK_KEY_SCROLL_UP,
693 NK_KEY_MAX
694 };
695 enum nk_buttons {
696 NK_BUTTON_LEFT,
697 NK_BUTTON_MIDDLE,
698 NK_BUTTON_RIGHT,
699 NK_BUTTON_DOUBLE,
700 NK_BUTTON_MAX
701 };
702 /* nk_input_begin - Begins the input mirroring process by resetting text, scroll
703 * mouse previous mouse position and movement as well as key state transitions,
704 * Parameters:
705 * @ctx must point to an previously initialized `nk_context` struct */
706 NK_API void nk_input_begin(struct nk_context*);
707 /* nk_input_motion - Mirrors current mouse position to nuklear
708 * Parameters:
709 * @ctx must point to an previously initialized `nk_context` struct
710 * @x must contain an integer describing the current mouse cursor x-position
711 * @y must contain an integer describing the current mouse cursor y-position */
712 NK_API void nk_input_motion(struct nk_context*, int x, int y);
713 /* nk_input_key - Mirrors state of a specific key to nuklear
714 * Parameters:
715 * @ctx must point to an previously initialized `nk_context` struct
716 * @key must be any value specified in enum `nk_keys` that needs to be mirrored
717 * @down must be 0 for key is up and 1 for key is down */
718 NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down);
719 /* nk_input_button - Mirrors the state of a specific mouse button to nuklear
720 * Parameters:
721 * @ctx must point to an previously initialized `nk_context` struct
722 * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored
723 * @x must contain an integer describing mouse cursor x-position on click up/down
724 * @y must contain an integer describing mouse cursor y-position on click up/down
725 * @down must be 0 for key is up and 1 for key is down */
726 NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down);
727 /* nk_input_scroll - Copies the last mouse scroll value to nuklear. Is generally
728 * a scroll value. So does not have to come from mouse and could also originate
729 * from touch for example.
730 * Parameters:
731 * @ctx must point to an previously initialized `nk_context` struct
732 * @val vector with both X- as well as Y-scroll value */
733 NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val);
734 /* nk_input_char - Copies a single ASCII character into an internal text buffer
735 * This is basically a helper function to quickly push ASCII characters into
736 * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into
737 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
738 * Parameters:
739 * @ctx must point to an previously initialized `nk_context` struct
740 * @c must be a single ASCII character preferable one that can be printed */
741 NK_API void nk_input_char(struct nk_context*, char);
742 /* nk_input_unicode - Converts a encoded unicode rune into UTF-8 and copies the result
743 * into an internal text buffer.
744 * Note that you can only push up to NK_INPUT_MAX bytes into
745 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
746 * Parameters:
747 * @ctx must point to an previously initialized `nk_context` struct
748 * @glyph UTF-32 unicode codepoint */
749 NK_API void nk_input_glyph(struct nk_context*, const nk_glyph);
750 /* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result
751 * into an internal text buffer.
752 * Note that you can only push up to NK_INPUT_MAX bytes into
753 * struct `nk_input` between `nk_input_begin` and `nk_input_end`.
754 * Parameters:
755 * @ctx must point to an previously initialized `nk_context` struct
756 * @glyph UTF-32 unicode codepoint */
757 NK_API void nk_input_unicode(struct nk_context*, nk_rune);
758 /* nk_input_end - End the input mirroring process by resetting mouse grabbing
759 * state to ensure the mouse cursor is not grabbed indefinitely.
760 * Parameters:
761 * @ctx must point to an previously initialized `nk_context` struct */
762 NK_API void nk_input_end(struct nk_context*);
763 /* =============================================================================
764 *
765 * DRAWING
766 *
767 * =============================================================================*/
768 /* This library was designed to be render backend agnostic so it does
769 * not draw anything to screen directly. Instead all drawn shapes, widgets
770 * are made of, are buffered into memory and make up a command queue.
771 * Each frame therefore fills the command buffer with draw commands
772 * that then need to be executed by the user and his own render backend.
773 * After that the command buffer needs to be cleared and a new frame can be
774 * started. It is probably important to note that the command buffer is the main
775 * drawing API and the optional vertex buffer API only takes this format and
776 * converts it into a hardware accessible format.
777 *
778 * Usage
779 * -------------------
780 * To draw all draw commands accumulated over a frame you need your own render
781 * backend able to draw a number of 2D primitives. This includes at least
782 * filled and stroked rectangles, circles, text, lines, triangles and scissors.
783 * As soon as this criterion is met you can iterate over each draw command
784 * and execute each draw command in a interpreter like fashion:
785 *
786 * const struct nk_command *cmd = 0;
787 * nk_foreach(cmd, &ctx) {
788 * switch (cmd->type) {
789 * case NK_COMMAND_LINE:
790 * your_draw_line_function(...)
791 * break;
792 * case NK_COMMAND_RECT
793 * your_draw_rect_function(...)
794 * break;
795 * case ...:
796 * [...]
797 * }
798 *
799 * In program flow context draw commands need to be executed after input has been
800 * gathered and the complete UI with windows and their contained widgets have
801 * been executed and before calling `nk_clear` which frees all previously
802 * allocated draw commands.
803 *
804 * struct nk_context ctx;
805 * nk_init_xxx(&ctx, ...);
806 * while (1) {
807 * Event evt;
808 * nk_input_begin(&ctx);
809 * while (GetEvent(&evt)) {
810 * if (evt.type == MOUSE_MOVE)
811 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
812 * else if (evt.type == [...]) {
813 * [...]
814 * }
815 * }
816 * nk_input_end(&ctx);
817 *
818 * [...]
819 *
820 * const struct nk_command *cmd = 0;
821 * nk_foreach(cmd, &ctx) {
822 * switch (cmd->type) {
823 * case NK_COMMAND_LINE:
824 * your_draw_line_function(...)
825 * break;
826 * case NK_COMMAND_RECT
827 * your_draw_rect_function(...)
828 * break;
829 * case ...:
830 * [...]
831 * }
832 * nk_clear(&ctx);
833 * }
834 * nk_free(&ctx);
835 *
836 * You probably noticed that you have to draw all of the UI each frame which is
837 * quite wasteful. While the actual UI updating loop is quite fast rendering
838 * without actually needing it is not. So there are multiple things you could do.
839 *
840 * First is only update on input. This of course is only an option if your
841 * application only depends on the UI and does not require any outside calculations.
842 * If you actually only update on input make sure to update the UI two times each
843 * frame and call `nk_clear` directly after the first pass and only draw in
844 * the second pass. In addition it is recommended to also add additional timers
845 * to make sure the UI is not drawn more than a fixed number of frames per second.
846 *
847 * struct nk_context ctx;
848 * nk_init_xxx(&ctx, ...);
849 * while (1) {
850 * [...wait for input ]
851 *
852 * [...do two UI passes ...]
853 * do_ui(...)
854 * nk_clear(&ctx);
855 * do_ui(...)
856 *
857 * const struct nk_command *cmd = 0;
858 * nk_foreach(cmd, &ctx) {
859 * switch (cmd->type) {
860 * case NK_COMMAND_LINE:
861 * your_draw_line_function(...)
862 * break;
863 * case NK_COMMAND_RECT
864 * your_draw_rect_function(...)
865 * break;
866 * case ...:
867 * [...]
868 * }
869 * nk_clear(&ctx);
870 * }
871 * nk_free(&ctx);
872 *
873 * The second probably more applicable trick is to only draw if anything changed.
874 * It is not really useful for applications with continuous draw loop but
875 * quite useful for desktop applications. To actually get nuklear to only
876 * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and
877 * allocate a memory buffer that will store each unique drawing output.
878 * After each frame you compare the draw command memory inside the library
879 * with your allocated buffer by memcmp. If memcmp detects differences
880 * you have to copy the command buffer into the allocated buffer
881 * and then draw like usual (this example uses fixed memory but you could
882 * use dynamically allocated memory).
883 *
884 * [... other defines ...]
885 * #define NK_ZERO_COMMAND_MEMORY
886 * #include "nuklear.h"
887 *
888 * struct nk_context ctx;
889 * void *last = calloc(1,64*1024);
890 * void *buf = calloc(1,64*1024);
891 * nk_init_fixed(&ctx, buf, 64*1024);
892 * while (1) {
893 * [...input...]
894 * [...ui...]
895 *
896 * void *cmds = nk_buffer_memory(&ctx.memory);
897 * if (memcmp(cmds, last, ctx.memory.allocated)) {
898 * memcpy(last,cmds,ctx.memory.allocated);
899 * const struct nk_command *cmd = 0;
900 * nk_foreach(cmd, &ctx) {
901 * switch (cmd->type) {
902 * case NK_COMMAND_LINE:
903 * your_draw_line_function(...)
904 * break;
905 * case NK_COMMAND_RECT
906 * your_draw_rect_function(...)
907 * break;
908 * case ...:
909 * [...]
910 * }
911 * }
912 * }
913 * nk_clear(&ctx);
914 * }
915 * nk_free(&ctx);
916 *
917 * Finally while using draw commands makes sense for higher abstracted platforms like
918 * X11 and Win32 or drawing libraries it is often desirable to use graphics
919 * hardware directly. Therefore it is possible to just define
920 * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output.
921 * To access the vertex output you first have to convert all draw commands into
922 * vertexes by calling `nk_convert` which takes in your preferred vertex format.
923 * After successfully converting all draw commands just iterate over and execute all
924 * vertex draw commands:
925 *
926 * struct nk_convert_config cfg = {};
927 * static const struct nk_draw_vertex_layout_element vertex_layout[] = {
928 * {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)},
929 * {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)},
930 * {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)},
931 * {NK_VERTEX_LAYOUT_END}
932 * };
933 * cfg.shape_AA = NK_ANTI_ALIASING_ON;
934 * cfg.line_AA = NK_ANTI_ALIASING_ON;
935 * cfg.vertex_layout = vertex_layout;
936 * cfg.vertex_size = sizeof(struct your_vertex);
937 * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex);
938 * cfg.circle_segment_count = 22;
939 * cfg.curve_segment_count = 22;
940 * cfg.arc_segment_count = 22;
941 * cfg.global_alpha = 1.0f;
942 * cfg.null = dev->null;
943 *
944 * struct nk_buffer cmds, verts, idx;
945 * nk_buffer_init_default(&cmds);
946 * nk_buffer_init_default(&verts);
947 * nk_buffer_init_default(&idx);
948 * nk_convert(&ctx, &cmds, &verts, &idx, &cfg);
949 * nk_draw_foreach(cmd, &ctx, &cmds) {
950 * if (!cmd->elem_count) continue;
951 * [...]
952 * }
953 * nk_buffer_free(&cms);
954 * nk_buffer_free(&verts);
955 * nk_buffer_free(&idx);
956 *
957 * Reference
958 * -------------------
959 * nk__begin - Returns the first draw command in the context draw command list to be drawn
960 * nk__next - Increments the draw command iterator to the next command inside the context draw command list
961 * nk_foreach - Iterates over each draw command inside the context draw command list
962 *
963 * nk_convert - Converts from the abstract draw commands list into a hardware accessible vertex format
964 * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed
965 * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list
966 * nk__draw_end - Returns the end of the vertex draw list
967 * nk_draw_foreach - Iterates over each vertex draw command inside the vertex draw list
968 */
969 enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON};
970 enum nk_convert_result {
971 NK_CONVERT_SUCCESS = 0,
972 NK_CONVERT_INVALID_PARAM = 1,
973 NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1),
974 NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2),
975 NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3)
976 };
977 struct nk_draw_null_texture {
978 nk_handle texture; /* texture handle to a texture with a white pixel */
979 struct nk_vec2 uv; /* coordinates to a white pixel in the texture */
980 };
981 struct nk_convert_config {
982 float global_alpha; /* global alpha value */
983 enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */
984 enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */
985 unsigned circle_segment_count; /* number of segments used for circles: default to 22 */
986 unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */
987 unsigned curve_segment_count; /* number of segments used for curves: default to 22 */
988 struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */
989 const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */
990 nk_size vertex_size; /* sizeof one vertex for vertex packing */
991 nk_size vertex_alignment; /* vertex alignment: Can be obtained by NK_ALIGNOF */
992 };
993 /* nk__begin - Returns a draw command list iterator to iterate all draw
994 * commands accumulated over one frame.
995 * Parameters:
996 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
997 * Return values:
998 * draw command pointer pointing to the first command inside the draw command list */
999 NK_API const struct nk_command* nk__begin(struct nk_context*);
1000 /* nk__next - Returns a draw command list iterator to iterate all draw
1001 * Parameters:
1002 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1003 * @cmd must point to an previously a draw command either returned by `nk__begin` or `nk__next`
1004 * Return values:
1005 * draw command pointer pointing to the next command inside the draw command list */
1006 NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);
1007 /* nk_foreach - Iterates over each draw command inside the context draw command list
1008 * Parameters:
1009 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1010 * @cmd pointer initialized to NULL */
1011 #define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c))
1012 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
1013 /* nk_convert - converts all internal draw command into vertex draw commands and fills
1014 * three buffers with vertexes, vertex draw commands and vertex indices. The vertex format
1015 * as well as some other configuration values have to be configured by filling out a
1016 * `nk_convert_config` struct.
1017 * Parameters:
1018 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1019 * @cmds must point to a previously initialized buffer to hold converted vertex draw commands
1020 * @vertices must point to a previously initialized buffer to hold all produced vertices
1021 * @elements must point to a previously initialized buffer to hold all produced vertex indices
1022 * @config must point to a filled out `nk_config` struct to configure the conversion process
1023 * Returns:
1024 * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */
1025 NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);
1026 /* nk__draw_begin - Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer
1027 * Parameters:
1028 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1029 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
1030 * Return values:
1031 * vertex draw command pointer pointing to the first command inside the vertex draw command buffer */
1032 NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);
1033 /* nk__draw_end - Returns the vertex draw command at the end of the vertex draw command buffer
1034 * Parameters:
1035 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1036 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
1037 * Return values:
1038 * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */
1039 NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*);
1040 /* nk__draw_next - Increments the vertex draw command buffer iterator
1041 * Parameters:
1042 * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command
1043 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
1044 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame
1045 * Return values:
1046 * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */
1047 NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);
1048 /* nk_draw_foreach - Iterates over each vertex draw command inside a vertex draw command buffer
1049 * Parameters:
1050 * @cmd nk_draw_command pointer set to NULL
1051 * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer
1052 * @ctx must point to an previously initialized `nk_context` struct at the end of a frame */
1053 #define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx))
1054 #endif
1055 /* =============================================================================
1056 *
1057 * WINDOW
1058 *
1059 * =============================================================================
1060 * Windows are the main persistent state used inside nuklear and are life time
1061 * controlled by simply "retouching" (i.e. calling) each window each frame.
1062 * All widgets inside nuklear can only be added inside function pair `nk_begin_xxx`
1063 * and `nk_end`. Calling any widgets outside these two functions will result in an
1064 * assert in debug or no state change in release mode.
1065 *
1066 * Each window holds frame persistent state like position, size, flags, state tables,
1067 * and some garbage collected internal persistent widget state. Each window
1068 * is linked into a window stack list which determines the drawing and overlapping
1069 * order. The topmost window thereby is the currently active window.
1070 *
1071 * To change window position inside the stack occurs either automatically by
1072 * user input by being clicked on or programmatically by calling `nk_window_focus`.
1073 * Windows by default are visible unless explicitly being defined with flag
1074 * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag
1075 * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling
1076 * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.
1077 *
1078 * Usage
1079 * -------------------
1080 * To create and keep a window you have to call one of the two `nk_begin_xxx`
1081 * functions to start window declarations and `nk_end` at the end. Furthermore it
1082 * is recommended to check the return value of `nk_begin_xxx` and only process
1083 * widgets inside the window if the value is not 0. Either way you have to call
1084 * `nk_end` at the end of window declarations. Furthermore, do not attempt to
1085 * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not
1086 * in a segmentation fault.
1087 *
1088 * if (nk_begin_xxx(...) {
1089 * [... widgets ...]
1090 * }
1091 * nk_end(ctx);
1092 *
1093 * In the grand concept window and widget declarations need to occur after input
1094 * handling and before drawing to screen. Not doing so can result in higher
1095 * latency or at worst invalid behavior. Furthermore make sure that `nk_clear`
1096 * is called at the end of the frame. While nuklear's default platform backends
1097 * already call `nk_clear` for you if you write your own backend not calling
1098 * `nk_clear` can cause asserts or even worse undefined behavior.
1099 *
1100 * struct nk_context ctx;
1101 * nk_init_xxx(&ctx, ...);
1102 * while (1) {
1103 * Event evt;
1104 * nk_input_begin(&ctx);
1105 * while (GetEvent(&evt)) {
1106 * if (evt.type == MOUSE_MOVE)
1107 * nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
1108 * else if (evt.type == [...]) {
1109 * nk_input_xxx(...);
1110 * }
1111 * }
1112 * nk_input_end(&ctx);
1113 *
1114 * if (nk_begin_xxx(...) {
1115 * [...]
1116 * }
1117 * nk_end(ctx);
1118 *
1119 * const struct nk_command *cmd = 0;
1120 * nk_foreach(cmd, &ctx) {
1121 * case NK_COMMAND_LINE:
1122 * your_draw_line_function(...)
1123 * break;
1124 * case NK_COMMAND_RECT
1125 * your_draw_rect_function(...)
1126 * break;
1127 * case ...:
1128 * [...]
1129 * }
1130 * nk_clear(&ctx);
1131 * }
1132 * nk_free(&ctx);
1133 *
1134 * Reference
1135 * -------------------
1136 * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed
1137 * nk_begin_titled - extended window start with separated title and identifier to allow multiple windows with same name but not title
1138 * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup
1139 *
1140 * nk_window_find - finds and returns the window with give name
1141 * nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window.
1142 * nk_window_get_position - returns the position of the currently processed window
1143 * nk_window_get_size - returns the size with width and height of the currently processed window
1144 * nk_window_get_width - returns the width of the currently processed window
1145 * nk_window_get_height - returns the height of the currently processed window
1146 * nk_window_get_panel - returns the underlying panel which contains all processing state of the current window
1147 * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window
1148 * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
1149 * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
1150 * nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window
1151 * nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets
1152 *
1153 * nk_window_has_focus - returns if the currently processed window is currently active
1154 * nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed
1155 * nk_window_is_closed - returns if the currently processed window was closed
1156 * nk_window_is_hidden - returns if the currently processed window was hidden
1157 * nk_window_is_active - same as nk_window_has_focus for some reason
1158 * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse
1159 * nk_window_is_any_hovered - return if any window currently hovered
1160 * nk_item_is_any_active - returns if any window or widgets is currently hovered or active
1161 *
1162 * nk_window_set_bounds - updates position and size of the currently processed window
1163 * nk_window_set_position - updates position of the currently process window
1164 * nk_window_set_size - updates the size of the currently processed window
1165 * nk_window_set_focus - set the currently processed window as active window
1166 *
1167 * nk_window_close - closes the window with given window name which deletes the window at the end of the frame
1168 * nk_window_collapse - collapses the window with given window name
1169 * nk_window_collapse_if - collapses the window with given window name if the given condition was met
1170 * nk_window_show - hides a visible or reshows a hidden window
1171 * nk_window_show_if - hides/shows a window depending on condition
1172 */
1173 enum nk_panel_flags {
1174 NK_WINDOW_BORDER = NK_FLAG(0), /* Draws a border around the window to visually separate window from the background */
1175 NK_WINDOW_MOVABLE = NK_FLAG(1), /* The movable flag indicates that a window can be moved by user input or by dragging the window header */
1176 NK_WINDOW_SCALABLE = NK_FLAG(2), /* The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window */
1177 NK_WINDOW_CLOSABLE = NK_FLAG(3), /* adds a closable icon into the header */
1178 NK_WINDOW_MINIMIZABLE = NK_FLAG(4), /* adds a minimize icon into the header */
1179 NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), /* Removes the scrollbar from the window */
1180 NK_WINDOW_TITLE = NK_FLAG(6), /* Forces a header at the top at the window showing the title */
1181 NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), /* Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame */
1182 NK_WINDOW_BACKGROUND = NK_FLAG(8), /* Always keep window in the background */
1183 NK_WINDOW_SCALE_LEFT = NK_FLAG(9), /* Puts window scaler in the left-ottom corner instead right-bottom*/
1184 NK_WINDOW_NO_INPUT = NK_FLAG(10) /* Prevents window of scaling, moving or getting focus */
1185 };
1186 /* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed
1187 * Parameters:
1188 * @ctx must point to an previously initialized `nk_context` struct
1189 * @title window title and identifier. Needs to be persistent over frames to identify the window
1190 * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
1191 * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors
1192 * Return values:
1193 * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/
1194 NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
1195 /* nk_begin_titled - extended window start with separated title and identifier to allow multiple windows with same name but not title
1196 * Parameters:
1197 * @ctx must point to an previously initialized `nk_context` struct
1198 * @name window identifier. Needs to be persistent over frames to identify the window
1199 * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set
1200 * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
1201 * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors
1202 * Return values:
1203 * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise `*/
1204 NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
1205 /* nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup.
1206 * All widget calls after this functions will result in asserts or no state changes
1207 * Parameters:
1208 * @ctx must point to an previously initialized `nk_context` struct */
1209 NK_API void nk_end(struct nk_context *ctx);
1210 /* nk_window_find - finds and returns the window with give name
1211 * Parameters:
1212 * @ctx must point to an previously initialized `nk_context` struct
1213 * @name window identifier
1214 * Return values:
1215 * returns a `nk_window` struct pointing to the identified window or 0 if no window with given name was found */
1216 NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name);
1217 /* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window.
1218 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1219 * Parameters:
1220 * @ctx must point to an previously initialized `nk_context` struct
1221 * Return values:
1222 * returns a `nk_rect` struct with window upper left position and size */
1223 NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);
1224 /* nk_window_get_position - returns the position of the currently processed window.
1225 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1226 * Parameters:
1227 * @ctx must point to an previously initialized `nk_context` struct
1228 * Return values:
1229 * returns a `nk_vec2` struct with window upper left position */
1230 NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);
1231 /* nk_window_get_size - returns the size with width and height of the currently processed window.
1232 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1233 * Parameters:
1234 * @ctx must point to an previously initialized `nk_context` struct
1235 * Return values:
1236 * returns a `nk_vec2` struct with window size */
1237 NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*);
1238 /* nk_window_get_width - returns the width of the currently processed window.
1239 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1240 * Parameters:
1241 * @ctx must point to an previously initialized `nk_context` struct
1242 * Return values:
1243 * returns the window width */
1244 NK_API float nk_window_get_width(const struct nk_context*);
1245 /* nk_window_get_height - returns the height of the currently processed window.
1246 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1247 * Parameters:
1248 * @ctx must point to an previously initialized `nk_context` struct
1249 * Return values:
1250 * returns the window height */
1251 NK_API float nk_window_get_height(const struct nk_context*);
1252 /* nk_window_get_panel - returns the underlying panel which contains all processing state of the current window.
1253 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1254 * Parameters:
1255 * @ctx must point to an previously initialized `nk_context` struct
1256 * Return values:
1257 * returns a pointer to window internal `nk_panel` state. DO NOT keep this pointer around it is only valid until `nk_end` */
1258 NK_API struct nk_panel* nk_window_get_panel(struct nk_context*);
1259 /* nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window.
1260 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1261 * Parameters:
1262 * @ctx must point to an previously initialized `nk_context` struct
1263 * Return values:
1264 * returns `nk_rect` struct with screen position and size (no scrollbar offset) of the visible space inside the current window */
1265 NK_API struct nk_rect nk_window_get_content_region(struct nk_context*);
1266 /* nk_window_get_content_region_min - returns the upper left position of the currently visible and non-clipped space inside the currently processed window.
1267 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1268 * Parameters:
1269 * @ctx must point to an previously initialized `nk_context` struct
1270 * Return values:
1271 * returns `nk_vec2` struct with upper left screen position (no scrollbar offset) of the visible space inside the current window */
1272 NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*);
1273 /* nk_window_get_content_region_max - returns the lower right screen position of the currently visible and non-clipped space inside the currently processed window.
1274 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1275 * Parameters:
1276 * @ctx must point to an previously initialized `nk_context` struct
1277 * Return values:
1278 * returns `nk_vec2` struct with lower right screen position (no scrollbar offset) of the visible space inside the current window */
1279 NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*);
1280 /* nk_window_get_content_region_size - returns the size of the currently visible and non-clipped space inside the currently processed window
1281 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1282 * Parameters:
1283 * @ctx must point to an previously initialized `nk_context` struct
1284 * Return values:
1285 * returns `nk_vec2` struct with size the visible space inside the current window */
1286 NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*);
1287 /* nk_window_get_canvas - returns the draw command buffer. Can be used to draw custom widgets
1288 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1289 * Parameters:
1290 * @ctx must point to an previously initialized `nk_context` struct
1291 * Return values:
1292 * returns a pointer to window internal `nk_command_buffer` struct used as drawing canvas. Can be used to do custom drawing */
1293 NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*);
1294 /* nk_window_has_focus - returns if the currently processed window is currently active
1295 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1296 * Parameters:
1297 * @ctx must point to an previously initialized `nk_context` struct
1298 * Return values:
1299 * returns 0 if current window is not active or 1 if it is */
1300 NK_API int nk_window_has_focus(const struct nk_context*);
1301 /* nk_window_is_collapsed - returns if the window with given name is currently minimized/collapsed
1302 * Parameters:
1303 * @ctx must point to an previously initialized `nk_context` struct
1304 * @name of window you want to check is collapsed
1305 * Return values:
1306 * returns 1 if current window is minimized and 0 if window not found or is not minimized */
1307 NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name);
1308 /* nk_window_is_closed - returns if the window with given name was closed by calling `nk_close`
1309 * Parameters:
1310 * @ctx must point to an previously initialized `nk_context` struct
1311 * @name of window you want to check is closed
1312 * Return values:
1313 * returns 1 if current window was closed or 0 window not found or not closed */
1314 NK_API int nk_window_is_closed(struct nk_context*, const char*);
1315 /* nk_window_is_hidden - returns if the window with given name is hidden
1316 * Parameters:
1317 * @ctx must point to an previously initialized `nk_context` struct
1318 * @name of window you want to check is hidden
1319 * Return values:
1320 * returns 1 if current window is hidden or 0 window not found or visible */
1321 NK_API int nk_window_is_hidden(struct nk_context*, const char*);
1322 /* nk_window_is_active - same as nk_window_has_focus for some reason
1323 * Parameters:
1324 * @ctx must point to an previously initialized `nk_context` struct
1325 * @name of window you want to check is hidden
1326 * Return values:
1327 * returns 1 if current window is active or 0 window not found or not active */
1328 NK_API int nk_window_is_active(struct nk_context*, const char*);
1329 /* nk_window_is_hovered - return if the current window is being hovered
1330 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1331 * Parameters:
1332 * @ctx must point to an previously initialized `nk_context` struct
1333 * Return values:
1334 * returns 1 if current window is hovered or 0 otherwise */
1335 NK_API int nk_window_is_hovered(struct nk_context*);
1336 /* nk_window_is_any_hovered - returns if the any window is being hovered
1337 * Parameters:
1338 * @ctx must point to an previously initialized `nk_context` struct
1339 * Return values:
1340 * returns 1 if any window is hovered or 0 otherwise */
1341 NK_API int nk_window_is_any_hovered(struct nk_context*);
1342 /* nk_item_is_any_active - returns if the any window is being hovered or any widget is currently active.
1343 * Can be used to decide if input should be processed by UI or your specific input handling.
1344 * Example could be UI and 3D camera to move inside a 3D space.
1345 * Parameters:
1346 * @ctx must point to an previously initialized `nk_context` struct
1347 * Return values:
1348 * returns 1 if any window is hovered or any item is active or 0 otherwise */
1349 NK_API int nk_item_is_any_active(struct nk_context*);
1350 /* nk_window_set_bounds - updates position and size of the currently processed window
1351 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1352 * Parameters:
1353 * @ctx must point to an previously initialized `nk_context` struct
1354 * @name of the window to modify both position and size
1355 * @bounds points to a `nk_rect` struct with the new position and size of currently active window */
1356 NK_API void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds);
1357 /* nk_window_set_position - updates position of the currently processed window
1358 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1359 * Parameters:
1360 * @ctx must point to an previously initialized `nk_context` struct
1361 * @name of the window to modify position of
1362 * @pos points to a `nk_vec2` struct with the new position of currently active window */
1363 NK_API void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos);
1364 /* nk_window_set_size - updates size of the currently processed window
1365 * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end`
1366 * Parameters:
1367 * @ctx must point to an previously initialized `nk_context` struct
1368 * @name of the window to modify size of
1369 * @size points to a `nk_vec2` struct with the new size of currently active window */
1370 NK_API void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2);
1371 /* nk_window_set_focus - sets the window with given name as active
1372 * Parameters:
1373 * @ctx must point to an previously initialized `nk_context` struct
1374 * @name of the window to be set active */
1375 NK_API void nk_window_set_focus(struct nk_context*, const char *name);
1376 /* nk_window_close - closed a window and marks it for being freed at the end of the frame
1377 * Parameters:
1378 * @ctx must point to an previously initialized `nk_context` struct
1379 * @name of the window to be closed */
1380 NK_API void nk_window_close(struct nk_context *ctx, const char *name);
1381 /* nk_window_collapse - updates collapse state of a window with given name
1382 * Parameters:
1383 * @ctx must point to an previously initialized `nk_context` struct
1384 * @name of the window to be either collapse or maximize */
1385 NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state);
1386 /* nk_window_collapse - updates collapse state of a window with given name if given condition is met
1387 * Parameters:
1388 * @ctx must point to an previously initialized `nk_context` struct
1389 * @name of the window to be either collapse or maximize
1390 * @state the window should be put into
1391 * @condition that has to be true to actually commit the collapse state change */
1392 NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond);
1393 /* nk_window_show - updates visibility state of a window with given name
1394 * Parameters:
1395 * @ctx must point to an previously initialized `nk_context` struct
1396 * @name of the window to be either collapse or maximize
1397 * @state with either visible or hidden to modify the window with */
1398 NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states);
1399 /* nk_window_show_if - updates visibility state of a window with given name if a given condition is met
1400 * Parameters:
1401 * @ctx must point to an previously initialized `nk_context` struct
1402 * @name of the window to be either collapse or maximize
1403 * @state with either visible or hidden to modify the window with
1404 * @condition that has to be true to actually commit the visible state change */
1405 NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond);
1406 /* =============================================================================
1407 *
1408 * LAYOUT
1409 *
1410 * ============================================================================= */
1411 /* Layouting in general describes placing widget inside a window with position and size.
1412 * While in this particular implementation there are five different APIs for layouting
1413 * each with different trade offs between control and ease of use.
1414 *
1415 * All layouting methods in this library are based around the concept of a row.
1416 * A row has a height the window content grows by and a number of columns and each
1417 * layouting method specifies how each widget is placed inside the row.
1418 * After a row has been allocated by calling a layouting functions and then
1419 * filled with widgets will advance an internal pointer over the allocated row.
1420 *
1421 * To actually define a layout you just call the appropriate layouting function
1422 * and each subsequent widget call will place the widget as specified. Important
1423 * here is that if you define more widgets then columns defined inside the layout
1424 * functions it will allocate the next row without you having to make another layouting
1425 * call.
1426 *
1427 * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API
1428 * is that you have to define the row height for each. However the row height
1429 * often depends on the height of the font.
1430 *
1431 * To fix that internally nuklear uses a minimum row height that is set to the
1432 * height plus padding of currently active font and overwrites the row height
1433 * value if zero.
1434 *
1435 * If you manually want to change the minimum row height then
1436 * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to
1437 * reset it back to be derived from font height.
1438 *
1439 * Also if you change the font in nuklear it will automatically change the minimum
1440 * row height for you and. This means if you change the font but still want
1441 * a minimum row height smaller than the font you have to repush your value.
1442 *
1443 * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx`
1444 * layouting method in combination with a cassowary constraint solver (there are
1445 * some versions on github with permissive license model) to take over all control over widget
1446 * layouting yourself. However for quick and dirty layouting using all the other layouting
1447 * functions should be fine.
1448 *
1449 * Usage
1450 * -------------------
1451 * 1.) nk_layout_row_dynamic
1452 * The easiest layouting function is `nk_layout_row_dynamic`. It provides each
1453 * widgets with same horizontal space inside the row and dynamically grows
1454 * if the owning window grows in width. So the number of columns dictates
1455 * the size of each widget dynamically by formula:
1456 *
1457 * widget_width = (window_width - padding - spacing) * (1/colum_count)
1458 *
1459 * Just like all other layouting APIs if you define more widget than columns this
1460 * library will allocate a new row and keep all layouting parameters previously
1461 * defined.
1462 *
1463 * if (nk_begin_xxx(...) {
1464 * // first row with height: 30 composed of two widgets
1465 * nk_layout_row_dynamic(&ctx, 30, 2);
1466 * nk_widget(...);
1467 * nk_widget(...);
1468 *
1469 * // second row with same parameter as defined above
1470 * nk_widget(...);
1471 * nk_widget(...);
1472 *
1473 * // third row uses 0 for height which will use auto layouting
1474 * nk_layout_row_dynamic(&ctx, 0, 2);
1475 * nk_widget(...);
1476 * nk_widget(...);
1477 * }
1478 * nk_end(...);
1479 *
1480 * 2.) nk_layout_row_static
1481 * Another easy layouting function is `nk_layout_row_static`. It provides each
1482 * widget with same horizontal pixel width inside the row and does not grow
1483 * if the owning window scales smaller or bigger.
1484 *
1485 * if (nk_begin_xxx(...) {
1486 * // first row with height: 30 composed of two widgets with width: 80
1487 * nk_layout_row_static(&ctx, 30, 80, 2);
1488 * nk_widget(...);
1489 * nk_widget(...);
1490 *
1491 * // second row with same parameter as defined above
1492 * nk_widget(...);
1493 * nk_widget(...);
1494 *
1495 * // third row uses 0 for height which will use auto layouting
1496 * nk_layout_row_static(&ctx, 0, 80, 2);
1497 * nk_widget(...);
1498 * nk_widget(...);
1499 * }
1500 * nk_end(...);
1501 *
1502 * 3.) nk_layout_row_xxx
1503 * A little bit more advanced layouting API are functions `nk_layout_row_begin`,
1504 * `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly
1505 * specify each column pixel or window ratio in a row. It supports either
1506 * directly setting per column pixel width or widget window ratio but not
1507 * both. Furthermore it is a immediate mode API so each value is directly
1508 * pushed before calling a widget. Therefore the layout is not automatically
1509 * repeating like the last two layouting functions.
1510 *
1511 * if (nk_begin_xxx(...) {
1512 * // first row with height: 25 composed of two widgets with width 60 and 40
1513 * nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
1514 * nk_layout_row_push(ctx, 60);
1515 * nk_widget(...);
1516 * nk_layout_row_push(ctx, 40);
1517 * nk_widget(...);
1518 * nk_layout_row_end(ctx);
1519 *
1520 * // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75
1521 * nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2);
1522 * nk_layout_row_push(ctx, 0.25f);
1523 * nk_widget(...);
1524 * nk_layout_row_push(ctx, 0.75f);
1525 * nk_widget(...);
1526 * nk_layout_row_end(ctx);
1527 *
1528 * // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75
1529 * nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2);
1530 * nk_layout_row_push(ctx, 0.25f);
1531 * nk_widget(...);
1532 * nk_layout_row_push(ctx, 0.75f);
1533 * nk_widget(...);
1534 * nk_layout_row_end(ctx);
1535 * }
1536 * nk_end(...);
1537 *
1538 * 4.) nk_layout_row
1539 * The array counterpart to API nk_layout_row_xxx is the single nk_layout_row
1540 * functions. Instead of pushing either pixel or window ratio for every widget
1541 * it allows to define it by array. The trade of for less control is that
1542 * `nk_layout_row` is automatically repeating. Otherwise the behavior is the
1543 * same.
1544 *
1545 * if (nk_begin_xxx(...) {
1546 * // two rows with height: 30 composed of two widgets with width 60 and 40
1547 * const float size[] = {60,40};
1548 * nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);
1549 * nk_widget(...);
1550 * nk_widget(...);
1551 * nk_widget(...);
1552 * nk_widget(...);
1553 *
1554 * // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75
1555 * const float ratio[] = {0.25, 0.75};
1556 * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);
1557 * nk_widget(...);
1558 * nk_widget(...);
1559 * nk_widget(...);
1560 * nk_widget(...);
1561 *
1562 * // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75
1563 * const float ratio[] = {0.25, 0.75};
1564 * nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);
1565 * nk_widget(...);
1566 * nk_widget(...);
1567 * nk_widget(...);
1568 * nk_widget(...);
1569 * }
1570 * nk_end(...);
1571 *
1572 * 5.) nk_layout_row_template_xxx
1573 * The most complex and second most flexible API is a simplified flexbox version without
1574 * line wrapping and weights for dynamic widgets. It is an immediate mode API but
1575 * unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called
1576 * before calling the templated widgets.
1577 * The row template layout has three different per widget size specifier. The first
1578 * one is the static widget size specifier with fixed widget pixel width. They do
1579 * not grow if the row grows and will always stay the same. The second size
1580 * specifier is nk_layout_row_template_push_variable which defines a
1581 * minimum widget size but it also can grow if more space is available not taken
1582 * by other widgets. Finally there are dynamic widgets which are completely flexible
1583 * and unlike variable widgets can even shrink to zero if not enough space
1584 * is provided.
1585 *
1586 * if (nk_begin_xxx(...) {
1587 * // two rows with height: 30 composed of three widgets
1588 * nk_layout_row_template_begin(ctx, 30);
1589 * nk_layout_row_template_push_dynamic(ctx);
1590 * nk_layout_row_template_push_variable(ctx, 80);
1591 * nk_layout_row_template_push_static(ctx, 80);
1592 * nk_layout_row_template_end(ctx);
1593 *
1594 * nk_widget(...); // dynamic widget can go to zero if not enough space
1595 * nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space
1596 * nk_widget(...); // static widget with fixed 80 pixel width
1597 *
1598 * // second row same layout
1599 * nk_widget(...);
1600 * nk_widget(...);
1601 * nk_widget(...);
1602 * }
1603 * nk_end(...);
1604 *
1605 * 6.) nk_layout_space_xxx
1606 * Finally the most flexible API directly allows you to place widgets inside the
1607 * window. The space layout API is an immediate mode API which does not support
1608 * row auto repeat and directly sets position and size of a widget. Position
1609 * and size hereby can be either specified as ratio of allocated space or
1610 * allocated space local position and pixel size. Since this API is quite
1611 * powerful there are a number of utility functions to get the available space
1612 * and convert between local allocated space and screen space.
1613 *
1614 * if (nk_begin_xxx(...) {
1615 * // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)
1616 * nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX);
1617 * nk_layout_space_push(ctx, nk_rect(0,0,150,200));
1618 * nk_widget(...);
1619 * nk_layout_space_push(ctx, nk_rect(200,200,100,200));
1620 * nk_widget(...);
1621 * nk_layout_space_end(ctx);
1622 *
1623 * // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)
1624 * nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX);
1625 * nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1));
1626 * nk_widget(...);
1627 * nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1));
1628 * nk_widget(...);
1629 * }
1630 * nk_end(...);
1631 *
1632 * Reference
1633 * -------------------
1634 * nk_layout_set_min_row_height - set the currently used minimum row height to a specified value
1635 * nk_layout_reset_min_row_height - resets the currently used minimum row height to font height
1636 *
1637 * nk_layout_widget_bounds - calculates current width a static layout row can fit inside a window
1638 * nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size
1639 *
1640 * nk_layout_row_dynamic - current layout is divided into n same sized growing columns
1641 * nk_layout_row_static - current layout is divided into n same fixed sized columns
1642 * nk_layout_row_begin - starts a new row with given height and number of columns
1643 * nk_layout_row_push - pushes another column with given size or window ratio
1644 * nk_layout_row_end - finished previously started row
1645 * nk_layout_row - specifies row columns in array as either window ratio or size
1646 *
1647 * nk_layout_row_template_begin - begins the row template declaration
1648 * nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space
1649 * nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width
1650 * nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size
1651 * nk_layout_row_template_end - marks the end of the row template
1652 *
1653 * nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size
1654 * nk_layout_space_push - pushes position and size of the next widget in own coordinate space either as pixel or ratio
1655 * nk_layout_space_end - marks the end of the layouting space
1656 *
1657 * nk_layout_space_bounds - callable after nk_layout_space_begin and returns total space allocated
1658 * nk_layout_space_to_screen - converts vector from nk_layout_space coordinate space into screen space
1659 * nk_layout_space_to_local - converts vector from screen space into nk_layout_space coordinates
1660 * nk_layout_space_rect_to_screen - converts rectangle from nk_layout_space coordinate space into screen space
1661 * nk_layout_space_rect_to_local - converts rectangle from screen space into nk_layout_space coordinates
1662 */
1663 /* nk_layout_set_min_row_height - sets the currently used minimum row height.
1664 * IMPORTANT: The passed height needs to include both your preferred row height
1665 * as well as padding. No internal padding is added.
1666 * Parameters:
1667 * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
1668 * @height new minimum row height to be used for auto generating the row height */
1669 NK_API void nk_layout_set_min_row_height(struct nk_context*, float height);
1670 /* nk_layout_reset_min_row_height - Reset the currently used minimum row height
1671 * back to font height + text padding + additional padding (style_window.min_row_height_padding)
1672 * Parameters:
1673 * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` */
1674 NK_API void nk_layout_reset_min_row_height(struct nk_context*);
1675 /* nk_layout_widget_bounds - returns the width of the next row allocate by one of the layouting functions
1676 * Parameters:
1677 * @ctx must point to an previously initialized `nk_context` */
1678 NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*);
1679 /* nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size
1680 * Parameters:
1681 * @ctx must point to an previously initialized `nk_context`
1682 * @pixel_width to convert to window ratio */
1683 NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width);
1684 /* nk_layout_row_dynamic - Sets current row layout to share horizontal space
1685 * between @cols number of widgets evenly. Once called all subsequent widget
1686 * calls greater than @cols will allocate a new row with same layout.
1687 * Parameters:
1688 * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
1689 * @row_height holds height of each widget in row or zero for auto layouting
1690 * @cols number of widget inside row */
1691 NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);
1692 /* nk_layout_row_static - Sets current row layout to fill @cols number of widgets
1693 * in row with same @item_width horizontal size. Once called all subsequent widget
1694 * calls greater than @cols will allocate a new row with same layout.
1695 * Parameters:
1696 * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
1697 * @height holds row height to allocate from panel for widget height
1698 * @item_width holds width of each widget in row
1699 * @cols number of widget inside row */
1700 NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);
1701 /* nk_layout_row_begin - Starts a new dynamic or fixed row with given height and columns.
1702 * Parameters:
1703 * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
1704 * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
1705 * @row_height holds height of each widget in row or zero for auto layouting
1706 * @cols number of widget inside row */
1707 NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);
1708 /* nk_layout_row_push - Specifies either window ratio or width of a single column
1709 * Parameters:
1710 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin`
1711 * @value either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call */
1712 NK_API void nk_layout_row_push(struct nk_context*, float value);
1713 /* nk_layout_row_end - finished previously started row
1714 * Parameters:
1715 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_begin` */
1716 NK_API void nk_layout_row_end(struct nk_context*);
1717 /* nk_layout_row - specifies row columns in array as either window ratio or size
1718 * Parameters:
1719 * @ctx must point to an previously initialized `nk_context`
1720 * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
1721 * @row_height holds height of each widget in row or zero for auto layouting
1722 * @cols number of widget inside row */
1723 NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);
1724 /* nk_layout_row_template_begin - Begins the row template declaration
1725 * Parameters:
1726 * @ctx must point to an previously initialized `nk_context` struct
1727 * @row_height holds height of each widget in row or zero for auto layouting */
1728 NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height);
1729 /* nk_layout_row_template_push_dynamic - adds a dynamic column that dynamically grows and can go to zero if not enough space
1730 * Parameters:
1731 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */
1732 NK_API void nk_layout_row_template_push_dynamic(struct nk_context*);
1733 /* nk_layout_row_template_push_variable - adds a variable column that dynamically grows but does not shrink below specified pixel width
1734 * Parameters:
1735 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin`
1736 * @min_width holds the minimum pixel width the next column must be */
1737 NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width);
1738 /* nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size
1739 * Parameters:
1740 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin`
1741 * @width holds the absolute pixel width value the next column must be */
1742 NK_API void nk_layout_row_template_push_static(struct nk_context*, float width);
1743 /* nk_layout_row_template_end - marks the end of the row template
1744 * Parameters:
1745 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` */
1746 NK_API void nk_layout_row_template_end(struct nk_context*);
1747 /* nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size.
1748 * Parameters:
1749 * @ctx must point to an previously initialized `nk_context` struct
1750 * @fmt either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
1751 * @row_height holds height of each widget in row or zero for auto layouting
1752 * @widget_count number of widgets inside row */
1753 NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);
1754 /* nk_layout_space_push - pushes position and size of the next widget in own coordinate space either as pixel or ratio
1755 * Parameters:
1756 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
1757 * @bounds position and size in laoyut space local coordinates */
1758 NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect);
1759 /* nk_layout_space_end - marks the end of the layout space
1760 * Parameters:
1761 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */
1762 NK_API void nk_layout_space_end(struct nk_context*);
1763 /* nk_layout_space_bounds - returns total space allocated for `nk_layout_space`
1764 * Parameters:
1765 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */
1766 NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*);
1767 /* nk_layout_space_to_screen - converts vector from nk_layout_space coordinate space into screen space
1768 * Parameters:
1769 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
1770 * @vec position to convert from layout space into screen coordinate space */
1771 NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2);
1772 /* nk_layout_space_to_screen - converts vector from layout space into screen space
1773 * Parameters:
1774 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
1775 * @vec position to convert from screen space into layout coordinate space */
1776 NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2);
1777 /* nk_layout_space_rect_to_screen - converts rectangle from screen space into layout space
1778 * Parameters:
1779 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
1780 * @bounds rectangle to convert from layout space into screen space */
1781 NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect);
1782 /* nk_layout_space_rect_to_local - converts rectangle from layout space into screen space
1783 * Parameters:
1784 * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
1785 * @bounds rectangle to convert from screen space into layout space */
1786 NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect);
1787 /* =============================================================================
1788 *
1789 * GROUP
1790 *
1791 * ============================================================================= */
1792 NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags);
1793 NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char*, nk_flags);
1794 NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll*, const char *title, nk_flags);
1795 NK_API void nk_group_scrolled_end(struct nk_context*);
1796 NK_API void nk_group_end(struct nk_context*);
1797 /* =============================================================================
1798 *
1799 * LIST VIEW
1800 *
1801 * ============================================================================= */
1802 struct nk_list_view {
1803 /* public: */
1804 int begin, end, count;
1805 /* private: */
1806 int total_height;
1807 struct nk_context *ctx;
1808 nk_uint *scroll_pointer;
1809 nk_uint scroll_value;
1810 };
1811 NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count);
1812 NK_API void nk_list_view_end(struct nk_list_view*);
1813 /* =============================================================================
1814 *
1815 * TREE
1816 *
1817 * ============================================================================= */
1818 #define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)
1819 #define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)
1820 NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
1821 #define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)
1822 #define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)
1823 NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
1824 NK_API void nk_tree_pop(struct nk_context*);
1825 NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
1826 NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
1827 NK_API void nk_tree_state_pop(struct nk_context*);
1828 /* =============================================================================
1829 *
1830 * WIDGET
1831 *
1832 * ============================================================================= */
1833 enum nk_widget_layout_states {
1834 NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */
1835 NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */
1836 NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */
1837 };
1838 enum nk_widget_states {
1839 NK_WIDGET_STATE_MODIFIED = NK_FLAG(1),
1840 NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */
1841 NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */
1842 NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */
1843 NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */
1844 NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */
1845 NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */
1846 NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */
1847 };
1848 NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*);
1849 NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2);
1850 NK_API struct nk_rect nk_widget_bounds(struct nk_context*);
1851 NK_API struct nk_vec2 nk_widget_position(struct nk_context*);
1852 NK_API struct nk_vec2 nk_widget_size(struct nk_context*);
1853 NK_API float nk_widget_width(struct nk_context*);
1854 NK_API float nk_widget_height(struct nk_context*);
1855 NK_API int nk_widget_is_hovered(struct nk_context*);
1856 NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons);
1857 NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down);
1858 NK_API void nk_spacing(struct nk_context*, int cols);
1859 /* =============================================================================
1860 *
1861 * TEXT
1862 *
1863 * ============================================================================= */
1864 enum nk_text_align {
1865 NK_TEXT_ALIGN_LEFT = 0x01,
1866 NK_TEXT_ALIGN_CENTERED = 0x02,
1867 NK_TEXT_ALIGN_RIGHT = 0x04,
1868 NK_TEXT_ALIGN_TOP = 0x08,
1869 NK_TEXT_ALIGN_MIDDLE = 0x10,
1870 NK_TEXT_ALIGN_BOTTOM = 0x20
1871 };
1872 enum nk_text_alignment {
1873 NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT,
1874 NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED,
1875 NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT
1876 };
1877 NK_API void nk_text(struct nk_context*, const char*, int, nk_flags);
1878 NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color);
1879 NK_API void nk_text_wrap(struct nk_context*, const char*, int);
1880 NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color);
1881 NK_API void nk_label(struct nk_context*, const char*, nk_flags align);
1882 NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color);
1883 NK_API void nk_label_wrap(struct nk_context*, const char*);
1884 NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color);
1885 NK_API void nk_image(struct nk_context*, struct nk_image);
1886 #ifdef NK_INCLUDE_STANDARD_VARARGS
1887 NK_API void nk_labelf(struct nk_context*, nk_flags, const char*, ...);
1888 NK_API void nk_labelf_colored(struct nk_context*, nk_flags align, struct nk_color, const char*,...);
1889 NK_API void nk_labelf_wrap(struct nk_context*, const char*,...);
1890 NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, const char*,...);
1891 NK_API void nk_value_bool(struct nk_context*, const char *prefix, int);
1892 NK_API void nk_value_int(struct nk_context*, const char *prefix, int);
1893 NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int);
1894 NK_API void nk_value_float(struct nk_context*, const char *prefix, float);
1895 NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color);
1896 NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color);
1897 NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color);
1898 #endif
1899 /* =============================================================================
1900 *
1901 * BUTTON
1902 *
1903 * ============================================================================= */
1904 NK_API int nk_button_text(struct nk_context*, const char *title, int len);
1905 NK_API int nk_button_label(struct nk_context*, const char *title);
1906 NK_API int nk_button_color(struct nk_context*, struct nk_color);
1907 NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type);
1908 NK_API int nk_button_image(struct nk_context*, struct nk_image img);
1909 NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment);
1910 NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1911 NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment);
1912 NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment);
1913 NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len);
1914 NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title);
1915 NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type);
1916 NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img);
1917 NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment);
1918 NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align);
1919 NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment);
1920 NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment);
1921 NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior);
1922 NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior);
1923 NK_API int nk_button_pop_behavior(struct nk_context*);
1924 /* =============================================================================
1925 *
1926 * CHECKBOX
1927 *
1928 * ============================================================================= */
1929 NK_API int nk_check_label(struct nk_context*, const char*, int active);
1930 NK_API int nk_check_text(struct nk_context*, const char*, int,int active);
1931 NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value);
1932 NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value);
1933 NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active);
1934 NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active);
1935 NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value);
1936 NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value);
1937 /* =============================================================================
1938 *
1939 * RADIO BUTTON
1940 *
1941 * ============================================================================= */
1942 NK_API int nk_radio_label(struct nk_context*, const char*, int *active);
1943 NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active);
1944 NK_API int nk_option_label(struct nk_context*, const char*, int active);
1945 NK_API int nk_option_text(struct nk_context*, const char*, int, int active);
1946 /* =============================================================================
1947 *
1948 * SELECTABLE
1949 *
1950 * ============================================================================= */
1951 NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value);
1952 NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value);
1953 NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value);
1954 NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value);
1955 NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value);
1956 NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value);
1957 NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value);
1958 NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value);
1959 /* =============================================================================
1960 *
1961 * SLIDER
1962 *
1963 * ============================================================================= */
1964 NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step);
1965 NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step);
1966 NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step);
1967 NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step);
1968 /* =============================================================================
1969 *
1970 * PROGRESSBAR
1971 *
1972 * ============================================================================= */
1973 NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable);
1974 NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable);
1975
1976 /* =============================================================================
1977 *
1978 * COLOR PICKER
1979 *
1980 * ============================================================================= */
1981 NK_API struct nk_color nk_color_picker(struct nk_context*, struct nk_color, enum nk_color_format);
1982 NK_API int nk_color_pick(struct nk_context*, struct nk_color*, enum nk_color_format);
1983 /* =============================================================================
1984 *
1985 * PROPERTIES
1986 *
1987 * ============================================================================= */
1988 NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel);
1989 NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel);
1990 NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel);
1991 NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel);
1992 NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel);
1993 NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel);
1994 /* =============================================================================
1995 *
1996 * TEXT EDIT
1997 *
1998 * ============================================================================= */
1999 enum nk_edit_flags {
2000 NK_EDIT_DEFAULT = 0,
2001 NK_EDIT_READ_ONLY = NK_FLAG(0),
2002 NK_EDIT_AUTO_SELECT = NK_FLAG(1),
2003 NK_EDIT_SIG_ENTER = NK_FLAG(2),
2004 NK_EDIT_ALLOW_TAB = NK_FLAG(3),
2005 NK_EDIT_NO_CURSOR = NK_FLAG(4),
2006 NK_EDIT_SELECTABLE = NK_FLAG(5),
2007 NK_EDIT_CLIPBOARD = NK_FLAG(6),
2008 NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7),
2009 NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8),
2010 NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9),
2011 NK_EDIT_MULTILINE = NK_FLAG(10),
2012 NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11)
2013 };
2014 enum nk_edit_types {
2015 NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE,
2016 NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD,
2017 NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD,
2018 NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD
2019 };
2020 enum nk_edit_events {
2021 NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */
2022 NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */
2023 NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */
2024 NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */
2025 NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */
2026 };
2027 NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);
2028 NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);
2029 NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
2030 NK_API void nk_edit_focus(struct nk_context*, nk_flags flags);
2031 NK_API void nk_edit_unfocus(struct nk_context*);
2032 /* =============================================================================
2033 *
2034 * CHART
2035 *
2036 * ============================================================================= */
2037 NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max);
2038 NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max);
2039 NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value);
2040 NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value);
2041 NK_API nk_flags nk_chart_push(struct nk_context*, float);
2042 NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int);
2043 NK_API void nk_chart_end(struct nk_context*);
2044 NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset);
2045 NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset);
2046 /* =============================================================================
2047 *
2048 * POPUP
2049 *
2050 * ============================================================================= */
2051 NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds);
2052 NK_API void nk_popup_close(struct nk_context*);
2053 NK_API void nk_popup_end(struct nk_context*);
2054 /* =============================================================================
2055 *
2056 * COMBOBOX
2057 *
2058 * ============================================================================= */
2059 NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size);
2060 NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size);
2061 NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size);
2062 NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size);
2063 NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size);
2064 NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size);
2065 NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size);
2066 NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size);
2067 /* =============================================================================
2068 *
2069 * ABSTRACT COMBOBOX
2070 *
2071 * ============================================================================= */
2072 NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size);
2073 NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size);
2074 NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size);
2075 NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size);
2076 NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size);
2077 NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size);
2078 NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size);
2079 NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size);
2080 NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size);
2081 NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment);
2082 NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment);
2083 NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
2084 NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment);
2085 NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
2086 NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
2087 NK_API void nk_combo_close(struct nk_context*);
2088 NK_API void nk_combo_end(struct nk_context*);
2089 /* =============================================================================
2090 *
2091 * CONTEXTUAL
2092 *
2093 * ============================================================================= */
2094 NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds);
2095 NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align);
2096 NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align);
2097 NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
2098 NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
2099 NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
2100 NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
2101 NK_API void nk_contextual_close(struct nk_context*);
2102 NK_API void nk_contextual_end(struct nk_context*);
2103 /* =============================================================================
2104 *
2105 * TOOLTIP
2106 *
2107 * ============================================================================= */
2108 NK_API void nk_tooltip(struct nk_context*, const char*);
2109 NK_API int nk_tooltip_begin(struct nk_context*, float width);
2110 NK_API void nk_tooltip_end(struct nk_context*);
2111 /* =============================================================================
2112 *
2113 * MENU
2114 *
2115 * ============================================================================= */
2116 NK_API void nk_menubar_begin(struct nk_context*);
2117 NK_API void nk_menubar_end(struct nk_context*);
2118 NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size);
2119 NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size);
2120 NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size);
2121 NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size);
2122 NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size);
2123 NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size);
2124 NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
2125 NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
2126 NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align);
2127 NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment);
2128 NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
2129 NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
2130 NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
2131 NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
2132 NK_API void nk_menu_close(struct nk_context*);
2133 NK_API void nk_menu_end(struct nk_context*);
2134 /* =============================================================================
2135 *
2136 * STYLE
2137 *
2138 * ============================================================================= */
2139 enum nk_style_colors {
2140 NK_COLOR_TEXT,
2141 NK_COLOR_WINDOW,
2142 NK_COLOR_HEADER,
2143 NK_COLOR_BORDER,
2144 NK_COLOR_BUTTON,
2145 NK_COLOR_BUTTON_HOVER,
2146 NK_COLOR_BUTTON_ACTIVE,
2147 NK_COLOR_TOGGLE,
2148 NK_COLOR_TOGGLE_HOVER,
2149 NK_COLOR_TOGGLE_CURSOR,
2150 NK_COLOR_SELECT,
2151 NK_COLOR_SELECT_ACTIVE,
2152 NK_COLOR_SLIDER,
2153 NK_COLOR_SLIDER_CURSOR,
2154 NK_COLOR_SLIDER_CURSOR_HOVER,
2155 NK_COLOR_SLIDER_CURSOR_ACTIVE,
2156 NK_COLOR_PROPERTY,
2157 NK_COLOR_EDIT,
2158 NK_COLOR_EDIT_CURSOR,
2159 NK_COLOR_COMBO,
2160 NK_COLOR_CHART,
2161 NK_COLOR_CHART_COLOR,
2162 NK_COLOR_CHART_COLOR_HIGHLIGHT,
2163 NK_COLOR_SCROLLBAR,
2164 NK_COLOR_SCROLLBAR_CURSOR,
2165 NK_COLOR_SCROLLBAR_CURSOR_HOVER,
2166 NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,
2167 NK_COLOR_TAB_HEADER,
2168 NK_COLOR_COUNT
2169 };
2170 enum nk_style_cursor {
2171 NK_CURSOR_ARROW,
2172 NK_CURSOR_TEXT,
2173 NK_CURSOR_MOVE,
2174 NK_CURSOR_RESIZE_VERTICAL,
2175 NK_CURSOR_RESIZE_HORIZONTAL,
2176 NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT,
2177 NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT,
2178 NK_CURSOR_COUNT
2179 };
2180 NK_API void nk_style_default(struct nk_context*);
2181 NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*);
2182 NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*);
2183 NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*);
2184 NK_API const char* nk_style_get_color_by_name(enum nk_style_colors);
2185 NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*);
2186 NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor);
2187 NK_API void nk_style_show_cursor(struct nk_context*);
2188 NK_API void nk_style_hide_cursor(struct nk_context*);
2189
2190 NK_API int nk_style_push_font(struct nk_context*, const struct nk_user_font*);
2191 NK_API int nk_style_push_float(struct nk_context*, float*, float);
2192 NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2);
2193 NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item);
2194 NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags);
2195 NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color);
2196
2197 NK_API int nk_style_pop_font(struct nk_context*);
2198 NK_API int nk_style_pop_float(struct nk_context*);
2199 NK_API int nk_style_pop_vec2(struct nk_context*);
2200 NK_API int nk_style_pop_style_item(struct nk_context*);
2201 NK_API int nk_style_pop_flags(struct nk_context*);
2202 NK_API int nk_style_pop_color(struct nk_context*);
2203 /* =============================================================================
2204 *
2205 * COLOR
2206 *
2207 * ============================================================================= */
2208 NK_API struct nk_color nk_rgb(int r, int g, int b);
2209 NK_API struct nk_color nk_rgb_iv(const int *rgb);
2210 NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb);
2211 NK_API struct nk_color nk_rgb_f(float r, float g, float b);
2212 NK_API struct nk_color nk_rgb_fv(const float *rgb);
2213 NK_API struct nk_color nk_rgb_hex(const char *rgb);
2214
2215 NK_API struct nk_color nk_rgba(int r, int g, int b, int a);
2216 NK_API struct nk_color nk_rgba_u32(nk_uint);
2217 NK_API struct nk_color nk_rgba_iv(const int *rgba);
2218 NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba);
2219 NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a);
2220 NK_API struct nk_color nk_rgba_fv(const float *rgba);
2221 NK_API struct nk_color nk_rgba_hex(const char *rgb);
2222
2223 NK_API struct nk_color nk_hsv(int h, int s, int v);
2224 NK_API struct nk_color nk_hsv_iv(const int *hsv);
2225 NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv);
2226 NK_API struct nk_color nk_hsv_f(float h, float s, float v);
2227 NK_API struct nk_color nk_hsv_fv(const float *hsv);
2228
2229 NK_API struct nk_color nk_hsva(int h, int s, int v, int a);
2230 NK_API struct nk_color nk_hsva_iv(const int *hsva);
2231 NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva);
2232 NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a);
2233 NK_API struct nk_color nk_hsva_fv(const float *hsva);
2234
2235 /* color (conversion nuklear --> user) */
2236 NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color);
2237 NK_API void nk_color_fv(float *rgba_out, struct nk_color);
2238 NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color);
2239 NK_API void nk_color_dv(double *rgba_out, struct nk_color);
2240
2241 NK_API nk_uint nk_color_u32(struct nk_color);
2242 NK_API void nk_color_hex_rgba(char *output, struct nk_color);
2243 NK_API void nk_color_hex_rgb(char *output, struct nk_color);
2244
2245 NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color);
2246 NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color);
2247 NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color);
2248 NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color);
2249 NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color);
2250 NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color);
2251
2252 NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color);
2253 NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color);
2254 NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color);
2255 NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color);
2256 NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color);
2257 NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color);
2258 /* =============================================================================
2259 *
2260 * IMAGE
2261 *
2262 * ============================================================================= */
2263 NK_API nk_handle nk_handle_ptr(void*);
2264 NK_API nk_handle nk_handle_id(int);
2265 NK_API struct nk_image nk_image_handle(nk_handle);
2266 NK_API struct nk_image nk_image_ptr(void*);
2267 NK_API struct nk_image nk_image_id(int);
2268 NK_API int nk_image_is_subimage(const struct nk_image* img);
2269 NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region);
2270 NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region);
2271 NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region);
2272 /* =============================================================================
2273 *
2274 * MATH
2275 *
2276 * ============================================================================= */
2277 NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed);
2278 NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading);
2279
2280 NK_API struct nk_vec2 nk_vec2(float x, float y);
2281 NK_API struct nk_vec2 nk_vec2i(int x, int y);
2282 NK_API struct nk_vec2 nk_vec2v(const float *xy);
2283 NK_API struct nk_vec2 nk_vec2iv(const int *xy);
2284
2285 NK_API struct nk_rect nk_get_null_rect(void);
2286 NK_API struct nk_rect nk_rect(float x, float y, float w, float h);
2287 NK_API struct nk_rect nk_recti(int x, int y, int w, int h);
2288 NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size);
2289 NK_API struct nk_rect nk_rectv(const float *xywh);
2290 NK_API struct nk_rect nk_rectiv(const int *xywh);
2291 NK_API struct nk_vec2 nk_rect_pos(struct nk_rect);
2292 NK_API struct nk_vec2 nk_rect_size(struct nk_rect);
2293 /* =============================================================================
2294 *
2295 * STRING
2296 *
2297 * ============================================================================= */
2298 NK_API int nk_strlen(const char *str);
2299 NK_API int nk_stricmp(const char *s1, const char *s2);
2300 NK_API int nk_stricmpn(const char *s1, const char *s2, int n);
2301 NK_API int nk_strtoi(const char *str, const char **endptr);
2302 NK_API float nk_strtof(const char *str, const char **endptr);
2303 NK_API double nk_strtod(const char *str, const char **endptr);
2304 NK_API int nk_strfilter(const char *text, const char *regexp);
2305 NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score);
2306 NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score);
2307 /* =============================================================================
2308 *
2309 * UTF-8
2310 *
2311 * ============================================================================= */
2312 NK_API int nk_utf_decode(const char*, nk_rune*, int);
2313 NK_API int nk_utf_encode(nk_rune, char*, int);
2314 NK_API int nk_utf_len(const char*, int byte_len);
2315 NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len);
2316 /* ===============================================================
2317 *
2318 * FONT
2319 *
2320 * ===============================================================*/
2321 /* Font handling in this library was designed to be quite customizable and lets
2322 you decide what you want to use and what you want to provide. There are three
2323 different ways to use the font atlas. The first two will use your font
2324 handling scheme and only requires essential data to run nuklear. The next
2325 slightly more advanced features is font handling with vertex buffer output.
2326 Finally the most complex API wise is using nuklear's font baking API.
2327
2328 1.) Using your own implementation without vertex buffer output
2329 --------------------------------------------------------------
2330 So first up the easiest way to do font handling is by just providing a
2331 `nk_user_font` struct which only requires the height in pixel of the used
2332 font and a callback to calculate the width of a string. This way of handling
2333 fonts is best fitted for using the normal draw shape command API where you
2334 do all the text drawing yourself and the library does not require any kind
2335 of deeper knowledge about which font handling mechanism you use.
2336 IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist
2337 over the complete life time! I know this sucks but it is currently the only
2338 way to switch between fonts.
2339
2340 float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
2341 {
2342 your_font_type *type = handle.ptr;
2343 float text_width = ...;
2344 return text_width;
2345 }
2346
2347 struct nk_user_font font;
2348 font.userdata.ptr = &your_font_class_or_struct;
2349 font.height = your_font_height;
2350 font.width = your_text_width_calculation;
2351
2352 struct nk_context ctx;
2353 nk_init_default(&ctx, &font);
2354
2355 2.) Using your own implementation with vertex buffer output
2356 --------------------------------------------------------------
2357 While the first approach works fine if you don't want to use the optional
2358 vertex buffer output it is not enough if you do. To get font handling working
2359 for these cases you have to provide two additional parameters inside the
2360 `nk_user_font`. First a texture atlas handle used to draw text as subimages
2361 of a bigger font atlas texture and a callback to query a character's glyph
2362 information (offset, size, ...). So it is still possible to provide your own
2363 font and use the vertex buffer output.
2364
2365 float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
2366 {
2367 your_font_type *type = handle.ptr;
2368 float text_width = ...;
2369 return text_width;
2370 }
2371 void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
2372 {
2373 your_font_type *type = handle.ptr;
2374 glyph.width = ...;
2375 glyph.height = ...;
2376 glyph.xadvance = ...;
2377 glyph.uv[0].x = ...;
2378 glyph.uv[0].y = ...;
2379 glyph.uv[1].x = ...;
2380 glyph.uv[1].y = ...;
2381 glyph.offset.x = ...;
2382 glyph.offset.y = ...;
2383 }
2384
2385 struct nk_user_font font;
2386 font.userdata.ptr = &your_font_class_or_struct;
2387 font.height = your_font_height;
2388 font.width = your_text_width_calculation;
2389 font.query = query_your_font_glyph;
2390 font.texture.id = your_font_texture;
2391
2392 struct nk_context ctx;
2393 nk_init_default(&ctx, &font);
2394
2395 3.) Nuklear font baker
2396 ------------------------------------
2397 The final approach if you do not have a font handling functionality or don't
2398 want to use it in this library is by using the optional font baker.
2399 The font baker APIs can be used to create a font plus font atlas texture
2400 and can be used with or without the vertex buffer output.
2401
2402 It still uses the `nk_user_font` struct and the two different approaches
2403 previously stated still work. The font baker is not located inside
2404 `nk_context` like all other systems since it can be understood as more of
2405 an extension to nuklear and does not really depend on any `nk_context` state.
2406
2407 Font baker need to be initialized first by one of the nk_font_atlas_init_xxx
2408 functions. If you don't care about memory just call the default version
2409 `nk_font_atlas_init_default` which will allocate all memory from the standard library.
2410 If you want to control memory allocation but you don't care if the allocated
2411 memory is temporary and therefore can be freed directly after the baking process
2412 is over or permanent you can call `nk_font_atlas_init`.
2413
2414 After successfully initializing the font baker you can add Truetype(.ttf) fonts from
2415 different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`.
2416 functions. Adding font will permanently store each font, font config and ttf memory block(!)
2417 inside the font atlas and allows to reuse the font atlas. If you don't want to reuse
2418 the font baker by for example adding additional fonts you can call
2419 `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end).
2420
2421 As soon as you added all fonts you wanted you can now start the baking process
2422 for every selected glyph to image by calling `nk_font_atlas_bake`.
2423 The baking process returns image memory, width and height which can be used to
2424 either create your own image object or upload it to any graphics library.
2425 No matter which case you finally have to call `nk_font_atlas_end` which
2426 will free all temporary memory including the font atlas image so make sure
2427 you created our texture beforehand. `nk_font_atlas_end` requires a handle
2428 to your font texture or object and optionally fills a `struct nk_draw_null_texture`
2429 which can be used for the optional vertex output. If you don't want it just
2430 set the argument to `NULL`.
2431
2432 At this point you are done and if you don't want to reuse the font atlas you
2433 can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration
2434 memory. Finally if you don't use the font atlas and any of it's fonts anymore
2435 you need to call `nk_font_atlas_clear` to free all memory still being used.
2436
2437 struct nk_font_atlas atlas;
2438 nk_font_atlas_init_default(&atlas);
2439 nk_font_atlas_begin(&atlas);
2440 nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0);
2441 nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0);
2442 const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32);
2443 nk_font_atlas_end(&atlas, nk_handle_id(texture), 0);
2444
2445 struct nk_context ctx;
2446 nk_init_default(&ctx, &font->handle);
2447 while (1) {
2448
2449 }
2450 nk_font_atlas_clear(&atlas);
2451
2452 The font baker API is probably the most complex API inside this library and
2453 I would suggest reading some of my examples `example/` to get a grip on how
2454 to use the font atlas. There are a number of details I left out. For example
2455 how to merge fonts, configure a font with `nk_font_config` to use other languages,
2456 use another texture coordinate format and a lot more:
2457
2458 struct nk_font_config cfg = nk_font_config(font_pixel_height);
2459 cfg.merge_mode = nk_false or nk_true;
2460 cfg.range = nk_font_korean_glyph_ranges();
2461 cfg.coord_type = NK_COORD_PIXEL;
2462 nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg);
2463
2464 */
2465 struct nk_user_font_glyph;
2466 typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len);
2467 typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,
2468 struct nk_user_font_glyph *glyph,
2469 nk_rune codepoint, nk_rune next_codepoint);
2470
2471 #if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT)
2472 struct nk_user_font_glyph {
2473 struct nk_vec2 uv[2];
2474 /* texture coordinates */
2475 struct nk_vec2 offset;
2476 /* offset between top left and glyph */
2477 float width, height;
2478 /* size of the glyph */
2479 float xadvance;
2480 /* offset to the next glyph */
2481 };
2482 #endif
2483
2484 struct nk_user_font {
2485 nk_handle userdata;
2486 /* user provided font handle */
2487 float height;
2488 /* max height of the font */
2489 nk_text_width_f width;
2490 /* font string width in pixel callback */
2491 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
2492 nk_query_font_glyph_f query;
2493 /* font glyph callback to query drawing info */
2494 nk_handle texture;
2495 /* texture handle to the used font atlas or texture */
2496 #endif
2497 };
2498
2499 #ifdef NK_INCLUDE_FONT_BAKING
2500 enum nk_font_coord_type {
2501 NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */
2502 NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */
2503 };
2504
2505 struct nk_baked_font {
2506 float height;
2507 /* height of the font */
2508 float ascent, descent;
2509 /* font glyphs ascent and descent */
2510 nk_rune glyph_offset;
2511 /* glyph array offset inside the font glyph baking output array */
2512 nk_rune glyph_count;
2513 /* number of glyphs of this font inside the glyph baking array output */
2514 const nk_rune *ranges;
2515 /* font codepoint ranges as pairs of (from/to) and 0 as last element */
2516 };
2517
2518 struct nk_font_config {
2519 struct nk_font_config *next;
2520 /* NOTE: only used internally */
2521 void *ttf_blob;
2522 /* pointer to loaded TTF file memory block.
2523 * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */
2524 nk_size ttf_size;
2525 /* size of the loaded TTF file memory block
2526 * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */
2527
2528 unsigned char ttf_data_owned_by_atlas;
2529 /* used inside font atlas: default to: 0*/
2530 unsigned char merge_mode;
2531 /* merges this font into the last font */
2532 unsigned char pixel_snap;
2533 /* align every character to pixel boundary (if true set oversample (1,1)) */
2534 unsigned char oversample_v, oversample_h;
2535 /* rasterize at hight quality for sub-pixel position */
2536 unsigned char padding[3];
2537
2538 float size;
2539 /* baked pixel height of the font */
2540 enum nk_font_coord_type coord_type;
2541 /* texture coordinate format with either pixel or UV coordinates */
2542 struct nk_vec2 spacing;
2543 /* extra pixel spacing between glyphs */
2544 const nk_rune *range;
2545 /* list of unicode ranges (2 values per range, zero terminated) */
2546 struct nk_baked_font *font;
2547 /* font to setup in the baking process: NOTE: not needed for font atlas */
2548 nk_rune fallback_glyph;
2549 /* fallback glyph to use if a given rune is not found */
2550 };
2551
2552 struct nk_font_glyph {
2553 nk_rune codepoint;
2554 float xadvance;
2555 float x0, y0, x1, y1, w, h;
2556 float u0, v0, u1, v1;
2557 };
2558
2559 struct nk_font {
2560 struct nk_font *next;
2561 struct nk_user_font handle;
2562 struct nk_baked_font info;
2563 float scale;
2564 struct nk_font_glyph *glyphs;
2565 const struct nk_font_glyph *fallback;
2566 nk_rune fallback_codepoint;
2567 nk_handle texture;
2568 struct nk_font_config *config;
2569 };
2570
2571 enum nk_font_atlas_format {
2572 NK_FONT_ATLAS_ALPHA8,
2573 NK_FONT_ATLAS_RGBA32
2574 };
2575
2576 struct nk_font_atlas {
2577 void *pixel;
2578 int tex_width;
2579 int tex_height;
2580
2581 struct nk_allocator permanent;
2582 struct nk_allocator temporary;
2583
2584 struct nk_recti custom;
2585 struct nk_cursor cursors[NK_CURSOR_COUNT];
2586
2587 int glyph_count;
2588 struct nk_font_glyph *glyphs;
2589 struct nk_font *default_font;
2590 struct nk_font *fonts;
2591 struct nk_font_config *config;
2592 int font_num;
2593 };
2594
2595 /* some language glyph codepoint ranges */
2596 NK_API const nk_rune *nk_font_default_glyph_ranges(void);
2597 NK_API const nk_rune *nk_font_chinese_glyph_ranges(void);
2598 NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void);
2599 NK_API const nk_rune *nk_font_korean_glyph_ranges(void);
2600
2601 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2602 NK_API void nk_font_atlas_init_default(struct nk_font_atlas*);
2603 #endif
2604 NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*);
2605 NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient);
2606 NK_API void nk_font_atlas_begin(struct nk_font_atlas*);
2607 NK_API struct nk_font_config nk_font_config(float pixel_height);
2608 NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*);
2609 #ifdef NK_INCLUDE_DEFAULT_FONT
2610 NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*);
2611 #endif
2612 NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config);
2613 #ifdef NK_INCLUDE_STANDARD_IO
2614 NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*);
2615 #endif
2616 NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*);
2617 NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config);
2618 NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format);
2619 NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*);
2620 NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode);
2621 NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas);
2622 NK_API void nk_font_atlas_clear(struct nk_font_atlas*);
2623
2624 #endif
2625
2626 /* ==============================================================
2627 *
2628 * MEMORY BUFFER
2629 *
2630 * ===============================================================*/
2631 /* A basic (double)-buffer with linear allocation and resetting as only
2632 freeing policy. The buffer's main purpose is to control all memory management
2633 inside the GUI toolkit and still leave memory control as much as possible in
2634 the hand of the user while also making sure the library is easy to use if
2635 not as much control is needed.
2636 In general all memory inside this library can be provided from the user in
2637 three different ways.
2638
2639 The first way and the one providing most control is by just passing a fixed
2640 size memory block. In this case all control lies in the hand of the user
2641 since he can exactly control where the memory comes from and how much memory
2642 the library should consume. Of course using the fixed size API removes the
2643 ability to automatically resize a buffer if not enough memory is provided so
2644 you have to take over the resizing. While being a fixed sized buffer sounds
2645 quite limiting, it is very effective in this library since the actual memory
2646 consumption is quite stable and has a fixed upper bound for a lot of cases.
2647
2648 If you don't want to think about how much memory the library should allocate
2649 at all time or have a very dynamic UI with unpredictable memory consumption
2650 habits but still want control over memory allocation you can use the dynamic
2651 allocator based API. The allocator consists of two callbacks for allocating
2652 and freeing memory and optional userdata so you can plugin your own allocator.
2653
2654 The final and easiest way can be used by defining
2655 NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory
2656 allocation functions malloc and free and takes over complete control over
2657 memory in this library.
2658 */
2659 struct nk_memory_status {
2660 void *memory;
2661 unsigned int type;
2662 nk_size size;
2663 nk_size allocated;
2664 nk_size needed;
2665 nk_size calls;
2666 };
2667
2668 enum nk_allocation_type {
2669 NK_BUFFER_FIXED,
2670 NK_BUFFER_DYNAMIC
2671 };
2672
2673 enum nk_buffer_allocation_type {
2674 NK_BUFFER_FRONT,
2675 NK_BUFFER_BACK,
2676 NK_BUFFER_MAX
2677 };
2678
2679 struct nk_buffer_marker {
2680 int active;
2681 nk_size offset;
2682 };
2683
2684 struct nk_memory {void *ptr;nk_size size;};
2685 struct nk_buffer {
2686 struct nk_buffer_marker marker[NK_BUFFER_MAX];
2687 /* buffer marker to free a buffer to a certain offset */
2688 struct nk_allocator pool;
2689 /* allocator callback for dynamic buffers */
2690 enum nk_allocation_type type;
2691 /* memory management type */
2692 struct nk_memory memory;
2693 /* memory and size of the current memory block */
2694 float grow_factor;
2695 /* growing factor for dynamic memory management */
2696 nk_size allocated;
2697 /* total amount of memory allocated */
2698 nk_size needed;
2699 /* totally consumed memory given that enough memory is present */
2700 nk_size calls;
2701 /* number of allocation calls */
2702 nk_size size;
2703 /* current size of the buffer */
2704 };
2705
2706 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2707 NK_API void nk_buffer_init_default(struct nk_buffer*);
2708 #endif
2709 NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size);
2710 NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size);
2711 NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*);
2712 NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align);
2713 NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type);
2714 NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type);
2715 NK_API void nk_buffer_clear(struct nk_buffer*);
2716 NK_API void nk_buffer_free(struct nk_buffer*);
2717 NK_API void *nk_buffer_memory(struct nk_buffer*);
2718 NK_API const void *nk_buffer_memory_const(const struct nk_buffer*);
2719 NK_API nk_size nk_buffer_total(struct nk_buffer*);
2720
2721 /* ==============================================================
2722 *
2723 * STRING
2724 *
2725 * ===============================================================*/
2726 /* Basic string buffer which is only used in context with the text editor
2727 * to manage and manipulate dynamic or fixed size string content. This is _NOT_
2728 * the default string handling method. The only instance you should have any contact
2729 * with this API is if you interact with an `nk_text_edit` object inside one of the
2730 * copy and paste functions and even there only for more advanced cases. */
2731 struct nk_str {
2732 struct nk_buffer buffer;
2733 int len; /* in codepoints/runes/glyphs */
2734 };
2735
2736 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2737 NK_API void nk_str_init_default(struct nk_str*);
2738 #endif
2739 NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size);
2740 NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size);
2741 NK_API void nk_str_clear(struct nk_str*);
2742 NK_API void nk_str_free(struct nk_str*);
2743
2744 NK_API int nk_str_append_text_char(struct nk_str*, const char*, int);
2745 NK_API int nk_str_append_str_char(struct nk_str*, const char*);
2746 NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int);
2747 NK_API int nk_str_append_str_utf8(struct nk_str*, const char*);
2748 NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int);
2749 NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*);
2750
2751 NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int);
2752 NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int);
2753
2754 NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int);
2755 NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*);
2756 NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int);
2757 NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*);
2758 NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int);
2759 NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*);
2760
2761 NK_API void nk_str_remove_chars(struct nk_str*, int len);
2762 NK_API void nk_str_remove_runes(struct nk_str *str, int len);
2763 NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len);
2764 NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len);
2765
2766 NK_API char *nk_str_at_char(struct nk_str*, int pos);
2767 NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len);
2768 NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos);
2769 NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos);
2770 NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len);
2771
2772 NK_API char *nk_str_get(struct nk_str*);
2773 NK_API const char *nk_str_get_const(const struct nk_str*);
2774 NK_API int nk_str_len(struct nk_str*);
2775 NK_API int nk_str_len_char(struct nk_str*);
2776
2777 /*===============================================================
2778 *
2779 * TEXT EDITOR
2780 *
2781 * ===============================================================*/
2782 /* Editing text in this library is handled by either `nk_edit_string` or
2783 * `nk_edit_buffer`. But like almost everything in this library there are multiple
2784 * ways of doing it and a balance between control and ease of use with memory
2785 * as well as functionality controlled by flags.
2786 *
2787 * This library generally allows three different levels of memory control:
2788 * First of is the most basic way of just providing a simple char array with
2789 * string length. This method is probably the easiest way of handling simple
2790 * user text input. Main upside is complete control over memory while the biggest
2791 * downside in comparison with the other two approaches is missing undo/redo.
2792 *
2793 * For UIs that require undo/redo the second way was created. It is based on
2794 * a fixed size nk_text_edit struct, which has an internal undo/redo stack.
2795 * This is mainly useful if you want something more like a text editor but don't want
2796 * to have a dynamically growing buffer.
2797 *
2798 * The final way is using a dynamically growing nk_text_edit struct, which
2799 * has both a default version if you don't care where memory comes from and an
2800 * allocator version if you do. While the text editor is quite powerful for its
2801 * complexity I would not recommend editing gigabytes of data with it.
2802 * It is rather designed for uses cases which make sense for a GUI library not for
2803 * an full blown text editor.
2804 */
2805 #ifndef NK_TEXTEDIT_UNDOSTATECOUNT
2806 #define NK_TEXTEDIT_UNDOSTATECOUNT 99
2807 #endif
2808
2809 #ifndef NK_TEXTEDIT_UNDOCHARCOUNT
2810 #define NK_TEXTEDIT_UNDOCHARCOUNT 999
2811 #endif
2812
2813 struct nk_text_edit;
2814 struct nk_clipboard {
2815 nk_handle userdata;
2816 nk_plugin_paste paste;
2817 nk_plugin_copy copy;
2818 };
2819
2820 struct nk_text_undo_record {
2821 int where;
2822 short insert_length;
2823 short delete_length;
2824 short char_storage;
2825 };
2826
2827 struct nk_text_undo_state {
2828 struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT];
2829 nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT];
2830 short undo_point;
2831 short redo_point;
2832 short undo_char_point;
2833 short redo_char_point;
2834 };
2835
2836 enum nk_text_edit_type {
2837 NK_TEXT_EDIT_SINGLE_LINE,
2838 NK_TEXT_EDIT_MULTI_LINE
2839 };
2840
2841 enum nk_text_edit_mode {
2842 NK_TEXT_EDIT_MODE_VIEW,
2843 NK_TEXT_EDIT_MODE_INSERT,
2844 NK_TEXT_EDIT_MODE_REPLACE
2845 };
2846
2847 struct nk_text_edit {
2848 struct nk_clipboard clip;
2849 struct nk_str string;
2850 nk_plugin_filter filter;
2851 struct nk_vec2 scrollbar;
2852
2853 int cursor;
2854 int select_start;
2855 int select_end;
2856 unsigned char mode;
2857 unsigned char cursor_at_end_of_line;
2858 unsigned char initialized;
2859 unsigned char has_preferred_x;
2860 unsigned char single_line;
2861 unsigned char active;
2862 unsigned char padding1;
2863 float preferred_x;
2864 struct nk_text_undo_state undo;
2865 };
2866
2867 /* filter function */
2868 NK_API int nk_filter_default(const struct nk_text_edit*, nk_rune unicode);
2869 NK_API int nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode);
2870 NK_API int nk_filter_float(const struct nk_text_edit*, nk_rune unicode);
2871 NK_API int nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode);
2872 NK_API int nk_filter_hex(const struct nk_text_edit*, nk_rune unicode);
2873 NK_API int nk_filter_oct(const struct nk_text_edit*, nk_rune unicode);
2874 NK_API int nk_filter_binary(const struct nk_text_edit*, nk_rune unicode);
2875
2876 /* text editor */
2877 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
2878 NK_API void nk_textedit_init_default(struct nk_text_edit*);
2879 #endif
2880 NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size);
2881 NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size);
2882 NK_API void nk_textedit_free(struct nk_text_edit*);
2883 NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len);
2884 NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len);
2885 NK_API void nk_textedit_delete_selection(struct nk_text_edit*);
2886 NK_API void nk_textedit_select_all(struct nk_text_edit*);
2887 NK_API int nk_textedit_cut(struct nk_text_edit*);
2888 NK_API int nk_textedit_paste(struct nk_text_edit*, char const*, int len);
2889 NK_API void nk_textedit_undo(struct nk_text_edit*);
2890 NK_API void nk_textedit_redo(struct nk_text_edit*);
2891
2892 /* ===============================================================
2893 *
2894 * DRAWING
2895 *
2896 * ===============================================================*/
2897 /* This library was designed to be render backend agnostic so it does
2898 not draw anything to screen. Instead all drawn shapes, widgets
2899 are made of, are buffered into memory and make up a command queue.
2900 Each frame therefore fills the command buffer with draw commands
2901 that then need to be executed by the user and his own render backend.
2902 After that the command buffer needs to be cleared and a new frame can be
2903 started. It is probably important to note that the command buffer is the main
2904 drawing API and the optional vertex buffer API only takes this format and
2905 converts it into a hardware accessible format.
2906
2907 To use the command queue to draw your own widgets you can access the
2908 command buffer of each window by calling `nk_window_get_canvas` after
2909 previously having called `nk_begin`:
2910
2911 void draw_red_rectangle_widget(struct nk_context *ctx)
2912 {
2913 struct nk_command_buffer *canvas;
2914 struct nk_input *input = &ctx->input;
2915 canvas = nk_window_get_canvas(ctx);
2916
2917 struct nk_rect space;
2918 enum nk_widget_layout_states state;
2919 state = nk_widget(&space, ctx);
2920 if (!state) return;
2921
2922 if (state != NK_WIDGET_ROM)
2923 update_your_widget_by_user_input(...);
2924 nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0));
2925 }
2926
2927 if (nk_begin(...)) {
2928 nk_layout_row_dynamic(ctx, 25, 1);
2929 draw_red_rectangle_widget(ctx);
2930 }
2931 nk_end(..)
2932
2933 Important to know if you want to create your own widgets is the `nk_widget`
2934 call. It allocates space on the panel reserved for this widget to be used,
2935 but also returns the state of the widget space. If your widget is not seen and does
2936 not have to be updated it is '0' and you can just return. If it only has
2937 to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both
2938 update and draw your widget. The reason for separating is to only draw and
2939 update what is actually necessary which is crucial for performance.
2940 */
2941 enum nk_command_type {
2942 NK_COMMAND_NOP,
2943 NK_COMMAND_SCISSOR,
2944 NK_COMMAND_LINE,
2945 NK_COMMAND_CURVE,
2946 NK_COMMAND_RECT,
2947 NK_COMMAND_RECT_FILLED,
2948 NK_COMMAND_RECT_MULTI_COLOR,
2949 NK_COMMAND_CIRCLE,
2950 NK_COMMAND_CIRCLE_FILLED,
2951 NK_COMMAND_ARC,
2952 NK_COMMAND_ARC_FILLED,
2953 NK_COMMAND_TRIANGLE,
2954 NK_COMMAND_TRIANGLE_FILLED,
2955 NK_COMMAND_POLYGON,
2956 NK_COMMAND_POLYGON_FILLED,
2957 NK_COMMAND_POLYLINE,
2958 NK_COMMAND_TEXT,
2959 NK_COMMAND_IMAGE,
2960 NK_COMMAND_CUSTOM
2961 };
2962
2963 /* command base and header of every command inside the buffer */
2964 struct nk_command {
2965 enum nk_command_type type;
2966 nk_size next;
2967 #ifdef NK_INCLUDE_COMMAND_USERDATA
2968 nk_handle userdata;
2969 #endif
2970 };
2971
2972 struct nk_command_scissor {
2973 struct nk_command header;
2974 short x, y;
2975 unsigned short w, h;
2976 };
2977
2978 struct nk_command_line {
2979 struct nk_command header;
2980 unsigned short line_thickness;
2981 struct nk_vec2i begin;
2982 struct nk_vec2i end;
2983 struct nk_color color;
2984 };
2985
2986 struct nk_command_curve {
2987 struct nk_command header;
2988 unsigned short line_thickness;
2989 struct nk_vec2i begin;
2990 struct nk_vec2i end;
2991 struct nk_vec2i ctrl[2];
2992 struct nk_color color;
2993 };
2994
2995 struct nk_command_rect {
2996 struct nk_command header;
2997 unsigned short rounding;
2998 unsigned short line_thickness;
2999 short x, y;
3000 unsigned short w, h;
3001 struct nk_color color;
3002 };
3003
3004 struct nk_command_rect_filled {
3005 struct nk_command header;
3006 unsigned short rounding;
3007 short x, y;
3008 unsigned short w, h;
3009 struct nk_color color;
3010 };
3011
3012 struct nk_command_rect_multi_color {
3013 struct nk_command header;
3014 short x, y;
3015 unsigned short w, h;
3016 struct nk_color left;
3017 struct nk_color top;
3018 struct nk_color bottom;
3019 struct nk_color right;
3020 };
3021
3022 struct nk_command_triangle {
3023 struct nk_command header;
3024 unsigned short line_thickness;
3025 struct nk_vec2i a;
3026 struct nk_vec2i b;
3027 struct nk_vec2i c;
3028 struct nk_color color;
3029 };
3030
3031 struct nk_command_triangle_filled {
3032 struct nk_command header;
3033 struct nk_vec2i a;
3034 struct nk_vec2i b;
3035 struct nk_vec2i c;
3036 struct nk_color color;
3037 };
3038
3039 struct nk_command_circle {
3040 struct nk_command header;
3041 short x, y;
3042 unsigned short line_thickness;
3043 unsigned short w, h;
3044 struct nk_color color;
3045 };
3046
3047 struct nk_command_circle_filled {
3048 struct nk_command header;
3049 short x, y;
3050 unsigned short w, h;
3051 struct nk_color color;
3052 };
3053
3054 struct nk_command_arc {
3055 struct nk_command header;
3056 short cx, cy;
3057 unsigned short r;
3058 unsigned short line_thickness;
3059 float a[2];
3060 struct nk_color color;
3061 };
3062
3063 struct nk_command_arc_filled {
3064 struct nk_command header;
3065 short cx, cy;
3066 unsigned short r;
3067 float a[2];
3068 struct nk_color color;
3069 };
3070
3071 struct nk_command_polygon {
3072 struct nk_command header;
3073 struct nk_color color;
3074 unsigned short line_thickness;
3075 unsigned short point_count;
3076 struct nk_vec2i points[1];
3077 };
3078
3079 struct nk_command_polygon_filled {
3080 struct nk_command header;
3081 struct nk_color color;
3082 unsigned short point_count;
3083 struct nk_vec2i points[1];
3084 };
3085
3086 struct nk_command_polyline {
3087 struct nk_command header;
3088 struct nk_color color;
3089 unsigned short line_thickness;
3090 unsigned short point_count;
3091 struct nk_vec2i points[1];
3092 };
3093
3094 struct nk_command_image {
3095 struct nk_command header;
3096 short x, y;
3097 unsigned short w, h;
3098 struct nk_image img;
3099 struct nk_color col;
3100 };
3101
3102 typedef void (*nk_command_custom_callback)(void *canvas, short x,short y,
3103 unsigned short w, unsigned short h, nk_handle callback_data);
3104 struct nk_command_custom {
3105 struct nk_command header;
3106 short x, y;
3107 unsigned short w, h;
3108 nk_handle callback_data;
3109 nk_command_custom_callback callback;
3110 };
3111
3112 struct nk_command_text {
3113 struct nk_command header;
3114 const struct nk_user_font *font;
3115 struct nk_color background;
3116 struct nk_color foreground;
3117 short x, y;
3118 unsigned short w, h;
3119 float height;
3120 int length;
3121 char string[1];
3122 };
3123
3124 enum nk_command_clipping {
3125 NK_CLIPPING_OFF = nk_false,
3126 NK_CLIPPING_ON = nk_true
3127 };
3128
3129 struct nk_command_buffer {
3130 struct nk_buffer *base;
3131 struct nk_rect clip;
3132 int use_clipping;
3133 nk_handle userdata;
3134 nk_size begin, end, last;
3135 };
3136
3137 /* shape outlines */
3138 NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color);
3139 NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color);
3140 NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color);
3141 NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color);
3142 NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color);
3143 NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color);
3144 NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col);
3145 NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color);
3146
3147 /* filled shades */
3148 NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color);
3149 NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);
3150 NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color);
3151 NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color);
3152 NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color);
3153 NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color);
3154
3155 /* misc */
3156 NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);
3157 NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color);
3158 NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);
3159 NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);
3160
3161 /* ===============================================================
3162 *
3163 * INPUT
3164 *
3165 * ===============================================================*/
3166 struct nk_mouse_button {
3167 int down;
3168 unsigned int clicked;
3169 struct nk_vec2 clicked_pos;
3170 };
3171 struct nk_mouse {
3172 struct nk_mouse_button buttons[NK_BUTTON_MAX];
3173 struct nk_vec2 pos;
3174 struct nk_vec2 prev;
3175 struct nk_vec2 delta;
3176 struct nk_vec2 scroll_delta;
3177 unsigned char grab;
3178 unsigned char grabbed;
3179 unsigned char ungrab;
3180 };
3181
3182 struct nk_key {
3183 int down;
3184 unsigned int clicked;
3185 };
3186 struct nk_keyboard {
3187 struct nk_key keys[NK_KEY_MAX];
3188 char text[NK_INPUT_MAX];
3189 int text_len;
3190 };
3191
3192 struct nk_input {
3193 struct nk_keyboard keyboard;
3194 struct nk_mouse mouse;
3195 };
3196
3197 NK_API int nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons);
3198 NK_API int nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
3199 NK_API int nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, int down);
3200 NK_API int nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
3201 NK_API int nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, int down);
3202 NK_API int nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect);
3203 NK_API int nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect);
3204 NK_API int nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect);
3205 NK_API int nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect);
3206 NK_API int nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons);
3207 NK_API int nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons);
3208 NK_API int nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons);
3209 NK_API int nk_input_is_key_pressed(const struct nk_input*, enum nk_keys);
3210 NK_API int nk_input_is_key_released(const struct nk_input*, enum nk_keys);
3211 NK_API int nk_input_is_key_down(const struct nk_input*, enum nk_keys);
3212
3213 /* ===============================================================
3214 *
3215 * DRAW LIST
3216 *
3217 * ===============================================================*/
3218 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
3219 /* The optional vertex buffer draw list provides a 2D drawing context
3220 with antialiasing functionality which takes basic filled or outlined shapes
3221 or a path and outputs vertexes, elements and draw commands.
3222 The actual draw list API is not required to be used directly while using this
3223 library since converting the default library draw command output is done by
3224 just calling `nk_convert` but I decided to still make this library accessible
3225 since it can be useful.
3226
3227 The draw list is based on a path buffering and polygon and polyline
3228 rendering API which allows a lot of ways to draw 2D content to screen.
3229 In fact it is probably more powerful than needed but allows even more crazy
3230 things than this library provides by default.
3231 */
3232 typedef nk_ushort nk_draw_index;
3233 enum nk_draw_list_stroke {
3234 NK_STROKE_OPEN = nk_false,
3235 /* build up path has no connection back to the beginning */
3236 NK_STROKE_CLOSED = nk_true
3237 /* build up path has a connection back to the beginning */
3238 };
3239
3240 enum nk_draw_vertex_layout_attribute {
3241 NK_VERTEX_POSITION,
3242 NK_VERTEX_COLOR,
3243 NK_VERTEX_TEXCOORD,
3244 NK_VERTEX_ATTRIBUTE_COUNT
3245 };
3246
3247 enum nk_draw_vertex_layout_format {
3248 NK_FORMAT_SCHAR,
3249 NK_FORMAT_SSHORT,
3250 NK_FORMAT_SINT,
3251 NK_FORMAT_UCHAR,
3252 NK_FORMAT_USHORT,
3253 NK_FORMAT_UINT,
3254 NK_FORMAT_FLOAT,
3255 NK_FORMAT_DOUBLE,
3256
3257 NK_FORMAT_COLOR_BEGIN,
3258 NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN,
3259 NK_FORMAT_R16G15B16,
3260 NK_FORMAT_R32G32B32,
3261
3262 NK_FORMAT_R8G8B8A8,
3263 NK_FORMAT_B8G8R8A8,
3264 NK_FORMAT_R16G15B16A16,
3265 NK_FORMAT_R32G32B32A32,
3266 NK_FORMAT_R32G32B32A32_FLOAT,
3267 NK_FORMAT_R32G32B32A32_DOUBLE,
3268
3269 NK_FORMAT_RGB32,
3270 NK_FORMAT_RGBA32,
3271 NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32,
3272 NK_FORMAT_COUNT
3273 };
3274
3275 #define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0
3276 struct nk_draw_vertex_layout_element {
3277 enum nk_draw_vertex_layout_attribute attribute;
3278 enum nk_draw_vertex_layout_format format;
3279 nk_size offset;
3280 };
3281
3282 struct nk_draw_command {
3283 unsigned int elem_count;
3284 /* number of elements in the current draw batch */
3285 struct nk_rect clip_rect;
3286 /* current screen clipping rectangle */
3287 nk_handle texture;
3288 /* current texture to set */
3289 #ifdef NK_INCLUDE_COMMAND_USERDATA
3290 nk_handle userdata;
3291 #endif
3292 };
3293
3294 struct nk_draw_list {
3295 struct nk_rect clip_rect;
3296 struct nk_vec2 circle_vtx[12];
3297 struct nk_convert_config config;
3298
3299 struct nk_buffer *buffer;
3300 struct nk_buffer *vertices;
3301 struct nk_buffer *elements;
3302
3303 unsigned int element_count;
3304 unsigned int vertex_count;
3305 unsigned int cmd_count;
3306 nk_size cmd_offset;
3307
3308 unsigned int path_count;
3309 unsigned int path_offset;
3310
3311 enum nk_anti_aliasing line_AA;
3312 enum nk_anti_aliasing shape_AA;
3313
3314 #ifdef NK_INCLUDE_COMMAND_USERDATA
3315 nk_handle userdata;
3316 #endif
3317 };
3318
3319 /* draw list */
3320 NK_API void nk_draw_list_init(struct nk_draw_list*);
3321 NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa);
3322 NK_API void nk_draw_list_clear(struct nk_draw_list*);
3323
3324 /* drawing */
3325 #define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can))
3326 NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*);
3327 NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*);
3328 NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*);
3329 NK_API void nk_draw_list_clear(struct nk_draw_list *list);
3330
3331 /* path */
3332 NK_API void nk_draw_list_path_clear(struct nk_draw_list*);
3333 NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos);
3334 NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max);
3335 NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments);
3336 NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding);
3337 NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments);
3338 NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color);
3339 NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness);
3340
3341 /* stroke */
3342 NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness);
3343 NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness);
3344 NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness);
3345 NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness);
3346 NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness);
3347 NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing);
3348
3349 /* fill */
3350 NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding);
3351 NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);
3352 NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color);
3353 NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs);
3354 NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing);
3355
3356 /* misc */
3357 NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color);
3358 NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color);
3359 #ifdef NK_INCLUDE_COMMAND_USERDATA
3360 NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata);
3361 #endif
3362
3363 #endif
3364
3365 /* ===============================================================
3366 *
3367 * GUI
3368 *
3369 * ===============================================================*/
3370 enum nk_style_item_type {
3371 NK_STYLE_ITEM_COLOR,
3372 NK_STYLE_ITEM_IMAGE
3373 };
3374
3375 union nk_style_item_data {
3376 struct nk_image image;
3377 struct nk_color color;
3378 };
3379
3380 struct nk_style_item {
3381 enum nk_style_item_type type;
3382 union nk_style_item_data data;
3383 };
3384
3385 struct nk_style_text {
3386 struct nk_color color;
3387 struct nk_vec2 padding;
3388 };
3389
3390 struct nk_style_button {
3391 /* background */
3392 struct nk_style_item normal;
3393 struct nk_style_item hover;
3394 struct nk_style_item active;
3395 struct nk_color border_color;
3396
3397 /* text */
3398 struct nk_color text_background;
3399 struct nk_color text_normal;
3400 struct nk_color text_hover;
3401 struct nk_color text_active;
3402 nk_flags text_alignment;
3403
3404 /* properties */
3405 float border;
3406 float rounding;
3407 struct nk_vec2 padding;
3408 struct nk_vec2 image_padding;
3409 struct nk_vec2 touch_padding;
3410
3411 /* optional user callbacks */
3412 nk_handle userdata;
3413 void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata);
3414 void(*draw_end)(struct nk_command_buffer*, nk_handle userdata);
3415 };
3416
3417 struct nk_style_toggle {
3418 /* background */
3419 struct nk_style_item normal;
3420 struct nk_style_item hover;
3421 struct nk_style_item active;
3422 struct nk_color border_color;
3423
3424 /* cursor */
3425 struct nk_style_item cursor_normal;
3426 struct nk_style_item cursor_hover;
3427
3428 /* text */
3429 struct nk_color text_normal;
3430 struct nk_color text_hover;
3431 struct nk_color text_active;
3432 struct nk_color text_background;
3433 nk_flags text_alignment;
3434
3435 /* properties */
3436 struct nk_vec2 padding;
3437 struct nk_vec2 touch_padding;
3438 float spacing;
3439 float border;
3440
3441 /* optional user callbacks */
3442 nk_handle userdata;
3443 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3444 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3445 };
3446
3447 struct nk_style_selectable {
3448 /* background (inactive) */
3449 struct nk_style_item normal;
3450 struct nk_style_item hover;
3451 struct nk_style_item pressed;
3452
3453 /* background (active) */
3454 struct nk_style_item normal_active;
3455 struct nk_style_item hover_active;
3456 struct nk_style_item pressed_active;
3457
3458 /* text color (inactive) */
3459 struct nk_color text_normal;
3460 struct nk_color text_hover;
3461 struct nk_color text_pressed;
3462
3463 /* text color (active) */
3464 struct nk_color text_normal_active;
3465 struct nk_color text_hover_active;
3466 struct nk_color text_pressed_active;
3467 struct nk_color text_background;
3468 nk_flags text_alignment;
3469
3470 /* properties */
3471 float rounding;
3472 struct nk_vec2 padding;
3473 struct nk_vec2 touch_padding;
3474 struct nk_vec2 image_padding;
3475
3476 /* optional user callbacks */
3477 nk_handle userdata;
3478 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3479 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3480 };
3481
3482 struct nk_style_slider {
3483 /* background */
3484 struct nk_style_item normal;
3485 struct nk_style_item hover;
3486 struct nk_style_item active;
3487 struct nk_color border_color;
3488
3489 /* background bar */
3490 struct nk_color bar_normal;
3491 struct nk_color bar_hover;
3492 struct nk_color bar_active;
3493 struct nk_color bar_filled;
3494
3495 /* cursor */
3496 struct nk_style_item cursor_normal;
3497 struct nk_style_item cursor_hover;
3498 struct nk_style_item cursor_active;
3499
3500 /* properties */
3501 float border;
3502 float rounding;
3503 float bar_height;
3504 struct nk_vec2 padding;
3505 struct nk_vec2 spacing;
3506 struct nk_vec2 cursor_size;
3507
3508 /* optional buttons */
3509 int show_buttons;
3510 struct nk_style_button inc_button;
3511 struct nk_style_button dec_button;
3512 enum nk_symbol_type inc_symbol;
3513 enum nk_symbol_type dec_symbol;
3514
3515 /* optional user callbacks */
3516 nk_handle userdata;
3517 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3518 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3519 };
3520
3521 struct nk_style_progress {
3522 /* background */
3523 struct nk_style_item normal;
3524 struct nk_style_item hover;
3525 struct nk_style_item active;
3526 struct nk_color border_color;
3527
3528 /* cursor */
3529 struct nk_style_item cursor_normal;
3530 struct nk_style_item cursor_hover;
3531 struct nk_style_item cursor_active;
3532 struct nk_color cursor_border_color;
3533
3534 /* properties */
3535 float rounding;
3536 float border;
3537 float cursor_border;
3538 float cursor_rounding;
3539 struct nk_vec2 padding;
3540
3541 /* optional user callbacks */
3542 nk_handle userdata;
3543 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3544 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3545 };
3546
3547 struct nk_style_scrollbar {
3548 /* background */
3549 struct nk_style_item normal;
3550 struct nk_style_item hover;
3551 struct nk_style_item active;
3552 struct nk_color border_color;
3553
3554 /* cursor */
3555 struct nk_style_item cursor_normal;
3556 struct nk_style_item cursor_hover;
3557 struct nk_style_item cursor_active;
3558 struct nk_color cursor_border_color;
3559
3560 /* properties */
3561 float border;
3562 float rounding;
3563 float border_cursor;
3564 float rounding_cursor;
3565 struct nk_vec2 padding;
3566
3567 /* optional buttons */
3568 int show_buttons;
3569 struct nk_style_button inc_button;
3570 struct nk_style_button dec_button;
3571 enum nk_symbol_type inc_symbol;
3572 enum nk_symbol_type dec_symbol;
3573
3574 /* optional user callbacks */
3575 nk_handle userdata;
3576 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3577 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3578 };
3579
3580 struct nk_style_edit {
3581 /* background */
3582 struct nk_style_item normal;
3583 struct nk_style_item hover;
3584 struct nk_style_item active;
3585 struct nk_color border_color;
3586 struct nk_style_scrollbar scrollbar;
3587
3588 /* cursor */
3589 struct nk_color cursor_normal;
3590 struct nk_color cursor_hover;
3591 struct nk_color cursor_text_normal;
3592 struct nk_color cursor_text_hover;
3593
3594 /* text (unselected) */
3595 struct nk_color text_normal;
3596 struct nk_color text_hover;
3597 struct nk_color text_active;
3598
3599 /* text (selected) */
3600 struct nk_color selected_normal;
3601 struct nk_color selected_hover;
3602 struct nk_color selected_text_normal;
3603 struct nk_color selected_text_hover;
3604
3605 /* properties */
3606 float border;
3607 float rounding;
3608 float cursor_size;
3609 struct nk_vec2 scrollbar_size;
3610 struct nk_vec2 padding;
3611 float row_padding;
3612 };
3613
3614 struct nk_style_property {
3615 /* background */
3616 struct nk_style_item normal;
3617 struct nk_style_item hover;
3618 struct nk_style_item active;
3619 struct nk_color border_color;
3620
3621 /* text */
3622 struct nk_color label_normal;
3623 struct nk_color label_hover;
3624 struct nk_color label_active;
3625
3626 /* symbols */
3627 enum nk_symbol_type sym_left;
3628 enum nk_symbol_type sym_right;
3629
3630 /* properties */
3631 float border;
3632 float rounding;
3633 struct nk_vec2 padding;
3634
3635 struct nk_style_edit edit;
3636 struct nk_style_button inc_button;
3637 struct nk_style_button dec_button;
3638
3639 /* optional user callbacks */
3640 nk_handle userdata;
3641 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
3642 void(*draw_end)(struct nk_command_buffer*, nk_handle);
3643 };
3644
3645 struct nk_style_chart {
3646 /* colors */
3647 struct nk_style_item background;
3648 struct nk_color border_color;
3649 struct nk_color selected_color;
3650 struct nk_color color;
3651
3652 /* properties */
3653 float border;
3654 float rounding;
3655 struct nk_vec2 padding;
3656 };
3657
3658 struct nk_style_combo {
3659 /* background */
3660 struct nk_style_item normal;
3661 struct nk_style_item hover;
3662 struct nk_style_item active;
3663 struct nk_color border_color;
3664
3665 /* label */
3666 struct nk_color label_normal;
3667 struct nk_color label_hover;
3668 struct nk_color label_active;
3669
3670 /* symbol */
3671 struct nk_color symbol_normal;
3672 struct nk_color symbol_hover;
3673 struct nk_color symbol_active;
3674
3675 /* button */
3676 struct nk_style_button button;
3677 enum nk_symbol_type sym_normal;
3678 enum nk_symbol_type sym_hover;
3679 enum nk_symbol_type sym_active;
3680
3681 /* properties */
3682 float border;
3683 float rounding;
3684 struct nk_vec2 content_padding;
3685 struct nk_vec2 button_padding;
3686 struct nk_vec2 spacing;
3687 };
3688
3689 struct nk_style_tab {
3690 /* background */
3691 struct nk_style_item background;
3692 struct nk_color border_color;
3693 struct nk_color text;
3694
3695 /* button */
3696 struct nk_style_button tab_maximize_button;
3697 struct nk_style_button tab_minimize_button;
3698 struct nk_style_button node_maximize_button;
3699 struct nk_style_button node_minimize_button;
3700 enum nk_symbol_type sym_minimize;
3701 enum nk_symbol_type sym_maximize;
3702
3703 /* properties */
3704 float border;
3705 float rounding;
3706 float indent;
3707 struct nk_vec2 padding;
3708 struct nk_vec2 spacing;
3709 };
3710
3711 enum nk_style_header_align {
3712 NK_HEADER_LEFT,
3713 NK_HEADER_RIGHT
3714 };
3715 struct nk_style_window_header {
3716 /* background */
3717 struct nk_style_item normal;
3718 struct nk_style_item hover;
3719 struct nk_style_item active;
3720
3721 /* button */
3722 struct nk_style_button close_button;
3723 struct nk_style_button minimize_button;
3724 enum nk_symbol_type close_symbol;
3725 enum nk_symbol_type minimize_symbol;
3726 enum nk_symbol_type maximize_symbol;
3727
3728 /* title */
3729 struct nk_color label_normal;
3730 struct nk_color label_hover;
3731 struct nk_color label_active;
3732
3733 /* properties */
3734 enum nk_style_header_align align;
3735 struct nk_vec2 padding;
3736 struct nk_vec2 label_padding;
3737 struct nk_vec2 spacing;
3738 };
3739
3740 struct nk_style_window {
3741 struct nk_style_window_header header;
3742 struct nk_style_item fixed_background;
3743 struct nk_color background;
3744
3745 struct nk_color border_color;
3746 struct nk_color popup_border_color;
3747 struct nk_color combo_border_color;
3748 struct nk_color contextual_border_color;
3749 struct nk_color menu_border_color;
3750 struct nk_color group_border_color;
3751 struct nk_color tooltip_border_color;
3752 struct nk_style_item scaler;
3753
3754 float border;
3755 float combo_border;
3756 float contextual_border;
3757 float menu_border;
3758 float group_border;
3759 float tooltip_border;
3760 float popup_border;
3761 float min_row_height_padding;
3762
3763 float rounding;
3764 struct nk_vec2 spacing;
3765 struct nk_vec2 scrollbar_size;
3766 struct nk_vec2 min_size;
3767
3768 struct nk_vec2 padding;
3769 struct nk_vec2 group_padding;
3770 struct nk_vec2 popup_padding;
3771 struct nk_vec2 combo_padding;
3772 struct nk_vec2 contextual_padding;
3773 struct nk_vec2 menu_padding;
3774 struct nk_vec2 tooltip_padding;
3775 };
3776
3777 struct nk_style {
3778 const struct nk_user_font *font;
3779 const struct nk_cursor *cursors[NK_CURSOR_COUNT];
3780 const struct nk_cursor *cursor_active;
3781 struct nk_cursor *cursor_last;
3782 int cursor_visible;
3783
3784 struct nk_style_text text;
3785 struct nk_style_button button;
3786 struct nk_style_button contextual_button;
3787 struct nk_style_button menu_button;
3788 struct nk_style_toggle option;
3789 struct nk_style_toggle checkbox;
3790 struct nk_style_selectable selectable;
3791 struct nk_style_slider slider;
3792 struct nk_style_progress progress;
3793 struct nk_style_property property;
3794 struct nk_style_edit edit;
3795 struct nk_style_chart chart;
3796 struct nk_style_scrollbar scrollh;
3797 struct nk_style_scrollbar scrollv;
3798 struct nk_style_tab tab;
3799 struct nk_style_combo combo;
3800 struct nk_style_window window;
3801 };
3802
3803 NK_API struct nk_style_item nk_style_item_image(struct nk_image img);
3804 NK_API struct nk_style_item nk_style_item_color(struct nk_color);
3805 NK_API struct nk_style_item nk_style_item_hide(void);
3806
3807 /*==============================================================
3808 * PANEL
3809 * =============================================================*/
3810 #ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS
3811 #define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16
3812 #endif
3813 #ifndef NK_CHART_MAX_SLOT
3814 #define NK_CHART_MAX_SLOT 4
3815 #endif
3816
3817 enum nk_panel_type {
3818 NK_PANEL_WINDOW = NK_FLAG(0),
3819 NK_PANEL_GROUP = NK_FLAG(1),
3820 NK_PANEL_POPUP = NK_FLAG(2),
3821 NK_PANEL_CONTEXTUAL = NK_FLAG(4),
3822 NK_PANEL_COMBO = NK_FLAG(5),
3823 NK_PANEL_MENU = NK_FLAG(6),
3824 NK_PANEL_TOOLTIP = NK_FLAG(7)
3825 };
3826 enum nk_panel_set {
3827 NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP,
3828 NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP,
3829 NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP
3830 };
3831
3832 struct nk_chart_slot {
3833 enum nk_chart_type type;
3834 struct nk_color color;
3835 struct nk_color highlight;
3836 float min, max, range;
3837 int count;
3838 struct nk_vec2 last;
3839 int index;
3840 };
3841
3842 struct nk_chart {
3843 int slot;
3844 float x, y, w, h;
3845 struct nk_chart_slot slots[NK_CHART_MAX_SLOT];
3846 };
3847
3848 enum nk_panel_row_layout_type {
3849 NK_LAYOUT_DYNAMIC_FIXED = 0,
3850 NK_LAYOUT_DYNAMIC_ROW,
3851 NK_LAYOUT_DYNAMIC_FREE,
3852 NK_LAYOUT_DYNAMIC,
3853 NK_LAYOUT_STATIC_FIXED,
3854 NK_LAYOUT_STATIC_ROW,
3855 NK_LAYOUT_STATIC_FREE,
3856 NK_LAYOUT_STATIC,
3857 NK_LAYOUT_TEMPLATE,
3858 NK_LAYOUT_COUNT
3859 };
3860 struct nk_row_layout {
3861 enum nk_panel_row_layout_type type;
3862 int index;
3863 float height;
3864 float min_height;
3865 int columns;
3866 const float *ratio;
3867 float item_width;
3868 float item_height;
3869 float item_offset;
3870 float filled;
3871 struct nk_rect item;
3872 int tree_depth;
3873 float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS];
3874 };
3875
3876 struct nk_popup_buffer {
3877 nk_size begin;
3878 nk_size parent;
3879 nk_size last;
3880 nk_size end;
3881 int active;
3882 };
3883
3884 struct nk_menu_state {
3885 float x, y, w, h;
3886 struct nk_scroll offset;
3887 };
3888
3889 struct nk_panel {
3890 enum nk_panel_type type;
3891 nk_flags flags;
3892 struct nk_rect bounds;
3893 nk_uint *offset_x;
3894 nk_uint *offset_y;
3895 float at_x, at_y, max_x;
3896 float footer_height;
3897 float header_height;
3898 float border;
3899 unsigned int has_scrolling;
3900 struct nk_rect clip;
3901 struct nk_menu_state menu;
3902 struct nk_row_layout row;
3903 struct nk_chart chart;
3904 struct nk_command_buffer *buffer;
3905 struct nk_panel *parent;
3906 };
3907
3908 /*==============================================================
3909 * WINDOW
3910 * =============================================================*/
3911 #ifndef NK_WINDOW_MAX_NAME
3912 #define NK_WINDOW_MAX_NAME 64
3913 #endif
3914
3915 struct nk_table;
3916 enum nk_window_flags {
3917 NK_WINDOW_PRIVATE = NK_FLAG(11),
3918 NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE,
3919 /* special window type growing up in height while being filled to a certain maximum height */
3920 NK_WINDOW_ROM = NK_FLAG(12),
3921 /* sets window widgets into a read only mode and does not allow input changes */
3922 NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT,
3923 /* prevents all interaction caused by input to either window or widgets inside */
3924 NK_WINDOW_HIDDEN = NK_FLAG(13),
3925 /* Hides window and stops any window interaction and drawing */
3926 NK_WINDOW_CLOSED = NK_FLAG(14),
3927 /* Directly closes and frees the window at the end of the frame */
3928 NK_WINDOW_MINIMIZED = NK_FLAG(15),
3929 /* marks the window as minimized */
3930 NK_WINDOW_REMOVE_ROM = NK_FLAG(16)
3931 /* Removes read only mode at the end of the window */
3932 };
3933
3934 struct nk_popup_state {
3935 struct nk_window *win;
3936 enum nk_panel_type type;
3937 struct nk_popup_buffer buf;
3938 nk_hash name;
3939 int active;
3940 unsigned combo_count;
3941 unsigned con_count, con_old;
3942 unsigned active_con;
3943 struct nk_rect header;
3944 };
3945
3946 struct nk_edit_state {
3947 nk_hash name;
3948 unsigned int seq;
3949 unsigned int old;
3950 int active, prev;
3951 int cursor;
3952 int sel_start;
3953 int sel_end;
3954 struct nk_scroll scrollbar;
3955 unsigned char mode;
3956 unsigned char single_line;
3957 };
3958
3959 struct nk_property_state {
3960 int active, prev;
3961 char buffer[NK_MAX_NUMBER_BUFFER];
3962 int length;
3963 int cursor;
3964 int select_start;
3965 int select_end;
3966 nk_hash name;
3967 unsigned int seq;
3968 unsigned int old;
3969 int state;
3970 };
3971
3972 struct nk_window {
3973 unsigned int seq;
3974 nk_hash name;
3975 char name_string[NK_WINDOW_MAX_NAME];
3976 nk_flags flags;
3977
3978 struct nk_rect bounds;
3979 struct nk_scroll scrollbar;
3980 struct nk_command_buffer buffer;
3981 struct nk_panel *layout;
3982 float scrollbar_hiding_timer;
3983
3984 /* persistent widget state */
3985 struct nk_property_state property;
3986 struct nk_popup_state popup;
3987 struct nk_edit_state edit;
3988 unsigned int scrolled;
3989
3990 struct nk_table *tables;
3991 unsigned int table_count;
3992
3993 /* window list hooks */
3994 struct nk_window *next;
3995 struct nk_window *prev;
3996 struct nk_window *parent;
3997 };
3998
3999 /*==============================================================
4000 * STACK
4001 * =============================================================*/
4002 /* The style modifier stack can be used to temporarily change a
4003 * property inside `nk_style`. For example if you want a special
4004 * red button you can temporarily push the old button color onto a stack
4005 * draw the button with a red color and then you just pop the old color
4006 * back from the stack:
4007 *
4008 * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0)));
4009 * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0)));
4010 * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0)));
4011 * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2));
4012 *
4013 * nk_button(...);
4014 *
4015 * nk_style_pop_style_item(ctx);
4016 * nk_style_pop_style_item(ctx);
4017 * nk_style_pop_style_item(ctx);
4018 * nk_style_pop_vec2(ctx);
4019 *
4020 * Nuklear has a stack for style_items, float properties, vector properties,
4021 * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack
4022 * which can be changed at compile time.
4023 */
4024 #ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE
4025 #define NK_BUTTON_BEHAVIOR_STACK_SIZE 8
4026 #endif
4027
4028 #ifndef NK_FONT_STACK_SIZE
4029 #define NK_FONT_STACK_SIZE 8
4030 #endif
4031
4032 #ifndef NK_STYLE_ITEM_STACK_SIZE
4033 #define NK_STYLE_ITEM_STACK_SIZE 16
4034 #endif
4035
4036 #ifndef NK_FLOAT_STACK_SIZE
4037 #define NK_FLOAT_STACK_SIZE 32
4038 #endif
4039
4040 #ifndef NK_VECTOR_STACK_SIZE
4041 #define NK_VECTOR_STACK_SIZE 16
4042 #endif
4043
4044 #ifndef NK_FLAGS_STACK_SIZE
4045 #define NK_FLAGS_STACK_SIZE 32
4046 #endif
4047
4048 #ifndef NK_COLOR_STACK_SIZE
4049 #define NK_COLOR_STACK_SIZE 32
4050 #endif
4051
4052 #define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\
4053 struct nk_config_stack_##name##_element {\
4054 prefix##_##type *address;\
4055 prefix##_##type old_value;\
4056 }
4057 #define NK_CONFIG_STACK(type,size)\
4058 struct nk_config_stack_##type {\
4059 int head;\
4060 struct nk_config_stack_##type##_element elements[size];\
4061 }
4062
4063 #define nk_float float
4064 NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item);
4065 NK_CONFIGURATION_STACK_TYPE(nk ,float, float);
4066 NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2);
4067 NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags);
4068 NK_CONFIGURATION_STACK_TYPE(struct nk, color, color);
4069 NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*);
4070 NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior);
4071
4072 NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE);
4073 NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE);
4074 NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE);
4075 NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE);
4076 NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE);
4077 NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE);
4078 NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE);
4079
4080 struct nk_configuration_stacks {
4081 struct nk_config_stack_style_item style_items;
4082 struct nk_config_stack_float floats;
4083 struct nk_config_stack_vec2 vectors;
4084 struct nk_config_stack_flags flags;
4085 struct nk_config_stack_color colors;
4086 struct nk_config_stack_user_font fonts;
4087 struct nk_config_stack_button_behavior button_behaviors;
4088 };
4089
4090 /*==============================================================
4091 * CONTEXT
4092 * =============================================================*/
4093 #define NK_VALUE_PAGE_CAPACITY \
4094 (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2)
4095
4096 struct nk_table {
4097 unsigned int seq;
4098 unsigned int size;
4099 nk_hash keys[NK_VALUE_PAGE_CAPACITY];
4100 nk_uint values[NK_VALUE_PAGE_CAPACITY];
4101 struct nk_table *next, *prev;
4102 };
4103
4104 union nk_page_data {
4105 struct nk_table tbl;
4106 struct nk_panel pan;
4107 struct nk_window win;
4108 };
4109
4110 struct nk_page_element {
4111 union nk_page_data data;
4112 struct nk_page_element *next;
4113 struct nk_page_element *prev;
4114 };
4115
4116 struct nk_page {
4117 unsigned int size;
4118 struct nk_page *next;
4119 struct nk_page_element win[1];
4120 };
4121
4122 struct nk_pool {
4123 struct nk_allocator alloc;
4124 enum nk_allocation_type type;
4125 unsigned int page_count;
4126 struct nk_page *pages;
4127 struct nk_page_element *freelist;
4128 unsigned capacity;
4129 nk_size size;
4130 nk_size cap;
4131 };
4132
4133 struct nk_context {
4134 /* public: can be accessed freely */
4135 struct nk_input input;
4136 struct nk_style style;
4137 struct nk_buffer memory;
4138 struct nk_clipboard clip;
4139 nk_flags last_widget_state;
4140 enum nk_button_behavior button_behavior;
4141 struct nk_configuration_stacks stacks;
4142 float delta_time_seconds;
4143
4144 /* private:
4145 should only be accessed if you
4146 know what you are doing */
4147 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
4148 struct nk_draw_list draw_list;
4149 #endif
4150 #ifdef NK_INCLUDE_COMMAND_USERDATA
4151 nk_handle userdata;
4152 #endif
4153 /* text editor objects are quite big because of an internal
4154 * undo/redo stack. Therefore it does not make sense to have one for
4155 * each window for temporary use cases, so I only provide *one* instance
4156 * for all windows. This works because the content is cleared anyway */
4157 struct nk_text_edit text_edit;
4158 /* draw buffer used for overlay drawing operation like cursor */
4159 struct nk_command_buffer overlay;
4160
4161 /* windows */
4162 int build;
4163 int use_pool;
4164 struct nk_pool pool;
4165 struct nk_window *begin;
4166 struct nk_window *end;
4167 struct nk_window *active;
4168 struct nk_window *current;
4169 struct nk_page_element *freelist;
4170 unsigned int count;
4171 unsigned int seq;
4172 };
4173
4174 /* ==============================================================
4175 * MATH
4176 * =============================================================== */
4177 #define NK_PI 3.141592654f
4178 #define NK_UTF_INVALID 0xFFFD
4179 #define NK_MAX_FLOAT_PRECISION 2
4180
4181 #define NK_UNUSED(x) ((void)(x))
4182 #define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x)))
4183 #define NK_LEN(a) (sizeof(a)/sizeof(a)[0])
4184 #define NK_ABS(a) (((a) < 0) ? -(a) : (a))
4185 #define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b))
4186 #define NK_INBOX(px, py, x, y, w, h)\
4187 (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h))
4188 #define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \
4189 (!(((x1 > (x0 + w0)) || ((x1 + w1) < x0) || (y1 > (y0 + h0)) || (y1 + h1) < y0)))
4190 #define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\
4191 (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh))
4192
4193 #define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y)
4194 #define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y)
4195 #define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y)
4196 #define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t))
4197
4198 #define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i))))
4199 #define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i))))
4200 #define nk_zero_struct(s) nk_zero(&s, sizeof(s))
4201
4202 /* ==============================================================
4203 * ALIGNMENT
4204 * =============================================================== */
4205 /* Pointer to Integer type conversion for pointer alignment */
4206 #if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/
4207 # define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x))
4208 # define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x))
4209 #elif !defined(__GNUC__) /* works for compilers other than LLVM */
4210 # define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x])
4211 # define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0))
4212 #elif defined(NK_USE_FIXED_TYPES) /* used if we have <stdint.h> */
4213 # define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x))
4214 # define NK_PTR_TO_UINT(x) ((uintptr_t)(x))
4215 #else /* generates warning but works */
4216 # define NK_UINT_TO_PTR(x) ((void*)(x))
4217 # define NK_PTR_TO_UINT(x) ((nk_size)(x))
4218 #endif
4219
4220 #define NK_ALIGN_PTR(x, mask)\
4221 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1))))
4222 #define NK_ALIGN_PTR_BACK(x, mask)\
4223 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1))))
4224
4225 #define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m))
4226 #define NK_CONTAINER_OF(ptr,type,member)\
4227 (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member)))
4228
4229 #ifdef __cplusplus
4230 }
4231 #endif
4232
4233 #ifdef __cplusplus
4234 template<typename T> struct nk_alignof;
4235 template<typename T, int size_diff> struct nk_helper{enum {value = size_diff};};
4236 template<typename T> struct nk_helper<T,0>{enum {value = nk_alignof<T>::value};};
4237 template<typename T> struct nk_alignof{struct Big {T x; char c;}; enum {
4238 diff = sizeof(Big) - sizeof(T), value = nk_helper<Big, diff>::value};};
4239 #define NK_ALIGNOF(t) (nk_alignof<t>::value)
4240 #elif defined(_MSC_VER)
4241 #define NK_ALIGNOF(t) (__alignof(t))
4242 #else
4243 #define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0)
4244 #endif
4245
4246 #endif /* NK_NUKLEAR_H_ */
4247 /*
4248 * ==============================================================
4249 *
4250 * IMPLEMENTATION
4251 *
4252 * ===============================================================
4253 */
4254 #ifdef NK_IMPLEMENTATION
4255
4256 #ifndef NK_POOL_DEFAULT_CAPACITY
4257 #define NK_POOL_DEFAULT_CAPACITY 16
4258 #endif
4259
4260 #ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE
4261 #define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)
4262 #endif
4263
4264 #ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE
4265 #define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)
4266 #endif
4267
4268 /* standard library headers */
4269 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
4270 #include <stdlib.h> /* malloc, free */
4271 #endif
4272 #ifdef NK_INCLUDE_STANDARD_IO
4273 #include <stdio.h> /* fopen, fclose,... */
4274 #endif
4275 #ifdef NK_INCLUDE_STANDARD_VARARGS
4276 #include <stdarg.h> /* valist, va_start, va_end, ... */
4277 #endif
4278 #ifndef NK_ASSERT
4279 #include <assert.h>
4280 #define NK_ASSERT(expr) assert(expr)
4281 #endif
4282
4283 #ifndef NK_MEMSET
4284 #define NK_MEMSET nk_memset
4285 #endif
4286 #ifndef NK_MEMCPY
4287 #define NK_MEMCPY nk_memcopy
4288 #endif
4289 #ifndef NK_SQRT
4290 #define NK_SQRT nk_sqrt
4291 #endif
4292 #ifndef NK_SIN
4293 #define NK_SIN nk_sin
4294 #endif
4295 #ifndef NK_COS
4296 #define NK_COS nk_cos
4297 #endif
4298 #ifndef NK_STRTOD
4299 #define NK_STRTOD nk_strtod
4300 #endif
4301 #ifndef NK_DTOA
4302 #define NK_DTOA nk_dtoa
4303 #endif
4304
4305 #define NK_DEFAULT (-1)
4306
4307 #ifndef NK_VSNPRINTF
4308 /* If your compiler does support `vsnprintf` I would highly recommend
4309 * defining this to vsnprintf instead since `vsprintf` is basically
4310 * unbelievable unsafe and should *NEVER* be used. But I have to support
4311 * it since C89 only provides this unsafe version. */
4312 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\
4313 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
4314 (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\
4315 (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\
4316 defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)
4317 #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)
4318 #else
4319 #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)
4320 #endif
4321 #endif
4322
4323 #define NK_SCHAR_MIN (-127)
4324 #define NK_SCHAR_MAX 127
4325 #define NK_UCHAR_MIN 0
4326 #define NK_UCHAR_MAX 256
4327 #define NK_SSHORT_MIN (-32767)
4328 #define NK_SSHORT_MAX 32767
4329 #define NK_USHORT_MIN 0
4330 #define NK_USHORT_MAX 65535
4331 #define NK_SINT_MIN (-2147483647)
4332 #define NK_SINT_MAX 2147483647
4333 #define NK_UINT_MIN 0
4334 #define NK_UINT_MAX 4294967295u
4335
4336 /* Make sure correct type size:
4337 * This will fire with a negative subscript error if the type sizes
4338 * are set incorrectly by the compiler, and compile out if not */
4339 NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
4340 NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));
4341 NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
4342 NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
4343 NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
4344 NK_STATIC_ASSERT(sizeof(nk_short) == 2);
4345 NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
4346 NK_STATIC_ASSERT(sizeof(nk_int) == 4);
4347 NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
4348
4349 NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};
4350 #define NK_FLOAT_PRECISION 0.00000000000001
4351
4352 NK_GLOBAL const struct nk_color nk_red = {255,0,0,255};
4353 NK_GLOBAL const struct nk_color nk_green = {0,255,0,255};
4354 NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};
4355 NK_GLOBAL const struct nk_color nk_white = {255,255,255,255};
4356 NK_GLOBAL const struct nk_color nk_black = {0,0,0,255};
4357 NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};
4358
4359 /*
4360 * ==============================================================
4361 *
4362 * MATH
4363 *
4364 * ===============================================================
4365 */
4366 /* Since nuklear is supposed to work on all systems providing floating point
4367 math without any dependencies I also had to implement my own math functions
4368 for sqrt, sin and cos. Since the actual highly accurate implementations for
4369 the standard library functions are quite complex and I do not need high
4370 precision for my use cases I use approximations.
4371
4372 Sqrt
4373 ----
4374 For square root nuklear uses the famous fast inverse square root:
4375 https://en.wikipedia.org/wiki/Fast_inverse_square_root with
4376 slightly tweaked magic constant. While on today's hardware it is
4377 probably not faster it is still fast and accurate enough for
4378 nuklear's use cases. IMPORTANT: this requires float format IEEE 754
4379
4380 Sine/Cosine
4381 -----------
4382 All constants inside both function are generated Remez's minimax
4383 approximations for value range 0...2*PI. The reason why I decided to
4384 approximate exactly that range is that nuklear only needs sine and
4385 cosine to generate circles which only requires that exact range.
4386 In addition I used Remez instead of Taylor for additional precision:
4387 www.lolengine.net/blog/2011/12/21/better-function-approximations.
4388
4389 The tool I used to generate constants for both sine and cosine
4390 (it can actually approximate a lot more functions) can be
4391 found here: www.lolengine.net/wiki/oss/lolremez
4392 */
4393 NK_INTERN float
4394 nk_inv_sqrt(float number)
4395 {
4396 float x2;
4397 const float threehalfs = 1.5f;
4398 union {nk_uint i; float f;} conv = {0};
4399 conv.f = number;
4400 x2 = number * 0.5f;
4401 conv.i = 0x5f375A84 - (conv.i >> 1);
4402 conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
4403 return conv.f;
4404 }
4405
4406 NK_INTERN float
4407 nk_sqrt(float x)
4408 {
4409 return x * nk_inv_sqrt(x);
4410 }
4411
4412 NK_INTERN float
4413 nk_sin(float x)
4414 {
4415 NK_STORAGE const float a0 = +1.91059300966915117e-31f;
4416 NK_STORAGE const float a1 = +1.00086760103908896f;
4417 NK_STORAGE const float a2 = -1.21276126894734565e-2f;
4418 NK_STORAGE const float a3 = -1.38078780785773762e-1f;
4419 NK_STORAGE const float a4 = -2.67353392911981221e-2f;
4420 NK_STORAGE const float a5 = +2.08026600266304389e-2f;
4421 NK_STORAGE const float a6 = -3.03996055049204407e-3f;
4422 NK_STORAGE const float a7 = +1.38235642404333740e-4f;
4423 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
4424 }
4425
4426 NK_INTERN float
4427 nk_cos(float x)
4428 {
4429 NK_STORAGE const float a0 = +1.00238601909309722f;
4430 NK_STORAGE const float a1 = -3.81919947353040024e-2f;
4431 NK_STORAGE const float a2 = -3.94382342128062756e-1f;
4432 NK_STORAGE const float a3 = -1.18134036025221444e-1f;
4433 NK_STORAGE const float a4 = +1.07123798512170878e-1f;
4434 NK_STORAGE const float a5 = -1.86637164165180873e-2f;
4435 NK_STORAGE const float a6 = +9.90140908664079833e-4f;
4436 NK_STORAGE const float a7 = -5.23022132118824778e-14f;
4437 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
4438 }
4439
4440 NK_INTERN nk_uint
4441 nk_round_up_pow2(nk_uint v)
4442 {
4443 v--;
4444 v |= v >> 1;
4445 v |= v >> 2;
4446 v |= v >> 4;
4447 v |= v >> 8;
4448 v |= v >> 16;
4449 v++;
4450 return v;
4451 }
4452
4453 NK_API struct nk_rect
4454 nk_get_null_rect(void)
4455 {
4456 return nk_null_rect;
4457 }
4458
4459 NK_API struct nk_rect
4460 nk_rect(float x, float y, float w, float h)
4461 {
4462 struct nk_rect r;
4463 r.x = x; r.y = y;
4464 r.w = w; r.h = h;
4465 return r;
4466 }
4467
4468 NK_API struct nk_rect
4469 nk_recti(int x, int y, int w, int h)
4470 {
4471 struct nk_rect r;
4472 r.x = (float)x;
4473 r.y = (float)y;
4474 r.w = (float)w;
4475 r.h = (float)h;
4476 return r;
4477 }
4478
4479 NK_API struct nk_rect
4480 nk_recta(struct nk_vec2 pos, struct nk_vec2 size)
4481 {
4482 return nk_rect(pos.x, pos.y, size.x, size.y);
4483 }
4484
4485 NK_API struct nk_rect
4486 nk_rectv(const float *r)
4487 {
4488 return nk_rect(r[0], r[1], r[2], r[3]);
4489 }
4490
4491 NK_API struct nk_rect
4492 nk_rectiv(const int *r)
4493 {
4494 return nk_recti(r[0], r[1], r[2], r[3]);
4495 }
4496
4497 NK_API struct nk_vec2
4498 nk_rect_pos(struct nk_rect r)
4499 {
4500 struct nk_vec2 ret;
4501 ret.x = r.x; ret.y = r.y;
4502 return ret;
4503 }
4504
4505 NK_API struct nk_vec2
4506 nk_rect_size(struct nk_rect r)
4507 {
4508 struct nk_vec2 ret;
4509 ret.x = r.w; ret.y = r.h;
4510 return ret;
4511 }
4512
4513 NK_INTERN struct nk_rect
4514 nk_shrink_rect(struct nk_rect r, float amount)
4515 {
4516 struct nk_rect res;
4517 r.w = NK_MAX(r.w, 2 * amount);
4518 r.h = NK_MAX(r.h, 2 * amount);
4519 res.x = r.x + amount;
4520 res.y = r.y + amount;
4521 res.w = r.w - 2 * amount;
4522 res.h = r.h - 2 * amount;
4523 return res;
4524 }
4525
4526 NK_INTERN struct nk_rect
4527 nk_pad_rect(struct nk_rect r, struct nk_vec2 pad)
4528 {
4529 r.w = NK_MAX(r.w, 2 * pad.x);
4530 r.h = NK_MAX(r.h, 2 * pad.y);
4531 r.x += pad.x; r.y += pad.y;
4532 r.w -= 2 * pad.x;
4533 r.h -= 2 * pad.y;
4534 return r;
4535 }
4536
4537 NK_API struct nk_vec2
4538 nk_vec2(float x, float y)
4539 {
4540 struct nk_vec2 ret;
4541 ret.x = x; ret.y = y;
4542 return ret;
4543 }
4544
4545 NK_API struct nk_vec2
4546 nk_vec2i(int x, int y)
4547 {
4548 struct nk_vec2 ret;
4549 ret.x = (float)x;
4550 ret.y = (float)y;
4551 return ret;
4552 }
4553
4554 NK_API struct nk_vec2
4555 nk_vec2v(const float *v)
4556 {
4557 return nk_vec2(v[0], v[1]);
4558 }
4559
4560 NK_API struct nk_vec2
4561 nk_vec2iv(const int *v)
4562 {
4563 return nk_vec2i(v[0], v[1]);
4564 }
4565
4566 /*
4567 * ==============================================================
4568 *
4569 * UTIL
4570 *
4571 * ===============================================================
4572 */
4573 NK_INTERN int nk_str_match_here(const char *regexp, const char *text);
4574 NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);
4575 NK_INTERN int nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}
4576 NK_INTERN int nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}
4577 NK_INTERN int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
4578 NK_INTERN int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}
4579
4580 NK_INTERN void*
4581 nk_memcopy(void *dst0, const void *src0, nk_size length)
4582 {
4583 nk_ptr t;
4584 char *dst = (char*)dst0;
4585 const char *src = (const char*)src0;
4586 if (length == 0 || dst == src)
4587 goto done;
4588
4589 #define nk_word int
4590 #define nk_wsize sizeof(nk_word)
4591 #define nk_wmask (nk_wsize-1)
4592 #define NK_TLOOP(s) if (t) NK_TLOOP1(s)
4593 #define NK_TLOOP1(s) do { s; } while (--t)
4594
4595 if (dst < src) {
4596 t = (nk_ptr)src; /* only need low bits */
4597 if ((t | (nk_ptr)dst) & nk_wmask) {
4598 if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)
4599 t = length;
4600 else
4601 t = nk_wsize - (t & nk_wmask);
4602 length -= t;
4603 NK_TLOOP1(*dst++ = *src++);
4604 }
4605 t = length / nk_wsize;
4606 NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;
4607 src += nk_wsize; dst += nk_wsize);
4608 t = length & nk_wmask;
4609 NK_TLOOP(*dst++ = *src++);
4610 } else {
4611 src += length;
4612 dst += length;
4613 t = (nk_ptr)src;
4614 if ((t | (nk_ptr)dst) & nk_wmask) {
4615 if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)
4616 t = length;
4617 else
4618 t &= nk_wmask;
4619 length -= t;
4620 NK_TLOOP1(*--dst = *--src);
4621 }
4622 t = length / nk_wsize;
4623 NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;
4624 *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);
4625 t = length & nk_wmask;
4626 NK_TLOOP(*--dst = *--src);
4627 }
4628 #undef nk_word
4629 #undef nk_wsize
4630 #undef nk_wmask
4631 #undef NK_TLOOP
4632 #undef NK_TLOOP1
4633 done:
4634 return (dst0);
4635 }
4636
4637 NK_INTERN void
4638 nk_memset(void *ptr, int c0, nk_size size)
4639 {
4640 #define nk_word unsigned
4641 #define nk_wsize sizeof(nk_word)
4642 #define nk_wmask (nk_wsize - 1)
4643 nk_byte *dst = (nk_byte*)ptr;
4644 unsigned c = 0;
4645 nk_size t = 0;
4646
4647 if ((c = (nk_byte)c0) != 0) {
4648 c = (c << 8) | c; /* at least 16-bits */
4649 if (sizeof(unsigned int) > 2)
4650 c = (c << 16) | c; /* at least 32-bits*/
4651 }
4652
4653 /* too small of a word count */
4654 dst = (nk_byte*)ptr;
4655 if (size < 3 * nk_wsize) {
4656 while (size--) *dst++ = (nk_byte)c0;
4657 return;
4658 }
4659
4660 /* align destination */
4661 if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {
4662 t = nk_wsize -t;
4663 size -= t;
4664 do {
4665 *dst++ = (nk_byte)c0;
4666 } while (--t != 0);
4667 }
4668
4669 /* fill word */
4670 t = size / nk_wsize;
4671 do {
4672 *(nk_word*)((void*)dst) = c;
4673 dst += nk_wsize;
4674 } while (--t != 0);
4675
4676 /* fill trailing bytes */
4677 t = (size & nk_wmask);
4678 if (t != 0) {
4679 do {
4680 *dst++ = (nk_byte)c0;
4681 } while (--t != 0);
4682 }
4683
4684 #undef nk_word
4685 #undef nk_wsize
4686 #undef nk_wmask
4687 }
4688
4689 NK_INTERN void
4690 nk_zero(void *ptr, nk_size size)
4691 {
4692 NK_ASSERT(ptr);
4693 NK_MEMSET(ptr, 0, size);
4694 }
4695
4696 NK_API int
4697 nk_strlen(const char *str)
4698 {
4699 int siz = 0;
4700 NK_ASSERT(str);
4701 while (str && *str++ != '\0') siz++;
4702 return siz;
4703 }
4704
4705 NK_API int
4706 nk_strtoi(const char *str, const char **endptr)
4707 {
4708 int neg = 1;
4709 const char *p = str;
4710 int value = 0;
4711
4712 NK_ASSERT(str);
4713 if (!str) return 0;
4714
4715 /* skip whitespace */
4716 while (*p == ' ') p++;
4717 if (*p == '-') {
4718 neg = -1;
4719 p++;
4720 }
4721 while (*p && *p >= '0' && *p <= '9') {
4722 value = value * 10 + (int) (*p - '0');
4723 p++;
4724 }
4725 if (endptr)
4726 *endptr = p;
4727 return neg*value;
4728 }
4729
4730 NK_API double
4731 nk_strtod(const char *str, const char **endptr)
4732 {
4733 double m;
4734 double neg = 1.0;
4735 const char *p = str;
4736 double value = 0;
4737 double number = 0;
4738
4739 NK_ASSERT(str);
4740 if (!str) return 0;
4741
4742 /* skip whitespace */
4743 while (*p == ' ') p++;
4744 if (*p == '-') {
4745 neg = -1.0;
4746 p++;
4747 }
4748
4749 while (*p && *p != '.' && *p != 'e') {
4750 value = value * 10.0 + (double) (*p - '0');
4751 p++;
4752 }
4753
4754 if (*p == '.') {
4755 p++;
4756 for(m = 0.1; *p && *p != 'e'; p++ ) {
4757 value = value + (double) (*p - '0') * m;
4758 m *= 0.1;
4759 }
4760 }
4761 if (*p == 'e') {
4762 int i, pow, div;
4763 p++;
4764 if (*p == '-') {
4765 div = nk_true;
4766 p++;
4767 } else if (*p == '+') {
4768 div = nk_false;
4769 p++;
4770 } else div = nk_false;
4771
4772 for (pow = 0; *p; p++)
4773 pow = pow * 10 + (int) (*p - '0');
4774
4775 for (m = 1.0, i = 0; i < pow; i++)
4776 m *= 10.0;
4777
4778 if (div)
4779 value /= m;
4780 else value *= m;
4781 }
4782 number = value * neg;
4783 if (endptr)
4784 *endptr = p;
4785 return number;
4786 }
4787
4788 NK_API float
4789 nk_strtof(const char *str, const char **endptr)
4790 {
4791 float float_value;
4792 double double_value;
4793 double_value = NK_STRTOD(str, endptr);
4794 float_value = (float)double_value;
4795 return float_value;
4796 }
4797
4798 NK_API int
4799 nk_stricmp(const char *s1, const char *s2)
4800 {
4801 nk_int c1,c2,d;
4802 do {
4803 c1 = *s1++;
4804 c2 = *s2++;
4805 d = c1 - c2;
4806 while (d) {
4807 if (c1 <= 'Z' && c1 >= 'A') {
4808 d += ('a' - 'A');
4809 if (!d) break;
4810 }
4811 if (c2 <= 'Z' && c2 >= 'A') {
4812 d -= ('a' - 'A');
4813 if (!d) break;
4814 }
4815 return ((d >= 0) << 1) - 1;
4816 }
4817 } while (c1);
4818 return 0;
4819 }
4820
4821 NK_API int
4822 nk_stricmpn(const char *s1, const char *s2, int n)
4823 {
4824 int c1,c2,d;
4825 NK_ASSERT(n >= 0);
4826 do {
4827 c1 = *s1++;
4828 c2 = *s2++;
4829 if (!n--) return 0;
4830
4831 d = c1 - c2;
4832 while (d) {
4833 if (c1 <= 'Z' && c1 >= 'A') {
4834 d += ('a' - 'A');
4835 if (!d) break;
4836 }
4837 if (c2 <= 'Z' && c2 >= 'A') {
4838 d -= ('a' - 'A');
4839 if (!d) break;
4840 }
4841 return ((d >= 0) << 1) - 1;
4842 }
4843 } while (c1);
4844 return 0;
4845 }
4846
4847 NK_INTERN int
4848 nk_str_match_here(const char *regexp, const char *text)
4849 {
4850 if (regexp[0] == '\0')
4851 return 1;
4852 if (regexp[1] == '*')
4853 return nk_str_match_star(regexp[0], regexp+2, text);
4854 if (regexp[0] == '$' && regexp[1] == '\0')
4855 return *text == '\0';
4856 if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
4857 return nk_str_match_here(regexp+1, text+1);
4858 return 0;
4859 }
4860
4861 NK_INTERN int
4862 nk_str_match_star(int c, const char *regexp, const char *text)
4863 {
4864 do {/* a '* matches zero or more instances */
4865 if (nk_str_match_here(regexp, text))
4866 return 1;
4867 } while (*text != '\0' && (*text++ == c || c == '.'));
4868 return 0;
4869 }
4870
4871 NK_API int
4872 nk_strfilter(const char *text, const char *regexp)
4873 {
4874 /*
4875 c matches any literal character c
4876 . matches any single character
4877 ^ matches the beginning of the input string
4878 $ matches the end of the input string
4879 * matches zero or more occurrences of the previous character*/
4880 if (regexp[0] == '^')
4881 return nk_str_match_here(regexp+1, text);
4882 do { /* must look even if string is empty */
4883 if (nk_str_match_here(regexp, text))
4884 return 1;
4885 } while (*text++ != '\0');
4886 return 0;
4887 }
4888
4889 NK_API int
4890 nk_strmatch_fuzzy_text(const char *str, int str_len,
4891 const char *pattern, int *out_score)
4892 {
4893 /* Returns true if each character in pattern is found sequentially within str
4894 * if found then out_score is also set. Score value has no intrinsic meaning.
4895 * Range varies with pattern. Can only compare scores with same search pattern. */
4896
4897 /* ------- scores --------- */
4898 /* bonus for adjacent matches */
4899 #define NK_ADJACENCY_BONUS 5
4900 /* bonus if match occurs after a separator */
4901 #define NK_SEPARATOR_BONUS 10
4902 /* bonus if match is uppercase and prev is lower */
4903 #define NK_CAMEL_BONUS 10
4904 /* penalty applied for every letter in str before the first match */
4905 #define NK_LEADING_LETTER_PENALTY (-3)
4906 /* maximum penalty for leading letters */
4907 #define NK_MAX_LEADING_LETTER_PENALTY (-9)
4908 /* penalty for every letter that doesn't matter */
4909 #define NK_UNMATCHED_LETTER_PENALTY (-1)
4910
4911 /* loop variables */
4912 int score = 0;
4913 char const * pattern_iter = pattern;
4914 int str_iter = 0;
4915 int prev_matched = nk_false;
4916 int prev_lower = nk_false;
4917 /* true so if first letter match gets separator bonus*/
4918 int prev_separator = nk_true;
4919
4920 /* use "best" matched letter if multiple string letters match the pattern */
4921 char const * best_letter = 0;
4922 int best_letter_score = 0;
4923
4924 /* loop over strings */
4925 NK_ASSERT(str);
4926 NK_ASSERT(pattern);
4927 if (!str || !str_len || !pattern) return 0;
4928 while (str_iter < str_len)
4929 {
4930 const char pattern_letter = *pattern_iter;
4931 const char str_letter = str[str_iter];
4932
4933 int next_match = *pattern_iter != '\0' &&
4934 nk_to_lower(pattern_letter) == nk_to_lower(str_letter);
4935 int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);
4936
4937 int advanced = next_match && best_letter;
4938 int pattern_repeat = best_letter && *pattern_iter != '\0';
4939 pattern_repeat = pattern_repeat &&
4940 nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);
4941
4942 if (advanced || pattern_repeat) {
4943 score += best_letter_score;
4944 best_letter = 0;
4945 best_letter_score = 0;
4946 }
4947
4948 if (next_match || rematch)
4949 {
4950 int new_score = 0;
4951 /* Apply penalty for each letter before the first pattern match */
4952 if (pattern_iter == pattern) {
4953 int count = (int)(&str[str_iter] - str);
4954 int penalty = NK_LEADING_LETTER_PENALTY * count;
4955 if (penalty < NK_MAX_LEADING_LETTER_PENALTY)
4956 penalty = NK_MAX_LEADING_LETTER_PENALTY;
4957
4958 score += penalty;
4959 }
4960
4961 /* apply bonus for consecutive bonuses */
4962 if (prev_matched)
4963 new_score += NK_ADJACENCY_BONUS;
4964
4965 /* apply bonus for matches after a separator */
4966 if (prev_separator)
4967 new_score += NK_SEPARATOR_BONUS;
4968
4969 /* apply bonus across camel case boundaries */
4970 if (prev_lower && nk_is_upper(str_letter))
4971 new_score += NK_CAMEL_BONUS;
4972
4973 /* update pattern iter IFF the next pattern letter was matched */
4974 if (next_match)
4975 ++pattern_iter;
4976
4977 /* update best letter in str which may be for a "next" letter or a rematch */
4978 if (new_score >= best_letter_score) {
4979 /* apply penalty for now skipped letter */
4980 if (best_letter != 0)
4981 score += NK_UNMATCHED_LETTER_PENALTY;
4982
4983 best_letter = &str[str_iter];
4984 best_letter_score = new_score;
4985 }
4986 prev_matched = nk_true;
4987 } else {
4988 score += NK_UNMATCHED_LETTER_PENALTY;
4989 prev_matched = nk_false;
4990 }
4991
4992 /* separators should be more easily defined */
4993 prev_lower = nk_is_lower(str_letter) != 0;
4994 prev_separator = str_letter == '_' || str_letter == ' ';
4995
4996 ++str_iter;
4997 }
4998
4999 /* apply score for last match */
5000 if (best_letter)
5001 score += best_letter_score;
5002
5003 /* did not match full pattern */
5004 if (*pattern_iter != '\0')
5005 return nk_false;
5006
5007 if (out_score)
5008 *out_score = score;
5009 return nk_true;
5010 }
5011
5012 NK_API int
5013 nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)
5014 {return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);}
5015
5016 NK_INTERN int
5017 nk_string_float_limit(char *string, int prec)
5018 {
5019 int dot = 0;
5020 char *c = string;
5021 while (*c) {
5022 if (*c == '.') {
5023 dot = 1;
5024 c++;
5025 continue;
5026 }
5027 if (dot == (prec+1)) {
5028 *c = 0;
5029 break;
5030 }
5031 if (dot > 0) dot++;
5032 c++;
5033 }
5034 return (int)(c - string);
5035 }
5036
5037 NK_INTERN double
5038 nk_pow(double x, int n)
5039 {
5040 /* check the sign of n */
5041 double r = 1;
5042 int plus = n >= 0;
5043 n = (plus) ? n : -n;
5044 while (n > 0) {
5045 if ((n & 1) == 1)
5046 r *= x;
5047 n /= 2;
5048 x *= x;
5049 }
5050 return plus ? r : 1.0 / r;
5051 }
5052
5053 NK_INTERN int
5054 nk_ifloord(double x)
5055 {
5056 x = (double)((int)x - ((x < 0.0) ? 1 : 0));
5057 return (int)x;
5058 }
5059
5060 NK_INTERN int
5061 nk_ifloorf(float x)
5062 {
5063 x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
5064 return (int)x;
5065 }
5066
5067 NK_INTERN int
5068 nk_iceilf(float x)
5069 {
5070 if (x >= 0) {
5071 int i = (int)x;
5072 return (x > i) ? i+1: i;
5073 } else {
5074 int t = (int)x;
5075 float r = x - (float)t;
5076 return (r > 0.0f) ? t+1: t;
5077 }
5078 }
5079
5080 NK_INTERN int
5081 nk_log10(double n)
5082 {
5083 int neg;
5084 int ret;
5085 int exp = 0;
5086
5087 neg = (n < 0) ? 1 : 0;
5088 ret = (neg) ? (int)-n : (int)n;
5089 while ((ret / 10) > 0) {
5090 ret /= 10;
5091 exp++;
5092 }
5093 if (neg) exp = -exp;
5094 return exp;
5095 }
5096
5097 NK_INTERN void
5098 nk_strrev_ascii(char *s)
5099 {
5100 int len = nk_strlen(s);
5101 int end = len / 2;
5102 int i = 0;
5103 char t;
5104 for (; i < end; ++i) {
5105 t = s[i];
5106 s[i] = s[len - 1 - i];
5107 s[len -1 - i] = t;
5108 }
5109 }
5110
5111 NK_INTERN char*
5112 nk_itoa(char *s, long n)
5113 {
5114 long i = 0;
5115 if (n == 0) {
5116 s[i++] = '0';
5117 s[i] = 0;
5118 return s;
5119 }
5120 if (n < 0) {
5121 s[i++] = '-';
5122 n = -n;
5123 }
5124 while (n > 0) {
5125 s[i++] = (char)('0' + (n % 10));
5126 n /= 10;
5127 }
5128 s[i] = 0;
5129 if (s[0] == '-')
5130 ++s;
5131
5132 nk_strrev_ascii(s);
5133 return s;
5134 }
5135
5136 NK_INTERN char*
5137 nk_dtoa(char *s, double n)
5138 {
5139 int useExp = 0;
5140 int digit = 0, m = 0, m1 = 0;
5141 char *c = s;
5142 int neg = 0;
5143
5144 NK_ASSERT(s);
5145 if (!s) return 0;
5146
5147 if (n == 0.0) {
5148 s[0] = '0'; s[1] = '\0';
5149 return s;
5150 }
5151
5152 neg = (n < 0);
5153 if (neg) n = -n;
5154
5155 /* calculate magnitude */
5156 m = nk_log10(n);
5157 useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
5158 if (neg) *(c++) = '-';
5159
5160 /* set up for scientific notation */
5161 if (useExp) {
5162 if (m < 0)
5163 m -= 1;
5164 n = n / (double)nk_pow(10.0, m);
5165 m1 = m;
5166 m = 0;
5167 }
5168 if (m < 1.0) {
5169 m = 0;
5170 }
5171
5172 /* convert the number */
5173 while (n > NK_FLOAT_PRECISION || m >= 0) {
5174 double weight = nk_pow(10.0, m);
5175 if (weight > 0) {
5176 double t = (double)n / weight;
5177 digit = nk_ifloord(t);
5178 n -= ((double)digit * weight);
5179 *(c++) = (char)('0' + (char)digit);
5180 }
5181 if (m == 0 && n > 0)
5182 *(c++) = '.';
5183 m--;
5184 }
5185
5186 if (useExp) {
5187 /* convert the exponent */
5188 int i, j;
5189 *(c++) = 'e';
5190 if (m1 > 0) {
5191 *(c++) = '+';
5192 } else {
5193 *(c++) = '-';
5194 m1 = -m1;
5195 }
5196 m = 0;
5197 while (m1 > 0) {
5198 *(c++) = (char)('0' + (char)(m1 % 10));
5199 m1 /= 10;
5200 m++;
5201 }
5202 c -= m;
5203 for (i = 0, j = m-1; i<j; i++, j--) {
5204 /* swap without temporary */
5205 c[i] ^= c[j];
5206 c[j] ^= c[i];
5207 c[i] ^= c[j];
5208 }
5209 c += m;
5210 }
5211 *(c) = '\0';
5212 return s;
5213 }
5214
5215 #ifdef NK_INCLUDE_STANDARD_VARARGS
5216 #ifndef NK_INCLUDE_STANDARD_IO
5217 static int
5218 nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)
5219 {
5220 enum nk_arg_type {
5221 NK_ARG_TYPE_CHAR,
5222 NK_ARG_TYPE_SHORT,
5223 NK_ARG_TYPE_DEFAULT,
5224 NK_ARG_TYPE_LONG
5225 };
5226 enum nk_arg_flags {
5227 NK_ARG_FLAG_LEFT = 0x01,
5228 NK_ARG_FLAG_PLUS = 0x02,
5229 NK_ARG_FLAG_SPACE = 0x04,
5230 NK_ARG_FLAG_NUM = 0x10,
5231 NK_ARG_FLAG_ZERO = 0x20
5232 };
5233
5234 char number_buffer[NK_MAX_NUMBER_BUFFER];
5235 enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;
5236 int precision = NK_DEFAULT;
5237 int width = NK_DEFAULT;
5238 nk_flags flag = 0;
5239
5240 int len = 0;
5241 int result = -1;
5242 const char *iter = fmt;
5243
5244 NK_ASSERT(buf);
5245 NK_ASSERT(buf_size);
5246 if (!buf || !buf_size || !fmt) return 0;
5247 for (iter = fmt; *iter && len < buf_size; iter++) {
5248 /* copy all non-format characters */
5249 while (*iter && (*iter != '%') && (len < buf_size))
5250 buf[len++] = *iter++;
5251 if (!(*iter) || len >= buf_size) break;
5252 iter++;
5253
5254 /* flag arguments */
5255 while (*iter) {
5256 if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;
5257 else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;
5258 else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;
5259 else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;
5260 else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;
5261 else break;
5262 iter++;
5263 }
5264
5265 /* width argument */
5266 width = NK_DEFAULT;
5267 if (*iter >= '1' && *iter <= '9') {
5268 const char *end;
5269 width = nk_strtoi(iter, &end);
5270 if (end == iter)
5271 width = -1;
5272 else iter = end;
5273 } else if (*iter == '*') {
5274 width = va_arg(args, int);
5275 iter++;
5276 }
5277
5278 /* precision argument */
5279 precision = NK_DEFAULT;
5280 if (*iter == '.') {
5281 iter++;
5282 if (*iter == '*') {
5283 precision = va_arg(args, int);
5284 iter++;
5285 } else {
5286 const char *end;
5287 precision = nk_strtoi(iter, &end);
5288 if (end == iter)
5289 precision = -1;
5290 else iter = end;
5291 }
5292 }
5293
5294 /* length modifier */
5295 if (*iter == 'h') {
5296 if (*(iter+1) == 'h') {
5297 arg_type = NK_ARG_TYPE_CHAR;
5298 iter++;
5299 } else arg_type = NK_ARG_TYPE_SHORT;
5300 iter++;
5301 } else if (*iter == 'l') {
5302 arg_type = NK_ARG_TYPE_LONG;
5303 iter++;
5304 } else arg_type = NK_ARG_TYPE_DEFAULT;
5305
5306 /* specifier */
5307 if (*iter == '%') {
5308 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
5309 NK_ASSERT(precision == NK_DEFAULT);
5310 NK_ASSERT(width == NK_DEFAULT);
5311 if (len < buf_size)
5312 buf[len++] = '%';
5313 } else if (*iter == 's') {
5314 /* string */
5315 const char *str = va_arg(args, const char*);
5316 NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!");
5317 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
5318 NK_ASSERT(precision == NK_DEFAULT);
5319 NK_ASSERT(width == NK_DEFAULT);
5320 if (str == buf) return -1;
5321 while (str && *str && len < buf_size)
5322 buf[len++] = *str++;
5323 } else if (*iter == 'n') {
5324 /* current length callback */
5325 signed int *n = va_arg(args, int*);
5326 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
5327 NK_ASSERT(precision == NK_DEFAULT);
5328 NK_ASSERT(width == NK_DEFAULT);
5329 if (n) *n = len;
5330 } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {
5331 /* signed integer */
5332 long value = 0;
5333 const char *num_iter;
5334 int num_len, num_print, padding;
5335 int cur_precision = NK_MAX(precision, 1);
5336 int cur_width = NK_MAX(width, 0);
5337
5338 /* retrieve correct value type */
5339 if (arg_type == NK_ARG_TYPE_CHAR)
5340 value = (signed char)va_arg(args, int);
5341 else if (arg_type == NK_ARG_TYPE_SHORT)
5342 value = (signed short)va_arg(args, int);
5343 else if (arg_type == NK_ARG_TYPE_LONG)
5344 value = va_arg(args, signed long);
5345 else if (*iter == 'c')
5346 value = (unsigned char)va_arg(args, int);
5347 else value = va_arg(args, signed int);
5348
5349 /* convert number to string */
5350 nk_itoa(number_buffer, value);
5351 num_len = nk_strlen(number_buffer);
5352 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
5353 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
5354 padding = NK_MAX(padding-1, 0);
5355
5356 /* fill left padding up to a total of `width` characters */
5357 if (!(flag & NK_ARG_FLAG_LEFT)) {
5358 while (padding-- > 0 && (len < buf_size)) {
5359 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
5360 buf[len++] = '0';
5361 else buf[len++] = ' ';
5362 }
5363 }
5364
5365 /* copy string value representation into buffer */
5366 if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)
5367 buf[len++] = '+';
5368 else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)
5369 buf[len++] = ' ';
5370
5371 /* fill up to precision number of digits with '0' */
5372 num_print = NK_MAX(cur_precision, num_len);
5373 while (precision && (num_print > num_len) && (len < buf_size)) {
5374 buf[len++] = '0';
5375 num_print--;
5376 }
5377
5378 /* copy string value representation into buffer */
5379 num_iter = number_buffer;
5380 while (precision && *num_iter && len < buf_size)
5381 buf[len++] = *num_iter++;
5382
5383 /* fill right padding up to width characters */
5384 if (flag & NK_ARG_FLAG_LEFT) {
5385 while ((padding-- > 0) && (len < buf_size))
5386 buf[len++] = ' ';
5387 }
5388 } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {
5389 /* unsigned integer */
5390 unsigned long value = 0;
5391 int num_len = 0, num_print, padding = 0;
5392 int cur_precision = NK_MAX(precision, 1);
5393 int cur_width = NK_MAX(width, 0);
5394 unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;
5395
5396 /* print oct/hex/dec value */
5397 const char *upper_output_format = "0123456789ABCDEF";
5398 const char *lower_output_format = "0123456789abcdef";
5399 const char *output_format = (*iter == 'x') ?
5400 lower_output_format: upper_output_format;
5401
5402 /* retrieve correct value type */
5403 if (arg_type == NK_ARG_TYPE_CHAR)
5404 value = (unsigned char)va_arg(args, int);
5405 else if (arg_type == NK_ARG_TYPE_SHORT)
5406 value = (unsigned short)va_arg(args, int);
5407 else if (arg_type == NK_ARG_TYPE_LONG)
5408 value = va_arg(args, unsigned long);
5409 else value = va_arg(args, unsigned int);
5410
5411 do {
5412 /* convert decimal number into hex/oct number */
5413 int digit = output_format[value % base];
5414 if (num_len < NK_MAX_NUMBER_BUFFER)
5415 number_buffer[num_len++] = (char)digit;
5416 value /= base;
5417 } while (value > 0);
5418
5419 num_print = NK_MAX(cur_precision, num_len);
5420 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
5421 if (flag & NK_ARG_FLAG_NUM)
5422 padding = NK_MAX(padding-1, 0);
5423
5424 /* fill left padding up to a total of `width` characters */
5425 if (!(flag & NK_ARG_FLAG_LEFT)) {
5426 while ((padding-- > 0) && (len < buf_size)) {
5427 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
5428 buf[len++] = '0';
5429 else buf[len++] = ' ';
5430 }
5431 }
5432
5433 /* fill up to precision number of digits */
5434 if (num_print && (flag & NK_ARG_FLAG_NUM)) {
5435 if ((*iter == 'o') && (len < buf_size)) {
5436 buf[len++] = '0';
5437 } else if ((*iter == 'x') && ((len+1) < buf_size)) {
5438 buf[len++] = '0';
5439 buf[len++] = 'x';
5440 } else if ((*iter == 'X') && ((len+1) < buf_size)) {
5441 buf[len++] = '0';
5442 buf[len++] = 'X';
5443 }
5444 }
5445 while (precision && (num_print > num_len) && (len < buf_size)) {
5446 buf[len++] = '0';
5447 num_print--;
5448 }
5449
5450 /* reverse number direction */
5451 while (num_len > 0) {
5452 if (precision && (len < buf_size))
5453 buf[len++] = number_buffer[num_len-1];
5454 num_len--;
5455 }
5456
5457 /* fill right padding up to width characters */
5458 if (flag & NK_ARG_FLAG_LEFT) {
5459 while ((padding-- > 0) && (len < buf_size))
5460 buf[len++] = ' ';
5461 }
5462 } else if (*iter == 'f') {
5463 /* floating point */
5464 const char *num_iter;
5465 int cur_precision = (precision < 0) ? 6: precision;
5466 int prefix, cur_width = NK_MAX(width, 0);
5467 double value = va_arg(args, double);
5468 int num_len = 0, frac_len = 0, dot = 0;
5469 int padding = 0;
5470
5471 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
5472 NK_DTOA(number_buffer, value);
5473 num_len = nk_strlen(number_buffer);
5474
5475 /* calculate padding */
5476 num_iter = number_buffer;
5477 while (*num_iter && *num_iter != '.')
5478 num_iter++;
5479
5480 prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;
5481 padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);
5482 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
5483 padding = NK_MAX(padding-1, 0);
5484
5485 /* fill left padding up to a total of `width` characters */
5486 if (!(flag & NK_ARG_FLAG_LEFT)) {
5487 while (padding-- > 0 && (len < buf_size)) {
5488 if (flag & NK_ARG_FLAG_ZERO)
5489 buf[len++] = '0';
5490 else buf[len++] = ' ';
5491 }
5492 }
5493
5494 /* copy string value representation into buffer */
5495 num_iter = number_buffer;
5496 if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))
5497 buf[len++] = '+';
5498 else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))
5499 buf[len++] = ' ';
5500 while (*num_iter) {
5501 if (dot) frac_len++;
5502 if (len < buf_size)
5503 buf[len++] = *num_iter;
5504 if (*num_iter == '.') dot = 1;
5505 if (frac_len >= cur_precision) break;
5506 num_iter++;
5507 }
5508
5509 /* fill number up to precision */
5510 while (frac_len < cur_precision) {
5511 if (!dot && len < buf_size) {
5512 buf[len++] = '.';
5513 dot = 1;
5514 }
5515 if (len < buf_size)
5516 buf[len++] = '0';
5517 frac_len++;
5518 }
5519
5520 /* fill right padding up to width characters */
5521 if (flag & NK_ARG_FLAG_LEFT) {
5522 while ((padding-- > 0) && (len < buf_size))
5523 buf[len++] = ' ';
5524 }
5525 } else {
5526 /* Specifier not supported: g,G,e,E,p,z */
5527 NK_ASSERT(0 && "specifier is not supported!");
5528 return result;
5529 }
5530 }
5531 buf[(len >= buf_size)?(buf_size-1):len] = 0;
5532 result = (len >= buf_size)?-1:len;
5533 return result;
5534 }
5535 #endif
5536
5537 NK_INTERN int
5538 nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)
5539 {
5540 int result = -1;
5541 NK_ASSERT(buf);
5542 NK_ASSERT(buf_size);
5543 if (!buf || !buf_size || !fmt) return 0;
5544 #ifdef NK_INCLUDE_STANDARD_IO
5545 result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);
5546 result = (result >= buf_size) ? -1: result;
5547 buf[buf_size-1] = 0;
5548 #else
5549 result = nk_vsnprintf(buf, buf_size, fmt, args);
5550 #endif
5551 return result;
5552 }
5553 #endif
5554
5555 NK_API nk_hash
5556 nk_murmur_hash(const void * key, int len, nk_hash seed)
5557 {
5558 /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/
5559 #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))
5560 union {const nk_uint *i; const nk_byte *b;} conv = {0};
5561 const nk_byte *data = (const nk_byte*)key;
5562 const int nblocks = len/4;
5563 nk_uint h1 = seed;
5564 const nk_uint c1 = 0xcc9e2d51;
5565 const nk_uint c2 = 0x1b873593;
5566 const nk_byte *tail;
5567 const nk_uint *blocks;
5568 nk_uint k1;
5569 int i;
5570
5571 /* body */
5572 if (!key) return 0;
5573 conv.b = (data + nblocks*4);
5574 blocks = (const nk_uint*)conv.i;
5575 for (i = -nblocks; i; ++i) {
5576 k1 = blocks[i];
5577 k1 *= c1;
5578 k1 = NK_ROTL(k1,15);
5579 k1 *= c2;
5580
5581 h1 ^= k1;
5582 h1 = NK_ROTL(h1,13);
5583 h1 = h1*5+0xe6546b64;
5584 }
5585
5586 /* tail */
5587 tail = (const nk_byte*)(data + nblocks*4);
5588 k1 = 0;
5589 switch (len & 3) {
5590 case 3: k1 ^= (nk_uint)(tail[2] << 16);
5591 case 2: k1 ^= (nk_uint)(tail[1] << 8u);
5592 case 1: k1 ^= tail[0];
5593 k1 *= c1;
5594 k1 = NK_ROTL(k1,15);
5595 k1 *= c2;
5596 h1 ^= k1;
5597 default: break;
5598 }
5599
5600 /* finalization */
5601 h1 ^= (nk_uint)len;
5602 /* fmix32 */
5603 h1 ^= h1 >> 16;
5604 h1 *= 0x85ebca6b;
5605 h1 ^= h1 >> 13;
5606 h1 *= 0xc2b2ae35;
5607 h1 ^= h1 >> 16;
5608
5609 #undef NK_ROTL
5610 return h1;
5611 }
5612
5613 #ifdef NK_INCLUDE_STANDARD_IO
5614 NK_INTERN char*
5615 nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc)
5616 {
5617 char *buf;
5618 FILE *fd;
5619 long ret;
5620
5621 NK_ASSERT(path);
5622 NK_ASSERT(siz);
5623 NK_ASSERT(alloc);
5624 if (!path || !siz || !alloc)
5625 return 0;
5626
5627 fd = fopen(path, "rb");
5628 if (!fd) return 0;
5629 fseek(fd, 0, SEEK_END);
5630 ret = ftell(fd);
5631 if (ret < 0) {
5632 fclose(fd);
5633 return 0;
5634 }
5635 *siz = (nk_size)ret;
5636 fseek(fd, 0, SEEK_SET);
5637 buf = (char*)alloc->alloc(alloc->userdata,0, *siz);
5638 NK_ASSERT(buf);
5639 if (!buf) {
5640 fclose(fd);
5641 return 0;
5642 }
5643 *siz = (nk_size)fread(buf, *siz, 1, fd);
5644 fclose(fd);
5645 return buf;
5646 }
5647 #endif
5648
5649 /*
5650 * ==============================================================
5651 *
5652 * COLOR
5653 *
5654 * ===============================================================
5655 */
5656 NK_INTERN int
5657 nk_parse_hex(const char *p, int length)
5658 {
5659 int i = 0;
5660 int len = 0;
5661 while (len < length) {
5662 i <<= 4;
5663 if (p[len] >= 'a' && p[len] <= 'f')
5664 i += ((p[len] - 'a') + 10);
5665 else if (p[len] >= 'A' && p[len] <= 'F')
5666 i += ((p[len] - 'A') + 10);
5667 else i += (p[len] - '0');
5668 len++;
5669 }
5670 return i;
5671 }
5672
5673 NK_API struct nk_color
5674 nk_rgba(int r, int g, int b, int a)
5675 {
5676 struct nk_color ret;
5677 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
5678 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
5679 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
5680 ret.a = (nk_byte)NK_CLAMP(0, a, 255);
5681 return ret;
5682 }
5683
5684 NK_API struct nk_color
5685 nk_rgb_hex(const char *rgb)
5686 {
5687 struct nk_color col;
5688 const char *c = rgb;
5689 if (*c == '#') c++;
5690 col.r = (nk_byte)nk_parse_hex(c, 2);
5691 col.g = (nk_byte)nk_parse_hex(c+2, 2);
5692 col.b = (nk_byte)nk_parse_hex(c+4, 2);
5693 col.a = 255;
5694 return col;
5695 }
5696
5697 NK_API struct nk_color
5698 nk_rgba_hex(const char *rgb)
5699 {
5700 struct nk_color col;
5701 const char *c = rgb;
5702 if (*c == '#') c++;
5703 col.r = (nk_byte)nk_parse_hex(c, 2);
5704 col.g = (nk_byte)nk_parse_hex(c+2, 2);
5705 col.b = (nk_byte)nk_parse_hex(c+4, 2);
5706 col.a = (nk_byte)nk_parse_hex(c+6, 2);
5707 return col;
5708 }
5709
5710 NK_API void
5711 nk_color_hex_rgba(char *output, struct nk_color col)
5712 {
5713 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
5714 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
5715 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
5716 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
5717 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
5718 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
5719 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
5720 output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);
5721 output[7] = (char)NK_TO_HEX((col.a & 0x0F));
5722 output[8] = '\0';
5723 #undef NK_TO_HEX
5724 }
5725
5726 NK_API void
5727 nk_color_hex_rgb(char *output, struct nk_color col)
5728 {
5729 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
5730 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
5731 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
5732 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
5733 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
5734 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
5735 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
5736 output[6] = '\0';
5737 #undef NK_TO_HEX
5738 }
5739
5740 NK_API struct nk_color
5741 nk_rgba_iv(const int *c)
5742 {
5743 return nk_rgba(c[0], c[1], c[2], c[3]);
5744 }
5745
5746 NK_API struct nk_color
5747 nk_rgba_bv(const nk_byte *c)
5748 {
5749 return nk_rgba(c[0], c[1], c[2], c[3]);
5750 }
5751
5752 NK_API struct nk_color
5753 nk_rgb(int r, int g, int b)
5754 {
5755 struct nk_color ret;
5756 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
5757 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
5758 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
5759 ret.a = (nk_byte)255;
5760 return ret;
5761 }
5762
5763 NK_API struct nk_color
5764 nk_rgb_iv(const int *c)
5765 {
5766 return nk_rgb(c[0], c[1], c[2]);
5767 }
5768
5769 NK_API struct nk_color
5770 nk_rgb_bv(const nk_byte* c)
5771 {
5772 return nk_rgb(c[0], c[1], c[2]);
5773 }
5774
5775 NK_API struct nk_color
5776 nk_rgba_u32(nk_uint in)
5777 {
5778 struct nk_color ret;
5779 ret.r = (in & 0xFF);
5780 ret.g = ((in >> 8) & 0xFF);
5781 ret.b = ((in >> 16) & 0xFF);
5782 ret.a = (nk_byte)((in >> 24) & 0xFF);
5783 return ret;
5784 }
5785
5786 NK_API struct nk_color
5787 nk_rgba_f(float r, float g, float b, float a)
5788 {
5789 struct nk_color ret;
5790 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
5791 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
5792 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
5793 ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);
5794 return ret;
5795 }
5796
5797 NK_API struct nk_color
5798 nk_rgba_fv(const float *c)
5799 {
5800 return nk_rgba_f(c[0], c[1], c[2], c[3]);
5801 }
5802
5803 NK_API struct nk_color
5804 nk_rgb_f(float r, float g, float b)
5805 {
5806 struct nk_color ret;
5807 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
5808 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
5809 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
5810 ret.a = 255;
5811 return ret;
5812 }
5813
5814 NK_API struct nk_color
5815 nk_rgb_fv(const float *c)
5816 {
5817 return nk_rgb_f(c[0], c[1], c[2]);
5818 }
5819
5820 NK_API struct nk_color
5821 nk_hsv(int h, int s, int v)
5822 {
5823 return nk_hsva(h, s, v, 255);
5824 }
5825
5826 NK_API struct nk_color
5827 nk_hsv_iv(const int *c)
5828 {
5829 return nk_hsv(c[0], c[1], c[2]);
5830 }
5831
5832 NK_API struct nk_color
5833 nk_hsv_bv(const nk_byte *c)
5834 {
5835 return nk_hsv(c[0], c[1], c[2]);
5836 }
5837
5838 NK_API struct nk_color
5839 nk_hsv_f(float h, float s, float v)
5840 {
5841 return nk_hsva_f(h, s, v, 1.0f);
5842 }
5843
5844 NK_API struct nk_color
5845 nk_hsv_fv(const float *c)
5846 {
5847 return nk_hsv_f(c[0], c[1], c[2]);
5848 }
5849
5850 NK_API struct nk_color
5851 nk_hsva(int h, int s, int v, int a)
5852 {
5853 float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;
5854 float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;
5855 float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;
5856 float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;
5857 return nk_hsva_f(hf, sf, vf, af);
5858 }
5859
5860 NK_API struct nk_color
5861 nk_hsva_iv(const int *c)
5862 {
5863 return nk_hsva(c[0], c[1], c[2], c[3]);
5864 }
5865
5866 NK_API struct nk_color
5867 nk_hsva_bv(const nk_byte *c)
5868 {
5869 return nk_hsva(c[0], c[1], c[2], c[3]);
5870 }
5871
5872 NK_API struct nk_color
5873 nk_hsva_f(float h, float s, float v, float a)
5874 {
5875 struct nk_colorf out = {0,0,0,0};
5876 float p, q, t, f;
5877 int i;
5878
5879 if (s <= 0.0f) {
5880 out.r = v; out.g = v; out.b = v;
5881 return nk_rgb_f(out.r, out.g, out.b);
5882 }
5883
5884 h = h / (60.0f/360.0f);
5885 i = (int)h;
5886 f = h - (float)i;
5887 p = v * (1.0f - s);
5888 q = v * (1.0f - (s * f));
5889 t = v * (1.0f - s * (1.0f - f));
5890
5891 switch (i) {
5892 case 0: default: out.r = v; out.g = t; out.b = p; break;
5893 case 1: out.r = q; out.g = v; out.b = p; break;
5894 case 2: out.r = p; out.g = v; out.b = t; break;
5895 case 3: out.r = p; out.g = q; out.b = v; break;
5896 case 4: out.r = t; out.g = p; out.b = v; break;
5897 case 5: out.r = v; out.g = p; out.b = q; break;
5898 }
5899 return nk_rgba_f(out.r, out.g, out.b, a);
5900 }
5901
5902 NK_API struct nk_color
5903 nk_hsva_fv(const float *c)
5904 {
5905 return nk_hsva_f(c[0], c[1], c[2], c[3]);
5906 }
5907
5908 NK_API nk_uint
5909 nk_color_u32(struct nk_color in)
5910 {
5911 nk_uint out = (nk_uint)in.r;
5912 out |= ((nk_uint)in.g << 8);
5913 out |= ((nk_uint)in.b << 16);
5914 out |= ((nk_uint)in.a << 24);
5915 return out;
5916 }
5917
5918 NK_API void
5919 nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)
5920 {
5921 NK_STORAGE const float s = 1.0f/255.0f;
5922 *r = (float)in.r * s;
5923 *g = (float)in.g * s;
5924 *b = (float)in.b * s;
5925 *a = (float)in.a * s;
5926 }
5927
5928 NK_API void
5929 nk_color_fv(float *c, struct nk_color in)
5930 {
5931 nk_color_f(&c[0], &c[1], &c[2], &c[3], in);
5932 }
5933
5934 NK_API void
5935 nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)
5936 {
5937 NK_STORAGE const double s = 1.0/255.0;
5938 *r = (double)in.r * s;
5939 *g = (double)in.g * s;
5940 *b = (double)in.b * s;
5941 *a = (double)in.a * s;
5942 }
5943
5944 NK_API void
5945 nk_color_dv(double *c, struct nk_color in)
5946 {
5947 nk_color_d(&c[0], &c[1], &c[2], &c[3], in);
5948 }
5949
5950 NK_API void
5951 nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)
5952 {
5953 float a;
5954 nk_color_hsva_f(out_h, out_s, out_v, &a, in);
5955 }
5956
5957 NK_API void
5958 nk_color_hsv_fv(float *out, struct nk_color in)
5959 {
5960 float a;
5961 nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);
5962 }
5963
5964 NK_API void
5965 nk_color_hsva_f(float *out_h, float *out_s,
5966 float *out_v, float *out_a, struct nk_color in)
5967 {
5968 float chroma;
5969 float K = 0.0f;
5970 float r,g,b,a;
5971
5972 nk_color_f(&r,&g,&b,&a, in);
5973 if (g < b) {
5974 const float t = g; g = b; b = t;
5975 K = -1.f;
5976 }
5977 if (r < g) {
5978 const float t = r; r = g; g = t;
5979 K = -2.f/6.0f - K;
5980 }
5981 chroma = r - ((g < b) ? g: b);
5982 *out_h = NK_ABS(K + (g - b)/(6.0f * chroma + 1e-20f));
5983 *out_s = chroma / (r + 1e-20f);
5984 *out_v = r;
5985 *out_a = (float)in.a / 255.0f;
5986 }
5987
5988 NK_API void
5989 nk_color_hsva_fv(float *out, struct nk_color in)
5990 {
5991 nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);
5992 }
5993
5994 NK_API void
5995 nk_color_hsva_i(int *out_h, int *out_s, int *out_v,
5996 int *out_a, struct nk_color in)
5997 {
5998 float h,s,v,a;
5999 nk_color_hsva_f(&h, &s, &v, &a, in);
6000 *out_h = (nk_byte)(h * 255.0f);
6001 *out_s = (nk_byte)(s * 255.0f);
6002 *out_v = (nk_byte)(v * 255.0f);
6003 *out_a = (nk_byte)(a * 255.0f);
6004 }
6005
6006 NK_API void
6007 nk_color_hsva_iv(int *out, struct nk_color in)
6008 {
6009 nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);
6010 }
6011
6012 NK_API void
6013 nk_color_hsva_bv(nk_byte *out, struct nk_color in)
6014 {
6015 int tmp[4];
6016 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
6017 out[0] = (nk_byte)tmp[0];
6018 out[1] = (nk_byte)tmp[1];
6019 out[2] = (nk_byte)tmp[2];
6020 out[3] = (nk_byte)tmp[3];
6021 }
6022
6023 NK_API void
6024 nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)
6025 {
6026 int tmp[4];
6027 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
6028 *h = (nk_byte)tmp[0];
6029 *s = (nk_byte)tmp[1];
6030 *v = (nk_byte)tmp[2];
6031 *a = (nk_byte)tmp[3];
6032 }
6033
6034 NK_API void
6035 nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)
6036 {
6037 int a;
6038 nk_color_hsva_i(out_h, out_s, out_v, &a, in);
6039 }
6040
6041 NK_API void
6042 nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)
6043 {
6044 int tmp[4];
6045 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
6046 *out_h = (nk_byte)tmp[0];
6047 *out_s = (nk_byte)tmp[1];
6048 *out_v = (nk_byte)tmp[2];
6049 }
6050
6051 NK_API void
6052 nk_color_hsv_iv(int *out, struct nk_color in)
6053 {
6054 nk_color_hsv_i(&out[0], &out[1], &out[2], in);
6055 }
6056
6057 NK_API void
6058 nk_color_hsv_bv(nk_byte *out, struct nk_color in)
6059 {
6060 int tmp[4];
6061 nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);
6062 out[0] = (nk_byte)tmp[0];
6063 out[1] = (nk_byte)tmp[1];
6064 out[2] = (nk_byte)tmp[2];
6065 }
6066 /*
6067 * ==============================================================
6068 *
6069 * IMAGE
6070 *
6071 * ===============================================================
6072 */
6073 NK_API nk_handle
6074 nk_handle_ptr(void *ptr)
6075 {
6076 nk_handle handle = {0};
6077 handle.ptr = ptr;
6078 return handle;
6079 }
6080
6081 NK_API nk_handle
6082 nk_handle_id(int id)
6083 {
6084 nk_handle handle;
6085 nk_zero_struct(handle);
6086 handle.id = id;
6087 return handle;
6088 }
6089
6090 NK_API struct nk_image
6091 nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r)
6092 {
6093 struct nk_image s;
6094 nk_zero(&s, sizeof(s));
6095 s.handle.ptr = ptr;
6096 s.w = w; s.h = h;
6097 s.region[0] = (unsigned short)r.x;
6098 s.region[1] = (unsigned short)r.y;
6099 s.region[2] = (unsigned short)r.w;
6100 s.region[3] = (unsigned short)r.h;
6101 return s;
6102 }
6103
6104 NK_API struct nk_image
6105 nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r)
6106 {
6107 struct nk_image s;
6108 nk_zero(&s, sizeof(s));
6109 s.handle.id = id;
6110 s.w = w; s.h = h;
6111 s.region[0] = (unsigned short)r.x;
6112 s.region[1] = (unsigned short)r.y;
6113 s.region[2] = (unsigned short)r.w;
6114 s.region[3] = (unsigned short)r.h;
6115 return s;
6116 }
6117
6118 NK_API struct nk_image
6119 nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h,
6120 struct nk_rect r)
6121 {
6122 struct nk_image s;
6123 nk_zero(&s, sizeof(s));
6124 s.handle = handle;
6125 s.w = w; s.h = h;
6126 s.region[0] = (unsigned short)r.x;
6127 s.region[1] = (unsigned short)r.y;
6128 s.region[2] = (unsigned short)r.w;
6129 s.region[3] = (unsigned short)r.h;
6130 return s;
6131 }
6132
6133 NK_API struct nk_image
6134 nk_image_handle(nk_handle handle)
6135 {
6136 struct nk_image s;
6137 nk_zero(&s, sizeof(s));
6138 s.handle = handle;
6139 s.w = 0; s.h = 0;
6140 s.region[0] = 0;
6141 s.region[1] = 0;
6142 s.region[2] = 0;
6143 s.region[3] = 0;
6144 return s;
6145 }
6146
6147 NK_API struct nk_image
6148 nk_image_ptr(void *ptr)
6149 {
6150 struct nk_image s;
6151 nk_zero(&s, sizeof(s));
6152 NK_ASSERT(ptr);
6153 s.handle.ptr = ptr;
6154 s.w = 0; s.h = 0;
6155 s.region[0] = 0;
6156 s.region[1] = 0;
6157 s.region[2] = 0;
6158 s.region[3] = 0;
6159 return s;
6160 }
6161
6162 NK_API struct nk_image
6163 nk_image_id(int id)
6164 {
6165 struct nk_image s;
6166 nk_zero(&s, sizeof(s));
6167 s.handle.id = id;
6168 s.w = 0; s.h = 0;
6169 s.region[0] = 0;
6170 s.region[1] = 0;
6171 s.region[2] = 0;
6172 s.region[3] = 0;
6173 return s;
6174 }
6175
6176 NK_API int
6177 nk_image_is_subimage(const struct nk_image* img)
6178 {
6179 NK_ASSERT(img);
6180 return !(img->w == 0 && img->h == 0);
6181 }
6182
6183 NK_INTERN void
6184 nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,
6185 float x1, float y1)
6186 {
6187 NK_ASSERT(a);
6188 NK_ASSERT(clip);
6189 clip->x = NK_MAX(a->x, x0);
6190 clip->y = NK_MAX(a->y, y0);
6191 clip->w = NK_MIN(a->x + a->w, x1) - clip->x;
6192 clip->h = NK_MIN(a->y + a->h, y1) - clip->y;
6193 clip->w = NK_MAX(0, clip->w);
6194 clip->h = NK_MAX(0, clip->h);
6195 }
6196
6197 NK_API void
6198 nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,
6199 float pad_x, float pad_y, enum nk_heading direction)
6200 {
6201 float w_half, h_half;
6202 NK_ASSERT(result);
6203
6204 r.w = NK_MAX(2 * pad_x, r.w);
6205 r.h = NK_MAX(2 * pad_y, r.h);
6206 r.w = r.w - 2 * pad_x;
6207 r.h = r.h - 2 * pad_y;
6208
6209 r.x = r.x + pad_x;
6210 r.y = r.y + pad_y;
6211
6212 w_half = r.w / 2.0f;
6213 h_half = r.h / 2.0f;
6214
6215 if (direction == NK_UP) {
6216 result[0] = nk_vec2(r.x + w_half, r.y);
6217 result[1] = nk_vec2(r.x + r.w, r.y + r.h);
6218 result[2] = nk_vec2(r.x, r.y + r.h);
6219 } else if (direction == NK_RIGHT) {
6220 result[0] = nk_vec2(r.x, r.y);
6221 result[1] = nk_vec2(r.x + r.w, r.y + h_half);
6222 result[2] = nk_vec2(r.x, r.y + r.h);
6223 } else if (direction == NK_DOWN) {
6224 result[0] = nk_vec2(r.x, r.y);
6225 result[1] = nk_vec2(r.x + r.w, r.y);
6226 result[2] = nk_vec2(r.x + w_half, r.y + r.h);
6227 } else {
6228 result[0] = nk_vec2(r.x, r.y + h_half);
6229 result[1] = nk_vec2(r.x + r.w, r.y);
6230 result[2] = nk_vec2(r.x + r.w, r.y + r.h);
6231 }
6232 }
6233
6234 NK_INTERN int
6235 nk_text_clamp(const struct nk_user_font *font, const char *text,
6236 int text_len, float space, int *glyphs, float *text_width,
6237 nk_rune *sep_list, int sep_count)
6238 {
6239 int i = 0;
6240 int glyph_len = 0;
6241 float last_width = 0;
6242 nk_rune unicode = 0;
6243 float width = 0;
6244 int len = 0;
6245 int g = 0;
6246 float s;
6247
6248 int sep_len = 0;
6249 int sep_g = 0;
6250 float sep_width = 0;
6251 sep_count = NK_MAX(sep_count,0);
6252
6253 glyph_len = nk_utf_decode(text, &unicode, text_len);
6254 while (glyph_len && (width < space) && (len < text_len)) {
6255 len += glyph_len;
6256 s = font->width(font->userdata, font->height, text, len);
6257 for (i = 0; i < sep_count; ++i) {
6258 if (unicode != sep_list[i]) continue;
6259 sep_width = last_width = width;
6260 sep_g = g+1;
6261 sep_len = len;
6262 break;
6263 }
6264 if (i == sep_count){
6265 last_width = sep_width = width;
6266 sep_g = g+1;
6267 }
6268 width = s;
6269 glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);
6270 g++;
6271 }
6272 if (len >= text_len) {
6273 *glyphs = g;
6274 *text_width = last_width;
6275 return len;
6276 } else {
6277 *glyphs = sep_g;
6278 *text_width = sep_width;
6279 return (!sep_len) ? len: sep_len;
6280 }
6281 }
6282
6283 enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};
6284 NK_INTERN struct nk_vec2
6285 nk_text_calculate_text_bounds(const struct nk_user_font *font,
6286 const char *begin, int byte_len, float row_height, const char **remaining,
6287 struct nk_vec2 *out_offset, int *glyphs, int op)
6288 {
6289 float line_height = row_height;
6290 struct nk_vec2 text_size = nk_vec2(0,0);
6291 float line_width = 0.0f;
6292
6293 float glyph_width;
6294 int glyph_len = 0;
6295 nk_rune unicode = 0;
6296 int text_len = 0;
6297 if (!begin || byte_len <= 0 || !font)
6298 return nk_vec2(0,row_height);
6299
6300 glyph_len = nk_utf_decode(begin, &unicode, byte_len);
6301 if (!glyph_len) return text_size;
6302 glyph_width = font->width(font->userdata, font->height, begin, glyph_len);
6303
6304 *glyphs = 0;
6305 while ((text_len < byte_len) && glyph_len) {
6306 if (unicode == '\n') {
6307 text_size.x = NK_MAX(text_size.x, line_width);
6308 text_size.y += line_height;
6309 line_width = 0;
6310 *glyphs+=1;
6311 if (op == NK_STOP_ON_NEW_LINE)
6312 break;
6313
6314 text_len++;
6315 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
6316 continue;
6317 }
6318
6319 if (unicode == '\r') {
6320 text_len++;
6321 *glyphs+=1;
6322 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
6323 continue;
6324 }
6325
6326 *glyphs = *glyphs + 1;
6327 text_len += glyph_len;
6328 line_width += (float)glyph_width;
6329 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
6330 glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);
6331 continue;
6332 }
6333
6334 if (text_size.x < line_width)
6335 text_size.x = line_width;
6336 if (out_offset)
6337 *out_offset = nk_vec2(line_width, text_size.y + line_height);
6338 if (line_width > 0 || text_size.y == 0.0f)
6339 text_size.y += line_height;
6340 if (remaining)
6341 *remaining = begin+text_len;
6342 return text_size;
6343 }
6344
6345 /* ==============================================================
6346 *
6347 * UTF-8
6348 *
6349 * ===============================================================*/
6350 NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
6351 NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
6352 NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};
6353 NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
6354
6355 NK_INTERN int
6356 nk_utf_validate(nk_rune *u, int i)
6357 {
6358 NK_ASSERT(u);
6359 if (!u) return 0;
6360 if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||
6361 NK_BETWEEN(*u, 0xD800, 0xDFFF))
6362 *u = NK_UTF_INVALID;
6363 for (i = 1; *u > nk_utfmax[i]; ++i);
6364 return i;
6365 }
6366
6367 NK_INTERN nk_rune
6368 nk_utf_decode_byte(char c, int *i)
6369 {
6370 NK_ASSERT(i);
6371 if (!i) return 0;
6372 for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {
6373 if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])
6374 return (nk_byte)(c & ~nk_utfmask[*i]);
6375 }
6376 return 0;
6377 }
6378
6379 NK_API int
6380 nk_utf_decode(const char *c, nk_rune *u, int clen)
6381 {
6382 int i, j, len, type=0;
6383 nk_rune udecoded;
6384
6385 NK_ASSERT(c);
6386 NK_ASSERT(u);
6387
6388 if (!c || !u) return 0;
6389 if (!clen) return 0;
6390 *u = NK_UTF_INVALID;
6391
6392 udecoded = nk_utf_decode_byte(c[0], &len);
6393 if (!NK_BETWEEN(len, 1, NK_UTF_SIZE))
6394 return 1;
6395
6396 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
6397 udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);
6398 if (type != 0)
6399 return j;
6400 }
6401 if (j < len)
6402 return 0;
6403 *u = udecoded;
6404 nk_utf_validate(u, len);
6405 return len;
6406 }
6407
6408 NK_INTERN char
6409 nk_utf_encode_byte(nk_rune u, int i)
6410 {
6411 return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));
6412 }
6413
6414 NK_API int
6415 nk_utf_encode(nk_rune u, char *c, int clen)
6416 {
6417 int len, i;
6418 len = nk_utf_validate(&u, 0);
6419 if (clen < len || !len || len > NK_UTF_SIZE)
6420 return 0;
6421
6422 for (i = len - 1; i != 0; --i) {
6423 c[i] = nk_utf_encode_byte(u, 0);
6424 u >>= 6;
6425 }
6426 c[0] = nk_utf_encode_byte(u, len);
6427 return len;
6428 }
6429
6430 NK_API int
6431 nk_utf_len(const char *str, int len)
6432 {
6433 const char *text;
6434 int glyphs = 0;
6435 int text_len;
6436 int glyph_len;
6437 int src_len = 0;
6438 nk_rune unicode;
6439
6440 NK_ASSERT(str);
6441 if (!str || !len) return 0;
6442
6443 text = str;
6444 text_len = len;
6445 glyph_len = nk_utf_decode(text, &unicode, text_len);
6446 while (glyph_len && src_len < len) {
6447 glyphs++;
6448 src_len = src_len + glyph_len;
6449 glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);
6450 }
6451 return glyphs;
6452 }
6453
6454 NK_API const char*
6455 nk_utf_at(const char *buffer, int length, int index,
6456 nk_rune *unicode, int *len)
6457 {
6458 int i = 0;
6459 int src_len = 0;
6460 int glyph_len = 0;
6461 const char *text;
6462 int text_len;
6463
6464 NK_ASSERT(buffer);
6465 NK_ASSERT(unicode);
6466 NK_ASSERT(len);
6467
6468 if (!buffer || !unicode || !len) return 0;
6469 if (index < 0) {
6470 *unicode = NK_UTF_INVALID;
6471 *len = 0;
6472 return 0;
6473 }
6474
6475 text = buffer;
6476 text_len = length;
6477 glyph_len = nk_utf_decode(text, unicode, text_len);
6478 while (glyph_len) {
6479 if (i == index) {
6480 *len = glyph_len;
6481 break;
6482 }
6483
6484 i++;
6485 src_len = src_len + glyph_len;
6486 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
6487 }
6488 if (i != index) return 0;
6489 return buffer + src_len;
6490 }
6491
6492 /* ==============================================================
6493 *
6494 * BUFFER
6495 *
6496 * ===============================================================*/
6497 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6498 NK_INTERN void* nk_malloc(nk_handle unused, void *old,nk_size size)
6499 {NK_UNUSED(unused); NK_UNUSED(old); return malloc(size);}
6500 NK_INTERN void nk_mfree(nk_handle unused, void *ptr)
6501 {NK_UNUSED(unused); free(ptr);}
6502
6503 NK_API void
6504 nk_buffer_init_default(struct nk_buffer *buffer)
6505 {
6506 struct nk_allocator alloc;
6507 alloc.userdata.ptr = 0;
6508 alloc.alloc = nk_malloc;
6509 alloc.free = nk_mfree;
6510 nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);
6511 }
6512 #endif
6513
6514 NK_API void
6515 nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,
6516 nk_size initial_size)
6517 {
6518 NK_ASSERT(b);
6519 NK_ASSERT(a);
6520 NK_ASSERT(initial_size);
6521 if (!b || !a || !initial_size) return;
6522
6523 nk_zero(b, sizeof(*b));
6524 b->type = NK_BUFFER_DYNAMIC;
6525 b->memory.ptr = a->alloc(a->userdata,0, initial_size);
6526 b->memory.size = initial_size;
6527 b->size = initial_size;
6528 b->grow_factor = 2.0f;
6529 b->pool = *a;
6530 }
6531
6532 NK_API void
6533 nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)
6534 {
6535 NK_ASSERT(b);
6536 NK_ASSERT(m);
6537 NK_ASSERT(size);
6538 if (!b || !m || !size) return;
6539
6540 nk_zero(b, sizeof(*b));
6541 b->type = NK_BUFFER_FIXED;
6542 b->memory.ptr = m;
6543 b->memory.size = size;
6544 b->size = size;
6545 }
6546
6547 NK_INTERN void*
6548 nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment,
6549 enum nk_buffer_allocation_type type)
6550 {
6551 void *memory = 0;
6552 switch (type) {
6553 default:
6554 case NK_BUFFER_MAX:
6555 case NK_BUFFER_FRONT:
6556 if (align) {
6557 memory = NK_ALIGN_PTR(unaligned, align);
6558 *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
6559 } else {
6560 memory = unaligned;
6561 *alignment = 0;
6562 }
6563 break;
6564 case NK_BUFFER_BACK:
6565 if (align) {
6566 memory = NK_ALIGN_PTR_BACK(unaligned, align);
6567 *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);
6568 } else {
6569 memory = unaligned;
6570 *alignment = 0;
6571 }
6572 break;
6573 }
6574 return memory;
6575 }
6576
6577 NK_INTERN void*
6578 nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
6579 {
6580 void *temp;
6581 nk_size buffer_size;
6582
6583 NK_ASSERT(b);
6584 NK_ASSERT(size);
6585 if (!b || !size || !b->pool.alloc || !b->pool.free)
6586 return 0;
6587
6588 buffer_size = b->memory.size;
6589 temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
6590 NK_ASSERT(temp);
6591 if (!temp) return 0;
6592
6593 *size = capacity;
6594 if (temp != b->memory.ptr) {
6595 NK_MEMCPY(temp, b->memory.ptr, buffer_size);
6596 b->pool.free(b->pool.userdata, b->memory.ptr);
6597 }
6598
6599 if (b->size == buffer_size) {
6600 /* no back buffer so just set correct size */
6601 b->size = capacity;
6602 return temp;
6603 } else {
6604 /* copy back buffer to the end of the new buffer */
6605 void *dst, *src;
6606 nk_size back_size;
6607 back_size = buffer_size - b->size;
6608 dst = nk_ptr_add(void, temp, capacity - back_size);
6609 src = nk_ptr_add(void, temp, b->size);
6610 NK_MEMCPY(dst, src, back_size);
6611 b->size = capacity - back_size;
6612 }
6613 return temp;
6614 }
6615
6616 NK_INTERN void*
6617 nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,
6618 nk_size size, nk_size align)
6619 {
6620 int full;
6621 nk_size alignment;
6622 void *unaligned;
6623 void *memory;
6624
6625 NK_ASSERT(b);
6626 NK_ASSERT(size);
6627 if (!b || !size) return 0;
6628 b->needed += size;
6629
6630 /* calculate total size with needed alignment + size */
6631 if (type == NK_BUFFER_FRONT)
6632 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
6633 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
6634 memory = nk_buffer_align(unaligned, align, &alignment, type);
6635
6636 /* check if buffer has enough memory*/
6637 if (type == NK_BUFFER_FRONT)
6638 full = ((b->allocated + size + alignment) > b->size);
6639 else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);
6640
6641 if (full) {
6642 nk_size capacity;
6643 if (b->type != NK_BUFFER_DYNAMIC)
6644 return 0;
6645 NK_ASSERT(b->pool.alloc && b->pool.free);
6646 if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)
6647 return 0;
6648
6649 /* buffer is full so allocate bigger buffer if dynamic */
6650 capacity = (nk_size)((float)b->memory.size * b->grow_factor);
6651 capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));
6652 b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);
6653 if (!b->memory.ptr) return 0;
6654
6655 /* align newly allocated pointer */
6656 if (type == NK_BUFFER_FRONT)
6657 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
6658 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
6659 memory = nk_buffer_align(unaligned, align, &alignment, type);
6660 }
6661 if (type == NK_BUFFER_FRONT)
6662 b->allocated += size + alignment;
6663 else b->size -= (size + alignment);
6664 b->needed += alignment;
6665 b->calls++;
6666 return memory;
6667 }
6668
6669 NK_API void
6670 nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,
6671 const void *memory, nk_size size, nk_size align)
6672 {
6673 void *mem = nk_buffer_alloc(b, type, size, align);
6674 if (!mem) return;
6675 NK_MEMCPY(mem, memory, size);
6676 }
6677
6678 NK_API void
6679 nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
6680 {
6681 NK_ASSERT(buffer);
6682 if (!buffer) return;
6683 buffer->marker[type].active = nk_true;
6684 if (type == NK_BUFFER_BACK)
6685 buffer->marker[type].offset = buffer->size;
6686 else buffer->marker[type].offset = buffer->allocated;
6687 }
6688
6689 NK_API void
6690 nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
6691 {
6692 NK_ASSERT(buffer);
6693 if (!buffer) return;
6694 if (type == NK_BUFFER_BACK) {
6695 /* reset back buffer either back to marker or empty */
6696 buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);
6697 if (buffer->marker[type].active)
6698 buffer->size = buffer->marker[type].offset;
6699 else buffer->size = buffer->memory.size;
6700 buffer->marker[type].active = nk_false;
6701 } else {
6702 /* reset front buffer either back to back marker or empty */
6703 buffer->needed -= (buffer->allocated - buffer->marker[type].offset);
6704 if (buffer->marker[type].active)
6705 buffer->allocated = buffer->marker[type].offset;
6706 else buffer->allocated = 0;
6707 buffer->marker[type].active = nk_false;
6708 }
6709 }
6710
6711 NK_API void
6712 nk_buffer_clear(struct nk_buffer *b)
6713 {
6714 NK_ASSERT(b);
6715 if (!b) return;
6716 b->allocated = 0;
6717 b->size = b->memory.size;
6718 b->calls = 0;
6719 b->needed = 0;
6720 }
6721
6722 NK_API void
6723 nk_buffer_free(struct nk_buffer *b)
6724 {
6725 NK_ASSERT(b);
6726 if (!b || !b->memory.ptr) return;
6727 if (b->type == NK_BUFFER_FIXED) return;
6728 if (!b->pool.free) return;
6729 NK_ASSERT(b->pool.free);
6730 b->pool.free(b->pool.userdata, b->memory.ptr);
6731 }
6732
6733 NK_API void
6734 nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b)
6735 {
6736 NK_ASSERT(b);
6737 NK_ASSERT(s);
6738 if (!s || !b) return;
6739 s->allocated = b->allocated;
6740 s->size = b->memory.size;
6741 s->needed = b->needed;
6742 s->memory = b->memory.ptr;
6743 s->calls = b->calls;
6744 }
6745
6746 NK_API void*
6747 nk_buffer_memory(struct nk_buffer *buffer)
6748 {
6749 NK_ASSERT(buffer);
6750 if (!buffer) return 0;
6751 return buffer->memory.ptr;
6752 }
6753
6754 NK_API const void*
6755 nk_buffer_memory_const(const struct nk_buffer *buffer)
6756 {
6757 NK_ASSERT(buffer);
6758 if (!buffer) return 0;
6759 return buffer->memory.ptr;
6760 }
6761
6762 NK_API nk_size
6763 nk_buffer_total(struct nk_buffer *buffer)
6764 {
6765 NK_ASSERT(buffer);
6766 if (!buffer) return 0;
6767 return buffer->memory.size;
6768 }
6769
6770 /*
6771 * ==============================================================
6772 *
6773 * STRING
6774 *
6775 * ===============================================================
6776 */
6777 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6778 NK_API void
6779 nk_str_init_default(struct nk_str *str)
6780 {
6781 struct nk_allocator alloc;
6782 alloc.userdata.ptr = 0;
6783 alloc.alloc = nk_malloc;
6784 alloc.free = nk_mfree;
6785 nk_buffer_init(&str->buffer, &alloc, 32);
6786 str->len = 0;
6787 }
6788 #endif
6789
6790 NK_API void
6791 nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)
6792 {
6793 nk_buffer_init(&str->buffer, alloc, size);
6794 str->len = 0;
6795 }
6796
6797 NK_API void
6798 nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)
6799 {
6800 nk_buffer_init_fixed(&str->buffer, memory, size);
6801 str->len = 0;
6802 }
6803
6804 NK_API int
6805 nk_str_append_text_char(struct nk_str *s, const char *str, int len)
6806 {
6807 char *mem;
6808 NK_ASSERT(s);
6809 NK_ASSERT(str);
6810 if (!s || !str || !len) return 0;
6811 mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
6812 if (!mem) return 0;
6813 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
6814 s->len += nk_utf_len(str, len);
6815 return len;
6816 }
6817
6818 NK_API int
6819 nk_str_append_str_char(struct nk_str *s, const char *str)
6820 {
6821 return nk_str_append_text_char(s, str, nk_strlen(str));
6822 }
6823
6824 NK_API int
6825 nk_str_append_text_utf8(struct nk_str *str, const char *text, int len)
6826 {
6827 int i = 0;
6828 int byte_len = 0;
6829 nk_rune unicode;
6830 if (!str || !text || !len) return 0;
6831 for (i = 0; i < len; ++i)
6832 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
6833 nk_str_append_text_char(str, text, byte_len);
6834 return len;
6835 }
6836
6837 NK_API int
6838 nk_str_append_str_utf8(struct nk_str *str, const char *text)
6839 {
6840 int runes = 0;
6841 int byte_len = 0;
6842 int num_runes = 0;
6843 int glyph_len = 0;
6844 nk_rune unicode;
6845 if (!str || !text) return 0;
6846
6847 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
6848 while (unicode != '\0' && glyph_len) {
6849 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
6850 byte_len += glyph_len;
6851 num_runes++;
6852 }
6853 nk_str_append_text_char(str, text, byte_len);
6854 return runes;
6855 }
6856
6857 NK_API int
6858 nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)
6859 {
6860 int i = 0;
6861 int byte_len = 0;
6862 nk_glyph glyph;
6863
6864 NK_ASSERT(str);
6865 if (!str || !text || !len) return 0;
6866 for (i = 0; i < len; ++i) {
6867 byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);
6868 if (!byte_len) break;
6869 nk_str_append_text_char(str, glyph, byte_len);
6870 }
6871 return len;
6872 }
6873
6874 NK_API int
6875 nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)
6876 {
6877 int i = 0;
6878 nk_glyph glyph;
6879 int byte_len;
6880 NK_ASSERT(str);
6881 if (!str || !runes) return 0;
6882 while (runes[i] != '\0') {
6883 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
6884 nk_str_append_text_char(str, glyph, byte_len);
6885 i++;
6886 }
6887 return i;
6888 }
6889
6890 NK_API int
6891 nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)
6892 {
6893 int i;
6894 void *mem;
6895 char *src;
6896 char *dst;
6897
6898 int copylen;
6899 NK_ASSERT(s);
6900 NK_ASSERT(str);
6901 NK_ASSERT(len >= 0);
6902 if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;
6903 if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&
6904 (s->buffer.type == NK_BUFFER_FIXED)) return 0;
6905
6906 copylen = (int)s->buffer.allocated - pos;
6907 if (!copylen) {
6908 nk_str_append_text_char(s, str, len);
6909 return 1;
6910 }
6911 mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
6912 if (!mem) return 0;
6913
6914 /* memmove */
6915 NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);
6916 NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);
6917 dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));
6918 src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));
6919 for (i = 0; i < copylen; ++i) *dst-- = *src--;
6920 mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);
6921 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
6922 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
6923 return 1;
6924 }
6925
6926 NK_API int
6927 nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)
6928 {
6929 int glyph_len;
6930 nk_rune unicode;
6931 const char *begin;
6932 const char *buffer;
6933
6934 NK_ASSERT(str);
6935 NK_ASSERT(cstr);
6936 NK_ASSERT(len);
6937 if (!str || !cstr || !len) return 0;
6938 begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);
6939 if (!str->len)
6940 return nk_str_append_text_char(str, cstr, len);
6941 buffer = nk_str_get_const(str);
6942 if (!begin) return 0;
6943 return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);
6944 }
6945
6946 NK_API int
6947 nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)
6948 {
6949 return nk_str_insert_text_utf8(str, pos, text, len);
6950 }
6951
6952 NK_API int
6953 nk_str_insert_str_char(struct nk_str *str, int pos, const char *text)
6954 {
6955 return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));
6956 }
6957
6958 NK_API int
6959 nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
6960 {
6961 int i = 0;
6962 int byte_len = 0;
6963 nk_rune unicode;
6964
6965 NK_ASSERT(str);
6966 NK_ASSERT(text);
6967 if (!str || !text || !len) return 0;
6968 for (i = 0; i < len; ++i)
6969 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
6970 nk_str_insert_at_rune(str, pos, text, byte_len);
6971 return len;
6972 }
6973
6974 NK_API int
6975 nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
6976 {
6977 int runes = 0;
6978 int byte_len = 0;
6979 int num_runes = 0;
6980 int glyph_len = 0;
6981 nk_rune unicode;
6982 if (!str || !text) return 0;
6983
6984 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
6985 while (unicode != '\0' && glyph_len) {
6986 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
6987 byte_len += glyph_len;
6988 num_runes++;
6989 }
6990 nk_str_insert_at_rune(str, pos, text, byte_len);
6991 return runes;
6992 }
6993
6994 NK_API int
6995 nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)
6996 {
6997 int i = 0;
6998 int byte_len = 0;
6999 nk_glyph glyph;
7000
7001 NK_ASSERT(str);
7002 if (!str || !runes || !len) return 0;
7003 for (i = 0; i < len; ++i) {
7004 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
7005 if (!byte_len) break;
7006 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
7007 }
7008 return len;
7009 }
7010
7011 NK_API int
7012 nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)
7013 {
7014 int i = 0;
7015 nk_glyph glyph;
7016 int byte_len;
7017 NK_ASSERT(str);
7018 if (!str || !runes) return 0;
7019 while (runes[i] != '\0') {
7020 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
7021 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
7022 i++;
7023 }
7024 return i;
7025 }
7026
7027 NK_API void
7028 nk_str_remove_chars(struct nk_str *s, int len)
7029 {
7030 NK_ASSERT(s);
7031 NK_ASSERT(len >= 0);
7032 if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;
7033 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
7034 s->buffer.allocated -= (nk_size)len;
7035 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
7036 }
7037
7038 NK_API void
7039 nk_str_remove_runes(struct nk_str *str, int len)
7040 {
7041 int index;
7042 const char *begin;
7043 const char *end;
7044 nk_rune unicode;
7045
7046 NK_ASSERT(str);
7047 NK_ASSERT(len >= 0);
7048 if (!str || len < 0) return;
7049 if (len >= str->len) {
7050 str->len = 0;
7051 return;
7052 }
7053
7054 index = str->len - len;
7055 begin = nk_str_at_rune(str, index, &unicode, &len);
7056 end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;
7057 nk_str_remove_chars(str, (int)(end-begin)+1);
7058 }
7059
7060 NK_API void
7061 nk_str_delete_chars(struct nk_str *s, int pos, int len)
7062 {
7063 NK_ASSERT(s);
7064 if (!s || !len || (nk_size)pos > s->buffer.allocated ||
7065 (nk_size)(pos + len) > s->buffer.allocated) return;
7066
7067 if ((nk_size)(pos + len) < s->buffer.allocated) {
7068 /* memmove */
7069 char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);
7070 char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);
7071 NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));
7072 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
7073 s->buffer.allocated -= (nk_size)len;
7074 } else nk_str_remove_chars(s, len);
7075 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
7076 }
7077
7078 NK_API void
7079 nk_str_delete_runes(struct nk_str *s, int pos, int len)
7080 {
7081 char *temp;
7082 nk_rune unicode;
7083 char *begin;
7084 char *end;
7085 int unused;
7086
7087 NK_ASSERT(s);
7088 NK_ASSERT(s->len >= pos + len);
7089 if (s->len < pos + len)
7090 len = NK_CLAMP(0, (s->len - pos), s->len);
7091 if (!len) return;
7092
7093 temp = (char *)s->buffer.memory.ptr;
7094 begin = nk_str_at_rune(s, pos, &unicode, &unused);
7095 if (!begin) return;
7096 s->buffer.memory.ptr = begin;
7097 end = nk_str_at_rune(s, len, &unicode, &unused);
7098 s->buffer.memory.ptr = temp;
7099 if (!end) return;
7100 nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));
7101 }
7102
7103 NK_API char*
7104 nk_str_at_char(struct nk_str *s, int pos)
7105 {
7106 NK_ASSERT(s);
7107 if (!s || pos > (int)s->buffer.allocated) return 0;
7108 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
7109 }
7110
7111 NK_API char*
7112 nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)
7113 {
7114 int i = 0;
7115 int src_len = 0;
7116 int glyph_len = 0;
7117 char *text;
7118 int text_len;
7119
7120 NK_ASSERT(str);
7121 NK_ASSERT(unicode);
7122 NK_ASSERT(len);
7123
7124 if (!str || !unicode || !len) return 0;
7125 if (pos < 0) {
7126 *unicode = 0;
7127 *len = 0;
7128 return 0;
7129 }
7130
7131 text = (char*)str->buffer.memory.ptr;
7132 text_len = (int)str->buffer.allocated;
7133 glyph_len = nk_utf_decode(text, unicode, text_len);
7134 while (glyph_len) {
7135 if (i == pos) {
7136 *len = glyph_len;
7137 break;
7138 }
7139
7140 i++;
7141 src_len = src_len + glyph_len;
7142 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
7143 }
7144 if (i != pos) return 0;
7145 return text + src_len;
7146 }
7147
7148 NK_API const char*
7149 nk_str_at_char_const(const struct nk_str *s, int pos)
7150 {
7151 NK_ASSERT(s);
7152 if (!s || pos > (int)s->buffer.allocated) return 0;
7153 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
7154 }
7155
7156 NK_API const char*
7157 nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)
7158 {
7159 int i = 0;
7160 int src_len = 0;
7161 int glyph_len = 0;
7162 char *text;
7163 int text_len;
7164
7165 NK_ASSERT(str);
7166 NK_ASSERT(unicode);
7167 NK_ASSERT(len);
7168
7169 if (!str || !unicode || !len) return 0;
7170 if (pos < 0) {
7171 *unicode = 0;
7172 *len = 0;
7173 return 0;
7174 }
7175
7176 text = (char*)str->buffer.memory.ptr;
7177 text_len = (int)str->buffer.allocated;
7178 glyph_len = nk_utf_decode(text, unicode, text_len);
7179 while (glyph_len) {
7180 if (i == pos) {
7181 *len = glyph_len;
7182 break;
7183 }
7184
7185 i++;
7186 src_len = src_len + glyph_len;
7187 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
7188 }
7189 if (i != pos) return 0;
7190 return text + src_len;
7191 }
7192
7193 NK_API nk_rune
7194 nk_str_rune_at(const struct nk_str *str, int pos)
7195 {
7196 int len;
7197 nk_rune unicode = 0;
7198 nk_str_at_const(str, pos, &unicode, &len);
7199 return unicode;
7200 }
7201
7202 NK_API char*
7203 nk_str_get(struct nk_str *s)
7204 {
7205 NK_ASSERT(s);
7206 if (!s || !s->len || !s->buffer.allocated) return 0;
7207 return (char*)s->buffer.memory.ptr;
7208 }
7209
7210 NK_API const char*
7211 nk_str_get_const(const struct nk_str *s)
7212 {
7213 NK_ASSERT(s);
7214 if (!s || !s->len || !s->buffer.allocated) return 0;
7215 return (const char*)s->buffer.memory.ptr;
7216 }
7217
7218 NK_API int
7219 nk_str_len(struct nk_str *s)
7220 {
7221 NK_ASSERT(s);
7222 if (!s || !s->len || !s->buffer.allocated) return 0;
7223 return s->len;
7224 }
7225
7226 NK_API int
7227 nk_str_len_char(struct nk_str *s)
7228 {
7229 NK_ASSERT(s);
7230 if (!s || !s->len || !s->buffer.allocated) return 0;
7231 return (int)s->buffer.allocated;
7232 }
7233
7234 NK_API void
7235 nk_str_clear(struct nk_str *str)
7236 {
7237 NK_ASSERT(str);
7238 nk_buffer_clear(&str->buffer);
7239 str->len = 0;
7240 }
7241
7242 NK_API void
7243 nk_str_free(struct nk_str *str)
7244 {
7245 NK_ASSERT(str);
7246 nk_buffer_free(&str->buffer);
7247 str->len = 0;
7248 }
7249
7250 /*
7251 * ==============================================================
7252 *
7253 * Command buffer
7254 *
7255 * ===============================================================
7256 */
7257 NK_INTERN void
7258 nk_command_buffer_init(struct nk_command_buffer *cmdbuf,
7259 struct nk_buffer *buffer, enum nk_command_clipping clip)
7260 {
7261 NK_ASSERT(cmdbuf);
7262 NK_ASSERT(buffer);
7263 if (!cmdbuf || !buffer) return;
7264 cmdbuf->base = buffer;
7265 cmdbuf->use_clipping = clip;
7266 cmdbuf->begin = buffer->allocated;
7267 cmdbuf->end = buffer->allocated;
7268 cmdbuf->last = buffer->allocated;
7269 }
7270
7271 NK_INTERN void
7272 nk_command_buffer_reset(struct nk_command_buffer *buffer)
7273 {
7274 NK_ASSERT(buffer);
7275 if (!buffer) return;
7276 buffer->begin = 0;
7277 buffer->end = 0;
7278 buffer->last = 0;
7279 buffer->clip = nk_null_rect;
7280 #ifdef NK_INCLUDE_COMMAND_USERDATA
7281 buffer->userdata.ptr = 0;
7282 #endif
7283 }
7284
7285 NK_INTERN void*
7286 nk_command_buffer_push(struct nk_command_buffer* b,
7287 enum nk_command_type t, nk_size size)
7288 {
7289 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);
7290 struct nk_command *cmd;
7291 nk_size alignment;
7292 void *unaligned;
7293 void *memory;
7294
7295 NK_ASSERT(b);
7296 NK_ASSERT(b->base);
7297 if (!b) return 0;
7298 cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);
7299 if (!cmd) return 0;
7300
7301 /* make sure the offset to the next command is aligned */
7302 b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);
7303 unaligned = (nk_byte*)cmd + size;
7304 memory = NK_ALIGN_PTR(unaligned, align);
7305 alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
7306 #ifdef NK_ZERO_COMMAND_MEMORY
7307 NK_MEMSET(cmd, 0, size + alignment);
7308 #endif
7309
7310 cmd->type = t;
7311 cmd->next = b->base->allocated + alignment;
7312 #ifdef NK_INCLUDE_COMMAND_USERDATA
7313 cmd->userdata = b->userdata;
7314 #endif
7315 b->end = cmd->next;
7316 return cmd;
7317 }
7318
7319 NK_API void
7320 nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)
7321 {
7322 struct nk_command_scissor *cmd;
7323 NK_ASSERT(b);
7324 if (!b) return;
7325
7326 b->clip.x = r.x;
7327 b->clip.y = r.y;
7328 b->clip.w = r.w;
7329 b->clip.h = r.h;
7330 cmd = (struct nk_command_scissor*)
7331 nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));
7332
7333 if (!cmd) return;
7334 cmd->x = (short)r.x;
7335 cmd->y = (short)r.y;
7336 cmd->w = (unsigned short)NK_MAX(0, r.w);
7337 cmd->h = (unsigned short)NK_MAX(0, r.h);
7338 }
7339
7340 NK_API void
7341 nk_stroke_line(struct nk_command_buffer *b, float x0, float y0,
7342 float x1, float y1, float line_thickness, struct nk_color c)
7343 {
7344 struct nk_command_line *cmd;
7345 NK_ASSERT(b);
7346 if (!b || line_thickness <= 0) return;
7347 cmd = (struct nk_command_line*)
7348 nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));
7349 if (!cmd) return;
7350 cmd->line_thickness = (unsigned short)line_thickness;
7351 cmd->begin.x = (short)x0;
7352 cmd->begin.y = (short)y0;
7353 cmd->end.x = (short)x1;
7354 cmd->end.y = (short)y1;
7355 cmd->color = c;
7356 }
7357
7358 NK_API void
7359 nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,
7360 float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,
7361 float bx, float by, float line_thickness, struct nk_color col)
7362 {
7363 struct nk_command_curve *cmd;
7364 NK_ASSERT(b);
7365 if (!b || col.a == 0 || line_thickness <= 0) return;
7366
7367 cmd = (struct nk_command_curve*)
7368 nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));
7369 if (!cmd) return;
7370 cmd->line_thickness = (unsigned short)line_thickness;
7371 cmd->begin.x = (short)ax;
7372 cmd->begin.y = (short)ay;
7373 cmd->ctrl[0].x = (short)ctrl0x;
7374 cmd->ctrl[0].y = (short)ctrl0y;
7375 cmd->ctrl[1].x = (short)ctrl1x;
7376 cmd->ctrl[1].y = (short)ctrl1y;
7377 cmd->end.x = (short)bx;
7378 cmd->end.y = (short)by;
7379 cmd->color = col;
7380 }
7381
7382 NK_API void
7383 nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,
7384 float rounding, float line_thickness, struct nk_color c)
7385 {
7386 struct nk_command_rect *cmd;
7387 NK_ASSERT(b);
7388 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;
7389 if (b->use_clipping) {
7390 const struct nk_rect *clip = &b->clip;
7391 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
7392 clip->x, clip->y, clip->w, clip->h)) return;
7393 }
7394 cmd = (struct nk_command_rect*)
7395 nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));
7396 if (!cmd) return;
7397 cmd->rounding = (unsigned short)rounding;
7398 cmd->line_thickness = (unsigned short)line_thickness;
7399 cmd->x = (short)rect.x;
7400 cmd->y = (short)rect.y;
7401 cmd->w = (unsigned short)NK_MAX(0, rect.w);
7402 cmd->h = (unsigned short)NK_MAX(0, rect.h);
7403 cmd->color = c;
7404 }
7405
7406 NK_API void
7407 nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,
7408 float rounding, struct nk_color c)
7409 {
7410 struct nk_command_rect_filled *cmd;
7411 NK_ASSERT(b);
7412 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
7413 if (b->use_clipping) {
7414 const struct nk_rect *clip = &b->clip;
7415 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
7416 clip->x, clip->y, clip->w, clip->h)) return;
7417 }
7418
7419 cmd = (struct nk_command_rect_filled*)
7420 nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));
7421 if (!cmd) return;
7422 cmd->rounding = (unsigned short)rounding;
7423 cmd->x = (short)rect.x;
7424 cmd->y = (short)rect.y;
7425 cmd->w = (unsigned short)NK_MAX(0, rect.w);
7426 cmd->h = (unsigned short)NK_MAX(0, rect.h);
7427 cmd->color = c;
7428 }
7429
7430 NK_API void
7431 nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,
7432 struct nk_color left, struct nk_color top, struct nk_color right,
7433 struct nk_color bottom)
7434 {
7435 struct nk_command_rect_multi_color *cmd;
7436 NK_ASSERT(b);
7437 if (!b || rect.w == 0 || rect.h == 0) return;
7438 if (b->use_clipping) {
7439 const struct nk_rect *clip = &b->clip;
7440 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
7441 clip->x, clip->y, clip->w, clip->h)) return;
7442 }
7443
7444 cmd = (struct nk_command_rect_multi_color*)
7445 nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));
7446 if (!cmd) return;
7447 cmd->x = (short)rect.x;
7448 cmd->y = (short)rect.y;
7449 cmd->w = (unsigned short)NK_MAX(0, rect.w);
7450 cmd->h = (unsigned short)NK_MAX(0, rect.h);
7451 cmd->left = left;
7452 cmd->top = top;
7453 cmd->right = right;
7454 cmd->bottom = bottom;
7455 }
7456
7457 NK_API void
7458 nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,
7459 float line_thickness, struct nk_color c)
7460 {
7461 struct nk_command_circle *cmd;
7462 if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;
7463 if (b->use_clipping) {
7464 const struct nk_rect *clip = &b->clip;
7465 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
7466 return;
7467 }
7468
7469 cmd = (struct nk_command_circle*)
7470 nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));
7471 if (!cmd) return;
7472 cmd->line_thickness = (unsigned short)line_thickness;
7473 cmd->x = (short)r.x;
7474 cmd->y = (short)r.y;
7475 cmd->w = (unsigned short)NK_MAX(r.w, 0);
7476 cmd->h = (unsigned short)NK_MAX(r.h, 0);
7477 cmd->color = c;
7478 }
7479
7480 NK_API void
7481 nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)
7482 {
7483 struct nk_command_circle_filled *cmd;
7484 NK_ASSERT(b);
7485 if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;
7486 if (b->use_clipping) {
7487 const struct nk_rect *clip = &b->clip;
7488 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
7489 return;
7490 }
7491
7492 cmd = (struct nk_command_circle_filled*)
7493 nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));
7494 if (!cmd) return;
7495 cmd->x = (short)r.x;
7496 cmd->y = (short)r.y;
7497 cmd->w = (unsigned short)NK_MAX(r.w, 0);
7498 cmd->h = (unsigned short)NK_MAX(r.h, 0);
7499 cmd->color = c;
7500 }
7501
7502 NK_API void
7503 nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
7504 float a_min, float a_max, float line_thickness, struct nk_color c)
7505 {
7506 struct nk_command_arc *cmd;
7507 if (!b || c.a == 0 || line_thickness <= 0) return;
7508 cmd = (struct nk_command_arc*)
7509 nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));
7510 if (!cmd) return;
7511 cmd->line_thickness = (unsigned short)line_thickness;
7512 cmd->cx = (short)cx;
7513 cmd->cy = (short)cy;
7514 cmd->r = (unsigned short)radius;
7515 cmd->a[0] = a_min;
7516 cmd->a[1] = a_max;
7517 cmd->color = c;
7518 }
7519
7520 NK_API void
7521 nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
7522 float a_min, float a_max, struct nk_color c)
7523 {
7524 struct nk_command_arc_filled *cmd;
7525 NK_ASSERT(b);
7526 if (!b || c.a == 0) return;
7527 cmd = (struct nk_command_arc_filled*)
7528 nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));
7529 if (!cmd) return;
7530 cmd->cx = (short)cx;
7531 cmd->cy = (short)cy;
7532 cmd->r = (unsigned short)radius;
7533 cmd->a[0] = a_min;
7534 cmd->a[1] = a_max;
7535 cmd->color = c;
7536 }
7537
7538 NK_API void
7539 nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
7540 float y1, float x2, float y2, float line_thickness, struct nk_color c)
7541 {
7542 struct nk_command_triangle *cmd;
7543 NK_ASSERT(b);
7544 if (!b || c.a == 0 || line_thickness <= 0) return;
7545 if (b->use_clipping) {
7546 const struct nk_rect *clip = &b->clip;
7547 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
7548 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
7549 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
7550 return;
7551 }
7552
7553 cmd = (struct nk_command_triangle*)
7554 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));
7555 if (!cmd) return;
7556 cmd->line_thickness = (unsigned short)line_thickness;
7557 cmd->a.x = (short)x0;
7558 cmd->a.y = (short)y0;
7559 cmd->b.x = (short)x1;
7560 cmd->b.y = (short)y1;
7561 cmd->c.x = (short)x2;
7562 cmd->c.y = (short)y2;
7563 cmd->color = c;
7564 }
7565
7566 NK_API void
7567 nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
7568 float y1, float x2, float y2, struct nk_color c)
7569 {
7570 struct nk_command_triangle_filled *cmd;
7571 NK_ASSERT(b);
7572 if (!b || c.a == 0) return;
7573 if (!b) return;
7574 if (b->use_clipping) {
7575 const struct nk_rect *clip = &b->clip;
7576 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
7577 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
7578 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
7579 return;
7580 }
7581
7582 cmd = (struct nk_command_triangle_filled*)
7583 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));
7584 if (!cmd) return;
7585 cmd->a.x = (short)x0;
7586 cmd->a.y = (short)y0;
7587 cmd->b.x = (short)x1;
7588 cmd->b.y = (short)y1;
7589 cmd->c.x = (short)x2;
7590 cmd->c.y = (short)y2;
7591 cmd->color = c;
7592 }
7593
7594 NK_API void
7595 nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count,
7596 float line_thickness, struct nk_color col)
7597 {
7598 int i;
7599 nk_size size = 0;
7600 struct nk_command_polygon *cmd;
7601
7602 NK_ASSERT(b);
7603 if (!b || col.a == 0 || line_thickness <= 0) return;
7604 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7605 cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);
7606 if (!cmd) return;
7607 cmd->color = col;
7608 cmd->line_thickness = (unsigned short)line_thickness;
7609 cmd->point_count = (unsigned short)point_count;
7610 for (i = 0; i < point_count; ++i) {
7611 cmd->points[i].x = (short)points[i*2];
7612 cmd->points[i].y = (short)points[i*2+1];
7613 }
7614 }
7615
7616 NK_API void
7617 nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
7618 struct nk_color col)
7619 {
7620 int i;
7621 nk_size size = 0;
7622 struct nk_command_polygon_filled *cmd;
7623
7624 NK_ASSERT(b);
7625 if (!b || col.a == 0) return;
7626 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7627 cmd = (struct nk_command_polygon_filled*)
7628 nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);
7629 if (!cmd) return;
7630 cmd->color = col;
7631 cmd->point_count = (unsigned short)point_count;
7632 for (i = 0; i < point_count; ++i) {
7633 cmd->points[i].x = (short)points[i*2+0];
7634 cmd->points[i].y = (short)points[i*2+1];
7635 }
7636 }
7637
7638 NK_API void
7639 nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count,
7640 float line_thickness, struct nk_color col)
7641 {
7642 int i;
7643 nk_size size = 0;
7644 struct nk_command_polyline *cmd;
7645
7646 NK_ASSERT(b);
7647 if (!b || col.a == 0 || line_thickness <= 0) return;
7648 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
7649 cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);
7650 if (!cmd) return;
7651 cmd->color = col;
7652 cmd->point_count = (unsigned short)point_count;
7653 cmd->line_thickness = (unsigned short)line_thickness;
7654 for (i = 0; i < point_count; ++i) {
7655 cmd->points[i].x = (short)points[i*2];
7656 cmd->points[i].y = (short)points[i*2+1];
7657 }
7658 }
7659
7660 NK_API void
7661 nk_draw_image(struct nk_command_buffer *b, struct nk_rect r,
7662 const struct nk_image *img, struct nk_color col)
7663 {
7664 struct nk_command_image *cmd;
7665 NK_ASSERT(b);
7666 if (!b) return;
7667 if (b->use_clipping) {
7668 const struct nk_rect *c = &b->clip;
7669 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7670 return;
7671 }
7672
7673 cmd = (struct nk_command_image*)
7674 nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));
7675 if (!cmd) return;
7676 cmd->x = (short)r.x;
7677 cmd->y = (short)r.y;
7678 cmd->w = (unsigned short)NK_MAX(0, r.w);
7679 cmd->h = (unsigned short)NK_MAX(0, r.h);
7680 cmd->img = *img;
7681 cmd->col = col;
7682 }
7683
7684 NK_API void
7685 nk_push_custom(struct nk_command_buffer *b, struct nk_rect r,
7686 nk_command_custom_callback cb, nk_handle usr)
7687 {
7688 struct nk_command_custom *cmd;
7689 NK_ASSERT(b);
7690 if (!b) return;
7691 if (b->use_clipping) {
7692 const struct nk_rect *c = &b->clip;
7693 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7694 return;
7695 }
7696
7697 cmd = (struct nk_command_custom*)
7698 nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));
7699 if (!cmd) return;
7700 cmd->x = (short)r.x;
7701 cmd->y = (short)r.y;
7702 cmd->w = (unsigned short)NK_MAX(0, r.w);
7703 cmd->h = (unsigned short)NK_MAX(0, r.h);
7704 cmd->callback_data = usr;
7705 cmd->callback = cb;
7706 }
7707
7708 NK_API void
7709 nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
7710 const char *string, int length, const struct nk_user_font *font,
7711 struct nk_color bg, struct nk_color fg)
7712 {
7713 float text_width = 0;
7714 struct nk_command_text *cmd;
7715
7716 NK_ASSERT(b);
7717 NK_ASSERT(font);
7718 if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;
7719 if (b->use_clipping) {
7720 const struct nk_rect *c = &b->clip;
7721 if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
7722 return;
7723 }
7724
7725 /* make sure text fits inside bounds */
7726 text_width = font->width(font->userdata, font->height, string, length);
7727 if (text_width > r.w){
7728 int glyphs = 0;
7729 float txt_width = (float)text_width;
7730 length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);
7731 }
7732
7733 if (!length) return;
7734 cmd = (struct nk_command_text*)
7735 nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));
7736 if (!cmd) return;
7737 cmd->x = (short)r.x;
7738 cmd->y = (short)r.y;
7739 cmd->w = (unsigned short)r.w;
7740 cmd->h = (unsigned short)r.h;
7741 cmd->background = bg;
7742 cmd->foreground = fg;
7743 cmd->font = font;
7744 cmd->length = length;
7745 cmd->height = font->height;
7746 NK_MEMCPY(cmd->string, string, (nk_size)length);
7747 cmd->string[length] = '\0';
7748 }
7749
7750 /* ==============================================================
7751 *
7752 * DRAW LIST
7753 *
7754 * ===============================================================*/
7755 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
7756 NK_API void
7757 nk_draw_list_init(struct nk_draw_list *list)
7758 {
7759 nk_size i = 0;
7760 NK_ASSERT(list);
7761 if (!list) return;
7762 nk_zero(list, sizeof(*list));
7763 for (i = 0; i < NK_LEN(list->circle_vtx); ++i) {
7764 const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI;
7765 list->circle_vtx[i].x = (float)NK_COS(a);
7766 list->circle_vtx[i].y = (float)NK_SIN(a);
7767 }
7768 }
7769
7770 NK_API void
7771 nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config,
7772 struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements,
7773 enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa)
7774 {
7775 NK_ASSERT(canvas);
7776 NK_ASSERT(config);
7777 NK_ASSERT(cmds);
7778 NK_ASSERT(vertices);
7779 NK_ASSERT(elements);
7780 if (!canvas || !config || !cmds || !vertices || !elements)
7781 return;
7782
7783 canvas->buffer = cmds;
7784 canvas->config = *config;
7785 canvas->elements = elements;
7786 canvas->vertices = vertices;
7787 canvas->line_AA = line_aa;
7788 canvas->shape_AA = shape_aa;
7789 canvas->clip_rect = nk_null_rect;
7790 }
7791
7792 NK_API const struct nk_draw_command*
7793 nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
7794 {
7795 nk_byte *memory;
7796 nk_size offset;
7797 const struct nk_draw_command *cmd;
7798
7799 NK_ASSERT(buffer);
7800 if (!buffer || !buffer->size || !canvas->cmd_count)
7801 return 0;
7802
7803 memory = (nk_byte*)buffer->memory.ptr;
7804 offset = buffer->memory.size - canvas->cmd_offset;
7805 cmd = nk_ptr_add(const struct nk_draw_command, memory, offset);
7806 return cmd;
7807 }
7808
7809 NK_API const struct nk_draw_command*
7810 nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
7811 {
7812 nk_size size;
7813 nk_size offset;
7814 nk_byte *memory;
7815 const struct nk_draw_command *end;
7816
7817 NK_ASSERT(buffer);
7818 NK_ASSERT(canvas);
7819 if (!buffer || !canvas)
7820 return 0;
7821
7822 memory = (nk_byte*)buffer->memory.ptr;
7823 size = buffer->memory.size;
7824 offset = size - canvas->cmd_offset;
7825 end = nk_ptr_add(const struct nk_draw_command, memory, offset);
7826 end -= (canvas->cmd_count-1);
7827 return end;
7828 }
7829
7830 NK_API const struct nk_draw_command*
7831 nk__draw_list_next(const struct nk_draw_command *cmd,
7832 const struct nk_buffer *buffer, const struct nk_draw_list *canvas)
7833 {
7834 const struct nk_draw_command *end;
7835 NK_ASSERT(buffer);
7836 NK_ASSERT(canvas);
7837 if (!cmd || !buffer || !canvas)
7838 return 0;
7839
7840 end = nk__draw_list_end(canvas, buffer);
7841 if (cmd <= end) return 0;
7842 return (cmd-1);
7843 }
7844
7845 NK_API void
7846 nk_draw_list_clear(struct nk_draw_list *list)
7847 {
7848 NK_ASSERT(list);
7849 if (!list) return;
7850 if (list->buffer)
7851 nk_buffer_clear(list->buffer);
7852 if (list->vertices)
7853 nk_buffer_clear(list->vertices);
7854 if (list->elements)
7855 nk_buffer_clear(list->elements);
7856
7857 list->element_count = 0;
7858 list->vertex_count = 0;
7859 list->cmd_offset = 0;
7860 list->cmd_count = 0;
7861 list->path_count = 0;
7862 list->vertices = 0;
7863 list->elements = 0;
7864 list->clip_rect = nk_null_rect;
7865 }
7866
7867 NK_INTERN struct nk_vec2*
7868 nk_draw_list_alloc_path(struct nk_draw_list *list, int count)
7869 {
7870 struct nk_vec2 *points;
7871 NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2);
7872 NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2);
7873 points = (struct nk_vec2*)
7874 nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT,
7875 point_size * (nk_size)count, point_align);
7876
7877 if (!points) return 0;
7878 if (!list->path_offset) {
7879 void *memory = nk_buffer_memory(list->buffer);
7880 list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory);
7881 }
7882 list->path_count += (unsigned int)count;
7883 return points;
7884 }
7885
7886 NK_INTERN struct nk_vec2
7887 nk_draw_list_path_last(struct nk_draw_list *list)
7888 {
7889 void *memory;
7890 struct nk_vec2 *point;
7891 NK_ASSERT(list->path_count);
7892 memory = nk_buffer_memory(list->buffer);
7893 point = nk_ptr_add(struct nk_vec2, memory, list->path_offset);
7894 point += (list->path_count-1);
7895 return *point;
7896 }
7897
7898 NK_INTERN struct nk_draw_command*
7899 nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip,
7900 nk_handle texture)
7901 {
7902 NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command);
7903 NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command);
7904 struct nk_draw_command *cmd;
7905
7906 NK_ASSERT(list);
7907 cmd = (struct nk_draw_command*)
7908 nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align);
7909
7910 if (!cmd) return 0;
7911 if (!list->cmd_count) {
7912 nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer);
7913 nk_size total = nk_buffer_total(list->buffer);
7914 memory = nk_ptr_add(nk_byte, memory, total);
7915 list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd);
7916 }
7917
7918 cmd->elem_count = 0;
7919 cmd->clip_rect = clip;
7920 cmd->texture = texture;
7921 #ifdef NK_INCLUDE_COMMAND_USERDATA
7922 cmd->userdata = list->userdata;
7923 #endif
7924
7925 list->cmd_count++;
7926 list->clip_rect = clip;
7927 return cmd;
7928 }
7929
7930 NK_INTERN struct nk_draw_command*
7931 nk_draw_list_command_last(struct nk_draw_list *list)
7932 {
7933 void *memory;
7934 nk_size size;
7935 struct nk_draw_command *cmd;
7936 NK_ASSERT(list->cmd_count);
7937
7938 memory = nk_buffer_memory(list->buffer);
7939 size = nk_buffer_total(list->buffer);
7940 cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset);
7941 return (cmd - (list->cmd_count-1));
7942 }
7943
7944 NK_INTERN void
7945 nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)
7946 {
7947 NK_ASSERT(list);
7948 if (!list) return;
7949 if (!list->cmd_count) {
7950 nk_draw_list_push_command(list, rect, list->config.null.texture);
7951 } else {
7952 struct nk_draw_command *prev = nk_draw_list_command_last(list);
7953 if (prev->elem_count == 0)
7954 prev->clip_rect = rect;
7955 nk_draw_list_push_command(list, rect, prev->texture);
7956 }
7957 }
7958
7959 NK_INTERN void
7960 nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture)
7961 {
7962 NK_ASSERT(list);
7963 if (!list) return;
7964 if (!list->cmd_count) {
7965 nk_draw_list_push_command(list, nk_null_rect, texture);
7966 } else {
7967 struct nk_draw_command *prev = nk_draw_list_command_last(list);
7968 if (prev->elem_count == 0)
7969 prev->texture = texture;
7970 else if (prev->texture.id != texture.id)
7971 nk_draw_list_push_command(list, prev->clip_rect, texture);
7972 }
7973 }
7974
7975 #ifdef NK_INCLUDE_COMMAND_USERDATA
7976 NK_API void
7977 nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata)
7978 {
7979 list->userdata = userdata;
7980 }
7981 #endif
7982
7983 NK_INTERN void*
7984 nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count)
7985 {
7986 void *vtx;
7987 NK_ASSERT(list);
7988 if (!list) return 0;
7989 vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT,
7990 list->config.vertex_size*count, list->config.vertex_alignment);
7991 if (!vtx) return 0;
7992 list->vertex_count += (unsigned int)count;
7993 return vtx;
7994 }
7995
7996 NK_INTERN nk_draw_index*
7997 nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count)
7998 {
7999 nk_draw_index *ids;
8000 struct nk_draw_command *cmd;
8001 NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index);
8002 NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index);
8003 NK_ASSERT(list);
8004 if (!list) return 0;
8005
8006 ids = (nk_draw_index*)
8007 nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align);
8008 if (!ids) return 0;
8009 cmd = nk_draw_list_command_last(list);
8010 list->element_count += (unsigned int)count;
8011 cmd->elem_count += (unsigned int)count;
8012 return ids;
8013 }
8014
8015 NK_INTERN int
8016 nk_draw_vertex_layout_element_is_end_of_layout(
8017 const struct nk_draw_vertex_layout_element *element)
8018 {
8019 return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT ||
8020 element->format == NK_FORMAT_COUNT);
8021 }
8022
8023 NK_INTERN void
8024 nk_draw_vertex_color(void *attribute, const float *values,
8025 enum nk_draw_vertex_layout_format format)
8026 {
8027 /* if this triggers you tried to provide a value format for a color */
8028 NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN);
8029 NK_ASSERT(format <= NK_FORMAT_COLOR_END);
8030 if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return;
8031
8032 switch (format) {
8033 default: NK_ASSERT(0 && "Invalid vertex layout color format"); break;
8034 case NK_FORMAT_R8G8B8A8:
8035 case NK_FORMAT_R8G8B8: {
8036 struct nk_color col = nk_rgba_fv(values);
8037 NK_MEMCPY(attribute, &col.r, sizeof(col));
8038 } break;
8039 case NK_FORMAT_B8G8R8A8: {
8040 struct nk_color col = nk_rgba_fv(values);
8041 struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a);
8042 NK_MEMCPY(attribute, &bgra, sizeof(bgra));
8043 } break;
8044 case NK_FORMAT_R16G15B16: {
8045 nk_ushort col[3];
8046 col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);
8047 col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX);
8048 col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX);
8049 NK_MEMCPY(attribute, col, sizeof(col));
8050 } break;
8051 case NK_FORMAT_R16G15B16A16: {
8052 nk_ushort col[4];
8053 col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);
8054 col[1] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[1] * NK_USHORT_MAX, NK_USHORT_MAX);
8055 col[2] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[2] * NK_USHORT_MAX, NK_USHORT_MAX);
8056 col[3] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[3] * NK_USHORT_MAX, NK_USHORT_MAX);
8057 NK_MEMCPY(attribute, col, sizeof(col));
8058 } break;
8059 case NK_FORMAT_R32G32B32: {
8060 nk_uint col[3];
8061 col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX);
8062 col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX);
8063 col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX);
8064 NK_MEMCPY(attribute, col, sizeof(col));
8065 } break;
8066 case NK_FORMAT_R32G32B32A32: {
8067 nk_uint col[4];
8068 col[0] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[0] * NK_UINT_MAX, NK_UINT_MAX);
8069 col[1] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[1] * NK_UINT_MAX, NK_UINT_MAX);
8070 col[2] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[2] * NK_UINT_MAX, NK_UINT_MAX);
8071 col[3] = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[3] * NK_UINT_MAX, NK_UINT_MAX);
8072 NK_MEMCPY(attribute, col, sizeof(col));
8073 } break;
8074 case NK_FORMAT_R32G32B32A32_FLOAT:
8075 NK_MEMCPY(attribute, values, sizeof(float)*4);
8076 break;
8077 case NK_FORMAT_R32G32B32A32_DOUBLE: {
8078 double col[4];
8079 col[0] = (double)NK_SATURATE(values[0]);
8080 col[1] = (double)NK_SATURATE(values[1]);
8081 col[2] = (double)NK_SATURATE(values[2]);
8082 col[3] = (double)NK_SATURATE(values[3]);
8083 NK_MEMCPY(attribute, col, sizeof(col));
8084 } break;
8085 case NK_FORMAT_RGB32:
8086 case NK_FORMAT_RGBA32: {
8087 struct nk_color col = nk_rgba_fv(values);
8088 nk_uint color = nk_color_u32(col);
8089 NK_MEMCPY(attribute, &color, sizeof(color));
8090 } break;
8091 }
8092 }
8093
8094 NK_INTERN void
8095 nk_draw_vertex_element(void *dst, const float *values, int value_count,
8096 enum nk_draw_vertex_layout_format format)
8097 {
8098 int value_index;
8099 void *attribute = dst;
8100 /* if this triggers you tried to provide a color format for a value */
8101 NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN);
8102 if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return;
8103 for (value_index = 0; value_index < value_count; ++value_index) {
8104 switch (format) {
8105 default: NK_ASSERT(0 && "invalid vertex layout format"); break;
8106 case NK_FORMAT_SCHAR: {
8107 char value = (char)NK_CLAMP(NK_SCHAR_MIN, values[value_index], NK_SCHAR_MAX);
8108 NK_MEMCPY(attribute, &value, sizeof(value));
8109 attribute = (void*)((char*)attribute + sizeof(char));
8110 } break;
8111 case NK_FORMAT_SSHORT: {
8112 nk_short value = (nk_short)NK_CLAMP(NK_SSHORT_MIN, values[value_index], NK_SSHORT_MAX);
8113 NK_MEMCPY(attribute, &value, sizeof(value));
8114 attribute = (void*)((char*)attribute + sizeof(value));
8115 } break;
8116 case NK_FORMAT_SINT: {
8117 nk_int value = (nk_int)NK_CLAMP(NK_SINT_MIN, values[value_index], NK_SINT_MAX);
8118 NK_MEMCPY(attribute, &value, sizeof(value));
8119 attribute = (void*)((char*)attribute + sizeof(nk_int));
8120 } break;
8121 case NK_FORMAT_UCHAR: {
8122 unsigned char value = (unsigned char)NK_CLAMP(NK_UCHAR_MIN, values[value_index], NK_UCHAR_MAX);
8123 NK_MEMCPY(attribute, &value, sizeof(value));
8124 attribute = (void*)((char*)attribute + sizeof(unsigned char));
8125 } break;
8126 case NK_FORMAT_USHORT: {
8127 nk_ushort value = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[value_index], NK_USHORT_MAX);
8128 NK_MEMCPY(attribute, &value, sizeof(value));
8129 attribute = (void*)((char*)attribute + sizeof(value));
8130 } break;
8131 case NK_FORMAT_UINT: {
8132 nk_uint value = (nk_uint)NK_CLAMP(NK_UINT_MIN, values[value_index], NK_UINT_MAX);
8133 NK_MEMCPY(attribute, &value, sizeof(value));
8134 attribute = (void*)((char*)attribute + sizeof(nk_uint));
8135 } break;
8136 case NK_FORMAT_FLOAT:
8137 NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index]));
8138 attribute = (void*)((char*)attribute + sizeof(float));
8139 break;
8140 case NK_FORMAT_DOUBLE: {
8141 double value = (double)values[value_index];
8142 NK_MEMCPY(attribute, &value, sizeof(value));
8143 attribute = (void*)((char*)attribute + sizeof(double));
8144 } break;
8145 }
8146 }
8147 }
8148
8149 NK_INTERN void*
8150 nk_draw_vertex(void *dst, const struct nk_convert_config *config,
8151 struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color)
8152 {
8153 void *result = (void*)((char*)dst + config->vertex_size);
8154 const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout;
8155 while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) {
8156 void *address = (void*)((char*)dst + elem_iter->offset);
8157 switch (elem_iter->attribute) {
8158 case NK_VERTEX_ATTRIBUTE_COUNT:
8159 default: NK_ASSERT(0 && "wrong element attribute");
8160 case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break;
8161 case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break;
8162 case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break;
8163 }
8164 elem_iter++;
8165 }
8166 return result;
8167 }
8168
8169 NK_API void
8170 nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points,
8171 const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed,
8172 float thickness, enum nk_anti_aliasing aliasing)
8173 {
8174 nk_size count;
8175 int thick_line;
8176 struct nk_colorf col;
8177 struct nk_colorf col_trans;
8178 NK_ASSERT(list);
8179 if (!list || points_count < 2) return;
8180
8181 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
8182 count = points_count;
8183 if (!closed) count = points_count-1;
8184 thick_line = thickness > 1.0f;
8185
8186 #ifdef NK_INCLUDE_COMMAND_USERDATA
8187 nk_draw_list_push_userdata(list, list->userdata);
8188 #endif
8189
8190 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
8191 nk_color_fv(&col.r, color);
8192 col_trans = col;
8193 col_trans.a = 0;
8194
8195 if (aliasing == NK_ANTI_ALIASING_ON) {
8196 /* ANTI-ALIASED STROKE */
8197 const float AA_SIZE = 1.0f;
8198 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
8199 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
8200
8201 /* allocate vertices and elements */
8202 nk_size i1 = 0;
8203 nk_size vertex_offset;
8204 nk_size index = list->vertex_count;
8205
8206 const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12);
8207 const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3);
8208
8209 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
8210 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
8211
8212 nk_size size;
8213 struct nk_vec2 *normals, *temp;
8214 if (!vtx || !ids) return;
8215
8216 /* temporary allocate normals + points */
8217 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
8218 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
8219 size = pnt_size * ((thick_line) ? 5 : 3) * points_count;
8220 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
8221 NK_ASSERT(normals);
8222 if (!normals) return;
8223 temp = normals + points_count;
8224
8225 /* make sure vertex pointer is still correct */
8226 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
8227
8228 /* calculate normals */
8229 for (i1 = 0; i1 < count; ++i1) {
8230 const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
8231 struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]);
8232 float len;
8233
8234 /* vec2 inverted length */
8235 len = nk_vec2_len_sqr(diff);
8236 if (len != 0.0f)
8237 len = nk_inv_sqrt(len);
8238 else len = 1.0f;
8239
8240 diff = nk_vec2_muls(diff, len);
8241 normals[i1].x = diff.y;
8242 normals[i1].y = -diff.x;
8243 }
8244
8245 if (!closed)
8246 normals[points_count-1] = normals[points_count-2];
8247
8248 if (!thick_line) {
8249 nk_size idx1, i;
8250 if (!closed) {
8251 struct nk_vec2 d;
8252 temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE));
8253 temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE));
8254 d = nk_vec2_muls(normals[points_count-1], AA_SIZE);
8255 temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d);
8256 temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d);
8257 }
8258
8259 /* fill elements */
8260 idx1 = index;
8261 for (i1 = 0; i1 < count; i1++) {
8262 struct nk_vec2 dm;
8263 float dmr2;
8264 nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
8265 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3);
8266
8267 /* average normals */
8268 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
8269 dmr2 = dm.x * dm.x + dm.y* dm.y;
8270 if (dmr2 > 0.000001f) {
8271 float scale = 1.0f/dmr2;
8272 scale = NK_MIN(100.0f, scale);
8273 dm = nk_vec2_muls(dm, scale);
8274 }
8275
8276 dm = nk_vec2_muls(dm, AA_SIZE);
8277 temp[i2*2+0] = nk_vec2_add(points[i2], dm);
8278 temp[i2*2+1] = nk_vec2_sub(points[i2], dm);
8279
8280 ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0);
8281 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
8282 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0);
8283 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
8284 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
8285 ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1);
8286 ids += 12;
8287 idx1 = idx2;
8288 }
8289
8290 /* fill vertices */
8291 for (i = 0; i < points_count; ++i) {
8292 const struct nk_vec2 uv = list->config.null.uv;
8293 vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);
8294 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);
8295 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);
8296 }
8297 } else {
8298 nk_size idx1, i;
8299 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
8300 if (!closed) {
8301 struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE);
8302 struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness);
8303
8304 temp[0] = nk_vec2_add(points[0], d1);
8305 temp[1] = nk_vec2_add(points[0], d2);
8306 temp[2] = nk_vec2_sub(points[0], d2);
8307 temp[3] = nk_vec2_sub(points[0], d1);
8308
8309 d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE);
8310 d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness);
8311
8312 temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1);
8313 temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2);
8314 temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2);
8315 temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1);
8316 }
8317
8318 /* add all elements */
8319 idx1 = index;
8320 for (i1 = 0; i1 < count; ++i1) {
8321 struct nk_vec2 dm_out, dm_in;
8322 const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1);
8323 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4);
8324
8325 /* average normals */
8326 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
8327 float dmr2 = dm.x * dm.x + dm.y* dm.y;
8328 if (dmr2 > 0.000001f) {
8329 float scale = 1.0f/dmr2;
8330 scale = NK_MIN(100.0f, scale);
8331 dm = nk_vec2_muls(dm, scale);
8332 }
8333
8334 dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE));
8335 dm_in = nk_vec2_muls(dm, half_inner_thickness);
8336 temp[i2*4+0] = nk_vec2_add(points[i2], dm_out);
8337 temp[i2*4+1] = nk_vec2_add(points[i2], dm_in);
8338 temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in);
8339 temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out);
8340
8341 /* add indexes */
8342 ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1);
8343 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
8344 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1);
8345 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
8346 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
8347 ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1);
8348 ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2);
8349 ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3);
8350 ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2);
8351 ids += 18;
8352 idx1 = idx2;
8353 }
8354
8355 /* add vertices */
8356 for (i = 0; i < points_count; ++i) {
8357 const struct nk_vec2 uv = list->config.null.uv;
8358 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);
8359 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);
8360 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);
8361 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans);
8362 }
8363 }
8364 /* free temporary normals + points */
8365 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
8366 } else {
8367 /* NON ANTI-ALIASED STROKE */
8368 nk_size i1 = 0;
8369 nk_size idx = list->vertex_count;
8370 const nk_size idx_count = count * 6;
8371 const nk_size vtx_count = count * 4;
8372 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
8373 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
8374 if (!vtx || !ids) return;
8375
8376 for (i1 = 0; i1 < count; ++i1) {
8377 float dx, dy;
8378 const struct nk_vec2 uv = list->config.null.uv;
8379 const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;
8380 const struct nk_vec2 p1 = points[i1];
8381 const struct nk_vec2 p2 = points[i2];
8382 struct nk_vec2 diff = nk_vec2_sub(p2, p1);
8383 float len;
8384
8385 /* vec2 inverted length */
8386 len = nk_vec2_len_sqr(diff);
8387 if (len != 0.0f)
8388 len = nk_inv_sqrt(len);
8389 else len = 1.0f;
8390 diff = nk_vec2_muls(diff, len);
8391
8392 /* add vertices */
8393 dx = diff.x * (thickness * 0.5f);
8394 dy = diff.y * (thickness * 0.5f);
8395
8396 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col);
8397 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col);
8398 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col);
8399 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col);
8400
8401 ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1);
8402 ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0);
8403 ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3);
8404
8405 ids += 6;
8406 idx += 4;
8407 }
8408 }
8409 }
8410
8411 NK_API void
8412 nk_draw_list_fill_poly_convex(struct nk_draw_list *list,
8413 const struct nk_vec2 *points, const unsigned int points_count,
8414 struct nk_color color, enum nk_anti_aliasing aliasing)
8415 {
8416 struct nk_colorf col;
8417 struct nk_colorf col_trans;
8418
8419 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
8420 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
8421 NK_ASSERT(list);
8422 if (!list || points_count < 3) return;
8423
8424 #ifdef NK_INCLUDE_COMMAND_USERDATA
8425 nk_draw_list_push_userdata(list, list->userdata);
8426 #endif
8427
8428 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
8429 nk_color_fv(&col.r, color);
8430 col_trans = col;
8431 col_trans.a = 0;
8432
8433 if (aliasing == NK_ANTI_ALIASING_ON) {
8434 nk_size i = 0;
8435 nk_size i0 = 0;
8436 nk_size i1 = 0;
8437
8438 const float AA_SIZE = 1.0f;
8439 nk_size vertex_offset = 0;
8440 nk_size index = list->vertex_count;
8441
8442 const nk_size idx_count = (points_count-2)*3 + points_count*6;
8443 const nk_size vtx_count = (points_count*2);
8444
8445 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
8446 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
8447
8448 nk_size size = 0;
8449 struct nk_vec2 *normals = 0;
8450 unsigned int vtx_inner_idx = (unsigned int)(index + 0);
8451 unsigned int vtx_outer_idx = (unsigned int)(index + 1);
8452 if (!vtx || !ids) return;
8453
8454 /* temporary allocate normals */
8455 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
8456 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
8457 size = pnt_size * points_count;
8458 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
8459 NK_ASSERT(normals);
8460 if (!normals) return;
8461 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
8462
8463 /* add elements */
8464 for (i = 2; i < points_count; i++) {
8465 ids[0] = (nk_draw_index)(vtx_inner_idx);
8466 ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1));
8467 ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1));
8468 ids += 3;
8469 }
8470
8471 /* compute normals */
8472 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
8473 struct nk_vec2 p0 = points[i0];
8474 struct nk_vec2 p1 = points[i1];
8475 struct nk_vec2 diff = nk_vec2_sub(p1, p0);
8476
8477 /* vec2 inverted length */
8478 float len = nk_vec2_len_sqr(diff);
8479 if (len != 0.0f)
8480 len = nk_inv_sqrt(len);
8481 else len = 1.0f;
8482 diff = nk_vec2_muls(diff, len);
8483
8484 normals[i0].x = diff.y;
8485 normals[i0].y = -diff.x;
8486 }
8487
8488 /* add vertices + indexes */
8489 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
8490 const struct nk_vec2 uv = list->config.null.uv;
8491 struct nk_vec2 n0 = normals[i0];
8492 struct nk_vec2 n1 = normals[i1];
8493 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);
8494 float dmr2 = dm.x*dm.x + dm.y*dm.y;
8495 if (dmr2 > 0.000001f) {
8496 float scale = 1.0f / dmr2;
8497 scale = NK_MIN(scale, 100.0f);
8498 dm = nk_vec2_muls(dm, scale);
8499 }
8500 dm = nk_vec2_muls(dm, AA_SIZE * 0.5f);
8501
8502 /* add vertices */
8503 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col);
8504 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans);
8505
8506 /* add indexes */
8507 ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
8508 ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1));
8509 ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
8510 ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
8511 ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1));
8512 ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
8513 ids += 6;
8514 }
8515 /* free temporary normals + points */
8516 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
8517 } else {
8518 nk_size i = 0;
8519 nk_size index = list->vertex_count;
8520 const nk_size idx_count = (points_count-2)*3;
8521 const nk_size vtx_count = points_count;
8522 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
8523 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
8524
8525 if (!vtx || !ids) return;
8526 for (i = 0; i < vtx_count; ++i)
8527 vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col);
8528 for (i = 2; i < points_count; ++i) {
8529 ids[0] = (nk_draw_index)index;
8530 ids[1] = (nk_draw_index)(index+ i - 1);
8531 ids[2] = (nk_draw_index)(index+i);
8532 ids += 3;
8533 }
8534 }
8535 }
8536
8537 NK_API void
8538 nk_draw_list_path_clear(struct nk_draw_list *list)
8539 {
8540 NK_ASSERT(list);
8541 if (!list) return;
8542 nk_buffer_reset(list->buffer, NK_BUFFER_FRONT);
8543 list->path_count = 0;
8544 list->path_offset = 0;
8545 }
8546
8547 NK_API void
8548 nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)
8549 {
8550 struct nk_vec2 *points = 0;
8551 struct nk_draw_command *cmd = 0;
8552 NK_ASSERT(list);
8553 if (!list) return;
8554 if (!list->cmd_count)
8555 nk_draw_list_add_clip(list, nk_null_rect);
8556
8557 cmd = nk_draw_list_command_last(list);
8558 if (cmd && cmd->texture.ptr != list->config.null.texture.ptr)
8559 nk_draw_list_push_image(list, list->config.null.texture);
8560
8561 points = nk_draw_list_alloc_path(list, 1);
8562 if (!points) return;
8563 points[0] = pos;
8564 }
8565
8566 NK_API void
8567 nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center,
8568 float radius, int a_min, int a_max)
8569 {
8570 int a = 0;
8571 NK_ASSERT(list);
8572 if (!list) return;
8573 if (a_min <= a_max) {
8574 for (a = a_min; a <= a_max; a++) {
8575 const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)];
8576 const float x = center.x + c.x * radius;
8577 const float y = center.y + c.y * radius;
8578 nk_draw_list_path_line_to(list, nk_vec2(x, y));
8579 }
8580 }
8581 }
8582
8583 NK_API void
8584 nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center,
8585 float radius, float a_min, float a_max, unsigned int segments)
8586 {
8587 unsigned int i = 0;
8588 NK_ASSERT(list);
8589 if (!list) return;
8590 if (radius == 0.0f) return;
8591
8592 /* This algorithm for arc drawing relies on these two trigonometric identities[1]:
8593 sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b)
8594 cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b)
8595
8596 Two coordinates (x, y) of a point on a circle centered on
8597 the origin can be written in polar form as:
8598 x = r * cos(a)
8599 y = r * sin(a)
8600 where r is the radius of the circle,
8601 a is the angle between (x, y) and the origin.
8602
8603 This allows us to rotate the coordinates around the
8604 origin by an angle b using the following transformation:
8605 x' = r * cos(a + b) = x * cos(b) - y * sin(b)
8606 y' = r * sin(a + b) = y * cos(b) + x * sin(b)
8607
8608 [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities
8609 */
8610 const float d_angle = (a_max - a_min) / (float)segments;
8611 const float sin_d = (float)NK_SIN(d_angle);
8612 const float cos_d = (float)NK_COS(d_angle);
8613
8614 float cx = (float)NK_COS(a_min) * radius;
8615 float cy = (float)NK_SIN(a_min) * radius;
8616 for(i = 0; i <= segments; ++i) {
8617 const float x = center.x + cx;
8618 const float y = center.y + cy;
8619 nk_draw_list_path_line_to(list, nk_vec2(x, y));
8620
8621 const float new_cx = cx * cos_d - cy * sin_d;
8622 const float new_cy = cy * cos_d + cx * sin_d;
8623 cx = new_cx;
8624 cy = new_cy;
8625 }
8626 }
8627
8628 NK_API void
8629 nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a,
8630 struct nk_vec2 b, float rounding)
8631 {
8632 float r;
8633 NK_ASSERT(list);
8634 if (!list) return;
8635 r = rounding;
8636 r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x));
8637 r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y));
8638
8639 if (r == 0.0f) {
8640 nk_draw_list_path_line_to(list, a);
8641 nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y));
8642 nk_draw_list_path_line_to(list, b);
8643 nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y));
8644 } else {
8645 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9);
8646 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12);
8647 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3);
8648 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6);
8649 }
8650 }
8651
8652 NK_API void
8653 nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2,
8654 struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments)
8655 {
8656 float t_step;
8657 unsigned int i_step;
8658 struct nk_vec2 p1;
8659
8660 NK_ASSERT(list);
8661 NK_ASSERT(list->path_count);
8662 if (!list || !list->path_count) return;
8663 num_segments = NK_MAX(num_segments, 1);
8664
8665 p1 = nk_draw_list_path_last(list);
8666 t_step = 1.0f/(float)num_segments;
8667 for (i_step = 1; i_step <= num_segments; ++i_step) {
8668 float t = t_step * (float)i_step;
8669 float u = 1.0f - t;
8670 float w1 = u*u*u;
8671 float w2 = 3*u*u*t;
8672 float w3 = 3*u*t*t;
8673 float w4 = t * t *t;
8674 float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
8675 float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
8676 nk_draw_list_path_line_to(list, nk_vec2(x,y));
8677 }
8678 }
8679
8680 NK_API void
8681 nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color)
8682 {
8683 struct nk_vec2 *points;
8684 NK_ASSERT(list);
8685 if (!list) return;
8686 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
8687 nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA);
8688 nk_draw_list_path_clear(list);
8689 }
8690
8691 NK_API void
8692 nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color,
8693 enum nk_draw_list_stroke closed, float thickness)
8694 {
8695 struct nk_vec2 *points;
8696 NK_ASSERT(list);
8697 if (!list) return;
8698 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
8699 nk_draw_list_stroke_poly_line(list, points, list->path_count, color,
8700 closed, thickness, list->config.line_AA);
8701 nk_draw_list_path_clear(list);
8702 }
8703
8704 NK_API void
8705 nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a,
8706 struct nk_vec2 b, struct nk_color col, float thickness)
8707 {
8708 NK_ASSERT(list);
8709 if (!list || !col.a) return;
8710 if (list->line_AA == NK_ANTI_ALIASING_ON) {
8711 nk_draw_list_path_line_to(list, a);
8712 nk_draw_list_path_line_to(list, b);
8713 } else {
8714 nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f)));
8715 nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f)));
8716 }
8717 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
8718 }
8719
8720 NK_API void
8721 nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect,
8722 struct nk_color col, float rounding)
8723 {
8724 NK_ASSERT(list);
8725 if (!list || !col.a) return;
8726
8727 if (list->line_AA == NK_ANTI_ALIASING_ON) {
8728 nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),
8729 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
8730 } else {
8731 nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),
8732 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
8733 } nk_draw_list_path_fill(list, col);
8734 }
8735
8736 NK_API void
8737 nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect,
8738 struct nk_color col, float rounding, float thickness)
8739 {
8740 NK_ASSERT(list);
8741 if (!list || !col.a) return;
8742 if (list->line_AA == NK_ANTI_ALIASING_ON) {
8743 nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),
8744 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
8745 } else {
8746 nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),
8747 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
8748 } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8749 }
8750
8751 NK_API void
8752 nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect,
8753 struct nk_color left, struct nk_color top, struct nk_color right,
8754 struct nk_color bottom)
8755 {
8756 void *vtx;
8757 struct nk_colorf col_left, col_top;
8758 struct nk_colorf col_right, col_bottom;
8759 nk_draw_index *idx;
8760 nk_draw_index index;
8761
8762 nk_color_fv(&col_left.r, left);
8763 nk_color_fv(&col_right.r, right);
8764 nk_color_fv(&col_top.r, top);
8765 nk_color_fv(&col_bottom.r, bottom);
8766
8767 NK_ASSERT(list);
8768 if (!list) return;
8769
8770 nk_draw_list_push_image(list, list->config.null.texture);
8771 index = (nk_draw_index)list->vertex_count;
8772 vtx = nk_draw_list_alloc_vertices(list, 4);
8773 idx = nk_draw_list_alloc_elements(list, 6);
8774 if (!vtx || !idx) return;
8775
8776 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
8777 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
8778 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
8779
8780 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left);
8781 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top);
8782 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right);
8783 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom);
8784 }
8785
8786 NK_API void
8787 nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,
8788 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col)
8789 {
8790 NK_ASSERT(list);
8791 if (!list || !col.a) return;
8792 nk_draw_list_path_line_to(list, a);
8793 nk_draw_list_path_line_to(list, b);
8794 nk_draw_list_path_line_to(list, c);
8795 nk_draw_list_path_fill(list, col);
8796 }
8797
8798 NK_API void
8799 nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a,
8800 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness)
8801 {
8802 NK_ASSERT(list);
8803 if (!list || !col.a) return;
8804 nk_draw_list_path_line_to(list, a);
8805 nk_draw_list_path_line_to(list, b);
8806 nk_draw_list_path_line_to(list, c);
8807 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8808 }
8809
8810 NK_API void
8811 nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center,
8812 float radius, struct nk_color col, unsigned int segs)
8813 {
8814 float a_max;
8815 NK_ASSERT(list);
8816 if (!list || !col.a) return;
8817 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
8818 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
8819 nk_draw_list_path_fill(list, col);
8820 }
8821
8822 NK_API void
8823 nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center,
8824 float radius, struct nk_color col, unsigned int segs, float thickness)
8825 {
8826 float a_max;
8827 NK_ASSERT(list);
8828 if (!list || !col.a) return;
8829 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
8830 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
8831 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
8832 }
8833
8834 NK_API void
8835 nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0,
8836 struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1,
8837 struct nk_color col, unsigned int segments, float thickness)
8838 {
8839 NK_ASSERT(list);
8840 if (!list || !col.a) return;
8841 nk_draw_list_path_line_to(list, p0);
8842 nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments);
8843 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
8844 }
8845
8846 NK_INTERN void
8847 nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a,
8848 struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc,
8849 struct nk_color color)
8850 {
8851 void *vtx;
8852 struct nk_vec2 uvb;
8853 struct nk_vec2 uvd;
8854 struct nk_vec2 b;
8855 struct nk_vec2 d;
8856
8857 struct nk_colorf col;
8858 nk_draw_index *idx;
8859 nk_draw_index index;
8860 NK_ASSERT(list);
8861 if (!list) return;
8862
8863 nk_color_fv(&col.r, color);
8864 uvb = nk_vec2(uvc.x, uva.y);
8865 uvd = nk_vec2(uva.x, uvc.y);
8866 b = nk_vec2(c.x, a.y);
8867 d = nk_vec2(a.x, c.y);
8868
8869 index = (nk_draw_index)list->vertex_count;
8870 vtx = nk_draw_list_alloc_vertices(list, 4);
8871 idx = nk_draw_list_alloc_elements(list, 6);
8872 if (!vtx || !idx) return;
8873
8874 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
8875 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
8876 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
8877
8878 vtx = nk_draw_vertex(vtx, &list->config, a, uva, col);
8879 vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col);
8880 vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col);
8881 vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col);
8882 }
8883
8884 NK_API void
8885 nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture,
8886 struct nk_rect rect, struct nk_color color)
8887 {
8888 NK_ASSERT(list);
8889 if (!list) return;
8890 /* push new command with given texture */
8891 nk_draw_list_push_image(list, texture.handle);
8892 if (nk_image_is_subimage(&texture)) {
8893 /* add region inside of the texture */
8894 struct nk_vec2 uv[2];
8895 uv[0].x = (float)texture.region[0]/(float)texture.w;
8896 uv[0].y = (float)texture.region[1]/(float)texture.h;
8897 uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w;
8898 uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h;
8899 nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
8900 nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color);
8901 } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
8902 nk_vec2(rect.x + rect.w, rect.y + rect.h),
8903 nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color);
8904 }
8905
8906 NK_API void
8907 nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font,
8908 struct nk_rect rect, const char *text, int len, float font_height,
8909 struct nk_color fg)
8910 {
8911 float x = 0;
8912 int text_len = 0;
8913 nk_rune unicode = 0;
8914 nk_rune next = 0;
8915 int glyph_len = 0;
8916 int next_glyph_len = 0;
8917 struct nk_user_font_glyph g;
8918
8919 NK_ASSERT(list);
8920 if (!list || !len || !text) return;
8921 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
8922 list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return;
8923
8924 nk_draw_list_push_image(list, font->texture);
8925 x = rect.x;
8926 glyph_len = nk_utf_decode(text, &unicode, len);
8927 if (!glyph_len) return;
8928
8929 /* draw every glyph image */
8930 fg.a = (nk_byte)((float)fg.a * list->config.global_alpha);
8931 while (text_len < len && glyph_len) {
8932 float gx, gy, gh, gw;
8933 float char_width = 0;
8934 if (unicode == NK_UTF_INVALID) break;
8935
8936 /* query currently drawn glyph information */
8937 next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);
8938 font->query(font->userdata, font_height, &g, unicode,
8939 (next == NK_UTF_INVALID) ? '\0' : next);
8940
8941 /* calculate and draw glyph drawing rectangle and image */
8942 gx = x + g.offset.x;
8943 gy = rect.y + g.offset.y;
8944 gw = g.width; gh = g.height;
8945 char_width = g.xadvance;
8946 nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh),
8947 g.uv[0], g.uv[1], fg);
8948
8949 /* offset next glyph */
8950 text_len += glyph_len;
8951 x += char_width;
8952 glyph_len = next_glyph_len;
8953 unicode = next;
8954 }
8955 }
8956
8957 NK_API nk_flags
8958 nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,
8959 struct nk_buffer *vertices, struct nk_buffer *elements,
8960 const struct nk_convert_config *config)
8961 {
8962 nk_flags res = NK_CONVERT_SUCCESS;
8963 const struct nk_command *cmd;
8964 NK_ASSERT(ctx);
8965 NK_ASSERT(cmds);
8966 NK_ASSERT(vertices);
8967 NK_ASSERT(elements);
8968 NK_ASSERT(config);
8969 NK_ASSERT(config->vertex_layout);
8970 NK_ASSERT(config->vertex_size);
8971 if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout)
8972 return NK_CONVERT_INVALID_PARAM;
8973
8974 nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements,
8975 config->line_AA, config->shape_AA);
8976 nk_foreach(cmd, ctx)
8977 {
8978 #ifdef NK_INCLUDE_COMMAND_USERDATA
8979 ctx->draw_list.userdata = cmd->userdata;
8980 #endif
8981 switch (cmd->type) {
8982 case NK_COMMAND_NOP: break;
8983 case NK_COMMAND_SCISSOR: {
8984 const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;
8985 nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h));
8986 } break;
8987 case NK_COMMAND_LINE: {
8988 const struct nk_command_line *l = (const struct nk_command_line*)cmd;
8989 nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y),
8990 nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness);
8991 } break;
8992 case NK_COMMAND_CURVE: {
8993 const struct nk_command_curve *q = (const struct nk_command_curve*)cmd;
8994 nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y),
8995 nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x,
8996 q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color,
8997 config->curve_segment_count, q->line_thickness);
8998 } break;
8999 case NK_COMMAND_RECT: {
9000 const struct nk_command_rect *r = (const struct nk_command_rect*)cmd;
9001 nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
9002 r->color, (float)r->rounding, r->line_thickness);
9003 } break;
9004 case NK_COMMAND_RECT_FILLED: {
9005 const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd;
9006 nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
9007 r->color, (float)r->rounding);
9008 } break;
9009 case NK_COMMAND_RECT_MULTI_COLOR: {
9010 const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd;
9011 nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
9012 r->left, r->top, r->right, r->bottom);
9013 } break;
9014 case NK_COMMAND_CIRCLE: {
9015 const struct nk_command_circle *c = (const struct nk_command_circle*)cmd;
9016 nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
9017 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
9018 config->circle_segment_count, c->line_thickness);
9019 } break;
9020 case NK_COMMAND_CIRCLE_FILLED: {
9021 const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
9022 nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
9023 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
9024 config->circle_segment_count);
9025 } break;
9026 case NK_COMMAND_ARC: {
9027 const struct nk_command_arc *c = (const struct nk_command_arc*)cmd;
9028 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
9029 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
9030 c->a[0], c->a[1], config->arc_segment_count);
9031 nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness);
9032 } break;
9033 case NK_COMMAND_ARC_FILLED: {
9034 const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd;
9035 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
9036 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
9037 c->a[0], c->a[1], config->arc_segment_count);
9038 nk_draw_list_path_fill(&ctx->draw_list, c->color);
9039 } break;
9040 case NK_COMMAND_TRIANGLE: {
9041 const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;
9042 nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
9043 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color,
9044 t->line_thickness);
9045 } break;
9046 case NK_COMMAND_TRIANGLE_FILLED: {
9047 const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;
9048 nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
9049 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color);
9050 } break;
9051 case NK_COMMAND_POLYGON: {
9052 int i;
9053 const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd;
9054 for (i = 0; i < p->point_count; ++i) {
9055 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
9056 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
9057 }
9058 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness);
9059 } break;
9060 case NK_COMMAND_POLYGON_FILLED: {
9061 int i;
9062 const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;
9063 for (i = 0; i < p->point_count; ++i) {
9064 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
9065 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
9066 }
9067 nk_draw_list_path_fill(&ctx->draw_list, p->color);
9068 } break;
9069 case NK_COMMAND_POLYLINE: {
9070 int i;
9071 const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd;
9072 for (i = 0; i < p->point_count; ++i) {
9073 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
9074 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
9075 }
9076 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness);
9077 } break;
9078 case NK_COMMAND_TEXT: {
9079 const struct nk_command_text *t = (const struct nk_command_text*)cmd;
9080 nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h),
9081 t->string, t->length, t->height, t->foreground);
9082 } break;
9083 case NK_COMMAND_IMAGE: {
9084 const struct nk_command_image *i = (const struct nk_command_image*)cmd;
9085 nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col);
9086 } break;
9087 case NK_COMMAND_CUSTOM: {
9088 const struct nk_command_custom *c = (const struct nk_command_custom*)cmd;
9089 c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data);
9090 } break;
9091 default: break;
9092 }
9093 }
9094 res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0;
9095 res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0;
9096 res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0;
9097 return res;
9098 }
9099 NK_API const struct nk_draw_command*
9100 nk__draw_begin(const struct nk_context *ctx,
9101 const struct nk_buffer *buffer)
9102 {return nk__draw_list_begin(&ctx->draw_list, buffer);}
9103
9104 NK_API const struct nk_draw_command*
9105 nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer)
9106 {return nk__draw_list_end(&ctx->draw_list, buffer);}
9107
9108 NK_API const struct nk_draw_command*
9109 nk__draw_next(const struct nk_draw_command *cmd,
9110 const struct nk_buffer *buffer, const struct nk_context *ctx)
9111 {return nk__draw_list_next(cmd, buffer, &ctx->draw_list);}
9112
9113 #endif
9114
9115 /*
9116 * ==============================================================
9117 *
9118 * FONT HANDLING
9119 *
9120 * ===============================================================
9121 */
9122 #ifdef NK_INCLUDE_FONT_BAKING
9123 /* -------------------------------------------------------------
9124 *
9125 * RECT PACK
9126 *
9127 * --------------------------------------------------------------*/
9128 /* stb_rect_pack.h - v0.05 - public domain - rectangle packing */
9129 /* Sean Barrett 2014 */
9130 #define NK_RP__MAXVAL 0xffff
9131 typedef unsigned short nk_rp_coord;
9132
9133 struct nk_rp_rect {
9134 /* reserved for your use: */
9135 int id;
9136 /* input: */
9137 nk_rp_coord w, h;
9138 /* output: */
9139 nk_rp_coord x, y;
9140 int was_packed;
9141 /* non-zero if valid packing */
9142 }; /* 16 bytes, nominally */
9143
9144 struct nk_rp_node {
9145 nk_rp_coord x,y;
9146 struct nk_rp_node *next;
9147 };
9148
9149 struct nk_rp_context {
9150 int width;
9151 int height;
9152 int align;
9153 int init_mode;
9154 int heuristic;
9155 int num_nodes;
9156 struct nk_rp_node *active_head;
9157 struct nk_rp_node *free_head;
9158 struct nk_rp_node extra[2];
9159 /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */
9160 };
9161
9162 struct nk_rp__findresult {
9163 int x,y;
9164 struct nk_rp_node **prev_link;
9165 };
9166
9167 enum NK_RP_HEURISTIC {
9168 NK_RP_HEURISTIC_Skyline_default=0,
9169 NK_RP_HEURISTIC_Skyline_BL_sortHeight = NK_RP_HEURISTIC_Skyline_default,
9170 NK_RP_HEURISTIC_Skyline_BF_sortHeight
9171 };
9172 enum NK_RP_INIT_STATE{NK_RP__INIT_skyline = 1};
9173
9174 NK_INTERN void
9175 nk_rp_setup_allow_out_of_mem(struct nk_rp_context *context, int allow_out_of_mem)
9176 {
9177 if (allow_out_of_mem)
9178 /* if it's ok to run out of memory, then don't bother aligning them; */
9179 /* this gives better packing, but may fail due to OOM (even though */
9180 /* the rectangles easily fit). @TODO a smarter approach would be to only */
9181 /* quantize once we've hit OOM, then we could get rid of this parameter. */
9182 context->align = 1;
9183 else {
9184 /* if it's not ok to run out of memory, then quantize the widths */
9185 /* so that num_nodes is always enough nodes. */
9186 /* */
9187 /* I.e. num_nodes * align >= width */
9188 /* align >= width / num_nodes */
9189 /* align = ceil(width/num_nodes) */
9190 context->align = (context->width + context->num_nodes-1) / context->num_nodes;
9191 }
9192 }
9193
9194 NK_INTERN void
9195 nk_rp_init_target(struct nk_rp_context *context, int width, int height,
9196 struct nk_rp_node *nodes, int num_nodes)
9197 {
9198 int i;
9199 #ifndef STBRP_LARGE_RECTS
9200 NK_ASSERT(width <= 0xffff && height <= 0xffff);
9201 #endif
9202
9203 for (i=0; i < num_nodes-1; ++i)
9204 nodes[i].next = &nodes[i+1];
9205 nodes[i].next = 0;
9206 context->init_mode = NK_RP__INIT_skyline;
9207 context->heuristic = NK_RP_HEURISTIC_Skyline_default;
9208 context->free_head = &nodes[0];
9209 context->active_head = &context->extra[0];
9210 context->width = width;
9211 context->height = height;
9212 context->num_nodes = num_nodes;
9213 nk_rp_setup_allow_out_of_mem(context, 0);
9214
9215 /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */
9216 context->extra[0].x = 0;
9217 context->extra[0].y = 0;
9218 context->extra[0].next = &context->extra[1];
9219 context->extra[1].x = (nk_rp_coord) width;
9220 context->extra[1].y = 65535;
9221 context->extra[1].next = 0;
9222 }
9223
9224 /* find minimum y position if it starts at x1 */
9225 NK_INTERN int
9226 nk_rp__skyline_find_min_y(struct nk_rp_context *c, struct nk_rp_node *first,
9227 int x0, int width, int *pwaste)
9228 {
9229 struct nk_rp_node *node = first;
9230 int x1 = x0 + width;
9231 int min_y, visited_width, waste_area;
9232 NK_ASSERT(first->x <= x0);
9233 NK_UNUSED(c);
9234
9235 NK_ASSERT(node->next->x > x0);
9236 /* we ended up handling this in the caller for efficiency */
9237 NK_ASSERT(node->x <= x0);
9238
9239 min_y = 0;
9240 waste_area = 0;
9241 visited_width = 0;
9242 while (node->x < x1)
9243 {
9244 if (node->y > min_y) {
9245 /* raise min_y higher. */
9246 /* we've accounted for all waste up to min_y, */
9247 /* but we'll now add more waste for everything we've visited */
9248 waste_area += visited_width * (node->y - min_y);
9249 min_y = node->y;
9250 /* the first time through, visited_width might be reduced */
9251 if (node->x < x0)
9252 visited_width += node->next->x - x0;
9253 else
9254 visited_width += node->next->x - node->x;
9255 } else {
9256 /* add waste area */
9257 int under_width = node->next->x - node->x;
9258 if (under_width + visited_width > width)
9259 under_width = width - visited_width;
9260 waste_area += under_width * (min_y - node->y);
9261 visited_width += under_width;
9262 }
9263 node = node->next;
9264 }
9265 *pwaste = waste_area;
9266 return min_y;
9267 }
9268
9269 NK_INTERN struct nk_rp__findresult
9270 nk_rp__skyline_find_best_pos(struct nk_rp_context *c, int width, int height)
9271 {
9272 int best_waste = (1<<30), best_x, best_y = (1 << 30);
9273 struct nk_rp__findresult fr;
9274 struct nk_rp_node **prev, *node, *tail, **best = 0;
9275
9276 /* align to multiple of c->align */
9277 width = (width + c->align - 1);
9278 width -= width % c->align;
9279 NK_ASSERT(width % c->align == 0);
9280
9281 node = c->active_head;
9282 prev = &c->active_head;
9283 while (node->x + width <= c->width) {
9284 int y,waste;
9285 y = nk_rp__skyline_find_min_y(c, node, node->x, width, &waste);
9286 /* actually just want to test BL */
9287 if (c->heuristic == NK_RP_HEURISTIC_Skyline_BL_sortHeight) {
9288 /* bottom left */
9289 if (y < best_y) {
9290 best_y = y;
9291 best = prev;
9292 }
9293 } else {
9294 /* best-fit */
9295 if (y + height <= c->height) {
9296 /* can only use it if it first vertically */
9297 if (y < best_y || (y == best_y && waste < best_waste)) {
9298 best_y = y;
9299 best_waste = waste;
9300 best = prev;
9301 }
9302 }
9303 }
9304 prev = &node->next;
9305 node = node->next;
9306 }
9307 best_x = (best == 0) ? 0 : (*best)->x;
9308
9309 /* if doing best-fit (BF), we also have to try aligning right edge to each node position */
9310 /* */
9311 /* e.g, if fitting */
9312 /* */
9313 /* ____________________ */
9314 /* |____________________| */
9315 /* */
9316 /* into */
9317 /* */
9318 /* | | */
9319 /* | ____________| */
9320 /* |____________| */
9321 /* */
9322 /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */
9323 /* */
9324 /* This makes BF take about 2x the time */
9325 if (c->heuristic == NK_RP_HEURISTIC_Skyline_BF_sortHeight)
9326 {
9327 tail = c->active_head;
9328 node = c->active_head;
9329 prev = &c->active_head;
9330 /* find first node that's admissible */
9331 while (tail->x < width)
9332 tail = tail->next;
9333 while (tail)
9334 {
9335 int xpos = tail->x - width;
9336 int y,waste;
9337 NK_ASSERT(xpos >= 0);
9338 /* find the left position that matches this */
9339 while (node->next->x <= xpos) {
9340 prev = &node->next;
9341 node = node->next;
9342 }
9343 NK_ASSERT(node->next->x > xpos && node->x <= xpos);
9344 y = nk_rp__skyline_find_min_y(c, node, xpos, width, &waste);
9345 if (y + height < c->height) {
9346 if (y <= best_y) {
9347 if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
9348 best_x = xpos;
9349 NK_ASSERT(y <= best_y);
9350 best_y = y;
9351 best_waste = waste;
9352 best = prev;
9353 }
9354 }
9355 }
9356 tail = tail->next;
9357 }
9358 }
9359 fr.prev_link = best;
9360 fr.x = best_x;
9361 fr.y = best_y;
9362 return fr;
9363 }
9364
9365 NK_INTERN struct nk_rp__findresult
9366 nk_rp__skyline_pack_rectangle(struct nk_rp_context *context, int width, int height)
9367 {
9368 /* find best position according to heuristic */
9369 struct nk_rp__findresult res = nk_rp__skyline_find_best_pos(context, width, height);
9370 struct nk_rp_node *node, *cur;
9371
9372 /* bail if: */
9373 /* 1. it failed */
9374 /* 2. the best node doesn't fit (we don't always check this) */
9375 /* 3. we're out of memory */
9376 if (res.prev_link == 0 || res.y + height > context->height || context->free_head == 0) {
9377 res.prev_link = 0;
9378 return res;
9379 }
9380
9381 /* on success, create new node */
9382 node = context->free_head;
9383 node->x = (nk_rp_coord) res.x;
9384 node->y = (nk_rp_coord) (res.y + height);
9385
9386 context->free_head = node->next;
9387
9388 /* insert the new node into the right starting point, and */
9389 /* let 'cur' point to the remaining nodes needing to be */
9390 /* stitched back in */
9391 cur = *res.prev_link;
9392 if (cur->x < res.x) {
9393 /* preserve the existing one, so start testing with the next one */
9394 struct nk_rp_node *next = cur->next;
9395 cur->next = node;
9396 cur = next;
9397 } else {
9398 *res.prev_link = node;
9399 }
9400
9401 /* from here, traverse cur and free the nodes, until we get to one */
9402 /* that shouldn't be freed */
9403 while (cur->next && cur->next->x <= res.x + width) {
9404 struct nk_rp_node *next = cur->next;
9405 /* move the current node to the free list */
9406 cur->next = context->free_head;
9407 context->free_head = cur;
9408 cur = next;
9409 }
9410 /* stitch the list back in */
9411 node->next = cur;
9412
9413 if (cur->x < res.x + width)
9414 cur->x = (nk_rp_coord) (res.x + width);
9415 return res;
9416 }
9417
9418 NK_INTERN int
9419 nk_rect_height_compare(const void *a, const void *b)
9420 {
9421 const struct nk_rp_rect *p = (const struct nk_rp_rect *) a;
9422 const struct nk_rp_rect *q = (const struct nk_rp_rect *) b;
9423 if (p->h > q->h)
9424 return -1;
9425 if (p->h < q->h)
9426 return 1;
9427 return (p->w > q->w) ? -1 : (p->w < q->w);
9428 }
9429
9430 NK_INTERN int
9431 nk_rect_original_order(const void *a, const void *b)
9432 {
9433 const struct nk_rp_rect *p = (const struct nk_rp_rect *) a;
9434 const struct nk_rp_rect *q = (const struct nk_rp_rect *) b;
9435 return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
9436 }
9437
9438 NK_INTERN void
9439 nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*))
9440 {
9441 /* iterative quick sort */
9442 #define NK_MAX_SORT_STACK 64
9443 unsigned right, left = 0, stack[NK_MAX_SORT_STACK], pos = 0;
9444 unsigned seed = len/2 * 69069+1;
9445 for (;;) {
9446 for (; left+1 < len; len++) {
9447 struct nk_rp_rect pivot, tmp;
9448 if (pos == NK_MAX_SORT_STACK) len = stack[pos = 0];
9449 pivot = array[left+seed%(len-left)];
9450 seed = seed * 69069 + 1;
9451 stack[pos++] = len;
9452 for (right = left-1;;) {
9453 while (cmp(&array[++right], &pivot) < 0);
9454 while (cmp(&pivot, &array[--len]) < 0);
9455 if (right >= len) break;
9456 tmp = array[right];
9457 array[right] = array[len];
9458 array[len] = tmp;
9459 }
9460 }
9461 if (pos == 0) break;
9462 left = len;
9463 len = stack[--pos];
9464 }
9465 #undef NK_MAX_SORT_STACK
9466 }
9467
9468 NK_INTERN void
9469 nk_rp_pack_rects(struct nk_rp_context *context, struct nk_rp_rect *rects, int num_rects)
9470 {
9471 int i;
9472 /* we use the 'was_packed' field internally to allow sorting/unsorting */
9473 for (i=0; i < num_rects; ++i) {
9474 rects[i].was_packed = i;
9475 }
9476
9477 /* sort according to heuristic */
9478 nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_height_compare);
9479
9480 for (i=0; i < num_rects; ++i) {
9481 struct nk_rp__findresult fr = nk_rp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
9482 if (fr.prev_link) {
9483 rects[i].x = (nk_rp_coord) fr.x;
9484 rects[i].y = (nk_rp_coord) fr.y;
9485 } else {
9486 rects[i].x = rects[i].y = NK_RP__MAXVAL;
9487 }
9488 }
9489
9490 /* unsort */
9491 nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_original_order);
9492
9493 /* set was_packed flags */
9494 for (i=0; i < num_rects; ++i)
9495 rects[i].was_packed = !(rects[i].x == NK_RP__MAXVAL && rects[i].y == NK_RP__MAXVAL);
9496 }
9497
9498 /*
9499 * ==============================================================
9500 *
9501 * TRUETYPE
9502 *
9503 * ===============================================================
9504 */
9505 /* stb_truetype.h - v1.07 - public domain */
9506 #define NK_TT_MAX_OVERSAMPLE 8
9507 #define NK_TT__OVER_MASK (NK_TT_MAX_OVERSAMPLE-1)
9508
9509 struct nk_tt_bakedchar {
9510 unsigned short x0,y0,x1,y1;
9511 /* coordinates of bbox in bitmap */
9512 float xoff,yoff,xadvance;
9513 };
9514
9515 struct nk_tt_aligned_quad{
9516 float x0,y0,s0,t0; /* top-left */
9517 float x1,y1,s1,t1; /* bottom-right */
9518 };
9519
9520 struct nk_tt_packedchar {
9521 unsigned short x0,y0,x1,y1;
9522 /* coordinates of bbox in bitmap */
9523 float xoff,yoff,xadvance;
9524 float xoff2,yoff2;
9525 };
9526
9527 struct nk_tt_pack_range {
9528 float font_size;
9529 int first_unicode_codepoint_in_range;
9530 /* if non-zero, then the chars are continuous, and this is the first codepoint */
9531 int *array_of_unicode_codepoints;
9532 /* if non-zero, then this is an array of unicode codepoints */
9533 int num_chars;
9534 struct nk_tt_packedchar *chardata_for_range; /* output */
9535 unsigned char h_oversample, v_oversample;
9536 /* don't set these, they're used internally */
9537 };
9538
9539 struct nk_tt_pack_context {
9540 void *pack_info;
9541 int width;
9542 int height;
9543 int stride_in_bytes;
9544 int padding;
9545 unsigned int h_oversample, v_oversample;
9546 unsigned char *pixels;
9547 void *nodes;
9548 };
9549
9550 struct nk_tt_fontinfo {
9551 const unsigned char* data; /* pointer to .ttf file */
9552 int fontstart;/* offset of start of font */
9553 int numGlyphs;/* number of glyphs, needed for range checking */
9554 int loca,head,glyf,hhea,hmtx,kern; /* table locations as offset from start of .ttf */
9555 int index_map; /* a cmap mapping for our chosen character encoding */
9556 int indexToLocFormat; /* format needed to map from glyph index to glyph */
9557 };
9558
9559 enum {
9560 NK_TT_vmove=1,
9561 NK_TT_vline,
9562 NK_TT_vcurve
9563 };
9564
9565 struct nk_tt_vertex {
9566 short x,y,cx,cy;
9567 unsigned char type,padding;
9568 };
9569
9570 struct nk_tt__bitmap{
9571 int w,h,stride;
9572 unsigned char *pixels;
9573 };
9574
9575 struct nk_tt__hheap_chunk {
9576 struct nk_tt__hheap_chunk *next;
9577 };
9578 struct nk_tt__hheap {
9579 struct nk_allocator alloc;
9580 struct nk_tt__hheap_chunk *head;
9581 void *first_free;
9582 int num_remaining_in_head_chunk;
9583 };
9584
9585 struct nk_tt__edge {
9586 float x0,y0, x1,y1;
9587 int invert;
9588 };
9589
9590 struct nk_tt__active_edge {
9591 struct nk_tt__active_edge *next;
9592 float fx,fdx,fdy;
9593 float direction;
9594 float sy;
9595 float ey;
9596 };
9597 struct nk_tt__point {float x,y;};
9598
9599 #define NK_TT_MACSTYLE_DONTCARE 0
9600 #define NK_TT_MACSTYLE_BOLD 1
9601 #define NK_TT_MACSTYLE_ITALIC 2
9602 #define NK_TT_MACSTYLE_UNDERSCORE 4
9603 #define NK_TT_MACSTYLE_NONE 8
9604 /* <= not same as 0, this makes us check the bitfield is 0 */
9605
9606 enum { /* platformID */
9607 NK_TT_PLATFORM_ID_UNICODE =0,
9608 NK_TT_PLATFORM_ID_MAC =1,
9609 NK_TT_PLATFORM_ID_ISO =2,
9610 NK_TT_PLATFORM_ID_MICROSOFT =3
9611 };
9612
9613 enum { /* encodingID for NK_TT_PLATFORM_ID_UNICODE */
9614 NK_TT_UNICODE_EID_UNICODE_1_0 =0,
9615 NK_TT_UNICODE_EID_UNICODE_1_1 =1,
9616 NK_TT_UNICODE_EID_ISO_10646 =2,
9617 NK_TT_UNICODE_EID_UNICODE_2_0_BMP=3,
9618 NK_TT_UNICODE_EID_UNICODE_2_0_FULL=4
9619 };
9620
9621 enum { /* encodingID for NK_TT_PLATFORM_ID_MICROSOFT */
9622 NK_TT_MS_EID_SYMBOL =0,
9623 NK_TT_MS_EID_UNICODE_BMP =1,
9624 NK_TT_MS_EID_SHIFTJIS =2,
9625 NK_TT_MS_EID_UNICODE_FULL =10
9626 };
9627
9628 enum { /* encodingID for NK_TT_PLATFORM_ID_MAC; same as Script Manager codes */
9629 NK_TT_MAC_EID_ROMAN =0, NK_TT_MAC_EID_ARABIC =4,
9630 NK_TT_MAC_EID_JAPANESE =1, NK_TT_MAC_EID_HEBREW =5,
9631 NK_TT_MAC_EID_CHINESE_TRAD =2, NK_TT_MAC_EID_GREEK =6,
9632 NK_TT_MAC_EID_KOREAN =3, NK_TT_MAC_EID_RUSSIAN =7
9633 };
9634
9635 enum { /* languageID for NK_TT_PLATFORM_ID_MICROSOFT; same as LCID... */
9636 /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */
9637 NK_TT_MS_LANG_ENGLISH =0x0409, NK_TT_MS_LANG_ITALIAN =0x0410,
9638 NK_TT_MS_LANG_CHINESE =0x0804, NK_TT_MS_LANG_JAPANESE =0x0411,
9639 NK_TT_MS_LANG_DUTCH =0x0413, NK_TT_MS_LANG_KOREAN =0x0412,
9640 NK_TT_MS_LANG_FRENCH =0x040c, NK_TT_MS_LANG_RUSSIAN =0x0419,
9641 NK_TT_MS_LANG_GERMAN =0x0407, NK_TT_MS_LANG_SPANISH =0x0409,
9642 NK_TT_MS_LANG_HEBREW =0x040d, NK_TT_MS_LANG_SWEDISH =0x041D
9643 };
9644
9645 enum { /* languageID for NK_TT_PLATFORM_ID_MAC */
9646 NK_TT_MAC_LANG_ENGLISH =0 , NK_TT_MAC_LANG_JAPANESE =11,
9647 NK_TT_MAC_LANG_ARABIC =12, NK_TT_MAC_LANG_KOREAN =23,
9648 NK_TT_MAC_LANG_DUTCH =4 , NK_TT_MAC_LANG_RUSSIAN =32,
9649 NK_TT_MAC_LANG_FRENCH =1 , NK_TT_MAC_LANG_SPANISH =6 ,
9650 NK_TT_MAC_LANG_GERMAN =2 , NK_TT_MAC_LANG_SWEDISH =5 ,
9651 NK_TT_MAC_LANG_HEBREW =10, NK_TT_MAC_LANG_CHINESE_SIMPLIFIED =33,
9652 NK_TT_MAC_LANG_ITALIAN =3 , NK_TT_MAC_LANG_CHINESE_TRAD =19
9653 };
9654
9655 #define nk_ttBYTE(p) (* (const nk_byte *) (p))
9656 #define nk_ttCHAR(p) (* (const char *) (p))
9657
9658 #if defined(NK_BIGENDIAN) && !defined(NK_ALLOW_UNALIGNED_TRUETYPE)
9659 #define nk_ttUSHORT(p) (* (nk_ushort *) (p))
9660 #define nk_ttSHORT(p) (* (nk_short *) (p))
9661 #define nk_ttULONG(p) (* (nk_uint *) (p))
9662 #define nk_ttLONG(p) (* (nk_int *) (p))
9663 #else
9664 static nk_ushort nk_ttUSHORT(const nk_byte *p) { return (nk_ushort)(p[0]*256 + p[1]); }
9665 static nk_short nk_ttSHORT(const nk_byte *p) { return (nk_short)(p[0]*256 + p[1]); }
9666 static nk_uint nk_ttULONG(const nk_byte *p) { return (nk_uint)((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]); }
9667 #endif
9668
9669 #define nk_tt_tag4(p,c0,c1,c2,c3)\
9670 ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
9671 #define nk_tt_tag(p,str) nk_tt_tag4(p,str[0],str[1],str[2],str[3])
9672
9673 NK_INTERN int nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc,
9674 int glyph_index, struct nk_tt_vertex **pvertices);
9675
9676 NK_INTERN nk_uint
9677 nk_tt__find_table(const nk_byte *data, nk_uint fontstart, const char *tag)
9678 {
9679 /* @OPTIMIZE: binary search */
9680 nk_int num_tables = nk_ttUSHORT(data+fontstart+4);
9681 nk_uint tabledir = fontstart + 12;
9682 nk_int i;
9683 for (i = 0; i < num_tables; ++i) {
9684 nk_uint loc = tabledir + (nk_uint)(16*i);
9685 if (nk_tt_tag(data+loc+0, tag))
9686 return nk_ttULONG(data+loc+8);
9687 }
9688 return 0;
9689 }
9690
9691 NK_INTERN int
9692 nk_tt_InitFont(struct nk_tt_fontinfo *info, const unsigned char *data2, int fontstart)
9693 {
9694 nk_uint cmap, t;
9695 nk_int i,numTables;
9696 const nk_byte *data = (const nk_byte *) data2;
9697
9698 info->data = data;
9699 info->fontstart = fontstart;
9700
9701 cmap = nk_tt__find_table(data, (nk_uint)fontstart, "cmap"); /* required */
9702 info->loca = (int)nk_tt__find_table(data, (nk_uint)fontstart, "loca"); /* required */
9703 info->head = (int)nk_tt__find_table(data, (nk_uint)fontstart, "head"); /* required */
9704 info->glyf = (int)nk_tt__find_table(data, (nk_uint)fontstart, "glyf"); /* required */
9705 info->hhea = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hhea"); /* required */
9706 info->hmtx = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hmtx"); /* required */
9707 info->kern = (int)nk_tt__find_table(data, (nk_uint)fontstart, "kern"); /* not required */
9708 if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
9709 return 0;
9710
9711 t = nk_tt__find_table(data, (nk_uint)fontstart, "maxp");
9712 if (t) info->numGlyphs = nk_ttUSHORT(data+t+4);
9713 else info->numGlyphs = 0xffff;
9714
9715 /* find a cmap encoding table we understand *now* to avoid searching */
9716 /* later. (todo: could make this installable) */
9717 /* the same regardless of glyph. */
9718 numTables = nk_ttUSHORT(data + cmap + 2);
9719 info->index_map = 0;
9720 for (i=0; i < numTables; ++i)
9721 {
9722 nk_uint encoding_record = cmap + 4 + 8 * (nk_uint)i;
9723 /* find an encoding we understand: */
9724 switch(nk_ttUSHORT(data+encoding_record)) {
9725 case NK_TT_PLATFORM_ID_MICROSOFT:
9726 switch (nk_ttUSHORT(data+encoding_record+2)) {
9727 case NK_TT_MS_EID_UNICODE_BMP:
9728 case NK_TT_MS_EID_UNICODE_FULL:
9729 /* MS/Unicode */
9730 info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4));
9731 break;
9732 default: break;
9733 } break;
9734 case NK_TT_PLATFORM_ID_UNICODE:
9735 /* Mac/iOS has these */
9736 /* all the encodingIDs are unicode, so we don't bother to check it */
9737 info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4));
9738 break;
9739 default: break;
9740 }
9741 }
9742 if (info->index_map == 0)
9743 return 0;
9744 info->indexToLocFormat = nk_ttUSHORT(data+info->head + 50);
9745 return 1;
9746 }
9747
9748 NK_INTERN int
9749 nk_tt_FindGlyphIndex(const struct nk_tt_fontinfo *info, int unicode_codepoint)
9750 {
9751 const nk_byte *data = info->data;
9752 nk_uint index_map = (nk_uint)info->index_map;
9753
9754 nk_ushort format = nk_ttUSHORT(data + index_map + 0);
9755 if (format == 0) { /* apple byte encoding */
9756 nk_int bytes = nk_ttUSHORT(data + index_map + 2);
9757 if (unicode_codepoint < bytes-6)
9758 return nk_ttBYTE(data + index_map + 6 + unicode_codepoint);
9759 return 0;
9760 } else if (format == 6) {
9761 nk_uint first = nk_ttUSHORT(data + index_map + 6);
9762 nk_uint count = nk_ttUSHORT(data + index_map + 8);
9763 if ((nk_uint) unicode_codepoint >= first && (nk_uint) unicode_codepoint < first+count)
9764 return nk_ttUSHORT(data + index_map + 10 + (unicode_codepoint - (int)first)*2);
9765 return 0;
9766 } else if (format == 2) {
9767 NK_ASSERT(0); /* @TODO: high-byte mapping for japanese/chinese/korean */
9768 return 0;
9769 } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */
9770 nk_ushort segcount = nk_ttUSHORT(data+index_map+6) >> 1;
9771 nk_ushort searchRange = nk_ttUSHORT(data+index_map+8) >> 1;
9772 nk_ushort entrySelector = nk_ttUSHORT(data+index_map+10);
9773 nk_ushort rangeShift = nk_ttUSHORT(data+index_map+12) >> 1;
9774
9775 /* do a binary search of the segments */
9776 nk_uint endCount = index_map + 14;
9777 nk_uint search = endCount;
9778
9779 if (unicode_codepoint > 0xffff)
9780 return 0;
9781
9782 /* they lie from endCount .. endCount + segCount */
9783 /* but searchRange is the nearest power of two, so... */
9784 if (unicode_codepoint >= nk_ttUSHORT(data + search + rangeShift*2))
9785 search += (nk_uint)(rangeShift*2);
9786
9787 /* now decrement to bias correctly to find smallest */
9788 search -= 2;
9789 while (entrySelector) {
9790 nk_ushort end;
9791 searchRange >>= 1;
9792 end = nk_ttUSHORT(data + search + searchRange*2);
9793 if (unicode_codepoint > end)
9794 search += (nk_uint)(searchRange*2);
9795 --entrySelector;
9796 }
9797 search += 2;
9798
9799 {
9800 nk_ushort offset, start;
9801 nk_ushort item = (nk_ushort) ((search - endCount) >> 1);
9802
9803 NK_ASSERT(unicode_codepoint <= nk_ttUSHORT(data + endCount + 2*item));
9804 start = nk_ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
9805 if (unicode_codepoint < start)
9806 return 0;
9807
9808 offset = nk_ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
9809 if (offset == 0)
9810 return (nk_ushort) (unicode_codepoint + nk_ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
9811
9812 return nk_ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
9813 }
9814 } else if (format == 12 || format == 13) {
9815 nk_uint ngroups = nk_ttULONG(data+index_map+12);
9816 nk_int low,high;
9817 low = 0; high = (nk_int)ngroups;
9818 /* Binary search the right group. */
9819 while (low < high) {
9820 nk_int mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */
9821 nk_uint start_char = nk_ttULONG(data+index_map+16+mid*12);
9822 nk_uint end_char = nk_ttULONG(data+index_map+16+mid*12+4);
9823 if ((nk_uint) unicode_codepoint < start_char)
9824 high = mid;
9825 else if ((nk_uint) unicode_codepoint > end_char)
9826 low = mid+1;
9827 else {
9828 nk_uint start_glyph = nk_ttULONG(data+index_map+16+mid*12+8);
9829 if (format == 12)
9830 return (int)start_glyph + (int)unicode_codepoint - (int)start_char;
9831 else /* format == 13 */
9832 return (int)start_glyph;
9833 }
9834 }
9835 return 0; /* not found */
9836 }
9837 /* @TODO */
9838 NK_ASSERT(0);
9839 return 0;
9840 }
9841
9842 NK_INTERN void
9843 nk_tt_setvertex(struct nk_tt_vertex *v, nk_byte type, nk_int x, nk_int y, nk_int cx, nk_int cy)
9844 {
9845 v->type = type;
9846 v->x = (nk_short) x;
9847 v->y = (nk_short) y;
9848 v->cx = (nk_short) cx;
9849 v->cy = (nk_short) cy;
9850 }
9851
9852 NK_INTERN int
9853 nk_tt__GetGlyfOffset(const struct nk_tt_fontinfo *info, int glyph_index)
9854 {
9855 int g1,g2;
9856 if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */
9857 if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */
9858
9859 if (info->indexToLocFormat == 0) {
9860 g1 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
9861 g2 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
9862 } else {
9863 g1 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4);
9864 g2 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4 + 4);
9865 }
9866 return g1==g2 ? -1 : g1; /* if length is 0, return -1 */
9867 }
9868
9869 NK_INTERN int
9870 nk_tt_GetGlyphBox(const struct nk_tt_fontinfo *info, int glyph_index,
9871 int *x0, int *y0, int *x1, int *y1)
9872 {
9873 int g = nk_tt__GetGlyfOffset(info, glyph_index);
9874 if (g < 0) return 0;
9875
9876 if (x0) *x0 = nk_ttSHORT(info->data + g + 2);
9877 if (y0) *y0 = nk_ttSHORT(info->data + g + 4);
9878 if (x1) *x1 = nk_ttSHORT(info->data + g + 6);
9879 if (y1) *y1 = nk_ttSHORT(info->data + g + 8);
9880 return 1;
9881 }
9882
9883 NK_INTERN int
9884 stbtt__close_shape(struct nk_tt_vertex *vertices, int num_vertices, int was_off,
9885 int start_off, nk_int sx, nk_int sy, nk_int scx, nk_int scy, nk_int cx, nk_int cy)
9886 {
9887 if (start_off) {
9888 if (was_off)
9889 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
9890 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, sx,sy,scx,scy);
9891 } else {
9892 if (was_off)
9893 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve,sx,sy,cx,cy);
9894 else
9895 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline,sx,sy,0,0);
9896 }
9897 return num_vertices;
9898 }
9899
9900 NK_INTERN int
9901 nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc,
9902 int glyph_index, struct nk_tt_vertex **pvertices)
9903 {
9904 nk_short numberOfContours;
9905 const nk_byte *endPtsOfContours;
9906 const nk_byte *data = info->data;
9907 struct nk_tt_vertex *vertices=0;
9908 int num_vertices=0;
9909 int g = nk_tt__GetGlyfOffset(info, glyph_index);
9910 *pvertices = 0;
9911
9912 if (g < 0) return 0;
9913 numberOfContours = nk_ttSHORT(data + g);
9914 if (numberOfContours > 0) {
9915 nk_byte flags=0,flagcount;
9916 nk_int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
9917 nk_int x,y,cx,cy,sx,sy, scx,scy;
9918 const nk_byte *points;
9919 endPtsOfContours = (data + g + 10);
9920 ins = nk_ttUSHORT(data + g + 10 + numberOfContours * 2);
9921 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
9922
9923 n = 1+nk_ttUSHORT(endPtsOfContours + numberOfContours*2-2);
9924 m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */
9925 vertices = (struct nk_tt_vertex *)alloc->alloc(alloc->userdata, 0, (nk_size)m * sizeof(vertices[0]));
9926 if (vertices == 0)
9927 return 0;
9928
9929 next_move = 0;
9930 flagcount=0;
9931
9932 /* in first pass, we load uninterpreted data into the allocated array */
9933 /* above, shifted to the end of the array so we won't overwrite it when */
9934 /* we create our final data starting from the front */
9935 off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */
9936
9937 /* first load flags */
9938 for (i=0; i < n; ++i) {
9939 if (flagcount == 0) {
9940 flags = *points++;
9941 if (flags & 8)
9942 flagcount = *points++;
9943 } else --flagcount;
9944 vertices[off+i].type = flags;
9945 }
9946
9947 /* now load x coordinates */
9948 x=0;
9949 for (i=0; i < n; ++i) {
9950 flags = vertices[off+i].type;
9951 if (flags & 2) {
9952 nk_short dx = *points++;
9953 x += (flags & 16) ? dx : -dx; /* ??? */
9954 } else {
9955 if (!(flags & 16)) {
9956 x = x + (nk_short) (points[0]*256 + points[1]);
9957 points += 2;
9958 }
9959 }
9960 vertices[off+i].x = (nk_short) x;
9961 }
9962
9963 /* now load y coordinates */
9964 y=0;
9965 for (i=0; i < n; ++i) {
9966 flags = vertices[off+i].type;
9967 if (flags & 4) {
9968 nk_short dy = *points++;
9969 y += (flags & 32) ? dy : -dy; /* ??? */
9970 } else {
9971 if (!(flags & 32)) {
9972 y = y + (nk_short) (points[0]*256 + points[1]);
9973 points += 2;
9974 }
9975 }
9976 vertices[off+i].y = (nk_short) y;
9977 }
9978
9979 /* now convert them to our format */
9980 num_vertices=0;
9981 sx = sy = cx = cy = scx = scy = 0;
9982 for (i=0; i < n; ++i)
9983 {
9984 flags = vertices[off+i].type;
9985 x = (nk_short) vertices[off+i].x;
9986 y = (nk_short) vertices[off+i].y;
9987
9988 if (next_move == i) {
9989 if (i != 0)
9990 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
9991
9992 /* now start the new one */
9993 start_off = !(flags & 1);
9994 if (start_off) {
9995 /* if we start off with an off-curve point, then when we need to find a point on the curve */
9996 /* where we can start, and we need to save some state for when we wraparound. */
9997 scx = x;
9998 scy = y;
9999 if (!(vertices[off+i+1].type & 1)) {
10000 /* next point is also a curve point, so interpolate an on-point curve */
10001 sx = (x + (nk_int) vertices[off+i+1].x) >> 1;
10002 sy = (y + (nk_int) vertices[off+i+1].y) >> 1;
10003 } else {
10004 /* otherwise just use the next point as our start point */
10005 sx = (nk_int) vertices[off+i+1].x;
10006 sy = (nk_int) vertices[off+i+1].y;
10007 ++i; /* we're using point i+1 as the starting point, so skip it */
10008 }
10009 } else {
10010 sx = x;
10011 sy = y;
10012 }
10013 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vmove,sx,sy,0,0);
10014 was_off = 0;
10015 next_move = 1 + nk_ttUSHORT(endPtsOfContours+j*2);
10016 ++j;
10017 } else {
10018 if (!(flags & 1))
10019 { /* if it's a curve */
10020 if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */
10021 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
10022 cx = x;
10023 cy = y;
10024 was_off = 1;
10025 } else {
10026 if (was_off)
10027 nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, x,y, cx, cy);
10028 else nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline, x,y,0,0);
10029 was_off = 0;
10030 }
10031 }
10032 }
10033 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
10034 } else if (numberOfContours == -1) {
10035 /* Compound shapes. */
10036 int more = 1;
10037 const nk_byte *comp = data + g + 10;
10038 num_vertices = 0;
10039 vertices = 0;
10040
10041 while (more)
10042 {
10043 nk_ushort flags, gidx;
10044 int comp_num_verts = 0, i;
10045 struct nk_tt_vertex *comp_verts = 0, *tmp = 0;
10046 float mtx[6] = {1,0,0,1,0,0}, m, n;
10047
10048 flags = (nk_ushort)nk_ttSHORT(comp); comp+=2;
10049 gidx = (nk_ushort)nk_ttSHORT(comp); comp+=2;
10050
10051 if (flags & 2) { /* XY values */
10052 if (flags & 1) { /* shorts */
10053 mtx[4] = nk_ttSHORT(comp); comp+=2;
10054 mtx[5] = nk_ttSHORT(comp); comp+=2;
10055 } else {
10056 mtx[4] = nk_ttCHAR(comp); comp+=1;
10057 mtx[5] = nk_ttCHAR(comp); comp+=1;
10058 }
10059 } else {
10060 /* @TODO handle matching point */
10061 NK_ASSERT(0);
10062 }
10063 if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */
10064 mtx[0] = mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10065 mtx[1] = mtx[2] = 0;
10066 } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */
10067 mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10068 mtx[1] = mtx[2] = 0;
10069 mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10070 } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */
10071 mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10072 mtx[1] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10073 mtx[2] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10074 mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2;
10075 }
10076
10077 /* Find transformation scales. */
10078 m = (float) NK_SQRT(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
10079 n = (float) NK_SQRT(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
10080
10081 /* Get indexed glyph. */
10082 comp_num_verts = nk_tt_GetGlyphShape(info, alloc, gidx, &comp_verts);
10083 if (comp_num_verts > 0)
10084 {
10085 /* Transform vertices. */
10086 for (i = 0; i < comp_num_verts; ++i) {
10087 struct nk_tt_vertex* v = &comp_verts[i];
10088 short x,y;
10089 x=v->x; y=v->y;
10090 v->x = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
10091 v->y = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
10092 x=v->cx; y=v->cy;
10093 v->cx = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
10094 v->cy = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
10095 }
10096 /* Append vertices. */
10097 tmp = (struct nk_tt_vertex*)alloc->alloc(alloc->userdata, 0,
10098 (nk_size)(num_vertices+comp_num_verts)*sizeof(struct nk_tt_vertex));
10099 if (!tmp) {
10100 if (vertices) alloc->free(alloc->userdata, vertices);
10101 if (comp_verts) alloc->free(alloc->userdata, comp_verts);
10102 return 0;
10103 }
10104 if (num_vertices > 0) NK_MEMCPY(tmp, vertices, (nk_size)num_vertices*sizeof(struct nk_tt_vertex));
10105 NK_MEMCPY(tmp+num_vertices, comp_verts, (nk_size)comp_num_verts*sizeof(struct nk_tt_vertex));
10106 if (vertices) alloc->free(alloc->userdata,vertices);
10107 vertices = tmp;
10108 alloc->free(alloc->userdata,comp_verts);
10109 num_vertices += comp_num_verts;
10110 }
10111 /* More components ? */
10112 more = flags & (1<<5);
10113 }
10114 } else if (numberOfContours < 0) {
10115 /* @TODO other compound variations? */
10116 NK_ASSERT(0);
10117 } else {
10118 /* numberOfCounters == 0, do nothing */
10119 }
10120 *pvertices = vertices;
10121 return num_vertices;
10122 }
10123
10124 NK_INTERN void
10125 nk_tt_GetGlyphHMetrics(const struct nk_tt_fontinfo *info, int glyph_index,
10126 int *advanceWidth, int *leftSideBearing)
10127 {
10128 nk_ushort numOfLongHorMetrics = nk_ttUSHORT(info->data+info->hhea + 34);
10129 if (glyph_index < numOfLongHorMetrics) {
10130 if (advanceWidth)
10131 *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index);
10132 if (leftSideBearing)
10133 *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
10134 } else {
10135 if (advanceWidth)
10136 *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
10137 if (leftSideBearing)
10138 *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
10139 }
10140 }
10141
10142 NK_INTERN void
10143 nk_tt_GetFontVMetrics(const struct nk_tt_fontinfo *info,
10144 int *ascent, int *descent, int *lineGap)
10145 {
10146 if (ascent ) *ascent = nk_ttSHORT(info->data+info->hhea + 4);
10147 if (descent) *descent = nk_ttSHORT(info->data+info->hhea + 6);
10148 if (lineGap) *lineGap = nk_ttSHORT(info->data+info->hhea + 8);
10149 }
10150
10151 NK_INTERN float
10152 nk_tt_ScaleForPixelHeight(const struct nk_tt_fontinfo *info, float height)
10153 {
10154 int fheight = nk_ttSHORT(info->data + info->hhea + 4) - nk_ttSHORT(info->data + info->hhea + 6);
10155 return (float) height / (float)fheight;
10156 }
10157
10158 NK_INTERN float
10159 nk_tt_ScaleForMappingEmToPixels(const struct nk_tt_fontinfo *info, float pixels)
10160 {
10161 int unitsPerEm = nk_ttUSHORT(info->data + info->head + 18);
10162 return pixels / (float)unitsPerEm;
10163 }
10164
10165 /*-------------------------------------------------------------
10166 * antialiasing software rasterizer
10167 * --------------------------------------------------------------*/
10168 NK_INTERN void
10169 nk_tt_GetGlyphBitmapBoxSubpixel(const struct nk_tt_fontinfo *font,
10170 int glyph, float scale_x, float scale_y,float shift_x, float shift_y,
10171 int *ix0, int *iy0, int *ix1, int *iy1)
10172 {
10173 int x0,y0,x1,y1;
10174 if (!nk_tt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
10175 /* e.g. space character */
10176 if (ix0) *ix0 = 0;
10177 if (iy0) *iy0 = 0;
10178 if (ix1) *ix1 = 0;
10179 if (iy1) *iy1 = 0;
10180 } else {
10181 /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */
10182 if (ix0) *ix0 = nk_ifloorf((float)x0 * scale_x + shift_x);
10183 if (iy0) *iy0 = nk_ifloorf((float)-y1 * scale_y + shift_y);
10184 if (ix1) *ix1 = nk_iceilf ((float)x1 * scale_x + shift_x);
10185 if (iy1) *iy1 = nk_iceilf ((float)-y0 * scale_y + shift_y);
10186 }
10187 }
10188
10189 NK_INTERN void
10190 nk_tt_GetGlyphBitmapBox(const struct nk_tt_fontinfo *font, int glyph,
10191 float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
10192 {
10193 nk_tt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
10194 }
10195
10196 /*-------------------------------------------------------------
10197 * Rasterizer
10198 * --------------------------------------------------------------*/
10199 NK_INTERN void*
10200 nk_tt__hheap_alloc(struct nk_tt__hheap *hh, nk_size size)
10201 {
10202 if (hh->first_free) {
10203 void *p = hh->first_free;
10204 hh->first_free = * (void **) p;
10205 return p;
10206 } else {
10207 if (hh->num_remaining_in_head_chunk == 0) {
10208 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
10209 struct nk_tt__hheap_chunk *c = (struct nk_tt__hheap_chunk *)
10210 hh->alloc.alloc(hh->alloc.userdata, 0,
10211 sizeof(struct nk_tt__hheap_chunk) + size * (nk_size)count);
10212 if (c == 0) return 0;
10213 c->next = hh->head;
10214 hh->head = c;
10215 hh->num_remaining_in_head_chunk = count;
10216 }
10217 --hh->num_remaining_in_head_chunk;
10218 return (char *) (hh->head) + size * (nk_size)hh->num_remaining_in_head_chunk;
10219 }
10220 }
10221
10222 NK_INTERN void
10223 nk_tt__hheap_free(struct nk_tt__hheap *hh, void *p)
10224 {
10225 *(void **) p = hh->first_free;
10226 hh->first_free = p;
10227 }
10228
10229 NK_INTERN void
10230 nk_tt__hheap_cleanup(struct nk_tt__hheap *hh)
10231 {
10232 struct nk_tt__hheap_chunk *c = hh->head;
10233 while (c) {
10234 struct nk_tt__hheap_chunk *n = c->next;
10235 hh->alloc.free(hh->alloc.userdata, c);
10236 c = n;
10237 }
10238 }
10239
10240 NK_INTERN struct nk_tt__active_edge*
10241 nk_tt__new_active(struct nk_tt__hheap *hh, struct nk_tt__edge *e,
10242 int off_x, float start_point)
10243 {
10244 struct nk_tt__active_edge *z = (struct nk_tt__active_edge *)
10245 nk_tt__hheap_alloc(hh, sizeof(*z));
10246 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
10247 /*STBTT_assert(e->y0 <= start_point); */
10248 if (!z) return z;
10249 z->fdx = dxdy;
10250 z->fdy = (dxdy != 0) ? (1/dxdy): 0;
10251 z->fx = e->x0 + dxdy * (start_point - e->y0);
10252 z->fx -= (float)off_x;
10253 z->direction = e->invert ? 1.0f : -1.0f;
10254 z->sy = e->y0;
10255 z->ey = e->y1;
10256 z->next = 0;
10257 return z;
10258 }
10259
10260 NK_INTERN void
10261 nk_tt__handle_clipped_edge(float *scanline, int x, struct nk_tt__active_edge *e,
10262 float x0, float y0, float x1, float y1)
10263 {
10264 if (y0 == y1) return;
10265 NK_ASSERT(y0 < y1);
10266 NK_ASSERT(e->sy <= e->ey);
10267 if (y0 > e->ey) return;
10268 if (y1 < e->sy) return;
10269 if (y0 < e->sy) {
10270 x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
10271 y0 = e->sy;
10272 }
10273 if (y1 > e->ey) {
10274 x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
10275 y1 = e->ey;
10276 }
10277
10278 if (x0 == x) NK_ASSERT(x1 <= x+1);
10279 else if (x0 == x+1) NK_ASSERT(x1 >= x);
10280 else if (x0 <= x) NK_ASSERT(x1 <= x);
10281 else if (x0 >= x+1) NK_ASSERT(x1 >= x+1);
10282 else NK_ASSERT(x1 >= x && x1 <= x+1);
10283
10284 if (x0 <= x && x1 <= x)
10285 scanline[x] += e->direction * (y1-y0);
10286 else if (x0 >= x+1 && x1 >= x+1);
10287 else {
10288 NK_ASSERT(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
10289 /* coverage = 1 - average x position */
10290 scanline[x] += (float)e->direction * (float)(y1-y0) * (1.0f-((x0-(float)x)+(x1-(float)x))/2.0f);
10291 }
10292 }
10293
10294 NK_INTERN void
10295 nk_tt__fill_active_edges_new(float *scanline, float *scanline_fill, int len,
10296 struct nk_tt__active_edge *e, float y_top)
10297 {
10298 float y_bottom = y_top+1;
10299 while (e)
10300 {
10301 /* brute force every pixel */
10302 /* compute intersection points with top & bottom */
10303 NK_ASSERT(e->ey >= y_top);
10304 if (e->fdx == 0) {
10305 float x0 = e->fx;
10306 if (x0 < len) {
10307 if (x0 >= 0) {
10308 nk_tt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
10309 nk_tt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
10310 } else {
10311 nk_tt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
10312 }
10313 }
10314 } else {
10315 float x0 = e->fx;
10316 float dx = e->fdx;
10317 float xb = x0 + dx;
10318 float x_top, x_bottom;
10319 float y0,y1;
10320 float dy = e->fdy;
10321 NK_ASSERT(e->sy <= y_bottom && e->ey >= y_top);
10322
10323 /* compute endpoints of line segment clipped to this scanline (if the */
10324 /* line segment starts on this scanline. x0 is the intersection of the */
10325 /* line with y_top, but that may be off the line segment. */
10326 if (e->sy > y_top) {
10327 x_top = x0 + dx * (e->sy - y_top);
10328 y0 = e->sy;
10329 } else {
10330 x_top = x0;
10331 y0 = y_top;
10332 }
10333
10334 if (e->ey < y_bottom) {
10335 x_bottom = x0 + dx * (e->ey - y_top);
10336 y1 = e->ey;
10337 } else {
10338 x_bottom = xb;
10339 y1 = y_bottom;
10340 }
10341
10342 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len)
10343 {
10344 /* from here on, we don't have to range check x values */
10345 if ((int) x_top == (int) x_bottom) {
10346 float height;
10347 /* simple case, only spans one pixel */
10348 int x = (int) x_top;
10349 height = y1 - y0;
10350 NK_ASSERT(x >= 0 && x < len);
10351 scanline[x] += e->direction * (1.0f-(((float)x_top - (float)x) + ((float)x_bottom-(float)x))/2.0f) * (float)height;
10352 scanline_fill[x] += e->direction * (float)height; /* everything right of this pixel is filled */
10353 } else {
10354 int x,x1,x2;
10355 float y_crossing, step, sign, area;
10356 /* covers 2+ pixels */
10357 if (x_top > x_bottom)
10358 {
10359 /* flip scanline vertically; signed area is the same */
10360 float t;
10361 y0 = y_bottom - (y0 - y_top);
10362 y1 = y_bottom - (y1 - y_top);
10363 t = y0; y0 = y1; y1 = t;
10364 t = x_bottom; x_bottom = x_top; x_top = t;
10365 dx = -dx;
10366 dy = -dy;
10367 t = x0; x0 = xb; xb = t;
10368 }
10369
10370 x1 = (int) x_top;
10371 x2 = (int) x_bottom;
10372 /* compute intersection with y axis at x1+1 */
10373 y_crossing = ((float)x1+1 - (float)x0) * (float)dy + (float)y_top;
10374
10375 sign = e->direction;
10376 /* area of the rectangle covered from y0..y_crossing */
10377 area = sign * (y_crossing-y0);
10378 /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */
10379 scanline[x1] += area * (1.0f-((float)((float)x_top - (float)x1)+(float)(x1+1-x1))/2.0f);
10380
10381 step = sign * dy;
10382 for (x = x1+1; x < x2; ++x) {
10383 scanline[x] += area + step/2;
10384 area += step;
10385 }
10386 y_crossing += (float)dy * (float)(x2 - (x1+1));
10387
10388 scanline[x2] += area + sign * (1.0f-((float)(x2-x2)+((float)x_bottom-(float)x2))/2.0f) * (y1-y_crossing);
10389 scanline_fill[x2] += sign * (y1-y0);
10390 }
10391 }
10392 else
10393 {
10394 /* if edge goes outside of box we're drawing, we require */
10395 /* clipping logic. since this does not match the intended use */
10396 /* of this library, we use a different, very slow brute */
10397 /* force implementation */
10398 int x;
10399 for (x=0; x < len; ++x)
10400 {
10401 /* cases: */
10402 /* */
10403 /* there can be up to two intersections with the pixel. any intersection */
10404 /* with left or right edges can be handled by splitting into two (or three) */
10405 /* regions. intersections with top & bottom do not necessitate case-wise logic. */
10406 /* */
10407 /* the old way of doing this found the intersections with the left & right edges, */
10408 /* then used some simple logic to produce up to three segments in sorted order */
10409 /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */
10410 /* across the x border, then the corresponding y position might not be distinct */
10411 /* from the other y segment, and it might ignored as an empty segment. to avoid */
10412 /* that, we need to explicitly produce segments based on x positions. */
10413
10414 /* rename variables to clear pairs */
10415 float ya = y_top;
10416 float x1 = (float) (x);
10417 float x2 = (float) (x+1);
10418 float x3 = xb;
10419 float y3 = y_bottom;
10420 float yb,y2;
10421
10422 yb = ((float)x - x0) / dx + y_top;
10423 y2 = ((float)x+1 - x0) / dx + y_top;
10424
10425 if (x0 < x1 && x3 > x2) { /* three segments descending down-right */
10426 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
10427 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x2,y2);
10428 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
10429 } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */
10430 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
10431 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x1,yb);
10432 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
10433 } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */
10434 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
10435 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
10436 } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */
10437 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb);
10438 nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3);
10439 } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */
10440 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
10441 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
10442 } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */
10443 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2);
10444 nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
10445 } else { /* one segment */
10446 nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x3,y3);
10447 }
10448 }
10449 }
10450 }
10451 e = e->next;
10452 }
10453 }
10454
10455 /* directly AA rasterize edges w/o supersampling */
10456 NK_INTERN void
10457 nk_tt__rasterize_sorted_edges(struct nk_tt__bitmap *result, struct nk_tt__edge *e,
10458 int n, int vsubsample, int off_x, int off_y, struct nk_allocator *alloc)
10459 {
10460 struct nk_tt__hheap hh;
10461 struct nk_tt__active_edge *active = 0;
10462 int y,j=0, i;
10463 float scanline_data[129], *scanline, *scanline2;
10464
10465 NK_UNUSED(vsubsample);
10466 nk_zero_struct(hh);
10467 hh.alloc = *alloc;
10468
10469 if (result->w > 64)
10470 scanline = (float *) alloc->alloc(alloc->userdata,0, (nk_size)(result->w*2+1) * sizeof(float));
10471 else scanline = scanline_data;
10472
10473 scanline2 = scanline + result->w;
10474 y = off_y;
10475 e[n].y0 = (float) (off_y + result->h) + 1;
10476
10477 while (j < result->h)
10478 {
10479 /* find center of pixel for this scanline */
10480 float scan_y_top = (float)y + 0.0f;
10481 float scan_y_bottom = (float)y + 1.0f;
10482 struct nk_tt__active_edge **step = &active;
10483
10484 NK_MEMSET(scanline , 0, (nk_size)result->w*sizeof(scanline[0]));
10485 NK_MEMSET(scanline2, 0, (nk_size)(result->w+1)*sizeof(scanline[0]));
10486
10487 /* update all active edges; */
10488 /* remove all active edges that terminate before the top of this scanline */
10489 while (*step) {
10490 struct nk_tt__active_edge * z = *step;
10491 if (z->ey <= scan_y_top) {
10492 *step = z->next; /* delete from list */
10493 NK_ASSERT(z->direction);
10494 z->direction = 0;
10495 nk_tt__hheap_free(&hh, z);
10496 } else {
10497 step = &((*step)->next); /* advance through list */
10498 }
10499 }
10500
10501 /* insert all edges that start before the bottom of this scanline */
10502 while (e->y0 <= scan_y_bottom) {
10503 if (e->y0 != e->y1) {
10504 struct nk_tt__active_edge *z = nk_tt__new_active(&hh, e, off_x, scan_y_top);
10505 if (z != 0) {
10506 NK_ASSERT(z->ey >= scan_y_top);
10507 /* insert at front */
10508 z->next = active;
10509 active = z;
10510 }
10511 }
10512 ++e;
10513 }
10514
10515 /* now process all active edges */
10516 if (active)
10517 nk_tt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
10518
10519 {
10520 float sum = 0;
10521 for (i=0; i < result->w; ++i) {
10522 float k;
10523 int m;
10524 sum += scanline2[i];
10525 k = scanline[i] + sum;
10526 k = (float) NK_ABS(k) * 255.0f + 0.5f;
10527 m = (int) k;
10528 if (m > 255) m = 255;
10529 result->pixels[j*result->stride + i] = (unsigned char) m;
10530 }
10531 }
10532 /* advance all the edges */
10533 step = &active;
10534 while (*step) {
10535 struct nk_tt__active_edge *z = *step;
10536 z->fx += z->fdx; /* advance to position for current scanline */
10537 step = &((*step)->next); /* advance through list */
10538 }
10539 ++y;
10540 ++j;
10541 }
10542 nk_tt__hheap_cleanup(&hh);
10543 if (scanline != scanline_data)
10544 alloc->free(alloc->userdata, scanline);
10545 }
10546
10547 #define NK_TT__COMPARE(a,b) ((a)->y0 < (b)->y0)
10548 NK_INTERN void
10549 nk_tt__sort_edges_ins_sort(struct nk_tt__edge *p, int n)
10550 {
10551 int i,j;
10552 for (i=1; i < n; ++i) {
10553 struct nk_tt__edge t = p[i], *a = &t;
10554 j = i;
10555 while (j > 0) {
10556 struct nk_tt__edge *b = &p[j-1];
10557 int c = NK_TT__COMPARE(a,b);
10558 if (!c) break;
10559 p[j] = p[j-1];
10560 --j;
10561 }
10562 if (i != j)
10563 p[j] = t;
10564 }
10565 }
10566
10567 NK_INTERN void
10568 nk_tt__sort_edges_quicksort(struct nk_tt__edge *p, int n)
10569 {
10570 /* threshold for transitioning to insertion sort */
10571 while (n > 12) {
10572 struct nk_tt__edge t;
10573 int c01,c12,c,m,i,j;
10574
10575 /* compute median of three */
10576 m = n >> 1;
10577 c01 = NK_TT__COMPARE(&p[0],&p[m]);
10578 c12 = NK_TT__COMPARE(&p[m],&p[n-1]);
10579
10580 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
10581 if (c01 != c12) {
10582 /* otherwise, we'll need to swap something else to middle */
10583 int z;
10584 c = NK_TT__COMPARE(&p[0],&p[n-1]);
10585 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
10586 /* 0<mid && mid>n: 0>n => 0; 0<n => n */
10587 z = (c == c12) ? 0 : n-1;
10588 t = p[z];
10589 p[z] = p[m];
10590 p[m] = t;
10591 }
10592
10593 /* now p[m] is the median-of-three */
10594 /* swap it to the beginning so it won't move around */
10595 t = p[0];
10596 p[0] = p[m];
10597 p[m] = t;
10598
10599 /* partition loop */
10600 i=1;
10601 j=n-1;
10602 for(;;) {
10603 /* handling of equality is crucial here */
10604 /* for sentinels & efficiency with duplicates */
10605 for (;;++i) {
10606 if (!NK_TT__COMPARE(&p[i], &p[0])) break;
10607 }
10608 for (;;--j) {
10609 if (!NK_TT__COMPARE(&p[0], &p[j])) break;
10610 }
10611
10612 /* make sure we haven't crossed */
10613 if (i >= j) break;
10614 t = p[i];
10615 p[i] = p[j];
10616 p[j] = t;
10617
10618 ++i;
10619 --j;
10620
10621 }
10622
10623 /* recurse on smaller side, iterate on larger */
10624 if (j < (n-i)) {
10625 nk_tt__sort_edges_quicksort(p,j);
10626 p = p+i;
10627 n = n-i;
10628 } else {
10629 nk_tt__sort_edges_quicksort(p+i, n-i);
10630 n = j;
10631 }
10632 }
10633 }
10634
10635 NK_INTERN void
10636 nk_tt__sort_edges(struct nk_tt__edge *p, int n)
10637 {
10638 nk_tt__sort_edges_quicksort(p, n);
10639 nk_tt__sort_edges_ins_sort(p, n);
10640 }
10641
10642 NK_INTERN void
10643 nk_tt__rasterize(struct nk_tt__bitmap *result, struct nk_tt__point *pts,
10644 int *wcount, int windings, float scale_x, float scale_y,
10645 float shift_x, float shift_y, int off_x, int off_y, int invert,
10646 struct nk_allocator *alloc)
10647 {
10648 float y_scale_inv = invert ? -scale_y : scale_y;
10649 struct nk_tt__edge *e;
10650 int n,i,j,k,m;
10651 int vsubsample = 1;
10652 /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */
10653
10654 /* now we have to blow out the windings into explicit edge lists */
10655 n = 0;
10656 for (i=0; i < windings; ++i)
10657 n += wcount[i];
10658
10659 e = (struct nk_tt__edge*)
10660 alloc->alloc(alloc->userdata, 0,(sizeof(*e) * (nk_size)(n+1)));
10661 if (e == 0) return;
10662 n = 0;
10663
10664 m=0;
10665 for (i=0; i < windings; ++i)
10666 {
10667 struct nk_tt__point *p = pts + m;
10668 m += wcount[i];
10669 j = wcount[i]-1;
10670 for (k=0; k < wcount[i]; j=k++) {
10671 int a=k,b=j;
10672 /* skip the edge if horizontal */
10673 if (p[j].y == p[k].y)
10674 continue;
10675
10676 /* add edge from j to k to the list */
10677 e[n].invert = 0;
10678 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
10679 e[n].invert = 1;
10680 a=j,b=k;
10681 }
10682 e[n].x0 = p[a].x * scale_x + shift_x;
10683 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * (float)vsubsample;
10684 e[n].x1 = p[b].x * scale_x + shift_x;
10685 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * (float)vsubsample;
10686 ++n;
10687 }
10688 }
10689
10690 /* now sort the edges by their highest point (should snap to integer, and then by x) */
10691 /*STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */
10692 nk_tt__sort_edges(e, n);
10693 /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */
10694 nk_tt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, alloc);
10695 alloc->free(alloc->userdata, e);
10696 }
10697
10698 NK_INTERN void
10699 nk_tt__add_point(struct nk_tt__point *points, int n, float x, float y)
10700 {
10701 if (!points) return; /* during first pass, it's unallocated */
10702 points[n].x = x;
10703 points[n].y = y;
10704 }
10705
10706 NK_INTERN int
10707 nk_tt__tesselate_curve(struct nk_tt__point *points, int *num_points,
10708 float x0, float y0, float x1, float y1, float x2, float y2,
10709 float objspace_flatness_squared, int n)
10710 {
10711 /* tesselate until threshold p is happy...
10712 * @TODO warped to compensate for non-linear stretching */
10713 /* midpoint */
10714 float mx = (x0 + 2*x1 + x2)/4;
10715 float my = (y0 + 2*y1 + y2)/4;
10716 /* versus directly drawn line */
10717 float dx = (x0+x2)/2 - mx;
10718 float dy = (y0+y2)/2 - my;
10719 if (n > 16) /* 65536 segments on one curve better be enough! */
10720 return 1;
10721
10722 /* half-pixel error allowed... need to be smaller if AA */
10723 if (dx*dx+dy*dy > objspace_flatness_squared) {
10724 nk_tt__tesselate_curve(points, num_points, x0,y0,
10725 (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
10726 nk_tt__tesselate_curve(points, num_points, mx,my,
10727 (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
10728 } else {
10729 nk_tt__add_point(points, *num_points,x2,y2);
10730 *num_points = *num_points+1;
10731 }
10732 return 1;
10733 }
10734
10735 /* returns number of contours */
10736 NK_INTERN struct nk_tt__point*
10737 nk_tt_FlattenCurves(struct nk_tt_vertex *vertices, int num_verts,
10738 float objspace_flatness, int **contour_lengths, int *num_contours,
10739 struct nk_allocator *alloc)
10740 {
10741 struct nk_tt__point *points=0;
10742 int num_points=0;
10743 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
10744 int i;
10745 int n=0;
10746 int start=0;
10747 int pass;
10748
10749 /* count how many "moves" there are to get the contour count */
10750 for (i=0; i < num_verts; ++i)
10751 if (vertices[i].type == NK_TT_vmove) ++n;
10752
10753 *num_contours = n;
10754 if (n == 0) return 0;
10755
10756 *contour_lengths = (int *)
10757 alloc->alloc(alloc->userdata,0, (sizeof(**contour_lengths) * (nk_size)n));
10758 if (*contour_lengths == 0) {
10759 *num_contours = 0;
10760 return 0;
10761 }
10762
10763 /* make two passes through the points so we don't need to realloc */
10764 for (pass=0; pass < 2; ++pass)
10765 {
10766 float x=0,y=0;
10767 if (pass == 1) {
10768 points = (struct nk_tt__point *)
10769 alloc->alloc(alloc->userdata,0, (nk_size)num_points * sizeof(points[0]));
10770 if (points == 0) goto error;
10771 }
10772 num_points = 0;
10773 n= -1;
10774
10775 for (i=0; i < num_verts; ++i)
10776 {
10777 switch (vertices[i].type) {
10778 case NK_TT_vmove:
10779 /* start the next contour */
10780 if (n >= 0)
10781 (*contour_lengths)[n] = num_points - start;
10782 ++n;
10783 start = num_points;
10784
10785 x = vertices[i].x, y = vertices[i].y;
10786 nk_tt__add_point(points, num_points++, x,y);
10787 break;
10788 case NK_TT_vline:
10789 x = vertices[i].x, y = vertices[i].y;
10790 nk_tt__add_point(points, num_points++, x, y);
10791 break;
10792 case NK_TT_vcurve:
10793 nk_tt__tesselate_curve(points, &num_points, x,y,
10794 vertices[i].cx, vertices[i].cy,
10795 vertices[i].x, vertices[i].y,
10796 objspace_flatness_squared, 0);
10797 x = vertices[i].x, y = vertices[i].y;
10798 break;
10799 default: break;
10800 }
10801 }
10802 (*contour_lengths)[n] = num_points - start;
10803 }
10804 return points;
10805
10806 error:
10807 alloc->free(alloc->userdata, points);
10808 alloc->free(alloc->userdata, *contour_lengths);
10809 *contour_lengths = 0;
10810 *num_contours = 0;
10811 return 0;
10812 }
10813
10814 NK_INTERN void
10815 nk_tt_Rasterize(struct nk_tt__bitmap *result, float flatness_in_pixels,
10816 struct nk_tt_vertex *vertices, int num_verts,
10817 float scale_x, float scale_y, float shift_x, float shift_y,
10818 int x_off, int y_off, int invert, struct nk_allocator *alloc)
10819 {
10820 float scale = scale_x > scale_y ? scale_y : scale_x;
10821 int winding_count, *winding_lengths;
10822 struct nk_tt__point *windings = nk_tt_FlattenCurves(vertices, num_verts,
10823 flatness_in_pixels / scale, &winding_lengths, &winding_count, alloc);
10824
10825 NK_ASSERT(alloc);
10826 if (windings) {
10827 nk_tt__rasterize(result, windings, winding_lengths, winding_count,
10828 scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, alloc);
10829 alloc->free(alloc->userdata, winding_lengths);
10830 alloc->free(alloc->userdata, windings);
10831 }
10832 }
10833
10834 NK_INTERN void
10835 nk_tt_MakeGlyphBitmapSubpixel(const struct nk_tt_fontinfo *info, unsigned char *output,
10836 int out_w, int out_h, int out_stride, float scale_x, float scale_y,
10837 float shift_x, float shift_y, int glyph, struct nk_allocator *alloc)
10838 {
10839 int ix0,iy0;
10840 struct nk_tt_vertex *vertices;
10841 int num_verts = nk_tt_GetGlyphShape(info, alloc, glyph, &vertices);
10842 struct nk_tt__bitmap gbm;
10843
10844 nk_tt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x,
10845 shift_y, &ix0,&iy0,0,0);
10846 gbm.pixels = output;
10847 gbm.w = out_w;
10848 gbm.h = out_h;
10849 gbm.stride = out_stride;
10850
10851 if (gbm.w && gbm.h)
10852 nk_tt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y,
10853 shift_x, shift_y, ix0,iy0, 1, alloc);
10854 alloc->free(alloc->userdata, vertices);
10855 }
10856
10857 /*-------------------------------------------------------------
10858 * Bitmap baking
10859 * --------------------------------------------------------------*/
10860 NK_INTERN int
10861 nk_tt_PackBegin(struct nk_tt_pack_context *spc, unsigned char *pixels,
10862 int pw, int ph, int stride_in_bytes, int padding, struct nk_allocator *alloc)
10863 {
10864 int num_nodes = pw - padding;
10865 struct nk_rp_context *context = (struct nk_rp_context *)
10866 alloc->alloc(alloc->userdata,0, sizeof(*context));
10867 struct nk_rp_node *nodes = (struct nk_rp_node*)
10868 alloc->alloc(alloc->userdata,0, (sizeof(*nodes ) * (nk_size)num_nodes));
10869
10870 if (context == 0 || nodes == 0) {
10871 if (context != 0) alloc->free(alloc->userdata, context);
10872 if (nodes != 0) alloc->free(alloc->userdata, nodes);
10873 return 0;
10874 }
10875
10876 spc->width = pw;
10877 spc->height = ph;
10878 spc->pixels = pixels;
10879 spc->pack_info = context;
10880 spc->nodes = nodes;
10881 spc->padding = padding;
10882 spc->stride_in_bytes = (stride_in_bytes != 0) ? stride_in_bytes : pw;
10883 spc->h_oversample = 1;
10884 spc->v_oversample = 1;
10885
10886 nk_rp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
10887 if (pixels)
10888 NK_MEMSET(pixels, 0, (nk_size)(pw*ph)); /* background of 0 around pixels */
10889 return 1;
10890 }
10891
10892 NK_INTERN void
10893 nk_tt_PackEnd(struct nk_tt_pack_context *spc, struct nk_allocator *alloc)
10894 {
10895 alloc->free(alloc->userdata, spc->nodes);
10896 alloc->free(alloc->userdata, spc->pack_info);
10897 }
10898
10899 NK_INTERN void
10900 nk_tt_PackSetOversampling(struct nk_tt_pack_context *spc,
10901 unsigned int h_oversample, unsigned int v_oversample)
10902 {
10903 NK_ASSERT(h_oversample <= NK_TT_MAX_OVERSAMPLE);
10904 NK_ASSERT(v_oversample <= NK_TT_MAX_OVERSAMPLE);
10905 if (h_oversample <= NK_TT_MAX_OVERSAMPLE)
10906 spc->h_oversample = h_oversample;
10907 if (v_oversample <= NK_TT_MAX_OVERSAMPLE)
10908 spc->v_oversample = v_oversample;
10909 }
10910
10911 NK_INTERN void
10912 nk_tt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes,
10913 int kernel_width)
10914 {
10915 unsigned char buffer[NK_TT_MAX_OVERSAMPLE];
10916 int safe_w = w - kernel_width;
10917 int j;
10918
10919 for (j=0; j < h; ++j)
10920 {
10921 int i;
10922 unsigned int total;
10923 NK_MEMSET(buffer, 0, (nk_size)kernel_width);
10924
10925 total = 0;
10926
10927 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
10928 switch (kernel_width) {
10929 case 2:
10930 for (i=0; i <= safe_w; ++i) {
10931 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10932 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10933 pixels[i] = (unsigned char) (total / 2);
10934 }
10935 break;
10936 case 3:
10937 for (i=0; i <= safe_w; ++i) {
10938 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10939 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10940 pixels[i] = (unsigned char) (total / 3);
10941 }
10942 break;
10943 case 4:
10944 for (i=0; i <= safe_w; ++i) {
10945 total += (unsigned int)pixels[i] - buffer[i & NK_TT__OVER_MASK];
10946 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10947 pixels[i] = (unsigned char) (total / 4);
10948 }
10949 break;
10950 case 5:
10951 for (i=0; i <= safe_w; ++i) {
10952 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10953 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10954 pixels[i] = (unsigned char) (total / 5);
10955 }
10956 break;
10957 default:
10958 for (i=0; i <= safe_w; ++i) {
10959 total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]);
10960 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i];
10961 pixels[i] = (unsigned char) (total / (unsigned int)kernel_width);
10962 }
10963 break;
10964 }
10965
10966 for (; i < w; ++i) {
10967 NK_ASSERT(pixels[i] == 0);
10968 total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]);
10969 pixels[i] = (unsigned char) (total / (unsigned int)kernel_width);
10970 }
10971 pixels += stride_in_bytes;
10972 }
10973 }
10974
10975 NK_INTERN void
10976 nk_tt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes,
10977 int kernel_width)
10978 {
10979 unsigned char buffer[NK_TT_MAX_OVERSAMPLE];
10980 int safe_h = h - kernel_width;
10981 int j;
10982
10983 for (j=0; j < w; ++j)
10984 {
10985 int i;
10986 unsigned int total;
10987 NK_MEMSET(buffer, 0, (nk_size)kernel_width);
10988
10989 total = 0;
10990
10991 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
10992 switch (kernel_width) {
10993 case 2:
10994 for (i=0; i <= safe_h; ++i) {
10995 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
10996 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
10997 pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
10998 }
10999 break;
11000 case 3:
11001 for (i=0; i <= safe_h; ++i) {
11002 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
11003 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
11004 pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
11005 }
11006 break;
11007 case 4:
11008 for (i=0; i <= safe_h; ++i) {
11009 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
11010 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
11011 pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
11012 }
11013 break;
11014 case 5:
11015 for (i=0; i <= safe_h; ++i) {
11016 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
11017 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
11018 pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
11019 }
11020 break;
11021 default:
11022 for (i=0; i <= safe_h; ++i) {
11023 total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]);
11024 buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes];
11025 pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width);
11026 }
11027 break;
11028 }
11029
11030 for (; i < h; ++i) {
11031 NK_ASSERT(pixels[i*stride_in_bytes] == 0);
11032 total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]);
11033 pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width);
11034 }
11035 pixels += 1;
11036 }
11037 }
11038
11039 NK_INTERN float
11040 nk_tt__oversample_shift(int oversample)
11041 {
11042 if (!oversample)
11043 return 0.0f;
11044
11045 /* The prefilter is a box filter of width "oversample", */
11046 /* which shifts phase by (oversample - 1)/2 pixels in */
11047 /* oversampled space. We want to shift in the opposite */
11048 /* direction to counter this. */
11049 return (float)-(oversample - 1) / (2.0f * (float)oversample);
11050 }
11051
11052 /* rects array must be big enough to accommodate all characters in the given ranges */
11053 NK_INTERN int
11054 nk_tt_PackFontRangesGatherRects(struct nk_tt_pack_context *spc,
11055 struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges,
11056 int num_ranges, struct nk_rp_rect *rects)
11057 {
11058 int i,j,k;
11059 k = 0;
11060
11061 for (i=0; i < num_ranges; ++i) {
11062 float fh = ranges[i].font_size;
11063 float scale = (fh > 0) ? nk_tt_ScaleForPixelHeight(info, fh):
11064 nk_tt_ScaleForMappingEmToPixels(info, -fh);
11065 ranges[i].h_oversample = (unsigned char) spc->h_oversample;
11066 ranges[i].v_oversample = (unsigned char) spc->v_oversample;
11067 for (j=0; j < ranges[i].num_chars; ++j) {
11068 int x0,y0,x1,y1;
11069 int codepoint = ranges[i].first_unicode_codepoint_in_range ?
11070 ranges[i].first_unicode_codepoint_in_range + j :
11071 ranges[i].array_of_unicode_codepoints[j];
11072
11073 int glyph = nk_tt_FindGlyphIndex(info, codepoint);
11074 nk_tt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * (float)spc->h_oversample,
11075 scale * (float)spc->v_oversample, 0,0, &x0,&y0,&x1,&y1);
11076 rects[k].w = (nk_rp_coord) (x1-x0 + spc->padding + (int)spc->h_oversample-1);
11077 rects[k].h = (nk_rp_coord) (y1-y0 + spc->padding + (int)spc->v_oversample-1);
11078 ++k;
11079 }
11080 }
11081 return k;
11082 }
11083
11084 NK_INTERN int
11085 nk_tt_PackFontRangesRenderIntoRects(struct nk_tt_pack_context *spc,
11086 struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges,
11087 int num_ranges, struct nk_rp_rect *rects, struct nk_allocator *alloc)
11088 {
11089 int i,j,k, return_value = 1;
11090 /* save current values */
11091 int old_h_over = (int)spc->h_oversample;
11092 int old_v_over = (int)spc->v_oversample;
11093 /* rects array must be big enough to accommodate all characters in the given ranges */
11094
11095 k = 0;
11096 for (i=0; i < num_ranges; ++i)
11097 {
11098 float fh = ranges[i].font_size;
11099 float recip_h,recip_v,sub_x,sub_y;
11100 float scale = fh > 0 ? nk_tt_ScaleForPixelHeight(info, fh):
11101 nk_tt_ScaleForMappingEmToPixels(info, -fh);
11102
11103 spc->h_oversample = ranges[i].h_oversample;
11104 spc->v_oversample = ranges[i].v_oversample;
11105
11106 recip_h = 1.0f / (float)spc->h_oversample;
11107 recip_v = 1.0f / (float)spc->v_oversample;
11108
11109 sub_x = nk_tt__oversample_shift((int)spc->h_oversample);
11110 sub_y = nk_tt__oversample_shift((int)spc->v_oversample);
11111
11112 for (j=0; j < ranges[i].num_chars; ++j)
11113 {
11114 struct nk_rp_rect *r = &rects[k];
11115 if (r->was_packed)
11116 {
11117 struct nk_tt_packedchar *bc = &ranges[i].chardata_for_range[j];
11118 int advance, lsb, x0,y0,x1,y1;
11119 int codepoint = ranges[i].first_unicode_codepoint_in_range ?
11120 ranges[i].first_unicode_codepoint_in_range + j :
11121 ranges[i].array_of_unicode_codepoints[j];
11122 int glyph = nk_tt_FindGlyphIndex(info, codepoint);
11123 nk_rp_coord pad = (nk_rp_coord) spc->padding;
11124
11125 /* pad on left and top */
11126 r->x = (nk_rp_coord)((int)r->x + (int)pad);
11127 r->y = (nk_rp_coord)((int)r->y + (int)pad);
11128 r->w = (nk_rp_coord)((int)r->w - (int)pad);
11129 r->h = (nk_rp_coord)((int)r->h - (int)pad);
11130
11131 nk_tt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
11132 nk_tt_GetGlyphBitmapBox(info, glyph, scale * (float)spc->h_oversample,
11133 (scale * (float)spc->v_oversample), &x0,&y0,&x1,&y1);
11134 nk_tt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y*spc->stride_in_bytes,
11135 (int)(r->w - spc->h_oversample+1), (int)(r->h - spc->v_oversample+1),
11136 spc->stride_in_bytes, scale * (float)spc->h_oversample,
11137 scale * (float)spc->v_oversample, 0,0, glyph, alloc);
11138
11139 if (spc->h_oversample > 1)
11140 nk_tt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
11141 r->w, r->h, spc->stride_in_bytes, (int)spc->h_oversample);
11142
11143 if (spc->v_oversample > 1)
11144 nk_tt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
11145 r->w, r->h, spc->stride_in_bytes, (int)spc->v_oversample);
11146
11147 bc->x0 = (nk_ushort) r->x;
11148 bc->y0 = (nk_ushort) r->y;
11149 bc->x1 = (nk_ushort) (r->x + r->w);
11150 bc->y1 = (nk_ushort) (r->y + r->h);
11151 bc->xadvance = scale * (float)advance;
11152 bc->xoff = (float) x0 * recip_h + sub_x;
11153 bc->yoff = (float) y0 * recip_v + sub_y;
11154 bc->xoff2 = ((float)x0 + r->w) * recip_h + sub_x;
11155 bc->yoff2 = ((float)y0 + r->h) * recip_v + sub_y;
11156 } else {
11157 return_value = 0; /* if any fail, report failure */
11158 }
11159 ++k;
11160 }
11161 }
11162 /* restore original values */
11163 spc->h_oversample = (unsigned int)old_h_over;
11164 spc->v_oversample = (unsigned int)old_v_over;
11165 return return_value;
11166 }
11167
11168 NK_INTERN void
11169 nk_tt_GetPackedQuad(struct nk_tt_packedchar *chardata, int pw, int ph,
11170 int char_index, float *xpos, float *ypos, struct nk_tt_aligned_quad *q,
11171 int align_to_integer)
11172 {
11173 float ipw = 1.0f / (float)pw, iph = 1.0f / (float)ph;
11174 struct nk_tt_packedchar *b = (struct nk_tt_packedchar*)(chardata + char_index);
11175 if (align_to_integer) {
11176 int tx = nk_ifloorf((*xpos + b->xoff) + 0.5f);
11177 int ty = nk_ifloorf((*ypos + b->yoff) + 0.5f);
11178
11179 float x = (float)tx;
11180 float y = (float)ty;
11181
11182 q->x0 = x;
11183 q->y0 = y;
11184 q->x1 = x + b->xoff2 - b->xoff;
11185 q->y1 = y + b->yoff2 - b->yoff;
11186 } else {
11187 q->x0 = *xpos + b->xoff;
11188 q->y0 = *ypos + b->yoff;
11189 q->x1 = *xpos + b->xoff2;
11190 q->y1 = *ypos + b->yoff2;
11191 }
11192 q->s0 = b->x0 * ipw;
11193 q->t0 = b->y0 * iph;
11194 q->s1 = b->x1 * ipw;
11195 q->t1 = b->y1 * iph;
11196 *xpos += b->xadvance;
11197 }
11198
11199 /* -------------------------------------------------------------
11200 *
11201 * FONT BAKING
11202 *
11203 * --------------------------------------------------------------*/
11204 struct nk_font_bake_data {
11205 struct nk_tt_fontinfo info;
11206 struct nk_rp_rect *rects;
11207 struct nk_tt_pack_range *ranges;
11208 nk_rune range_count;
11209 };
11210
11211 struct nk_font_baker {
11212 struct nk_allocator alloc;
11213 struct nk_tt_pack_context spc;
11214 struct nk_font_bake_data *build;
11215 struct nk_tt_packedchar *packed_chars;
11216 struct nk_rp_rect *rects;
11217 struct nk_tt_pack_range *ranges;
11218 };
11219
11220 NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct nk_rp_rect);
11221 NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(struct nk_tt_pack_range);
11222 NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(struct nk_tt_packedchar);
11223 NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data);
11224 NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker);
11225
11226 NK_INTERN int
11227 nk_range_count(const nk_rune *range)
11228 {
11229 const nk_rune *iter = range;
11230 NK_ASSERT(range);
11231 if (!range) return 0;
11232 while (*(iter++) != 0);
11233 return (iter == range) ? 0 : (int)((iter - range)/2);
11234 }
11235
11236 NK_INTERN int
11237 nk_range_glyph_count(const nk_rune *range, int count)
11238 {
11239 int i = 0;
11240 int total_glyphs = 0;
11241 for (i = 0; i < count; ++i) {
11242 int diff;
11243 nk_rune f = range[(i*2)+0];
11244 nk_rune t = range[(i*2)+1];
11245 NK_ASSERT(t >= f);
11246 diff = (int)((t - f) + 1);
11247 total_glyphs += diff;
11248 }
11249 return total_glyphs;
11250 }
11251
11252 NK_API const nk_rune*
11253 nk_font_default_glyph_ranges(void)
11254 {
11255 NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0};
11256 return ranges;
11257 }
11258
11259 NK_API const nk_rune*
11260 nk_font_chinese_glyph_ranges(void)
11261 {
11262 NK_STORAGE const nk_rune ranges[] = {
11263 0x0020, 0x00FF,
11264 0x3000, 0x30FF,
11265 0x31F0, 0x31FF,
11266 0xFF00, 0xFFEF,
11267 0x4e00, 0x9FAF,
11268 0
11269 };
11270 return ranges;
11271 }
11272
11273 NK_API const nk_rune*
11274 nk_font_cyrillic_glyph_ranges(void)
11275 {
11276 NK_STORAGE const nk_rune ranges[] = {
11277 0x0020, 0x00FF,
11278 0x0400, 0x052F,
11279 0x2DE0, 0x2DFF,
11280 0xA640, 0xA69F,
11281 0
11282 };
11283 return ranges;
11284 }
11285
11286 NK_API const nk_rune*
11287 nk_font_korean_glyph_ranges(void)
11288 {
11289 NK_STORAGE const nk_rune ranges[] = {
11290 0x0020, 0x00FF,
11291 0x3131, 0x3163,
11292 0xAC00, 0xD79D,
11293 0
11294 };
11295 return ranges;
11296 }
11297
11298 NK_INTERN void
11299 nk_font_baker_memory(nk_size *temp, int *glyph_count,
11300 struct nk_font_config *config_list, int count)
11301 {
11302 int range_count = 0;
11303 int total_range_count = 0;
11304 struct nk_font_config *iter;
11305
11306 NK_ASSERT(config_list);
11307 NK_ASSERT(glyph_count);
11308 if (!config_list) {
11309 *temp = 0;
11310 *glyph_count = 0;
11311 return;
11312 }
11313
11314 *glyph_count = 0;
11315 if (!config_list->range)
11316 config_list->range = nk_font_default_glyph_ranges();
11317 for (iter = config_list; iter; iter = iter->next) {
11318 range_count = nk_range_count(iter->range);
11319 total_range_count += range_count;
11320 *glyph_count += nk_range_glyph_count(iter->range, range_count);
11321 }
11322
11323 *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect);
11324 *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range);
11325 *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar);
11326 *temp += (nk_size)count * sizeof(struct nk_font_bake_data);
11327 *temp += sizeof(struct nk_font_baker);
11328 *temp += nk_rect_align + nk_range_align + nk_char_align;
11329 *temp += nk_build_align + nk_baker_align;
11330 }
11331
11332 NK_INTERN struct nk_font_baker*
11333 nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc)
11334 {
11335 struct nk_font_baker *baker;
11336 if (!memory) return 0;
11337 /* setup baker inside a memory block */
11338 baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align);
11339 baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align);
11340 baker->packed_chars = (struct nk_tt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align);
11341 baker->rects = (struct nk_rp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align);
11342 baker->ranges = (struct nk_tt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align);
11343 baker->alloc = *alloc;
11344 return baker;
11345 }
11346
11347 NK_INTERN int
11348 nk_font_bake_pack(struct nk_font_baker *baker,
11349 nk_size *image_memory, int *width, int *height, struct nk_recti *custom,
11350 const struct nk_font_config *config_list, int count,
11351 struct nk_allocator *alloc)
11352 {
11353 NK_STORAGE const nk_size max_height = 1024 * 32;
11354 const struct nk_font_config *config_iter;
11355 int total_glyph_count = 0;
11356 int total_range_count = 0;
11357 int range_count = 0;
11358 int i = 0;
11359
11360 NK_ASSERT(image_memory);
11361 NK_ASSERT(width);
11362 NK_ASSERT(height);
11363 NK_ASSERT(config_list);
11364 NK_ASSERT(count);
11365 NK_ASSERT(alloc);
11366
11367 if (!image_memory || !width || !height || !config_list || !count) return nk_false;
11368 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
11369 range_count = nk_range_count(config_iter->range);
11370 total_range_count += range_count;
11371 total_glyph_count += nk_range_glyph_count(config_iter->range, range_count);
11372 }
11373
11374 /* setup font baker from temporary memory */
11375 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
11376 const struct nk_font_config *cfg = config_iter;
11377 if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)cfg->ttf_blob, 0))
11378 return nk_false;
11379 }
11380
11381 *height = 0;
11382 *width = (total_glyph_count > 1000) ? 1024 : 512;
11383 nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc);
11384 {
11385 int input_i = 0;
11386 int range_n = 0;
11387 int rect_n = 0;
11388 int char_n = 0;
11389
11390 if (custom) {
11391 /* pack custom user data first so it will be in the upper left corner*/
11392 struct nk_rp_rect custom_space;
11393 nk_zero(&custom_space, sizeof(custom_space));
11394 custom_space.w = (nk_rp_coord)((custom->w * 2) + 1);
11395 custom_space.h = (nk_rp_coord)(custom->h + 1);
11396
11397 nk_tt_PackSetOversampling(&baker->spc, 1, 1);
11398 nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, &custom_space, 1);
11399 *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h));
11400
11401 custom->x = (short)custom_space.x;
11402 custom->y = (short)custom_space.y;
11403 custom->w = (short)custom_space.w;
11404 custom->h = (short)custom_space.h;
11405 }
11406
11407 /* first font pass: pack all glyphs */
11408 for (input_i = 0, config_iter = config_list; input_i < count && config_iter;
11409 input_i++, config_iter = config_iter->next)
11410 {
11411 int n = 0;
11412 int glyph_count;
11413 const nk_rune *in_range;
11414 const struct nk_font_config *cfg = config_iter;
11415 struct nk_font_bake_data *tmp = &baker->build[input_i];
11416
11417 /* count glyphs + ranges in current font */
11418 glyph_count = 0; range_count = 0;
11419 for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) {
11420 glyph_count += (int)(in_range[1] - in_range[0]) + 1;
11421 range_count++;
11422 }
11423
11424 /* setup ranges */
11425 tmp->ranges = baker->ranges + range_n;
11426 tmp->range_count = (nk_rune)range_count;
11427 range_n += range_count;
11428 for (i = 0; i < range_count; ++i) {
11429 in_range = &cfg->range[i * 2];
11430 tmp->ranges[i].font_size = cfg->size;
11431 tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0];
11432 tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1;
11433 tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n;
11434 char_n += tmp->ranges[i].num_chars;
11435 }
11436
11437 /* pack */
11438 tmp->rects = baker->rects + rect_n;
11439 rect_n += glyph_count;
11440 nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
11441 n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info,
11442 tmp->ranges, (int)tmp->range_count, tmp->rects);
11443 nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n);
11444
11445 /* texture height */
11446 for (i = 0; i < n; ++i) {
11447 if (tmp->rects[i].was_packed)
11448 *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h);
11449 }
11450 }
11451 NK_ASSERT(rect_n == total_glyph_count);
11452 NK_ASSERT(char_n == total_glyph_count);
11453 NK_ASSERT(range_n == total_range_count);
11454 }
11455 *height = (int)nk_round_up_pow2((nk_uint)*height);
11456 *image_memory = (nk_size)(*width) * (nk_size)(*height);
11457 return nk_true;
11458 }
11459
11460 NK_INTERN void
11461 nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height,
11462 struct nk_font_glyph *glyphs, int glyphs_count,
11463 const struct nk_font_config *config_list, int font_count)
11464 {
11465 int input_i = 0;
11466 nk_rune glyph_n = 0;
11467 const struct nk_font_config *config_iter;
11468
11469 NK_ASSERT(image_memory);
11470 NK_ASSERT(width);
11471 NK_ASSERT(height);
11472 NK_ASSERT(config_list);
11473 NK_ASSERT(baker);
11474 NK_ASSERT(font_count);
11475 NK_ASSERT(glyphs_count);
11476 if (!image_memory || !width || !height || !config_list ||
11477 !font_count || !glyphs || !glyphs_count)
11478 return;
11479
11480 /* second font pass: render glyphs */
11481 nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height));
11482 baker->spc.pixels = (unsigned char*)image_memory;
11483 baker->spc.height = (int)height;
11484 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
11485 ++input_i, config_iter = config_iter->next)
11486 {
11487 const struct nk_font_config *cfg = config_iter;
11488 struct nk_font_bake_data *tmp = &baker->build[input_i];
11489 nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
11490 nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges,
11491 (int)tmp->range_count, tmp->rects, &baker->alloc);
11492 }
11493 nk_tt_PackEnd(&baker->spc, &baker->alloc);
11494
11495 /* third pass: setup font and glyphs */
11496 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
11497 ++input_i, config_iter = config_iter->next)
11498 {
11499 nk_size i = 0;
11500 int char_idx = 0;
11501 nk_rune glyph_count = 0;
11502 const struct nk_font_config *cfg = config_iter;
11503 struct nk_font_bake_data *tmp = &baker->build[input_i];
11504 struct nk_baked_font *dst_font = cfg->font;
11505
11506 float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size);
11507 int unscaled_ascent, unscaled_descent, unscaled_line_gap;
11508 nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent,
11509 &unscaled_line_gap);
11510
11511 /* fill baked font */
11512 if (!cfg->merge_mode) {
11513 dst_font->ranges = cfg->range;
11514 dst_font->height = cfg->size;
11515 dst_font->ascent = ((float)unscaled_ascent * font_scale);
11516 dst_font->descent = ((float)unscaled_descent * font_scale);
11517 dst_font->glyph_offset = glyph_n;
11518 }
11519
11520 /* fill own baked font glyph array */
11521 for (i = 0; i < tmp->range_count; ++i)
11522 {
11523 struct nk_tt_pack_range *range = &tmp->ranges[i];
11524 for (char_idx = 0; char_idx < range->num_chars; char_idx++)
11525 {
11526 nk_rune codepoint = 0;
11527 float dummy_x = 0, dummy_y = 0;
11528 struct nk_tt_aligned_quad q;
11529 struct nk_font_glyph *glyph;
11530
11531 /* query glyph bounds from stb_truetype */
11532 const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx];
11533 if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue;
11534 codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx);
11535 nk_tt_GetPackedQuad(range->chardata_for_range, (int)width,
11536 (int)height, char_idx, &dummy_x, &dummy_y, &q, 0);
11537
11538 /* fill own glyph type with data */
11539 glyph = &glyphs[dst_font->glyph_offset + (unsigned int)glyph_count];
11540 glyph->codepoint = codepoint;
11541 glyph->x0 = q.x0; glyph->y0 = q.y0;
11542 glyph->x1 = q.x1; glyph->y1 = q.y1;
11543 glyph->y0 += (dst_font->ascent + 0.5f);
11544 glyph->y1 += (dst_font->ascent + 0.5f);
11545 glyph->w = glyph->x1 - glyph->x0 + 0.5f;
11546 glyph->h = glyph->y1 - glyph->y0;
11547
11548 if (cfg->coord_type == NK_COORD_PIXEL) {
11549 glyph->u0 = q.s0 * (float)width;
11550 glyph->v0 = q.t0 * (float)height;
11551 glyph->u1 = q.s1 * (float)width;
11552 glyph->v1 = q.t1 * (float)height;
11553 } else {
11554 glyph->u0 = q.s0;
11555 glyph->v0 = q.t0;
11556 glyph->u1 = q.s1;
11557 glyph->v1 = q.t1;
11558 }
11559 glyph->xadvance = (pc->xadvance + cfg->spacing.x);
11560 if (cfg->pixel_snap)
11561 glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f);
11562 glyph_count++;
11563 }
11564 }
11565 dst_font->glyph_count = glyph_count;
11566 glyph_n += dst_font->glyph_count;
11567 }
11568 }
11569
11570 NK_INTERN void
11571 nk_font_bake_custom_data(void *img_memory, int img_width, int img_height,
11572 struct nk_recti img_dst, const char *texture_data_mask, int tex_width,
11573 int tex_height, char white, char black)
11574 {
11575 nk_byte *pixels;
11576 int y = 0;
11577 int x = 0;
11578 int n = 0;
11579
11580 NK_ASSERT(img_memory);
11581 NK_ASSERT(img_width);
11582 NK_ASSERT(img_height);
11583 NK_ASSERT(texture_data_mask);
11584 NK_UNUSED(tex_height);
11585 if (!img_memory || !img_width || !img_height || !texture_data_mask)
11586 return;
11587
11588 pixels = (nk_byte*)img_memory;
11589 for (y = 0, n = 0; y < tex_height; ++y) {
11590 for (x = 0; x < tex_width; ++x, ++n) {
11591 const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width);
11592 const int off1 = off0 + 1 + tex_width;
11593 pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00;
11594 pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00;
11595 }
11596 }
11597 }
11598
11599 NK_INTERN void
11600 nk_font_bake_convert(void *out_memory, int img_width, int img_height,
11601 const void *in_memory)
11602 {
11603 int n = 0;
11604 nk_rune *dst;
11605 const nk_byte *src;
11606
11607 NK_ASSERT(out_memory);
11608 NK_ASSERT(in_memory);
11609 NK_ASSERT(img_width);
11610 NK_ASSERT(img_height);
11611 if (!out_memory || !in_memory || !img_height || !img_width) return;
11612
11613 dst = (nk_rune*)out_memory;
11614 src = (const nk_byte*)in_memory;
11615 for (n = (int)(img_width * img_height); n > 0; n--)
11616 *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF;
11617 }
11618
11619 /* -------------------------------------------------------------
11620 *
11621 * FONT
11622 *
11623 * --------------------------------------------------------------*/
11624 NK_INTERN float
11625 nk_font_text_width(nk_handle handle, float height, const char *text, int len)
11626 {
11627 nk_rune unicode;
11628 int text_len = 0;
11629 float text_width = 0;
11630 int glyph_len = 0;
11631 float scale = 0;
11632
11633 struct nk_font *font = (struct nk_font*)handle.ptr;
11634 NK_ASSERT(font);
11635 NK_ASSERT(font->glyphs);
11636 if (!font || !text || !len)
11637 return 0;
11638
11639 scale = height/font->info.height;
11640 glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len);
11641 if (!glyph_len) return 0;
11642 while (text_len <= (int)len && glyph_len) {
11643 const struct nk_font_glyph *g;
11644 if (unicode == NK_UTF_INVALID) break;
11645
11646 /* query currently drawn glyph information */
11647 g = nk_font_find_glyph(font, unicode);
11648 text_width += g->xadvance * scale;
11649
11650 /* offset next glyph */
11651 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len);
11652 text_len += glyph_len;
11653 }
11654 return text_width;
11655 }
11656
11657 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
11658 NK_INTERN void
11659 nk_font_query_font_glyph(nk_handle handle, float height,
11660 struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
11661 {
11662 float scale;
11663 const struct nk_font_glyph *g;
11664 struct nk_font *font;
11665
11666 NK_ASSERT(glyph);
11667 NK_UNUSED(next_codepoint);
11668
11669 font = (struct nk_font*)handle.ptr;
11670 NK_ASSERT(font);
11671 NK_ASSERT(font->glyphs);
11672 if (!font || !glyph)
11673 return;
11674
11675 scale = height/font->info.height;
11676 g = nk_font_find_glyph(font, codepoint);
11677 glyph->width = (g->x1 - g->x0) * scale;
11678 glyph->height = (g->y1 - g->y0) * scale;
11679 glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);
11680 glyph->xadvance = (g->xadvance * scale);
11681 glyph->uv[0] = nk_vec2(g->u0, g->v0);
11682 glyph->uv[1] = nk_vec2(g->u1, g->v1);
11683 }
11684 #endif
11685
11686 NK_API const struct nk_font_glyph*
11687 nk_font_find_glyph(struct nk_font *font, nk_rune unicode)
11688 {
11689 int i = 0;
11690 int count;
11691 int total_glyphs = 0;
11692 const struct nk_font_glyph *glyph = 0;
11693
11694 NK_ASSERT(font);
11695 NK_ASSERT(font->glyphs);
11696 NK_ASSERT(font->info.ranges);
11697 if (!font || !font->glyphs) return 0;
11698
11699 glyph = font->fallback;
11700 count = nk_range_count(font->info.ranges);
11701 for (i = 0; i < count; ++i) {
11702 nk_rune f = font->info.ranges[(i*2)+0];
11703 nk_rune t = font->info.ranges[(i*2)+1];
11704 int diff = (int)((t - f) + 1);
11705 if (unicode >= f && unicode <= t)
11706 return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))];
11707 total_glyphs += diff;
11708 }
11709 return glyph;
11710 }
11711
11712 NK_INTERN void
11713 nk_font_init(struct nk_font *font, float pixel_height,
11714 nk_rune fallback_codepoint, struct nk_font_glyph *glyphs,
11715 const struct nk_baked_font *baked_font, nk_handle atlas)
11716 {
11717 struct nk_baked_font baked;
11718 NK_ASSERT(font);
11719 NK_ASSERT(glyphs);
11720 NK_ASSERT(baked_font);
11721 if (!font || !glyphs || !baked_font)
11722 return;
11723
11724 baked = *baked_font;
11725 font->fallback = 0;
11726 font->info = baked;
11727 font->scale = (float)pixel_height / (float)font->info.height;
11728 font->glyphs = &glyphs[baked_font->glyph_offset];
11729 font->texture = atlas;
11730 font->fallback_codepoint = fallback_codepoint;
11731 font->fallback = nk_font_find_glyph(font, fallback_codepoint);
11732
11733 font->handle.height = font->info.height * font->scale;
11734 font->handle.width = nk_font_text_width;
11735 font->handle.userdata.ptr = font;
11736 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
11737 font->handle.query = nk_font_query_font_glyph;
11738 font->handle.texture = font->texture;
11739 #endif
11740 }
11741
11742 /* ---------------------------------------------------------------------------
11743 *
11744 * DEFAULT FONT
11745 *
11746 * ProggyClean.ttf
11747 * Copyright (c) 2004, 2005 Tristan Grimmer
11748 * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
11749 * Download and more information at http://upperbounds.net
11750 *-----------------------------------------------------------------------------*/
11751 #ifdef NK_INCLUDE_DEFAULT_FONT
11752
11753 #ifdef __clang__
11754 #pragma clang diagnostic push
11755
11756 #pragma clang diagnostic ignored "-Woverlength-strings"
11757 #elif defined(__GNUC__) || defined(__GNUG__)
11758 #pragma GCC diagnostic push
11759 #pragma GCC diagnostic ignored "-Woverlength-strings"
11760 #endif
11761
11762 NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] =
11763 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
11764 "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"
11765 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
11766 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
11767 "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
11768 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
11769 "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"
11770 "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."
11771 "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"
11772 "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"
11773 "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"
11774 "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"
11775 "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"
11776 "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"
11777 "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"
11778 "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"
11779 "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("
11780 "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"
11781 "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
11782 "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"
11783 "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"
11784 "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"
11785 "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"
11786 "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"
11787 "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"
11788 "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"
11789 "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("
11790 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
11791 "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"
11792 "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"
11793 ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"
11794 "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("
11795 "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"
11796 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
11797 "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"
11798 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i"
11799 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
11800 ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"
11801 "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"
11802 "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"
11803 "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"
11804 "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"
11805 "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"
11806 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
11807 "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"
11808 "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"
11809 ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"
11810 "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"
11811 "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"
11812 ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"
11813 "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"
11814 "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"
11815 "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"
11816 ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"
11817 "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"
11818 "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"
11819 "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"
11820 "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"
11821 "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"
11822 "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"
11823 "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"
11824 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
11825 "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"
11826 "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"
11827 "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"
11828 "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"
11829 "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"
11830 "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"
11831 ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"
11832 "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"
11833 "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"
11834 "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"
11835 "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"
11836 "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"
11837 "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"
11838 "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"
11839 "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"
11840 ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"
11841 "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"
11842 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
11843 "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"
11844 "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"
11845 "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"
11846 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
11847 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
11848 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
11849 #endif /* NK_INCLUDE_DEFAULT_FONT */
11850
11851 #define NK_CURSOR_DATA_W 90
11852 #define NK_CURSOR_DATA_H 27
11853 NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] =
11854 {
11855 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
11856 "..- -X.....X- X.X - X.X -X.....X - X.....X"
11857 "--- -XXX.XXX- X...X - X...X -X....X - X....X"
11858 "X - X.X - X.....X - X.....X -X...X - X...X"
11859 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
11860 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
11861 "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
11862 "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
11863 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
11864 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
11865 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
11866 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
11867 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
11868 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
11869 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
11870 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
11871 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
11872 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
11873 "X.X X..X - -X.......X- X.......X - XX XX - "
11874 "XX X..X - - X.....X - X.....X - X.X X.X - "
11875 " X..X - X...X - X...X - X..X X..X - "
11876 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
11877 "------------ - X - X -X.....................X- "
11878 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
11879 " - X..X X..X - "
11880 " - X.X X.X - "
11881 " - XX XX - "
11882 };
11883
11884 #ifdef __clang__
11885 #pragma clang diagnostic pop
11886 #elif defined(__GNUC__) || defined(__GNUG__)
11887 #pragma GCC diagnostic pop
11888 #endif
11889
11890 NK_INTERN unsigned int
11891 nk_decompress_length(unsigned char *input)
11892 {
11893 return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]);
11894 }
11895
11896 NK_GLOBAL unsigned char *nk__barrier;
11897 NK_GLOBAL unsigned char *nk__barrier2;
11898 NK_GLOBAL unsigned char *nk__barrier3;
11899 NK_GLOBAL unsigned char *nk__barrier4;
11900 NK_GLOBAL unsigned char *nk__dout;
11901
11902 NK_INTERN void
11903 nk__match(unsigned char *data, unsigned int length)
11904 {
11905 /* INVERSE of memmove... write each byte before copying the next...*/
11906 NK_ASSERT (nk__dout + length <= nk__barrier);
11907 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
11908 if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; }
11909 while (length--) *nk__dout++ = *data++;
11910 }
11911
11912 NK_INTERN void
11913 nk__lit(unsigned char *data, unsigned int length)
11914 {
11915 NK_ASSERT (nk__dout + length <= nk__barrier);
11916 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
11917 if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; }
11918 NK_MEMCPY(nk__dout, data, length);
11919 nk__dout += length;
11920 }
11921
11922 #define nk__in2(x) ((i[x] << 8) + i[(x)+1])
11923 #define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1))
11924 #define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1))
11925
11926 NK_INTERN unsigned char*
11927 nk_decompress_token(unsigned char *i)
11928 {
11929 if (*i >= 0x20) { /* use fewer if's for cases that expand small */
11930 if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2;
11931 else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3;
11932 else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
11933 } else { /* more ifs for cases that expand large, since overhead is amortized */
11934 if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4;
11935 else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5;
11936 else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1);
11937 else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1);
11938 else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5;
11939 else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6;
11940 }
11941 return i;
11942 }
11943
11944 NK_INTERN unsigned int
11945 nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
11946 {
11947 const unsigned long ADLER_MOD = 65521;
11948 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
11949 unsigned long blocklen, i;
11950
11951 blocklen = buflen % 5552;
11952 while (buflen) {
11953 for (i=0; i + 7 < blocklen; i += 8) {
11954 s1 += buffer[0]; s2 += s1;
11955 s1 += buffer[1]; s2 += s1;
11956 s1 += buffer[2]; s2 += s1;
11957 s1 += buffer[3]; s2 += s1;
11958 s1 += buffer[4]; s2 += s1;
11959 s1 += buffer[5]; s2 += s1;
11960 s1 += buffer[6]; s2 += s1;
11961 s1 += buffer[7]; s2 += s1;
11962 buffer += 8;
11963 }
11964 for (; i < blocklen; ++i) {
11965 s1 += *buffer++; s2 += s1;
11966 }
11967
11968 s1 %= ADLER_MOD; s2 %= ADLER_MOD;
11969 buflen -= (unsigned int)blocklen;
11970 blocklen = 5552;
11971 }
11972 return (unsigned int)(s2 << 16) + (unsigned int)s1;
11973 }
11974
11975 NK_INTERN unsigned int
11976 nk_decompress(unsigned char *output, unsigned char *i, unsigned int length)
11977 {
11978 unsigned int olen;
11979 if (nk__in4(0) != 0x57bC0000) return 0;
11980 if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */
11981 olen = nk_decompress_length(i);
11982 nk__barrier2 = i;
11983 nk__barrier3 = i+length;
11984 nk__barrier = output + olen;
11985 nk__barrier4 = output;
11986 i += 16;
11987
11988 nk__dout = output;
11989 for (;;) {
11990 unsigned char *old_i = i;
11991 i = nk_decompress_token(i);
11992 if (i == old_i) {
11993 if (*i == 0x05 && i[1] == 0xfa) {
11994 NK_ASSERT(nk__dout == output + olen);
11995 if (nk__dout != output + olen) return 0;
11996 if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2))
11997 return 0;
11998 return olen;
11999 } else {
12000 NK_ASSERT(0); /* NOTREACHED */
12001 return 0;
12002 }
12003 }
12004 NK_ASSERT(nk__dout <= output + olen);
12005 if (nk__dout > output + olen)
12006 return 0;
12007 }
12008 }
12009
12010 NK_INTERN unsigned int
12011 nk_decode_85_byte(char c)
12012 { return (unsigned int)((c >= '\\') ? c-36 : c-35); }
12013
12014 NK_INTERN void
12015 nk_decode_85(unsigned char* dst, const unsigned char* src)
12016 {
12017 while (*src)
12018 {
12019 unsigned int tmp =
12020 nk_decode_85_byte((char)src[0]) +
12021 85 * (nk_decode_85_byte((char)src[1]) +
12022 85 * (nk_decode_85_byte((char)src[2]) +
12023 85 * (nk_decode_85_byte((char)src[3]) +
12024 85 * nk_decode_85_byte((char)src[4]))));
12025
12026 /* we can't assume little-endianess. */
12027 dst[0] = (unsigned char)((tmp >> 0) & 0xFF);
12028 dst[1] = (unsigned char)((tmp >> 8) & 0xFF);
12029 dst[2] = (unsigned char)((tmp >> 16) & 0xFF);
12030 dst[3] = (unsigned char)((tmp >> 24) & 0xFF);
12031
12032 src += 5;
12033 dst += 4;
12034 }
12035 }
12036
12037 /* -------------------------------------------------------------
12038 *
12039 * FONT ATLAS
12040 *
12041 * --------------------------------------------------------------*/
12042 NK_API struct nk_font_config
12043 nk_font_config(float pixel_height)
12044 {
12045 struct nk_font_config cfg;
12046 nk_zero_struct(cfg);
12047 cfg.ttf_blob = 0;
12048 cfg.ttf_size = 0;
12049 cfg.ttf_data_owned_by_atlas = 0;
12050 cfg.size = pixel_height;
12051 cfg.oversample_h = 3;
12052 cfg.oversample_v = 1;
12053 cfg.pixel_snap = 0;
12054 cfg.coord_type = NK_COORD_UV;
12055 cfg.spacing = nk_vec2(0,0);
12056 cfg.range = nk_font_default_glyph_ranges();
12057 cfg.merge_mode = 0;
12058 cfg.fallback_glyph = '?';
12059 cfg.font = 0;
12060 return cfg;
12061 }
12062
12063 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
12064 NK_API void
12065 nk_font_atlas_init_default(struct nk_font_atlas *atlas)
12066 {
12067 NK_ASSERT(atlas);
12068 if (!atlas) return;
12069 nk_zero_struct(*atlas);
12070 atlas->temporary.userdata.ptr = 0;
12071 atlas->temporary.alloc = nk_malloc;
12072 atlas->temporary.free = nk_mfree;
12073 atlas->permanent.userdata.ptr = 0;
12074 atlas->permanent.alloc = nk_malloc;
12075 atlas->permanent.free = nk_mfree;
12076 }
12077 #endif
12078
12079 NK_API void
12080 nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc)
12081 {
12082 NK_ASSERT(atlas);
12083 NK_ASSERT(alloc);
12084 if (!atlas || !alloc) return;
12085 nk_zero_struct(*atlas);
12086 atlas->permanent = *alloc;
12087 atlas->temporary = *alloc;
12088 }
12089
12090 NK_API void
12091 nk_font_atlas_init_custom(struct nk_font_atlas *atlas,
12092 struct nk_allocator *permanent, struct nk_allocator *temporary)
12093 {
12094 NK_ASSERT(atlas);
12095 NK_ASSERT(permanent);
12096 NK_ASSERT(temporary);
12097 if (!atlas || !permanent || !temporary) return;
12098 nk_zero_struct(*atlas);
12099 atlas->permanent = *permanent;
12100 atlas->temporary = *temporary;
12101 }
12102
12103 NK_API void
12104 nk_font_atlas_begin(struct nk_font_atlas *atlas)
12105 {
12106 NK_ASSERT(atlas);
12107 NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free);
12108 NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free);
12109 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free ||
12110 !atlas->temporary.alloc || !atlas->temporary.free) return;
12111 if (atlas->glyphs) {
12112 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
12113 atlas->glyphs = 0;
12114 }
12115 if (atlas->pixel) {
12116 atlas->permanent.free(atlas->permanent.userdata, atlas->pixel);
12117 atlas->pixel = 0;
12118 }
12119 }
12120
12121 NK_API struct nk_font*
12122 nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config)
12123 {
12124 struct nk_font *font = 0;
12125 struct nk_font_config *cfg;
12126
12127 NK_ASSERT(atlas);
12128 NK_ASSERT(atlas->permanent.alloc);
12129 NK_ASSERT(atlas->permanent.free);
12130 NK_ASSERT(atlas->temporary.alloc);
12131 NK_ASSERT(atlas->temporary.free);
12132
12133 NK_ASSERT(config);
12134 NK_ASSERT(config->ttf_blob);
12135 NK_ASSERT(config->ttf_size);
12136 NK_ASSERT(config->size > 0.0f);
12137
12138 if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f||
12139 !atlas->permanent.alloc || !atlas->permanent.free ||
12140 !atlas->temporary.alloc || !atlas->temporary.free)
12141 return 0;
12142
12143 /* allocate and insert font config into list */
12144 cfg = (struct nk_font_config*)
12145 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config));
12146 NK_MEMCPY(cfg, config, sizeof(*config));
12147 if (!atlas->config) {
12148 atlas->config = cfg;
12149 cfg->next = 0;
12150 } else {
12151 cfg->next = atlas->config;
12152 atlas->config = cfg;
12153 }
12154
12155 /* allocate new font */
12156 if (!config->merge_mode) {
12157 font = (struct nk_font*)
12158 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font));
12159 NK_ASSERT(font);
12160 if (!font) return 0;
12161 font->config = cfg;
12162 } else {
12163 NK_ASSERT(atlas->font_num);
12164 font = atlas->fonts;
12165 font->config = cfg;
12166 }
12167
12168 /* insert font into list */
12169 if (!config->merge_mode) {
12170 if (!atlas->fonts) {
12171 atlas->fonts = font;
12172 font->next = 0;
12173 } else {
12174 font->next = atlas->fonts;
12175 atlas->fonts = font;
12176 }
12177 cfg->font = &font->info;
12178 }
12179
12180 /* create own copy of .TTF font blob */
12181 if (!config->ttf_data_owned_by_atlas) {
12182 cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size);
12183 NK_ASSERT(cfg->ttf_blob);
12184 if (!cfg->ttf_blob) {
12185 atlas->font_num++;
12186 return 0;
12187 }
12188 NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size);
12189 cfg->ttf_data_owned_by_atlas = 1;
12190 }
12191 atlas->font_num++;
12192 return font;
12193 }
12194
12195 NK_API struct nk_font*
12196 nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory,
12197 nk_size size, float height, const struct nk_font_config *config)
12198 {
12199 struct nk_font_config cfg;
12200 NK_ASSERT(memory);
12201 NK_ASSERT(size);
12202
12203 NK_ASSERT(atlas);
12204 NK_ASSERT(atlas->temporary.alloc);
12205 NK_ASSERT(atlas->temporary.free);
12206 NK_ASSERT(atlas->permanent.alloc);
12207 NK_ASSERT(atlas->permanent.free);
12208 if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size ||
12209 !atlas->permanent.alloc || !atlas->permanent.free)
12210 return 0;
12211
12212 cfg = (config) ? *config: nk_font_config(height);
12213 cfg.ttf_blob = memory;
12214 cfg.ttf_size = size;
12215 cfg.size = height;
12216 cfg.ttf_data_owned_by_atlas = 0;
12217 return nk_font_atlas_add(atlas, &cfg);
12218 }
12219
12220 #ifdef NK_INCLUDE_STANDARD_IO
12221 NK_API struct nk_font*
12222 nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path,
12223 float height, const struct nk_font_config *config)
12224 {
12225 nk_size size;
12226 char *memory;
12227 struct nk_font_config cfg;
12228
12229 NK_ASSERT(atlas);
12230 NK_ASSERT(atlas->temporary.alloc);
12231 NK_ASSERT(atlas->temporary.free);
12232 NK_ASSERT(atlas->permanent.alloc);
12233 NK_ASSERT(atlas->permanent.free);
12234
12235 if (!atlas || !file_path) return 0;
12236 memory = nk_file_load(file_path, &size, &atlas->permanent);
12237 if (!memory) return 0;
12238
12239 cfg = (config) ? *config: nk_font_config(height);
12240 cfg.ttf_blob = memory;
12241 cfg.ttf_size = size;
12242 cfg.size = height;
12243 cfg.ttf_data_owned_by_atlas = 1;
12244 return nk_font_atlas_add(atlas, &cfg);
12245 }
12246 #endif
12247
12248 NK_API struct nk_font*
12249 nk_font_atlas_add_compressed(struct nk_font_atlas *atlas,
12250 void *compressed_data, nk_size compressed_size, float height,
12251 const struct nk_font_config *config)
12252 {
12253 unsigned int decompressed_size;
12254 void *decompressed_data;
12255 struct nk_font_config cfg;
12256
12257 NK_ASSERT(atlas);
12258 NK_ASSERT(atlas->temporary.alloc);
12259 NK_ASSERT(atlas->temporary.free);
12260 NK_ASSERT(atlas->permanent.alloc);
12261 NK_ASSERT(atlas->permanent.free);
12262
12263 NK_ASSERT(compressed_data);
12264 NK_ASSERT(compressed_size);
12265 if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free ||
12266 !atlas->permanent.alloc || !atlas->permanent.free)
12267 return 0;
12268
12269 decompressed_size = nk_decompress_length((unsigned char*)compressed_data);
12270 decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size);
12271 NK_ASSERT(decompressed_data);
12272 if (!decompressed_data) return 0;
12273 nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data,
12274 (unsigned int)compressed_size);
12275
12276 cfg = (config) ? *config: nk_font_config(height);
12277 cfg.ttf_blob = decompressed_data;
12278 cfg.ttf_size = decompressed_size;
12279 cfg.size = height;
12280 cfg.ttf_data_owned_by_atlas = 1;
12281 return nk_font_atlas_add(atlas, &cfg);
12282 }
12283
12284 NK_API struct nk_font*
12285 nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas,
12286 const char *data_base85, float height, const struct nk_font_config *config)
12287 {
12288 int compressed_size;
12289 void *compressed_data;
12290 struct nk_font *font;
12291
12292 NK_ASSERT(atlas);
12293 NK_ASSERT(atlas->temporary.alloc);
12294 NK_ASSERT(atlas->temporary.free);
12295 NK_ASSERT(atlas->permanent.alloc);
12296 NK_ASSERT(atlas->permanent.free);
12297
12298 NK_ASSERT(data_base85);
12299 if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free ||
12300 !atlas->permanent.alloc || !atlas->permanent.free)
12301 return 0;
12302
12303 compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4;
12304 compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size);
12305 NK_ASSERT(compressed_data);
12306 if (!compressed_data) return 0;
12307 nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85);
12308 font = nk_font_atlas_add_compressed(atlas, compressed_data,
12309 (nk_size)compressed_size, height, config);
12310 atlas->temporary.free(atlas->temporary.userdata, compressed_data);
12311 return font;
12312 }
12313
12314 #ifdef NK_INCLUDE_DEFAULT_FONT
12315 NK_API struct nk_font*
12316 nk_font_atlas_add_default(struct nk_font_atlas *atlas,
12317 float pixel_height, const struct nk_font_config *config)
12318 {
12319 NK_ASSERT(atlas);
12320 NK_ASSERT(atlas->temporary.alloc);
12321 NK_ASSERT(atlas->temporary.free);
12322 NK_ASSERT(atlas->permanent.alloc);
12323 NK_ASSERT(atlas->permanent.free);
12324 return nk_font_atlas_add_compressed_base85(atlas,
12325 nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config);
12326 }
12327 #endif
12328
12329 NK_API const void*
12330 nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height,
12331 enum nk_font_atlas_format fmt)
12332 {
12333 int i = 0;
12334 void *tmp = 0;
12335 nk_size tmp_size, img_size;
12336 struct nk_font *font_iter;
12337 struct nk_font_baker *baker;
12338
12339 NK_ASSERT(atlas);
12340 NK_ASSERT(atlas->temporary.alloc);
12341 NK_ASSERT(atlas->temporary.free);
12342 NK_ASSERT(atlas->permanent.alloc);
12343 NK_ASSERT(atlas->permanent.free);
12344
12345 NK_ASSERT(width);
12346 NK_ASSERT(height);
12347 if (!atlas || !width || !height ||
12348 !atlas->temporary.alloc || !atlas->temporary.free ||
12349 !atlas->permanent.alloc || !atlas->permanent.free)
12350 return 0;
12351
12352 #ifdef NK_INCLUDE_DEFAULT_FONT
12353 /* no font added so just use default font */
12354 if (!atlas->font_num)
12355 atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0);
12356 #endif
12357 NK_ASSERT(atlas->font_num);
12358 if (!atlas->font_num) return 0;
12359
12360 /* allocate temporary baker memory required for the baking process */
12361 nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num);
12362 tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size);
12363 NK_ASSERT(tmp);
12364 if (!tmp) goto failed;
12365
12366 /* allocate glyph memory for all fonts */
12367 baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary);
12368 atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc(
12369 atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count);
12370 NK_ASSERT(atlas->glyphs);
12371 if (!atlas->glyphs)
12372 goto failed;
12373
12374 /* pack all glyphs into a tight fit space */
12375 atlas->custom.w = (NK_CURSOR_DATA_W*2)+1;
12376 atlas->custom.h = NK_CURSOR_DATA_H + 1;
12377 if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom,
12378 atlas->config, atlas->font_num, &atlas->temporary))
12379 goto failed;
12380
12381 /* allocate memory for the baked image font atlas */
12382 atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size);
12383 NK_ASSERT(atlas->pixel);
12384 if (!atlas->pixel)
12385 goto failed;
12386
12387 /* bake glyphs and custom white pixel into image */
12388 nk_font_bake(baker, atlas->pixel, *width, *height,
12389 atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num);
12390 nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom,
12391 nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X');
12392
12393 if (fmt == NK_FONT_ATLAS_RGBA32) {
12394 /* convert alpha8 image into rgba32 image */
12395 void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0,
12396 (nk_size)(*width * *height * 4));
12397 NK_ASSERT(img_rgba);
12398 if (!img_rgba) goto failed;
12399 nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel);
12400 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
12401 atlas->pixel = img_rgba;
12402 }
12403 atlas->tex_width = *width;
12404 atlas->tex_height = *height;
12405
12406 /* initialize each font */
12407 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
12408 struct nk_font *font = font_iter;
12409 struct nk_font_config *config = font->config;
12410 nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs,
12411 config->font, nk_handle_ptr(0));
12412 }
12413
12414 /* initialize each cursor */
12415 {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = {
12416 /* Pos ----- Size ------- Offset --*/
12417 {{ 0, 3}, {12,19}, { 0, 0}},
12418 {{13, 0}, { 7,16}, { 4, 8}},
12419 {{31, 0}, {23,23}, {11,11}},
12420 {{21, 0}, { 9, 23}, { 5,11}},
12421 {{55,18}, {23, 9}, {11, 5}},
12422 {{73, 0}, {17,17}, { 9, 9}},
12423 {{55, 0}, {17,17}, { 9, 9}}
12424 };
12425 for (i = 0; i < NK_CURSOR_COUNT; ++i) {
12426 struct nk_cursor *cursor = &atlas->cursors[i];
12427 cursor->img.w = (unsigned short)*width;
12428 cursor->img.h = (unsigned short)*height;
12429 cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x);
12430 cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y);
12431 cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x;
12432 cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y;
12433 cursor->size = nk_cursor_data[i][1];
12434 cursor->offset = nk_cursor_data[i][2];
12435 }}
12436 /* free temporary memory */
12437 atlas->temporary.free(atlas->temporary.userdata, tmp);
12438 return atlas->pixel;
12439
12440 failed:
12441 /* error so cleanup all memory */
12442 if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp);
12443 if (atlas->glyphs) {
12444 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
12445 atlas->glyphs = 0;
12446 }
12447 if (atlas->pixel) {
12448 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
12449 atlas->pixel = 0;
12450 }
12451 return 0;
12452 }
12453
12454 NK_API void
12455 nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,
12456 struct nk_draw_null_texture *null)
12457 {
12458 int i = 0;
12459 struct nk_font *font_iter;
12460 NK_ASSERT(atlas);
12461 if (!atlas) {
12462 if (!null) return;
12463 null->texture = texture;
12464 null->uv = nk_vec2(0.5f,0.5f);
12465 }
12466 if (null) {
12467 null->texture = texture;
12468 null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;
12469 null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;
12470 }
12471 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
12472 font_iter->texture = texture;
12473 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
12474 font_iter->handle.texture = texture;
12475 #endif
12476 }
12477 for (i = 0; i < NK_CURSOR_COUNT; ++i)
12478 atlas->cursors[i].img.handle = texture;
12479
12480 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
12481 atlas->pixel = 0;
12482 atlas->tex_width = 0;
12483 atlas->tex_height = 0;
12484 atlas->custom.x = 0;
12485 atlas->custom.y = 0;
12486 atlas->custom.w = 0;
12487 atlas->custom.h = 0;
12488 }
12489
12490 NK_API void
12491 nk_font_atlas_cleanup(struct nk_font_atlas *atlas)
12492 {
12493 NK_ASSERT(atlas);
12494 NK_ASSERT(atlas->temporary.alloc);
12495 NK_ASSERT(atlas->temporary.free);
12496 NK_ASSERT(atlas->permanent.alloc);
12497 NK_ASSERT(atlas->permanent.free);
12498
12499 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
12500 if (atlas->config) {
12501 struct nk_font_config *iter, *next;
12502 for (iter = atlas->config; iter; iter = next) {
12503 next = iter->next;
12504 atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);
12505 atlas->permanent.free(atlas->permanent.userdata, iter);
12506 }
12507 atlas->config = 0;
12508 }
12509 }
12510
12511 NK_API void
12512 nk_font_atlas_clear(struct nk_font_atlas *atlas)
12513 {
12514 NK_ASSERT(atlas);
12515 NK_ASSERT(atlas->temporary.alloc);
12516 NK_ASSERT(atlas->temporary.free);
12517 NK_ASSERT(atlas->permanent.alloc);
12518 NK_ASSERT(atlas->permanent.free);
12519 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
12520
12521 nk_font_atlas_cleanup(atlas);
12522 if (atlas->fonts) {
12523 struct nk_font *iter, *next;
12524 for (iter = atlas->fonts; iter; iter = next) {
12525 next = iter->next;
12526 atlas->permanent.free(atlas->permanent.userdata, iter);
12527 }
12528 atlas->fonts = 0;
12529 }
12530 if (atlas->glyphs)
12531 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
12532 nk_zero_struct(*atlas);
12533 }
12534 #endif
12535 /* ==============================================================
12536 *
12537 * INPUT
12538 *
12539 * ===============================================================*/
12540 NK_API void
12541 nk_input_begin(struct nk_context *ctx)
12542 {
12543 int i;
12544 struct nk_input *in;
12545 NK_ASSERT(ctx);
12546 if (!ctx) return;
12547 in = &ctx->input;
12548 for (i = 0; i < NK_BUTTON_MAX; ++i)
12549 in->mouse.buttons[i].clicked = 0;
12550
12551 in->keyboard.text_len = 0;
12552 in->mouse.scroll_delta = nk_vec2(0,0);
12553 in->mouse.prev.x = in->mouse.pos.x;
12554 in->mouse.prev.y = in->mouse.pos.y;
12555 in->mouse.delta.x = 0;
12556 in->mouse.delta.y = 0;
12557 for (i = 0; i < NK_KEY_MAX; i++)
12558 in->keyboard.keys[i].clicked = 0;
12559 }
12560
12561 NK_API void
12562 nk_input_end(struct nk_context *ctx)
12563 {
12564 struct nk_input *in;
12565 NK_ASSERT(ctx);
12566 if (!ctx) return;
12567 in = &ctx->input;
12568 if (in->mouse.grab)
12569 in->mouse.grab = 0;
12570 if (in->mouse.ungrab) {
12571 in->mouse.grabbed = 0;
12572 in->mouse.ungrab = 0;
12573 in->mouse.grab = 0;
12574 }
12575 }
12576
12577 NK_API void
12578 nk_input_motion(struct nk_context *ctx, int x, int y)
12579 {
12580 struct nk_input *in;
12581 NK_ASSERT(ctx);
12582 if (!ctx) return;
12583 in = &ctx->input;
12584 in->mouse.pos.x = (float)x;
12585 in->mouse.pos.y = (float)y;
12586 in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;
12587 in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;
12588 }
12589
12590 NK_API void
12591 nk_input_key(struct nk_context *ctx, enum nk_keys key, int down)
12592 {
12593 struct nk_input *in;
12594 NK_ASSERT(ctx);
12595 if (!ctx) return;
12596 in = &ctx->input;
12597 if (in->keyboard.keys[key].down != down)
12598 in->keyboard.keys[key].clicked++;
12599 in->keyboard.keys[key].down = down;
12600 }
12601
12602 NK_API void
12603 nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down)
12604 {
12605 struct nk_mouse_button *btn;
12606 struct nk_input *in;
12607 NK_ASSERT(ctx);
12608 if (!ctx) return;
12609 in = &ctx->input;
12610 if (in->mouse.buttons[id].down == down) return;
12611
12612 btn = &in->mouse.buttons[id];
12613 btn->clicked_pos.x = (float)x;
12614 btn->clicked_pos.y = (float)y;
12615 btn->down = down;
12616 btn->clicked++;
12617 }
12618
12619 NK_API void
12620 nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)
12621 {
12622 NK_ASSERT(ctx);
12623 if (!ctx) return;
12624 ctx->input.mouse.scroll_delta.x += val.x;
12625 ctx->input.mouse.scroll_delta.y += val.y;
12626 }
12627
12628 NK_API void
12629 nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)
12630 {
12631 int len = 0;
12632 nk_rune unicode;
12633 struct nk_input *in;
12634
12635 NK_ASSERT(ctx);
12636 if (!ctx) return;
12637 in = &ctx->input;
12638
12639 len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);
12640 if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {
12641 nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],
12642 NK_INPUT_MAX - in->keyboard.text_len);
12643 in->keyboard.text_len += len;
12644 }
12645 }
12646
12647 NK_API void
12648 nk_input_char(struct nk_context *ctx, char c)
12649 {
12650 nk_glyph glyph;
12651 NK_ASSERT(ctx);
12652 if (!ctx) return;
12653 glyph[0] = c;
12654 nk_input_glyph(ctx, glyph);
12655 }
12656
12657 NK_API void
12658 nk_input_unicode(struct nk_context *ctx, nk_rune unicode)
12659 {
12660 nk_glyph rune;
12661 NK_ASSERT(ctx);
12662 if (!ctx) return;
12663 nk_utf_encode(unicode, rune, NK_UTF_SIZE);
12664 nk_input_glyph(ctx, rune);
12665 }
12666
12667 NK_API int
12668 nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)
12669 {
12670 const struct nk_mouse_button *btn;
12671 if (!i) return nk_false;
12672 btn = &i->mouse.buttons[id];
12673 return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;
12674 }
12675
12676 NK_API int
12677 nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
12678 struct nk_rect b)
12679 {
12680 const struct nk_mouse_button *btn;
12681 if (!i) return nk_false;
12682 btn = &i->mouse.buttons[id];
12683 if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
12684 return nk_false;
12685 return nk_true;
12686 }
12687
12688 NK_API int
12689 nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
12690 struct nk_rect b, int down)
12691 {
12692 const struct nk_mouse_button *btn;
12693 if (!i) return nk_false;
12694 btn = &i->mouse.buttons[id];
12695 return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);
12696 }
12697
12698 NK_API int
12699 nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
12700 struct nk_rect b)
12701 {
12702 const struct nk_mouse_button *btn;
12703 if (!i) return nk_false;
12704 btn = &i->mouse.buttons[id];
12705 return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&
12706 btn->clicked) ? nk_true : nk_false;
12707 }
12708
12709 NK_API int
12710 nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
12711 struct nk_rect b, int down)
12712 {
12713 const struct nk_mouse_button *btn;
12714 if (!i) return nk_false;
12715 btn = &i->mouse.buttons[id];
12716 return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&
12717 btn->clicked) ? nk_true : nk_false;
12718 }
12719
12720 NK_API int
12721 nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)
12722 {
12723 int i, down = 0;
12724 for (i = 0; i < NK_BUTTON_MAX; ++i)
12725 down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);
12726 return down;
12727 }
12728
12729 NK_API int
12730 nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)
12731 {
12732 if (!i) return nk_false;
12733 return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);
12734 }
12735
12736 NK_API int
12737 nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)
12738 {
12739 if (!i) return nk_false;
12740 return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);
12741 }
12742
12743 NK_API int
12744 nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)
12745 {
12746 if (!i) return nk_false;
12747 if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;
12748 return nk_input_is_mouse_click_in_rect(i, id, rect);
12749 }
12750
12751 NK_API int
12752 nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)
12753 {
12754 if (!i) return nk_false;
12755 return i->mouse.buttons[id].down;
12756 }
12757
12758 NK_API int
12759 nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)
12760 {
12761 const struct nk_mouse_button *b;
12762 if (!i) return nk_false;
12763 b = &i->mouse.buttons[id];
12764 if (b->down && b->clicked)
12765 return nk_true;
12766 return nk_false;
12767 }
12768
12769 NK_API int
12770 nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)
12771 {
12772 if (!i) return nk_false;
12773 return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);
12774 }
12775
12776 NK_API int
12777 nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)
12778 {
12779 const struct nk_key *k;
12780 if (!i) return nk_false;
12781 k = &i->keyboard.keys[key];
12782 if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))
12783 return nk_true;
12784 return nk_false;
12785 }
12786
12787 NK_API int
12788 nk_input_is_key_released(const struct nk_input *i, enum nk_keys key)
12789 {
12790 const struct nk_key *k;
12791 if (!i) return nk_false;
12792 k = &i->keyboard.keys[key];
12793 if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))
12794 return nk_true;
12795 return nk_false;
12796 }
12797
12798 NK_API int
12799 nk_input_is_key_down(const struct nk_input *i, enum nk_keys key)
12800 {
12801 const struct nk_key *k;
12802 if (!i) return nk_false;
12803 k = &i->keyboard.keys[key];
12804 if (k->down) return nk_true;
12805 return nk_false;
12806 }
12807
12808 /*
12809 * ==============================================================
12810 *
12811 * TEXT EDITOR
12812 *
12813 * ===============================================================
12814 */
12815 /* stb_textedit.h - v1.8 - public domain - Sean Barrett */
12816 struct nk_text_find {
12817 float x,y; /* position of n'th character */
12818 float height; /* height of line */
12819 int first_char, length; /* first char of row, and length */
12820 int prev_first; /*_ first char of previous row */
12821 };
12822
12823 struct nk_text_edit_row {
12824 float x0,x1;
12825 /* starting x location, end x location (allows for align=right, etc) */
12826 float baseline_y_delta;
12827 /* position of baseline relative to previous row's baseline*/
12828 float ymin,ymax;
12829 /* height of row above and below baseline */
12830 int num_chars;
12831 };
12832
12833 /* forward declarations */
12834 NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int);
12835 NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int);
12836 NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int);
12837 #define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
12838
12839 NK_INTERN float
12840 nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id,
12841 const struct nk_user_font *font)
12842 {
12843 int len = 0;
12844 nk_rune unicode = 0;
12845 const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len);
12846 return font->width(font->userdata, font->height, str, len);
12847 }
12848
12849 NK_INTERN void
12850 nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit,
12851 int line_start_id, float row_height, const struct nk_user_font *font)
12852 {
12853 int l;
12854 int glyphs = 0;
12855 nk_rune unicode;
12856 const char *remaining;
12857 int len = nk_str_len_char(&edit->string);
12858 const char *end = nk_str_get_const(&edit->string) + len;
12859 const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l);
12860 const struct nk_vec2 size = nk_text_calculate_text_bounds(font,
12861 text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE);
12862
12863 r->x0 = 0.0f;
12864 r->x1 = size.x;
12865 r->baseline_y_delta = size.y;
12866 r->ymin = 0.0f;
12867 r->ymax = size.y;
12868 r->num_chars = glyphs;
12869 }
12870
12871 NK_INTERN int
12872 nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y,
12873 const struct nk_user_font *font, float row_height)
12874 {
12875 struct nk_text_edit_row r;
12876 int n = edit->string.len;
12877 float base_y = 0, prev_x;
12878 int i=0, k;
12879
12880 r.x0 = r.x1 = 0;
12881 r.ymin = r.ymax = 0;
12882 r.num_chars = 0;
12883
12884 /* search rows to find one that straddles 'y' */
12885 while (i < n) {
12886 nk_textedit_layout_row(&r, edit, i, row_height, font);
12887 if (r.num_chars <= 0)
12888 return n;
12889
12890 if (i==0 && y < base_y + r.ymin)
12891 return 0;
12892
12893 if (y < base_y + r.ymax)
12894 break;
12895
12896 i += r.num_chars;
12897 base_y += r.baseline_y_delta;
12898 }
12899
12900 /* below all text, return 'after' last character */
12901 if (i >= n)
12902 return n;
12903
12904 /* check if it's before the beginning of the line */
12905 if (x < r.x0)
12906 return i;
12907
12908 /* check if it's before the end of the line */
12909 if (x < r.x1) {
12910 /* search characters in row for one that straddles 'x' */
12911 k = i;
12912 prev_x = r.x0;
12913 for (i=0; i < r.num_chars; ++i) {
12914 float w = nk_textedit_get_width(edit, k, i, font);
12915 if (x < prev_x+w) {
12916 if (x < prev_x+w/2)
12917 return k+i;
12918 else return k+i+1;
12919 }
12920 prev_x += w;
12921 }
12922 /* shouldn't happen, but if it does, fall through to end-of-line case */
12923 }
12924
12925 /* if the last character is a newline, return that.
12926 * otherwise return 'after' the last character */
12927 if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n')
12928 return i+r.num_chars-1;
12929 else return i+r.num_chars;
12930 }
12931
12932 NK_INTERN void
12933 nk_textedit_click(struct nk_text_edit *state, float x, float y,
12934 const struct nk_user_font *font, float row_height)
12935 {
12936 /* API click: on mouse down, move the cursor to the clicked location,
12937 * and reset the selection */
12938 state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height);
12939 state->select_start = state->cursor;
12940 state->select_end = state->cursor;
12941 state->has_preferred_x = 0;
12942 }
12943
12944 NK_INTERN void
12945 nk_textedit_drag(struct nk_text_edit *state, float x, float y,
12946 const struct nk_user_font *font, float row_height)
12947 {
12948 /* API drag: on mouse drag, move the cursor and selection endpoint
12949 * to the clicked location */
12950 int p = nk_textedit_locate_coord(state, x, y, font, row_height);
12951 if (state->select_start == state->select_end)
12952 state->select_start = state->cursor;
12953 state->cursor = state->select_end = p;
12954 }
12955
12956 NK_INTERN void
12957 nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state,
12958 int n, int single_line, const struct nk_user_font *font, float row_height)
12959 {
12960 /* find the x/y location of a character, and remember info about the previous
12961 * row in case we get a move-up event (for page up, we'll have to rescan) */
12962 struct nk_text_edit_row r;
12963 int prev_start = 0;
12964 int z = state->string.len;
12965 int i=0, first;
12966
12967 nk_zero_struct(r);
12968 if (n == z) {
12969 /* if it's at the end, then find the last line -- simpler than trying to
12970 explicitly handle this case in the regular code */
12971 nk_textedit_layout_row(&r, state, 0, row_height, font);
12972 if (single_line) {
12973 find->first_char = 0;
12974 find->length = z;
12975 } else {
12976 while (i < z) {
12977 prev_start = i;
12978 i += r.num_chars;
12979 nk_textedit_layout_row(&r, state, i, row_height, font);
12980 }
12981
12982 find->first_char = i;
12983 find->length = r.num_chars;
12984 }
12985 find->x = r.x1;
12986 find->y = r.ymin;
12987 find->height = r.ymax - r.ymin;
12988 find->prev_first = prev_start;
12989 return;
12990 }
12991
12992 /* search rows to find the one that straddles character n */
12993 find->y = 0;
12994
12995 for(;;) {
12996 nk_textedit_layout_row(&r, state, i, row_height, font);
12997 if (n < i + r.num_chars) break;
12998 prev_start = i;
12999 i += r.num_chars;
13000 find->y += r.baseline_y_delta;
13001 }
13002
13003 find->first_char = first = i;
13004 find->length = r.num_chars;
13005 find->height = r.ymax - r.ymin;
13006 find->prev_first = prev_start;
13007
13008 /* now scan to find xpos */
13009 find->x = r.x0;
13010 for (i=0; first+i < n; ++i)
13011 find->x += nk_textedit_get_width(state, first, i, font);
13012 }
13013
13014 NK_INTERN void
13015 nk_textedit_clamp(struct nk_text_edit *state)
13016 {
13017 /* make the selection/cursor state valid if client altered the string */
13018 int n = state->string.len;
13019 if (NK_TEXT_HAS_SELECTION(state)) {
13020 if (state->select_start > n) state->select_start = n;
13021 if (state->select_end > n) state->select_end = n;
13022 /* if clamping forced them to be equal, move the cursor to match */
13023 if (state->select_start == state->select_end)
13024 state->cursor = state->select_start;
13025 }
13026 if (state->cursor > n) state->cursor = n;
13027 }
13028
13029 NK_API void
13030 nk_textedit_delete(struct nk_text_edit *state, int where, int len)
13031 {
13032 /* delete characters while updating undo */
13033 nk_textedit_makeundo_delete(state, where, len);
13034 nk_str_delete_runes(&state->string, where, len);
13035 state->has_preferred_x = 0;
13036 }
13037
13038 NK_API void
13039 nk_textedit_delete_selection(struct nk_text_edit *state)
13040 {
13041 /* delete the section */
13042 nk_textedit_clamp(state);
13043 if (NK_TEXT_HAS_SELECTION(state)) {
13044 if (state->select_start < state->select_end) {
13045 nk_textedit_delete(state, state->select_start,
13046 state->select_end - state->select_start);
13047 state->select_end = state->cursor = state->select_start;
13048 } else {
13049 nk_textedit_delete(state, state->select_end,
13050 state->select_start - state->select_end);
13051 state->select_start = state->cursor = state->select_end;
13052 }
13053 state->has_preferred_x = 0;
13054 }
13055 }
13056
13057 NK_INTERN void
13058 nk_textedit_sortselection(struct nk_text_edit *state)
13059 {
13060 /* canonicalize the selection so start <= end */
13061 if (state->select_end < state->select_start) {
13062 int temp = state->select_end;
13063 state->select_end = state->select_start;
13064 state->select_start = temp;
13065 }
13066 }
13067
13068 NK_INTERN void
13069 nk_textedit_move_to_first(struct nk_text_edit *state)
13070 {
13071 /* move cursor to first character of selection */
13072 if (NK_TEXT_HAS_SELECTION(state)) {
13073 nk_textedit_sortselection(state);
13074 state->cursor = state->select_start;
13075 state->select_end = state->select_start;
13076 state->has_preferred_x = 0;
13077 }
13078 }
13079
13080 NK_INTERN void
13081 nk_textedit_move_to_last(struct nk_text_edit *state)
13082 {
13083 /* move cursor to last character of selection */
13084 if (NK_TEXT_HAS_SELECTION(state)) {
13085 nk_textedit_sortselection(state);
13086 nk_textedit_clamp(state);
13087 state->cursor = state->select_end;
13088 state->select_start = state->select_end;
13089 state->has_preferred_x = 0;
13090 }
13091 }
13092
13093 NK_INTERN int
13094 nk_is_word_boundary( struct nk_text_edit *state, int idx)
13095 {
13096 int len;
13097 nk_rune c;
13098 if (idx <= 0) return 1;
13099 if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1;
13100 return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' ||
13101 c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' ||
13102 c == '|');
13103 }
13104
13105 NK_INTERN int
13106 nk_textedit_move_to_word_previous(struct nk_text_edit *state)
13107 {
13108 int c = state->cursor - 1;
13109 while( c >= 0 && !nk_is_word_boundary(state, c))
13110 --c;
13111
13112 if( c < 0 )
13113 c = 0;
13114
13115 return c;
13116 }
13117
13118 NK_INTERN int
13119 nk_textedit_move_to_word_next(struct nk_text_edit *state)
13120 {
13121 const int len = state->string.len;
13122 int c = state->cursor+1;
13123 while( c < len && !nk_is_word_boundary(state, c))
13124 ++c;
13125
13126 if( c > len )
13127 c = len;
13128
13129 return c;
13130 }
13131
13132 NK_INTERN void
13133 nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state)
13134 {
13135 /* update selection and cursor to match each other */
13136 if (!NK_TEXT_HAS_SELECTION(state))
13137 state->select_start = state->select_end = state->cursor;
13138 else state->cursor = state->select_end;
13139 }
13140
13141 NK_API int
13142 nk_textedit_cut(struct nk_text_edit *state)
13143 {
13144 /* API cut: delete selection */
13145 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
13146 return 0;
13147 if (NK_TEXT_HAS_SELECTION(state)) {
13148 nk_textedit_delete_selection(state); /* implicitly clamps */
13149 state->has_preferred_x = 0;
13150 return 1;
13151 }
13152 return 0;
13153 }
13154
13155 NK_API int
13156 nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)
13157 {
13158 /* API paste: replace existing selection with passed-in text */
13159 int glyphs;
13160 const char *text = (const char *) ctext;
13161 if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;
13162
13163 /* if there's a selection, the paste should delete it */
13164 nk_textedit_clamp(state);
13165 nk_textedit_delete_selection(state);
13166
13167 /* try to insert the characters */
13168 glyphs = nk_utf_len(ctext, len);
13169 if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {
13170 nk_textedit_makeundo_insert(state, state->cursor, glyphs);
13171 state->cursor += len;
13172 state->has_preferred_x = 0;
13173 return 1;
13174 }
13175 /* remove the undo since we didn't actually insert the characters */
13176 if (state->undo.undo_point)
13177 --state->undo.undo_point;
13178 return 0;
13179 }
13180
13181 NK_API void
13182 nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)
13183 {
13184 nk_rune unicode;
13185 int glyph_len;
13186 int text_len = 0;
13187
13188 NK_ASSERT(state);
13189 NK_ASSERT(text);
13190 if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return;
13191
13192 glyph_len = nk_utf_decode(text, &unicode, total_len);
13193 while ((text_len < total_len) && glyph_len)
13194 {
13195 /* don't insert a backward delete, just process the event */
13196 if (unicode == 127) goto next;
13197 /* can't add newline in single-line mode */
13198 if (unicode == '\n' && state->single_line) goto next;
13199 /* filter incoming text */
13200 if (state->filter && !state->filter(state, unicode)) goto next;
13201
13202 if (!NK_TEXT_HAS_SELECTION(state) &&
13203 state->cursor < state->string.len)
13204 {
13205 if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) {
13206 nk_textedit_makeundo_replace(state, state->cursor, 1, 1);
13207 nk_str_delete_runes(&state->string, state->cursor, 1);
13208 }
13209 if (nk_str_insert_text_utf8(&state->string, state->cursor,
13210 text+text_len, 1))
13211 {
13212 ++state->cursor;
13213 state->has_preferred_x = 0;
13214 }
13215 } else {
13216 nk_textedit_delete_selection(state); /* implicitly clamps */
13217 if (nk_str_insert_text_utf8(&state->string, state->cursor,
13218 text+text_len, 1))
13219 {
13220 nk_textedit_makeundo_insert(state, state->cursor, 1);
13221 ++state->cursor;
13222 state->has_preferred_x = 0;
13223 }
13224 }
13225 next:
13226 text_len += glyph_len;
13227 glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len);
13228 }
13229 }
13230
13231 NK_INTERN void
13232 nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod,
13233 const struct nk_user_font *font, float row_height)
13234 {
13235 retry:
13236 switch (key)
13237 {
13238 case NK_KEY_NONE:
13239 case NK_KEY_CTRL:
13240 case NK_KEY_ENTER:
13241 case NK_KEY_SHIFT:
13242 case NK_KEY_TAB:
13243 case NK_KEY_COPY:
13244 case NK_KEY_CUT:
13245 case NK_KEY_PASTE:
13246 case NK_KEY_MAX:
13247 default: break;
13248 case NK_KEY_TEXT_UNDO:
13249 nk_textedit_undo(state);
13250 state->has_preferred_x = 0;
13251 break;
13252
13253 case NK_KEY_TEXT_REDO:
13254 nk_textedit_redo(state);
13255 state->has_preferred_x = 0;
13256 break;
13257
13258 case NK_KEY_TEXT_SELECT_ALL:
13259 nk_textedit_select_all(state);
13260 state->has_preferred_x = 0;
13261 break;
13262
13263 case NK_KEY_TEXT_INSERT_MODE:
13264 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
13265 state->mode = NK_TEXT_EDIT_MODE_INSERT;
13266 break;
13267 case NK_KEY_TEXT_REPLACE_MODE:
13268 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
13269 state->mode = NK_TEXT_EDIT_MODE_REPLACE;
13270 break;
13271 case NK_KEY_TEXT_RESET_MODE:
13272 if (state->mode == NK_TEXT_EDIT_MODE_INSERT ||
13273 state->mode == NK_TEXT_EDIT_MODE_REPLACE)
13274 state->mode = NK_TEXT_EDIT_MODE_VIEW;
13275 break;
13276
13277 case NK_KEY_LEFT:
13278 if (shift_mod) {
13279 nk_textedit_clamp(state);
13280 nk_textedit_prep_selection_at_cursor(state);
13281 /* move selection left */
13282 if (state->select_end > 0)
13283 --state->select_end;
13284 state->cursor = state->select_end;
13285 state->has_preferred_x = 0;
13286 } else {
13287 /* if currently there's a selection,
13288 * move cursor to start of selection */
13289 if (NK_TEXT_HAS_SELECTION(state))
13290 nk_textedit_move_to_first(state);
13291 else if (state->cursor > 0)
13292 --state->cursor;
13293 state->has_preferred_x = 0;
13294 } break;
13295
13296 case NK_KEY_RIGHT:
13297 if (shift_mod) {
13298 nk_textedit_prep_selection_at_cursor(state);
13299 /* move selection right */
13300 ++state->select_end;
13301 nk_textedit_clamp(state);
13302 state->cursor = state->select_end;
13303 state->has_preferred_x = 0;
13304 } else {
13305 /* if currently there's a selection,
13306 * move cursor to end of selection */
13307 if (NK_TEXT_HAS_SELECTION(state))
13308 nk_textedit_move_to_last(state);
13309 else ++state->cursor;
13310 nk_textedit_clamp(state);
13311 state->has_preferred_x = 0;
13312 } break;
13313
13314 case NK_KEY_TEXT_WORD_LEFT:
13315 if (shift_mod) {
13316 if( !NK_TEXT_HAS_SELECTION( state ) )
13317 nk_textedit_prep_selection_at_cursor(state);
13318 state->cursor = nk_textedit_move_to_word_previous(state);
13319 state->select_end = state->cursor;
13320 nk_textedit_clamp(state );
13321 } else {
13322 if (NK_TEXT_HAS_SELECTION(state))
13323 nk_textedit_move_to_first(state);
13324 else {
13325 state->cursor = nk_textedit_move_to_word_previous(state);
13326 nk_textedit_clamp(state );
13327 }
13328 } break;
13329
13330 case NK_KEY_TEXT_WORD_RIGHT:
13331 if (shift_mod) {
13332 if( !NK_TEXT_HAS_SELECTION( state ) )
13333 nk_textedit_prep_selection_at_cursor(state);
13334 state->cursor = nk_textedit_move_to_word_next(state);
13335 state->select_end = state->cursor;
13336 nk_textedit_clamp(state);
13337 } else {
13338 if (NK_TEXT_HAS_SELECTION(state))
13339 nk_textedit_move_to_last(state);
13340 else {
13341 state->cursor = nk_textedit_move_to_word_next(state);
13342 nk_textedit_clamp(state );
13343 }
13344 } break;
13345
13346 case NK_KEY_DOWN: {
13347 struct nk_text_find find;
13348 struct nk_text_edit_row row;
13349 int i, sel = shift_mod;
13350
13351 if (state->single_line) {
13352 /* on windows, up&down in single-line behave like left&right */
13353 key = NK_KEY_RIGHT;
13354 goto retry;
13355 }
13356
13357 if (sel)
13358 nk_textedit_prep_selection_at_cursor(state);
13359 else if (NK_TEXT_HAS_SELECTION(state))
13360 nk_textedit_move_to_last(state);
13361
13362 /* compute current position of cursor point */
13363 nk_textedit_clamp(state);
13364 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13365 font, row_height);
13366
13367 /* now find character position down a row */
13368 if (find.length)
13369 {
13370 float x;
13371 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
13372 int start = find.first_char + find.length;
13373
13374 state->cursor = start;
13375 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
13376 x = row.x0;
13377
13378 for (i=0; i < row.num_chars && x < row.x1; ++i) {
13379 float dx = nk_textedit_get_width(state, start, i, font);
13380 x += dx;
13381 if (x > goal_x)
13382 break;
13383 ++state->cursor;
13384 }
13385 nk_textedit_clamp(state);
13386
13387 state->has_preferred_x = 1;
13388 state->preferred_x = goal_x;
13389 if (sel)
13390 state->select_end = state->cursor;
13391 }
13392 } break;
13393
13394 case NK_KEY_UP: {
13395 struct nk_text_find find;
13396 struct nk_text_edit_row row;
13397 int i, sel = shift_mod;
13398
13399 if (state->single_line) {
13400 /* on windows, up&down become left&right */
13401 key = NK_KEY_LEFT;
13402 goto retry;
13403 }
13404
13405 if (sel)
13406 nk_textedit_prep_selection_at_cursor(state);
13407 else if (NK_TEXT_HAS_SELECTION(state))
13408 nk_textedit_move_to_first(state);
13409
13410 /* compute current position of cursor point */
13411 nk_textedit_clamp(state);
13412 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13413 font, row_height);
13414
13415 /* can only go up if there's a previous row */
13416 if (find.prev_first != find.first_char) {
13417 /* now find character position up a row */
13418 float x;
13419 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
13420
13421 state->cursor = find.prev_first;
13422 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
13423 x = row.x0;
13424
13425 for (i=0; i < row.num_chars && x < row.x1; ++i) {
13426 float dx = nk_textedit_get_width(state, find.prev_first, i, font);
13427 x += dx;
13428 if (x > goal_x)
13429 break;
13430 ++state->cursor;
13431 }
13432 nk_textedit_clamp(state);
13433
13434 state->has_preferred_x = 1;
13435 state->preferred_x = goal_x;
13436 if (sel) state->select_end = state->cursor;
13437 }
13438 } break;
13439
13440 case NK_KEY_DEL:
13441 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
13442 break;
13443 if (NK_TEXT_HAS_SELECTION(state))
13444 nk_textedit_delete_selection(state);
13445 else {
13446 int n = state->string.len;
13447 if (state->cursor < n)
13448 nk_textedit_delete(state, state->cursor, 1);
13449 }
13450 state->has_preferred_x = 0;
13451 break;
13452
13453 case NK_KEY_BACKSPACE:
13454 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
13455 break;
13456 if (NK_TEXT_HAS_SELECTION(state))
13457 nk_textedit_delete_selection(state);
13458 else {
13459 nk_textedit_clamp(state);
13460 if (state->cursor > 0) {
13461 nk_textedit_delete(state, state->cursor-1, 1);
13462 --state->cursor;
13463 }
13464 }
13465 state->has_preferred_x = 0;
13466 break;
13467
13468 case NK_KEY_TEXT_START:
13469 if (shift_mod) {
13470 nk_textedit_prep_selection_at_cursor(state);
13471 state->cursor = state->select_end = 0;
13472 state->has_preferred_x = 0;
13473 } else {
13474 state->cursor = state->select_start = state->select_end = 0;
13475 state->has_preferred_x = 0;
13476 }
13477 break;
13478
13479 case NK_KEY_TEXT_END:
13480 if (shift_mod) {
13481 nk_textedit_prep_selection_at_cursor(state);
13482 state->cursor = state->select_end = state->string.len;
13483 state->has_preferred_x = 0;
13484 } else {
13485 state->cursor = state->string.len;
13486 state->select_start = state->select_end = 0;
13487 state->has_preferred_x = 0;
13488 }
13489 break;
13490
13491 case NK_KEY_TEXT_LINE_START: {
13492 if (shift_mod) {
13493 struct nk_text_find find;
13494 nk_textedit_clamp(state);
13495 nk_textedit_prep_selection_at_cursor(state);
13496 if (state->string.len && state->cursor == state->string.len)
13497 --state->cursor;
13498 nk_textedit_find_charpos(&find, state,state->cursor, state->single_line,
13499 font, row_height);
13500 state->cursor = state->select_end = find.first_char;
13501 state->has_preferred_x = 0;
13502 } else {
13503 struct nk_text_find find;
13504 if (state->string.len && state->cursor == state->string.len)
13505 --state->cursor;
13506 nk_textedit_clamp(state);
13507 nk_textedit_move_to_first(state);
13508 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13509 font, row_height);
13510 state->cursor = find.first_char;
13511 state->has_preferred_x = 0;
13512 }
13513 } break;
13514
13515 case NK_KEY_TEXT_LINE_END: {
13516 if (shift_mod) {
13517 struct nk_text_find find;
13518 nk_textedit_clamp(state);
13519 nk_textedit_prep_selection_at_cursor(state);
13520 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13521 font, row_height);
13522 state->has_preferred_x = 0;
13523 state->cursor = find.first_char + find.length;
13524 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
13525 --state->cursor;
13526 state->select_end = state->cursor;
13527 } else {
13528 struct nk_text_find find;
13529 nk_textedit_clamp(state);
13530 nk_textedit_move_to_first(state);
13531 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
13532 font, row_height);
13533
13534 state->has_preferred_x = 0;
13535 state->cursor = find.first_char + find.length;
13536 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
13537 --state->cursor;
13538 }} break;
13539 }
13540 }
13541
13542 NK_INTERN void
13543 nk_textedit_flush_redo(struct nk_text_undo_state *state)
13544 {
13545 state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
13546 state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
13547 }
13548
13549 NK_INTERN void
13550 nk_textedit_discard_undo(struct nk_text_undo_state *state)
13551 {
13552 /* discard the oldest entry in the undo list */
13553 if (state->undo_point > 0) {
13554 /* if the 0th undo state has characters, clean those up */
13555 if (state->undo_rec[0].char_storage >= 0) {
13556 int n = state->undo_rec[0].insert_length, i;
13557 /* delete n characters from all other records */
13558 state->undo_char_point = (short)(state->undo_char_point - n);
13559 NK_MEMCPY(state->undo_char, state->undo_char + n,
13560 (nk_size)state->undo_char_point*sizeof(nk_rune));
13561 for (i=0; i < state->undo_point; ++i) {
13562 if (state->undo_rec[i].char_storage >= 0)
13563 state->undo_rec[i].char_storage = (short)
13564 (state->undo_rec[i].char_storage - n);
13565 }
13566 }
13567 --state->undo_point;
13568 NK_MEMCPY(state->undo_rec, state->undo_rec+1,
13569 (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0])));
13570 }
13571 }
13572
13573 NK_INTERN void
13574 nk_textedit_discard_redo(struct nk_text_undo_state *state)
13575 {
13576 /* discard the oldest entry in the redo list--it's bad if this
13577 ever happens, but because undo & redo have to store the actual
13578 characters in different cases, the redo character buffer can
13579 fill up even though the undo buffer didn't */
13580 nk_size num;
13581 int k = NK_TEXTEDIT_UNDOSTATECOUNT-1;
13582 if (state->redo_point <= k) {
13583 /* if the k'th undo state has characters, clean those up */
13584 if (state->undo_rec[k].char_storage >= 0) {
13585 int n = state->undo_rec[k].insert_length, i;
13586 /* delete n characters from all other records */
13587 state->redo_char_point = (short)(state->redo_char_point + n);
13588 num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point);
13589 NK_MEMCPY(state->undo_char + state->redo_char_point,
13590 state->undo_char + state->redo_char_point-n, num * sizeof(char));
13591 for (i = state->redo_point; i < k; ++i) {
13592 if (state->undo_rec[i].char_storage >= 0) {
13593 state->undo_rec[i].char_storage = (short)
13594 (state->undo_rec[i].char_storage + n);
13595 }
13596 }
13597 }
13598 ++state->redo_point;
13599 num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point);
13600 if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1,
13601 state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0]));
13602 }
13603 }
13604
13605 NK_INTERN struct nk_text_undo_record*
13606 nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars)
13607 {
13608 /* any time we create a new undo record, we discard redo*/
13609 nk_textedit_flush_redo(state);
13610
13611 /* if we have no free records, we have to make room,
13612 * by sliding the existing records down */
13613 if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13614 nk_textedit_discard_undo(state);
13615
13616 /* if the characters to store won't possibly fit in the buffer,
13617 * we can't undo */
13618 if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) {
13619 state->undo_point = 0;
13620 state->undo_char_point = 0;
13621 return 0;
13622 }
13623
13624 /* if we don't have enough free characters in the buffer,
13625 * we have to make room */
13626 while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT)
13627 nk_textedit_discard_undo(state);
13628 return &state->undo_rec[state->undo_point++];
13629 }
13630
13631 NK_INTERN nk_rune*
13632 nk_textedit_createundo(struct nk_text_undo_state *state, int pos,
13633 int insert_len, int delete_len)
13634 {
13635 struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len);
13636 if (r == 0)
13637 return 0;
13638
13639 r->where = pos;
13640 r->insert_length = (short) insert_len;
13641 r->delete_length = (short) delete_len;
13642
13643 if (insert_len == 0) {
13644 r->char_storage = -1;
13645 return 0;
13646 } else {
13647 r->char_storage = state->undo_char_point;
13648 state->undo_char_point = (short)(state->undo_char_point + insert_len);
13649 return &state->undo_char[r->char_storage];
13650 }
13651 }
13652
13653 NK_API void
13654 nk_textedit_undo(struct nk_text_edit *state)
13655 {
13656 struct nk_text_undo_state *s = &state->undo;
13657 struct nk_text_undo_record u, *r;
13658 if (s->undo_point == 0)
13659 return;
13660
13661 /* we need to do two things: apply the undo record, and create a redo record */
13662 u = s->undo_rec[s->undo_point-1];
13663 r = &s->undo_rec[s->redo_point-1];
13664 r->char_storage = -1;
13665
13666 r->insert_length = u.delete_length;
13667 r->delete_length = u.insert_length;
13668 r->where = u.where;
13669
13670 if (u.delete_length)
13671 {
13672 /* if the undo record says to delete characters, then the redo record will
13673 need to re-insert the characters that get deleted, so we need to store
13674 them.
13675 there are three cases:
13676 - there's enough room to store the characters
13677 - characters stored for *redoing* don't leave room for redo
13678 - characters stored for *undoing* don't leave room for redo
13679 if the last is true, we have to bail */
13680 if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) {
13681 /* the undo records take up too much character space; there's no space
13682 * to store the redo characters */
13683 r->insert_length = 0;
13684 } else {
13685 int i;
13686 /* there's definitely room to store the characters eventually */
13687 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
13688 /* there's currently not enough room, so discard a redo record */
13689 nk_textedit_discard_redo(s);
13690 /* should never happen: */
13691 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13692 return;
13693 }
13694
13695 r = &s->undo_rec[s->redo_point-1];
13696 r->char_storage = (short)(s->redo_char_point - u.delete_length);
13697 s->redo_char_point = (short)(s->redo_char_point - u.delete_length);
13698
13699 /* now save the characters */
13700 for (i=0; i < u.delete_length; ++i)
13701 s->undo_char[r->char_storage + i] =
13702 nk_str_rune_at(&state->string, u.where + i);
13703 }
13704 /* now we can carry out the deletion */
13705 nk_str_delete_runes(&state->string, u.where, u.delete_length);
13706 }
13707
13708 /* check type of recorded action: */
13709 if (u.insert_length) {
13710 /* easy case: was a deletion, so we need to insert n characters */
13711 nk_str_insert_text_runes(&state->string, u.where,
13712 &s->undo_char[u.char_storage], u.insert_length);
13713 s->undo_char_point = (short)(s->undo_char_point - u.insert_length);
13714 }
13715 state->cursor = (short)(u.where + u.insert_length);
13716
13717 s->undo_point--;
13718 s->redo_point--;
13719 }
13720
13721 NK_API void
13722 nk_textedit_redo(struct nk_text_edit *state)
13723 {
13724 struct nk_text_undo_state *s = &state->undo;
13725 struct nk_text_undo_record *u, r;
13726 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
13727 return;
13728
13729 /* we need to do two things: apply the redo record, and create an undo record */
13730 u = &s->undo_rec[s->undo_point];
13731 r = s->undo_rec[s->redo_point];
13732
13733 /* we KNOW there must be room for the undo record, because the redo record
13734 was derived from an undo record */
13735 u->delete_length = r.insert_length;
13736 u->insert_length = r.delete_length;
13737 u->where = r.where;
13738 u->char_storage = -1;
13739
13740 if (r.delete_length) {
13741 /* the redo record requires us to delete characters, so the undo record
13742 needs to store the characters */
13743 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
13744 u->insert_length = 0;
13745 u->delete_length = 0;
13746 } else {
13747 int i;
13748 u->char_storage = s->undo_char_point;
13749 s->undo_char_point = (short)(s->undo_char_point + u->insert_length);
13750
13751 /* now save the characters */
13752 for (i=0; i < u->insert_length; ++i) {
13753 s->undo_char[u->char_storage + i] =
13754 nk_str_rune_at(&state->string, u->where + i);
13755 }
13756 }
13757 nk_str_delete_runes(&state->string, r.where, r.delete_length);
13758 }
13759
13760 if (r.insert_length) {
13761 /* easy case: need to insert n characters */
13762 nk_str_insert_text_runes(&state->string, r.where,
13763 &s->undo_char[r.char_storage], r.insert_length);
13764 }
13765 state->cursor = r.where + r.insert_length;
13766
13767 s->undo_point++;
13768 s->redo_point++;
13769 }
13770
13771 NK_INTERN void
13772 nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length)
13773 {
13774 nk_textedit_createundo(&state->undo, where, 0, length);
13775 }
13776
13777 NK_INTERN void
13778 nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length)
13779 {
13780 int i;
13781 nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0);
13782 if (p) {
13783 for (i=0; i < length; ++i)
13784 p[i] = nk_str_rune_at(&state->string, where+i);
13785 }
13786 }
13787
13788 NK_INTERN void
13789 nk_textedit_makeundo_replace(struct nk_text_edit *state, int where,
13790 int old_length, int new_length)
13791 {
13792 int i;
13793 nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length);
13794 if (p) {
13795 for (i=0; i < old_length; ++i)
13796 p[i] = nk_str_rune_at(&state->string, where+i);
13797 }
13798 }
13799
13800 NK_INTERN void
13801 nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type,
13802 nk_plugin_filter filter)
13803 {
13804 /* reset the state to default */
13805 state->undo.undo_point = 0;
13806 state->undo.undo_char_point = 0;
13807 state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
13808 state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
13809 state->select_end = state->select_start = 0;
13810 state->cursor = 0;
13811 state->has_preferred_x = 0;
13812 state->preferred_x = 0;
13813 state->cursor_at_end_of_line = 0;
13814 state->initialized = 1;
13815 state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE);
13816 state->mode = NK_TEXT_EDIT_MODE_VIEW;
13817 state->filter = filter;
13818 state->scrollbar = nk_vec2(0,0);
13819 }
13820
13821 NK_API void
13822 nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size)
13823 {
13824 NK_ASSERT(state);
13825 NK_ASSERT(memory);
13826 if (!state || !memory || !size) return;
13827 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
13828 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13829 nk_str_init_fixed(&state->string, memory, size);
13830 }
13831
13832 NK_API void
13833 nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size)
13834 {
13835 NK_ASSERT(state);
13836 NK_ASSERT(alloc);
13837 if (!state || !alloc) return;
13838 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
13839 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13840 nk_str_init(&state->string, alloc, size);
13841 }
13842
13843 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
13844 NK_API void
13845 nk_textedit_init_default(struct nk_text_edit *state)
13846 {
13847 NK_ASSERT(state);
13848 if (!state) return;
13849 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
13850 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
13851 nk_str_init_default(&state->string);
13852 }
13853 #endif
13854
13855 NK_API void
13856 nk_textedit_select_all(struct nk_text_edit *state)
13857 {
13858 NK_ASSERT(state);
13859 state->select_start = 0;
13860 state->select_end = state->string.len;
13861 }
13862
13863 NK_API void
13864 nk_textedit_free(struct nk_text_edit *state)
13865 {
13866 NK_ASSERT(state);
13867 if (!state) return;
13868 nk_str_free(&state->string);
13869 }
13870
13871 /* ===============================================================
13872 *
13873 * TEXT WIDGET
13874 *
13875 * ===============================================================*/
13876 #define nk_widget_state_reset(s)\
13877 if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\
13878 (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\
13879 else (*(s)) = NK_WIDGET_STATE_INACTIVE;
13880
13881 struct nk_text {
13882 struct nk_vec2 padding;
13883 struct nk_color background;
13884 struct nk_color text;
13885 };
13886
13887 NK_INTERN void
13888 nk_widget_text(struct nk_command_buffer *o, struct nk_rect b,
13889 const char *string, int len, const struct nk_text *t,
13890 nk_flags a, const struct nk_user_font *f)
13891 {
13892 struct nk_rect label;
13893 float text_width;
13894
13895 NK_ASSERT(o);
13896 NK_ASSERT(t);
13897 if (!o || !t) return;
13898
13899 b.h = NK_MAX(b.h, 2 * t->padding.y);
13900 label.x = 0; label.w = 0;
13901 label.y = b.y + t->padding.y;
13902 label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);
13903
13904 text_width = f->width(f->userdata, f->height, (const char*)string, len);
13905 text_width += (2.0f * t->padding.x);
13906
13907 /* align in x-axis */
13908 if (a & NK_TEXT_ALIGN_LEFT) {
13909 label.x = b.x + t->padding.x;
13910 label.w = NK_MAX(0, b.w - 2 * t->padding.x);
13911 } else if (a & NK_TEXT_ALIGN_CENTERED) {
13912 label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);
13913 label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);
13914 label.x = NK_MAX(b.x + t->padding.x, label.x);
13915 label.w = NK_MIN(b.x + b.w, label.x + label.w);
13916 if (label.w >= label.x) label.w -= label.x;
13917 } else if (a & NK_TEXT_ALIGN_RIGHT) {
13918 label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));
13919 label.w = (float)text_width + 2 * t->padding.x;
13920 } else return;
13921
13922 /* align in y-axis */
13923 if (a & NK_TEXT_ALIGN_MIDDLE) {
13924 label.y = b.y + b.h/2.0f - (float)f->height/2.0f;
13925 label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));
13926 } else if (a & NK_TEXT_ALIGN_BOTTOM) {
13927 label.y = b.y + b.h - f->height;
13928 label.h = f->height;
13929 }
13930 nk_draw_text(o, label, (const char*)string,
13931 len, f, t->background, t->text);
13932 }
13933
13934 NK_INTERN void
13935 nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,
13936 const char *string, int len, const struct nk_text *t,
13937 const struct nk_user_font *f)
13938 {
13939 float width;
13940 int glyphs = 0;
13941 int fitting = 0;
13942 int done = 0;
13943 struct nk_rect line;
13944 struct nk_text text;
13945 NK_INTERN nk_rune seperator[] = {' '};
13946
13947 NK_ASSERT(o);
13948 NK_ASSERT(t);
13949 if (!o || !t) return;
13950
13951 text.padding = nk_vec2(0,0);
13952 text.background = t->background;
13953 text.text = t->text;
13954
13955 b.w = NK_MAX(b.w, 2 * t->padding.x);
13956 b.h = NK_MAX(b.h, 2 * t->padding.y);
13957 b.h = b.h - 2 * t->padding.y;
13958
13959 line.x = b.x + t->padding.x;
13960 line.y = b.y + t->padding.y;
13961 line.w = b.w - 2 * t->padding.x;
13962 line.h = 2 * t->padding.y + f->height;
13963
13964 fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
13965 while (done < len) {
13966 if (!fitting || line.y + line.h >= (b.y + b.h)) break;
13967 nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);
13968 done += fitting;
13969 line.y += f->height + 2 * t->padding.y;
13970 fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
13971 }
13972 }
13973
13974 /* ===============================================================
13975 *
13976 * BUTTON
13977 *
13978 * ===============================================================*/
13979 NK_INTERN void
13980 nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,
13981 struct nk_rect content, struct nk_color background, struct nk_color foreground,
13982 float border_width, const struct nk_user_font *font)
13983 {
13984 switch (type) {
13985 case NK_SYMBOL_X:
13986 case NK_SYMBOL_UNDERSCORE:
13987 case NK_SYMBOL_PLUS:
13988 case NK_SYMBOL_MINUS: {
13989 /* single character text symbol */
13990 const char *X = (type == NK_SYMBOL_X) ? "x":
13991 (type == NK_SYMBOL_UNDERSCORE) ? "_":
13992 (type == NK_SYMBOL_PLUS) ? "+": "-";
13993 struct nk_text text;
13994 text.padding = nk_vec2(0,0);
13995 text.background = background;
13996 text.text = foreground;
13997 nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);
13998 } break;
13999 case NK_SYMBOL_CIRCLE_SOLID:
14000 case NK_SYMBOL_CIRCLE_OUTLINE:
14001 case NK_SYMBOL_RECT_SOLID:
14002 case NK_SYMBOL_RECT_OUTLINE: {
14003 /* simple empty/filled shapes */
14004 if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {
14005 nk_fill_rect(out, content, 0, foreground);
14006 if (type == NK_SYMBOL_RECT_OUTLINE)
14007 nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);
14008 } else {
14009 nk_fill_circle(out, content, foreground);
14010 if (type == NK_SYMBOL_CIRCLE_OUTLINE)
14011 nk_fill_circle(out, nk_shrink_rect(content, 1), background);
14012 }
14013 } break;
14014 case NK_SYMBOL_TRIANGLE_UP:
14015 case NK_SYMBOL_TRIANGLE_DOWN:
14016 case NK_SYMBOL_TRIANGLE_LEFT:
14017 case NK_SYMBOL_TRIANGLE_RIGHT: {
14018 enum nk_heading heading;
14019 struct nk_vec2 points[3];
14020 heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :
14021 (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:
14022 (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;
14023 nk_triangle_from_direction(points, content, 0, 0, heading);
14024 nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,
14025 points[2].x, points[2].y, foreground);
14026 } break;
14027 default:
14028 case NK_SYMBOL_NONE:
14029 case NK_SYMBOL_MAX: break;
14030 }
14031 }
14032
14033 NK_INTERN int
14034 nk_button_behavior(nk_flags *state, struct nk_rect r,
14035 const struct nk_input *i, enum nk_button_behavior behavior)
14036 {
14037 int ret = 0;
14038 nk_widget_state_reset(state);
14039 if (!i) return 0;
14040 if (nk_input_is_mouse_hovering_rect(i, r)) {
14041 *state = NK_WIDGET_STATE_HOVERED;
14042 if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))
14043 *state = NK_WIDGET_STATE_ACTIVE;
14044 if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) {
14045 ret = (behavior != NK_BUTTON_DEFAULT) ?
14046 nk_input_is_mouse_down(i, NK_BUTTON_LEFT):
14047 #ifdef NK_BUTTON_TRIGGER_ON_RELEASE
14048 nk_input_is_mouse_released(i, NK_BUTTON_LEFT);
14049 #else
14050 nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);
14051 #endif
14052 }
14053 }
14054 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))
14055 *state |= NK_WIDGET_STATE_ENTERED;
14056 else if (nk_input_is_mouse_prev_hovering_rect(i, r))
14057 *state |= NK_WIDGET_STATE_LEFT;
14058 return ret;
14059 }
14060
14061 NK_INTERN const struct nk_style_item*
14062 nk_draw_button(struct nk_command_buffer *out,
14063 const struct nk_rect *bounds, nk_flags state,
14064 const struct nk_style_button *style)
14065 {
14066 const struct nk_style_item *background;
14067 if (state & NK_WIDGET_STATE_HOVER)
14068 background = &style->hover;
14069 else if (state & NK_WIDGET_STATE_ACTIVED)
14070 background = &style->active;
14071 else background = &style->normal;
14072
14073 if (background->type == NK_STYLE_ITEM_IMAGE) {
14074 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14075 } else {
14076 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14077 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14078 }
14079 return background;
14080 }
14081
14082 NK_INTERN int
14083 nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,
14084 const struct nk_style_button *style, const struct nk_input *in,
14085 enum nk_button_behavior behavior, struct nk_rect *content)
14086 {
14087 struct nk_rect bounds;
14088 NK_ASSERT(style);
14089 NK_ASSERT(state);
14090 NK_ASSERT(out);
14091 if (!out || !style)
14092 return nk_false;
14093
14094 /* calculate button content space */
14095 content->x = r.x + style->padding.x + style->border + style->rounding;
14096 content->y = r.y + style->padding.y + style->border + style->rounding;
14097 content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2);
14098 content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2);
14099
14100 /* execute button behavior */
14101 bounds.x = r.x - style->touch_padding.x;
14102 bounds.y = r.y - style->touch_padding.y;
14103 bounds.w = r.w + 2 * style->touch_padding.x;
14104 bounds.h = r.h + 2 * style->touch_padding.y;
14105 return nk_button_behavior(state, bounds, in, behavior);
14106 }
14107
14108 NK_INTERN void
14109 nk_draw_button_text(struct nk_command_buffer *out,
14110 const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,
14111 const struct nk_style_button *style, const char *txt, int len,
14112 nk_flags text_alignment, const struct nk_user_font *font)
14113 {
14114 struct nk_text text;
14115 const struct nk_style_item *background;
14116 background = nk_draw_button(out, bounds, state, style);
14117
14118 /* select correct colors/images */
14119 if (background->type == NK_STYLE_ITEM_COLOR)
14120 text.background = background->data.color;
14121 else text.background = style->text_background;
14122 if (state & NK_WIDGET_STATE_HOVER)
14123 text.text = style->text_hover;
14124 else if (state & NK_WIDGET_STATE_ACTIVED)
14125 text.text = style->text_active;
14126 else text.text = style->text_normal;
14127
14128 text.padding = nk_vec2(0,0);
14129 nk_widget_text(out, *content, txt, len, &text, text_alignment, font);
14130 }
14131
14132 NK_INTERN int
14133 nk_do_button_text(nk_flags *state,
14134 struct nk_command_buffer *out, struct nk_rect bounds,
14135 const char *string, int len, nk_flags align, enum nk_button_behavior behavior,
14136 const struct nk_style_button *style, const struct nk_input *in,
14137 const struct nk_user_font *font)
14138 {
14139 struct nk_rect content;
14140 int ret = nk_false;
14141
14142 NK_ASSERT(state);
14143 NK_ASSERT(style);
14144 NK_ASSERT(out);
14145 NK_ASSERT(string);
14146 NK_ASSERT(font);
14147 if (!out || !style || !font || !string)
14148 return nk_false;
14149
14150 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
14151 if (style->draw_begin) style->draw_begin(out, style->userdata);
14152 nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);
14153 if (style->draw_end) style->draw_end(out, style->userdata);
14154 return ret;
14155 }
14156
14157 NK_INTERN void
14158 nk_draw_button_symbol(struct nk_command_buffer *out,
14159 const struct nk_rect *bounds, const struct nk_rect *content,
14160 nk_flags state, const struct nk_style_button *style,
14161 enum nk_symbol_type type, const struct nk_user_font *font)
14162 {
14163 struct nk_color sym, bg;
14164 const struct nk_style_item *background;
14165
14166 /* select correct colors/images */
14167 background = nk_draw_button(out, bounds, state, style);
14168 if (background->type == NK_STYLE_ITEM_COLOR)
14169 bg = background->data.color;
14170 else bg = style->text_background;
14171
14172 if (state & NK_WIDGET_STATE_HOVER)
14173 sym = style->text_hover;
14174 else if (state & NK_WIDGET_STATE_ACTIVED)
14175 sym = style->text_active;
14176 else sym = style->text_normal;
14177 nk_draw_symbol(out, type, *content, bg, sym, 1, font);
14178 }
14179
14180 NK_INTERN int
14181 nk_do_button_symbol(nk_flags *state,
14182 struct nk_command_buffer *out, struct nk_rect bounds,
14183 enum nk_symbol_type symbol, enum nk_button_behavior behavior,
14184 const struct nk_style_button *style, const struct nk_input *in,
14185 const struct nk_user_font *font)
14186 {
14187 int ret;
14188 struct nk_rect content;
14189
14190 NK_ASSERT(state);
14191 NK_ASSERT(style);
14192 NK_ASSERT(font);
14193 NK_ASSERT(out);
14194 if (!out || !style || !font || !state)
14195 return nk_false;
14196
14197 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
14198 if (style->draw_begin) style->draw_begin(out, style->userdata);
14199 nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);
14200 if (style->draw_end) style->draw_end(out, style->userdata);
14201 return ret;
14202 }
14203
14204 NK_INTERN void
14205 nk_draw_button_image(struct nk_command_buffer *out,
14206 const struct nk_rect *bounds, const struct nk_rect *content,
14207 nk_flags state, const struct nk_style_button *style, const struct nk_image *img)
14208 {
14209 nk_draw_button(out, bounds, state, style);
14210 nk_draw_image(out, *content, img, nk_white);
14211 }
14212
14213 NK_INTERN int
14214 nk_do_button_image(nk_flags *state,
14215 struct nk_command_buffer *out, struct nk_rect bounds,
14216 struct nk_image img, enum nk_button_behavior b,
14217 const struct nk_style_button *style, const struct nk_input *in)
14218 {
14219 int ret;
14220 struct nk_rect content;
14221
14222 NK_ASSERT(state);
14223 NK_ASSERT(style);
14224 NK_ASSERT(out);
14225 if (!out || !style || !state)
14226 return nk_false;
14227
14228 ret = nk_do_button(state, out, bounds, style, in, b, &content);
14229 content.x += style->image_padding.x;
14230 content.y += style->image_padding.y;
14231 content.w -= 2 * style->image_padding.x;
14232 content.h -= 2 * style->image_padding.y;
14233
14234 if (style->draw_begin) style->draw_begin(out, style->userdata);
14235 nk_draw_button_image(out, &bounds, &content, *state, style, &img);
14236 if (style->draw_end) style->draw_end(out, style->userdata);
14237 return ret;
14238 }
14239
14240 NK_INTERN void
14241 nk_draw_button_text_symbol(struct nk_command_buffer *out,
14242 const struct nk_rect *bounds, const struct nk_rect *label,
14243 const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,
14244 const char *str, int len, enum nk_symbol_type type,
14245 const struct nk_user_font *font)
14246 {
14247 struct nk_color sym;
14248 struct nk_text text;
14249 const struct nk_style_item *background;
14250
14251 /* select correct background colors/images */
14252 background = nk_draw_button(out, bounds, state, style);
14253 if (background->type == NK_STYLE_ITEM_COLOR)
14254 text.background = background->data.color;
14255 else text.background = style->text_background;
14256
14257 /* select correct text colors */
14258 if (state & NK_WIDGET_STATE_HOVER) {
14259 sym = style->text_hover;
14260 text.text = style->text_hover;
14261 } else if (state & NK_WIDGET_STATE_ACTIVED) {
14262 sym = style->text_active;
14263 text.text = style->text_active;
14264 } else {
14265 sym = style->text_normal;
14266 text.text = style->text_normal;
14267 }
14268
14269 text.padding = nk_vec2(0,0);
14270 nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);
14271 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
14272 }
14273
14274 NK_INTERN int
14275 nk_do_button_text_symbol(nk_flags *state,
14276 struct nk_command_buffer *out, struct nk_rect bounds,
14277 enum nk_symbol_type symbol, const char *str, int len, nk_flags align,
14278 enum nk_button_behavior behavior, const struct nk_style_button *style,
14279 const struct nk_user_font *font, const struct nk_input *in)
14280 {
14281 int ret;
14282 struct nk_rect tri = {0,0,0,0};
14283 struct nk_rect content;
14284
14285 NK_ASSERT(style);
14286 NK_ASSERT(out);
14287 NK_ASSERT(font);
14288 if (!out || !style || !font)
14289 return nk_false;
14290
14291 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
14292 tri.y = content.y + (content.h/2) - font->height/2;
14293 tri.w = font->height; tri.h = font->height;
14294 if (align & NK_TEXT_ALIGN_LEFT) {
14295 tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);
14296 tri.x = NK_MAX(tri.x, 0);
14297 } else tri.x = content.x + 2 * style->padding.x;
14298
14299 /* draw button */
14300 if (style->draw_begin) style->draw_begin(out, style->userdata);
14301 nk_draw_button_text_symbol(out, &bounds, &content, &tri,
14302 *state, style, str, len, symbol, font);
14303 if (style->draw_end) style->draw_end(out, style->userdata);
14304 return ret;
14305 }
14306
14307 NK_INTERN void
14308 nk_draw_button_text_image(struct nk_command_buffer *out,
14309 const struct nk_rect *bounds, const struct nk_rect *label,
14310 const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,
14311 const char *str, int len, const struct nk_user_font *font,
14312 const struct nk_image *img)
14313 {
14314 struct nk_text text;
14315 const struct nk_style_item *background;
14316 background = nk_draw_button(out, bounds, state, style);
14317
14318 /* select correct colors */
14319 if (background->type == NK_STYLE_ITEM_COLOR)
14320 text.background = background->data.color;
14321 else text.background = style->text_background;
14322 if (state & NK_WIDGET_STATE_HOVER)
14323 text.text = style->text_hover;
14324 else if (state & NK_WIDGET_STATE_ACTIVED)
14325 text.text = style->text_active;
14326 else text.text = style->text_normal;
14327
14328 text.padding = nk_vec2(0,0);
14329 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
14330 nk_draw_image(out, *image, img, nk_white);
14331 }
14332
14333 NK_INTERN int
14334 nk_do_button_text_image(nk_flags *state,
14335 struct nk_command_buffer *out, struct nk_rect bounds,
14336 struct nk_image img, const char* str, int len, nk_flags align,
14337 enum nk_button_behavior behavior, const struct nk_style_button *style,
14338 const struct nk_user_font *font, const struct nk_input *in)
14339 {
14340 int ret;
14341 struct nk_rect icon;
14342 struct nk_rect content;
14343
14344 NK_ASSERT(style);
14345 NK_ASSERT(state);
14346 NK_ASSERT(font);
14347 NK_ASSERT(out);
14348 if (!out || !font || !style || !str)
14349 return nk_false;
14350
14351 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
14352 icon.y = bounds.y + style->padding.y;
14353 icon.w = icon.h = bounds.h - 2 * style->padding.y;
14354 if (align & NK_TEXT_ALIGN_LEFT) {
14355 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
14356 icon.x = NK_MAX(icon.x, 0);
14357 } else icon.x = bounds.x + 2 * style->padding.x;
14358
14359 icon.x += style->image_padding.x;
14360 icon.y += style->image_padding.y;
14361 icon.w -= 2 * style->image_padding.x;
14362 icon.h -= 2 * style->image_padding.y;
14363
14364 if (style->draw_begin) style->draw_begin(out, style->userdata);
14365 nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);
14366 if (style->draw_end) style->draw_end(out, style->userdata);
14367 return ret;
14368 }
14369
14370 /* ===============================================================
14371 *
14372 * TOGGLE
14373 *
14374 * ===============================================================*/
14375 enum nk_toggle_type {
14376 NK_TOGGLE_CHECK,
14377 NK_TOGGLE_OPTION
14378 };
14379
14380 NK_INTERN int
14381 nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
14382 nk_flags *state, int active)
14383 {
14384 nk_widget_state_reset(state);
14385 if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {
14386 *state = NK_WIDGET_STATE_ACTIVE;
14387 active = !active;
14388 }
14389 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))
14390 *state |= NK_WIDGET_STATE_ENTERED;
14391 else if (nk_input_is_mouse_prev_hovering_rect(in, select))
14392 *state |= NK_WIDGET_STATE_LEFT;
14393 return active;
14394 }
14395
14396 NK_INTERN void
14397 nk_draw_checkbox(struct nk_command_buffer *out,
14398 nk_flags state, const struct nk_style_toggle *style, int active,
14399 const struct nk_rect *label, const struct nk_rect *selector,
14400 const struct nk_rect *cursors, const char *string, int len,
14401 const struct nk_user_font *font)
14402 {
14403 const struct nk_style_item *background;
14404 const struct nk_style_item *cursor;
14405 struct nk_text text;
14406
14407 /* select correct colors/images */
14408 if (state & NK_WIDGET_STATE_HOVER) {
14409 background = &style->hover;
14410 cursor = &style->cursor_hover;
14411 text.text = style->text_hover;
14412 } else if (state & NK_WIDGET_STATE_ACTIVED) {
14413 background = &style->hover;
14414 cursor = &style->cursor_hover;
14415 text.text = style->text_active;
14416 } else {
14417 background = &style->normal;
14418 cursor = &style->cursor_normal;
14419 text.text = style->text_normal;
14420 }
14421
14422 /* draw background and cursor */
14423 if (background->type == NK_STYLE_ITEM_COLOR) {
14424 nk_fill_rect(out, *selector, 0, style->border_color);
14425 nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color);
14426 } else nk_draw_image(out, *selector, &background->data.image, nk_white);
14427 if (active) {
14428 if (cursor->type == NK_STYLE_ITEM_IMAGE)
14429 nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
14430 else nk_fill_rect(out, *cursors, 0, cursor->data.color);
14431 }
14432
14433 text.padding.x = 0;
14434 text.padding.y = 0;
14435 text.background = style->text_background;
14436 nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
14437 }
14438
14439 NK_INTERN void
14440 nk_draw_option(struct nk_command_buffer *out,
14441 nk_flags state, const struct nk_style_toggle *style, int active,
14442 const struct nk_rect *label, const struct nk_rect *selector,
14443 const struct nk_rect *cursors, const char *string, int len,
14444 const struct nk_user_font *font)
14445 {
14446 const struct nk_style_item *background;
14447 const struct nk_style_item *cursor;
14448 struct nk_text text;
14449
14450 /* select correct colors/images */
14451 if (state & NK_WIDGET_STATE_HOVER) {
14452 background = &style->hover;
14453 cursor = &style->cursor_hover;
14454 text.text = style->text_hover;
14455 } else if (state & NK_WIDGET_STATE_ACTIVED) {
14456 background = &style->hover;
14457 cursor = &style->cursor_hover;
14458 text.text = style->text_active;
14459 } else {
14460 background = &style->normal;
14461 cursor = &style->cursor_normal;
14462 text.text = style->text_normal;
14463 }
14464
14465 /* draw background and cursor */
14466 if (background->type == NK_STYLE_ITEM_COLOR) {
14467 nk_fill_circle(out, *selector, style->border_color);
14468 nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color);
14469 } else nk_draw_image(out, *selector, &background->data.image, nk_white);
14470 if (active) {
14471 if (cursor->type == NK_STYLE_ITEM_IMAGE)
14472 nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
14473 else nk_fill_circle(out, *cursors, cursor->data.color);
14474 }
14475
14476 text.padding.x = 0;
14477 text.padding.y = 0;
14478 text.background = style->text_background;
14479 nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
14480 }
14481
14482 NK_INTERN int
14483 nk_do_toggle(nk_flags *state,
14484 struct nk_command_buffer *out, struct nk_rect r,
14485 int *active, const char *str, int len, enum nk_toggle_type type,
14486 const struct nk_style_toggle *style, const struct nk_input *in,
14487 const struct nk_user_font *font)
14488 {
14489 int was_active;
14490 struct nk_rect bounds;
14491 struct nk_rect select;
14492 struct nk_rect cursor;
14493 struct nk_rect label;
14494
14495 NK_ASSERT(style);
14496 NK_ASSERT(out);
14497 NK_ASSERT(font);
14498 if (!out || !style || !font || !active)
14499 return 0;
14500
14501 r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);
14502 r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);
14503
14504 /* add additional touch padding for touch screen devices */
14505 bounds.x = r.x - style->touch_padding.x;
14506 bounds.y = r.y - style->touch_padding.y;
14507 bounds.w = r.w + 2 * style->touch_padding.x;
14508 bounds.h = r.h + 2 * style->touch_padding.y;
14509
14510 /* calculate the selector space */
14511 select.w = font->height;
14512 select.h = select.w;
14513 select.y = r.y + r.h/2.0f - select.h/2.0f;
14514 select.x = r.x;
14515
14516 /* calculate the bounds of the cursor inside the selector */
14517 cursor.x = select.x + style->padding.x + style->border;
14518 cursor.y = select.y + style->padding.y + style->border;
14519 cursor.w = select.w - (2 * style->padding.x + 2 * style->border);
14520 cursor.h = select.h - (2 * style->padding.y + 2 * style->border);
14521
14522 /* label behind the selector */
14523 label.x = select.x + select.w + style->spacing;
14524 label.y = select.y;
14525 label.w = NK_MAX(r.x + r.w, label.x) - label.x;
14526 label.h = select.w;
14527
14528 /* update selector */
14529 was_active = *active;
14530 *active = nk_toggle_behavior(in, bounds, state, *active);
14531
14532 /* draw selector */
14533 if (style->draw_begin)
14534 style->draw_begin(out, style->userdata);
14535 if (type == NK_TOGGLE_CHECK) {
14536 nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font);
14537 } else {
14538 nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font);
14539 }
14540 if (style->draw_end)
14541 style->draw_end(out, style->userdata);
14542 return (was_active != *active);
14543 }
14544
14545 /* ===============================================================
14546 *
14547 * SELECTABLE
14548 *
14549 * ===============================================================*/
14550 NK_INTERN void
14551 nk_draw_selectable(struct nk_command_buffer *out,
14552 nk_flags state, const struct nk_style_selectable *style, int active,
14553 const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img,
14554 const char *string, int len, nk_flags align, const struct nk_user_font *font)
14555 {
14556 const struct nk_style_item *background;
14557 struct nk_text text;
14558 text.padding = style->padding;
14559
14560 /* select correct colors/images */
14561 if (!active) {
14562 if (state & NK_WIDGET_STATE_ACTIVED) {
14563 background = &style->pressed;
14564 text.text = style->text_pressed;
14565 } else if (state & NK_WIDGET_STATE_HOVER) {
14566 background = &style->hover;
14567 text.text = style->text_hover;
14568 } else {
14569 background = &style->normal;
14570 text.text = style->text_normal;
14571 }
14572 } else {
14573 if (state & NK_WIDGET_STATE_ACTIVED) {
14574 background = &style->pressed_active;
14575 text.text = style->text_pressed_active;
14576 } else if (state & NK_WIDGET_STATE_HOVER) {
14577 background = &style->hover_active;
14578 text.text = style->text_hover_active;
14579 } else {
14580 background = &style->normal_active;
14581 text.text = style->text_normal_active;
14582 }
14583 }
14584
14585
14586 /* draw selectable background and text */
14587 if (background->type == NK_STYLE_ITEM_IMAGE) {
14588 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14589 text.background = nk_rgba(0,0,0,0);
14590 } else {
14591 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14592 text.background = background->data.color;
14593 }
14594 if (img && icon) nk_draw_image(out, *icon, img, nk_white);
14595 nk_widget_text(out, *bounds, string, len, &text, align, font);
14596 }
14597
14598 NK_INTERN int
14599 nk_do_selectable(nk_flags *state, struct nk_command_buffer *out,
14600 struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
14601 const struct nk_style_selectable *style, const struct nk_input *in,
14602 const struct nk_user_font *font)
14603 {
14604 int old_value;
14605 struct nk_rect touch;
14606
14607 NK_ASSERT(state);
14608 NK_ASSERT(out);
14609 NK_ASSERT(str);
14610 NK_ASSERT(len);
14611 NK_ASSERT(value);
14612 NK_ASSERT(style);
14613 NK_ASSERT(font);
14614
14615 if (!state || !out || !str || !len || !value || !style || !font) return 0;
14616 old_value = *value;
14617
14618 /* remove padding */
14619 touch.x = bounds.x - style->touch_padding.x;
14620 touch.y = bounds.y - style->touch_padding.y;
14621 touch.w = bounds.w + style->touch_padding.x * 2;
14622 touch.h = bounds.h + style->touch_padding.y * 2;
14623
14624 /* update button */
14625 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
14626 *value = !(*value);
14627
14628 /* draw selectable */
14629 if (style->draw_begin) style->draw_begin(out, style->userdata);
14630 nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font);
14631 if (style->draw_end) style->draw_end(out, style->userdata);
14632 return old_value != *value;
14633 }
14634
14635 NK_INTERN int
14636 nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,
14637 struct nk_rect bounds, const char *str, int len, nk_flags align, int *value,
14638 const struct nk_image *img, const struct nk_style_selectable *style,
14639 const struct nk_input *in, const struct nk_user_font *font)
14640 {
14641 int old_value;
14642 struct nk_rect touch;
14643 struct nk_rect icon;
14644
14645 NK_ASSERT(state);
14646 NK_ASSERT(out);
14647 NK_ASSERT(str);
14648 NK_ASSERT(len);
14649 NK_ASSERT(value);
14650 NK_ASSERT(style);
14651 NK_ASSERT(font);
14652
14653 if (!state || !out || !str || !len || !value || !style || !font) return 0;
14654 old_value = *value;
14655
14656 /* toggle behavior */
14657 touch.x = bounds.x - style->touch_padding.x;
14658 touch.y = bounds.y - style->touch_padding.y;
14659 touch.w = bounds.w + style->touch_padding.x * 2;
14660 touch.h = bounds.h + style->touch_padding.y * 2;
14661 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
14662 *value = !(*value);
14663
14664 icon.y = bounds.y + style->padding.y;
14665 icon.w = icon.h = bounds.h - 2 * style->padding.y;
14666 if (align & NK_TEXT_ALIGN_LEFT) {
14667 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
14668 icon.x = NK_MAX(icon.x, 0);
14669 } else icon.x = bounds.x + 2 * style->padding.x;
14670
14671 icon.x += style->image_padding.x;
14672 icon.y += style->image_padding.y;
14673 icon.w -= 2 * style->image_padding.x;
14674 icon.h -= 2 * style->image_padding.y;
14675
14676 /* draw selectable */
14677 if (style->draw_begin) style->draw_begin(out, style->userdata);
14678 nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font);
14679 if (style->draw_end) style->draw_end(out, style->userdata);
14680 return old_value != *value;
14681 }
14682
14683
14684 /* ===============================================================
14685 *
14686 * SLIDER
14687 *
14688 * ===============================================================*/
14689 NK_INTERN float
14690 nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,
14691 struct nk_rect *visual_cursor, struct nk_input *in,
14692 struct nk_rect bounds, float slider_min, float slider_max, float slider_value,
14693 float slider_step, float slider_steps)
14694 {
14695 int left_mouse_down;
14696 int left_mouse_click_in_cursor;
14697
14698 /* check if visual cursor is being dragged */
14699 nk_widget_state_reset(state);
14700 left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
14701 left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
14702 NK_BUTTON_LEFT, *visual_cursor, nk_true);
14703
14704 if (left_mouse_down && left_mouse_click_in_cursor)
14705 {
14706 float ratio = 0;
14707 const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);
14708 const float pxstep = bounds.w / slider_steps;
14709
14710 /* only update value if the next slider step is reached */
14711 *state = NK_WIDGET_STATE_ACTIVE;
14712 if (NK_ABS(d) >= pxstep) {
14713 const float steps = (float)((int)(NK_ABS(d) / pxstep));
14714 slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);
14715 slider_value = NK_CLAMP(slider_min, slider_value, slider_max);
14716 ratio = (slider_value - slider_min)/slider_step;
14717 logical_cursor->x = bounds.x + (logical_cursor->w * ratio);
14718 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;
14719 }
14720 }
14721
14722 /* slider widget state */
14723 if (nk_input_is_mouse_hovering_rect(in, bounds))
14724 *state = NK_WIDGET_STATE_HOVERED;
14725 if (*state & NK_WIDGET_STATE_HOVER &&
14726 !nk_input_is_mouse_prev_hovering_rect(in, bounds))
14727 *state |= NK_WIDGET_STATE_ENTERED;
14728 else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
14729 *state |= NK_WIDGET_STATE_LEFT;
14730 return slider_value;
14731 }
14732
14733 NK_INTERN void
14734 nk_draw_slider(struct nk_command_buffer *out, nk_flags state,
14735 const struct nk_style_slider *style, const struct nk_rect *bounds,
14736 const struct nk_rect *visual_cursor, float min, float value, float max)
14737 {
14738 struct nk_rect fill;
14739 struct nk_rect bar;
14740 const struct nk_style_item *background;
14741
14742 /* select correct slider images/colors */
14743 struct nk_color bar_color;
14744 const struct nk_style_item *cursor;
14745
14746 NK_UNUSED(min);
14747 NK_UNUSED(max);
14748 NK_UNUSED(value);
14749
14750 if (state & NK_WIDGET_STATE_ACTIVED) {
14751 background = &style->active;
14752 bar_color = style->bar_active;
14753 cursor = &style->cursor_active;
14754 } else if (state & NK_WIDGET_STATE_HOVER) {
14755 background = &style->hover;
14756 bar_color = style->bar_hover;
14757 cursor = &style->cursor_hover;
14758 } else {
14759 background = &style->normal;
14760 bar_color = style->bar_normal;
14761 cursor = &style->cursor_normal;
14762 }
14763
14764 /* calculate slider background bar */
14765 bar.x = bounds->x;
14766 bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;
14767 bar.w = bounds->w;
14768 bar.h = bounds->h/6;
14769
14770 /* filled background bar style */
14771 fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;
14772 fill.x = bar.x;
14773 fill.y = bar.y;
14774 fill.h = bar.h;
14775
14776 /* draw background */
14777 if (background->type == NK_STYLE_ITEM_IMAGE) {
14778 nk_draw_image(out, *bounds, &background->data.image, nk_white);
14779 } else {
14780 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14781 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14782 }
14783
14784 /* draw slider bar */
14785 nk_fill_rect(out, bar, style->rounding, bar_color);
14786 nk_fill_rect(out, fill, style->rounding, style->bar_filled);
14787
14788 /* draw cursor */
14789 if (cursor->type == NK_STYLE_ITEM_IMAGE)
14790 nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white);
14791 else nk_fill_circle(out, *visual_cursor, cursor->data.color);
14792 }
14793
14794 NK_INTERN float
14795 nk_do_slider(nk_flags *state,
14796 struct nk_command_buffer *out, struct nk_rect bounds,
14797 float min, float val, float max, float step,
14798 const struct nk_style_slider *style, struct nk_input *in,
14799 const struct nk_user_font *font)
14800 {
14801 float slider_range;
14802 float slider_min;
14803 float slider_max;
14804 float slider_value;
14805 float slider_steps;
14806 float cursor_offset;
14807
14808 struct nk_rect visual_cursor;
14809 struct nk_rect logical_cursor;
14810
14811 NK_ASSERT(style);
14812 NK_ASSERT(out);
14813 if (!out || !style)
14814 return 0;
14815
14816 /* remove padding from slider bounds */
14817 bounds.x = bounds.x + style->padding.x;
14818 bounds.y = bounds.y + style->padding.y;
14819 bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
14820 bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);
14821 bounds.w -= 2 * style->padding.x;
14822 bounds.h -= 2 * style->padding.y;
14823
14824 /* optional buttons */
14825 if (style->show_buttons) {
14826 nk_flags ws;
14827 struct nk_rect button;
14828 button.y = bounds.y;
14829 button.w = bounds.h;
14830 button.h = bounds.h;
14831
14832 /* decrement button */
14833 button.x = bounds.x;
14834 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,
14835 &style->dec_button, in, font))
14836 val -= step;
14837
14838 /* increment button */
14839 button.x = (bounds.x + bounds.w) - button.w;
14840 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,
14841 &style->inc_button, in, font))
14842 val += step;
14843
14844 bounds.x = bounds.x + button.w + style->spacing.x;
14845 bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);
14846 }
14847
14848 /* remove one cursor size to support visual cursor */
14849 bounds.x += style->cursor_size.x*0.5f;
14850 bounds.w -= style->cursor_size.x;
14851
14852 /* make sure the provided values are correct */
14853 slider_max = NK_MAX(min, max);
14854 slider_min = NK_MIN(min, max);
14855 slider_value = NK_CLAMP(slider_min, val, slider_max);
14856 slider_range = slider_max - slider_min;
14857 slider_steps = slider_range / step;
14858 cursor_offset = (slider_value - slider_min) / step;
14859
14860 /* calculate cursor
14861 Basically you have two cursors. One for visual representation and interaction
14862 and one for updating the actual cursor value. */
14863 logical_cursor.h = bounds.h;
14864 logical_cursor.w = bounds.w / slider_steps;
14865 logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);
14866 logical_cursor.y = bounds.y;
14867
14868 visual_cursor.h = style->cursor_size.y;
14869 visual_cursor.w = style->cursor_size.x;
14870 visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;
14871 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
14872
14873 slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,
14874 in, bounds, slider_min, slider_max, slider_value, step, slider_steps);
14875 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
14876
14877 /* draw slider */
14878 if (style->draw_begin) style->draw_begin(out, style->userdata);
14879 nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);
14880 if (style->draw_end) style->draw_end(out, style->userdata);
14881 return slider_value;
14882 }
14883
14884 /* ===============================================================
14885 *
14886 * PROGRESSBAR
14887 *
14888 * ===============================================================*/
14889 NK_INTERN nk_size
14890 nk_progress_behavior(nk_flags *state, const struct nk_input *in,
14891 struct nk_rect r, nk_size max, nk_size value, int modifiable)
14892 {
14893 nk_widget_state_reset(state);
14894 if (in && modifiable && nk_input_is_mouse_hovering_rect(in, r)) {
14895 int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
14896 int left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
14897 NK_BUTTON_LEFT, r, nk_true);
14898
14899 if (left_mouse_down && left_mouse_click_in_cursor) {
14900 float ratio = NK_MAX(0, (float)(in->mouse.pos.x - r.x)) / (float)r.w;
14901 value = (nk_size)NK_MAX(0,((float)max * ratio));
14902 *state = NK_WIDGET_STATE_ACTIVE;
14903 } else *state = NK_WIDGET_STATE_HOVERED;
14904 }
14905
14906 /* set progressbar widget state */
14907 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))
14908 *state |= NK_WIDGET_STATE_ENTERED;
14909 else if (nk_input_is_mouse_prev_hovering_rect(in, r))
14910 *state |= NK_WIDGET_STATE_LEFT;
14911
14912 if (!max) return value;
14913 value = NK_MIN(value, max);
14914 return value;
14915 }
14916
14917 NK_INTERN void
14918 nk_draw_progress(struct nk_command_buffer *out, nk_flags state,
14919 const struct nk_style_progress *style, const struct nk_rect *bounds,
14920 const struct nk_rect *scursor, nk_size value, nk_size max)
14921 {
14922 const struct nk_style_item *background;
14923 const struct nk_style_item *cursor;
14924
14925 NK_UNUSED(max);
14926 NK_UNUSED(value);
14927
14928 /* select correct colors/images to draw */
14929 if (state & NK_WIDGET_STATE_ACTIVED) {
14930 background = &style->active;
14931 cursor = &style->cursor_active;
14932 } else if (state & NK_WIDGET_STATE_HOVER){
14933 background = &style->hover;
14934 cursor = &style->cursor_hover;
14935 } else {
14936 background = &style->normal;
14937 cursor = &style->cursor_normal;
14938 }
14939
14940 /* draw background */
14941 if (background->type == NK_STYLE_ITEM_COLOR) {
14942 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
14943 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
14944 } else nk_draw_image(out, *bounds, &background->data.image, nk_white);
14945
14946 /* draw cursor */
14947 if (cursor->type == NK_STYLE_ITEM_COLOR) {
14948 nk_fill_rect(out, *scursor, style->rounding, cursor->data.color);
14949 nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color);
14950 } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white);
14951 }
14952
14953 NK_INTERN nk_size
14954 nk_do_progress(nk_flags *state,
14955 struct nk_command_buffer *out, struct nk_rect bounds,
14956 nk_size value, nk_size max, int modifiable,
14957 const struct nk_style_progress *style, const struct nk_input *in)
14958 {
14959 float prog_scale;
14960 nk_size prog_value;
14961 struct nk_rect cursor;
14962
14963 NK_ASSERT(style);
14964 NK_ASSERT(out);
14965 if (!out || !style) return 0;
14966
14967 /* calculate progressbar cursor */
14968 cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);
14969 cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);
14970 cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));
14971 prog_scale = (float)value / (float)max;
14972 cursor.w = (bounds.w - 2) * prog_scale;
14973
14974 /* update progressbar */
14975 prog_value = NK_MIN(value, max);
14976 prog_value = nk_progress_behavior(state, in, bounds, max, prog_value, modifiable);
14977
14978 /* draw progressbar */
14979 if (style->draw_begin) style->draw_begin(out, style->userdata);
14980 nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);
14981 if (style->draw_end) style->draw_end(out, style->userdata);
14982 return prog_value;
14983 }
14984
14985 /* ===============================================================
14986 *
14987 * SCROLLBAR
14988 *
14989 * ===============================================================*/
14990 NK_INTERN float
14991 nk_scrollbar_behavior(nk_flags *state, struct nk_input *in,
14992 int has_scrolling, const struct nk_rect *scroll,
14993 const struct nk_rect *cursor, const struct nk_rect *empty0,
14994 const struct nk_rect *empty1, float scroll_offset,
14995 float target, float scroll_step, enum nk_orientation o)
14996 {
14997 nk_flags ws = 0;
14998 int left_mouse_down;
14999 int left_mouse_click_in_cursor;
15000 float scroll_delta;
15001
15002 nk_widget_state_reset(state);
15003 if (!in) return scroll_offset;
15004
15005 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
15006 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
15007 NK_BUTTON_LEFT, *cursor, nk_true);
15008 if (nk_input_is_mouse_hovering_rect(in, *scroll))
15009 *state = NK_WIDGET_STATE_HOVERED;
15010
15011 scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;
15012 if (left_mouse_down && left_mouse_click_in_cursor) {
15013 /* update cursor by mouse dragging */
15014 float pixel, delta;
15015 *state = NK_WIDGET_STATE_ACTIVE;
15016 if (o == NK_VERTICAL) {
15017 float cursor_y;
15018 pixel = in->mouse.delta.y;
15019 delta = (pixel / scroll->h) * target;
15020 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);
15021 cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);
15022 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;
15023 } else {
15024 float cursor_x;
15025 pixel = in->mouse.delta.x;
15026 delta = (pixel / scroll->w) * target;
15027 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);
15028 cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);
15029 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;
15030 }
15031 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||
15032 nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {
15033 /* scroll page up by click on empty space or shortcut */
15034 if (o == NK_VERTICAL)
15035 scroll_offset = NK_MAX(0, scroll_offset - scroll->h);
15036 else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);
15037 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||
15038 nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {
15039 /* scroll page down by click on empty space or shortcut */
15040 if (o == NK_VERTICAL)
15041 scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);
15042 else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);
15043 } else if (has_scrolling) {
15044 if ((scroll_delta < 0 || (scroll_delta > 0))) {
15045 /* update cursor by mouse scrolling */
15046 scroll_offset = scroll_offset + scroll_step * (-scroll_delta);
15047 if (o == NK_VERTICAL)
15048 scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);
15049 else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);
15050 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {
15051 /* update cursor to the beginning */
15052 if (o == NK_VERTICAL) scroll_offset = 0;
15053 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {
15054 /* update cursor to the end */
15055 if (o == NK_VERTICAL) scroll_offset = target - scroll->h;
15056 }
15057 }
15058 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))
15059 *state |= NK_WIDGET_STATE_ENTERED;
15060 else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))
15061 *state |= NK_WIDGET_STATE_LEFT;
15062 return scroll_offset;
15063 }
15064
15065 NK_INTERN void
15066 nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,
15067 const struct nk_style_scrollbar *style, const struct nk_rect *bounds,
15068 const struct nk_rect *scroll)
15069 {
15070 const struct nk_style_item *background;
15071 const struct nk_style_item *cursor;
15072
15073 /* select correct colors/images to draw */
15074 if (state & NK_WIDGET_STATE_ACTIVED) {
15075 background = &style->active;
15076 cursor = &style->cursor_active;
15077 } else if (state & NK_WIDGET_STATE_HOVER) {
15078 background = &style->hover;
15079 cursor = &style->cursor_hover;
15080 } else {
15081 background = &style->normal;
15082 cursor = &style->cursor_normal;
15083 }
15084
15085 /* draw background */
15086 if (background->type == NK_STYLE_ITEM_COLOR) {
15087 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
15088 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
15089 } else {
15090 nk_draw_image(out, *bounds, &background->data.image, nk_white);
15091 }
15092
15093 /* draw cursor */
15094 if (background->type == NK_STYLE_ITEM_COLOR) {
15095 nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);
15096 nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);
15097 } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white);
15098 }
15099
15100 NK_INTERN float
15101 nk_do_scrollbarv(nk_flags *state,
15102 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
15103 float offset, float target, float step, float button_pixel_inc,
15104 const struct nk_style_scrollbar *style, struct nk_input *in,
15105 const struct nk_user_font *font)
15106 {
15107 struct nk_rect empty_north;
15108 struct nk_rect empty_south;
15109 struct nk_rect cursor;
15110
15111 float scroll_step;
15112 float scroll_offset;
15113 float scroll_off;
15114 float scroll_ratio;
15115
15116 NK_ASSERT(out);
15117 NK_ASSERT(style);
15118 NK_ASSERT(state);
15119 if (!out || !style) return 0;
15120
15121 scroll.w = NK_MAX(scroll.w, 1);
15122 scroll.h = NK_MAX(scroll.h, 0);
15123 if (target <= scroll.h) return 0;
15124
15125 /* optional scrollbar buttons */
15126 if (style->show_buttons) {
15127 nk_flags ws;
15128 float scroll_h;
15129 struct nk_rect button;
15130
15131 button.x = scroll.x;
15132 button.w = scroll.w;
15133 button.h = scroll.w;
15134
15135 scroll_h = NK_MAX(scroll.h - 2 * button.h,0);
15136 scroll_step = NK_MIN(step, button_pixel_inc);
15137
15138 /* decrement button */
15139 button.y = scroll.y;
15140 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
15141 NK_BUTTON_REPEATER, &style->dec_button, in, font))
15142 offset = offset - scroll_step;
15143
15144 /* increment button */
15145 button.y = scroll.y + scroll.h - button.h;
15146 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
15147 NK_BUTTON_REPEATER, &style->inc_button, in, font))
15148 offset = offset + scroll_step;
15149
15150 scroll.y = scroll.y + button.h;
15151 scroll.h = scroll_h;
15152 }
15153
15154 /* calculate scrollbar constants */
15155 scroll_step = NK_MIN(step, scroll.h);
15156 scroll_offset = NK_CLAMP(0, offset, target - scroll.h);
15157 scroll_ratio = scroll.h / target;
15158 scroll_off = scroll_offset / target;
15159
15160 /* calculate scrollbar cursor bounds */
15161 cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0);
15162 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;
15163 cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);
15164 cursor.x = scroll.x + style->border + style->padding.x;
15165
15166 /* calculate empty space around cursor */
15167 empty_north.x = scroll.x;
15168 empty_north.y = scroll.y;
15169 empty_north.w = scroll.w;
15170 empty_north.h = NK_MAX(cursor.y - scroll.y, 0);
15171
15172 empty_south.x = scroll.x;
15173 empty_south.y = cursor.y + cursor.h;
15174 empty_south.w = scroll.w;
15175 empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0);
15176
15177 /* update scrollbar */
15178 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
15179 &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);
15180 scroll_off = scroll_offset / target;
15181 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;
15182
15183 /* draw scrollbar */
15184 if (style->draw_begin) style->draw_begin(out, style->userdata);
15185 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
15186 if (style->draw_end) style->draw_end(out, style->userdata);
15187 return scroll_offset;
15188 }
15189
15190 NK_INTERN float
15191 nk_do_scrollbarh(nk_flags *state,
15192 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
15193 float offset, float target, float step, float button_pixel_inc,
15194 const struct nk_style_scrollbar *style, struct nk_input *in,
15195 const struct nk_user_font *font)
15196 {
15197 struct nk_rect cursor;
15198 struct nk_rect empty_west;
15199 struct nk_rect empty_east;
15200
15201 float scroll_step;
15202 float scroll_offset;
15203 float scroll_off;
15204 float scroll_ratio;
15205
15206 NK_ASSERT(out);
15207 NK_ASSERT(style);
15208 if (!out || !style) return 0;
15209
15210 /* scrollbar background */
15211 scroll.h = NK_MAX(scroll.h, 1);
15212 scroll.w = NK_MAX(scroll.w, 2 * scroll.h);
15213 if (target <= scroll.w) return 0;
15214
15215 /* optional scrollbar buttons */
15216 if (style->show_buttons) {
15217 nk_flags ws;
15218 float scroll_w;
15219 struct nk_rect button;
15220 button.y = scroll.y;
15221 button.w = scroll.h;
15222 button.h = scroll.h;
15223
15224 scroll_w = scroll.w - 2 * button.w;
15225 scroll_step = NK_MIN(step, button_pixel_inc);
15226
15227 /* decrement button */
15228 button.x = scroll.x;
15229 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
15230 NK_BUTTON_REPEATER, &style->dec_button, in, font))
15231 offset = offset - scroll_step;
15232
15233 /* increment button */
15234 button.x = scroll.x + scroll.w - button.w;
15235 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
15236 NK_BUTTON_REPEATER, &style->inc_button, in, font))
15237 offset = offset + scroll_step;
15238
15239 scroll.x = scroll.x + button.w;
15240 scroll.w = scroll_w;
15241 }
15242
15243 /* calculate scrollbar constants */
15244 scroll_step = NK_MIN(step, scroll.w);
15245 scroll_offset = NK_CLAMP(0, offset, target - scroll.w);
15246 scroll_ratio = scroll.w / target;
15247 scroll_off = scroll_offset / target;
15248
15249 /* calculate cursor bounds */
15250 cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);
15251 cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;
15252 cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);
15253 cursor.y = scroll.y + style->border + style->padding.y;
15254
15255 /* calculate empty space around cursor */
15256 empty_west.x = scroll.x;
15257 empty_west.y = scroll.y;
15258 empty_west.w = cursor.x - scroll.x;
15259 empty_west.h = scroll.h;
15260
15261 empty_east.x = cursor.x + cursor.w;
15262 empty_east.y = scroll.y;
15263 empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);
15264 empty_east.h = scroll.h;
15265
15266 /* update scrollbar */
15267 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
15268 &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);
15269 scroll_off = scroll_offset / target;
15270 cursor.x = scroll.x + (scroll_off * scroll.w);
15271
15272 /* draw scrollbar */
15273 if (style->draw_begin) style->draw_begin(out, style->userdata);
15274 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
15275 if (style->draw_end) style->draw_end(out, style->userdata);
15276 return scroll_offset;
15277 }
15278
15279 /* ===============================================================
15280 *
15281 * FILTER
15282 *
15283 * ===============================================================*/
15284 NK_API int nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
15285 {(void)unicode;NK_UNUSED(box);return nk_true;}
15286
15287 NK_API int
15288 nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)
15289 {
15290 NK_UNUSED(box);
15291 if (unicode > 128) return nk_false;
15292 else return nk_true;
15293 }
15294
15295 NK_API int
15296 nk_filter_float(const struct nk_text_edit *box, nk_rune unicode)
15297 {
15298 NK_UNUSED(box);
15299 if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
15300 return nk_false;
15301 else return nk_true;
15302 }
15303
15304 NK_API int
15305 nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)
15306 {
15307 NK_UNUSED(box);
15308 if ((unicode < '0' || unicode > '9') && unicode != '-')
15309 return nk_false;
15310 else return nk_true;
15311 }
15312
15313 NK_API int
15314 nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)
15315 {
15316 NK_UNUSED(box);
15317 if ((unicode < '0' || unicode > '9') &&
15318 (unicode < 'a' || unicode > 'f') &&
15319 (unicode < 'A' || unicode > 'F'))
15320 return nk_false;
15321 else return nk_true;
15322 }
15323
15324 NK_API int
15325 nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)
15326 {
15327 NK_UNUSED(box);
15328 if (unicode < '0' || unicode > '7')
15329 return nk_false;
15330 else return nk_true;
15331 }
15332
15333 NK_API int
15334 nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)
15335 {
15336 NK_UNUSED(box);
15337 if (unicode != '0' && unicode != '1')
15338 return nk_false;
15339 else return nk_true;
15340 }
15341
15342 /* ===============================================================
15343 *
15344 * EDIT
15345 *
15346 * ===============================================================*/
15347 NK_INTERN void
15348 nk_edit_draw_text(struct nk_command_buffer *out,
15349 const struct nk_style_edit *style, float pos_x, float pos_y,
15350 float x_offset, const char *text, int byte_len, float row_height,
15351 const struct nk_user_font *font, struct nk_color background,
15352 struct nk_color foreground, int is_selected)
15353 {
15354 NK_ASSERT(out);
15355 NK_ASSERT(font);
15356 NK_ASSERT(style);
15357 if (!text || !byte_len || !out || !style) return;
15358
15359 {int glyph_len = 0;
15360 nk_rune unicode = 0;
15361 int text_len = 0;
15362 float line_width = 0;
15363 float glyph_width;
15364 const char *line = text;
15365 float line_offset = 0;
15366 int line_count = 0;
15367
15368 struct nk_text txt;
15369 txt.padding = nk_vec2(0,0);
15370 txt.background = background;
15371 txt.text = foreground;
15372
15373 glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
15374 if (!glyph_len) return;
15375 while ((text_len < byte_len) && glyph_len)
15376 {
15377 if (unicode == '\n') {
15378 /* new line separator so draw previous line */
15379 struct nk_rect label;
15380 label.y = pos_y + line_offset;
15381 label.h = row_height;
15382 label.w = line_width;
15383 label.x = pos_x;
15384 if (!line_count)
15385 label.x += x_offset;
15386
15387 if (is_selected) /* selection needs to draw different background color */
15388 nk_fill_rect(out, label, 0, background);
15389 nk_widget_text(out, label, line, (int)((text + text_len) - line),
15390 &txt, NK_TEXT_CENTERED, font);
15391
15392 text_len++;
15393 line_count++;
15394 line_width = 0;
15395 line = text + text_len;
15396 line_offset += row_height;
15397 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));
15398 continue;
15399 }
15400 if (unicode == '\r') {
15401 text_len++;
15402 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
15403 continue;
15404 }
15405 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
15406 line_width += (float)glyph_width;
15407 text_len += glyph_len;
15408 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
15409 continue;
15410 }
15411 if (line_width > 0) {
15412 /* draw last line */
15413 struct nk_rect label;
15414 label.y = pos_y + line_offset;
15415 label.h = row_height;
15416 label.w = line_width;
15417 label.x = pos_x;
15418 if (!line_count)
15419 label.x += x_offset;
15420
15421 if (is_selected)
15422 nk_fill_rect(out, label, 0, background);
15423 nk_widget_text(out, label, line, (int)((text + text_len) - line),
15424 &txt, NK_TEXT_LEFT, font);
15425 }}
15426 }
15427
15428 NK_INTERN nk_flags
15429 nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
15430 struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,
15431 struct nk_text_edit *edit, const struct nk_style_edit *style,
15432 struct nk_input *in, const struct nk_user_font *font)
15433 {
15434 struct nk_rect area;
15435 nk_flags ret = 0;
15436 float row_height;
15437 char prev_state = 0;
15438 char is_hovered = 0;
15439 char select_all = 0;
15440 char cursor_follow = 0;
15441 struct nk_rect old_clip;
15442 struct nk_rect clip;
15443
15444 NK_ASSERT(state);
15445 NK_ASSERT(out);
15446 NK_ASSERT(style);
15447 if (!state || !out || !style)
15448 return ret;
15449
15450 /* visible text area calculation */
15451 area.x = bounds.x + style->padding.x + style->border;
15452 area.y = bounds.y + style->padding.y + style->border;
15453 area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);
15454 area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);
15455 if (flags & NK_EDIT_MULTILINE)
15456 area.w = NK_MAX(0, area.w - style->scrollbar_size.x);
15457 row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;
15458
15459 /* calculate clipping rectangle */
15460 old_clip = out->clip;
15461 nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
15462
15463 /* update edit state */
15464 prev_state = (char)edit->active;
15465 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds);
15466 if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {
15467 edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,
15468 bounds.x, bounds.y, bounds.w, bounds.h);
15469 }
15470
15471 /* (de)activate text editor */
15472 if (!prev_state && edit->active) {
15473 const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?
15474 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;
15475 nk_textedit_clear_state(edit, type, filter);
15476 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
15477 edit->mode = NK_TEXT_EDIT_MODE_INSERT;
15478 if (flags & NK_EDIT_AUTO_SELECT)
15479 select_all = nk_true;
15480 if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {
15481 edit->cursor = edit->string.len;
15482 in = 0;
15483 }
15484 } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;
15485 if (flags & NK_EDIT_READ_ONLY)
15486 edit->mode = NK_TEXT_EDIT_MODE_VIEW;
15487
15488 ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;
15489 if (prev_state != edit->active)
15490 ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;
15491
15492 /* handle user input */
15493 if (edit->active && in)
15494 {
15495 int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;
15496 const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;
15497 const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;
15498
15499 /* mouse click handler */
15500 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);
15501 if (select_all) {
15502 nk_textedit_select_all(edit);
15503 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
15504 in->mouse.buttons[NK_BUTTON_LEFT].clicked) {
15505 nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);
15506 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
15507 (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) {
15508 nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);
15509 cursor_follow = nk_true;
15510 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&
15511 in->mouse.buttons[NK_BUTTON_RIGHT].down) {
15512 nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);
15513 nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);
15514 cursor_follow = nk_true;
15515 }
15516
15517 {int i; /* keyboard input */
15518 int old_mode = edit->mode;
15519 for (i = 0; i < NK_KEY_MAX; ++i) {
15520 if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */
15521 if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {
15522 nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);
15523 cursor_follow = nk_true;
15524 }
15525 }
15526 if (old_mode != edit->mode) {
15527 in->keyboard.text_len = 0;
15528 }}
15529
15530 /* text input */
15531 edit->filter = filter;
15532 if (in->keyboard.text_len) {
15533 nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);
15534 cursor_follow = nk_true;
15535 in->keyboard.text_len = 0;
15536 }
15537
15538 /* enter key handler */
15539 if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {
15540 cursor_follow = nk_true;
15541 if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)
15542 nk_textedit_text(edit, "\n", 1);
15543 else if (flags & NK_EDIT_SIG_ENTER)
15544 ret |= NK_EDIT_COMMITED;
15545 else nk_textedit_text(edit, "\n", 1);
15546 }
15547
15548 /* cut & copy handler */
15549 {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);
15550 int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);
15551 if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))
15552 {
15553 int glyph_len;
15554 nk_rune unicode;
15555 const char *text;
15556 int b = edit->select_start;
15557 int e = edit->select_end;
15558
15559 int begin = NK_MIN(b, e);
15560 int end = NK_MAX(b, e);
15561 text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);
15562 if (edit->clip.copy)
15563 edit->clip.copy(edit->clip.userdata, text, end - begin);
15564 if (cut && !(flags & NK_EDIT_READ_ONLY)){
15565 nk_textedit_cut(edit);
15566 cursor_follow = nk_true;
15567 }
15568 }}
15569
15570 /* paste handler */
15571 {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);
15572 if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {
15573 edit->clip.paste(edit->clip.userdata, edit);
15574 cursor_follow = nk_true;
15575 }}
15576
15577 /* tab handler */
15578 {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);
15579 if (tab && (flags & NK_EDIT_ALLOW_TAB)) {
15580 nk_textedit_text(edit, " ", 4);
15581 cursor_follow = nk_true;
15582 }}
15583 }
15584
15585 /* set widget state */
15586 if (edit->active)
15587 *state = NK_WIDGET_STATE_ACTIVE;
15588 else nk_widget_state_reset(state);
15589
15590 if (is_hovered)
15591 *state |= NK_WIDGET_STATE_HOVERED;
15592
15593 /* DRAW EDIT */
15594 {const char *text = nk_str_get_const(&edit->string);
15595 int len = nk_str_len_char(&edit->string);
15596
15597 {/* select background colors/images */
15598 const struct nk_style_item *background;
15599 if (*state & NK_WIDGET_STATE_ACTIVED)
15600 background = &style->active;
15601 else if (*state & NK_WIDGET_STATE_HOVER)
15602 background = &style->hover;
15603 else background = &style->normal;
15604
15605 /* draw background frame */
15606 if (background->type == NK_STYLE_ITEM_COLOR) {
15607 nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color);
15608 nk_fill_rect(out, bounds, style->rounding, background->data.color);
15609 } else nk_draw_image(out, bounds, &background->data.image, nk_white);}
15610
15611 area.w = NK_MAX(0, area.w - style->cursor_size);
15612 if (edit->active)
15613 {
15614 int total_lines = 1;
15615 struct nk_vec2 text_size = nk_vec2(0,0);
15616
15617 /* text pointer positions */
15618 const char *cursor_ptr = 0;
15619 const char *select_begin_ptr = 0;
15620 const char *select_end_ptr = 0;
15621
15622 /* 2D pixel positions */
15623 struct nk_vec2 cursor_pos = nk_vec2(0,0);
15624 struct nk_vec2 selection_offset_start = nk_vec2(0,0);
15625 struct nk_vec2 selection_offset_end = nk_vec2(0,0);
15626
15627 int selection_begin = NK_MIN(edit->select_start, edit->select_end);
15628 int selection_end = NK_MAX(edit->select_start, edit->select_end);
15629
15630 /* calculate total line count + total space + cursor/selection position */
15631 float line_width = 0.0f;
15632 if (text && len)
15633 {
15634 /* utf8 encoding */
15635 float glyph_width;
15636 int glyph_len = 0;
15637 nk_rune unicode = 0;
15638 int text_len = 0;
15639 int glyphs = 0;
15640 int row_begin = 0;
15641
15642 glyph_len = nk_utf_decode(text, &unicode, len);
15643 glyph_width = font->width(font->userdata, font->height, text, glyph_len);
15644 line_width = 0;
15645
15646 /* iterate all lines */
15647 while ((text_len < len) && glyph_len)
15648 {
15649 /* set cursor 2D position and line */
15650 if (!cursor_ptr && glyphs == edit->cursor)
15651 {
15652 int glyph_offset;
15653 struct nk_vec2 out_offset;
15654 struct nk_vec2 row_size;
15655 const char *remaining;
15656
15657 /* calculate 2d position */
15658 cursor_pos.y = (float)(total_lines-1) * row_height;
15659 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15660 text_len-row_begin, row_height, &remaining,
15661 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15662 cursor_pos.x = row_size.x;
15663 cursor_ptr = text + text_len;
15664 }
15665
15666 /* set start selection 2D position and line */
15667 if (!select_begin_ptr && edit->select_start != edit->select_end &&
15668 glyphs == selection_begin)
15669 {
15670 int glyph_offset;
15671 struct nk_vec2 out_offset;
15672 struct nk_vec2 row_size;
15673 const char *remaining;
15674
15675 /* calculate 2d position */
15676 selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;
15677 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15678 text_len-row_begin, row_height, &remaining,
15679 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15680 selection_offset_start.x = row_size.x;
15681 select_begin_ptr = text + text_len;
15682 }
15683
15684 /* set end selection 2D position and line */
15685 if (!select_end_ptr && edit->select_start != edit->select_end &&
15686 glyphs == selection_end)
15687 {
15688 int glyph_offset;
15689 struct nk_vec2 out_offset;
15690 struct nk_vec2 row_size;
15691 const char *remaining;
15692
15693 /* calculate 2d position */
15694 selection_offset_end.y = (float)(total_lines-1) * row_height;
15695 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
15696 text_len-row_begin, row_height, &remaining,
15697 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
15698 selection_offset_end.x = row_size.x;
15699 select_end_ptr = text + text_len;
15700 }
15701 if (unicode == '\n') {
15702 text_size.x = NK_MAX(text_size.x, line_width);
15703 total_lines++;
15704 line_width = 0;
15705 text_len++;
15706 glyphs++;
15707 row_begin = text_len;
15708 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
15709 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
15710 continue;
15711 }
15712
15713 glyphs++;
15714 text_len += glyph_len;
15715 line_width += (float)glyph_width;
15716
15717 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
15718 glyph_width = font->width(font->userdata, font->height,
15719 text+text_len, glyph_len);
15720 continue;
15721 }
15722 text_size.y = (float)total_lines * row_height;
15723
15724 /* handle case when cursor is at end of text buffer */
15725 if (!cursor_ptr && edit->cursor == edit->string.len) {
15726 cursor_pos.x = line_width;
15727 cursor_pos.y = text_size.y - row_height;
15728 }
15729 }
15730 {
15731 /* scrollbar */
15732 if (cursor_follow)
15733 {
15734 /* update scrollbar to follow cursor */
15735 if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {
15736 /* horizontal scroll */
15737 const float scroll_increment = area.w * 0.25f;
15738 if (cursor_pos.x < edit->scrollbar.x)
15739 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);
15740 if (cursor_pos.x >= edit->scrollbar.x + area.w)
15741 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x);
15742 } else edit->scrollbar.x = 0;
15743
15744 if (flags & NK_EDIT_MULTILINE) {
15745 /* vertical scroll */
15746 if (cursor_pos.y < edit->scrollbar.y)
15747 edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height);
15748 if (cursor_pos.y >= edit->scrollbar.y + area.h)
15749 edit->scrollbar.y = edit->scrollbar.y + row_height;
15750 } else edit->scrollbar.y = 0;
15751 }
15752
15753 /* scrollbar widget */
15754 if (flags & NK_EDIT_MULTILINE)
15755 {
15756 nk_flags ws;
15757 struct nk_rect scroll;
15758 float scroll_target;
15759 float scroll_offset;
15760 float scroll_step;
15761 float scroll_inc;
15762
15763 scroll = area;
15764 scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;
15765 scroll.w = style->scrollbar_size.x;
15766
15767 scroll_offset = edit->scrollbar.y;
15768 scroll_step = scroll.h * 0.10f;
15769 scroll_inc = scroll.h * 0.01f;
15770 scroll_target = text_size.y;
15771 edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, 0,
15772 scroll_offset, scroll_target, scroll_step, scroll_inc,
15773 &style->scrollbar, in, font);
15774 }
15775 }
15776
15777 /* draw text */
15778 {struct nk_color background_color;
15779 struct nk_color text_color;
15780 struct nk_color sel_background_color;
15781 struct nk_color sel_text_color;
15782 struct nk_color cursor_color;
15783 struct nk_color cursor_text_color;
15784 const struct nk_style_item *background;
15785 nk_push_scissor(out, clip);
15786
15787 /* select correct colors to draw */
15788 if (*state & NK_WIDGET_STATE_ACTIVED) {
15789 background = &style->active;
15790 text_color = style->text_active;
15791 sel_text_color = style->selected_text_hover;
15792 sel_background_color = style->selected_hover;
15793 cursor_color = style->cursor_hover;
15794 cursor_text_color = style->cursor_text_hover;
15795 } else if (*state & NK_WIDGET_STATE_HOVER) {
15796 background = &style->hover;
15797 text_color = style->text_hover;
15798 sel_text_color = style->selected_text_hover;
15799 sel_background_color = style->selected_hover;
15800 cursor_text_color = style->cursor_text_hover;
15801 cursor_color = style->cursor_hover;
15802 } else {
15803 background = &style->normal;
15804 text_color = style->text_normal;
15805 sel_text_color = style->selected_text_normal;
15806 sel_background_color = style->selected_normal;
15807 cursor_color = style->cursor_normal;
15808 cursor_text_color = style->cursor_text_normal;
15809 }
15810 if (background->type == NK_STYLE_ITEM_IMAGE)
15811 background_color = nk_rgba(0,0,0,0);
15812 else background_color = background->data.color;
15813
15814
15815 if (edit->select_start == edit->select_end) {
15816 /* no selection so just draw the complete text */
15817 const char *begin = nk_str_get_const(&edit->string);
15818 int l = nk_str_len_char(&edit->string);
15819 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15820 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
15821 background_color, text_color, nk_false);
15822 } else {
15823 /* edit has selection so draw 1-3 text chunks */
15824 if (edit->select_start != edit->select_end && selection_begin > 0){
15825 /* draw unselected text before selection */
15826 const char *begin = nk_str_get_const(&edit->string);
15827 NK_ASSERT(select_begin_ptr);
15828 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15829 area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),
15830 row_height, font, background_color, text_color, nk_false);
15831 }
15832 if (edit->select_start != edit->select_end) {
15833 /* draw selected text */
15834 NK_ASSERT(select_begin_ptr);
15835 if (!select_end_ptr) {
15836 const char *begin = nk_str_get_const(&edit->string);
15837 select_end_ptr = begin + nk_str_len_char(&edit->string);
15838 }
15839 nk_edit_draw_text(out, style,
15840 area.x - edit->scrollbar.x,
15841 area.y + selection_offset_start.y - edit->scrollbar.y,
15842 selection_offset_start.x,
15843 select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),
15844 row_height, font, sel_background_color, sel_text_color, nk_true);
15845 }
15846 if ((edit->select_start != edit->select_end &&
15847 selection_end < edit->string.len))
15848 {
15849 /* draw unselected text after selected text */
15850 const char *begin = select_end_ptr;
15851 const char *end = nk_str_get_const(&edit->string) +
15852 nk_str_len_char(&edit->string);
15853 NK_ASSERT(select_end_ptr);
15854 nk_edit_draw_text(out, style,
15855 area.x - edit->scrollbar.x,
15856 area.y + selection_offset_end.y - edit->scrollbar.y,
15857 selection_offset_end.x,
15858 begin, (int)(end - begin), row_height, font,
15859 background_color, text_color, nk_true);
15860 }
15861 }
15862
15863 /* cursor */
15864 if (edit->select_start == edit->select_end)
15865 {
15866 if (edit->cursor >= nk_str_len(&edit->string) ||
15867 (cursor_ptr && *cursor_ptr == '\n')) {
15868 /* draw cursor at end of line */
15869 struct nk_rect cursor;
15870 cursor.w = style->cursor_size;
15871 cursor.h = font->height;
15872 cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;
15873 cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;
15874 cursor.y -= edit->scrollbar.y;
15875 nk_fill_rect(out, cursor, 0, cursor_color);
15876 } else {
15877 /* draw cursor inside text */
15878 int glyph_len;
15879 struct nk_rect label;
15880 struct nk_text txt;
15881
15882 nk_rune unicode;
15883 NK_ASSERT(cursor_ptr);
15884 glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);
15885
15886 label.x = area.x + cursor_pos.x - edit->scrollbar.x;
15887 label.y = area.y + cursor_pos.y - edit->scrollbar.y;
15888 label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);
15889 label.h = row_height;
15890
15891 txt.padding = nk_vec2(0,0);
15892 txt.background = cursor_color;;
15893 txt.text = cursor_text_color;
15894 nk_fill_rect(out, label, 0, cursor_color);
15895 nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);
15896 }
15897 }}
15898 } else {
15899 /* not active so just draw text */
15900 int l = nk_str_len_char(&edit->string);
15901 const char *begin = nk_str_get_const(&edit->string);
15902
15903 const struct nk_style_item *background;
15904 struct nk_color background_color;
15905 struct nk_color text_color;
15906 nk_push_scissor(out, clip);
15907 if (*state & NK_WIDGET_STATE_ACTIVED) {
15908 background = &style->active;
15909 text_color = style->text_active;
15910 } else if (*state & NK_WIDGET_STATE_HOVER) {
15911 background = &style->hover;
15912 text_color = style->text_hover;
15913 } else {
15914 background = &style->normal;
15915 text_color = style->text_normal;
15916 }
15917 if (background->type == NK_STYLE_ITEM_IMAGE)
15918 background_color = nk_rgba(0,0,0,0);
15919 else background_color = background->data.color;
15920 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
15921 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
15922 background_color, text_color, nk_false);
15923 }
15924 nk_push_scissor(out, old_clip);}
15925 return ret;
15926 }
15927
15928 /* ===============================================================
15929 *
15930 * PROPERTY
15931 *
15932 * ===============================================================*/
15933 enum nk_property_status {
15934 NK_PROPERTY_DEFAULT,
15935 NK_PROPERTY_EDIT,
15936 NK_PROPERTY_DRAG
15937 };
15938 enum nk_property_filter {
15939 NK_FILTER_INT,
15940 NK_FILTER_FLOAT
15941 };
15942 enum nk_property_kind {
15943 NK_PROPERTY_INT,
15944 NK_PROPERTY_FLOAT,
15945 NK_PROPERTY_DOUBLE
15946 };
15947 union nk_property {
15948 int i;
15949 float f;
15950 double d;
15951 };
15952 struct nk_property_variant {
15953 enum nk_property_kind kind;
15954 union nk_property value;
15955 union nk_property min_value;
15956 union nk_property max_value;
15957 union nk_property step;
15958 };
15959
15960 NK_INTERN void
15961 nk_drag_behavior(nk_flags *state, const struct nk_input *in,
15962 struct nk_rect drag, struct nk_property_variant *variant,
15963 float inc_per_pixel)
15964 {
15965 int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
15966 int left_mouse_click_in_cursor = in &&
15967 nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);
15968
15969 nk_widget_state_reset(state);
15970 if (nk_input_is_mouse_hovering_rect(in, drag))
15971 *state = NK_WIDGET_STATE_HOVERED;
15972
15973 if (left_mouse_down && left_mouse_click_in_cursor) {
15974 float delta, pixels;
15975 pixels = in->mouse.delta.x;
15976 delta = pixels * inc_per_pixel;
15977 switch (variant->kind) {
15978 default: break;
15979 case NK_PROPERTY_INT:
15980 variant->value.i = variant->value.i + (int)delta;
15981 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
15982 break;
15983 case NK_PROPERTY_FLOAT:
15984 variant->value.f = variant->value.f + (float)delta;
15985 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
15986 break;
15987 case NK_PROPERTY_DOUBLE:
15988 variant->value.d = variant->value.d + (double)delta;
15989 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
15990 break;
15991 }
15992 *state = NK_WIDGET_STATE_ACTIVE;
15993 }
15994 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))
15995 *state |= NK_WIDGET_STATE_ENTERED;
15996 else if (nk_input_is_mouse_prev_hovering_rect(in, drag))
15997 *state |= NK_WIDGET_STATE_LEFT;
15998 }
15999
16000 NK_INTERN void
16001 nk_property_behavior(nk_flags *ws, const struct nk_input *in,
16002 struct nk_rect property, struct nk_rect label, struct nk_rect edit,
16003 struct nk_rect empty, int *state, struct nk_property_variant *variant,
16004 float inc_per_pixel)
16005 {
16006 if (in && *state == NK_PROPERTY_DEFAULT) {
16007 if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))
16008 *state = NK_PROPERTY_EDIT;
16009 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))
16010 *state = NK_PROPERTY_DRAG;
16011 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))
16012 *state = NK_PROPERTY_DRAG;
16013 }
16014 if (*state == NK_PROPERTY_DRAG) {
16015 nk_drag_behavior(ws, in, property, variant, inc_per_pixel);
16016 if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;
16017 }
16018 }
16019
16020 NK_INTERN void
16021 nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,
16022 const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,
16023 const char *name, int len, const struct nk_user_font *font)
16024 {
16025 struct nk_text text;
16026 const struct nk_style_item *background;
16027
16028 /* select correct background and text color */
16029 if (state & NK_WIDGET_STATE_ACTIVED) {
16030 background = &style->active;
16031 text.text = style->label_active;
16032 } else if (state & NK_WIDGET_STATE_HOVER) {
16033 background = &style->hover;
16034 text.text = style->label_hover;
16035 } else {
16036 background = &style->normal;
16037 text.text = style->label_normal;
16038 }
16039
16040 /* draw background */
16041 if (background->type == NK_STYLE_ITEM_IMAGE) {
16042 nk_draw_image(out, *bounds, &background->data.image, nk_white);
16043 text.background = nk_rgba(0,0,0,0);
16044 } else {
16045 text.background = background->data.color;
16046 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
16047 nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color);
16048 }
16049
16050 /* draw label */
16051 text.padding = nk_vec2(0,0);
16052 nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
16053 }
16054
16055 NK_INTERN void
16056 nk_do_property(nk_flags *ws,
16057 struct nk_command_buffer *out, struct nk_rect property,
16058 const char *name, struct nk_property_variant *variant,
16059 float inc_per_pixel, char *buffer, int *len,
16060 int *state, int *cursor, int *select_begin, int *select_end,
16061 const struct nk_style_property *style,
16062 enum nk_property_filter filter, struct nk_input *in,
16063 const struct nk_user_font *font, struct nk_text_edit *text_edit,
16064 enum nk_button_behavior behavior)
16065 {
16066 const nk_plugin_filter filters[] = {
16067 nk_filter_decimal,
16068 nk_filter_float
16069 };
16070 int active, old;
16071 int num_len, name_len;
16072 char string[NK_MAX_NUMBER_BUFFER];
16073 float size;
16074
16075 char *dst = 0;
16076 int *length;
16077
16078 struct nk_rect left;
16079 struct nk_rect right;
16080 struct nk_rect label;
16081 struct nk_rect edit;
16082 struct nk_rect empty;
16083
16084 /* left decrement button */
16085 left.h = font->height/2;
16086 left.w = left.h;
16087 left.x = property.x + style->border + style->padding.x;
16088 left.y = property.y + style->border + property.h/2.0f - left.h/2;
16089
16090 /* text label */
16091 name_len = nk_strlen(name);
16092 size = font->width(font->userdata, font->height, name, name_len);
16093 label.x = left.x + left.w + style->padding.x;
16094 label.w = (float)size + 2 * style->padding.x;
16095 label.y = property.y + style->border + style->padding.y;
16096 label.h = property.h - (2 * style->border + 2 * style->padding.y);
16097
16098 /* right increment button */
16099 right.y = left.y;
16100 right.w = left.w;
16101 right.h = left.h;
16102 right.x = property.x + property.w - (right.w + style->padding.x);
16103
16104 /* edit */
16105 if (*state == NK_PROPERTY_EDIT) {
16106 size = font->width(font->userdata, font->height, buffer, *len);
16107 size += style->edit.cursor_size;
16108 length = len;
16109 dst = buffer;
16110 } else {
16111 switch (variant->kind) {
16112 default: break;
16113 case NK_PROPERTY_INT:
16114 nk_itoa(string, variant->value.i);
16115 num_len = nk_strlen(string);
16116 break;
16117 case NK_PROPERTY_FLOAT:
16118 nk_dtoa(string, (double)variant->value.f);
16119 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
16120 break;
16121 case NK_PROPERTY_DOUBLE:
16122 nk_dtoa(string, variant->value.d);
16123 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
16124 break;
16125 }
16126 size = font->width(font->userdata, font->height, string, num_len);
16127 dst = string;
16128 length = &num_len;
16129 }
16130
16131 edit.w = (float)size + 2 * style->padding.x;
16132 edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));
16133 edit.x = right.x - (edit.w + style->padding.x);
16134 edit.y = property.y + style->border;
16135 edit.h = property.h - (2 * style->border);
16136
16137 /* empty left space activator */
16138 empty.w = edit.x - (label.x + label.w);
16139 empty.x = label.x + label.w;
16140 empty.y = property.y;
16141 empty.h = property.h;
16142
16143 /* update property */
16144 old = (*state == NK_PROPERTY_EDIT);
16145 nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);
16146
16147 /* draw property */
16148 if (style->draw_begin) style->draw_begin(out, style->userdata);
16149 nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);
16150 if (style->draw_end) style->draw_end(out, style->userdata);
16151
16152 /* execute right button */
16153 if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {
16154 switch (variant->kind) {
16155 default: break;
16156 case NK_PROPERTY_INT:
16157 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;
16158 case NK_PROPERTY_FLOAT:
16159 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;
16160 case NK_PROPERTY_DOUBLE:
16161 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;
16162 }
16163 }
16164 /* execute left button */
16165 if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {
16166 switch (variant->kind) {
16167 default: break;
16168 case NK_PROPERTY_INT:
16169 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;
16170 case NK_PROPERTY_FLOAT:
16171 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;
16172 case NK_PROPERTY_DOUBLE:
16173 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;
16174 }
16175 }
16176 if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) {
16177 /* property has been activated so setup buffer */
16178 NK_MEMCPY(buffer, dst, (nk_size)*length);
16179 *cursor = nk_utf_len(buffer, *length);
16180 *len = *length;
16181 length = len;
16182 dst = buffer;
16183 active = 0;
16184 } else active = (*state == NK_PROPERTY_EDIT);
16185
16186 /* execute and run text edit field */
16187 nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);
16188 text_edit->active = (unsigned char)active;
16189 text_edit->string.len = *length;
16190 text_edit->cursor = NK_CLAMP(0, *cursor, *length);
16191 text_edit->select_start = NK_CLAMP(0,*select_begin, *length);
16192 text_edit->select_end = NK_CLAMP(0,*select_end, *length);
16193 text_edit->string.buffer.allocated = (nk_size)*length;
16194 text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;
16195 text_edit->string.buffer.memory.ptr = dst;
16196 text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;
16197 text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;
16198 nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT,
16199 filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);
16200
16201 *length = text_edit->string.len;
16202 *cursor = text_edit->cursor;
16203 *select_begin = text_edit->select_start;
16204 *select_end = text_edit->select_end;
16205 if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))
16206 text_edit->active = nk_false;
16207
16208 if (active && !text_edit->active) {
16209 /* property is now not active so convert edit text to value*/
16210 *state = NK_PROPERTY_DEFAULT;
16211 buffer[*len] = '\0';
16212 switch (variant->kind) {
16213 default: break;
16214 case NK_PROPERTY_INT:
16215 variant->value.i = nk_strtoi(buffer, 0);
16216 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
16217 break;
16218 case NK_PROPERTY_FLOAT:
16219 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
16220 variant->value.f = nk_strtof(buffer, 0);
16221 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
16222 break;
16223 case NK_PROPERTY_DOUBLE:
16224 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
16225 variant->value.d = nk_strtod(buffer, 0);
16226 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
16227 break;
16228 }
16229 }
16230 }
16231 /* ===============================================================
16232 *
16233 * COLOR PICKER
16234 *
16235 * ===============================================================*/
16236 NK_INTERN int
16237 nk_color_picker_behavior(nk_flags *state,
16238 const struct nk_rect *bounds, const struct nk_rect *matrix,
16239 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
16240 struct nk_color *color, const struct nk_input *in)
16241 {
16242 float hsva[4];
16243 int value_changed = 0;
16244 int hsv_changed = 0;
16245
16246 NK_ASSERT(state);
16247 NK_ASSERT(matrix);
16248 NK_ASSERT(hue_bar);
16249 NK_ASSERT(color);
16250
16251 /* color matrix */
16252 nk_color_hsva_fv(hsva, *color);
16253 if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {
16254 hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));
16255 hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));
16256 value_changed = hsv_changed = 1;
16257 }
16258
16259 /* hue bar */
16260 if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {
16261 hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));
16262 value_changed = hsv_changed = 1;
16263 }
16264
16265 /* alpha bar */
16266 if (alpha_bar) {
16267 if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {
16268 hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));
16269 value_changed = 1;
16270 }
16271 }
16272 nk_widget_state_reset(state);
16273 if (hsv_changed) {
16274 *color = nk_hsva_fv(hsva);
16275 *state = NK_WIDGET_STATE_ACTIVE;
16276 }
16277 if (value_changed) {
16278 color->a = (nk_byte)(hsva[3] * 255.0f);
16279 *state = NK_WIDGET_STATE_ACTIVE;
16280 }
16281
16282 /* set color picker widget state */
16283 if (nk_input_is_mouse_hovering_rect(in, *bounds))
16284 *state = NK_WIDGET_STATE_HOVERED;
16285 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))
16286 *state |= NK_WIDGET_STATE_ENTERED;
16287 else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))
16288 *state |= NK_WIDGET_STATE_LEFT;
16289 return value_changed;
16290 }
16291
16292 NK_INTERN void
16293 nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,
16294 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
16295 struct nk_color color)
16296 {
16297 NK_STORAGE const struct nk_color black = {0,0,0,255};
16298 NK_STORAGE const struct nk_color white = {255, 255, 255, 255};
16299 NK_STORAGE const struct nk_color black_trans = {0,0,0,0};
16300
16301 const float crosshair_size = 7.0f;
16302 struct nk_color temp;
16303 float hsva[4];
16304 float line_y;
16305 int i;
16306
16307 NK_ASSERT(o);
16308 NK_ASSERT(matrix);
16309 NK_ASSERT(hue_bar);
16310
16311 /* draw hue bar */
16312 nk_color_hsv_fv(hsva, color);
16313 for (i = 0; i < 6; ++i) {
16314 NK_GLOBAL const struct nk_color hue_colors[] = {
16315 {255, 0, 0, 255},
16316 {255,255,0,255},
16317 {0,255,0,255},
16318 {0, 255,255,255},
16319 {0,0,255,255},
16320 {255, 0, 255, 255},
16321 {255, 0, 0, 255}
16322 };
16323 nk_fill_rect_multi_color(o,
16324 nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,
16325 hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],
16326 hue_colors[i+1], hue_colors[i+1]);
16327 }
16328 line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);
16329 nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,
16330 line_y, 1, nk_rgb(255,255,255));
16331
16332 /* draw alpha bar */
16333 if (alpha_bar) {
16334 float alpha = NK_SATURATE((float)color.a/255.0f);
16335 line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f);
16336
16337 nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);
16338 nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,
16339 line_y, 1, nk_rgb(255,255,255));
16340 }
16341
16342 /* draw color matrix */
16343 temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);
16344 nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);
16345 nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);
16346
16347 /* draw cross-hair */
16348 {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];
16349 p.x = (float)(int)(matrix->x + S * matrix->w);
16350 p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);
16351 nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);
16352 nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);
16353 nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);
16354 nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}
16355 }
16356
16357 NK_INTERN int
16358 nk_do_color_picker(nk_flags *state,
16359 struct nk_command_buffer *out, struct nk_color *color,
16360 enum nk_color_format fmt, struct nk_rect bounds,
16361 struct nk_vec2 padding, const struct nk_input *in,
16362 const struct nk_user_font *font)
16363 {
16364 int ret = 0;
16365 struct nk_rect matrix;
16366 struct nk_rect hue_bar;
16367 struct nk_rect alpha_bar;
16368 float bar_w;
16369
16370 NK_ASSERT(out);
16371 NK_ASSERT(color);
16372 NK_ASSERT(state);
16373 NK_ASSERT(font);
16374 if (!out || !color || !state || !font)
16375 return ret;
16376
16377 bar_w = font->height;
16378 bounds.x += padding.x;
16379 bounds.y += padding.x;
16380 bounds.w -= 2 * padding.x;
16381 bounds.h -= 2 * padding.y;
16382
16383 matrix.x = bounds.x;
16384 matrix.y = bounds.y;
16385 matrix.h = bounds.h;
16386 matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);
16387
16388 hue_bar.w = bar_w;
16389 hue_bar.y = bounds.y;
16390 hue_bar.h = matrix.h;
16391 hue_bar.x = matrix.x + matrix.w + padding.x;
16392
16393 alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;
16394 alpha_bar.y = bounds.y;
16395 alpha_bar.w = bar_w;
16396 alpha_bar.h = matrix.h;
16397
16398 ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,
16399 (fmt == NK_RGBA) ? &alpha_bar:0, color, in);
16400 nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *color);
16401 return ret;
16402 }
16403
16404 /* ==============================================================
16405 *
16406 * STYLE
16407 *
16408 * ===============================================================*/
16409 NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}
16410 #define NK_COLOR_MAP(NK_COLOR)\
16411 NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \
16412 NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \
16413 NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \
16414 NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \
16415 NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \
16416 NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \
16417 NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \
16418 NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \
16419 NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \
16420 NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \
16421 NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \
16422 NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \
16423 NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \
16424 NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \
16425 NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \
16426 NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \
16427 NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \
16428 NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \
16429 NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \
16430 NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \
16431 NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \
16432 NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \
16433 NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,255, 0, 0, 255) \
16434 NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \
16435 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \
16436 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,120,120,120,255) \
16437 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,150,150,150,255) \
16438 NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255)
16439
16440 NK_GLOBAL const struct nk_color
16441 nk_default_color_style[NK_COLOR_COUNT] = {
16442 #define NK_COLOR(a,b,c,d,e) {b,c,d,e},
16443 NK_COLOR_MAP(NK_COLOR)
16444 #undef NK_COLOR
16445 };
16446
16447 NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {
16448 #define NK_COLOR(a,b,c,d,e) #a,
16449 NK_COLOR_MAP(NK_COLOR)
16450 #undef NK_COLOR
16451 };
16452
16453 NK_API const char *nk_style_get_color_by_name(enum nk_style_colors c)
16454 {return nk_color_names[c];}
16455
16456 NK_API struct nk_style_item nk_style_item_image(struct nk_image img)
16457 {struct nk_style_item i; i.type = NK_STYLE_ITEM_IMAGE; i.data.image = img; return i;}
16458
16459 NK_API struct nk_style_item nk_style_item_color(struct nk_color col)
16460 {struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = col; return i;}
16461
16462 NK_API struct nk_style_item nk_style_item_hide(void)
16463 {struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = nk_rgba(0,0,0,0); return i;}
16464
16465 NK_API void
16466 nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
16467 {
16468 struct nk_style *style;
16469 struct nk_style_text *text;
16470 struct nk_style_button *button;
16471 struct nk_style_toggle *toggle;
16472 struct nk_style_selectable *select;
16473 struct nk_style_slider *slider;
16474 struct nk_style_progress *prog;
16475 struct nk_style_scrollbar *scroll;
16476 struct nk_style_edit *edit;
16477 struct nk_style_property *property;
16478 struct nk_style_combo *combo;
16479 struct nk_style_chart *chart;
16480 struct nk_style_tab *tab;
16481 struct nk_style_window *win;
16482
16483 NK_ASSERT(ctx);
16484 if (!ctx) return;
16485 style = &ctx->style;
16486 table = (!table) ? nk_default_color_style: table;
16487
16488 /* default text */
16489 text = &style->text;
16490 text->color = table[NK_COLOR_TEXT];
16491 text->padding = nk_vec2(0,0);
16492
16493 /* default button */
16494 button = &style->button;
16495 nk_zero_struct(*button);
16496 button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]);
16497 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
16498 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
16499 button->border_color = table[NK_COLOR_BORDER];
16500 button->text_background = table[NK_COLOR_BUTTON];
16501 button->text_normal = table[NK_COLOR_TEXT];
16502 button->text_hover = table[NK_COLOR_TEXT];
16503 button->text_active = table[NK_COLOR_TEXT];
16504 button->padding = nk_vec2(2.0f,2.0f);
16505 button->image_padding = nk_vec2(0.0f,0.0f);
16506 button->touch_padding = nk_vec2(0.0f, 0.0f);
16507 button->userdata = nk_handle_ptr(0);
16508 button->text_alignment = NK_TEXT_CENTERED;
16509 button->border = 1.0f;
16510 button->rounding = 4.0f;
16511 button->draw_begin = 0;
16512 button->draw_end = 0;
16513
16514 /* contextual button */
16515 button = &style->contextual_button;
16516 nk_zero_struct(*button);
16517 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16518 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
16519 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
16520 button->border_color = table[NK_COLOR_WINDOW];
16521 button->text_background = table[NK_COLOR_WINDOW];
16522 button->text_normal = table[NK_COLOR_TEXT];
16523 button->text_hover = table[NK_COLOR_TEXT];
16524 button->text_active = table[NK_COLOR_TEXT];
16525 button->padding = nk_vec2(2.0f,2.0f);
16526 button->touch_padding = nk_vec2(0.0f,0.0f);
16527 button->userdata = nk_handle_ptr(0);
16528 button->text_alignment = NK_TEXT_CENTERED;
16529 button->border = 0.0f;
16530 button->rounding = 0.0f;
16531 button->draw_begin = 0;
16532 button->draw_end = 0;
16533
16534 /* menu button */
16535 button = &style->menu_button;
16536 nk_zero_struct(*button);
16537 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16538 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
16539 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
16540 button->border_color = table[NK_COLOR_WINDOW];
16541 button->text_background = table[NK_COLOR_WINDOW];
16542 button->text_normal = table[NK_COLOR_TEXT];
16543 button->text_hover = table[NK_COLOR_TEXT];
16544 button->text_active = table[NK_COLOR_TEXT];
16545 button->padding = nk_vec2(2.0f,2.0f);
16546 button->touch_padding = nk_vec2(0.0f,0.0f);
16547 button->userdata = nk_handle_ptr(0);
16548 button->text_alignment = NK_TEXT_CENTERED;
16549 button->border = 0.0f;
16550 button->rounding = 1.0f;
16551 button->draw_begin = 0;
16552 button->draw_end = 0;
16553
16554 /* checkbox toggle */
16555 toggle = &style->checkbox;
16556 nk_zero_struct(*toggle);
16557 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
16558 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16559 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16560 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16561 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16562 toggle->userdata = nk_handle_ptr(0);
16563 toggle->text_background = table[NK_COLOR_WINDOW];
16564 toggle->text_normal = table[NK_COLOR_TEXT];
16565 toggle->text_hover = table[NK_COLOR_TEXT];
16566 toggle->text_active = table[NK_COLOR_TEXT];
16567 toggle->padding = nk_vec2(2.0f, 2.0f);
16568 toggle->touch_padding = nk_vec2(0,0);
16569 toggle->border_color = nk_rgba(0,0,0,0);
16570 toggle->border = 0.0f;
16571 toggle->spacing = 4;
16572
16573 /* option toggle */
16574 toggle = &style->option;
16575 nk_zero_struct(*toggle);
16576 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
16577 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16578 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
16579 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16580 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
16581 toggle->userdata = nk_handle_ptr(0);
16582 toggle->text_background = table[NK_COLOR_WINDOW];
16583 toggle->text_normal = table[NK_COLOR_TEXT];
16584 toggle->text_hover = table[NK_COLOR_TEXT];
16585 toggle->text_active = table[NK_COLOR_TEXT];
16586 toggle->padding = nk_vec2(3.0f, 3.0f);
16587 toggle->touch_padding = nk_vec2(0,0);
16588 toggle->border_color = nk_rgba(0,0,0,0);
16589 toggle->border = 0.0f;
16590 toggle->spacing = 4;
16591
16592 /* selectable */
16593 select = &style->selectable;
16594 nk_zero_struct(*select);
16595 select->normal = nk_style_item_color(table[NK_COLOR_SELECT]);
16596 select->hover = nk_style_item_color(table[NK_COLOR_SELECT]);
16597 select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]);
16598 select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16599 select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16600 select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
16601 select->text_normal = table[NK_COLOR_TEXT];
16602 select->text_hover = table[NK_COLOR_TEXT];
16603 select->text_pressed = table[NK_COLOR_TEXT];
16604 select->text_normal_active = table[NK_COLOR_TEXT];
16605 select->text_hover_active = table[NK_COLOR_TEXT];
16606 select->text_pressed_active = table[NK_COLOR_TEXT];
16607 select->padding = nk_vec2(2.0f,2.0f);
16608 select->touch_padding = nk_vec2(0,0);
16609 select->userdata = nk_handle_ptr(0);
16610 select->rounding = 0.0f;
16611 select->draw_begin = 0;
16612 select->draw_end = 0;
16613
16614 /* slider */
16615 slider = &style->slider;
16616 nk_zero_struct(*slider);
16617 slider->normal = nk_style_item_hide();
16618 slider->hover = nk_style_item_hide();
16619 slider->active = nk_style_item_hide();
16620 slider->bar_normal = table[NK_COLOR_SLIDER];
16621 slider->bar_hover = table[NK_COLOR_SLIDER];
16622 slider->bar_active = table[NK_COLOR_SLIDER];
16623 slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR];
16624 slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
16625 slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
16626 slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
16627 slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT;
16628 slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT;
16629 slider->cursor_size = nk_vec2(16,16);
16630 slider->padding = nk_vec2(2,2);
16631 slider->spacing = nk_vec2(2,2);
16632 slider->userdata = nk_handle_ptr(0);
16633 slider->show_buttons = nk_false;
16634 slider->bar_height = 8;
16635 slider->rounding = 0;
16636 slider->draw_begin = 0;
16637 slider->draw_end = 0;
16638
16639 /* slider buttons */
16640 button = &style->slider.inc_button;
16641 button->normal = nk_style_item_color(nk_rgb(40,40,40));
16642 button->hover = nk_style_item_color(nk_rgb(42,42,42));
16643 button->active = nk_style_item_color(nk_rgb(44,44,44));
16644 button->border_color = nk_rgb(65,65,65);
16645 button->text_background = nk_rgb(40,40,40);
16646 button->text_normal = nk_rgb(175,175,175);
16647 button->text_hover = nk_rgb(175,175,175);
16648 button->text_active = nk_rgb(175,175,175);
16649 button->padding = nk_vec2(8.0f,8.0f);
16650 button->touch_padding = nk_vec2(0.0f,0.0f);
16651 button->userdata = nk_handle_ptr(0);
16652 button->text_alignment = NK_TEXT_CENTERED;
16653 button->border = 1.0f;
16654 button->rounding = 0.0f;
16655 button->draw_begin = 0;
16656 button->draw_end = 0;
16657 style->slider.dec_button = style->slider.inc_button;
16658
16659 /* progressbar */
16660 prog = &style->progress;
16661 nk_zero_struct(*prog);
16662 prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]);
16663 prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]);
16664 prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]);
16665 prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
16666 prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
16667 prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
16668 prog->border_color = nk_rgba(0,0,0,0);
16669 prog->cursor_border_color = nk_rgba(0,0,0,0);
16670 prog->userdata = nk_handle_ptr(0);
16671 prog->padding = nk_vec2(4,4);
16672 prog->rounding = 0;
16673 prog->border = 0;
16674 prog->cursor_rounding = 0;
16675 prog->cursor_border = 0;
16676 prog->draw_begin = 0;
16677 prog->draw_end = 0;
16678
16679 /* scrollbars */
16680 scroll = &style->scrollh;
16681 nk_zero_struct(*scroll);
16682 scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16683 scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16684 scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
16685 scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);
16686 scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);
16687 scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);
16688 scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID;
16689 scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID;
16690 scroll->userdata = nk_handle_ptr(0);
16691 scroll->border_color = table[NK_COLOR_SCROLLBAR];
16692 scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];
16693 scroll->padding = nk_vec2(0,0);
16694 scroll->show_buttons = nk_false;
16695 scroll->border = 0;
16696 scroll->rounding = 0;
16697 scroll->border_cursor = 0;
16698 scroll->rounding_cursor = 0;
16699 scroll->draw_begin = 0;
16700 scroll->draw_end = 0;
16701 style->scrollv = style->scrollh;
16702
16703 /* scrollbars buttons */
16704 button = &style->scrollh.inc_button;
16705 button->normal = nk_style_item_color(nk_rgb(40,40,40));
16706 button->hover = nk_style_item_color(nk_rgb(42,42,42));
16707 button->active = nk_style_item_color(nk_rgb(44,44,44));
16708 button->border_color = nk_rgb(65,65,65);
16709 button->text_background = nk_rgb(40,40,40);
16710 button->text_normal = nk_rgb(175,175,175);
16711 button->text_hover = nk_rgb(175,175,175);
16712 button->text_active = nk_rgb(175,175,175);
16713 button->padding = nk_vec2(4.0f,4.0f);
16714 button->touch_padding = nk_vec2(0.0f,0.0f);
16715 button->userdata = nk_handle_ptr(0);
16716 button->text_alignment = NK_TEXT_CENTERED;
16717 button->border = 1.0f;
16718 button->rounding = 0.0f;
16719 button->draw_begin = 0;
16720 button->draw_end = 0;
16721 style->scrollh.dec_button = style->scrollh.inc_button;
16722 style->scrollv.inc_button = style->scrollh.inc_button;
16723 style->scrollv.dec_button = style->scrollh.inc_button;
16724
16725 /* edit */
16726 edit = &style->edit;
16727 nk_zero_struct(*edit);
16728 edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]);
16729 edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]);
16730 edit->active = nk_style_item_color(table[NK_COLOR_EDIT]);
16731 edit->cursor_normal = table[NK_COLOR_TEXT];
16732 edit->cursor_hover = table[NK_COLOR_TEXT];
16733 edit->cursor_text_normal= table[NK_COLOR_EDIT];
16734 edit->cursor_text_hover = table[NK_COLOR_EDIT];
16735 edit->border_color = table[NK_COLOR_BORDER];
16736 edit->text_normal = table[NK_COLOR_TEXT];
16737 edit->text_hover = table[NK_COLOR_TEXT];
16738 edit->text_active = table[NK_COLOR_TEXT];
16739 edit->selected_normal = table[NK_COLOR_TEXT];
16740 edit->selected_hover = table[NK_COLOR_TEXT];
16741 edit->selected_text_normal = table[NK_COLOR_EDIT];
16742 edit->selected_text_hover = table[NK_COLOR_EDIT];
16743 edit->scrollbar_size = nk_vec2(10,10);
16744 edit->scrollbar = style->scrollv;
16745 edit->padding = nk_vec2(4,4);
16746 edit->row_padding = 2;
16747 edit->cursor_size = 4;
16748 edit->border = 1;
16749 edit->rounding = 0;
16750
16751 /* property */
16752 property = &style->property;
16753 nk_zero_struct(*property);
16754 property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16755 property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16756 property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16757 property->border_color = table[NK_COLOR_BORDER];
16758 property->label_normal = table[NK_COLOR_TEXT];
16759 property->label_hover = table[NK_COLOR_TEXT];
16760 property->label_active = table[NK_COLOR_TEXT];
16761 property->sym_left = NK_SYMBOL_TRIANGLE_LEFT;
16762 property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT;
16763 property->userdata = nk_handle_ptr(0);
16764 property->padding = nk_vec2(4,4);
16765 property->border = 1;
16766 property->rounding = 10;
16767 property->draw_begin = 0;
16768 property->draw_end = 0;
16769
16770 /* property buttons */
16771 button = &style->property.dec_button;
16772 nk_zero_struct(*button);
16773 button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16774 button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16775 button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16776 button->border_color = nk_rgba(0,0,0,0);
16777 button->text_background = table[NK_COLOR_PROPERTY];
16778 button->text_normal = table[NK_COLOR_TEXT];
16779 button->text_hover = table[NK_COLOR_TEXT];
16780 button->text_active = table[NK_COLOR_TEXT];
16781 button->padding = nk_vec2(0.0f,0.0f);
16782 button->touch_padding = nk_vec2(0.0f,0.0f);
16783 button->userdata = nk_handle_ptr(0);
16784 button->text_alignment = NK_TEXT_CENTERED;
16785 button->border = 0.0f;
16786 button->rounding = 0.0f;
16787 button->draw_begin = 0;
16788 button->draw_end = 0;
16789 style->property.inc_button = style->property.dec_button;
16790
16791 /* property edit */
16792 edit = &style->property.edit;
16793 nk_zero_struct(*edit);
16794 edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16795 edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16796 edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
16797 edit->border_color = nk_rgba(0,0,0,0);
16798 edit->cursor_normal = table[NK_COLOR_TEXT];
16799 edit->cursor_hover = table[NK_COLOR_TEXT];
16800 edit->cursor_text_normal= table[NK_COLOR_EDIT];
16801 edit->cursor_text_hover = table[NK_COLOR_EDIT];
16802 edit->text_normal = table[NK_COLOR_TEXT];
16803 edit->text_hover = table[NK_COLOR_TEXT];
16804 edit->text_active = table[NK_COLOR_TEXT];
16805 edit->selected_normal = table[NK_COLOR_TEXT];
16806 edit->selected_hover = table[NK_COLOR_TEXT];
16807 edit->selected_text_normal = table[NK_COLOR_EDIT];
16808 edit->selected_text_hover = table[NK_COLOR_EDIT];
16809 edit->padding = nk_vec2(0,0);
16810 edit->cursor_size = 8;
16811 edit->border = 0;
16812 edit->rounding = 0;
16813
16814 /* chart */
16815 chart = &style->chart;
16816 nk_zero_struct(*chart);
16817 chart->background = nk_style_item_color(table[NK_COLOR_CHART]);
16818 chart->border_color = table[NK_COLOR_BORDER];
16819 chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];
16820 chart->color = table[NK_COLOR_CHART_COLOR];
16821 chart->padding = nk_vec2(4,4);
16822 chart->border = 0;
16823 chart->rounding = 0;
16824
16825 /* combo */
16826 combo = &style->combo;
16827 combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
16828 combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
16829 combo->active = nk_style_item_color(table[NK_COLOR_COMBO]);
16830 combo->border_color = table[NK_COLOR_BORDER];
16831 combo->label_normal = table[NK_COLOR_TEXT];
16832 combo->label_hover = table[NK_COLOR_TEXT];
16833 combo->label_active = table[NK_COLOR_TEXT];
16834 combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN;
16835 combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN;
16836 combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN;
16837 combo->content_padding = nk_vec2(4,4);
16838 combo->button_padding = nk_vec2(0,4);
16839 combo->spacing = nk_vec2(4,0);
16840 combo->border = 1;
16841 combo->rounding = 0;
16842
16843 /* combo button */
16844 button = &style->combo.button;
16845 nk_zero_struct(*button);
16846 button->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
16847 button->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
16848 button->active = nk_style_item_color(table[NK_COLOR_COMBO]);
16849 button->border_color = nk_rgba(0,0,0,0);
16850 button->text_background = table[NK_COLOR_COMBO];
16851 button->text_normal = table[NK_COLOR_TEXT];
16852 button->text_hover = table[NK_COLOR_TEXT];
16853 button->text_active = table[NK_COLOR_TEXT];
16854 button->padding = nk_vec2(2.0f,2.0f);
16855 button->touch_padding = nk_vec2(0.0f,0.0f);
16856 button->userdata = nk_handle_ptr(0);
16857 button->text_alignment = NK_TEXT_CENTERED;
16858 button->border = 0.0f;
16859 button->rounding = 0.0f;
16860 button->draw_begin = 0;
16861 button->draw_end = 0;
16862
16863 /* tab */
16864 tab = &style->tab;
16865 tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16866 tab->border_color = table[NK_COLOR_BORDER];
16867 tab->text = table[NK_COLOR_TEXT];
16868 tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT;
16869 tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN;
16870 tab->padding = nk_vec2(4,4);
16871 tab->spacing = nk_vec2(4,4);
16872 tab->indent = 10.0f;
16873 tab->border = 1;
16874 tab->rounding = 0;
16875
16876 /* tab button */
16877 button = &style->tab.tab_minimize_button;
16878 nk_zero_struct(*button);
16879 button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16880 button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16881 button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
16882 button->border_color = nk_rgba(0,0,0,0);
16883 button->text_background = table[NK_COLOR_TAB_HEADER];
16884 button->text_normal = table[NK_COLOR_TEXT];
16885 button->text_hover = table[NK_COLOR_TEXT];
16886 button->text_active = table[NK_COLOR_TEXT];
16887 button->padding = nk_vec2(2.0f,2.0f);
16888 button->touch_padding = nk_vec2(0.0f,0.0f);
16889 button->userdata = nk_handle_ptr(0);
16890 button->text_alignment = NK_TEXT_CENTERED;
16891 button->border = 0.0f;
16892 button->rounding = 0.0f;
16893 button->draw_begin = 0;
16894 button->draw_end = 0;
16895 style->tab.tab_maximize_button =*button;
16896
16897 /* node button */
16898 button = &style->tab.node_minimize_button;
16899 nk_zero_struct(*button);
16900 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
16901 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
16902 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
16903 button->border_color = nk_rgba(0,0,0,0);
16904 button->text_background = table[NK_COLOR_TAB_HEADER];
16905 button->text_normal = table[NK_COLOR_TEXT];
16906 button->text_hover = table[NK_COLOR_TEXT];
16907 button->text_active = table[NK_COLOR_TEXT];
16908 button->padding = nk_vec2(2.0f,2.0f);
16909 button->touch_padding = nk_vec2(0.0f,0.0f);
16910 button->userdata = nk_handle_ptr(0);
16911 button->text_alignment = NK_TEXT_CENTERED;
16912 button->border = 0.0f;
16913 button->rounding = 0.0f;
16914 button->draw_begin = 0;
16915 button->draw_end = 0;
16916 style->tab.node_maximize_button =*button;
16917
16918 /* window header */
16919 win = &style->window;
16920 win->header.align = NK_HEADER_RIGHT;
16921 win->header.close_symbol = NK_SYMBOL_X;
16922 win->header.minimize_symbol = NK_SYMBOL_MINUS;
16923 win->header.maximize_symbol = NK_SYMBOL_PLUS;
16924 win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16925 win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16926 win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);
16927 win->header.label_normal = table[NK_COLOR_TEXT];
16928 win->header.label_hover = table[NK_COLOR_TEXT];
16929 win->header.label_active = table[NK_COLOR_TEXT];
16930 win->header.label_padding = nk_vec2(4,4);
16931 win->header.padding = nk_vec2(4,4);
16932 win->header.spacing = nk_vec2(0,0);
16933
16934 /* window header close button */
16935 button = &style->window.header.close_button;
16936 nk_zero_struct(*button);
16937 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16938 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16939 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
16940 button->border_color = nk_rgba(0,0,0,0);
16941 button->text_background = table[NK_COLOR_HEADER];
16942 button->text_normal = table[NK_COLOR_TEXT];
16943 button->text_hover = table[NK_COLOR_TEXT];
16944 button->text_active = table[NK_COLOR_TEXT];
16945 button->padding = nk_vec2(0.0f,0.0f);
16946 button->touch_padding = nk_vec2(0.0f,0.0f);
16947 button->userdata = nk_handle_ptr(0);
16948 button->text_alignment = NK_TEXT_CENTERED;
16949 button->border = 0.0f;
16950 button->rounding = 0.0f;
16951 button->draw_begin = 0;
16952 button->draw_end = 0;
16953
16954 /* window header minimize button */
16955 button = &style->window.header.minimize_button;
16956 nk_zero_struct(*button);
16957 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
16958 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
16959 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
16960 button->border_color = nk_rgba(0,0,0,0);
16961 button->text_background = table[NK_COLOR_HEADER];
16962 button->text_normal = table[NK_COLOR_TEXT];
16963 button->text_hover = table[NK_COLOR_TEXT];
16964 button->text_active = table[NK_COLOR_TEXT];
16965 button->padding = nk_vec2(0.0f,0.0f);
16966 button->touch_padding = nk_vec2(0.0f,0.0f);
16967 button->userdata = nk_handle_ptr(0);
16968 button->text_alignment = NK_TEXT_CENTERED;
16969 button->border = 0.0f;
16970 button->rounding = 0.0f;
16971 button->draw_begin = 0;
16972 button->draw_end = 0;
16973
16974 /* window */
16975 win->background = table[NK_COLOR_WINDOW];
16976 win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);
16977 win->border_color = table[NK_COLOR_BORDER];
16978 win->popup_border_color = table[NK_COLOR_BORDER];
16979 win->combo_border_color = table[NK_COLOR_BORDER];
16980 win->contextual_border_color = table[NK_COLOR_BORDER];
16981 win->menu_border_color = table[NK_COLOR_BORDER];
16982 win->group_border_color = table[NK_COLOR_BORDER];
16983 win->tooltip_border_color = table[NK_COLOR_BORDER];
16984 win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);
16985
16986 win->rounding = 0.0f;
16987 win->spacing = nk_vec2(4,4);
16988 win->scrollbar_size = nk_vec2(10,10);
16989 win->min_size = nk_vec2(64,64);
16990
16991 win->combo_border = 1.0f;
16992 win->contextual_border = 1.0f;
16993 win->menu_border = 1.0f;
16994 win->group_border = 1.0f;
16995 win->tooltip_border = 1.0f;
16996 win->popup_border = 1.0f;
16997 win->border = 2.0f;
16998 win->min_row_height_padding = 8;
16999
17000 win->padding = nk_vec2(4,4);
17001 win->group_padding = nk_vec2(4,4);
17002 win->popup_padding = nk_vec2(4,4);
17003 win->combo_padding = nk_vec2(4,4);
17004 win->contextual_padding = nk_vec2(4,4);
17005 win->menu_padding = nk_vec2(4,4);
17006 win->tooltip_padding = nk_vec2(4,4);
17007 }
17008
17009 NK_API void
17010 nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)
17011 {
17012 struct nk_style *style;
17013 NK_ASSERT(ctx);
17014
17015 if (!ctx) return;
17016 style = &ctx->style;
17017 style->font = font;
17018 ctx->stacks.fonts.head = 0;
17019 if (ctx->current)
17020 nk_layout_reset_min_row_height(ctx);
17021 }
17022
17023 NK_API int
17024 nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font)
17025 {
17026 struct nk_config_stack_user_font *font_stack;
17027 struct nk_config_stack_user_font_element *element;
17028
17029 NK_ASSERT(ctx);
17030 if (!ctx) return 0;
17031
17032 font_stack = &ctx->stacks.fonts;
17033 NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));
17034 if (font_stack->head >= (int)NK_LEN(font_stack->elements))
17035 return 0;
17036
17037 element = &font_stack->elements[font_stack->head++];
17038 element->address = &ctx->style.font;
17039 element->old_value = ctx->style.font;
17040 ctx->style.font = font;
17041 return 1;
17042 }
17043
17044 NK_API int
17045 nk_style_pop_font(struct nk_context *ctx)
17046 {
17047 struct nk_config_stack_user_font *font_stack;
17048 struct nk_config_stack_user_font_element *element;
17049
17050 NK_ASSERT(ctx);
17051 if (!ctx) return 0;
17052
17053 font_stack = &ctx->stacks.fonts;
17054 NK_ASSERT(font_stack->head > 0);
17055 if (font_stack->head < 1)
17056 return 0;
17057
17058 element = &font_stack->elements[--font_stack->head];
17059 *element->address = element->old_value;
17060 return 1;
17061 }
17062
17063 #define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \
17064 nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\
17065 {\
17066 struct nk_config_stack_##type * type_stack;\
17067 struct nk_config_stack_##type##_element *element;\
17068 NK_ASSERT(ctx);\
17069 if (!ctx) return 0;\
17070 type_stack = &ctx->stacks.stack;\
17071 NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\
17072 if (type_stack->head >= (int)NK_LEN(type_stack->elements))\
17073 return 0;\
17074 element = &type_stack->elements[type_stack->head++];\
17075 element->address = address;\
17076 element->old_value = *address;\
17077 *address = value;\
17078 return 1;\
17079 }
17080
17081 #define NK_STYLE_POP_IMPLEMENATION(type, stack) \
17082 nk_style_pop_##type(struct nk_context *ctx)\
17083 {\
17084 struct nk_config_stack_##type *type_stack;\
17085 struct nk_config_stack_##type##_element *element;\
17086 NK_ASSERT(ctx);\
17087 if (!ctx) return 0;\
17088 type_stack = &ctx->stacks.stack;\
17089 NK_ASSERT(type_stack->head > 0);\
17090 if (type_stack->head < 1)\
17091 return 0;\
17092 element = &type_stack->elements[--type_stack->head];\
17093 *element->address = element->old_value;\
17094 return 1;\
17095 }
17096
17097 NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)
17098 NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)
17099 NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)
17100 NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)
17101 NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)
17102
17103 NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items)
17104 NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats)
17105 NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors)
17106 NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags)
17107 NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors)
17108
17109 NK_API int
17110 nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)
17111 {
17112 struct nk_style *style;
17113 NK_ASSERT(ctx);
17114 if (!ctx) return 0;
17115 style = &ctx->style;
17116 if (style->cursors[c]) {
17117 style->cursor_active = style->cursors[c];
17118 return 1;
17119 }
17120 return 0;
17121 }
17122
17123 NK_API void
17124 nk_style_show_cursor(struct nk_context *ctx)
17125 {
17126 ctx->style.cursor_visible = nk_true;
17127 }
17128
17129 NK_API void
17130 nk_style_hide_cursor(struct nk_context *ctx)
17131 {
17132 ctx->style.cursor_visible = nk_false;
17133 }
17134
17135 NK_API void
17136 nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,
17137 const struct nk_cursor *c)
17138 {
17139 struct nk_style *style;
17140 NK_ASSERT(ctx);
17141 if (!ctx) return;
17142 style = &ctx->style;
17143 style->cursors[cursor] = c;
17144 }
17145
17146 NK_API void
17147 nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors)
17148 {
17149 int i = 0;
17150 struct nk_style *style;
17151 NK_ASSERT(ctx);
17152 if (!ctx) return;
17153 style = &ctx->style;
17154 for (i = 0; i < NK_CURSOR_COUNT; ++i)
17155 style->cursors[i] = &cursors[i];
17156 style->cursor_visible = nk_true;
17157 }
17158
17159 /* ===============================================================
17160 *
17161 * POOL
17162 *
17163 * ===============================================================*/
17164 NK_INTERN void
17165 nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc,
17166 unsigned int capacity)
17167 {
17168 nk_zero(pool, sizeof(*pool));
17169 pool->alloc = *alloc;
17170 pool->capacity = capacity;
17171 pool->type = NK_BUFFER_DYNAMIC;
17172 pool->pages = 0;
17173 }
17174
17175 NK_INTERN void
17176 nk_pool_free(struct nk_pool *pool)
17177 {
17178 struct nk_page *iter = pool->pages;
17179 if (!pool) return;
17180 if (pool->type == NK_BUFFER_FIXED) return;
17181 while (iter) {
17182 struct nk_page *next = iter->next;
17183 pool->alloc.free(pool->alloc.userdata, iter);
17184 iter = next;
17185 }
17186 }
17187
17188 NK_INTERN void
17189 nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)
17190 {
17191 nk_zero(pool, sizeof(*pool));
17192 NK_ASSERT(size >= sizeof(struct nk_page));
17193 if (size < sizeof(struct nk_page)) return;
17194 pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element);
17195 pool->pages = (struct nk_page*)memory;
17196 pool->type = NK_BUFFER_FIXED;
17197 pool->size = size;
17198 }
17199
17200 NK_INTERN struct nk_page_element*
17201 nk_pool_alloc(struct nk_pool *pool)
17202 {
17203 if (!pool->pages || pool->pages->size >= pool->capacity) {
17204 /* allocate new page */
17205 struct nk_page *page;
17206 if (pool->type == NK_BUFFER_FIXED) {
17207 if (!pool->pages) {
17208 NK_ASSERT(pool->pages);
17209 return 0;
17210 }
17211 NK_ASSERT(pool->pages->size < pool->capacity);
17212 return 0;
17213 } else {
17214 nk_size size = sizeof(struct nk_page);
17215 size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data);
17216 page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);
17217 page->next = pool->pages;
17218 pool->pages = page;
17219 page->size = 0;
17220 }
17221 }
17222 return &pool->pages->win[pool->pages->size++];
17223 }
17224
17225 /* ===============================================================
17226 *
17227 * CONTEXT
17228 *
17229 * ===============================================================*/
17230 NK_INTERN void* nk_create_window(struct nk_context *ctx);
17231 NK_INTERN void nk_remove_window(struct nk_context*, struct nk_window*);
17232 NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win);
17233 NK_INTERN void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
17234 NK_INTERN void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
17235 NK_INTERN void* nk_create_panel(struct nk_context *ctx);
17236 NK_INTERN void nk_free_panel(struct nk_context*, struct nk_panel *pan);
17237
17238 NK_INTERN void
17239 nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
17240 {
17241 NK_ASSERT(ctx);
17242 if (!ctx) return;
17243 nk_zero_struct(*ctx);
17244 nk_style_default(ctx);
17245 ctx->seq = 1;
17246 if (font) ctx->style.font = font;
17247 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
17248 nk_draw_list_init(&ctx->draw_list);
17249 #endif
17250 }
17251
17252 #ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
17253 NK_API int
17254 nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
17255 {
17256 struct nk_allocator alloc;
17257 alloc.userdata.ptr = 0;
17258 alloc.alloc = nk_malloc;
17259 alloc.free = nk_mfree;
17260 return nk_init(ctx, &alloc, font);
17261 }
17262 #endif
17263
17264 NK_API int
17265 nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
17266 const struct nk_user_font *font)
17267 {
17268 NK_ASSERT(memory);
17269 if (!memory) return 0;
17270 nk_setup(ctx, font);
17271 nk_buffer_init_fixed(&ctx->memory, memory, size);
17272 ctx->use_pool = nk_false;
17273 return 1;
17274 }
17275
17276 NK_API int
17277 nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
17278 struct nk_buffer *pool, const struct nk_user_font *font)
17279 {
17280 NK_ASSERT(cmds);
17281 NK_ASSERT(pool);
17282 if (!cmds || !pool) return 0;
17283
17284 nk_setup(ctx, font);
17285 ctx->memory = *cmds;
17286 if (pool->type == NK_BUFFER_FIXED) {
17287 /* take memory from buffer and alloc fixed pool */
17288 nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
17289 } else {
17290 /* create dynamic pool from buffer allocator */
17291 struct nk_allocator *alloc = &pool->pool;
17292 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
17293 }
17294 ctx->use_pool = nk_true;
17295 return 1;
17296 }
17297
17298 NK_API int
17299 nk_init(struct nk_context *ctx, struct nk_allocator *alloc,
17300 const struct nk_user_font *font)
17301 {
17302 NK_ASSERT(alloc);
17303 if (!alloc) return 0;
17304 nk_setup(ctx, font);
17305 nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
17306 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
17307 ctx->use_pool = nk_true;
17308 return 1;
17309 }
17310
17311 #ifdef NK_INCLUDE_COMMAND_USERDATA
17312 NK_API void
17313 nk_set_user_data(struct nk_context *ctx, nk_handle handle)
17314 {
17315 if (!ctx) return;
17316 ctx->userdata = handle;
17317 if (ctx->current)
17318 ctx->current->buffer.userdata = handle;
17319 }
17320 #endif
17321
17322 NK_API void
17323 nk_free(struct nk_context *ctx)
17324 {
17325 NK_ASSERT(ctx);
17326 if (!ctx) return;
17327 nk_buffer_free(&ctx->memory);
17328 if (ctx->use_pool)
17329 nk_pool_free(&ctx->pool);
17330
17331 nk_zero(&ctx->input, sizeof(ctx->input));
17332 nk_zero(&ctx->style, sizeof(ctx->style));
17333 nk_zero(&ctx->memory, sizeof(ctx->memory));
17334
17335 ctx->seq = 0;
17336 ctx->build = 0;
17337 ctx->begin = 0;
17338 ctx->end = 0;
17339 ctx->active = 0;
17340 ctx->current = 0;
17341 ctx->freelist = 0;
17342 ctx->count = 0;
17343 }
17344
17345 NK_API void
17346 nk_clear(struct nk_context *ctx)
17347 {
17348 struct nk_window *iter;
17349 struct nk_window *next;
17350 NK_ASSERT(ctx);
17351
17352 if (!ctx) return;
17353 if (ctx->use_pool)
17354 nk_buffer_clear(&ctx->memory);
17355 else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
17356
17357 ctx->build = 0;
17358 ctx->memory.calls = 0;
17359 ctx->last_widget_state = 0;
17360 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
17361 NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
17362 #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
17363 nk_draw_list_clear(&ctx->draw_list);
17364 #endif
17365
17366 /* garbage collector */
17367 iter = ctx->begin;
17368 while (iter) {
17369 /* make sure minimized windows do not get removed */
17370 if ((iter->flags & NK_WINDOW_MINIMIZED) &&
17371 !(iter->flags & NK_WINDOW_CLOSED)) {
17372 iter = iter->next;
17373 continue;
17374 }
17375 /* remove hotness from hidden or closed windows*/
17376 if (((iter->flags & NK_WINDOW_HIDDEN) ||
17377 (iter->flags & NK_WINDOW_CLOSED)) &&
17378 iter == ctx->active) {
17379 ctx->active = iter->prev;
17380 ctx->end = iter->prev;
17381 if (ctx->active)
17382 ctx->active->flags &= ~NK_WINDOW_ROM;
17383 }
17384
17385 /* free unused popup windows */
17386 if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
17387 nk_free_window(ctx, iter->popup.win);
17388 iter->popup.win = 0;
17389 }
17390 /* remove unused window state tables */
17391 {struct nk_table *n, *it = iter->tables;
17392 while (it) {
17393 n = it->next;
17394 if (it->seq != ctx->seq) {
17395 nk_remove_table(iter, it);
17396 nk_zero(it, sizeof(union nk_page_data));
17397 nk_free_table(ctx, it);
17398 if (it == iter->tables)
17399 iter->tables = n;
17400 }
17401 it = n;
17402 }}
17403 /* window itself is not used anymore so free */
17404 if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
17405 next = iter->next;
17406 nk_remove_window(ctx, iter);
17407 nk_free_window(ctx, iter);
17408 iter = next;
17409 } else iter = iter->next;
17410 }
17411 ctx->seq++;
17412 }
17413
17414 /* ----------------------------------------------------------------
17415 *
17416 * BUFFERING
17417 *
17418 * ---------------------------------------------------------------*/
17419 NK_INTERN void
17420 nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
17421 {
17422 NK_ASSERT(ctx);
17423 NK_ASSERT(buffer);
17424 if (!ctx || !buffer) return;
17425 buffer->begin = ctx->memory.allocated;
17426 buffer->end = buffer->begin;
17427 buffer->last = buffer->begin;
17428 buffer->clip = nk_null_rect;
17429 }
17430
17431 NK_INTERN void
17432 nk_start(struct nk_context *ctx, struct nk_window *win)
17433 {
17434 NK_ASSERT(ctx);
17435 NK_ASSERT(win);
17436 nk_start_buffer(ctx, &win->buffer);
17437 }
17438
17439 NK_INTERN void
17440 nk_start_popup(struct nk_context *ctx, struct nk_window *win)
17441 {
17442 struct nk_popup_buffer *buf;
17443 NK_ASSERT(ctx);
17444 NK_ASSERT(win);
17445 if (!ctx || !win) return;
17446
17447 /* save buffer fill state for popup */
17448 buf = &win->popup.buf;
17449 buf->begin = win->buffer.end;
17450 buf->end = win->buffer.end;
17451 buf->parent = win->buffer.last;
17452 buf->last = buf->begin;
17453 buf->active = nk_true;
17454 }
17455
17456 NK_INTERN void
17457 nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
17458 {
17459 struct nk_popup_buffer *buf;
17460 NK_ASSERT(ctx);
17461 NK_ASSERT(win);
17462 if (!ctx || !win) return;
17463
17464 buf = &win->popup.buf;
17465 buf->last = win->buffer.last;
17466 buf->end = win->buffer.end;
17467 }
17468
17469 NK_INTERN void
17470 nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
17471 {
17472 NK_ASSERT(ctx);
17473 NK_ASSERT(buffer);
17474 if (!ctx || !buffer) return;
17475 buffer->end = ctx->memory.allocated;
17476 }
17477
17478 NK_INTERN void
17479 nk_finish(struct nk_context *ctx, struct nk_window *win)
17480 {
17481 struct nk_popup_buffer *buf;
17482 struct nk_command *parent_last;
17483 void *memory;
17484
17485 NK_ASSERT(ctx);
17486 NK_ASSERT(win);
17487 if (!ctx || !win) return;
17488 nk_finish_buffer(ctx, &win->buffer);
17489 if (!win->popup.buf.active) return;
17490
17491 buf = &win->popup.buf;
17492 memory = ctx->memory.memory.ptr;
17493 parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
17494 parent_last->next = buf->end;
17495 }
17496
17497 NK_INTERN void
17498 nk_build(struct nk_context *ctx)
17499 {
17500 struct nk_window *iter = 0;
17501 struct nk_command *cmd = 0;
17502 nk_byte *buffer = 0;
17503
17504 /* draw cursor overlay */
17505 if (!ctx->style.cursor_active)
17506 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
17507 if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
17508 struct nk_rect mouse_bounds;
17509 const struct nk_cursor *cursor = ctx->style.cursor_active;
17510 nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
17511 nk_start_buffer(ctx, &ctx->overlay);
17512
17513 mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
17514 mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
17515 mouse_bounds.w = cursor->size.x;
17516 mouse_bounds.h = cursor->size.y;
17517
17518 nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
17519 nk_finish_buffer(ctx, &ctx->overlay);
17520 }
17521 /* build one big draw command list out of all window buffers */
17522 iter = ctx->begin;
17523 buffer = (nk_byte*)ctx->memory.memory.ptr;
17524 while (iter != 0) {
17525 struct nk_window *next = iter->next;
17526 if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)||
17527 iter->seq != ctx->seq)
17528 goto cont;
17529
17530 cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last);
17531 while (next && ((next->buffer.last == next->buffer.begin) ||
17532 (next->flags & NK_WINDOW_HIDDEN)))
17533 next = next->next; /* skip empty command buffers */
17534
17535 if (next) cmd->next = next->buffer.begin;
17536 cont: iter = next;
17537 }
17538 /* append all popup draw commands into lists */
17539 iter = ctx->begin;
17540 while (iter != 0) {
17541 struct nk_window *next = iter->next;
17542 struct nk_popup_buffer *buf;
17543 if (!iter->popup.buf.active)
17544 goto skip;
17545
17546 buf = &iter->popup.buf;
17547 cmd->next = buf->begin;
17548 cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
17549 buf->active = nk_false;
17550 skip: iter = next;
17551 }
17552 /* append overlay commands */
17553 if (cmd) {
17554 if (ctx->overlay.end != ctx->overlay.begin)
17555 cmd->next = ctx->overlay.begin;
17556 else cmd->next = ctx->memory.allocated;
17557 }
17558 }
17559
17560 NK_API const struct nk_command*
17561 nk__begin(struct nk_context *ctx)
17562 {
17563 struct nk_window *iter;
17564 nk_byte *buffer;
17565 NK_ASSERT(ctx);
17566 if (!ctx) return 0;
17567 if (!ctx->count) return 0;
17568
17569 buffer = (nk_byte*)ctx->memory.memory.ptr;
17570 if (!ctx->build) {
17571 nk_build(ctx);
17572 ctx->build = nk_true;
17573 }
17574 iter = ctx->begin;
17575 while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN)))
17576 iter = iter->next;
17577 if (!iter) return 0;
17578 return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
17579 }
17580
17581 NK_API const struct nk_command*
17582 nk__next(struct nk_context *ctx, const struct nk_command *cmd)
17583 {
17584 nk_byte *buffer;
17585 const struct nk_command *next;
17586 NK_ASSERT(ctx);
17587 if (!ctx || !cmd || !ctx->count) return 0;
17588 if (cmd->next >= ctx->memory.allocated) return 0;
17589 buffer = (nk_byte*)ctx->memory.memory.ptr;
17590 next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
17591 return next;
17592 }
17593
17594 /* ----------------------------------------------------------------
17595 *
17596 * PANEL
17597 *
17598 * ---------------------------------------------------------------*/
17599 static int
17600 nk_panel_has_header(nk_flags flags, const char *title)
17601 {
17602 int active = 0;
17603 active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));
17604 active = active || (flags & NK_WINDOW_TITLE);
17605 active = active && !(flags & NK_WINDOW_HIDDEN) && title;
17606 return active;
17607 }
17608
17609 NK_INTERN struct nk_vec2
17610 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)
17611 {
17612 switch (type) {
17613 default:
17614 case NK_PANEL_WINDOW: return style->window.padding;
17615 case NK_PANEL_GROUP: return style->window.group_padding;
17616 case NK_PANEL_POPUP: return style->window.popup_padding;
17617 case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;
17618 case NK_PANEL_COMBO: return style->window.combo_padding;
17619 case NK_PANEL_MENU: return style->window.menu_padding;
17620 case NK_PANEL_TOOLTIP: return style->window.menu_padding;
17621 }
17622 }
17623
17624 NK_INTERN float
17625 nk_panel_get_border(const struct nk_style *style, nk_flags flags,
17626 enum nk_panel_type type)
17627 {
17628 if (flags & NK_WINDOW_BORDER) {
17629 switch (type) {
17630 default:
17631 case NK_PANEL_WINDOW: return style->window.border;
17632 case NK_PANEL_GROUP: return style->window.group_border;
17633 case NK_PANEL_POPUP: return style->window.popup_border;
17634 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;
17635 case NK_PANEL_COMBO: return style->window.combo_border;
17636 case NK_PANEL_MENU: return style->window.menu_border;
17637 case NK_PANEL_TOOLTIP: return style->window.menu_border;
17638 }} else return 0;
17639 }
17640
17641 NK_INTERN struct nk_color
17642 nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)
17643 {
17644 switch (type) {
17645 default:
17646 case NK_PANEL_WINDOW: return style->window.border_color;
17647 case NK_PANEL_GROUP: return style->window.group_border_color;
17648 case NK_PANEL_POPUP: return style->window.popup_border_color;
17649 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;
17650 case NK_PANEL_COMBO: return style->window.combo_border_color;
17651 case NK_PANEL_MENU: return style->window.menu_border_color;
17652 case NK_PANEL_TOOLTIP: return style->window.menu_border_color;
17653 }
17654 }
17655
17656 NK_INTERN int
17657 nk_panel_is_sub(enum nk_panel_type type)
17658 {
17659 return (type & NK_PANEL_SET_SUB)?1:0;
17660 }
17661
17662 NK_INTERN int
17663 nk_panel_is_nonblock(enum nk_panel_type type)
17664 {
17665 return (type & NK_PANEL_SET_NONBLOCK)?1:0;
17666 }
17667
17668 NK_INTERN int
17669 nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)
17670 {
17671 struct nk_input *in;
17672 struct nk_window *win;
17673 struct nk_panel *layout;
17674 struct nk_command_buffer *out;
17675 const struct nk_style *style;
17676 const struct nk_user_font *font;
17677
17678 struct nk_vec2 scrollbar_size;
17679 struct nk_vec2 panel_padding;
17680
17681 NK_ASSERT(ctx);
17682 NK_ASSERT(ctx->current);
17683 NK_ASSERT(ctx->current->layout);
17684 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
17685 nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));
17686 if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {
17687 nk_zero(ctx->current->layout, sizeof(struct nk_panel));
17688 ctx->current->layout->type = panel_type;
17689 return 0;
17690 }
17691 /* pull state into local stack */
17692 style = &ctx->style;
17693 font = style->font;
17694 win = ctx->current;
17695 layout = win->layout;
17696 out = &win->buffer;
17697 in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;
17698 #ifdef NK_INCLUDE_COMMAND_USERDATA
17699 win->buffer.userdata = ctx->userdata;
17700 #endif
17701 /* pull style configuration into local stack */
17702 scrollbar_size = style->window.scrollbar_size;
17703 panel_padding = nk_panel_get_padding(style, panel_type);
17704
17705 /* window movement */
17706 if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {
17707 int left_mouse_down;
17708 int left_mouse_click_in_cursor;
17709
17710 /* calculate draggable window space */
17711 struct nk_rect header;
17712 header.x = win->bounds.x;
17713 header.y = win->bounds.y;
17714 header.w = win->bounds.w;
17715 if (nk_panel_has_header(win->flags, title)) {
17716 header.h = font->height + 2.0f * style->window.header.padding.y;
17717 header.h += 2.0f * style->window.header.label_padding.y;
17718 } else header.h = panel_padding.y;
17719
17720 /* window movement by dragging */
17721 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
17722 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
17723 NK_BUTTON_LEFT, header, nk_true);
17724 if (left_mouse_down && left_mouse_click_in_cursor) {
17725 win->bounds.x = win->bounds.x + in->mouse.delta.x;
17726 win->bounds.y = win->bounds.y + in->mouse.delta.y;
17727 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;
17728 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;
17729 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];
17730 }
17731 }
17732
17733 /* setup panel */
17734 layout->type = panel_type;
17735 layout->flags = win->flags;
17736 layout->bounds = win->bounds;
17737 layout->bounds.x += panel_padding.x;
17738 layout->bounds.w -= 2*panel_padding.x;
17739 if (win->flags & NK_WINDOW_BORDER) {
17740 layout->border = nk_panel_get_border(style, win->flags, panel_type);
17741 layout->bounds = nk_shrink_rect(layout->bounds, layout->border);
17742 } else layout->border = 0;
17743 layout->at_y = layout->bounds.y;
17744 layout->at_x = layout->bounds.x;
17745 layout->max_x = 0;
17746 layout->header_height = 0;
17747 layout->footer_height = 0;
17748 nk_layout_reset_min_row_height(ctx);
17749 layout->row.index = 0;
17750 layout->row.columns = 0;
17751 layout->row.ratio = 0;
17752 layout->row.item_width = 0;
17753 layout->row.tree_depth = 0;
17754 layout->row.height = panel_padding.y;
17755 layout->has_scrolling = nk_true;
17756 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))
17757 layout->bounds.w -= scrollbar_size.x;
17758 if (!nk_panel_is_nonblock(panel_type)) {
17759 layout->footer_height = 0;
17760 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)
17761 layout->footer_height = scrollbar_size.y;
17762 layout->bounds.h -= layout->footer_height;
17763 }
17764
17765 /* panel header */
17766 if (nk_panel_has_header(win->flags, title))
17767 {
17768 struct nk_text text;
17769 struct nk_rect header;
17770 const struct nk_style_item *background = 0;
17771
17772 /* calculate header bounds */
17773 header.x = win->bounds.x;
17774 header.y = win->bounds.y;
17775 header.w = win->bounds.w;
17776 header.h = font->height + 2.0f * style->window.header.padding.y;
17777 header.h += (2.0f * style->window.header.label_padding.y);
17778
17779 /* shrink panel by header */
17780 layout->header_height = header.h;
17781 layout->bounds.y += header.h;
17782 layout->bounds.h -= header.h;
17783 layout->at_y += header.h;
17784
17785 /* select correct header background and text color */
17786 if (ctx->active == win) {
17787 background = &style->window.header.active;
17788 text.text = style->window.header.label_active;
17789 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {
17790 background = &style->window.header.hover;
17791 text.text = style->window.header.label_hover;
17792 } else {
17793 background = &style->window.header.normal;
17794 text.text = style->window.header.label_normal;
17795 }
17796
17797 /* draw header background */
17798 header.h += 1.0f;
17799 if (background->type == NK_STYLE_ITEM_IMAGE) {
17800 text.background = nk_rgba(0,0,0,0);
17801 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
17802 } else {
17803 text.background = background->data.color;
17804 nk_fill_rect(out, header, 0, background->data.color);
17805 }
17806
17807 /* window close button */
17808 {struct nk_rect button;
17809 button.y = header.y + style->window.header.padding.y;
17810 button.h = header.h - 2 * style->window.header.padding.y;
17811 button.w = button.h;
17812 if (win->flags & NK_WINDOW_CLOSABLE) {
17813 nk_flags ws = 0;
17814 if (style->window.header.align == NK_HEADER_RIGHT) {
17815 button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);
17816 header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;
17817 } else {
17818 button.x = header.x + style->window.header.padding.x;
17819 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
17820 }
17821
17822 if (nk_do_button_symbol(&ws, &win->buffer, button,
17823 style->window.header.close_symbol, NK_BUTTON_DEFAULT,
17824 &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
17825 {
17826 layout->flags |= NK_WINDOW_HIDDEN;
17827 layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;
17828 }
17829 }
17830
17831 /* window minimize button */
17832 if (win->flags & NK_WINDOW_MINIMIZABLE) {
17833 nk_flags ws = 0;
17834 if (style->window.header.align == NK_HEADER_RIGHT) {
17835 button.x = (header.w + header.x) - button.w;
17836 if (!(win->flags & NK_WINDOW_CLOSABLE)) {
17837 button.x -= style->window.header.padding.x;
17838 header.w -= style->window.header.padding.x;
17839 }
17840 header.w -= button.w + style->window.header.spacing.x;
17841 } else {
17842 button.x = header.x;
17843 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
17844 }
17845 if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?
17846 style->window.header.maximize_symbol: style->window.header.minimize_symbol,
17847 NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
17848 layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?
17849 layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:
17850 layout->flags | NK_WINDOW_MINIMIZED;
17851 }}
17852
17853 {/* window header title */
17854 int text_len = nk_strlen(title);
17855 struct nk_rect label = {0,0,0,0};
17856 float t = font->width(font->userdata, font->height, title, text_len);
17857 text.padding = nk_vec2(0,0);
17858
17859 label.x = header.x + style->window.header.padding.x;
17860 label.x += style->window.header.label_padding.x;
17861 label.y = header.y + style->window.header.label_padding.y;
17862 label.h = font->height + 2 * style->window.header.label_padding.y;
17863 label.w = t + 2 * style->window.header.spacing.x;
17864 label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);
17865 nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);}
17866 }
17867
17868 /* draw window background */
17869 if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {
17870 struct nk_rect body;
17871 body.x = win->bounds.x;
17872 body.w = win->bounds.w;
17873 body.y = (win->bounds.y + layout->header_height);
17874 body.h = (win->bounds.h - layout->header_height);
17875 if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE)
17876 nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);
17877 else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color);
17878 }
17879
17880 /* set clipping rectangle */
17881 {struct nk_rect clip;
17882 layout->clip = layout->bounds;
17883 nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,
17884 layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);
17885 nk_push_scissor(out, clip);
17886 layout->clip = clip;}
17887 return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);
17888 }
17889
17890 NK_INTERN void
17891 nk_panel_end(struct nk_context *ctx)
17892 {
17893 struct nk_input *in;
17894 struct nk_window *window;
17895 struct nk_panel *layout;
17896 const struct nk_style *style;
17897 struct nk_command_buffer *out;
17898
17899 struct nk_vec2 scrollbar_size;
17900 struct nk_vec2 panel_padding;
17901
17902 NK_ASSERT(ctx);
17903 NK_ASSERT(ctx->current);
17904 NK_ASSERT(ctx->current->layout);
17905 if (!ctx || !ctx->current || !ctx->current->layout)
17906 return;
17907
17908 window = ctx->current;
17909 layout = window->layout;
17910 style = &ctx->style;
17911 out = &window->buffer;
17912 in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;
17913 if (!nk_panel_is_sub(layout->type))
17914 nk_push_scissor(out, nk_null_rect);
17915
17916 /* cache configuration data */
17917 scrollbar_size = style->window.scrollbar_size;
17918 panel_padding = nk_panel_get_padding(style, layout->type);
17919
17920 /* update the current cursor Y-position to point over the last added widget */
17921 layout->at_y += layout->row.height;
17922
17923 /* dynamic panels */
17924 if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))
17925 {
17926 /* update panel height to fit dynamic growth */
17927 struct nk_rect empty_space;
17928 if (layout->at_y < (layout->bounds.y + layout->bounds.h))
17929 layout->bounds.h = layout->at_y - layout->bounds.y;
17930
17931 /* fill top empty space */
17932 empty_space.x = window->bounds.x;
17933 empty_space.y = layout->bounds.y;
17934 empty_space.h = panel_padding.y;
17935 empty_space.w = window->bounds.w;
17936 nk_fill_rect(out, empty_space, 0, style->window.background);
17937
17938 /* fill left empty space */
17939 empty_space.x = window->bounds.x;
17940 empty_space.y = layout->bounds.y;
17941 empty_space.w = panel_padding.x + layout->border;
17942 empty_space.h = layout->bounds.h;
17943 nk_fill_rect(out, empty_space, 0, style->window.background);
17944
17945 /* fill right empty space */
17946 empty_space.x = layout->bounds.x + layout->bounds.w - layout->border;
17947 empty_space.y = layout->bounds.y;
17948 empty_space.w = panel_padding.x + layout->border;
17949 empty_space.h = layout->bounds.h;
17950 if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))
17951 empty_space.w += scrollbar_size.x;
17952 nk_fill_rect(out, empty_space, 0, style->window.background);
17953
17954 /* fill bottom empty space */
17955 if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) {
17956 empty_space.x = window->bounds.x;
17957 empty_space.y = layout->bounds.y + layout->bounds.h;
17958 empty_space.w = window->bounds.w;
17959 empty_space.h = scrollbar_size.y;
17960 nk_fill_rect(out, empty_space, 0, style->window.background);
17961 }
17962 }
17963
17964 /* scrollbars */
17965 if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&
17966 !(layout->flags & NK_WINDOW_MINIMIZED) &&
17967 window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)
17968 {
17969 struct nk_rect scroll;
17970 int scroll_has_scrolling;
17971 float scroll_target;
17972 float scroll_offset;
17973 float scroll_step;
17974 float scroll_inc;
17975
17976 /* mouse wheel scrolling */
17977 if (nk_panel_is_sub(layout->type))
17978 {
17979 /* sub-window mouse wheel scrolling */
17980 struct nk_window *root_window = window;
17981 struct nk_panel *root_panel = window->layout;
17982 while (root_panel->parent)
17983 root_panel = root_panel->parent;
17984 while (root_window->parent)
17985 root_window = root_window->parent;
17986
17987 /* only allow scrolling if parent window is active */
17988 scroll_has_scrolling = 0;
17989 if ((root_window == ctx->active) && layout->has_scrolling) {
17990 /* and panel is being hovered and inside clip rect*/
17991 if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&
17992 NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,
17993 root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))
17994 {
17995 /* deactivate all parent scrolling */
17996 root_panel = window->layout;
17997 while (root_panel->parent) {
17998 root_panel->has_scrolling = nk_false;
17999 root_panel = root_panel->parent;
18000 }
18001 root_panel->has_scrolling = nk_false;
18002 scroll_has_scrolling = nk_true;
18003 }
18004 }
18005 } else if (!nk_panel_is_sub(layout->type)) {
18006 /* window mouse wheel scrolling */
18007 scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;
18008 if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)
18009 window->scrolled = nk_true;
18010 else window->scrolled = nk_false;
18011 } else scroll_has_scrolling = nk_false;
18012
18013 {
18014 /* vertical scrollbar */
18015 nk_flags state = 0;
18016 scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
18017 scroll.y = layout->bounds.y;
18018 scroll.w = scrollbar_size.x;
18019 scroll.h = layout->bounds.h;
18020
18021 scroll_offset = (float)*layout->offset_y;
18022 scroll_step = scroll.h * 0.10f;
18023 scroll_inc = scroll.h * 0.01f;
18024 scroll_target = (float)(int)(layout->at_y - scroll.y);
18025 scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,
18026 scroll_offset, scroll_target, scroll_step, scroll_inc,
18027 &ctx->style.scrollv, in, style->font);
18028 *layout->offset_y = (nk_uint)scroll_offset;
18029 if (in && scroll_has_scrolling)
18030 in->mouse.scroll_delta.y = 0;
18031 }
18032 {
18033 /* horizontal scrollbar */
18034 nk_flags state = 0;
18035 scroll.x = layout->bounds.x;
18036 scroll.y = layout->bounds.y + layout->bounds.h;
18037 scroll.w = layout->bounds.w;
18038 scroll.h = scrollbar_size.y;
18039
18040 scroll_offset = (float)*layout->offset_x;
18041 scroll_target = (float)(int)(layout->max_x - scroll.x);
18042 scroll_step = layout->max_x * 0.05f;
18043 scroll_inc = layout->max_x * 0.005f;
18044 scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,
18045 scroll_offset, scroll_target, scroll_step, scroll_inc,
18046 &ctx->style.scrollh, in, style->font);
18047 *layout->offset_x = (nk_uint)scroll_offset;
18048 }
18049 }
18050
18051 /* hide scroll if no user input */
18052 if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {
18053 int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0;
18054 int is_window_hovered = nk_window_is_hovered(ctx);
18055 int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
18056 if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))
18057 window->scrollbar_hiding_timer += ctx->delta_time_seconds;
18058 else window->scrollbar_hiding_timer = 0;
18059 } else window->scrollbar_hiding_timer = 0;
18060
18061 /* window border */
18062 if (layout->flags & NK_WINDOW_BORDER)
18063 {
18064 struct nk_color border_color = nk_panel_get_border_color(style, layout->type);
18065 const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) ?
18066 style->window.border + window->bounds.y + layout->header_height:
18067 (layout->flags & NK_WINDOW_DYNAMIC)?
18068 layout->bounds.y + layout->bounds.h + layout->footer_height:
18069 window->bounds.y + window->bounds.h;
18070
18071 /* draw border top */
18072 nk_stroke_line(out,window->bounds.x,window->bounds.y,
18073 window->bounds.x + window->bounds.w, window->bounds.y,
18074 layout->border, border_color);
18075
18076 /* draw bottom border */
18077 nk_stroke_line(out, window->bounds.x, padding_y,
18078 window->bounds.x + window->bounds.w, padding_y, layout->border, border_color);
18079
18080 /* draw left border */
18081 nk_stroke_line(out, window->bounds.x + layout->border*0.5f,
18082 window->bounds.y, window->bounds.x + layout->border*0.5f,
18083 padding_y, layout->border, border_color);
18084
18085 /* draw right border */
18086 nk_stroke_line(out, window->bounds.x + window->bounds.w - layout->border*0.5f,
18087 window->bounds.y, window->bounds.x + window->bounds.w - layout->border*0.5f,
18088 padding_y, layout->border, border_color);
18089 }
18090
18091 /* scaler */
18092 if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))
18093 {
18094 /* calculate scaler bounds */
18095 struct nk_rect scaler;
18096 scaler.w = scrollbar_size.x;
18097 scaler.h = scrollbar_size.y;
18098 scaler.y = layout->bounds.y + layout->bounds.h;
18099 if (layout->flags & NK_WINDOW_SCALE_LEFT)
18100 scaler.x = layout->bounds.x - panel_padding.x * 0.5f;
18101 else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
18102 if (layout->flags & NK_WINDOW_NO_SCROLLBAR)
18103 scaler.x -= scaler.w;
18104
18105 /* draw scaler */
18106 {const struct nk_style_item *item = &style->window.scaler;
18107 if (item->type == NK_STYLE_ITEM_IMAGE)
18108 nk_draw_image(out, scaler, &item->data.image, nk_white);
18109 else {
18110 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
18111 nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,
18112 scaler.y + scaler.h, scaler.x + scaler.w,
18113 scaler.y + scaler.h, item->data.color);
18114 } else {
18115 nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,
18116 scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);
18117 }
18118 }}
18119
18120 /* do window scaling */
18121 if (!(window->flags & NK_WINDOW_ROM)) {
18122 struct nk_vec2 window_size = style->window.min_size;
18123 int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
18124 int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,
18125 NK_BUTTON_LEFT, scaler, nk_true);
18126
18127 if (left_mouse_down && left_mouse_click_in_scaler) {
18128 float delta_x = in->mouse.delta.x;
18129 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
18130 delta_x = -delta_x;
18131 window->bounds.x += in->mouse.delta.x;
18132 }
18133 /* dragging in x-direction */
18134 if (window->bounds.w + delta_x >= window_size.x) {
18135 if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) {
18136 window->bounds.w = window->bounds.w + delta_x;
18137 scaler.x += in->mouse.delta.x;
18138 }
18139 }
18140 /* dragging in y-direction (only possible if static window) */
18141 if (!(layout->flags & NK_WINDOW_DYNAMIC)) {
18142 if (window_size.y < window->bounds.h + in->mouse.delta.y) {
18143 if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) {
18144 window->bounds.h = window->bounds.h + in->mouse.delta.y;
18145 scaler.y += in->mouse.delta.y;
18146 }
18147 }
18148 }
18149 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];
18150 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;
18151 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;
18152 }
18153 }
18154 }
18155 if (!nk_panel_is_sub(layout->type)) {
18156 /* window is hidden so clear command buffer */
18157 if (layout->flags & NK_WINDOW_HIDDEN)
18158 nk_command_buffer_reset(&window->buffer);
18159 /* window is visible and not tab */
18160 else nk_finish(ctx, window);
18161 }
18162
18163 /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */
18164 if (layout->flags & NK_WINDOW_REMOVE_ROM) {
18165 layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
18166 layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
18167 }
18168 window->flags = layout->flags;
18169
18170 /* property garbage collector */
18171 if (window->property.active && window->property.old != window->property.seq &&
18172 window->property.active == window->property.prev) {
18173 nk_zero(&window->property, sizeof(window->property));
18174 } else {
18175 window->property.old = window->property.seq;
18176 window->property.prev = window->property.active;
18177 window->property.seq = 0;
18178 }
18179 /* edit garbage collector */
18180 if (window->edit.active && window->edit.old != window->edit.seq &&
18181 window->edit.active == window->edit.prev) {
18182 nk_zero(&window->edit, sizeof(window->edit));
18183 } else {
18184 window->edit.old = window->edit.seq;
18185 window->edit.prev = window->edit.active;
18186 window->edit.seq = 0;
18187 }
18188 /* contextual garbage collector */
18189 if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {
18190 window->popup.con_count = 0;
18191 window->popup.con_old = 0;
18192 window->popup.active_con = 0;
18193 } else {
18194 window->popup.con_old = window->popup.con_count;
18195 window->popup.con_count = 0;
18196 }
18197 window->popup.combo_count = 0;
18198 /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */
18199 NK_ASSERT(!layout->row.tree_depth);
18200 }
18201
18202 /* ----------------------------------------------------------------
18203 *
18204 * PAGE ELEMENT
18205 *
18206 * ---------------------------------------------------------------*/
18207 NK_INTERN struct nk_page_element*
18208 nk_create_page_element(struct nk_context *ctx)
18209 {
18210 struct nk_page_element *elem;
18211 if (ctx->freelist) {
18212 /* unlink page element from free list */
18213 elem = ctx->freelist;
18214 ctx->freelist = elem->next;
18215 } else if (ctx->use_pool) {
18216 /* allocate page element from memory pool */
18217 elem = nk_pool_alloc(&ctx->pool);
18218 NK_ASSERT(elem);
18219 if (!elem) return 0;
18220 } else {
18221 /* allocate new page element from back of fixed size memory buffer */
18222 NK_STORAGE const nk_size size = sizeof(struct nk_page_element);
18223 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);
18224 elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);
18225 NK_ASSERT(elem);
18226 if (!elem) return 0;
18227 }
18228 nk_zero_struct(*elem);
18229 elem->next = 0;
18230 elem->prev = 0;
18231 return elem;
18232 }
18233
18234 NK_INTERN void
18235 nk_link_page_element_into_freelist(struct nk_context *ctx,
18236 struct nk_page_element *elem)
18237 {
18238 /* link table into freelist */
18239 if (!ctx->freelist) {
18240 ctx->freelist = elem;
18241 } else {
18242 elem->next = ctx->freelist;
18243 ctx->freelist = elem;
18244 }
18245 }
18246
18247 NK_INTERN void
18248 nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)
18249 {
18250 /* we have a pool so just add to free list */
18251 if (ctx->use_pool) {
18252 nk_link_page_element_into_freelist(ctx, elem);
18253 return;
18254 }
18255 /* if possible remove last element from back of fixed memory buffer */
18256 {void *elem_end = (void*)(elem + 1);
18257 void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;
18258 if (elem_end == buffer_end)
18259 ctx->memory.size -= sizeof(struct nk_page_element);
18260 else nk_link_page_element_into_freelist(ctx, elem);}
18261 }
18262
18263 /* ----------------------------------------------------------------
18264 *
18265 * PANEL
18266 *
18267 * ---------------------------------------------------------------*/
18268 NK_INTERN void*
18269 nk_create_panel(struct nk_context *ctx)
18270 {
18271 struct nk_page_element *elem;
18272 elem = nk_create_page_element(ctx);
18273 if (!elem) return 0;
18274 nk_zero_struct(*elem);
18275 return &elem->data.pan;
18276 }
18277
18278 NK_INTERN void
18279 nk_free_panel(struct nk_context *ctx, struct nk_panel *pan)
18280 {
18281 union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);
18282 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
18283 nk_free_page_element(ctx, pe);
18284 }
18285
18286 /* ----------------------------------------------------------------
18287 *
18288 * TABLES
18289 *
18290 * ---------------------------------------------------------------*/
18291 NK_INTERN struct nk_table*
18292 nk_create_table(struct nk_context *ctx)
18293 {
18294 struct nk_page_element *elem;
18295 elem = nk_create_page_element(ctx);
18296 if (!elem) return 0;
18297 nk_zero_struct(*elem);
18298 return &elem->data.tbl;
18299 }
18300
18301 NK_INTERN void
18302 nk_free_table(struct nk_context *ctx, struct nk_table *tbl)
18303 {
18304 union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);
18305 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
18306 nk_free_page_element(ctx, pe);
18307 }
18308
18309 NK_INTERN void
18310 nk_push_table(struct nk_window *win, struct nk_table *tbl)
18311 {
18312 if (!win->tables) {
18313 win->tables = tbl;
18314 tbl->next = 0;
18315 tbl->prev = 0;
18316 tbl->size = 0;
18317 win->table_count = 1;
18318 return;
18319 }
18320 win->tables->prev = tbl;
18321 tbl->next = win->tables;
18322 tbl->prev = 0;
18323 tbl->size = 0;
18324 win->tables = tbl;
18325 win->table_count++;
18326 }
18327
18328 NK_INTERN void
18329 nk_remove_table(struct nk_window *win, struct nk_table *tbl)
18330 {
18331 if (win->tables == tbl)
18332 win->tables = tbl->next;
18333 if (tbl->next)
18334 tbl->next->prev = tbl->prev;
18335 if (tbl->prev)
18336 tbl->prev->next = tbl->next;
18337 tbl->next = 0;
18338 tbl->prev = 0;
18339 }
18340
18341 NK_INTERN nk_uint*
18342 nk_add_value(struct nk_context *ctx, struct nk_window *win,
18343 nk_hash name, nk_uint value)
18344 {
18345 NK_ASSERT(ctx);
18346 NK_ASSERT(win);
18347 if (!win || !ctx) return 0;
18348 if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) {
18349 struct nk_table *tbl = nk_create_table(ctx);
18350 NK_ASSERT(tbl);
18351 if (!tbl) return 0;
18352 nk_push_table(win, tbl);
18353 }
18354 win->tables->seq = win->seq;
18355 win->tables->keys[win->tables->size] = name;
18356 win->tables->values[win->tables->size] = value;
18357 return &win->tables->values[win->tables->size++];
18358 }
18359
18360 NK_INTERN nk_uint*
18361 nk_find_value(struct nk_window *win, nk_hash name)
18362 {
18363 struct nk_table *iter = win->tables;
18364 while (iter) {
18365 unsigned int i = 0;
18366 unsigned int size = iter->size;
18367 for (i = 0; i < size; ++i) {
18368 if (iter->keys[i] == name) {
18369 iter->seq = win->seq;
18370 return &iter->values[i];
18371 }
18372 } size = NK_VALUE_PAGE_CAPACITY;
18373 iter = iter->next;
18374 }
18375 return 0;
18376 }
18377
18378 /* ----------------------------------------------------------------
18379 *
18380 * WINDOW
18381 *
18382 * ---------------------------------------------------------------*/
18383 NK_INTERN void*
18384 nk_create_window(struct nk_context *ctx)
18385 {
18386 struct nk_page_element *elem;
18387 elem = nk_create_page_element(ctx);
18388 if (!elem) return 0;
18389 elem->data.win.seq = ctx->seq;
18390 return &elem->data.win;
18391 }
18392
18393 NK_INTERN void
18394 nk_free_window(struct nk_context *ctx, struct nk_window *win)
18395 {
18396 /* unlink windows from list */
18397 struct nk_table *it = win->tables;
18398 if (win->popup.win) {
18399 nk_free_window(ctx, win->popup.win);
18400 win->popup.win = 0;
18401 }
18402 win->next = 0;
18403 win->prev = 0;
18404
18405 while (it) {
18406 /*free window state tables */
18407 struct nk_table *n = it->next;
18408 nk_remove_table(win, it);
18409 nk_free_table(ctx, it);
18410 if (it == win->tables)
18411 win->tables = n;
18412 it = n;
18413 }
18414
18415 /* link windows into freelist */
18416 {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);
18417 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
18418 nk_free_page_element(ctx, pe);}
18419 }
18420
18421 NK_INTERN struct nk_window*
18422 nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name)
18423 {
18424 struct nk_window *iter;
18425 iter = ctx->begin;
18426 while (iter) {
18427 NK_ASSERT(iter != iter->next);
18428 if (iter->name == hash) {
18429 int max_len = nk_strlen(iter->name_string);
18430 if (!nk_stricmpn(iter->name_string, name, max_len))
18431 return iter;
18432 }
18433 iter = iter->next;
18434 }
18435 return 0;
18436 }
18437
18438 enum nk_window_insert_location {
18439 NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */
18440 NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */
18441 };
18442 NK_INTERN void
18443 nk_insert_window(struct nk_context *ctx, struct nk_window *win,
18444 enum nk_window_insert_location loc)
18445 {
18446 const struct nk_window *iter;
18447 NK_ASSERT(ctx);
18448 NK_ASSERT(win);
18449 if (!win || !ctx) return;
18450
18451 iter = ctx->begin;
18452 while (iter) {
18453 NK_ASSERT(iter != iter->next);
18454 NK_ASSERT(iter != win);
18455 if (iter == win) return;
18456 iter = iter->next;
18457 }
18458
18459 if (!ctx->begin) {
18460 win->next = 0;
18461 win->prev = 0;
18462 ctx->begin = win;
18463 ctx->end = win;
18464 ctx->count = 1;
18465 return;
18466 }
18467 if (loc == NK_INSERT_BACK) {
18468 struct nk_window *end;
18469 end = ctx->end;
18470 end->flags |= NK_WINDOW_ROM;
18471 end->next = win;
18472 win->prev = ctx->end;
18473 win->next = 0;
18474 ctx->end = win;
18475 ctx->active = ctx->end;
18476 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
18477 } else {
18478 /*ctx->end->flags |= NK_WINDOW_ROM;*/
18479 ctx->begin->prev = win;
18480 win->next = ctx->begin;
18481 win->prev = 0;
18482 ctx->begin = win;
18483 ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;
18484 }
18485 ctx->count++;
18486 }
18487
18488 NK_INTERN void
18489 nk_remove_window(struct nk_context *ctx, struct nk_window *win)
18490 {
18491 if (win == ctx->begin || win == ctx->end) {
18492 if (win == ctx->begin) {
18493 ctx->begin = win->next;
18494 if (win->next)
18495 win->next->prev = 0;
18496 }
18497 if (win == ctx->end) {
18498 ctx->end = win->prev;
18499 if (win->prev)
18500 win->prev->next = 0;
18501 }
18502 } else {
18503 if (win->next)
18504 win->next->prev = win->prev;
18505 if (win->prev)
18506 win->prev->next = win->next;
18507 }
18508 if (win == ctx->active || !ctx->active) {
18509 ctx->active = ctx->end;
18510 if (ctx->end)
18511 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
18512 }
18513 win->next = 0;
18514 win->prev = 0;
18515 ctx->count--;
18516 }
18517
18518 NK_API int
18519 nk_begin(struct nk_context *ctx, const char *title,
18520 struct nk_rect bounds, nk_flags flags)
18521 {
18522 return nk_begin_titled(ctx, title, title, bounds, flags);
18523 }
18524
18525 NK_API int
18526 nk_begin_titled(struct nk_context *ctx, const char *name, const char *title,
18527 struct nk_rect bounds, nk_flags flags)
18528 {
18529 struct nk_window *win;
18530 struct nk_style *style;
18531 nk_hash title_hash;
18532 int title_len;
18533 int ret = 0;
18534
18535 NK_ASSERT(ctx);
18536 NK_ASSERT(name);
18537 NK_ASSERT(title);
18538 NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font");
18539 NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call");
18540 if (!ctx || ctx->current || !title || !name)
18541 return 0;
18542
18543 /* find or create window */
18544 style = &ctx->style;
18545 title_len = (int)nk_strlen(name);
18546 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18547 win = nk_find_window(ctx, title_hash, name);
18548 if (!win) {
18549 /* create new window */
18550 nk_size name_length = (nk_size)nk_strlen(name);
18551 win = (struct nk_window*)nk_create_window(ctx);
18552 NK_ASSERT(win);
18553 if (!win) return 0;
18554
18555 if (flags & NK_WINDOW_BACKGROUND)
18556 nk_insert_window(ctx, win, NK_INSERT_FRONT);
18557 else nk_insert_window(ctx, win, NK_INSERT_BACK);
18558 nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);
18559
18560 win->flags = flags;
18561 win->bounds = bounds;
18562 win->name = title_hash;
18563 name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);
18564 NK_MEMCPY(win->name_string, name, name_length);
18565 win->name_string[name_length] = 0;
18566 win->popup.win = 0;
18567 if (!ctx->active)
18568 ctx->active = win;
18569 } else {
18570 /* update window */
18571 win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);
18572 win->flags |= flags;
18573 if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))
18574 win->bounds = bounds;
18575 /* If this assert triggers you either:
18576 *
18577 * I.) Have more than one window with the same name or
18578 * II.) You forgot to actually draw the window.
18579 * More specific you did not call `nk_clear` (nk_clear will be
18580 * automatically called for you if you are using one of the
18581 * provided demo backends). */
18582 NK_ASSERT(win->seq != ctx->seq);
18583 win->seq = ctx->seq;
18584 if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) {
18585 ctx->active = win;
18586 ctx->end = win;
18587 }
18588 }
18589 if (win->flags & NK_WINDOW_HIDDEN) {
18590 ctx->current = win;
18591 win->layout = 0;
18592 return 0;
18593 }
18594
18595 /* window overlapping */
18596 if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))
18597 {
18598 int inpanel, ishovered;
18599 struct nk_window *iter = win;
18600 float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +
18601 (2.0f * style->window.header.label_padding.y);
18602 struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?
18603 win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);
18604
18605 /* activate window if hovered and no other window is overlapping this window */
18606 nk_start(ctx, win);
18607 inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);
18608 inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;
18609 ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);
18610 if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {
18611 iter = win->next;
18612 while (iter) {
18613 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
18614 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
18615 if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18616 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
18617 (!(iter->flags & NK_WINDOW_HIDDEN)))
18618 break;
18619
18620 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
18621 NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18622 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
18623 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
18624 break;
18625 iter = iter->next;
18626 }
18627 }
18628
18629 /* activate window if clicked */
18630 if (iter && inpanel && (win != ctx->end)) {
18631 iter = win->next;
18632 while (iter) {
18633 /* try to find a panel with higher priority in the same position */
18634 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
18635 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
18636 if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,
18637 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
18638 !(iter->flags & NK_WINDOW_HIDDEN))
18639 break;
18640 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
18641 NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
18642 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
18643 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
18644 break;
18645 iter = iter->next;
18646 }
18647 }
18648 if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) {
18649 win->flags |= (nk_flags)NK_WINDOW_ROM;
18650 iter->flags &= ~(nk_flags)NK_WINDOW_ROM;
18651 ctx->active = iter;
18652 if (!(iter->flags & NK_WINDOW_BACKGROUND)) {
18653 /* current window is active in that position so transfer to top
18654 * at the highest priority in stack */
18655 nk_remove_window(ctx, iter);
18656 nk_insert_window(ctx, iter, NK_INSERT_BACK);
18657 }
18658 } else {
18659 if (!iter && ctx->end != win) {
18660 if (!(win->flags & NK_WINDOW_BACKGROUND)) {
18661 /* current window is active in that position so transfer to top
18662 * at the highest priority in stack */
18663 nk_remove_window(ctx, win);
18664 nk_insert_window(ctx, win, NK_INSERT_BACK);
18665 }
18666 win->flags &= ~(nk_flags)NK_WINDOW_ROM;
18667 ctx->active = win;
18668 }
18669 if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))
18670 win->flags |= NK_WINDOW_ROM;
18671 }
18672 }
18673
18674 win->layout = (struct nk_panel*)nk_create_panel(ctx);
18675 ctx->current = win;
18676 ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);
18677 win->layout->offset_x = &win->scrollbar.x;
18678 win->layout->offset_y = &win->scrollbar.y;
18679 return ret;
18680 }
18681
18682 NK_API void
18683 nk_end(struct nk_context *ctx)
18684 {
18685 struct nk_panel *layout;
18686 NK_ASSERT(ctx);
18687 NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`");
18688 if (!ctx || !ctx->current)
18689 return;
18690
18691 layout = ctx->current->layout;
18692 if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {
18693 ctx->current = 0;
18694 return;
18695 }
18696 nk_panel_end(ctx);
18697 nk_free_panel(ctx, ctx->current->layout);
18698 ctx->current = 0;
18699 }
18700
18701 NK_API struct nk_rect
18702 nk_window_get_bounds(const struct nk_context *ctx)
18703 {
18704 NK_ASSERT(ctx);
18705 NK_ASSERT(ctx->current);
18706 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
18707 return ctx->current->bounds;
18708 }
18709
18710 NK_API struct nk_vec2
18711 nk_window_get_position(const struct nk_context *ctx)
18712 {
18713 NK_ASSERT(ctx);
18714 NK_ASSERT(ctx->current);
18715 if (!ctx || !ctx->current) return nk_vec2(0,0);
18716 return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);
18717 }
18718
18719 NK_API struct nk_vec2
18720 nk_window_get_size(const struct nk_context *ctx)
18721 {
18722 NK_ASSERT(ctx);
18723 NK_ASSERT(ctx->current);
18724 if (!ctx || !ctx->current) return nk_vec2(0,0);
18725 return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);
18726 }
18727
18728 NK_API float
18729 nk_window_get_width(const struct nk_context *ctx)
18730 {
18731 NK_ASSERT(ctx);
18732 NK_ASSERT(ctx->current);
18733 if (!ctx || !ctx->current) return 0;
18734 return ctx->current->bounds.w;
18735 }
18736
18737 NK_API float
18738 nk_window_get_height(const struct nk_context *ctx)
18739 {
18740 NK_ASSERT(ctx);
18741 NK_ASSERT(ctx->current);
18742 if (!ctx || !ctx->current) return 0;
18743 return ctx->current->bounds.h;
18744 }
18745
18746 NK_API struct nk_rect
18747 nk_window_get_content_region(struct nk_context *ctx)
18748 {
18749 NK_ASSERT(ctx);
18750 NK_ASSERT(ctx->current);
18751 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
18752 return ctx->current->layout->clip;
18753 }
18754
18755 NK_API struct nk_vec2
18756 nk_window_get_content_region_min(struct nk_context *ctx)
18757 {
18758 NK_ASSERT(ctx);
18759 NK_ASSERT(ctx->current);
18760 NK_ASSERT(ctx->current->layout);
18761 if (!ctx || !ctx->current) return nk_vec2(0,0);
18762 return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);
18763 }
18764
18765 NK_API struct nk_vec2
18766 nk_window_get_content_region_max(struct nk_context *ctx)
18767 {
18768 NK_ASSERT(ctx);
18769 NK_ASSERT(ctx->current);
18770 NK_ASSERT(ctx->current->layout);
18771 if (!ctx || !ctx->current) return nk_vec2(0,0);
18772 return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,
18773 ctx->current->layout->clip.y + ctx->current->layout->clip.h);
18774 }
18775
18776 NK_API struct nk_vec2
18777 nk_window_get_content_region_size(struct nk_context *ctx)
18778 {
18779 NK_ASSERT(ctx);
18780 NK_ASSERT(ctx->current);
18781 NK_ASSERT(ctx->current->layout);
18782 if (!ctx || !ctx->current) return nk_vec2(0,0);
18783 return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);
18784 }
18785
18786 NK_API struct nk_command_buffer*
18787 nk_window_get_canvas(struct nk_context *ctx)
18788 {
18789 NK_ASSERT(ctx);
18790 NK_ASSERT(ctx->current);
18791 NK_ASSERT(ctx->current->layout);
18792 if (!ctx || !ctx->current) return 0;
18793 return &ctx->current->buffer;
18794 }
18795
18796 NK_API struct nk_panel*
18797 nk_window_get_panel(struct nk_context *ctx)
18798 {
18799 NK_ASSERT(ctx);
18800 NK_ASSERT(ctx->current);
18801 if (!ctx || !ctx->current) return 0;
18802 return ctx->current->layout;
18803 }
18804
18805 NK_API int
18806 nk_window_has_focus(const struct nk_context *ctx)
18807 {
18808 NK_ASSERT(ctx);
18809 NK_ASSERT(ctx->current);
18810 NK_ASSERT(ctx->current->layout);
18811 if (!ctx || !ctx->current) return 0;
18812 return ctx->current == ctx->active;
18813 }
18814
18815 NK_API int
18816 nk_window_is_hovered(struct nk_context *ctx)
18817 {
18818 NK_ASSERT(ctx);
18819 NK_ASSERT(ctx->current);
18820 if (!ctx || !ctx->current) return 0;
18821 if(ctx->current->flags & NK_WINDOW_HIDDEN)
18822 return 0;
18823 return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds);
18824 }
18825
18826 NK_API int
18827 nk_window_is_any_hovered(struct nk_context *ctx)
18828 {
18829 struct nk_window *iter;
18830 NK_ASSERT(ctx);
18831 if (!ctx) return 0;
18832 iter = ctx->begin;
18833 while (iter) {
18834 /* check if window is being hovered */
18835 if(!(iter->flags & NK_WINDOW_HIDDEN)) {
18836 /* check if window popup is being hovered */
18837 if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))
18838 return 1;
18839
18840 if (iter->flags & NK_WINDOW_MINIMIZED) {
18841 struct nk_rect header = iter->bounds;
18842 header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;
18843 if (nk_input_is_mouse_hovering_rect(&ctx->input, header))
18844 return 1;
18845 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {
18846 return 1;
18847 }
18848 }
18849 iter = iter->next;
18850 }
18851 return 0;
18852 }
18853
18854 NK_API int
18855 nk_item_is_any_active(struct nk_context *ctx)
18856 {
18857 int any_hovered = nk_window_is_any_hovered(ctx);
18858 int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
18859 return any_hovered || any_active;
18860 }
18861
18862 NK_API int
18863 nk_window_is_collapsed(struct nk_context *ctx, const char *name)
18864 {
18865 int title_len;
18866 nk_hash title_hash;
18867 struct nk_window *win;
18868 NK_ASSERT(ctx);
18869 if (!ctx) return 0;
18870
18871 title_len = (int)nk_strlen(name);
18872 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18873 win = nk_find_window(ctx, title_hash, name);
18874 if (!win) return 0;
18875 return win->flags & NK_WINDOW_MINIMIZED;
18876 }
18877
18878 NK_API int
18879 nk_window_is_closed(struct nk_context *ctx, const char *name)
18880 {
18881 int title_len;
18882 nk_hash title_hash;
18883 struct nk_window *win;
18884 NK_ASSERT(ctx);
18885 if (!ctx) return 1;
18886
18887 title_len = (int)nk_strlen(name);
18888 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18889 win = nk_find_window(ctx, title_hash, name);
18890 if (!win) return 1;
18891 return (win->flags & NK_WINDOW_CLOSED);
18892 }
18893
18894 NK_API int
18895 nk_window_is_hidden(struct nk_context *ctx, const char *name)
18896 {
18897 int title_len;
18898 nk_hash title_hash;
18899 struct nk_window *win;
18900 NK_ASSERT(ctx);
18901 if (!ctx) return 1;
18902
18903 title_len = (int)nk_strlen(name);
18904 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18905 win = nk_find_window(ctx, title_hash, name);
18906 if (!win) return 1;
18907 return (win->flags & NK_WINDOW_HIDDEN);
18908 }
18909
18910 NK_API int
18911 nk_window_is_active(struct nk_context *ctx, const char *name)
18912 {
18913 int title_len;
18914 nk_hash title_hash;
18915 struct nk_window *win;
18916 NK_ASSERT(ctx);
18917 if (!ctx) return 0;
18918
18919 title_len = (int)nk_strlen(name);
18920 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18921 win = nk_find_window(ctx, title_hash, name);
18922 if (!win) return 0;
18923 return win == ctx->active;
18924 }
18925
18926 NK_API struct nk_window*
18927 nk_window_find(struct nk_context *ctx, const char *name)
18928 {
18929 int title_len;
18930 nk_hash title_hash;
18931 title_len = (int)nk_strlen(name);
18932 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18933 return nk_find_window(ctx, title_hash, name);
18934 }
18935
18936 NK_API void
18937 nk_window_close(struct nk_context *ctx, const char *name)
18938 {
18939 struct nk_window *win;
18940 NK_ASSERT(ctx);
18941 if (!ctx) return;
18942 win = nk_window_find(ctx, name);
18943 if (!win) return;
18944 NK_ASSERT(ctx->current != win && "You cannot close a currently active window");
18945 if (ctx->current == win) return;
18946 win->flags |= NK_WINDOW_HIDDEN;
18947 win->flags |= NK_WINDOW_CLOSED;
18948 }
18949
18950 NK_API void
18951 nk_window_set_bounds(struct nk_context *ctx,
18952 const char *name, struct nk_rect bounds)
18953 {
18954 struct nk_window *win;
18955 NK_ASSERT(ctx);
18956 if (!ctx) return;
18957 win = nk_window_find(ctx, name);
18958 if (!win) return;
18959 NK_ASSERT(ctx->current != win && "You cannot update a currently in procecss window");
18960 win->bounds = bounds;
18961 }
18962
18963 NK_API void
18964 nk_window_set_position(struct nk_context *ctx,
18965 const char *name, struct nk_vec2 pos)
18966 {
18967 struct nk_window *win = nk_window_find(ctx, name);
18968 if (!win) return;
18969 win->bounds.x = pos.x;
18970 win->bounds.y = pos.y;
18971 }
18972
18973 NK_API void
18974 nk_window_set_size(struct nk_context *ctx,
18975 const char *name, struct nk_vec2 size)
18976 {
18977 struct nk_window *win = nk_window_find(ctx, name);
18978 if (!win) return;
18979 win->bounds.w = size.x;
18980 win->bounds.h = size.y;
18981 }
18982
18983 NK_API void
18984 nk_window_collapse(struct nk_context *ctx, const char *name,
18985 enum nk_collapse_states c)
18986 {
18987 int title_len;
18988 nk_hash title_hash;
18989 struct nk_window *win;
18990 NK_ASSERT(ctx);
18991 if (!ctx) return;
18992
18993 title_len = (int)nk_strlen(name);
18994 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
18995 win = nk_find_window(ctx, title_hash, name);
18996 if (!win) return;
18997 if (c == NK_MINIMIZED)
18998 win->flags |= NK_WINDOW_MINIMIZED;
18999 else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;
19000 }
19001
19002 NK_API void
19003 nk_window_collapse_if(struct nk_context *ctx, const char *name,
19004 enum nk_collapse_states c, int cond)
19005 {
19006 NK_ASSERT(ctx);
19007 if (!ctx || !cond) return;
19008 nk_window_collapse(ctx, name, c);
19009 }
19010
19011 NK_API void
19012 nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)
19013 {
19014 int title_len;
19015 nk_hash title_hash;
19016 struct nk_window *win;
19017 NK_ASSERT(ctx);
19018 if (!ctx) return;
19019
19020 title_len = (int)nk_strlen(name);
19021 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
19022 win = nk_find_window(ctx, title_hash, name);
19023 if (!win) return;
19024 if (s == NK_HIDDEN) {
19025 win->flags |= NK_WINDOW_HIDDEN;
19026 } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;
19027 }
19028
19029 NK_API void
19030 nk_window_show_if(struct nk_context *ctx, const char *name,
19031 enum nk_show_states s, int cond)
19032 {
19033 NK_ASSERT(ctx);
19034 if (!ctx || !cond) return;
19035 nk_window_show(ctx, name, s);
19036 }
19037
19038 NK_API void
19039 nk_window_set_focus(struct nk_context *ctx, const char *name)
19040 {
19041 int title_len;
19042 nk_hash title_hash;
19043 struct nk_window *win;
19044 NK_ASSERT(ctx);
19045 if (!ctx) return;
19046
19047 title_len = (int)nk_strlen(name);
19048 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
19049 win = nk_find_window(ctx, title_hash, name);
19050 if (win && ctx->end != win) {
19051 nk_remove_window(ctx, win);
19052 nk_insert_window(ctx, win, NK_INSERT_BACK);
19053 }
19054 ctx->active = win;
19055 }
19056
19057 /*----------------------------------------------------------------
19058 *
19059 * MENUBAR
19060 *
19061 * --------------------------------------------------------------*/
19062 NK_API void
19063 nk_menubar_begin(struct nk_context *ctx)
19064 {
19065 struct nk_panel *layout;
19066 NK_ASSERT(ctx);
19067 NK_ASSERT(ctx->current);
19068 NK_ASSERT(ctx->current->layout);
19069 if (!ctx || !ctx->current || !ctx->current->layout)
19070 return;
19071
19072 layout = ctx->current->layout;
19073 NK_ASSERT(layout->at_y == layout->bounds.y);
19074 /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.
19075 If you want a menubar the first nuklear function after `nk_begin` has to be a
19076 `nk_menubar_begin` call. Inside the menubar you then have to allocate space for
19077 widgets (also supports multiple rows).
19078 Example:
19079 if (nk_begin(...)) {
19080 nk_menubar_begin(...);
19081 nk_layout_xxxx(...);
19082 nk_button(...);
19083 nk_layout_xxxx(...);
19084 nk_button(...);
19085 nk_menubar_end(...);
19086 }
19087 nk_end(...);
19088 */
19089 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
19090 return;
19091
19092 layout->menu.x = layout->at_x;
19093 layout->menu.y = layout->at_y + layout->row.height;
19094 layout->menu.w = layout->bounds.w;
19095 layout->menu.offset.x = *layout->offset_x;
19096 layout->menu.offset.y = *layout->offset_y;
19097 *layout->offset_y = 0;
19098 }
19099
19100 NK_API void
19101 nk_menubar_end(struct nk_context *ctx)
19102 {
19103 struct nk_window *win;
19104 struct nk_panel *layout;
19105 struct nk_command_buffer *out;
19106
19107 NK_ASSERT(ctx);
19108 NK_ASSERT(ctx->current);
19109 NK_ASSERT(ctx->current->layout);
19110 if (!ctx || !ctx->current || !ctx->current->layout)
19111 return;
19112
19113 win = ctx->current;
19114 out = &win->buffer;
19115 layout = win->layout;
19116 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
19117 return;
19118
19119 layout->menu.h = layout->at_y - layout->menu.y;
19120 layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
19121 layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height;
19122
19123 *layout->offset_x = layout->menu.offset.x;
19124 *layout->offset_y = layout->menu.offset.y;
19125 layout->at_y = layout->bounds.y - layout->row.height;
19126
19127 layout->clip.y = layout->bounds.y;
19128 layout->clip.h = layout->bounds.h;
19129 nk_push_scissor(out, layout->clip);
19130 }
19131 /* -------------------------------------------------------------
19132 *
19133 * LAYOUT
19134 *
19135 * --------------------------------------------------------------*/
19136 NK_API void
19137 nk_layout_set_min_row_height(struct nk_context *ctx, float height)
19138 {
19139 struct nk_window *win;
19140 struct nk_panel *layout;
19141
19142 NK_ASSERT(ctx);
19143 NK_ASSERT(ctx->current);
19144 NK_ASSERT(ctx->current->layout);
19145 if (!ctx || !ctx->current || !ctx->current->layout)
19146 return;
19147
19148 win = ctx->current;
19149 layout = win->layout;
19150 layout->row.min_height = height;
19151 }
19152
19153 NK_API void
19154 nk_layout_reset_min_row_height(struct nk_context *ctx)
19155 {
19156 struct nk_window *win;
19157 struct nk_panel *layout;
19158
19159 NK_ASSERT(ctx);
19160 NK_ASSERT(ctx->current);
19161 NK_ASSERT(ctx->current->layout);
19162 if (!ctx || !ctx->current || !ctx->current->layout)
19163 return;
19164
19165 win = ctx->current;
19166 layout = win->layout;
19167 layout->row.min_height = ctx->style.font->height;
19168 layout->row.min_height += ctx->style.text.padding.y*2;
19169 layout->row.min_height += ctx->style.window.min_row_height_padding*2;
19170 }
19171
19172 NK_INTERN float
19173 nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
19174 float total_space, int columns)
19175 {
19176 float panel_padding;
19177 float panel_spacing;
19178 float panel_space;
19179
19180 struct nk_vec2 spacing;
19181 struct nk_vec2 padding;
19182
19183 spacing = style->window.spacing;
19184 padding = nk_panel_get_padding(style, type);
19185
19186 /* calculate the usable panel space */
19187 panel_padding = 2 * padding.x;
19188 panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
19189 panel_space = total_space - panel_padding - panel_spacing;
19190 return panel_space;
19191 }
19192
19193 NK_INTERN void
19194 nk_panel_layout(const struct nk_context *ctx, struct nk_window *win,
19195 float height, int cols)
19196 {
19197 struct nk_panel *layout;
19198 const struct nk_style *style;
19199 struct nk_command_buffer *out;
19200
19201 struct nk_vec2 item_spacing;
19202 struct nk_color color;
19203
19204 NK_ASSERT(ctx);
19205 NK_ASSERT(ctx->current);
19206 NK_ASSERT(ctx->current->layout);
19207 if (!ctx || !ctx->current || !ctx->current->layout)
19208 return;
19209
19210 /* prefetch some configuration data */
19211 layout = win->layout;
19212 style = &ctx->style;
19213 out = &win->buffer;
19214 color = style->window.background;
19215 item_spacing = style->window.spacing;
19216
19217 /* if one of these triggers you forgot to add an `if` condition around either
19218 a window, group, popup, combobox or contextual menu `begin` and `end` block.
19219 Example:
19220 if (nk_begin(...) {...} nk_end(...); or
19221 if (nk_group_begin(...) { nk_group_end(...);} */
19222 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
19223 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
19224 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
19225
19226 /* update the current row and set the current row layout */
19227 layout->row.index = 0;
19228 layout->at_y += layout->row.height;
19229 layout->row.columns = cols;
19230 if (height == 0.0f)
19231 layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;
19232 else layout->row.height = height + item_spacing.y;
19233
19234 layout->row.item_offset = 0;
19235 if (layout->flags & NK_WINDOW_DYNAMIC) {
19236 /* draw background for dynamic panels */
19237 struct nk_rect background;
19238 background.x = win->bounds.x;
19239 background.w = win->bounds.w;
19240 background.y = layout->at_y - 1.0f;
19241 background.h = layout->row.height + 1.0f;
19242 nk_fill_rect(out, background, 0, color);
19243 }
19244 }
19245
19246 NK_INTERN void
19247 nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
19248 float height, int cols, int width)
19249 {
19250 /* update the current row and set the current row layout */
19251 struct nk_window *win;
19252 NK_ASSERT(ctx);
19253 NK_ASSERT(ctx->current);
19254 NK_ASSERT(ctx->current->layout);
19255 if (!ctx || !ctx->current || !ctx->current->layout)
19256 return;
19257
19258 win = ctx->current;
19259 nk_panel_layout(ctx, win, height, cols);
19260 if (fmt == NK_DYNAMIC)
19261 win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;
19262 else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;
19263
19264 win->layout->row.ratio = 0;
19265 win->layout->row.filled = 0;
19266 win->layout->row.item_offset = 0;
19267 win->layout->row.item_width = (float)width;
19268 }
19269
19270 NK_API float
19271 nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width)
19272 {
19273 struct nk_window *win;
19274 NK_ASSERT(ctx);
19275 NK_ASSERT(pixel_width);
19276 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
19277 win = ctx->current;
19278 return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);
19279 }
19280
19281 NK_API void
19282 nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
19283 {
19284 nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);
19285 }
19286
19287 NK_API void
19288 nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
19289 {
19290 nk_row_layout(ctx, NK_STATIC, height, cols, item_width);
19291 }
19292
19293 NK_API void
19294 nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,
19295 float row_height, int cols)
19296 {
19297 struct nk_window *win;
19298 struct nk_panel *layout;
19299
19300 NK_ASSERT(ctx);
19301 NK_ASSERT(ctx->current);
19302 NK_ASSERT(ctx->current->layout);
19303 if (!ctx || !ctx->current || !ctx->current->layout)
19304 return;
19305
19306 win = ctx->current;
19307 layout = win->layout;
19308 nk_panel_layout(ctx, win, row_height, cols);
19309 if (fmt == NK_DYNAMIC)
19310 layout->row.type = NK_LAYOUT_DYNAMIC_ROW;
19311 else layout->row.type = NK_LAYOUT_STATIC_ROW;
19312
19313 layout->row.ratio = 0;
19314 layout->row.filled = 0;
19315 layout->row.item_width = 0;
19316 layout->row.item_offset = 0;
19317 layout->row.columns = cols;
19318 }
19319
19320 NK_API void
19321 nk_layout_row_push(struct nk_context *ctx, float ratio_or_width)
19322 {
19323 struct nk_window *win;
19324 struct nk_panel *layout;
19325
19326 NK_ASSERT(ctx);
19327 NK_ASSERT(ctx->current);
19328 NK_ASSERT(ctx->current->layout);
19329 if (!ctx || !ctx->current || !ctx->current->layout)
19330 return;
19331
19332 win = ctx->current;
19333 layout = win->layout;
19334 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
19335 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
19336 return;
19337
19338 if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {
19339 float ratio = ratio_or_width;
19340 if ((ratio + layout->row.filled) > 1.0f) return;
19341 if (ratio > 0.0f)
19342 layout->row.item_width = NK_SATURATE(ratio);
19343 else layout->row.item_width = 1.0f - layout->row.filled;
19344 } else layout->row.item_width = ratio_or_width;
19345 }
19346
19347 NK_API void
19348 nk_layout_row_end(struct nk_context *ctx)
19349 {
19350 struct nk_window *win;
19351 struct nk_panel *layout;
19352
19353 NK_ASSERT(ctx);
19354 NK_ASSERT(ctx->current);
19355 NK_ASSERT(ctx->current->layout);
19356 if (!ctx || !ctx->current || !ctx->current->layout)
19357 return;
19358
19359 win = ctx->current;
19360 layout = win->layout;
19361 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
19362 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
19363 return;
19364 layout->row.item_width = 0;
19365 layout->row.item_offset = 0;
19366 }
19367
19368 NK_API void
19369 nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,
19370 float height, int cols, const float *ratio)
19371 {
19372 int i;
19373 int n_undef = 0;
19374 struct nk_window *win;
19375 struct nk_panel *layout;
19376
19377 NK_ASSERT(ctx);
19378 NK_ASSERT(ctx->current);
19379 NK_ASSERT(ctx->current->layout);
19380 if (!ctx || !ctx->current || !ctx->current->layout)
19381 return;
19382
19383 win = ctx->current;
19384 layout = win->layout;
19385 nk_panel_layout(ctx, win, height, cols);
19386 if (fmt == NK_DYNAMIC) {
19387 /* calculate width of undefined widget ratios */
19388 float r = 0;
19389 layout->row.ratio = ratio;
19390 for (i = 0; i < cols; ++i) {
19391 if (ratio[i] < 0.0f)
19392 n_undef++;
19393 else r += ratio[i];
19394 }
19395 r = NK_SATURATE(1.0f - r);
19396 layout->row.type = NK_LAYOUT_DYNAMIC;
19397 layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;
19398 } else {
19399 layout->row.ratio = ratio;
19400 layout->row.type = NK_LAYOUT_STATIC;
19401 layout->row.item_width = 0;
19402 layout->row.item_offset = 0;
19403 }
19404 layout->row.item_offset = 0;
19405 layout->row.filled = 0;
19406 }
19407
19408 NK_API void
19409 nk_layout_row_template_begin(struct nk_context *ctx, float height)
19410 {
19411 struct nk_window *win;
19412 struct nk_panel *layout;
19413
19414 NK_ASSERT(ctx);
19415 NK_ASSERT(ctx->current);
19416 NK_ASSERT(ctx->current->layout);
19417 if (!ctx || !ctx->current || !ctx->current->layout)
19418 return;
19419
19420 win = ctx->current;
19421 layout = win->layout;
19422 nk_panel_layout(ctx, win, height, 1);
19423 layout->row.type = NK_LAYOUT_TEMPLATE;
19424 layout->row.columns = 0;
19425 layout->row.ratio = 0;
19426 layout->row.item_width = 0;
19427 layout->row.item_height = 0;
19428 layout->row.item_offset = 0;
19429 layout->row.filled = 0;
19430 layout->row.item.x = 0;
19431 layout->row.item.y = 0;
19432 layout->row.item.w = 0;
19433 layout->row.item.h = 0;
19434 }
19435
19436 NK_API void
19437 nk_layout_row_template_push_dynamic(struct nk_context *ctx)
19438 {
19439 struct nk_window *win;
19440 struct nk_panel *layout;
19441
19442 NK_ASSERT(ctx);
19443 NK_ASSERT(ctx->current);
19444 NK_ASSERT(ctx->current->layout);
19445 if (!ctx || !ctx->current || !ctx->current->layout)
19446 return;
19447
19448 win = ctx->current;
19449 layout = win->layout;
19450 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
19451 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
19452 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
19453 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
19454 layout->row.templates[layout->row.columns++] = -1.0f;
19455 }
19456
19457 NK_API void
19458 nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)
19459 {
19460 struct nk_window *win;
19461 struct nk_panel *layout;
19462
19463 NK_ASSERT(ctx);
19464 NK_ASSERT(ctx->current);
19465 NK_ASSERT(ctx->current->layout);
19466 if (!ctx || !ctx->current || !ctx->current->layout)
19467 return;
19468
19469 win = ctx->current;
19470 layout = win->layout;
19471 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
19472 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
19473 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
19474 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
19475 layout->row.templates[layout->row.columns++] = -min_width;
19476 }
19477
19478 NK_API void
19479 nk_layout_row_template_push_static(struct nk_context *ctx, float width)
19480 {
19481 struct nk_window *win;
19482 struct nk_panel *layout;
19483
19484 NK_ASSERT(ctx);
19485 NK_ASSERT(ctx->current);
19486 NK_ASSERT(ctx->current->layout);
19487 if (!ctx || !ctx->current || !ctx->current->layout)
19488 return;
19489
19490 win = ctx->current;
19491 layout = win->layout;
19492 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
19493 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
19494 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
19495 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
19496 layout->row.templates[layout->row.columns++] = width;
19497 }
19498
19499 NK_API void
19500 nk_layout_row_template_end(struct nk_context *ctx)
19501 {
19502 struct nk_window *win;
19503 struct nk_panel *layout;
19504
19505 int i = 0;
19506 int variable_count = 0;
19507 int min_variable_count = 0;
19508 float min_fixed_width = 0.0f;
19509 float total_fixed_width = 0.0f;
19510 float max_variable_width = 0.0f;
19511
19512 NK_ASSERT(ctx);
19513 NK_ASSERT(ctx->current);
19514 NK_ASSERT(ctx->current->layout);
19515 if (!ctx || !ctx->current || !ctx->current->layout)
19516 return;
19517
19518 win = ctx->current;
19519 layout = win->layout;
19520 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
19521 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
19522 for (i = 0; i < layout->row.columns; ++i) {
19523 float width = layout->row.templates[i];
19524 if (width >= 0.0f) {
19525 total_fixed_width += width;
19526 min_fixed_width += width;
19527 } else if (width < -1.0f) {
19528 width = -width;
19529 total_fixed_width += width;
19530 max_variable_width = NK_MAX(max_variable_width, width);
19531 variable_count++;
19532 } else {
19533 min_variable_count++;
19534 variable_count++;
19535 }
19536 }
19537 if (variable_count) {
19538 float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
19539 layout->bounds.w, layout->row.columns);
19540 float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;
19541 int enough_space = var_width >= max_variable_width;
19542 if (!enough_space)
19543 var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;
19544 for (i = 0; i < layout->row.columns; ++i) {
19545 float *width = &layout->row.templates[i];
19546 *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;
19547 }
19548 }
19549 }
19550
19551 NK_API void
19552 nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,
19553 float height, int widget_count)
19554 {
19555 struct nk_window *win;
19556 struct nk_panel *layout;
19557
19558 NK_ASSERT(ctx);
19559 NK_ASSERT(ctx->current);
19560 NK_ASSERT(ctx->current->layout);
19561 if (!ctx || !ctx->current || !ctx->current->layout)
19562 return;
19563
19564 win = ctx->current;
19565 layout = win->layout;
19566 nk_panel_layout(ctx, win, height, widget_count);
19567 if (fmt == NK_STATIC)
19568 layout->row.type = NK_LAYOUT_STATIC_FREE;
19569 else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;
19570
19571 layout->row.ratio = 0;
19572 layout->row.filled = 0;
19573 layout->row.item_width = 0;
19574 layout->row.item_offset = 0;
19575 }
19576
19577 NK_API void
19578 nk_layout_space_end(struct nk_context *ctx)
19579 {
19580 struct nk_window *win;
19581 struct nk_panel *layout;
19582
19583 NK_ASSERT(ctx);
19584 NK_ASSERT(ctx->current);
19585 NK_ASSERT(ctx->current->layout);
19586 if (!ctx || !ctx->current || !ctx->current->layout)
19587 return;
19588
19589 win = ctx->current;
19590 layout = win->layout;
19591 layout->row.item_width = 0;
19592 layout->row.item_height = 0;
19593 layout->row.item_offset = 0;
19594 nk_zero(&layout->row.item, sizeof(layout->row.item));
19595 }
19596
19597 NK_API void
19598 nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
19599 {
19600 struct nk_window *win;
19601 struct nk_panel *layout;
19602
19603 NK_ASSERT(ctx);
19604 NK_ASSERT(ctx->current);
19605 NK_ASSERT(ctx->current->layout);
19606 if (!ctx || !ctx->current || !ctx->current->layout)
19607 return;
19608
19609 win = ctx->current;
19610 layout = win->layout;
19611 layout->row.item = rect;
19612 }
19613
19614 NK_API struct nk_rect
19615 nk_layout_space_bounds(struct nk_context *ctx)
19616 {
19617 struct nk_rect ret;
19618 struct nk_window *win;
19619 struct nk_panel *layout;
19620
19621 NK_ASSERT(ctx);
19622 NK_ASSERT(ctx->current);
19623 NK_ASSERT(ctx->current->layout);
19624 win = ctx->current;
19625 layout = win->layout;
19626
19627 ret.x = layout->clip.x;
19628 ret.y = layout->clip.y;
19629 ret.w = layout->clip.w;
19630 ret.h = layout->row.height;
19631 return ret;
19632 }
19633
19634 NK_API struct nk_rect
19635 nk_layout_widget_bounds(struct nk_context *ctx)
19636 {
19637 struct nk_rect ret;
19638 struct nk_window *win;
19639 struct nk_panel *layout;
19640
19641 NK_ASSERT(ctx);
19642 NK_ASSERT(ctx->current);
19643 NK_ASSERT(ctx->current->layout);
19644 win = ctx->current;
19645 layout = win->layout;
19646
19647 ret.x = layout->at_x;
19648 ret.y = layout->at_y;
19649 ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);
19650 ret.h = layout->row.height;
19651 return ret;
19652 }
19653
19654 NK_API struct nk_vec2
19655 nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
19656 {
19657 struct nk_window *win;
19658 struct nk_panel *layout;
19659
19660 NK_ASSERT(ctx);
19661 NK_ASSERT(ctx->current);
19662 NK_ASSERT(ctx->current->layout);
19663 win = ctx->current;
19664 layout = win->layout;
19665
19666 ret.x += layout->at_x - (float)*layout->offset_x;
19667 ret.y += layout->at_y - (float)*layout->offset_y;
19668 return ret;
19669 }
19670
19671 NK_API struct nk_vec2
19672 nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
19673 {
19674 struct nk_window *win;
19675 struct nk_panel *layout;
19676
19677 NK_ASSERT(ctx);
19678 NK_ASSERT(ctx->current);
19679 NK_ASSERT(ctx->current->layout);
19680 win = ctx->current;
19681 layout = win->layout;
19682
19683 ret.x += -layout->at_x + (float)*layout->offset_x;
19684 ret.y += -layout->at_y + (float)*layout->offset_y;
19685 return ret;
19686 }
19687
19688 NK_API struct nk_rect
19689 nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
19690 {
19691 struct nk_window *win;
19692 struct nk_panel *layout;
19693
19694 NK_ASSERT(ctx);
19695 NK_ASSERT(ctx->current);
19696 NK_ASSERT(ctx->current->layout);
19697 win = ctx->current;
19698 layout = win->layout;
19699
19700 ret.x += layout->at_x - (float)*layout->offset_x;
19701 ret.y += layout->at_y - (float)*layout->offset_y;
19702 return ret;
19703 }
19704
19705 NK_API struct nk_rect
19706 nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret)
19707 {
19708 struct nk_window *win;
19709 struct nk_panel *layout;
19710
19711 NK_ASSERT(ctx);
19712 NK_ASSERT(ctx->current);
19713 NK_ASSERT(ctx->current->layout);
19714 win = ctx->current;
19715 layout = win->layout;
19716
19717 ret.x += -layout->at_x + (float)*layout->offset_x;
19718 ret.y += -layout->at_y + (float)*layout->offset_y;
19719 return ret;
19720 }
19721
19722 NK_INTERN void
19723 nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)
19724 {
19725 struct nk_panel *layout = win->layout;
19726 struct nk_vec2 spacing = ctx->style.window.spacing;
19727 const float row_height = layout->row.height - spacing.y;
19728 nk_panel_layout(ctx, win, row_height, layout->row.columns);
19729 }
19730
19731 NK_INTERN void
19732 nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,
19733 struct nk_window *win, int modify)
19734 {
19735 struct nk_panel *layout;
19736 const struct nk_style *style;
19737
19738 struct nk_vec2 spacing;
19739 struct nk_vec2 padding;
19740
19741 float item_offset = 0;
19742 float item_width = 0;
19743 float item_spacing = 0;
19744 float panel_space = 0;
19745
19746 NK_ASSERT(ctx);
19747 NK_ASSERT(ctx->current);
19748 NK_ASSERT(ctx->current->layout);
19749 if (!ctx || !ctx->current || !ctx->current->layout)
19750 return;
19751
19752 win = ctx->current;
19753 layout = win->layout;
19754 style = &ctx->style;
19755 NK_ASSERT(bounds);
19756
19757 spacing = style->window.spacing;
19758 padding = nk_panel_get_padding(style, layout->type);
19759 panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
19760 layout->bounds.w, layout->row.columns);
19761
19762 /* calculate the width of one item inside the current layout space */
19763 switch (layout->row.type) {
19764 case NK_LAYOUT_DYNAMIC_FIXED: {
19765 /* scaling fixed size widgets item width */
19766 item_width = NK_MAX(1.0f,panel_space-1.0f) / (float)layout->row.columns;
19767 item_offset = (float)layout->row.index * item_width;
19768 item_spacing = (float)layout->row.index * spacing.x;
19769 } break;
19770 case NK_LAYOUT_DYNAMIC_ROW: {
19771 /* scaling single ratio widget width */
19772 item_width = layout->row.item_width * panel_space;
19773 item_offset = layout->row.item_offset;
19774 item_spacing = 0;
19775
19776 if (modify) {
19777 layout->row.item_offset += item_width + spacing.x;
19778 layout->row.filled += layout->row.item_width;
19779 layout->row.index = 0;
19780 }
19781 } break;
19782 case NK_LAYOUT_DYNAMIC_FREE: {
19783 /* panel width depended free widget placing */
19784 bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);
19785 bounds->x -= (float)*layout->offset_x;
19786 bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);
19787 bounds->y -= (float)*layout->offset_y;
19788 bounds->w = layout->bounds.w * layout->row.item.w;
19789 bounds->h = layout->row.height * layout->row.item.h;
19790 return;
19791 } break;
19792 case NK_LAYOUT_DYNAMIC: {
19793 /* scaling arrays of panel width ratios for every widget */
19794 float ratio;
19795 NK_ASSERT(layout->row.ratio);
19796 ratio = (layout->row.ratio[layout->row.index] < 0) ?
19797 layout->row.item_width : layout->row.ratio[layout->row.index];
19798
19799 item_spacing = (float)layout->row.index * spacing.x;
19800 item_width = (ratio * panel_space);
19801 item_offset = layout->row.item_offset;
19802
19803 if (modify) {
19804 layout->row.item_offset += item_width;
19805 layout->row.filled += ratio;
19806 }
19807 } break;
19808 case NK_LAYOUT_STATIC_FIXED: {
19809 /* non-scaling fixed widgets item width */
19810 item_width = layout->row.item_width;
19811 item_offset = (float)layout->row.index * item_width;
19812 item_spacing = (float)layout->row.index * spacing.x;
19813 } break;
19814 case NK_LAYOUT_STATIC_ROW: {
19815 /* scaling single ratio widget width */
19816 item_width = layout->row.item_width;
19817 item_offset = layout->row.item_offset;
19818 item_spacing = (float)layout->row.index * spacing.x;
19819 if (modify) layout->row.item_offset += item_width;
19820 } break;
19821 case NK_LAYOUT_STATIC_FREE: {
19822 /* free widget placing */
19823 bounds->x = layout->at_x + layout->row.item.x;
19824 bounds->w = layout->row.item.w;
19825 if (((bounds->x + bounds->w) > layout->max_x) && modify)
19826 layout->max_x = (bounds->x + bounds->w);
19827 bounds->x -= (float)*layout->offset_x;
19828 bounds->y = layout->at_y + layout->row.item.y;
19829 bounds->y -= (float)*layout->offset_y;
19830 bounds->h = layout->row.item.h;
19831 return;
19832 } break;
19833 case NK_LAYOUT_STATIC: {
19834 /* non-scaling array of panel pixel width for every widget */
19835 item_spacing = (float)layout->row.index * spacing.x;
19836 item_width = layout->row.ratio[layout->row.index];
19837 item_offset = layout->row.item_offset;
19838 if (modify) layout->row.item_offset += item_width;
19839 } break;
19840 case NK_LAYOUT_TEMPLATE: {
19841 /* stretchy row layout with combined dynamic/static widget width*/
19842 NK_ASSERT(layout->row.index < layout->row.columns);
19843 NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
19844 item_width = layout->row.templates[layout->row.index];
19845 item_offset = layout->row.item_offset;
19846 item_spacing = (float)layout->row.index * spacing.x;
19847 if (modify) layout->row.item_offset += item_width;
19848 } break;
19849 default: NK_ASSERT(0); break;
19850 };
19851
19852 /* set the bounds of the newly allocated widget */
19853 bounds->w = item_width;
19854 bounds->h = layout->row.height - spacing.y;
19855 bounds->y = layout->at_y - (float)*layout->offset_y;
19856 bounds->x = layout->at_x + item_offset + item_spacing + padding.x;
19857 if (((bounds->x + bounds->w) > layout->max_x) && modify)
19858 layout->max_x = bounds->x + bounds->w;
19859 bounds->x -= (float)*layout->offset_x;
19860 }
19861
19862 NK_INTERN void
19863 nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
19864 {
19865 struct nk_window *win;
19866 struct nk_panel *layout;
19867
19868 NK_ASSERT(ctx);
19869 NK_ASSERT(ctx->current);
19870 NK_ASSERT(ctx->current->layout);
19871 if (!ctx || !ctx->current || !ctx->current->layout)
19872 return;
19873
19874 /* check if the end of the row has been hit and begin new row if so */
19875 win = ctx->current;
19876 layout = win->layout;
19877 if (layout->row.index >= layout->row.columns)
19878 nk_panel_alloc_row(ctx, win);
19879
19880 /* calculate widget position and size */
19881 nk_layout_widget_space(bounds, ctx, win, nk_true);
19882 layout->row.index++;
19883 }
19884
19885 NK_INTERN void
19886 nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx)
19887 {
19888 float y;
19889 int index;
19890 struct nk_window *win;
19891 struct nk_panel *layout;
19892
19893 NK_ASSERT(ctx);
19894 NK_ASSERT(ctx->current);
19895 NK_ASSERT(ctx->current->layout);
19896 if (!ctx || !ctx->current || !ctx->current->layout)
19897 return;
19898
19899 win = ctx->current;
19900 layout = win->layout;
19901 y = layout->at_y;
19902 index = layout->row.index;
19903 if (layout->row.index >= layout->row.columns) {
19904 layout->at_y += layout->row.height;
19905 layout->row.index = 0;
19906 }
19907 nk_layout_widget_space(bounds, ctx, win, nk_false);
19908 layout->at_y = y;
19909 layout->row.index = index;
19910 }
19911
19912 NK_INTERN int
19913 nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,
19914 struct nk_image *img, const char *title, enum nk_collapse_states *state)
19915 {
19916 struct nk_window *win;
19917 struct nk_panel *layout;
19918 const struct nk_style *style;
19919 struct nk_command_buffer *out;
19920 const struct nk_input *in;
19921 const struct nk_style_button *button;
19922 enum nk_symbol_type symbol;
19923 float row_height;
19924
19925 struct nk_vec2 item_spacing;
19926 struct nk_rect header = {0,0,0,0};
19927 struct nk_rect sym = {0,0,0,0};
19928 struct nk_text text;
19929
19930 nk_flags ws = 0;
19931 enum nk_widget_layout_states widget_state;
19932
19933 NK_ASSERT(ctx);
19934 NK_ASSERT(ctx->current);
19935 NK_ASSERT(ctx->current->layout);
19936 if (!ctx || !ctx->current || !ctx->current->layout)
19937 return 0;
19938
19939 /* cache some data */
19940 win = ctx->current;
19941 layout = win->layout;
19942 out = &win->buffer;
19943 style = &ctx->style;
19944 item_spacing = style->window.spacing;
19945
19946 /* calculate header bounds and draw background */
19947 row_height = style->font->height + 2 * style->tab.padding.y;
19948 nk_layout_set_min_row_height(ctx, row_height);
19949 nk_layout_row_dynamic(ctx, row_height, 1);
19950 nk_layout_reset_min_row_height(ctx);
19951
19952 widget_state = nk_widget(&header, ctx);
19953 if (type == NK_TREE_TAB) {
19954 const struct nk_style_item *background = &style->tab.background;
19955 if (background->type == NK_STYLE_ITEM_IMAGE) {
19956 nk_draw_image(out, header, &background->data.image, nk_white);
19957 text.background = nk_rgba(0,0,0,0);
19958 } else {
19959 text.background = background->data.color;
19960 nk_fill_rect(out, header, 0, style->tab.border_color);
19961 nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
19962 style->tab.rounding, background->data.color);
19963 }
19964 } else text.background = style->window.background;
19965
19966 /* update node state */
19967 in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
19968 in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
19969 if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))
19970 *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;
19971
19972 /* select correct button style */
19973 if (*state == NK_MAXIMIZED) {
19974 symbol = style->tab.sym_maximize;
19975 if (type == NK_TREE_TAB)
19976 button = &style->tab.tab_maximize_button;
19977 else button = &style->tab.node_maximize_button;
19978 } else {
19979 symbol = style->tab.sym_minimize;
19980 if (type == NK_TREE_TAB)
19981 button = &style->tab.tab_minimize_button;
19982 else button = &style->tab.node_minimize_button;
19983 }
19984
19985 {/* draw triangle button */
19986 sym.w = sym.h = style->font->height;
19987 sym.y = header.y + style->tab.padding.y;
19988 sym.x = header.x + style->tab.padding.x;
19989 nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,
19990 button, 0, style->font);
19991
19992 if (img) {
19993 /* draw optional image icon */
19994 sym.x = sym.x + sym.w + 4 * item_spacing.x;
19995 nk_draw_image(&win->buffer, sym, img, nk_white);
19996 sym.w = style->font->height + style->tab.spacing.x;}
19997 }
19998
19999 {/* draw label */
20000 struct nk_rect label;
20001 header.w = NK_MAX(header.w, sym.w + item_spacing.x);
20002 label.x = sym.x + sym.w + item_spacing.x;
20003 label.y = sym.y;
20004 label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);
20005 label.h = style->font->height;
20006 text.text = style->tab.text;
20007 text.padding = nk_vec2(0,0);
20008 nk_widget_text(out, label, title, nk_strlen(title), &text,
20009 NK_TEXT_LEFT, style->font);}
20010
20011 /* increase x-axis cursor widget position pointer */
20012 if (*state == NK_MAXIMIZED) {
20013 layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
20014 layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
20015 layout->bounds.w -= (style->tab.indent + style->window.padding.x);
20016 layout->row.tree_depth++;
20017 return nk_true;
20018 } else return nk_false;
20019 }
20020
20021 NK_INTERN int
20022 nk_tree_base(struct nk_context *ctx, enum nk_tree_type type,
20023 struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
20024 const char *hash, int len, int line)
20025 {
20026 struct nk_window *win = ctx->current;
20027 int title_len = 0;
20028 nk_hash tree_hash = 0;
20029 nk_uint *state = 0;
20030
20031 /* retrieve tree state from internal widget state tables */
20032 if (!hash) {
20033 title_len = (int)nk_strlen(title);
20034 tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
20035 } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
20036 state = nk_find_value(win, tree_hash);
20037 if (!state) {
20038 state = nk_add_value(ctx, win, tree_hash, 0);
20039 *state = initial_state;
20040 }
20041 return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);
20042 }
20043
20044 NK_API int
20045 nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,
20046 const char *title, enum nk_collapse_states *state)
20047 {return nk_tree_state_base(ctx, type, 0, title, state);}
20048
20049 NK_API int
20050 nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,
20051 struct nk_image img, const char *title, enum nk_collapse_states *state)
20052 {return nk_tree_state_base(ctx, type, &img, title, state);}
20053
20054 NK_API void
20055 nk_tree_state_pop(struct nk_context *ctx)
20056 {
20057 struct nk_window *win = 0;
20058 struct nk_panel *layout = 0;
20059
20060 NK_ASSERT(ctx);
20061 NK_ASSERT(ctx->current);
20062 NK_ASSERT(ctx->current->layout);
20063 if (!ctx || !ctx->current || !ctx->current->layout)
20064 return;
20065
20066 win = ctx->current;
20067 layout = win->layout;
20068 layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x;
20069 layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;
20070 NK_ASSERT(layout->row.tree_depth);
20071 layout->row.tree_depth--;
20072 }
20073
20074 NK_API int
20075 nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
20076 const char *title, enum nk_collapse_states initial_state,
20077 const char *hash, int len, int line)
20078 {return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);}
20079
20080 NK_API int
20081 nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
20082 struct nk_image img, const char *title, enum nk_collapse_states initial_state,
20083 const char *hash, int len,int seed)
20084 {return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);}
20085
20086 NK_API void
20087 nk_tree_pop(struct nk_context *ctx)
20088 {nk_tree_state_pop(ctx);}
20089
20090 /*----------------------------------------------------------------
20091 *
20092 * WIDGETS
20093 *
20094 * --------------------------------------------------------------*/
20095 NK_API struct nk_rect
20096 nk_widget_bounds(struct nk_context *ctx)
20097 {
20098 struct nk_rect bounds;
20099 NK_ASSERT(ctx);
20100 NK_ASSERT(ctx->current);
20101 if (!ctx || !ctx->current)
20102 return nk_rect(0,0,0,0);
20103 nk_layout_peek(&bounds, ctx);
20104 return bounds;
20105 }
20106
20107 NK_API struct nk_vec2
20108 nk_widget_position(struct nk_context *ctx)
20109 {
20110 struct nk_rect bounds;
20111 NK_ASSERT(ctx);
20112 NK_ASSERT(ctx->current);
20113 if (!ctx || !ctx->current)
20114 return nk_vec2(0,0);
20115
20116 nk_layout_peek(&bounds, ctx);
20117 return nk_vec2(bounds.x, bounds.y);
20118 }
20119
20120 NK_API struct nk_vec2
20121 nk_widget_size(struct nk_context *ctx)
20122 {
20123 struct nk_rect bounds;
20124 NK_ASSERT(ctx);
20125 NK_ASSERT(ctx->current);
20126 if (!ctx || !ctx->current)
20127 return nk_vec2(0,0);
20128
20129 nk_layout_peek(&bounds, ctx);
20130 return nk_vec2(bounds.w, bounds.h);
20131 }
20132
20133 NK_API float
20134 nk_widget_width(struct nk_context *ctx)
20135 {
20136 struct nk_rect bounds;
20137 NK_ASSERT(ctx);
20138 NK_ASSERT(ctx->current);
20139 if (!ctx || !ctx->current)
20140 return 0;
20141
20142 nk_layout_peek(&bounds, ctx);
20143 return bounds.w;
20144 }
20145
20146 NK_API float
20147 nk_widget_height(struct nk_context *ctx)
20148 {
20149 struct nk_rect bounds;
20150 NK_ASSERT(ctx);
20151 NK_ASSERT(ctx->current);
20152 if (!ctx || !ctx->current)
20153 return 0;
20154
20155 nk_layout_peek(&bounds, ctx);
20156 return bounds.h;
20157 }
20158
20159 NK_API int
20160 nk_widget_is_hovered(struct nk_context *ctx)
20161 {
20162 struct nk_rect c, v;
20163 struct nk_rect bounds;
20164 NK_ASSERT(ctx);
20165 NK_ASSERT(ctx->current);
20166 if (!ctx || !ctx->current || ctx->active != ctx->current)
20167 return 0;
20168
20169 c = ctx->current->layout->clip;
20170 c.x = (float)((int)c.x);
20171 c.y = (float)((int)c.y);
20172 c.w = (float)((int)c.w);
20173 c.h = (float)((int)c.h);
20174
20175 nk_layout_peek(&bounds, ctx);
20176 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
20177 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
20178 return 0;
20179 return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
20180 }
20181
20182 NK_API int
20183 nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn)
20184 {
20185 struct nk_rect c, v;
20186 struct nk_rect bounds;
20187 NK_ASSERT(ctx);
20188 NK_ASSERT(ctx->current);
20189 if (!ctx || !ctx->current || ctx->active != ctx->current)
20190 return 0;
20191
20192 c = ctx->current->layout->clip;
20193 c.x = (float)((int)c.x);
20194 c.y = (float)((int)c.y);
20195 c.w = (float)((int)c.w);
20196 c.h = (float)((int)c.h);
20197
20198 nk_layout_peek(&bounds, ctx);
20199 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
20200 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
20201 return 0;
20202 return nk_input_mouse_clicked(&ctx->input, btn, bounds);
20203 }
20204
20205 NK_API int
20206 nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down)
20207 {
20208 struct nk_rect c, v;
20209 struct nk_rect bounds;
20210 NK_ASSERT(ctx);
20211 NK_ASSERT(ctx->current);
20212 if (!ctx || !ctx->current || ctx->active != ctx->current)
20213 return 0;
20214
20215 c = ctx->current->layout->clip;
20216 c.x = (float)((int)c.x);
20217 c.y = (float)((int)c.y);
20218 c.w = (float)((int)c.w);
20219 c.h = (float)((int)c.h);
20220
20221 nk_layout_peek(&bounds, ctx);
20222 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
20223 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
20224 return 0;
20225 return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);
20226 }
20227
20228 NK_API enum nk_widget_layout_states
20229 nk_widget(struct nk_rect *bounds, const struct nk_context *ctx)
20230 {
20231 struct nk_rect c, v;
20232 struct nk_window *win;
20233 struct nk_panel *layout;
20234 const struct nk_input *in;
20235
20236 NK_ASSERT(ctx);
20237 NK_ASSERT(ctx->current);
20238 NK_ASSERT(ctx->current->layout);
20239 if (!ctx || !ctx->current || !ctx->current->layout)
20240 return NK_WIDGET_INVALID;
20241
20242 /* allocate space and check if the widget needs to be updated and drawn */
20243 nk_panel_alloc_space(bounds, ctx);
20244 win = ctx->current;
20245 layout = win->layout;
20246 in = &ctx->input;
20247 c = layout->clip;
20248
20249 /* if one of these triggers you forgot to add an `if` condition around either
20250 a window, group, popup, combobox or contextual menu `begin` and `end` block.
20251 Example:
20252 if (nk_begin(...) {...} nk_end(...); or
20253 if (nk_group_begin(...) { nk_group_end(...);} */
20254 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
20255 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
20256 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
20257
20258 /* need to convert to int here to remove floating point errors */
20259 bounds->x = (float)((int)bounds->x);
20260 bounds->y = (float)((int)bounds->y);
20261 bounds->w = (float)((int)bounds->w);
20262 bounds->h = (float)((int)bounds->h);
20263
20264 c.x = (float)((int)c.x);
20265 c.y = (float)((int)c.y);
20266 c.w = (float)((int)c.w);
20267 c.h = (float)((int)c.h);
20268
20269 nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);
20270 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))
20271 return NK_WIDGET_INVALID;
20272 if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))
20273 return NK_WIDGET_ROM;
20274 return NK_WIDGET_VALID;
20275 }
20276
20277 NK_API enum nk_widget_layout_states
20278 nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx,
20279 struct nk_vec2 item_padding)
20280 {
20281 /* update the bounds to stand without padding */
20282 struct nk_window *win;
20283 struct nk_style *style;
20284 struct nk_panel *layout;
20285 enum nk_widget_layout_states state;
20286 struct nk_vec2 panel_padding;
20287
20288 NK_ASSERT(ctx);
20289 NK_ASSERT(ctx->current);
20290 NK_ASSERT(ctx->current->layout);
20291 if (!ctx || !ctx->current || !ctx->current->layout)
20292 return NK_WIDGET_INVALID;
20293
20294 win = ctx->current;
20295 style = &ctx->style;
20296 layout = win->layout;
20297 state = nk_widget(bounds, ctx);
20298
20299 panel_padding = nk_panel_get_padding(style, layout->type);
20300 if (layout->row.index == 1) {
20301 bounds->w += panel_padding.x;
20302 bounds->x -= panel_padding.x;
20303 } else bounds->x -= item_padding.x;
20304
20305 if (layout->row.index == layout->row.columns)
20306 bounds->w += panel_padding.x;
20307 else bounds->w += item_padding.x;
20308 return state;
20309 }
20310
20311 /*----------------------------------------------------------------
20312 *
20313 * MISC
20314 *
20315 * --------------------------------------------------------------*/
20316 NK_API void
20317 nk_spacing(struct nk_context *ctx, int cols)
20318 {
20319 struct nk_window *win;
20320 struct nk_panel *layout;
20321 struct nk_rect none;
20322 int i, index, rows;
20323
20324 NK_ASSERT(ctx);
20325 NK_ASSERT(ctx->current);
20326 NK_ASSERT(ctx->current->layout);
20327 if (!ctx || !ctx->current || !ctx->current->layout)
20328 return;
20329
20330 /* spacing over row boundaries */
20331 win = ctx->current;
20332 layout = win->layout;
20333 index = (layout->row.index + cols) % layout->row.columns;
20334 rows = (layout->row.index + cols) / layout->row.columns;
20335 if (rows) {
20336 for (i = 0; i < rows; ++i)
20337 nk_panel_alloc_row(ctx, win);
20338 cols = index;
20339 }
20340 /* non table layout need to allocate space */
20341 if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&
20342 layout->row.type != NK_LAYOUT_STATIC_FIXED) {
20343 for (i = 0; i < cols; ++i)
20344 nk_panel_alloc_space(&none, ctx);
20345 }
20346 layout->row.index = index;
20347 }
20348
20349 /*----------------------------------------------------------------
20350 *
20351 * TEXT
20352 *
20353 * --------------------------------------------------------------*/
20354 NK_API void
20355 nk_text_colored(struct nk_context *ctx, const char *str, int len,
20356 nk_flags alignment, struct nk_color color)
20357 {
20358 struct nk_window *win;
20359 const struct nk_style *style;
20360
20361 struct nk_vec2 item_padding;
20362 struct nk_rect bounds;
20363 struct nk_text text;
20364
20365 NK_ASSERT(ctx);
20366 NK_ASSERT(ctx->current);
20367 NK_ASSERT(ctx->current->layout);
20368 if (!ctx || !ctx->current || !ctx->current->layout) return;
20369
20370 win = ctx->current;
20371 style = &ctx->style;
20372 nk_panel_alloc_space(&bounds, ctx);
20373 item_padding = style->text.padding;
20374
20375 text.padding.x = item_padding.x;
20376 text.padding.y = item_padding.y;
20377 text.background = style->window.background;
20378 text.text = color;
20379 nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);
20380 }
20381
20382 NK_API void
20383 nk_text_wrap_colored(struct nk_context *ctx, const char *str,
20384 int len, struct nk_color color)
20385 {
20386 struct nk_window *win;
20387 const struct nk_style *style;
20388
20389 struct nk_vec2 item_padding;
20390 struct nk_rect bounds;
20391 struct nk_text text;
20392
20393 NK_ASSERT(ctx);
20394 NK_ASSERT(ctx->current);
20395 NK_ASSERT(ctx->current->layout);
20396 if (!ctx || !ctx->current || !ctx->current->layout) return;
20397
20398 win = ctx->current;
20399 style = &ctx->style;
20400 nk_panel_alloc_space(&bounds, ctx);
20401 item_padding = style->text.padding;
20402
20403 text.padding.x = item_padding.x;
20404 text.padding.y = item_padding.y;
20405 text.background = style->window.background;
20406 text.text = color;
20407 nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);
20408 }
20409
20410 #ifdef NK_INCLUDE_STANDARD_VARARGS
20411 NK_API void
20412 nk_labelf_colored(struct nk_context *ctx, nk_flags flags,
20413 struct nk_color color, const char *fmt, ...)
20414 {
20415 char buf[256];
20416 va_list args;
20417 va_start(args, fmt);
20418 nk_strfmt(buf, NK_LEN(buf), fmt, args);
20419 nk_label_colored(ctx, buf, flags, color);
20420 va_end(args);
20421 }
20422
20423 NK_API void
20424 nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,
20425 const char *fmt, ...)
20426 {
20427 char buf[256];
20428 va_list args;
20429 va_start(args, fmt);
20430 nk_strfmt(buf, NK_LEN(buf), fmt, args);
20431 nk_label_colored_wrap(ctx, buf, color);
20432 va_end(args);
20433 }
20434
20435 NK_API void
20436 nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)
20437 {
20438 char buf[256];
20439 va_list args;
20440 va_start(args, fmt);
20441 nk_strfmt(buf, NK_LEN(buf), fmt, args);
20442 nk_label(ctx, buf, flags);
20443 va_end(args);
20444 }
20445
20446 NK_API void
20447 nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)
20448 {
20449 char buf[256];
20450 va_list args;
20451 va_start(args, fmt);
20452 nk_strfmt(buf, NK_LEN(buf), fmt, args);
20453 nk_label_wrap(ctx, buf);
20454 va_end(args);
20455 }
20456
20457 NK_API void
20458 nk_value_bool(struct nk_context *ctx, const char *prefix, int value)
20459 {nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));}
20460
20461 NK_API void
20462 nk_value_int(struct nk_context *ctx, const char *prefix, int value)
20463 {nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);}
20464
20465 NK_API void
20466 nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)
20467 {nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);}
20468
20469 NK_API void
20470 nk_value_float(struct nk_context *ctx, const char *prefix, float value)
20471 {
20472 double double_value = (double)value;
20473 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value);
20474 }
20475
20476 NK_API void
20477 nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)
20478 {nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);}
20479
20480 NK_API void
20481 nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)
20482 {
20483 double c[4]; nk_color_dv(c, color);
20484 nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)",
20485 p, c[0], c[1], c[2], c[3]);
20486 }
20487
20488 NK_API void
20489 nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)
20490 {
20491 char hex[16];
20492 nk_color_hex_rgba(hex, color);
20493 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex);
20494 }
20495 #endif
20496
20497 NK_API void
20498 nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)
20499 {
20500 NK_ASSERT(ctx);
20501 if (!ctx) return;
20502 nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);
20503 }
20504
20505 NK_API void
20506 nk_text_wrap(struct nk_context *ctx, const char *str, int len)
20507 {
20508 NK_ASSERT(ctx);
20509 if (!ctx) return;
20510 nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);
20511 }
20512
20513 NK_API void
20514 nk_label(struct nk_context *ctx, const char *str, nk_flags alignment)
20515 {nk_text(ctx, str, nk_strlen(str), alignment);}
20516
20517 NK_API void
20518 nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,
20519 struct nk_color color)
20520 {nk_text_colored(ctx, str, nk_strlen(str), align, color);}
20521
20522 NK_API void
20523 nk_label_wrap(struct nk_context *ctx, const char *str)
20524 {nk_text_wrap(ctx, str, nk_strlen(str));}
20525
20526 NK_API void
20527 nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)
20528 {nk_text_wrap_colored(ctx, str, nk_strlen(str), color);}
20529
20530 NK_API void
20531 nk_image(struct nk_context *ctx, struct nk_image img)
20532 {
20533 struct nk_window *win;
20534 struct nk_rect bounds;
20535
20536 NK_ASSERT(ctx);
20537 NK_ASSERT(ctx->current);
20538 NK_ASSERT(ctx->current->layout);
20539 if (!ctx || !ctx->current || !ctx->current->layout) return;
20540
20541 win = ctx->current;
20542 if (!nk_widget(&bounds, ctx)) return;
20543 nk_draw_image(&win->buffer, bounds, &img, nk_white);
20544 }
20545
20546 /*----------------------------------------------------------------
20547 *
20548 * BUTTON
20549 *
20550 * --------------------------------------------------------------*/
20551 NK_API void
20552 nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
20553 {
20554 NK_ASSERT(ctx);
20555 if (!ctx) return;
20556 ctx->button_behavior = behavior;
20557 }
20558
20559 NK_API int
20560 nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
20561 {
20562 struct nk_config_stack_button_behavior *button_stack;
20563 struct nk_config_stack_button_behavior_element *element;
20564
20565 NK_ASSERT(ctx);
20566 if (!ctx) return 0;
20567
20568 button_stack = &ctx->stacks.button_behaviors;
20569 NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));
20570 if (button_stack->head >= (int)NK_LEN(button_stack->elements))
20571 return 0;
20572
20573 element = &button_stack->elements[button_stack->head++];
20574 element->address = &ctx->button_behavior;
20575 element->old_value = ctx->button_behavior;
20576 ctx->button_behavior = behavior;
20577 return 1;
20578 }
20579
20580 NK_API int
20581 nk_button_pop_behavior(struct nk_context *ctx)
20582 {
20583 struct nk_config_stack_button_behavior *button_stack;
20584 struct nk_config_stack_button_behavior_element *element;
20585
20586 NK_ASSERT(ctx);
20587 if (!ctx) return 0;
20588
20589 button_stack = &ctx->stacks.button_behaviors;
20590 NK_ASSERT(button_stack->head > 0);
20591 if (button_stack->head < 1)
20592 return 0;
20593
20594 element = &button_stack->elements[--button_stack->head];
20595 *element->address = element->old_value;
20596 return 1;
20597 }
20598
20599 NK_API int
20600 nk_button_text_styled(struct nk_context *ctx,
20601 const struct nk_style_button *style, const char *title, int len)
20602 {
20603 struct nk_window *win;
20604 struct nk_panel *layout;
20605 const struct nk_input *in;
20606
20607 struct nk_rect bounds;
20608 enum nk_widget_layout_states state;
20609
20610 NK_ASSERT(ctx);
20611 NK_ASSERT(style);
20612 NK_ASSERT(ctx->current);
20613 NK_ASSERT(ctx->current->layout);
20614 if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;
20615
20616 win = ctx->current;
20617 layout = win->layout;
20618 state = nk_widget(&bounds, ctx);
20619
20620 if (!state) return 0;
20621 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20622 return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
20623 title, len, style->text_alignment, ctx->button_behavior,
20624 style, in, ctx->style.font);
20625 }
20626
20627 NK_API int
20628 nk_button_text(struct nk_context *ctx, const char *title, int len)
20629 {
20630 NK_ASSERT(ctx);
20631 if (!ctx) return 0;
20632 return nk_button_text_styled(ctx, &ctx->style.button, title, len);
20633 }
20634
20635 NK_API int nk_button_label_styled(struct nk_context *ctx,
20636 const struct nk_style_button *style, const char *title)
20637 {return nk_button_text_styled(ctx, style, title, nk_strlen(title));}
20638
20639 NK_API int nk_button_label(struct nk_context *ctx, const char *title)
20640 {return nk_button_text(ctx, title, nk_strlen(title));}
20641
20642 NK_API int
20643 nk_button_color(struct nk_context *ctx, struct nk_color color)
20644 {
20645 struct nk_window *win;
20646 struct nk_panel *layout;
20647 const struct nk_input *in;
20648 struct nk_style_button button;
20649
20650 int ret = 0;
20651 struct nk_rect bounds;
20652 struct nk_rect content;
20653 enum nk_widget_layout_states state;
20654
20655 NK_ASSERT(ctx);
20656 NK_ASSERT(ctx->current);
20657 NK_ASSERT(ctx->current->layout);
20658 if (!ctx || !ctx->current || !ctx->current->layout)
20659 return 0;
20660
20661 win = ctx->current;
20662 layout = win->layout;
20663
20664 state = nk_widget(&bounds, ctx);
20665 if (!state) return 0;
20666 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20667
20668 button = ctx->style.button;
20669 button.normal = nk_style_item_color(color);
20670 button.hover = nk_style_item_color(color);
20671 button.active = nk_style_item_color(color);
20672 ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,
20673 &button, in, ctx->button_behavior, &content);
20674 nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);
20675 return ret;
20676 }
20677
20678 NK_API int
20679 nk_button_symbol_styled(struct nk_context *ctx,
20680 const struct nk_style_button *style, enum nk_symbol_type symbol)
20681 {
20682 struct nk_window *win;
20683 struct nk_panel *layout;
20684 const struct nk_input *in;
20685
20686 struct nk_rect bounds;
20687 enum nk_widget_layout_states state;
20688
20689 NK_ASSERT(ctx);
20690 NK_ASSERT(ctx->current);
20691 NK_ASSERT(ctx->current->layout);
20692 if (!ctx || !ctx->current || !ctx->current->layout)
20693 return 0;
20694
20695 win = ctx->current;
20696 layout = win->layout;
20697 state = nk_widget(&bounds, ctx);
20698 if (!state) return 0;
20699 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20700 return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,
20701 symbol, ctx->button_behavior, style, in, ctx->style.font);
20702 }
20703
20704 NK_API int
20705 nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)
20706 {
20707 NK_ASSERT(ctx);
20708 if (!ctx) return 0;
20709 return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);
20710 }
20711
20712 NK_API int
20713 nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,
20714 struct nk_image img)
20715 {
20716 struct nk_window *win;
20717 struct nk_panel *layout;
20718 const struct nk_input *in;
20719
20720 struct nk_rect bounds;
20721 enum nk_widget_layout_states state;
20722
20723 NK_ASSERT(ctx);
20724 NK_ASSERT(ctx->current);
20725 NK_ASSERT(ctx->current->layout);
20726 if (!ctx || !ctx->current || !ctx->current->layout)
20727 return 0;
20728
20729 win = ctx->current;
20730 layout = win->layout;
20731
20732 state = nk_widget(&bounds, ctx);
20733 if (!state) return 0;
20734 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20735 return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,
20736 img, ctx->button_behavior, style, in);
20737 }
20738
20739 NK_API int
20740 nk_button_image(struct nk_context *ctx, struct nk_image img)
20741 {
20742 NK_ASSERT(ctx);
20743 if (!ctx) return 0;
20744 return nk_button_image_styled(ctx, &ctx->style.button, img);
20745 }
20746
20747 NK_API int
20748 nk_button_symbol_text_styled(struct nk_context *ctx,
20749 const struct nk_style_button *style, enum nk_symbol_type symbol,
20750 const char *text, int len, nk_flags align)
20751 {
20752 struct nk_window *win;
20753 struct nk_panel *layout;
20754 const struct nk_input *in;
20755
20756 struct nk_rect bounds;
20757 enum nk_widget_layout_states state;
20758
20759 NK_ASSERT(ctx);
20760 NK_ASSERT(ctx->current);
20761 NK_ASSERT(ctx->current->layout);
20762 if (!ctx || !ctx->current || !ctx->current->layout)
20763 return 0;
20764
20765 win = ctx->current;
20766 layout = win->layout;
20767
20768 state = nk_widget(&bounds, ctx);
20769 if (!state) return 0;
20770 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20771 return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
20772 symbol, text, len, align, ctx->button_behavior,
20773 style, ctx->style.font, in);
20774 }
20775
20776 NK_API int
20777 nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
20778 const char* text, int len, nk_flags align)
20779 {
20780 NK_ASSERT(ctx);
20781 if (!ctx) return 0;
20782 return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);
20783 }
20784
20785 NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
20786 const char *label, nk_flags align)
20787 {return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);}
20788
20789 NK_API int nk_button_symbol_label_styled(struct nk_context *ctx,
20790 const struct nk_style_button *style, enum nk_symbol_type symbol,
20791 const char *title, nk_flags align)
20792 {return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);}
20793
20794 NK_API int
20795 nk_button_image_text_styled(struct nk_context *ctx,
20796 const struct nk_style_button *style, struct nk_image img, const char *text,
20797 int len, nk_flags align)
20798 {
20799 struct nk_window *win;
20800 struct nk_panel *layout;
20801 const struct nk_input *in;
20802
20803 struct nk_rect bounds;
20804 enum nk_widget_layout_states state;
20805
20806 NK_ASSERT(ctx);
20807 NK_ASSERT(ctx->current);
20808 NK_ASSERT(ctx->current->layout);
20809 if (!ctx || !ctx->current || !ctx->current->layout)
20810 return 0;
20811
20812 win = ctx->current;
20813 layout = win->layout;
20814
20815 state = nk_widget(&bounds, ctx);
20816 if (!state) return 0;
20817 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20818 return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
20819 bounds, img, text, len, align, ctx->button_behavior,
20820 style, ctx->style.font, in);
20821 }
20822
20823 NK_API int
20824 nk_button_image_text(struct nk_context *ctx, struct nk_image img,
20825 const char *text, int len, nk_flags align)
20826 {return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);}
20827
20828
20829 NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img,
20830 const char *label, nk_flags align)
20831 {return nk_button_image_text(ctx, img, label, nk_strlen(label), align);}
20832
20833 NK_API int nk_button_image_label_styled(struct nk_context *ctx,
20834 const struct nk_style_button *style, struct nk_image img,
20835 const char *label, nk_flags text_alignment)
20836 {return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);}
20837
20838 /*----------------------------------------------------------------
20839 *
20840 * SELECTABLE
20841 *
20842 * --------------------------------------------------------------*/
20843 NK_API int
20844 nk_selectable_text(struct nk_context *ctx, const char *str, int len,
20845 nk_flags align, int *value)
20846 {
20847 struct nk_window *win;
20848 struct nk_panel *layout;
20849 const struct nk_input *in;
20850 const struct nk_style *style;
20851
20852 enum nk_widget_layout_states state;
20853 struct nk_rect bounds;
20854
20855 NK_ASSERT(ctx);
20856 NK_ASSERT(value);
20857 NK_ASSERT(ctx->current);
20858 NK_ASSERT(ctx->current->layout);
20859 if (!ctx || !ctx->current || !ctx->current->layout || !value)
20860 return 0;
20861
20862 win = ctx->current;
20863 layout = win->layout;
20864 style = &ctx->style;
20865
20866 state = nk_widget(&bounds, ctx);
20867 if (!state) return 0;
20868 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20869 return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,
20870 str, len, align, value, &style->selectable, in, style->font);
20871 }
20872
20873 NK_API int
20874 nk_selectable_image_text(struct nk_context *ctx, struct nk_image img,
20875 const char *str, int len, nk_flags align, int *value)
20876 {
20877 struct nk_window *win;
20878 struct nk_panel *layout;
20879 const struct nk_input *in;
20880 const struct nk_style *style;
20881
20882 enum nk_widget_layout_states state;
20883 struct nk_rect bounds;
20884
20885 NK_ASSERT(ctx);
20886 NK_ASSERT(value);
20887 NK_ASSERT(ctx->current);
20888 NK_ASSERT(ctx->current->layout);
20889 if (!ctx || !ctx->current || !ctx->current->layout || !value)
20890 return 0;
20891
20892 win = ctx->current;
20893 layout = win->layout;
20894 style = &ctx->style;
20895
20896 state = nk_widget(&bounds, ctx);
20897 if (!state) return 0;
20898 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20899 return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,
20900 str, len, align, value, &img, &style->selectable, in, style->font);
20901 }
20902
20903 NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len,
20904 nk_flags align, int value)
20905 {nk_selectable_text(ctx, str, len, align, &value);return value;}
20906
20907 NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value)
20908 {return nk_selectable_text(ctx, str, nk_strlen(str), align, value);}
20909
20910 NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,
20911 const char *str, nk_flags align, int *value)
20912 {return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);}
20913
20914 NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value)
20915 {nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;}
20916
20917 NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img,
20918 const char *str, nk_flags align, int value)
20919 {nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;}
20920
20921 NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img,
20922 const char *str, int len, nk_flags align, int value)
20923 {nk_selectable_image_text(ctx, img, str, len, align, &value);return value;}
20924
20925 /*----------------------------------------------------------------
20926 *
20927 * CHECKBOX
20928 *
20929 * --------------------------------------------------------------*/
20930 NK_API int
20931 nk_check_text(struct nk_context *ctx, const char *text, int len, int active)
20932 {
20933 struct nk_window *win;
20934 struct nk_panel *layout;
20935 const struct nk_input *in;
20936 const struct nk_style *style;
20937
20938 struct nk_rect bounds;
20939 enum nk_widget_layout_states state;
20940
20941 NK_ASSERT(ctx);
20942 NK_ASSERT(ctx->current);
20943 NK_ASSERT(ctx->current->layout);
20944 if (!ctx || !ctx->current || !ctx->current->layout)
20945 return active;
20946
20947 win = ctx->current;
20948 style = &ctx->style;
20949 layout = win->layout;
20950
20951 state = nk_widget(&bounds, ctx);
20952 if (!state) return active;
20953 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
20954 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
20955 text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font);
20956 return active;
20957 }
20958
20959 NK_API unsigned int
20960 nk_check_flags_text(struct nk_context *ctx, const char *text, int len,
20961 unsigned int flags, unsigned int value)
20962 {
20963 int old_active;
20964 NK_ASSERT(ctx);
20965 NK_ASSERT(text);
20966 if (!ctx || !text) return flags;
20967 old_active = (int)((flags & value) & value);
20968 if (nk_check_text(ctx, text, len, old_active))
20969 flags |= value;
20970 else flags &= ~value;
20971 return flags;
20972 }
20973
20974 NK_API int
20975 nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active)
20976 {
20977 int old_val;
20978 NK_ASSERT(ctx);
20979 NK_ASSERT(text);
20980 NK_ASSERT(active);
20981 if (!ctx || !text || !active) return 0;
20982 old_val = *active;
20983 *active = nk_check_text(ctx, text, len, *active);
20984 return old_val != *active;
20985 }
20986
20987 NK_API int
20988 nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
20989 unsigned int *flags, unsigned int value)
20990 {
20991 int active;
20992 NK_ASSERT(ctx);
20993 NK_ASSERT(text);
20994 NK_ASSERT(flags);
20995 if (!ctx || !text || !flags) return 0;
20996
20997 active = (int)((*flags & value) & value);
20998 if (nk_checkbox_text(ctx, text, len, &active)) {
20999 if (active) *flags |= value;
21000 else *flags &= ~value;
21001 return 1;
21002 }
21003 return 0;
21004 }
21005
21006 NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active)
21007 {return nk_check_text(ctx, label, nk_strlen(label), active);}
21008
21009 NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,
21010 unsigned int flags, unsigned int value)
21011 {return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);}
21012
21013 NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active)
21014 {return nk_checkbox_text(ctx, label, nk_strlen(label), active);}
21015
21016 NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label,
21017 unsigned int *flags, unsigned int value)
21018 {return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);}
21019
21020 /*----------------------------------------------------------------
21021 *
21022 * OPTION
21023 *
21024 * --------------------------------------------------------------*/
21025 NK_API int
21026 nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active)
21027 {
21028 struct nk_window *win;
21029 struct nk_panel *layout;
21030 const struct nk_input *in;
21031 const struct nk_style *style;
21032
21033 struct nk_rect bounds;
21034 enum nk_widget_layout_states state;
21035
21036 NK_ASSERT(ctx);
21037 NK_ASSERT(ctx->current);
21038 NK_ASSERT(ctx->current->layout);
21039 if (!ctx || !ctx->current || !ctx->current->layout)
21040 return is_active;
21041
21042 win = ctx->current;
21043 style = &ctx->style;
21044 layout = win->layout;
21045
21046 state = nk_widget(&bounds, ctx);
21047 if (!state) return state;
21048 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21049 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
21050 text, len, NK_TOGGLE_OPTION, &style->option, in, style->font);
21051 return is_active;
21052 }
21053
21054 NK_API int
21055 nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active)
21056 {
21057 int old_value;
21058 NK_ASSERT(ctx);
21059 NK_ASSERT(text);
21060 NK_ASSERT(active);
21061 if (!ctx || !text || !active) return 0;
21062 old_value = *active;
21063 *active = nk_option_text(ctx, text, len, old_value);
21064 return old_value != *active;
21065 }
21066
21067 NK_API int
21068 nk_option_label(struct nk_context *ctx, const char *label, int active)
21069 {return nk_option_text(ctx, label, nk_strlen(label), active);}
21070
21071 NK_API int
21072 nk_radio_label(struct nk_context *ctx, const char *label, int *active)
21073 {return nk_radio_text(ctx, label, nk_strlen(label), active);}
21074
21075 /*----------------------------------------------------------------
21076 *
21077 * SLIDER
21078 *
21079 * --------------------------------------------------------------*/
21080 NK_API int
21081 nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,
21082 float value_step)
21083 {
21084 struct nk_window *win;
21085 struct nk_panel *layout;
21086 struct nk_input *in;
21087 const struct nk_style *style;
21088
21089 int ret = 0;
21090 float old_value;
21091 struct nk_rect bounds;
21092 enum nk_widget_layout_states state;
21093
21094 NK_ASSERT(ctx);
21095 NK_ASSERT(ctx->current);
21096 NK_ASSERT(ctx->current->layout);
21097 NK_ASSERT(value);
21098 if (!ctx || !ctx->current || !ctx->current->layout || !value)
21099 return ret;
21100
21101 win = ctx->current;
21102 style = &ctx->style;
21103 layout = win->layout;
21104
21105 state = nk_widget(&bounds, ctx);
21106 if (!state) return ret;
21107 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21108
21109 old_value = *value;
21110 *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,
21111 old_value, max_value, value_step, &style->slider, in, style->font);
21112 return (old_value > *value || old_value < *value);
21113 }
21114
21115 NK_API float
21116 nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)
21117 {
21118 nk_slider_float(ctx, min, &val, max, step); return val;
21119 }
21120
21121 NK_API int
21122 nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)
21123 {
21124 float value = (float)val;
21125 nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
21126 return (int)value;
21127 }
21128
21129 NK_API int
21130 nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)
21131 {
21132 int ret;
21133 float value = (float)*val;
21134 ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
21135 *val = (int)value;
21136 return ret;
21137 }
21138
21139 /*----------------------------------------------------------------
21140 *
21141 * PROGRESSBAR
21142 *
21143 * --------------------------------------------------------------*/
21144 NK_API int
21145 nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable)
21146 {
21147 struct nk_window *win;
21148 struct nk_panel *layout;
21149 const struct nk_style *style;
21150 const struct nk_input *in;
21151
21152 struct nk_rect bounds;
21153 enum nk_widget_layout_states state;
21154 nk_size old_value;
21155
21156 NK_ASSERT(ctx);
21157 NK_ASSERT(cur);
21158 NK_ASSERT(ctx->current);
21159 NK_ASSERT(ctx->current->layout);
21160 if (!ctx || !ctx->current || !ctx->current->layout || !cur)
21161 return 0;
21162
21163 win = ctx->current;
21164 style = &ctx->style;
21165 layout = win->layout;
21166 state = nk_widget(&bounds, ctx);
21167 if (!state) return 0;
21168
21169 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21170 old_value = *cur;
21171 *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,
21172 *cur, max, is_modifyable, &style->progress, in);
21173 return (*cur != old_value);
21174 }
21175
21176 NK_API nk_size nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable)
21177 {nk_progress(ctx, &cur, max, modifyable);return cur;}
21178
21179 /*----------------------------------------------------------------
21180 *
21181 * EDIT
21182 *
21183 * --------------------------------------------------------------*/
21184 NK_API void
21185 nk_edit_focus(struct nk_context *ctx, nk_flags flags)
21186 {
21187 nk_hash hash;
21188 struct nk_window *win;
21189
21190 NK_ASSERT(ctx);
21191 NK_ASSERT(ctx->current);
21192 if (!ctx || !ctx->current) return;
21193
21194 win = ctx->current;
21195 hash = win->edit.seq;
21196 win->edit.active = nk_true;
21197 win->edit.name = hash;
21198 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
21199 win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;
21200 }
21201
21202 NK_API void
21203 nk_edit_unfocus(struct nk_context *ctx)
21204 {
21205 struct nk_window *win;
21206 NK_ASSERT(ctx);
21207 NK_ASSERT(ctx->current);
21208 if (!ctx || !ctx->current) return;
21209
21210 win = ctx->current;
21211 win->edit.active = nk_false;
21212 win->edit.name = 0;
21213 }
21214
21215 NK_API nk_flags
21216 nk_edit_string(struct nk_context *ctx, nk_flags flags,
21217 char *memory, int *len, int max, nk_plugin_filter filter)
21218 {
21219 nk_hash hash;
21220 nk_flags state;
21221 struct nk_text_edit *edit;
21222 struct nk_window *win;
21223
21224 NK_ASSERT(ctx);
21225 NK_ASSERT(memory);
21226 NK_ASSERT(len);
21227 if (!ctx || !memory || !len)
21228 return 0;
21229
21230 filter = (!filter) ? nk_filter_default: filter;
21231 win = ctx->current;
21232 hash = win->edit.seq;
21233 edit = &ctx->text_edit;
21234 nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?
21235 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);
21236
21237 if (win->edit.active && hash == win->edit.name) {
21238 if (flags & NK_EDIT_NO_CURSOR)
21239 edit->cursor = nk_utf_len(memory, *len);
21240 else edit->cursor = win->edit.cursor;
21241 if (!(flags & NK_EDIT_SELECTABLE)) {
21242 edit->select_start = win->edit.cursor;
21243 edit->select_end = win->edit.cursor;
21244 } else {
21245 edit->select_start = win->edit.sel_start;
21246 edit->select_end = win->edit.sel_end;
21247 }
21248 edit->mode = win->edit.mode;
21249 edit->scrollbar.x = (float)win->edit.scrollbar.x;
21250 edit->scrollbar.y = (float)win->edit.scrollbar.y;
21251 edit->active = nk_true;
21252 } else edit->active = nk_false;
21253
21254 max = NK_MAX(1, max);
21255 *len = NK_MIN(*len, max-1);
21256 nk_str_init_fixed(&edit->string, memory, (nk_size)max);
21257 edit->string.buffer.allocated = (nk_size)*len;
21258 edit->string.len = nk_utf_len(memory, *len);
21259 state = nk_edit_buffer(ctx, flags, edit, filter);
21260 *len = (int)edit->string.buffer.allocated;
21261
21262 if (edit->active) {
21263 win->edit.cursor = edit->cursor;
21264 win->edit.sel_start = edit->select_start;
21265 win->edit.sel_end = edit->select_end;
21266 win->edit.mode = edit->mode;
21267 win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;
21268 win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;
21269 }
21270 return state;
21271 }
21272
21273 NK_API nk_flags
21274 nk_edit_buffer(struct nk_context *ctx, nk_flags flags,
21275 struct nk_text_edit *edit, nk_plugin_filter filter)
21276 {
21277 struct nk_window *win;
21278 struct nk_style *style;
21279 struct nk_input *in;
21280
21281 enum nk_widget_layout_states state;
21282 struct nk_rect bounds;
21283
21284 nk_flags ret_flags = 0;
21285 unsigned char prev_state;
21286 nk_hash hash;
21287
21288 /* make sure correct values */
21289 NK_ASSERT(ctx);
21290 NK_ASSERT(edit);
21291 NK_ASSERT(ctx->current);
21292 NK_ASSERT(ctx->current->layout);
21293 if (!ctx || !ctx->current || !ctx->current->layout)
21294 return 0;
21295
21296 win = ctx->current;
21297 style = &ctx->style;
21298 state = nk_widget(&bounds, ctx);
21299 if (!state) return state;
21300 in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21301
21302 /* check if edit is currently hot item */
21303 hash = win->edit.seq++;
21304 if (win->edit.active && hash == win->edit.name) {
21305 if (flags & NK_EDIT_NO_CURSOR)
21306 edit->cursor = edit->string.len;
21307 if (!(flags & NK_EDIT_SELECTABLE)) {
21308 edit->select_start = edit->cursor;
21309 edit->select_end = edit->cursor;
21310 }
21311 if (flags & NK_EDIT_CLIPBOARD)
21312 edit->clip = ctx->clip;
21313 edit->active = win->edit.active;
21314 } else edit->active = nk_false;
21315 edit->mode = win->edit.mode;
21316
21317 filter = (!filter) ? nk_filter_default: filter;
21318 prev_state = (unsigned char)edit->active;
21319 in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
21320 ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,
21321 filter, edit, &style->edit, in, style->font);
21322
21323 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
21324 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
21325 if (edit->active && prev_state != edit->active) {
21326 /* current edit is now hot */
21327 win->edit.active = nk_true;
21328 win->edit.name = hash;
21329 } else if (prev_state && !edit->active) {
21330 /* current edit is now cold */
21331 win->edit.active = nk_false;
21332 }
21333 return ret_flags;
21334 }
21335
21336 NK_API nk_flags
21337 nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,
21338 char *buffer, int max, nk_plugin_filter filter)
21339 {
21340 nk_flags result;
21341 int len = nk_strlen(buffer);
21342 result = nk_edit_string(ctx, flags, buffer, &len, max, filter);
21343 buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0';
21344 return result;
21345 }
21346
21347 /*----------------------------------------------------------------
21348 *
21349 * PROPERTY
21350 *
21351 * --------------------------------------------------------------*/
21352 NK_INTERN struct nk_property_variant
21353 nk_property_variant_int(int value, int min_value, int max_value, int step)
21354 {
21355 struct nk_property_variant result;
21356 result.kind = NK_PROPERTY_INT;
21357 result.value.i = value;
21358 result.min_value.i = min_value;
21359 result.max_value.i = max_value;
21360 result.step.i = step;
21361 return result;
21362 }
21363
21364 NK_INTERN struct nk_property_variant
21365 nk_property_variant_float(float value, float min_value, float max_value, float step)
21366 {
21367 struct nk_property_variant result;
21368 result.kind = NK_PROPERTY_FLOAT;
21369 result.value.f = value;
21370 result.min_value.f = min_value;
21371 result.max_value.f = max_value;
21372 result.step.f = step;
21373 return result;
21374 }
21375
21376 NK_INTERN struct nk_property_variant
21377 nk_property_variant_double(double value, double min_value, double max_value,
21378 double step)
21379 {
21380 struct nk_property_variant result;
21381 result.kind = NK_PROPERTY_DOUBLE;
21382 result.value.d = value;
21383 result.min_value.d = min_value;
21384 result.max_value.d = max_value;
21385 result.step.d = step;
21386 return result;
21387 }
21388
21389 NK_INTERN void
21390 nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,
21391 float inc_per_pixel, const enum nk_property_filter filter)
21392 {
21393 struct nk_window *win;
21394 struct nk_panel *layout;
21395 struct nk_input *in;
21396 const struct nk_style *style;
21397
21398 struct nk_rect bounds;
21399 enum nk_widget_layout_states s;
21400
21401 int *state = 0;
21402 nk_hash hash = 0;
21403 char *buffer = 0;
21404 int *len = 0;
21405 int *cursor = 0;
21406 int *select_begin = 0;
21407 int *select_end = 0;
21408 int old_state;
21409
21410 char dummy_buffer[NK_MAX_NUMBER_BUFFER];
21411 int dummy_state = NK_PROPERTY_DEFAULT;
21412 int dummy_length = 0;
21413 int dummy_cursor = 0;
21414 int dummy_select_begin = 0;
21415 int dummy_select_end = 0;
21416
21417 NK_ASSERT(ctx);
21418 NK_ASSERT(ctx->current);
21419 NK_ASSERT(ctx->current->layout);
21420 if (!ctx || !ctx->current || !ctx->current->layout)
21421 return;
21422
21423 win = ctx->current;
21424 layout = win->layout;
21425 style = &ctx->style;
21426 s = nk_widget(&bounds, ctx);
21427 if (!s) return;
21428
21429 /* calculate hash from name */
21430 if (name[0] == '#') {
21431 hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);
21432 name++; /* special number hash */
21433 } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);
21434
21435 /* check if property is currently hot item */
21436 if (win->property.active && hash == win->property.name) {
21437 buffer = win->property.buffer;
21438 len = &win->property.length;
21439 cursor = &win->property.cursor;
21440 state = &win->property.state;
21441 select_begin = &win->property.select_start;
21442 select_end = &win->property.select_end;
21443 } else {
21444 buffer = dummy_buffer;
21445 len = &dummy_length;
21446 cursor = &dummy_cursor;
21447 state = &dummy_state;
21448 select_begin = &dummy_select_begin;
21449 select_end = &dummy_select_end;
21450 }
21451
21452 /* execute property widget */
21453 old_state = *state;
21454 ctx->text_edit.clip = ctx->clip;
21455 in = ((s == NK_WIDGET_ROM && !win->property.active) ||
21456 layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21457 nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,
21458 variant, inc_per_pixel, buffer, len, state, cursor, select_begin,
21459 select_end, &style->property, filter, in, style->font, &ctx->text_edit,
21460 ctx->button_behavior);
21461
21462 if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) {
21463 /* current property is now hot */
21464 win->property.active = 1;
21465 NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);
21466 win->property.length = *len;
21467 win->property.cursor = *cursor;
21468 win->property.state = *state;
21469 win->property.name = hash;
21470 win->property.select_start = *select_begin;
21471 win->property.select_end = *select_end;
21472 if (*state == NK_PROPERTY_DRAG) {
21473 ctx->input.mouse.grab = nk_true;
21474 ctx->input.mouse.grabbed = nk_true;
21475 }
21476 }
21477 /* check if previously active property is now inactive */
21478 if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {
21479 if (old_state == NK_PROPERTY_DRAG) {
21480 ctx->input.mouse.grab = nk_false;
21481 ctx->input.mouse.grabbed = nk_false;
21482 ctx->input.mouse.ungrab = nk_true;
21483 }
21484 win->property.select_start = 0;
21485 win->property.select_end = 0;
21486 win->property.active = 0;
21487 }
21488 }
21489
21490 NK_API void
21491 nk_property_int(struct nk_context *ctx, const char *name,
21492 int min, int *val, int max, int step, float inc_per_pixel)
21493 {
21494 struct nk_property_variant variant;
21495 NK_ASSERT(ctx);
21496 NK_ASSERT(name);
21497 NK_ASSERT(val);
21498
21499 if (!ctx || !ctx->current || !name || !val) return;
21500 variant = nk_property_variant_int(*val, min, max, step);
21501 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
21502 *val = variant.value.i;
21503 }
21504
21505 NK_API void
21506 nk_property_float(struct nk_context *ctx, const char *name,
21507 float min, float *val, float max, float step, float inc_per_pixel)
21508 {
21509 struct nk_property_variant variant;
21510 NK_ASSERT(ctx);
21511 NK_ASSERT(name);
21512 NK_ASSERT(val);
21513
21514 if (!ctx || !ctx->current || !name || !val) return;
21515 variant = nk_property_variant_float(*val, min, max, step);
21516 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
21517 *val = variant.value.f;
21518 }
21519
21520 NK_API void
21521 nk_property_double(struct nk_context *ctx, const char *name,
21522 double min, double *val, double max, double step, float inc_per_pixel)
21523 {
21524 struct nk_property_variant variant;
21525 NK_ASSERT(ctx);
21526 NK_ASSERT(name);
21527 NK_ASSERT(val);
21528
21529 if (!ctx || !ctx->current || !name || !val) return;
21530 variant = nk_property_variant_double(*val, min, max, step);
21531 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
21532 *val = variant.value.d;
21533 }
21534
21535 NK_API int
21536 nk_propertyi(struct nk_context *ctx, const char *name, int min, int val,
21537 int max, int step, float inc_per_pixel)
21538 {
21539 struct nk_property_variant variant;
21540 NK_ASSERT(ctx);
21541 NK_ASSERT(name);
21542
21543 if (!ctx || !ctx->current || !name) return val;
21544 variant = nk_property_variant_int(val, min, max, step);
21545 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
21546 val = variant.value.i;
21547 return val;
21548 }
21549
21550 NK_API float
21551 nk_propertyf(struct nk_context *ctx, const char *name, float min,
21552 float val, float max, float step, float inc_per_pixel)
21553 {
21554 struct nk_property_variant variant;
21555 NK_ASSERT(ctx);
21556 NK_ASSERT(name);
21557
21558 if (!ctx || !ctx->current || !name) return val;
21559 variant = nk_property_variant_float(val, min, max, step);
21560 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
21561 val = variant.value.f;
21562 return val;
21563 }
21564
21565 NK_API double
21566 nk_propertyd(struct nk_context *ctx, const char *name, double min,
21567 double val, double max, double step, float inc_per_pixel)
21568 {
21569 struct nk_property_variant variant;
21570 NK_ASSERT(ctx);
21571 NK_ASSERT(name);
21572
21573 if (!ctx || !ctx->current || !name) return val;
21574 variant = nk_property_variant_double(val, min, max, step);
21575 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
21576 val = variant.value.d;
21577 return val;
21578 }
21579
21580 /*----------------------------------------------------------------
21581 *
21582 * COLOR PICKER
21583 *
21584 * --------------------------------------------------------------*/
21585 NK_API int
21586 nk_color_pick(struct nk_context * ctx, struct nk_color *color,
21587 enum nk_color_format fmt)
21588 {
21589 struct nk_window *win;
21590 struct nk_panel *layout;
21591 const struct nk_style *config;
21592 const struct nk_input *in;
21593
21594 enum nk_widget_layout_states state;
21595 struct nk_rect bounds;
21596
21597 NK_ASSERT(ctx);
21598 NK_ASSERT(color);
21599 NK_ASSERT(ctx->current);
21600 NK_ASSERT(ctx->current->layout);
21601 if (!ctx || !ctx->current || !ctx->current->layout || !color)
21602 return 0;
21603
21604 win = ctx->current;
21605 config = &ctx->style;
21606 layout = win->layout;
21607 state = nk_widget(&bounds, ctx);
21608 if (!state) return 0;
21609 in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21610 return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,
21611 nk_vec2(0,0), in, config->font);
21612 }
21613
21614 NK_API struct nk_color
21615 nk_color_picker(struct nk_context *ctx, struct nk_color color,
21616 enum nk_color_format fmt)
21617 {
21618 nk_color_pick(ctx, &color, fmt);
21619 return color;
21620 }
21621
21622 /* -------------------------------------------------------------
21623 *
21624 * CHART
21625 *
21626 * --------------------------------------------------------------*/
21627 NK_API int
21628 nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
21629 struct nk_color color, struct nk_color highlight,
21630 int count, float min_value, float max_value)
21631 {
21632 struct nk_window *win;
21633 struct nk_chart *chart;
21634 const struct nk_style *config;
21635 const struct nk_style_chart *style;
21636
21637 const struct nk_style_item *background;
21638 struct nk_rect bounds = {0, 0, 0, 0};
21639
21640 NK_ASSERT(ctx);
21641 NK_ASSERT(ctx->current);
21642 NK_ASSERT(ctx->current->layout);
21643
21644 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
21645 if (!nk_widget(&bounds, ctx)) {
21646 chart = &ctx->current->layout->chart;
21647 nk_zero(chart, sizeof(*chart));
21648 return 0;
21649 }
21650
21651 win = ctx->current;
21652 config = &ctx->style;
21653 chart = &win->layout->chart;
21654 style = &config->chart;
21655
21656 /* setup basic generic chart */
21657 nk_zero(chart, sizeof(*chart));
21658 chart->x = bounds.x + style->padding.x;
21659 chart->y = bounds.y + style->padding.y;
21660 chart->w = bounds.w - 2 * style->padding.x;
21661 chart->h = bounds.h - 2 * style->padding.y;
21662 chart->w = NK_MAX(chart->w, 2 * style->padding.x);
21663 chart->h = NK_MAX(chart->h, 2 * style->padding.y);
21664
21665 /* add first slot into chart */
21666 {struct nk_chart_slot *slot = &chart->slots[chart->slot++];
21667 slot->type = type;
21668 slot->count = count;
21669 slot->color = color;
21670 slot->highlight = highlight;
21671 slot->min = NK_MIN(min_value, max_value);
21672 slot->max = NK_MAX(min_value, max_value);
21673 slot->range = slot->max - slot->min;}
21674
21675 /* draw chart background */
21676 background = &style->background;
21677 if (background->type == NK_STYLE_ITEM_IMAGE) {
21678 nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
21679 } else {
21680 nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
21681 nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
21682 style->rounding, style->background.data.color);
21683 }
21684 return 1;
21685 }
21686
21687 NK_API int
21688 nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
21689 int count, float min_value, float max_value)
21690 {return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);}
21691
21692 NK_API void
21693 nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
21694 struct nk_color color, struct nk_color highlight,
21695 int count, float min_value, float max_value)
21696 {
21697 NK_ASSERT(ctx);
21698 NK_ASSERT(ctx->current);
21699 NK_ASSERT(ctx->current->layout);
21700 NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
21701 if (!ctx || !ctx->current || !ctx->current->layout) return;
21702 if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
21703
21704 /* add another slot into the graph */
21705 {struct nk_chart *chart = &ctx->current->layout->chart;
21706 struct nk_chart_slot *slot = &chart->slots[chart->slot++];
21707 slot->type = type;
21708 slot->count = count;
21709 slot->color = color;
21710 slot->highlight = highlight;
21711 slot->min = NK_MIN(min_value, max_value);
21712 slot->max = NK_MAX(min_value, max_value);
21713 slot->range = slot->max - slot->min;}
21714 }
21715
21716 NK_API void
21717 nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
21718 int count, float min_value, float max_value)
21719 {nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);}
21720
21721 NK_INTERN nk_flags
21722 nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
21723 struct nk_chart *g, float value, int slot)
21724 {
21725 struct nk_panel *layout = win->layout;
21726 const struct nk_input *i = &ctx->input;
21727 struct nk_command_buffer *out = &win->buffer;
21728
21729 nk_flags ret = 0;
21730 struct nk_vec2 cur;
21731 struct nk_rect bounds;
21732 struct nk_color color;
21733 float step;
21734 float range;
21735 float ratio;
21736
21737 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21738 step = g->w / (float)g->slots[slot].count;
21739 range = g->slots[slot].max - g->slots[slot].min;
21740 ratio = (value - g->slots[slot].min) / range;
21741
21742 if (g->slots[slot].index == 0) {
21743 /* first data point does not have a connection */
21744 g->slots[slot].last.x = g->x;
21745 g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
21746
21747 bounds.x = g->slots[slot].last.x - 2;
21748 bounds.y = g->slots[slot].last.y - 2;
21749 bounds.w = bounds.h = 4;
21750
21751 color = g->slots[slot].color;
21752 if (!(layout->flags & NK_WINDOW_ROM) &&
21753 NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
21754 ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
21755 ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
21756 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21757 color = g->slots[slot].highlight;
21758 }
21759 nk_fill_rect(out, bounds, 0, color);
21760 g->slots[slot].index += 1;
21761 return ret;
21762 }
21763
21764 /* draw a line between the last data point and the new one */
21765 color = g->slots[slot].color;
21766 cur.x = g->x + (float)(step * (float)g->slots[slot].index);
21767 cur.y = (g->y + g->h) - (ratio * (float)g->h);
21768 nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
21769
21770 bounds.x = cur.x - 3;
21771 bounds.y = cur.y - 3;
21772 bounds.w = bounds.h = 6;
21773
21774 /* user selection of current data point */
21775 if (!(layout->flags & NK_WINDOW_ROM)) {
21776 if (nk_input_is_mouse_hovering_rect(i, bounds)) {
21777 ret = NK_CHART_HOVERING;
21778 ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
21779 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21780 color = g->slots[slot].highlight;
21781 }
21782 }
21783 nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
21784
21785 /* save current data point position */
21786 g->slots[slot].last.x = cur.x;
21787 g->slots[slot].last.y = cur.y;
21788 g->slots[slot].index += 1;
21789 return ret;
21790 }
21791
21792 NK_INTERN nk_flags
21793 nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
21794 struct nk_chart *chart, float value, int slot)
21795 {
21796 struct nk_command_buffer *out = &win->buffer;
21797 const struct nk_input *in = &ctx->input;
21798 struct nk_panel *layout = win->layout;
21799
21800 float ratio;
21801 nk_flags ret = 0;
21802 struct nk_color color;
21803 struct nk_rect item = {0,0,0,0};
21804
21805 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21806 if (chart->slots[slot].index >= chart->slots[slot].count)
21807 return nk_false;
21808 if (chart->slots[slot].count) {
21809 float padding = (float)(chart->slots[slot].count-1);
21810 item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
21811 }
21812
21813 /* calculate bounds of current bar chart entry */
21814 color = chart->slots[slot].color;;
21815 item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
21816 if (value >= 0) {
21817 ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
21818 item.y = (chart->y + chart->h) - chart->h * ratio;
21819 } else {
21820 ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
21821 item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
21822 }
21823 item.x = chart->x + ((float)chart->slots[slot].index * item.w);
21824 item.x = item.x + ((float)chart->slots[slot].index);
21825
21826 /* user chart bar selection */
21827 if (!(layout->flags & NK_WINDOW_ROM) &&
21828 NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
21829 ret = NK_CHART_HOVERING;
21830 ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
21831 in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
21832 color = chart->slots[slot].highlight;
21833 }
21834 nk_fill_rect(out, item, 0, color);
21835 chart->slots[slot].index += 1;
21836 return ret;
21837 }
21838
21839 NK_API nk_flags
21840 nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
21841 {
21842 nk_flags flags;
21843 struct nk_window *win;
21844
21845 NK_ASSERT(ctx);
21846 NK_ASSERT(ctx->current);
21847 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
21848 NK_ASSERT(slot < ctx->current->layout->chart.slot);
21849 if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
21850 if (slot >= ctx->current->layout->chart.slot) return nk_false;
21851
21852 win = ctx->current;
21853 if (win->layout->chart.slot < slot) return nk_false;
21854 switch (win->layout->chart.slots[slot].type) {
21855 case NK_CHART_LINES:
21856 flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
21857 case NK_CHART_COLUMN:
21858 flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
21859 default:
21860 case NK_CHART_MAX:
21861 flags = 0;
21862 }
21863 return flags;
21864 }
21865
21866 NK_API nk_flags
21867 nk_chart_push(struct nk_context *ctx, float value)
21868 {return nk_chart_push_slot(ctx, value, 0);}
21869
21870 NK_API void
21871 nk_chart_end(struct nk_context *ctx)
21872 {
21873 struct nk_window *win;
21874 struct nk_chart *chart;
21875
21876 NK_ASSERT(ctx);
21877 NK_ASSERT(ctx->current);
21878 if (!ctx || !ctx->current)
21879 return;
21880
21881 win = ctx->current;
21882 chart = &win->layout->chart;
21883 NK_MEMSET(chart, 0, sizeof(*chart));
21884 return;
21885 }
21886
21887 NK_API void
21888 nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
21889 int count, int offset)
21890 {
21891 int i = 0;
21892 float min_value;
21893 float max_value;
21894
21895 NK_ASSERT(ctx);
21896 NK_ASSERT(values);
21897 if (!ctx || !values || !count) return;
21898
21899 min_value = values[offset];
21900 max_value = values[offset];
21901 for (i = 0; i < count; ++i) {
21902 min_value = NK_MIN(values[i + offset], min_value);
21903 max_value = NK_MAX(values[i + offset], max_value);
21904 }
21905
21906 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
21907 for (i = 0; i < count; ++i)
21908 nk_chart_push(ctx, values[i + offset]);
21909 nk_chart_end(ctx);
21910 }
21911 }
21912
21913 NK_API void
21914 nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
21915 float(*value_getter)(void* user, int index), int count, int offset)
21916 {
21917 int i = 0;
21918 float min_value;
21919 float max_value;
21920
21921 NK_ASSERT(ctx);
21922 NK_ASSERT(value_getter);
21923 if (!ctx || !value_getter || !count) return;
21924
21925 max_value = min_value = value_getter(userdata, offset);
21926 for (i = 0; i < count; ++i) {
21927 float value = value_getter(userdata, i + offset);
21928 min_value = NK_MIN(value, min_value);
21929 max_value = NK_MAX(value, max_value);
21930 }
21931
21932 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
21933 for (i = 0; i < count; ++i)
21934 nk_chart_push(ctx, value_getter(userdata, i + offset));
21935 nk_chart_end(ctx);
21936 }
21937 }
21938
21939 /* -------------------------------------------------------------
21940 *
21941 * GROUP
21942 *
21943 * --------------------------------------------------------------*/
21944 NK_API int
21945 nk_group_scrolled_offset_begin(struct nk_context *ctx,
21946 nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)
21947 {
21948 struct nk_rect bounds;
21949 struct nk_window panel;
21950 struct nk_window *win;
21951
21952 win = ctx->current;
21953 nk_panel_alloc_space(&bounds, ctx);
21954 {const struct nk_rect *c = &win->layout->clip;
21955 if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&
21956 !(flags & NK_WINDOW_MOVABLE)) {
21957 return 0;
21958 }}
21959 if (win->flags & NK_WINDOW_ROM)
21960 flags |= NK_WINDOW_ROM;
21961
21962 /* initialize a fake window to create the panel from */
21963 nk_zero(&panel, sizeof(panel));
21964 panel.bounds = bounds;
21965 panel.flags = flags;
21966 panel.scrollbar.x = *x_offset;
21967 panel.scrollbar.y = *y_offset;
21968 panel.buffer = win->buffer;
21969 panel.layout = (struct nk_panel*)nk_create_panel(ctx);
21970 ctx->current = &panel;
21971 nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);
21972
21973 win->buffer = panel.buffer;
21974 win->buffer.clip = panel.layout->clip;
21975 panel.layout->offset_x = x_offset;
21976 panel.layout->offset_y = y_offset;
21977 panel.layout->parent = win->layout;
21978 win->layout = panel.layout;
21979
21980 ctx->current = win;
21981 if ((panel.layout->flags & NK_WINDOW_CLOSED) ||
21982 (panel.layout->flags & NK_WINDOW_MINIMIZED))
21983 {
21984 nk_flags f = panel.layout->flags;
21985 nk_group_scrolled_end(ctx);
21986 if (f & NK_WINDOW_CLOSED)
21987 return NK_WINDOW_CLOSED;
21988 if (f & NK_WINDOW_MINIMIZED)
21989 return NK_WINDOW_MINIMIZED;
21990 }
21991 return 1;
21992 }
21993
21994 NK_API void
21995 nk_group_scrolled_end(struct nk_context *ctx)
21996 {
21997 struct nk_window *win;
21998 struct nk_panel *parent;
21999 struct nk_panel *g;
22000
22001 struct nk_rect clip;
22002 struct nk_window pan;
22003 struct nk_vec2 panel_padding;
22004
22005 NK_ASSERT(ctx);
22006 NK_ASSERT(ctx->current);
22007 if (!ctx || !ctx->current)
22008 return;
22009
22010 /* make sure nk_group_begin was called correctly */
22011 NK_ASSERT(ctx->current);
22012 win = ctx->current;
22013 NK_ASSERT(win->layout);
22014 g = win->layout;
22015 NK_ASSERT(g->parent);
22016 parent = g->parent;
22017
22018 /* dummy window */
22019 nk_zero_struct(pan);
22020 panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);
22021 pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);
22022 pan.bounds.x = g->bounds.x - panel_padding.x;
22023 pan.bounds.w = g->bounds.w + 2 * panel_padding.x;
22024 pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;
22025 if (g->flags & NK_WINDOW_BORDER) {
22026 pan.bounds.x -= g->border;
22027 pan.bounds.y -= g->border;
22028 pan.bounds.w += 2*g->border;
22029 pan.bounds.h += 2*g->border;
22030 }
22031 if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {
22032 pan.bounds.w += ctx->style.window.scrollbar_size.x;
22033 pan.bounds.h += ctx->style.window.scrollbar_size.y;
22034 }
22035 pan.scrollbar.x = *g->offset_x;
22036 pan.scrollbar.y = *g->offset_y;
22037 pan.flags = g->flags;
22038 pan.buffer = win->buffer;
22039 pan.layout = g;
22040 pan.parent = win;
22041 ctx->current = &pan;
22042
22043 /* make sure group has correct clipping rectangle */
22044 nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,
22045 pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);
22046 nk_push_scissor(&pan.buffer, clip);
22047 nk_end(ctx);
22048
22049 win->buffer = pan.buffer;
22050 nk_push_scissor(&win->buffer, parent->clip);
22051 ctx->current = win;
22052 win->layout = parent;
22053 g->bounds = pan.bounds;
22054 return;
22055 }
22056
22057 NK_API int
22058 nk_group_scrolled_begin(struct nk_context *ctx,
22059 struct nk_scroll *scroll, const char *title, nk_flags flags)
22060 {return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);}
22061
22062 NK_API int
22063 nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)
22064 {
22065 int title_len;
22066 nk_hash title_hash;
22067 struct nk_window *win;
22068 nk_uint *x_offset;
22069 nk_uint *y_offset;
22070
22071 NK_ASSERT(ctx);
22072 NK_ASSERT(title);
22073 NK_ASSERT(ctx->current);
22074 NK_ASSERT(ctx->current->layout);
22075 if (!ctx || !ctx->current || !ctx->current->layout || !title)
22076 return 0;
22077
22078 /* find persistent group scrollbar value */
22079 win = ctx->current;
22080 title_len = (int)nk_strlen(title);
22081 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
22082 x_offset = nk_find_value(win, title_hash);
22083 if (!x_offset) {
22084 x_offset = nk_add_value(ctx, win, title_hash, 0);
22085 y_offset = nk_add_value(ctx, win, title_hash+1, 0);
22086
22087 NK_ASSERT(x_offset);
22088 NK_ASSERT(y_offset);
22089 if (!x_offset || !y_offset) return 0;
22090 *x_offset = *y_offset = 0;
22091 } else y_offset = nk_find_value(win, title_hash+1);
22092 return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
22093 }
22094
22095 NK_API void
22096 nk_group_end(struct nk_context *ctx)
22097 {nk_group_scrolled_end(ctx);}
22098
22099 NK_API int
22100 nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,
22101 const char *title, nk_flags flags, int row_height, int row_count)
22102 {
22103 int title_len;
22104 nk_hash title_hash;
22105 nk_uint *x_offset;
22106 nk_uint *y_offset;
22107
22108 int result;
22109 struct nk_window *win;
22110 struct nk_panel *layout;
22111 const struct nk_style *style;
22112 struct nk_vec2 item_spacing;
22113
22114 NK_ASSERT(ctx);
22115 NK_ASSERT(view);
22116 NK_ASSERT(title);
22117 if (!ctx || !view || !title) return 0;
22118
22119 win = ctx->current;
22120 style = &ctx->style;
22121 item_spacing = style->window.spacing;
22122 row_height += NK_MAX(0, (int)item_spacing.y);
22123
22124 /* find persistent list view scrollbar offset */
22125 title_len = (int)nk_strlen(title);
22126 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
22127 x_offset = nk_find_value(win, title_hash);
22128 if (!x_offset) {
22129 x_offset = nk_add_value(ctx, win, title_hash, 0);
22130 y_offset = nk_add_value(ctx, win, title_hash+1, 0);
22131
22132 NK_ASSERT(x_offset);
22133 NK_ASSERT(y_offset);
22134 if (!x_offset || !y_offset) return 0;
22135 *x_offset = *y_offset = 0;
22136 } else y_offset = nk_find_value(win, title_hash+1);
22137 view->scroll_value = *y_offset;
22138 view->scroll_pointer = y_offset;
22139
22140 *y_offset = 0;
22141 result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
22142 win = ctx->current;
22143 layout = win->layout;
22144
22145 view->total_height = row_height * NK_MAX(row_count,1);
22146 view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);
22147 view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0);
22148 view->end = view->begin + view->count;
22149 view->ctx = ctx;
22150 return result;
22151 }
22152
22153 NK_API void
22154 nk_list_view_end(struct nk_list_view *view)
22155 {
22156 struct nk_context *ctx;
22157 struct nk_window *win;
22158 struct nk_panel *layout;
22159
22160 NK_ASSERT(view);
22161 NK_ASSERT(view->ctx);
22162 NK_ASSERT(view->scroll_pointer);
22163 if (!view || !view->ctx) return;
22164
22165 ctx = view->ctx;
22166 win = ctx->current;
22167 layout = win->layout;
22168 layout->at_y = layout->bounds.y + (float)view->total_height;
22169 *view->scroll_pointer = *view->scroll_pointer + view->scroll_value;
22170 nk_group_end(view->ctx);
22171 }
22172
22173 /* --------------------------------------------------------------
22174 *
22175 * POPUP
22176 *
22177 * --------------------------------------------------------------*/
22178 NK_API int
22179 nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,
22180 const char *title, nk_flags flags, struct nk_rect rect)
22181 {
22182 struct nk_window *popup;
22183 struct nk_window *win;
22184 struct nk_panel *panel;
22185
22186 int title_len;
22187 nk_hash title_hash;
22188 nk_size allocated;
22189
22190 NK_ASSERT(ctx);
22191 NK_ASSERT(title);
22192 NK_ASSERT(ctx->current);
22193 NK_ASSERT(ctx->current->layout);
22194 if (!ctx || !ctx->current || !ctx->current->layout)
22195 return 0;
22196
22197 win = ctx->current;
22198 panel = win->layout;
22199 NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups");
22200 (void)panel;
22201 title_len = (int)nk_strlen(title);
22202 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);
22203
22204 popup = win->popup.win;
22205 if (!popup) {
22206 popup = (struct nk_window*)nk_create_window(ctx);
22207 popup->parent = win;
22208 win->popup.win = popup;
22209 win->popup.active = 0;
22210 win->popup.type = NK_PANEL_POPUP;
22211 }
22212
22213 /* make sure we have correct popup */
22214 if (win->popup.name != title_hash) {
22215 if (!win->popup.active) {
22216 nk_zero(popup, sizeof(*popup));
22217 win->popup.name = title_hash;
22218 win->popup.active = 1;
22219 win->popup.type = NK_PANEL_POPUP;
22220 } else return 0;
22221 }
22222
22223 /* popup position is local to window */
22224 ctx->current = popup;
22225 rect.x += win->layout->clip.x;
22226 rect.y += win->layout->clip.y;
22227
22228 /* setup popup data */
22229 popup->parent = win;
22230 popup->bounds = rect;
22231 popup->seq = ctx->seq;
22232 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
22233 popup->flags = flags;
22234 popup->flags |= NK_WINDOW_BORDER;
22235 if (type == NK_POPUP_DYNAMIC)
22236 popup->flags |= NK_WINDOW_DYNAMIC;
22237
22238 popup->buffer = win->buffer;
22239 nk_start_popup(ctx, win);
22240 allocated = ctx->memory.allocated;
22241 nk_push_scissor(&popup->buffer, nk_null_rect);
22242
22243 if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {
22244 /* popup is running therefore invalidate parent panels */
22245 struct nk_panel *root;
22246 root = win->layout;
22247 while (root) {
22248 root->flags |= NK_WINDOW_ROM;
22249 root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
22250 root = root->parent;
22251 }
22252 win->popup.active = 1;
22253 popup->layout->offset_x = &popup->scrollbar.x;
22254 popup->layout->offset_y = &popup->scrollbar.y;
22255 popup->layout->parent = win->layout;
22256 return 1;
22257 } else {
22258 /* popup was closed/is invalid so cleanup */
22259 struct nk_panel *root;
22260 root = win->layout;
22261 while (root) {
22262 root->flags |= NK_WINDOW_REMOVE_ROM;
22263 root = root->parent;
22264 }
22265 win->popup.buf.active = 0;
22266 win->popup.active = 0;
22267 ctx->memory.allocated = allocated;
22268 ctx->current = win;
22269 nk_free_panel(ctx, popup->layout);
22270 popup->layout = 0;
22271 return 0;
22272 }
22273 }
22274
22275 NK_INTERN int
22276 nk_nonblock_begin(struct nk_context *ctx,
22277 nk_flags flags, struct nk_rect body, struct nk_rect header,
22278 enum nk_panel_type panel_type)
22279 {
22280 struct nk_window *popup;
22281 struct nk_window *win;
22282 struct nk_panel *panel;
22283 int is_active = nk_true;
22284
22285 NK_ASSERT(ctx);
22286 NK_ASSERT(ctx->current);
22287 NK_ASSERT(ctx->current->layout);
22288 if (!ctx || !ctx->current || !ctx->current->layout)
22289 return 0;
22290
22291 /* popups cannot have popups */
22292 win = ctx->current;
22293 panel = win->layout;
22294 NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP));
22295 (void)panel;
22296 popup = win->popup.win;
22297 if (!popup) {
22298 /* create window for nonblocking popup */
22299 popup = (struct nk_window*)nk_create_window(ctx);
22300 popup->parent = win;
22301 win->popup.win = popup;
22302 win->popup.type = panel_type;
22303 nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);
22304 } else {
22305 /* close the popup if user pressed outside or in the header */
22306 int pressed, in_body, in_header;
22307 pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
22308 in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
22309 in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);
22310 if (pressed && (!in_body || in_header))
22311 is_active = nk_false;
22312 }
22313 win->popup.header = header;
22314
22315 if (!is_active) {
22316 /* remove read only mode from all parent panels */
22317 struct nk_panel *root = win->layout;
22318 while (root) {
22319 root->flags |= NK_WINDOW_REMOVE_ROM;
22320 root = root->parent;
22321 }
22322 return is_active;
22323 }
22324
22325 popup->bounds = body;
22326 popup->parent = win;
22327 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
22328 popup->flags = flags;
22329 popup->flags |= NK_WINDOW_BORDER;
22330 popup->flags |= NK_WINDOW_DYNAMIC;
22331 popup->seq = ctx->seq;
22332 win->popup.active = 1;
22333 NK_ASSERT(popup->layout);
22334
22335 nk_start_popup(ctx, win);
22336 popup->buffer = win->buffer;
22337 nk_push_scissor(&popup->buffer, nk_null_rect);
22338 ctx->current = popup;
22339
22340 nk_panel_begin(ctx, 0, panel_type);
22341 win->buffer = popup->buffer;
22342 popup->layout->parent = win->layout;
22343 popup->layout->offset_x = &popup->scrollbar.x;
22344 popup->layout->offset_y = &popup->scrollbar.y;
22345
22346 /* set read only mode to all parent panels */
22347 {struct nk_panel *root;
22348 root = win->layout;
22349 while (root) {
22350 root->flags |= NK_WINDOW_ROM;
22351 root = root->parent;
22352 }}
22353 return is_active;
22354 }
22355
22356 NK_API void
22357 nk_popup_close(struct nk_context *ctx)
22358 {
22359 struct nk_window *popup;
22360 NK_ASSERT(ctx);
22361 if (!ctx || !ctx->current) return;
22362
22363 popup = ctx->current;
22364 NK_ASSERT(popup->parent);
22365 NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP);
22366 popup->flags |= NK_WINDOW_HIDDEN;
22367 }
22368
22369 NK_API void
22370 nk_popup_end(struct nk_context *ctx)
22371 {
22372 struct nk_window *win;
22373 struct nk_window *popup;
22374
22375 NK_ASSERT(ctx);
22376 NK_ASSERT(ctx->current);
22377 NK_ASSERT(ctx->current->layout);
22378 if (!ctx || !ctx->current || !ctx->current->layout)
22379 return;
22380
22381 popup = ctx->current;
22382 if (!popup->parent) return;
22383 win = popup->parent;
22384 if (popup->flags & NK_WINDOW_HIDDEN) {
22385 struct nk_panel *root;
22386 root = win->layout;
22387 while (root) {
22388 root->flags |= NK_WINDOW_REMOVE_ROM;
22389 root = root->parent;
22390 }
22391 win->popup.active = 0;
22392 }
22393 nk_push_scissor(&popup->buffer, nk_null_rect);
22394 nk_end(ctx);
22395
22396 win->buffer = popup->buffer;
22397 nk_finish_popup(ctx, win);
22398 ctx->current = win;
22399 nk_push_scissor(&win->buffer, win->layout->clip);
22400 }
22401 /* -------------------------------------------------------------
22402 *
22403 * TOOLTIP
22404 *
22405 * -------------------------------------------------------------- */
22406 NK_API int
22407 nk_tooltip_begin(struct nk_context *ctx, float width)
22408 {
22409 struct nk_window *win;
22410 const struct nk_input *in;
22411 struct nk_rect bounds;
22412 int ret;
22413
22414 NK_ASSERT(ctx);
22415 NK_ASSERT(ctx->current);
22416 NK_ASSERT(ctx->current->layout);
22417 if (!ctx || !ctx->current || !ctx->current->layout)
22418 return 0;
22419
22420 /* make sure that no nonblocking popup is currently active */
22421 win = ctx->current;
22422 in = &ctx->input;
22423 if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK))
22424 return 0;
22425
22426 bounds.w = width;
22427 bounds.h = nk_null_rect.h;
22428 bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x;
22429 bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y;
22430
22431 ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,
22432 "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);
22433 if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
22434 win->popup.type = NK_PANEL_TOOLTIP;
22435 ctx->current->layout->type = NK_PANEL_TOOLTIP;
22436 return ret;
22437 }
22438
22439 NK_API void
22440 nk_tooltip_end(struct nk_context *ctx)
22441 {
22442 NK_ASSERT(ctx);
22443 NK_ASSERT(ctx->current);
22444 if (!ctx || !ctx->current) return;
22445 ctx->current->seq--;
22446 nk_popup_close(ctx);
22447 nk_popup_end(ctx);
22448 }
22449
22450 NK_API void
22451 nk_tooltip(struct nk_context *ctx, const char *text)
22452 {
22453 const struct nk_style *style;
22454 struct nk_vec2 padding;
22455
22456 int text_len;
22457 float text_width;
22458 float text_height;
22459
22460 NK_ASSERT(ctx);
22461 NK_ASSERT(ctx->current);
22462 NK_ASSERT(ctx->current->layout);
22463 NK_ASSERT(text);
22464 if (!ctx || !ctx->current || !ctx->current->layout || !text)
22465 return;
22466
22467 /* fetch configuration data */
22468 style = &ctx->style;
22469 padding = style->window.padding;
22470
22471 /* calculate size of the text and tooltip */
22472 text_len = nk_strlen(text);
22473 text_width = style->font->width(style->font->userdata,
22474 style->font->height, text, text_len);
22475 text_width += (4 * padding.x);
22476 text_height = (style->font->height + 2 * padding.y);
22477
22478 /* execute tooltip and fill with text */
22479 if (nk_tooltip_begin(ctx, (float)text_width)) {
22480 nk_layout_row_dynamic(ctx, (float)text_height, 1);
22481 nk_text(ctx, text, text_len, NK_TEXT_LEFT);
22482 nk_tooltip_end(ctx);
22483 }
22484 }
22485 /* -------------------------------------------------------------
22486 *
22487 * CONTEXTUAL
22488 *
22489 * -------------------------------------------------------------- */
22490 NK_API int
22491 nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,
22492 struct nk_rect trigger_bounds)
22493 {
22494 struct nk_window *win;
22495 struct nk_window *popup;
22496 struct nk_rect body;
22497
22498 NK_STORAGE const struct nk_rect null_rect = {0,0,0,0};
22499 int is_clicked = 0;
22500 int is_active = 0;
22501 int is_open = 0;
22502 int ret = 0;
22503
22504 NK_ASSERT(ctx);
22505 NK_ASSERT(ctx->current);
22506 NK_ASSERT(ctx->current->layout);
22507 if (!ctx || !ctx->current || !ctx->current->layout)
22508 return 0;
22509
22510 win = ctx->current;
22511 ++win->popup.con_count;
22512
22513 /* check if currently active contextual is active */
22514 popup = win->popup.win;
22515 is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);
22516 is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds);
22517 if (win->popup.active_con && win->popup.con_count != win->popup.active_con)
22518 return 0;
22519 if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked))
22520 return 0;
22521
22522 /* calculate contextual position on click */
22523 win->popup.active_con = win->popup.con_count;
22524 if (is_clicked) {
22525 body.x = ctx->input.mouse.pos.x;
22526 body.y = ctx->input.mouse.pos.y;
22527 } else {
22528 body.x = popup->bounds.x;
22529 body.y = popup->bounds.y;
22530 }
22531 body.w = size.x;
22532 body.h = size.y;
22533
22534 /* start nonblocking contextual popup */
22535 ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body,
22536 null_rect, NK_PANEL_CONTEXTUAL);
22537 if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;
22538 else {
22539 win->popup.active_con = 0;
22540 if (win->popup.win)
22541 win->popup.win->flags = 0;
22542 }
22543 return ret;
22544 }
22545
22546 NK_API int
22547 nk_contextual_item_text(struct nk_context *ctx, const char *text, int len,
22548 nk_flags alignment)
22549 {
22550 struct nk_window *win;
22551 const struct nk_input *in;
22552 const struct nk_style *style;
22553
22554 struct nk_rect bounds;
22555 enum nk_widget_layout_states state;
22556
22557 NK_ASSERT(ctx);
22558 NK_ASSERT(ctx->current);
22559 NK_ASSERT(ctx->current->layout);
22560 if (!ctx || !ctx->current || !ctx->current->layout)
22561 return 0;
22562
22563 win = ctx->current;
22564 style = &ctx->style;
22565 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
22566 if (!state) return nk_false;
22567
22568 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22569 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
22570 text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {
22571 nk_contextual_close(ctx);
22572 return nk_true;
22573 }
22574 return nk_false;
22575 }
22576
22577 NK_API int nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)
22578 {return nk_contextual_item_text(ctx, label, nk_strlen(label), align);}
22579
22580 NK_API int
22581 nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,
22582 const char *text, int len, nk_flags align)
22583 {
22584 struct nk_window *win;
22585 const struct nk_input *in;
22586 const struct nk_style *style;
22587
22588 struct nk_rect bounds;
22589 enum nk_widget_layout_states state;
22590
22591 NK_ASSERT(ctx);
22592 NK_ASSERT(ctx->current);
22593 NK_ASSERT(ctx->current->layout);
22594 if (!ctx || !ctx->current || !ctx->current->layout)
22595 return 0;
22596
22597 win = ctx->current;
22598 style = &ctx->style;
22599 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
22600 if (!state) return nk_false;
22601
22602 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22603 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,
22604 img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){
22605 nk_contextual_close(ctx);
22606 return nk_true;
22607 }
22608 return nk_false;
22609 }
22610
22611 NK_API int nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,
22612 const char *label, nk_flags align)
22613 {return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);}
22614
22615 NK_API int
22616 nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
22617 const char *text, int len, nk_flags align)
22618 {
22619 struct nk_window *win;
22620 const struct nk_input *in;
22621 const struct nk_style *style;
22622
22623 struct nk_rect bounds;
22624 enum nk_widget_layout_states state;
22625
22626 NK_ASSERT(ctx);
22627 NK_ASSERT(ctx->current);
22628 NK_ASSERT(ctx->current->layout);
22629 if (!ctx || !ctx->current || !ctx->current->layout)
22630 return 0;
22631
22632 win = ctx->current;
22633 style = &ctx->style;
22634 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
22635 if (!state) return nk_false;
22636
22637 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
22638 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
22639 symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {
22640 nk_contextual_close(ctx);
22641 return nk_true;
22642 }
22643 return nk_false;
22644 }
22645
22646 NK_API int nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
22647 const char *text, nk_flags align)
22648 {return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);}
22649
22650 NK_API void
22651 nk_contextual_close(struct nk_context *ctx)
22652 {
22653 NK_ASSERT(ctx);
22654 NK_ASSERT(ctx->current);
22655 NK_ASSERT(ctx->current->layout);
22656 if (!ctx || !ctx->current || !ctx->current->layout) return;
22657 nk_popup_close(ctx);
22658 }
22659
22660 NK_API void
22661 nk_contextual_end(struct nk_context *ctx)
22662 {
22663 struct nk_window *popup;
22664 struct nk_panel *panel;
22665 NK_ASSERT(ctx);
22666 NK_ASSERT(ctx->current);
22667 if (!ctx || !ctx->current) return;
22668
22669 popup = ctx->current;
22670 panel = popup->layout;
22671 NK_ASSERT(popup->parent);
22672 NK_ASSERT(panel->type & NK_PANEL_SET_POPUP);
22673 if (panel->flags & NK_WINDOW_DYNAMIC) {
22674 /* Close behavior
22675 This is a bit of a hack solution since we do not know before we end our popup
22676 how big it will be. We therefore do not directly know when a
22677 click outside the non-blocking popup must close it at that direct frame.
22678 Instead it will be closed in the next frame.*/
22679 struct nk_rect body = {0,0,0,0};
22680 if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {
22681 struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);
22682 body = panel->bounds;
22683 body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);
22684 body.h = (panel->bounds.y + panel->bounds.h) - body.y;
22685 }
22686 {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
22687 int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
22688 if (pressed && in_body)
22689 popup->flags |= NK_WINDOW_HIDDEN;
22690 }
22691 }
22692 if (popup->flags & NK_WINDOW_HIDDEN)
22693 popup->seq = 0;
22694 nk_popup_end(ctx);
22695 return;
22696 }
22697 /* -------------------------------------------------------------
22698 *
22699 * COMBO
22700 *
22701 * --------------------------------------------------------------*/
22702 NK_INTERN int
22703 nk_combo_begin(struct nk_context *ctx, struct nk_window *win,
22704 struct nk_vec2 size, int is_clicked, struct nk_rect header)
22705 {
22706 struct nk_window *popup;
22707 int is_open = 0;
22708 int is_active = 0;
22709 struct nk_rect body;
22710 nk_hash hash;
22711
22712 NK_ASSERT(ctx);
22713 NK_ASSERT(ctx->current);
22714 NK_ASSERT(ctx->current->layout);
22715 if (!ctx || !ctx->current || !ctx->current->layout)
22716 return 0;
22717
22718 popup = win->popup.win;
22719 body.x = header.x;
22720 body.w = size.x;
22721 body.y = header.y + header.h-ctx->style.window.combo_border;
22722 body.h = size.y;
22723
22724 hash = win->popup.combo_count++;
22725 is_open = (popup) ? nk_true:nk_false;
22726 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);
22727 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
22728 (!is_open && !is_active && !is_clicked)) return 0;
22729 if (!nk_nonblock_begin(ctx, 0, body,
22730 (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;
22731
22732 win->popup.type = NK_PANEL_COMBO;
22733 win->popup.name = hash;
22734 return 1;
22735 }
22736
22737 NK_API int
22738 nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,
22739 struct nk_vec2 size)
22740 {
22741 const struct nk_input *in;
22742 struct nk_window *win;
22743 struct nk_style *style;
22744
22745 enum nk_widget_layout_states s;
22746 int is_clicked = nk_false;
22747 struct nk_rect header;
22748 const struct nk_style_item *background;
22749 struct nk_text text;
22750
22751 NK_ASSERT(ctx);
22752 NK_ASSERT(selected);
22753 NK_ASSERT(ctx->current);
22754 NK_ASSERT(ctx->current->layout);
22755 if (!ctx || !ctx->current || !ctx->current->layout || !selected)
22756 return 0;
22757
22758 win = ctx->current;
22759 style = &ctx->style;
22760 s = nk_widget(&header, ctx);
22761 if (s == NK_WIDGET_INVALID)
22762 return 0;
22763
22764 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22765 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22766 is_clicked = nk_true;
22767
22768 /* draw combo box header background and border */
22769 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22770 background = &style->combo.active;
22771 text.text = style->combo.label_active;
22772 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22773 background = &style->combo.hover;
22774 text.text = style->combo.label_hover;
22775 } else {
22776 background = &style->combo.normal;
22777 text.text = style->combo.label_normal;
22778 }
22779 if (background->type == NK_STYLE_ITEM_IMAGE) {
22780 text.background = nk_rgba(0,0,0,0);
22781 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22782 } else {
22783 text.background = background->data.color;
22784 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22785 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22786 }
22787 {
22788 /* print currently selected text item */
22789 struct nk_rect label;
22790 struct nk_rect button;
22791 struct nk_rect content;
22792
22793 enum nk_symbol_type sym;
22794 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22795 sym = style->combo.sym_hover;
22796 else if (is_clicked)
22797 sym = style->combo.sym_active;
22798 else sym = style->combo.sym_normal;
22799
22800 /* calculate button */
22801 button.w = header.h - 2 * style->combo.button_padding.y;
22802 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22803 button.y = header.y + style->combo.button_padding.y;
22804 button.h = button.w;
22805
22806 content.x = button.x + style->combo.button.padding.x;
22807 content.y = button.y + style->combo.button.padding.y;
22808 content.w = button.w - 2 * style->combo.button.padding.x;
22809 content.h = button.h - 2 * style->combo.button.padding.y;
22810
22811 /* draw selected label */
22812 text.padding = nk_vec2(0,0);
22813 label.x = header.x + style->combo.content_padding.x;
22814 label.y = header.y + style->combo.content_padding.y;
22815 label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;;
22816 label.h = header.h - 2 * style->combo.content_padding.y;
22817 nk_widget_text(&win->buffer, label, selected, len, &text,
22818 NK_TEXT_LEFT, ctx->style.font);
22819
22820 /* draw open/close button */
22821 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22822 &ctx->style.combo.button, sym, style->font);
22823 }
22824 return nk_combo_begin(ctx, win, size, is_clicked, header);
22825 }
22826
22827 NK_API int nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)
22828 {return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);}
22829
22830 NK_API int
22831 nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)
22832 {
22833 struct nk_window *win;
22834 struct nk_style *style;
22835 const struct nk_input *in;
22836
22837 struct nk_rect header;
22838 int is_clicked = nk_false;
22839 enum nk_widget_layout_states s;
22840 const struct nk_style_item *background;
22841
22842 NK_ASSERT(ctx);
22843 NK_ASSERT(ctx->current);
22844 NK_ASSERT(ctx->current->layout);
22845 if (!ctx || !ctx->current || !ctx->current->layout)
22846 return 0;
22847
22848 win = ctx->current;
22849 style = &ctx->style;
22850 s = nk_widget(&header, ctx);
22851 if (s == NK_WIDGET_INVALID)
22852 return 0;
22853
22854 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22855 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22856 is_clicked = nk_true;
22857
22858 /* draw combo box header background and border */
22859 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
22860 background = &style->combo.active;
22861 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22862 background = &style->combo.hover;
22863 else background = &style->combo.normal;
22864
22865 if (background->type == NK_STYLE_ITEM_IMAGE) {
22866 nk_draw_image(&win->buffer, header, &background->data.image,nk_white);
22867 } else {
22868 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22869 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22870 }
22871 {
22872 struct nk_rect content;
22873 struct nk_rect button;
22874 struct nk_rect bounds;
22875
22876 enum nk_symbol_type sym;
22877 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22878 sym = style->combo.sym_hover;
22879 else if (is_clicked)
22880 sym = style->combo.sym_active;
22881 else sym = style->combo.sym_normal;
22882
22883 /* calculate button */
22884 button.w = header.h - 2 * style->combo.button_padding.y;
22885 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
22886 button.y = header.y + style->combo.button_padding.y;
22887 button.h = button.w;
22888
22889 content.x = button.x + style->combo.button.padding.x;
22890 content.y = button.y + style->combo.button.padding.y;
22891 content.w = button.w - 2 * style->combo.button.padding.x;
22892 content.h = button.h - 2 * style->combo.button.padding.y;
22893
22894 /* draw color */
22895 bounds.h = header.h - 4 * style->combo.content_padding.y;
22896 bounds.y = header.y + 2 * style->combo.content_padding.y;
22897 bounds.x = header.x + 2 * style->combo.content_padding.x;
22898 bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;
22899 nk_fill_rect(&win->buffer, bounds, 0, color);
22900
22901 /* draw open/close button */
22902 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
22903 &ctx->style.combo.button, sym, style->font);
22904 }
22905 return nk_combo_begin(ctx, win, size, is_clicked, header);
22906 }
22907
22908 NK_API int
22909 nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)
22910 {
22911 struct nk_window *win;
22912 struct nk_style *style;
22913 const struct nk_input *in;
22914
22915 struct nk_rect header;
22916 int is_clicked = nk_false;
22917 enum nk_widget_layout_states s;
22918 const struct nk_style_item *background;
22919 struct nk_color sym_background;
22920 struct nk_color symbol_color;
22921
22922 NK_ASSERT(ctx);
22923 NK_ASSERT(ctx->current);
22924 NK_ASSERT(ctx->current->layout);
22925 if (!ctx || !ctx->current || !ctx->current->layout)
22926 return 0;
22927
22928 win = ctx->current;
22929 style = &ctx->style;
22930 s = nk_widget(&header, ctx);
22931 if (s == NK_WIDGET_INVALID)
22932 return 0;
22933
22934 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
22935 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
22936 is_clicked = nk_true;
22937
22938 /* draw combo box header background and border */
22939 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
22940 background = &style->combo.active;
22941 symbol_color = style->combo.symbol_active;
22942 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
22943 background = &style->combo.hover;
22944 symbol_color = style->combo.symbol_hover;
22945 } else {
22946 background = &style->combo.normal;
22947 symbol_color = style->combo.symbol_hover;
22948 }
22949
22950 if (background->type == NK_STYLE_ITEM_IMAGE) {
22951 sym_background = nk_rgba(0,0,0,0);
22952 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
22953 } else {
22954 sym_background = background->data.color;
22955 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
22956 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
22957 }
22958 {
22959 struct nk_rect bounds = {0,0,0,0};
22960 struct nk_rect content;
22961 struct nk_rect button;
22962
22963 enum nk_symbol_type sym;
22964 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
22965 sym = style->combo.sym_hover;
22966 else if (is_clicked)
22967 sym = style->combo.sym_active;
22968 else sym = style->combo.sym_normal;
22969
22970 /* calculate button */
22971 button.w = header.h - 2 * style->combo.button_padding.y;
22972 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
22973 button.y = header.y + style->combo.button_padding.y;
22974 button.h = button.w;
22975
22976 content.x = button.x + style->combo.button.padding.x;
22977 content.y = button.y + style->combo.button.padding.y;
22978 content.w = button.w - 2 * style->combo.button.padding.x;
22979 content.h = button.h - 2 * style->combo.button.padding.y;
22980
22981 /* draw symbol */
22982 bounds.h = header.h - 2 * style->combo.content_padding.y;
22983 bounds.y = header.y + style->combo.content_padding.y;
22984 bounds.x = header.x + style->combo.content_padding.x;
22985 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
22986 nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,
22987 1.0f, style->font);
22988
22989 /* draw open/close button */
22990 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
22991 &ctx->style.combo.button, sym, style->font);
22992 }
22993 return nk_combo_begin(ctx, win, size, is_clicked, header);
22994 }
22995
22996 NK_API int
22997 nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,
22998 enum nk_symbol_type symbol, struct nk_vec2 size)
22999 {
23000 struct nk_window *win;
23001 struct nk_style *style;
23002 struct nk_input *in;
23003
23004 struct nk_rect header;
23005 int is_clicked = nk_false;
23006 enum nk_widget_layout_states s;
23007 const struct nk_style_item *background;
23008 struct nk_color symbol_color;
23009 struct nk_text text;
23010
23011 NK_ASSERT(ctx);
23012 NK_ASSERT(ctx->current);
23013 NK_ASSERT(ctx->current->layout);
23014 if (!ctx || !ctx->current || !ctx->current->layout)
23015 return 0;
23016
23017 win = ctx->current;
23018 style = &ctx->style;
23019 s = nk_widget(&header, ctx);
23020 if (!s) return 0;
23021
23022 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
23023 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
23024 is_clicked = nk_true;
23025
23026 /* draw combo box header background and border */
23027 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
23028 background = &style->combo.active;
23029 symbol_color = style->combo.symbol_active;
23030 text.text = style->combo.label_active;
23031 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
23032 background = &style->combo.hover;
23033 symbol_color = style->combo.symbol_hover;
23034 text.text = style->combo.label_hover;
23035 } else {
23036 background = &style->combo.normal;
23037 symbol_color = style->combo.symbol_normal;
23038 text.text = style->combo.label_normal;
23039 }
23040 if (background->type == NK_STYLE_ITEM_IMAGE) {
23041 text.background = nk_rgba(0,0,0,0);
23042 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
23043 } else {
23044 text.background = background->data.color;
23045 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
23046 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
23047 }
23048 {
23049 struct nk_rect content;
23050 struct nk_rect button;
23051 struct nk_rect label;
23052 struct nk_rect image;
23053
23054 enum nk_symbol_type sym;
23055 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
23056 sym = style->combo.sym_hover;
23057 else if (is_clicked)
23058 sym = style->combo.sym_active;
23059 else sym = style->combo.sym_normal;
23060
23061 /* calculate button */
23062 button.w = header.h - 2 * style->combo.button_padding.y;
23063 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
23064 button.y = header.y + style->combo.button_padding.y;
23065 button.h = button.w;
23066
23067 content.x = button.x + style->combo.button.padding.x;
23068 content.y = button.y + style->combo.button.padding.y;
23069 content.w = button.w - 2 * style->combo.button.padding.x;
23070 content.h = button.h - 2 * style->combo.button.padding.y;
23071 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
23072 &ctx->style.combo.button, sym, style->font);
23073
23074 /* draw symbol */
23075 image.x = header.x + style->combo.content_padding.x;
23076 image.y = header.y + style->combo.content_padding.y;
23077 image.h = header.h - 2 * style->combo.content_padding.y;
23078 image.w = image.h;
23079 nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,
23080 1.0f, style->font);
23081
23082 /* draw label */
23083 text.padding = nk_vec2(0,0);
23084 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
23085 label.y = header.y + style->combo.content_padding.y;
23086 label.w = (button.x - style->combo.content_padding.x) - label.x;
23087 label.h = header.h - 2 * style->combo.content_padding.y;
23088 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
23089 }
23090 return nk_combo_begin(ctx, win, size, is_clicked, header);
23091 }
23092
23093 NK_API int
23094 nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)
23095 {
23096 struct nk_window *win;
23097 struct nk_style *style;
23098 const struct nk_input *in;
23099
23100 struct nk_rect header;
23101 int is_clicked = nk_false;
23102 enum nk_widget_layout_states s;
23103 const struct nk_style_item *background;
23104
23105 NK_ASSERT(ctx);
23106 NK_ASSERT(ctx->current);
23107 NK_ASSERT(ctx->current->layout);
23108 if (!ctx || !ctx->current || !ctx->current->layout)
23109 return 0;
23110
23111 win = ctx->current;
23112 style = &ctx->style;
23113 s = nk_widget(&header, ctx);
23114 if (s == NK_WIDGET_INVALID)
23115 return 0;
23116
23117 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
23118 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
23119 is_clicked = nk_true;
23120
23121 /* draw combo box header background and border */
23122 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
23123 background = &style->combo.active;
23124 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
23125 background = &style->combo.hover;
23126 else background = &style->combo.normal;
23127
23128 if (background->type == NK_STYLE_ITEM_IMAGE) {
23129 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
23130 } else {
23131 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
23132 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
23133 }
23134 {
23135 struct nk_rect bounds = {0,0,0,0};
23136 struct nk_rect content;
23137 struct nk_rect button;
23138
23139 enum nk_symbol_type sym;
23140 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
23141 sym = style->combo.sym_hover;
23142 else if (is_clicked)
23143 sym = style->combo.sym_active;
23144 else sym = style->combo.sym_normal;
23145
23146 /* calculate button */
23147 button.w = header.h - 2 * style->combo.button_padding.y;
23148 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
23149 button.y = header.y + style->combo.button_padding.y;
23150 button.h = button.w;
23151
23152 content.x = button.x + style->combo.button.padding.x;
23153 content.y = button.y + style->combo.button.padding.y;
23154 content.w = button.w - 2 * style->combo.button.padding.x;
23155 content.h = button.h - 2 * style->combo.button.padding.y;
23156
23157 /* draw image */
23158 bounds.h = header.h - 2 * style->combo.content_padding.y;
23159 bounds.y = header.y + style->combo.content_padding.y;
23160 bounds.x = header.x + style->combo.content_padding.x;
23161 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
23162 nk_draw_image(&win->buffer, bounds, &img, nk_white);
23163
23164 /* draw open/close button */
23165 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
23166 &ctx->style.combo.button, sym, style->font);
23167 }
23168 return nk_combo_begin(ctx, win, size, is_clicked, header);
23169 }
23170
23171 NK_API int
23172 nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,
23173 struct nk_image img, struct nk_vec2 size)
23174 {
23175 struct nk_window *win;
23176 struct nk_style *style;
23177 struct nk_input *in;
23178
23179 struct nk_rect header;
23180 int is_clicked = nk_false;
23181 enum nk_widget_layout_states s;
23182 const struct nk_style_item *background;
23183 struct nk_text text;
23184
23185 NK_ASSERT(ctx);
23186 NK_ASSERT(ctx->current);
23187 NK_ASSERT(ctx->current->layout);
23188 if (!ctx || !ctx->current || !ctx->current->layout)
23189 return 0;
23190
23191 win = ctx->current;
23192 style = &ctx->style;
23193 s = nk_widget(&header, ctx);
23194 if (!s) return 0;
23195
23196 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input;
23197 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
23198 is_clicked = nk_true;
23199
23200 /* draw combo box header background and border */
23201 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
23202 background = &style->combo.active;
23203 text.text = style->combo.label_active;
23204 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
23205 background = &style->combo.hover;
23206 text.text = style->combo.label_hover;
23207 } else {
23208 background = &style->combo.normal;
23209 text.text = style->combo.label_normal;
23210 }
23211 if (background->type == NK_STYLE_ITEM_IMAGE) {
23212 text.background = nk_rgba(0,0,0,0);
23213 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
23214 } else {
23215 text.background = background->data.color;
23216 nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color);
23217 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color);
23218 }
23219 {
23220 struct nk_rect content;
23221 struct nk_rect button;
23222 struct nk_rect label;
23223 struct nk_rect image;
23224
23225 enum nk_symbol_type sym;
23226 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
23227 sym = style->combo.sym_hover;
23228 else if (is_clicked)
23229 sym = style->combo.sym_active;
23230 else sym = style->combo.sym_normal;
23231
23232 /* calculate button */
23233 button.w = header.h - 2 * style->combo.button_padding.y;
23234 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
23235 button.y = header.y + style->combo.button_padding.y;
23236 button.h = button.w;
23237
23238 content.x = button.x + style->combo.button.padding.x;
23239 content.y = button.y + style->combo.button.padding.y;
23240 content.w = button.w - 2 * style->combo.button.padding.x;
23241 content.h = button.h - 2 * style->combo.button.padding.y;
23242 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
23243 &ctx->style.combo.button, sym, style->font);
23244
23245 /* draw image */
23246 image.x = header.x + style->combo.content_padding.x;
23247 image.y = header.y + style->combo.content_padding.y;
23248 image.h = header.h - 2 * style->combo.content_padding.y;
23249 image.w = image.h;
23250 nk_draw_image(&win->buffer, image, &img, nk_white);
23251
23252 /* draw label */
23253 text.padding = nk_vec2(0,0);
23254 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
23255 label.y = header.y + style->combo.content_padding.y;
23256 label.w = (button.x - style->combo.content_padding.x) - label.x;
23257 label.h = header.h - 2 * style->combo.content_padding.y;
23258 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
23259 }
23260 return nk_combo_begin(ctx, win, size, is_clicked, header);
23261 }
23262
23263 NK_API int nk_combo_begin_symbol_label(struct nk_context *ctx,
23264 const char *selected, enum nk_symbol_type type, struct nk_vec2 size)
23265 {return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);}
23266
23267 NK_API int nk_combo_begin_image_label(struct nk_context *ctx,
23268 const char *selected, struct nk_image img, struct nk_vec2 size)
23269 {return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);}
23270
23271 NK_API int nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)
23272 {return nk_contextual_item_text(ctx, text, len, align);}
23273
23274 NK_API int nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)
23275 {return nk_contextual_item_label(ctx, label, align);}
23276
23277 NK_API int nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,
23278 int len, nk_flags alignment)
23279 {return nk_contextual_item_image_text(ctx, img, text, len, alignment);}
23280
23281 NK_API int nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,
23282 const char *text, nk_flags alignment)
23283 {return nk_contextual_item_image_label(ctx, img, text, alignment);}
23284
23285 NK_API int nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
23286 const char *text, int len, nk_flags alignment)
23287 {return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);}
23288
23289 NK_API int nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
23290 const char *label, nk_flags alignment)
23291 {return nk_contextual_item_symbol_label(ctx, sym, label, alignment);}
23292
23293 NK_API void nk_combo_end(struct nk_context *ctx)
23294 {nk_contextual_end(ctx);}
23295
23296 NK_API void nk_combo_close(struct nk_context *ctx)
23297 {nk_contextual_close(ctx);}
23298
23299 NK_API int
23300 nk_combo(struct nk_context *ctx, const char **items, int count,
23301 int selected, int item_height, struct nk_vec2 size)
23302 {
23303 int i = 0;
23304 int max_height;
23305 struct nk_vec2 item_spacing;
23306 struct nk_vec2 window_padding;
23307
23308 NK_ASSERT(ctx);
23309 NK_ASSERT(items);
23310 NK_ASSERT(ctx->current);
23311 if (!ctx || !items ||!count)
23312 return selected;
23313
23314 item_spacing = ctx->style.window.spacing;
23315 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
23316 max_height = count * item_height + count * (int)item_spacing.y;
23317 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
23318 size.y = NK_MIN(size.y, (float)max_height);
23319 if (nk_combo_begin_label(ctx, items[selected], size)) {
23320 nk_layout_row_dynamic(ctx, (float)item_height, 1);
23321 for (i = 0; i < count; ++i) {
23322 if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
23323 selected = i;
23324 }
23325 nk_combo_end(ctx);
23326 }
23327 return selected;
23328 }
23329
23330 NK_API int
23331 nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,
23332 int separator, int selected, int count, int item_height, struct nk_vec2 size)
23333 {
23334 int i;
23335 int max_height;
23336 struct nk_vec2 item_spacing;
23337 struct nk_vec2 window_padding;
23338 const char *current_item;
23339 const char *iter;
23340 int length = 0;
23341
23342 NK_ASSERT(ctx);
23343 NK_ASSERT(items_separated_by_separator);
23344 if (!ctx || !items_separated_by_separator)
23345 return selected;
23346
23347 /* calculate popup window */
23348 item_spacing = ctx->style.window.spacing;
23349 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
23350 max_height = count * item_height + count * (int)item_spacing.y;
23351 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
23352 size.y = NK_MIN(size.y, (float)max_height);
23353
23354 /* find selected item */
23355 current_item = items_separated_by_separator;
23356 for (i = 0; i < count; ++i) {
23357 iter = current_item;
23358 while (*iter && *iter != separator) iter++;
23359 length = (int)(iter - current_item);
23360 if (i == selected) break;
23361 current_item = iter + 1;
23362 }
23363
23364 if (nk_combo_begin_text(ctx, current_item, length, size)) {
23365 current_item = items_separated_by_separator;
23366 nk_layout_row_dynamic(ctx, (float)item_height, 1);
23367 for (i = 0; i < count; ++i) {
23368 iter = current_item;
23369 while (*iter && *iter != separator) iter++;
23370 length = (int)(iter - current_item);
23371 if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))
23372 selected = i;
23373 current_item = current_item + length + 1;
23374 }
23375 nk_combo_end(ctx);
23376 }
23377 return selected;
23378 }
23379
23380 NK_API int
23381 nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,
23382 int selected, int count, int item_height, struct nk_vec2 size)
23383 {return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);}
23384
23385 NK_API int
23386 nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),
23387 void *userdata, int selected, int count, int item_height, struct nk_vec2 size)
23388 {
23389 int i;
23390 int max_height;
23391 struct nk_vec2 item_spacing;
23392 struct nk_vec2 window_padding;
23393 const char *item;
23394
23395 NK_ASSERT(ctx);
23396 NK_ASSERT(item_getter);
23397 if (!ctx || !item_getter)
23398 return selected;
23399
23400 /* calculate popup window */
23401 item_spacing = ctx->style.window.spacing;
23402 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
23403 max_height = count * item_height + count * (int)item_spacing.y;
23404 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
23405 size.y = NK_MIN(size.y, (float)max_height);
23406
23407 item_getter(userdata, selected, &item);
23408 if (nk_combo_begin_label(ctx, item, size)) {
23409 nk_layout_row_dynamic(ctx, (float)item_height, 1);
23410 for (i = 0; i < count; ++i) {
23411 item_getter(userdata, i, &item);
23412 if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))
23413 selected = i;
23414 }
23415 nk_combo_end(ctx);
23416 }
23417 return selected;
23418 }
23419
23420 NK_API void nk_combobox(struct nk_context *ctx, const char **items, int count,
23421 int *selected, int item_height, struct nk_vec2 size)
23422 {*selected = nk_combo(ctx, items, count, *selected, item_height, size);}
23423
23424 NK_API void nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,
23425 int *selected, int count, int item_height, struct nk_vec2 size)
23426 {*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);}
23427
23428 NK_API void nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,
23429 int separator,int *selected, int count, int item_height, struct nk_vec2 size)
23430 {*selected = nk_combo_separator(ctx, items_separated_by_separator, separator,
23431 *selected, count, item_height, size);}
23432
23433 NK_API void nk_combobox_callback(struct nk_context *ctx,
23434 void(*item_getter)(void* data, int id, const char **out_text),
23435 void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)
23436 {*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);}
23437
23438 /*
23439 * -------------------------------------------------------------
23440 *
23441 * MENU
23442 *
23443 * --------------------------------------------------------------
23444 */
23445 NK_INTERN int
23446 nk_menu_begin(struct nk_context *ctx, struct nk_window *win,
23447 const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)
23448 {
23449 int is_open = 0;
23450 int is_active = 0;
23451 struct nk_rect body;
23452 struct nk_window *popup;
23453 nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);
23454
23455 NK_ASSERT(ctx);
23456 NK_ASSERT(ctx->current);
23457 NK_ASSERT(ctx->current->layout);
23458 if (!ctx || !ctx->current || !ctx->current->layout)
23459 return 0;
23460
23461 body.x = header.x;
23462 body.w = size.x;
23463 body.y = header.y + header.h;
23464 body.h = size.y;
23465
23466 popup = win->popup.win;
23467 is_open = popup ? nk_true : nk_false;
23468 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);
23469 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
23470 (!is_open && !is_active && !is_clicked)) return 0;
23471 if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))
23472 return 0;
23473
23474 win->popup.type = NK_PANEL_MENU;
23475 win->popup.name = hash;
23476 return 1;
23477 }
23478
23479 NK_API int
23480 nk_menu_begin_text(struct nk_context *ctx, const char *title, int len,
23481 nk_flags align, struct nk_vec2 size)
23482 {
23483 struct nk_window *win;
23484 const struct nk_input *in;
23485 struct nk_rect header;
23486 int is_clicked = nk_false;
23487 nk_flags state;
23488
23489 NK_ASSERT(ctx);
23490 NK_ASSERT(ctx->current);
23491 NK_ASSERT(ctx->current->layout);
23492 if (!ctx || !ctx->current || !ctx->current->layout)
23493 return 0;
23494
23495 win = ctx->current;
23496 state = nk_widget(&header, ctx);
23497 if (!state) return 0;
23498 in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
23499 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,
23500 title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
23501 is_clicked = nk_true;
23502 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
23503 }
23504
23505 NK_API int nk_menu_begin_label(struct nk_context *ctx,
23506 const char *text, nk_flags align, struct nk_vec2 size)
23507 {return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);}
23508
23509 NK_API int
23510 nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,
23511 struct nk_vec2 size)
23512 {
23513 struct nk_window *win;
23514 struct nk_rect header;
23515 const struct nk_input *in;
23516 int is_clicked = nk_false;
23517 nk_flags state;
23518
23519 NK_ASSERT(ctx);
23520 NK_ASSERT(ctx->current);
23521 NK_ASSERT(ctx->current->layout);
23522 if (!ctx || !ctx->current || !ctx->current->layout)
23523 return 0;
23524
23525 win = ctx->current;
23526 state = nk_widget(&header, ctx);
23527 if (!state) return 0;
23528 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
23529 if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,
23530 img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))
23531 is_clicked = nk_true;
23532 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
23533 }
23534
23535 NK_API int
23536 nk_menu_begin_symbol(struct nk_context *ctx, const char *id,
23537 enum nk_symbol_type sym, struct nk_vec2 size)
23538 {
23539 struct nk_window *win;
23540 const struct nk_input *in;
23541 struct nk_rect header;
23542 int is_clicked = nk_false;
23543 nk_flags state;
23544
23545 NK_ASSERT(ctx);
23546 NK_ASSERT(ctx->current);
23547 NK_ASSERT(ctx->current->layout);
23548 if (!ctx || !ctx->current || !ctx->current->layout)
23549 return 0;
23550
23551 win = ctx->current;
23552 state = nk_widget(&header, ctx);
23553 if (!state) return 0;
23554 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
23555 if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header,
23556 sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
23557 is_clicked = nk_true;
23558 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
23559 }
23560
23561 NK_API int
23562 nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,
23563 nk_flags align, struct nk_image img, struct nk_vec2 size)
23564 {
23565 struct nk_window *win;
23566 struct nk_rect header;
23567 const struct nk_input *in;
23568 int is_clicked = nk_false;
23569 nk_flags state;
23570
23571 NK_ASSERT(ctx);
23572 NK_ASSERT(ctx->current);
23573 NK_ASSERT(ctx->current->layout);
23574 if (!ctx || !ctx->current || !ctx->current->layout)
23575 return 0;
23576
23577 win = ctx->current;
23578 state = nk_widget(&header, ctx);
23579 if (!state) return 0;
23580 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
23581 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
23582 header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
23583 ctx->style.font, in))
23584 is_clicked = nk_true;
23585 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
23586 }
23587
23588 NK_API int nk_menu_begin_image_label(struct nk_context *ctx,
23589 const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)
23590 {return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);}
23591
23592 NK_API int
23593 nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,
23594 nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)
23595 {
23596 struct nk_window *win;
23597 struct nk_rect header;
23598 const struct nk_input *in;
23599 int is_clicked = nk_false;
23600 nk_flags state;
23601
23602 NK_ASSERT(ctx);
23603 NK_ASSERT(ctx->current);
23604 NK_ASSERT(ctx->current->layout);
23605 if (!ctx || !ctx->current || !ctx->current->layout)
23606 return 0;
23607
23608 win = ctx->current;
23609 state = nk_widget(&header, ctx);
23610 if (!state) return 0;
23611
23612 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
23613 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,
23614 header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
23615 ctx->style.font, in)) is_clicked = nk_true;
23616 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
23617 }
23618
23619 NK_API int nk_menu_begin_symbol_label(struct nk_context *ctx,
23620 const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )
23621 {return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);}
23622
23623 NK_API int nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)
23624 {return nk_contextual_item_text(ctx, title, len, align);}
23625
23626 NK_API int nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)
23627 {return nk_contextual_item_label(ctx, label, align);}
23628
23629 NK_API int nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,
23630 const char *label, nk_flags align)
23631 {return nk_contextual_item_image_label(ctx, img, label, align);}
23632
23633 NK_API int nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,
23634 const char *text, int len, nk_flags align)
23635 {return nk_contextual_item_image_text(ctx, img, text, len, align);}
23636
23637 NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
23638 const char *text, int len, nk_flags align)
23639 {return nk_contextual_item_symbol_text(ctx, sym, text, len, align);}
23640
23641 NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
23642 const char *label, nk_flags align)
23643 {return nk_contextual_item_symbol_label(ctx, sym, label, align);}
23644
23645 NK_API void nk_menu_close(struct nk_context *ctx)
23646 {nk_contextual_close(ctx);}
23647
23648 NK_API void
23649 nk_menu_end(struct nk_context *ctx)
23650 {nk_contextual_end(ctx);}
23651
23652 #endif /* NK_IMPLEMENTATION */