Vulkan2D
2D renderer written in C using Vulkan and SDL2
Loading...
Searching...
No Matches
nuklear.h
Go to the documentation of this file.
1/*
2# Nuklear
3![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
4
5## Contents
61. About section
72. Highlights section
83. Features section
94. Usage section
10 1. Flags section
11 2. Constants section
12 3. Dependencies section
135. Example section
146. API section
15 1. Context section
16 2. Input section
17 3. Drawing section
18 4. Window section
19 5. Layouting section
20 6. Groups section
21 7. Tree section
22 8. Properties section
237. License section
248. Changelog section
259. Gallery section
2610. Credits section
27
28## About
29This is a minimal state immediate mode graphical user interface toolkit
30written in ANSI C and licensed under public domain. It was designed as a simple
31embeddable user interface for application and does not have any dependencies,
32a default renderbackend or OS window and input handling but instead provides a very modular
33library approach by using simple input state for input and draw
34commands describing primitive shapes as output. So instead of providing a
35layered library that tries to abstract over a number of platform and
36render backends it only focuses on the actual UI.
37
38## Highlights
39- Graphical user interface toolkit
40- Single header library
41- Written in C89 (a.k.a. ANSI C or ISO C90)
42- Small codebase (~18kLOC)
43- Focus on portability, efficiency and simplicity
44- No dependencies (not even the standard library if not wanted)
45- Fully skinnable and customizable
46- Low memory footprint with total memory control if needed or wanted
47- UTF-8 support
48- No global or hidden state
49- Customizable library modules (you can compile and use only what you need)
50- Optional font baker and vertex buffer output
51- [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)
52
53## Features
54- Absolutely no platform dependent code
55- Memory management control ranging from/to
56 - Ease of use by allocating everything from standard library
57 - Control every byte of memory inside the library
58- Font handling control ranging from/to
59 - Use your own font implementation for everything
60 - Use this libraries internal font baking and handling API
61- Drawing output control ranging from/to
62 - Simple shapes for more high level APIs which already have drawing capabilities
63 - Hardware accessible anti-aliased vertex buffer output
64- Customizable colors and properties ranging from/to
65 - Simple changes to color by filling a simple color table
66 - Complete control with ability to use skinning to decorate widgets
67- Bendable UI library with widget ranging from/to
68 - Basic widgets like buttons, checkboxes, slider, ...
69 - Advanced widget like abstract comboboxes, contextual menus,...
70- Compile time configuration to only compile what you need
71 - Subset which can be used if you do not want to link or use the standard library
72- Can be easily modified to only update on user input instead of frame updates
73
74## Usage
75This library is self contained in one single header file and can be used either
76in header only mode or in implementation mode. The header only mode is used
77by default when included and allows including this header in other headers
78and does not contain the actual implementation. <br /><br />
79
80The implementation mode requires to define the preprocessor macro
81NK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:
82
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C
84 #define NK_IMPLEMENTATION
85 #include "nuklear.h"
86~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87
88Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
89below in header and implementation mode if you want to use additional functionality
90or need more control over the library.
91
92!!! WARNING
93 Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.
94
95### Flags
96Flag | Description
97--------------------------------|------------------------------------------
98NK_PRIVATE | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation
99NK_INCLUDE_FIXED_TYPES | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
100NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
101NK_INCLUDE_STANDARD_IO | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
102NK_INCLUDE_STANDARD_VARARGS | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
103NK_INCLUDE_STANDARD_BOOL | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
104NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
105NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
106NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
107NK_INCLUDE_COMMAND_USERDATA | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.
108NK_BUTTON_TRIGGER_ON_RELEASE | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.
109NK_ZERO_COMMAND_MEMORY | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.
110NK_UINT_DRAW_INDEX | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit
111NK_KEYSTATE_BASED_INPUT | Define this if your backend uses key state for each frame rather than key press/release events
112NK_IS_WORD_BOUNDARY(c) | Define this to a function macro that takes a single nk_rune (nk_uint) and returns true if it's a word separator. If not defined, uses the default definition (see nk_is_word_boundary())
113
114!!! WARNING
115 The following flags will pull in the standard C library:
116 - NK_INCLUDE_DEFAULT_ALLOCATOR
117 - NK_INCLUDE_STANDARD_IO
118 - NK_INCLUDE_STANDARD_VARARGS
119
120!!! WARNING
121 The following flags if defined need to be defined for both header and implementation:
122 - NK_INCLUDE_FIXED_TYPES
123 - NK_INCLUDE_DEFAULT_ALLOCATOR
124 - NK_INCLUDE_STANDARD_VARARGS
125 - NK_INCLUDE_STANDARD_BOOL
126 - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
127 - NK_INCLUDE_FONT_BAKING
128 - NK_INCLUDE_DEFAULT_FONT
129 - NK_INCLUDE_STANDARD_VARARGS
130 - NK_INCLUDE_COMMAND_USERDATA
131 - NK_UINT_DRAW_INDEX
132
133### Constants
134Define | Description
135--------------------------------|---------------------------------------
136NK_BUFFER_DEFAULT_INITIAL_SIZE | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.
137NK_MAX_NUMBER_BUFFER | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.
138NK_INPUT_MAX | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.
139
140!!! WARNING
141 The following constants if defined need to be defined for both header and implementation:
142 - NK_MAX_NUMBER_BUFFER
143 - NK_BUFFER_DEFAULT_INITIAL_SIZE
144 - NK_INPUT_MAX
145
146### Dependencies
147Function | Description
148------------|---------------------------------------------------------------
149NK_ASSERT | If you don't define this, nuklear will use <assert.h> with assert().
150NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
151NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
152NK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
153NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
154NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
155NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
156NK_DTOA | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
157NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
158
159!!! WARNING
160 The following dependencies will pull in the standard C library if not redefined:
161 - NK_ASSERT
162
163!!! WARNING
164 The following dependencies if defined need to be defined for both header and implementation:
165 - NK_ASSERT
166
167!!! WARNING
168 The following dependencies if defined need to be defined only for the implementation part:
169 - NK_MEMSET
170 - NK_MEMCPY
171 - NK_SQRT
172 - NK_SIN
173 - NK_COS
174 - NK_STRTOD
175 - NK_DTOA
176 - NK_VSNPRINTF
177
178## Example
179
180~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
181// init gui state
182enum {EASY, HARD};
183static int op = EASY;
184static float value = 0.6f;
185static int i = 20;
186struct nk_context ctx;
187
188nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
189if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
190 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
191 // fixed widget pixel width
192 nk_layout_row_static(&ctx, 30, 80, 1);
193 if (nk_button_label(&ctx, "button")) {
194 // event handling
195 }
196
197 // fixed widget window ratio width
198 nk_layout_row_dynamic(&ctx, 30, 2);
199 if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
200 if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
201
202 // custom widget pixel width
203 nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
204 {
205 nk_layout_row_push(&ctx, 50);
206 nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
207 nk_layout_row_push(&ctx, 110);
208 nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
209 }
210 nk_layout_row_end(&ctx);
211}
212nk_end(&ctx);
213~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214
215![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
216
217## API
218
219*/
220#ifndef NK_SINGLE_FILE
221 #define NK_SINGLE_FILE
222#endif
223
229#ifndef NK_NUKLEAR_H_
230#define NK_NUKLEAR_H_
231
232#ifdef __cplusplus
233extern "C" {
234#endif
235/*
236 * ==============================================================
237 *
238 * CONSTANTS
239 *
240 * ===============================================================
241 */
242
243#define NK_UNDEFINED (-1.0f)
244#define NK_UTF_INVALID 0xFFFD
245#define NK_UTF_SIZE 4
246#ifndef NK_INPUT_MAX
247 #define NK_INPUT_MAX 16
248#endif
249#ifndef NK_MAX_NUMBER_BUFFER
250 #define NK_MAX_NUMBER_BUFFER 64
251#endif
252#ifndef NK_SCROLLBAR_HIDING_TIMEOUT
253 #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f
254#endif
255/*
256 * ==============================================================
257 *
258 * HELPER
259 *
260 * ===============================================================
261 */
262
263#ifndef NK_API
264 #ifdef NK_PRIVATE
265 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L))
266 #define NK_API static inline
267 #elif defined(__cplusplus)
268 #define NK_API static inline
269 #else
270 #define NK_API static
271 #endif
272 #else
273 #define NK_API extern
274 #endif
275#endif
276#ifndef NK_LIB
277 #ifdef NK_SINGLE_FILE
278 #define NK_LIB static
279 #else
280 #define NK_LIB extern
281 #endif
282#endif
283
284#define NK_INTERN static
285#define NK_STORAGE static
286#define NK_GLOBAL static
287
288#define NK_FLAG(x) (1 << (x))
289#define NK_STRINGIFY(x) #x
290#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x)
291#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2
292#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2)
293#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2)
294
295#ifdef _MSC_VER
296 #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__)
297#else
298 #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__)
299#endif
300
301#ifndef NK_STATIC_ASSERT
302 #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1]
303#endif
304
305#ifndef NK_FILE_LINE
306#ifdef _MSC_VER
307 #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__)
308#else
309 #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__)
310#endif
311#endif
312
313#define NK_MIN(a,b) ((a) < (b) ? (a) : (b))
314#define NK_MAX(a,b) ((a) < (b) ? (b) : (a))
315#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i))
316
317#ifdef NK_INCLUDE_STANDARD_VARARGS
318 #include <stdarg.h>
319 #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */
320 #include <sal.h>
321 #define NK_PRINTF_FORMAT_STRING _Printf_format_string_
322 #else
323 #define NK_PRINTF_FORMAT_STRING
324 #endif
325 #if defined(__GNUC__)
326 #define NK_PRINTF_VARARG_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, fmtargnumber+1)))
327 #define NK_PRINTF_VALIST_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, 0)))
328 #else
329 #define NK_PRINTF_VARARG_FUNC(fmtargnumber)
330 #define NK_PRINTF_VALIST_FUNC(fmtargnumber)
331 #endif
332#endif
333
334/*
335 * ===============================================================
336 *
337 * BASIC
338 *
339 * ===============================================================
340 */
341 #ifdef NK_INCLUDE_FIXED_TYPES
342 #include <stdint.h>
343 #define NK_INT8 int8_t
344 #define NK_UINT8 uint8_t
345 #define NK_INT16 int16_t
346 #define NK_UINT16 uint16_t
347 #define NK_INT32 int32_t
348 #define NK_UINT32 uint32_t
349 #define NK_SIZE_TYPE uintptr_t
350 #define NK_POINTER_TYPE uintptr_t
351#else
352 #ifndef NK_INT8
353 #define NK_INT8 signed char
354 #endif
355 #ifndef NK_UINT8
356 #define NK_UINT8 unsigned char
357 #endif
358 #ifndef NK_INT16
359 #define NK_INT16 signed short
360 #endif
361 #ifndef NK_UINT16
362 #define NK_UINT16 unsigned short
363 #endif
364 #ifndef NK_INT32
365 #if defined(_MSC_VER)
366 #define NK_INT32 __int32
367 #else
368 #define NK_INT32 signed int
369 #endif
370 #endif
371 #ifndef NK_UINT32
372 #if defined(_MSC_VER)
373 #define NK_UINT32 unsigned __int32
374 #else
375 #define NK_UINT32 unsigned int
376 #endif
377 #endif
378 #ifndef NK_SIZE_TYPE
379 #if defined(_WIN64) && defined(_MSC_VER)
380 #define NK_SIZE_TYPE unsigned __int64
381 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
382 #define NK_SIZE_TYPE unsigned __int32
383 #elif defined(__GNUC__) || defined(__clang__)
384 #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)
385 #define NK_SIZE_TYPE unsigned long
386 #else
387 #define NK_SIZE_TYPE unsigned int
388 #endif
389 #else
390 #define NK_SIZE_TYPE unsigned long
391 #endif
392 #endif
393 #ifndef NK_POINTER_TYPE
394 #if defined(_WIN64) && defined(_MSC_VER)
395 #define NK_POINTER_TYPE unsigned __int64
396 #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
397 #define NK_POINTER_TYPE unsigned __int32
398 #elif defined(__GNUC__) || defined(__clang__)
399 #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)
400 #define NK_POINTER_TYPE unsigned long
401 #else
402 #define NK_POINTER_TYPE unsigned int
403 #endif
404 #else
405 #define NK_POINTER_TYPE unsigned long
406 #endif
407 #endif
408#endif
409
410#ifndef NK_BOOL
411 #ifdef NK_INCLUDE_STANDARD_BOOL
412 #include <stdbool.h>
413 #define NK_BOOL bool
414 #else
415 #define NK_BOOL int
416 #endif
417#endif
418
419typedef NK_INT8 nk_char;
420typedef NK_UINT8 nk_uchar;
421typedef NK_UINT8 nk_byte;
422typedef NK_INT16 nk_short;
423typedef NK_UINT16 nk_ushort;
424typedef NK_INT32 nk_int;
425typedef NK_UINT32 nk_uint;
426typedef NK_SIZE_TYPE nk_size;
427typedef NK_POINTER_TYPE nk_ptr;
428typedef NK_BOOL nk_bool;
429
430typedef nk_uint nk_hash;
431typedef nk_uint nk_flags;
432typedef nk_uint nk_rune;
433
434/* Make sure correct type size:
435 * This will fire with a negative subscript error if the type sizes
436 * are set incorrectly by the compiler, and compile out if not */
437NK_STATIC_ASSERT(sizeof(nk_short) == 2);
438NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
439NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
440NK_STATIC_ASSERT(sizeof(nk_int) == 4);
441NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
442NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
443NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
444NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
445NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*));
446#ifdef NK_INCLUDE_STANDARD_BOOL
447NK_STATIC_ASSERT(sizeof(nk_bool) == sizeof(bool));
448#else
449NK_STATIC_ASSERT(sizeof(nk_bool) >= 2);
450#endif
451
452/* ============================================================================
453 *
454 * API
455 *
456 * =========================================================================== */
457struct nk_buffer;
458struct nk_allocator;
459struct nk_command_buffer;
460struct nk_draw_command;
461struct nk_convert_config;
462struct nk_style_item;
463struct nk_text_edit;
464struct nk_draw_list;
465struct nk_user_font;
466struct nk_panel;
467struct nk_context;
468struct nk_draw_vertex_layout_element;
469struct nk_style_button;
470struct nk_style_toggle;
472struct nk_style_slide;
473struct nk_style_progress;
474struct nk_style_scrollbar;
475struct nk_style_edit;
476struct nk_style_property;
477struct nk_style_chart;
478struct nk_style_combo;
479struct nk_style_tab;
481struct nk_style_window;
482
483enum {nk_false, nk_true};
484struct nk_color {nk_byte r,g,b,a;};
485struct nk_colorf {float r,g,b,a;};
486struct nk_vec2 {float x,y;};
487struct nk_vec2i {short x, y;};
488struct nk_rect {float x,y,w,h;};
489struct nk_recti {short x,y,w,h;};
490typedef char nk_glyph[NK_UTF_SIZE];
491typedef union {void *ptr; int id;} nk_handle;
492struct nk_image {nk_handle handle; nk_ushort w, h; nk_ushort region[4];};
493struct nk_nine_slice {struct nk_image img; nk_ushort l, t, r, b;};
494struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};
495struct nk_scroll {nk_uint x, y;};
496
497enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT};
498enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER};
499enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true};
500enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL};
501enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true};
502enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true};
503enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX};
504enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02};
505enum nk_color_format {NK_RGB, NK_RGBA};
506enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};
507enum nk_layout_format {NK_DYNAMIC, NK_STATIC};
508enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB};
509
510typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);
511typedef void (*nk_plugin_free)(nk_handle, void *old);
512typedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);
513typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*);
514typedef void(*nk_plugin_copy)(nk_handle, const char*, int len);
515
517 nk_handle userdata;
518 nk_plugin_alloc alloc;
519 nk_plugin_free free;
520};
521enum nk_symbol_type {
522 NK_SYMBOL_NONE,
523 NK_SYMBOL_X,
524 NK_SYMBOL_UNDERSCORE,
525 NK_SYMBOL_CIRCLE_SOLID,
526 NK_SYMBOL_CIRCLE_OUTLINE,
527 NK_SYMBOL_RECT_SOLID,
528 NK_SYMBOL_RECT_OUTLINE,
529 NK_SYMBOL_TRIANGLE_UP,
530 NK_SYMBOL_TRIANGLE_DOWN,
531 NK_SYMBOL_TRIANGLE_LEFT,
532 NK_SYMBOL_TRIANGLE_RIGHT,
533 NK_SYMBOL_PLUS,
534 NK_SYMBOL_MINUS,
535 NK_SYMBOL_TRIANGLE_UP_OUTLINE,
536 NK_SYMBOL_TRIANGLE_DOWN_OUTLINE,
537 NK_SYMBOL_TRIANGLE_LEFT_OUTLINE,
538 NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE,
539 NK_SYMBOL_MAX
540};
541/* =============================================================================
542 *
543 * CONTEXT
544 *
545 * =============================================================================*/
581#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
582
599NK_API nk_bool nk_init_default(struct nk_context*, const struct nk_user_font*);
600#endif
625NK_API nk_bool nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*);
626
645NK_API nk_bool nk_init(struct nk_context*, const struct nk_allocator*, const struct nk_user_font*);
646
665NK_API nk_bool nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*);
666
680NK_API void nk_clear(struct nk_context*);
681
692NK_API void nk_free(struct nk_context*);
693
694#ifdef NK_INCLUDE_COMMAND_USERDATA
706NK_API void nk_set_user_data(struct nk_context*, nk_handle handle);
707#endif
708/* =============================================================================
709 *
710 * INPUT
711 *
712 * =============================================================================*/
777enum nk_keys {
778 NK_KEY_NONE,
779 NK_KEY_SHIFT,
780 NK_KEY_CTRL,
781 NK_KEY_DEL,
782 NK_KEY_ENTER,
783 NK_KEY_TAB,
784 NK_KEY_BACKSPACE,
785 NK_KEY_COPY,
786 NK_KEY_CUT,
787 NK_KEY_PASTE,
788 NK_KEY_UP,
789 NK_KEY_DOWN,
790 NK_KEY_LEFT,
791 NK_KEY_RIGHT,
792 /* Shortcuts: text field */
793 NK_KEY_TEXT_INSERT_MODE,
794 NK_KEY_TEXT_REPLACE_MODE,
795 NK_KEY_TEXT_RESET_MODE,
796 NK_KEY_TEXT_LINE_START,
797 NK_KEY_TEXT_LINE_END,
798 NK_KEY_TEXT_START,
799 NK_KEY_TEXT_END,
800 NK_KEY_TEXT_UNDO,
801 NK_KEY_TEXT_REDO,
802 NK_KEY_TEXT_SELECT_ALL,
803 NK_KEY_TEXT_WORD_LEFT,
804 NK_KEY_TEXT_WORD_RIGHT,
805 /* Shortcuts: scrollbar */
806 NK_KEY_SCROLL_START,
807 NK_KEY_SCROLL_END,
808 NK_KEY_SCROLL_DOWN,
809 NK_KEY_SCROLL_UP,
810 NK_KEY_MAX
811};
812enum nk_buttons {
813 NK_BUTTON_LEFT,
814 NK_BUTTON_MIDDLE,
815 NK_BUTTON_RIGHT,
816 NK_BUTTON_DOUBLE,
817 NK_BUTTON_MAX
818};
819
831NK_API void nk_input_begin(struct nk_context*);
832
845NK_API void nk_input_motion(struct nk_context*, int x, int y);
846
859NK_API void nk_input_key(struct nk_context*, enum nk_keys, nk_bool down);
860
875NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, nk_bool down);
876
891NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val);
892
910NK_API void nk_input_char(struct nk_context*, char);
911
926NK_API void nk_input_glyph(struct nk_context*, const nk_glyph);
927
943NK_API void nk_input_unicode(struct nk_context*, nk_rune);
944
956NK_API void nk_input_end(struct nk_context*);
957
1189enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON};
1190enum nk_convert_result {
1191 NK_CONVERT_SUCCESS = 0,
1192 NK_CONVERT_INVALID_PARAM = 1,
1193 NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1),
1194 NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2),
1195 NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3)
1196};
1198 nk_handle texture;
1199 struct nk_vec2 uv;
1200};
1202 float global_alpha;
1203 enum nk_anti_aliasing line_AA;
1204 enum nk_anti_aliasing shape_AA;
1209 const struct nk_draw_vertex_layout_element *vertex_layout;
1210 nk_size vertex_size;
1212};
1213
1227NK_API const struct nk_command* nk__begin(struct nk_context*);
1228
1242NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);
1243
1254#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c))
1255
1256#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
1257
1287NK_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*);
1288
1302NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);
1303
1321NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*);
1322
1340NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);
1341
1357#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx))
1358#endif
1359
1507enum nk_panel_flags {
1508 NK_WINDOW_BORDER = NK_FLAG(0),
1509 NK_WINDOW_MOVABLE = NK_FLAG(1),
1510 NK_WINDOW_SCALABLE = NK_FLAG(2),
1511 NK_WINDOW_CLOSABLE = NK_FLAG(3),
1512 NK_WINDOW_MINIMIZABLE = NK_FLAG(4),
1513 NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5),
1514 NK_WINDOW_TITLE = NK_FLAG(6),
1515 NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7),
1516 NK_WINDOW_BACKGROUND = NK_FLAG(8),
1517 NK_WINDOW_SCALE_LEFT = NK_FLAG(9),
1518 NK_WINDOW_NO_INPUT = NK_FLAG(10)
1519};
1520
1541NK_API nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
1542
1564NK_API nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
1565
1580NK_API void nk_end(struct nk_context *ctx);
1581
1598NK_API struct nk_window *nk_window_find(const struct nk_context *ctx, const char *name);
1599
1617NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);
1618
1636NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);
1637
1655NK_API struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);
1656
1673NK_API float nk_window_get_width(const struct nk_context *ctx);
1674
1692NK_API float nk_window_get_height(const struct nk_context* ctx);
1693
1713NK_API struct nk_panel* nk_window_get_panel(const struct nk_context* ctx);
1714
1735NK_API struct nk_rect nk_window_get_content_region(const struct nk_context* ctx);
1736
1757NK_API struct nk_vec2 nk_window_get_content_region_min(const struct nk_context *ctx);
1758
1779NK_API struct nk_vec2 nk_window_get_content_region_max(const struct nk_context *ctx);
1780
1801
1821NK_API struct nk_command_buffer* nk_window_get_canvas(const struct nk_context* ctx);
1822
1840NK_API void nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);
1841
1858NK_API nk_bool nk_window_has_focus(const struct nk_context *ctx);
1859
1876NK_API nk_bool nk_window_is_hovered(const struct nk_context *ctx);
1877
1894NK_API nk_bool nk_window_is_collapsed(const struct nk_context *ctx, const char *name);
1895
1911NK_API nk_bool nk_window_is_closed(const struct nk_context *ctx, const char* name);
1912
1928NK_API nk_bool nk_window_is_hidden(const struct nk_context *ctx, const char* name);
1929
1944NK_API nk_bool nk_window_is_active(const struct nk_context *ctx, const char* name);
1945
1959NK_API nk_bool nk_window_is_any_hovered(const struct nk_context *ctx);
1960
1977NK_API nk_bool nk_item_is_any_active(const struct nk_context *ctx);
1978
1993NK_API void nk_window_set_bounds(struct nk_context *ctx, const char *name, struct nk_rect bounds);
1994
2009NK_API void nk_window_set_position(struct nk_context *ctx, const char *name, struct nk_vec2 pos);
2010
2025NK_API void nk_window_set_size(struct nk_context *ctx, const char *name, struct nk_vec2 size);
2026
2040NK_API void nk_window_set_focus(struct nk_context *ctx, const char *name);
2041
2059NK_API void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);
2060
2074NK_API void nk_window_close(struct nk_context *ctx, const char *name);
2075
2090NK_API void nk_window_collapse(struct nk_context *ctx, const char *name, enum nk_collapse_states state);
2091
2107NK_API void nk_window_collapse_if(struct nk_context *ctx, const char *name, enum nk_collapse_states state, int cond);
2108
2122NK_API void nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states state);
2123
2139NK_API void nk_window_show_if(struct nk_context *ctx, const char *name, enum nk_show_states state, int cond);
2140
2154NK_API void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding);
2155
2156/* =============================================================================
2157 *
2158 * LAYOUT
2159 *
2160 * =============================================================================*/
2429enum nk_widget_align {
2430 NK_WIDGET_ALIGN_LEFT = 0x01,
2431 NK_WIDGET_ALIGN_CENTERED = 0x02,
2432 NK_WIDGET_ALIGN_RIGHT = 0x04,
2433 NK_WIDGET_ALIGN_TOP = 0x08,
2434 NK_WIDGET_ALIGN_MIDDLE = 0x10,
2435 NK_WIDGET_ALIGN_BOTTOM = 0x20
2436};
2437enum nk_widget_alignment {
2438 NK_WIDGET_LEFT = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_LEFT,
2439 NK_WIDGET_CENTERED = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_CENTERED,
2440 NK_WIDGET_RIGHT = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_RIGHT
2441};
2442
2456NK_API void nk_layout_set_min_row_height(struct nk_context*, float height);
2457
2467
2480NK_API struct nk_rect nk_layout_widget_bounds(const struct nk_context *ctx);
2481
2495NK_API float nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width);
2496
2511NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);
2512
2528NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);
2529
2543NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);
2544
2556NK_API void nk_layout_row_push(struct nk_context*, float value);
2557
2568NK_API void nk_layout_row_end(struct nk_context*);
2569
2583NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);
2584
2597NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height);
2598
2612
2625NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width);
2626
2639NK_API void nk_layout_row_template_push_static(struct nk_context*, float width);
2640
2653
2668NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);
2669
2682NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect bounds);
2683
2695NK_API void nk_layout_space_end(struct nk_context*);
2696
2710NK_API struct nk_rect nk_layout_space_bounds(const struct nk_context *ctx);
2711
2726NK_API struct nk_vec2 nk_layout_space_to_screen(const struct nk_context* ctx, struct nk_vec2 vec);
2727
2742NK_API struct nk_vec2 nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 vec);
2743
2758NK_API struct nk_rect nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect bounds);
2759
2774NK_API struct nk_rect nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect bounds);
2775
2788NK_API void nk_spacer(struct nk_context *ctx);
2789
2790
2895NK_API nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);
2896
2910NK_API nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);
2911
2923NK_API void nk_group_end(struct nk_context*);
2924
2943NK_API nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);
2944
2962NK_API nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);
2963
2976
2991NK_API void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);
2992
3007NK_API void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);
3008
3102#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__)
3103
3121#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)
3122
3143NK_API nk_bool 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);
3144
3167#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__)
3168
3189#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)
3190
3212NK_API nk_bool 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);
3213
3225NK_API void nk_tree_pop(struct nk_context*);
3226
3243NK_API nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
3244
3262NK_API nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
3263
3275NK_API void nk_tree_state_pop(struct nk_context*);
3276
3277#define nk_tree_element_push(ctx, type, title, state, sel) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)
3278#define nk_tree_element_push_id(ctx, type, title, state, sel, id) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)
3279NK_API nk_bool nk_tree_element_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len, int seed);
3280NK_API nk_bool nk_tree_element_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len,int seed);
3281NK_API void nk_tree_element_pop(struct nk_context*);
3282
3283/* =============================================================================
3284 *
3285 * LIST VIEW
3286 *
3287 * ============================================================================= */
3289/* public: */
3290 int begin, end, count;
3291/* private: */
3292 int total_height;
3293 struct nk_context *ctx;
3294 nk_uint *scroll_pointer;
3295 nk_uint scroll_value;
3296};
3297NK_API nk_bool nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count);
3298NK_API void nk_list_view_end(struct nk_list_view*);
3299/* =============================================================================
3300 *
3301 * WIDGET
3302 *
3303 * ============================================================================= */
3311 NK_WIDGET_STATE_MODIFIED = NK_FLAG(1),
3312 NK_WIDGET_STATE_INACTIVE = NK_FLAG(2),
3318 NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED
3320NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*);
3321NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, const struct nk_context*, struct nk_vec2);
3322NK_API struct nk_rect nk_widget_bounds(const struct nk_context*);
3323NK_API struct nk_vec2 nk_widget_position(const struct nk_context*);
3324NK_API struct nk_vec2 nk_widget_size(const struct nk_context*);
3325NK_API float nk_widget_width(const struct nk_context*);
3326NK_API float nk_widget_height(const struct nk_context*);
3327NK_API nk_bool nk_widget_is_hovered(const struct nk_context*);
3328NK_API nk_bool nk_widget_is_mouse_clicked(const struct nk_context*, enum nk_buttons);
3329NK_API nk_bool nk_widget_has_mouse_click_down(const struct nk_context*, enum nk_buttons, nk_bool down);
3330NK_API void nk_spacing(struct nk_context*, int cols);
3331NK_API void nk_widget_disable_begin(struct nk_context* ctx);
3332NK_API void nk_widget_disable_end(struct nk_context* ctx);
3333/* =============================================================================
3334 *
3335 * TEXT
3336 *
3337 * ============================================================================= */
3338enum nk_text_align {
3339 NK_TEXT_ALIGN_LEFT = 0x01,
3340 NK_TEXT_ALIGN_CENTERED = 0x02,
3341 NK_TEXT_ALIGN_RIGHT = 0x04,
3342 NK_TEXT_ALIGN_TOP = 0x08,
3343 NK_TEXT_ALIGN_MIDDLE = 0x10,
3344 NK_TEXT_ALIGN_BOTTOM = 0x20
3345};
3346enum nk_text_alignment {
3347 NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT,
3348 NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED,
3349 NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT
3350};
3351NK_API void nk_text(struct nk_context*, const char*, int, nk_flags);
3352NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color);
3353NK_API void nk_text_wrap(struct nk_context*, const char*, int);
3354NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color);
3355NK_API void nk_label(struct nk_context*, const char*, nk_flags align);
3356NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color);
3357NK_API void nk_label_wrap(struct nk_context*, const char*);
3358NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color);
3359NK_API void nk_image(struct nk_context*, struct nk_image);
3360NK_API void nk_image_color(struct nk_context*, struct nk_image, struct nk_color);
3361#ifdef NK_INCLUDE_STANDARD_VARARGS
3362NK_API void nk_labelf(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(3);
3363NK_API void nk_labelf_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(4);
3364NK_API void nk_labelf_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(2);
3365NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(3);
3366NK_API void nk_labelfv(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);
3367NK_API void nk_labelfv_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4);
3368NK_API void nk_labelfv_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);
3369NK_API void nk_labelfv_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);
3370NK_API void nk_value_bool(struct nk_context*, const char *prefix, int);
3371NK_API void nk_value_int(struct nk_context*, const char *prefix, int);
3372NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int);
3373NK_API void nk_value_float(struct nk_context*, const char *prefix, float);
3374NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color);
3375NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color);
3376NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color);
3377#endif
3378/* =============================================================================
3379 *
3380 * BUTTON
3381 *
3382 * ============================================================================= */
3383NK_API nk_bool nk_button_text(struct nk_context*, const char *title, int len);
3384NK_API nk_bool nk_button_label(struct nk_context*, const char *title);
3385NK_API nk_bool nk_button_color(struct nk_context*, struct nk_color);
3386NK_API nk_bool nk_button_symbol(struct nk_context*, enum nk_symbol_type);
3387NK_API nk_bool nk_button_image(struct nk_context*, struct nk_image img);
3388NK_API nk_bool nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment);
3389NK_API nk_bool nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
3390NK_API nk_bool nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment);
3391NK_API nk_bool nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment);
3392NK_API nk_bool nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len);
3393NK_API nk_bool nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title);
3394NK_API nk_bool nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type);
3395NK_API nk_bool nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img);
3396NK_API nk_bool nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment);
3397NK_API nk_bool 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);
3398NK_API nk_bool nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment);
3399NK_API nk_bool nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment);
3400NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior);
3401NK_API nk_bool nk_button_push_behavior(struct nk_context*, enum nk_button_behavior);
3402NK_API nk_bool nk_button_pop_behavior(struct nk_context*);
3403/* =============================================================================
3404 *
3405 * CHECKBOX
3406 *
3407 * ============================================================================= */
3408NK_API nk_bool nk_check_label(struct nk_context*, const char*, nk_bool active);
3409NK_API nk_bool nk_check_text(struct nk_context*, const char*, int, nk_bool active);
3410NK_API nk_bool nk_check_text_align(struct nk_context*, const char*, int, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);
3411NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value);
3412NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value);
3413NK_API nk_bool nk_checkbox_label(struct nk_context*, const char*, nk_bool *active);
3414NK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);
3415NK_API nk_bool nk_checkbox_text(struct nk_context*, const char*, int, nk_bool *active);
3416NK_API nk_bool nk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);
3417NK_API nk_bool nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value);
3418NK_API nk_bool nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value);
3419/* =============================================================================
3420 *
3421 * RADIO BUTTON
3422 *
3423 * ============================================================================= */
3424NK_API nk_bool nk_radio_label(struct nk_context*, const char*, nk_bool *active);
3425NK_API nk_bool nk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);
3426NK_API nk_bool nk_radio_text(struct nk_context*, const char*, int, nk_bool *active);
3427NK_API nk_bool nk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);
3428NK_API nk_bool nk_option_label(struct nk_context*, const char*, nk_bool active);
3429NK_API nk_bool nk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);
3430NK_API nk_bool nk_option_text(struct nk_context*, const char*, int, nk_bool active);
3431NK_API nk_bool nk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment);
3432/* =============================================================================
3433 *
3434 * SELECTABLE
3435 *
3436 * ============================================================================= */
3437NK_API nk_bool nk_selectable_label(struct nk_context*, const char*, nk_flags align, nk_bool *value);
3438NK_API nk_bool nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, nk_bool *value);
3439NK_API nk_bool nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, nk_bool *value);
3440NK_API nk_bool nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, nk_bool *value);
3441NK_API nk_bool nk_selectable_symbol_label(struct nk_context*,enum nk_symbol_type, const char*, nk_flags align, nk_bool *value);
3442NK_API nk_bool nk_selectable_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool *value);
3443
3444NK_API nk_bool nk_select_label(struct nk_context*, const char*, nk_flags align, nk_bool value);
3445NK_API nk_bool nk_select_text(struct nk_context*, const char*, int, nk_flags align, nk_bool value);
3446NK_API nk_bool nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, nk_bool value);
3447NK_API nk_bool nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, nk_bool value);
3448NK_API nk_bool nk_select_symbol_label(struct nk_context*,enum nk_symbol_type, const char*, nk_flags align, nk_bool value);
3449NK_API nk_bool nk_select_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool value);
3450
3451/* =============================================================================
3452 *
3453 * SLIDER
3454 *
3455 * ============================================================================= */
3456NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step);
3457NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step);
3458NK_API nk_bool nk_slider_float(struct nk_context*, float min, float *val, float max, float step);
3459NK_API nk_bool nk_slider_int(struct nk_context*, int min, int *val, int max, int step);
3460
3461/* =============================================================================
3462 *
3463 * KNOB
3464 *
3465 * ============================================================================= */
3466NK_API nk_bool nk_knob_float(struct nk_context*, float min, float *val, float max, float step, enum nk_heading zero_direction, float dead_zone_degrees);
3467NK_API nk_bool nk_knob_int(struct nk_context*, int min, int *val, int max, int step, enum nk_heading zero_direction, float dead_zone_degrees);
3468
3469/* =============================================================================
3470 *
3471 * PROGRESSBAR
3472 *
3473 * ============================================================================= */
3474NK_API nk_bool nk_progress(struct nk_context*, nk_size *cur, nk_size max, nk_bool modifyable);
3475NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, nk_bool modifyable);
3476
3477/* =============================================================================
3478 *
3479 * COLOR PICKER
3480 *
3481 * ============================================================================= */
3482NK_API struct nk_colorf nk_color_picker(struct nk_context*, struct nk_colorf, enum nk_color_format);
3483NK_API nk_bool nk_color_pick(struct nk_context*, struct nk_colorf*, enum nk_color_format);
3484/* =============================================================================
3485 *
3486 * PROPERTIES
3487 *
3488 * =============================================================================*/
3581NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel);
3582
3604NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel);
3605
3627NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel);
3628
3650NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel);
3651
3673NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel);
3674
3696NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel);
3697
3698/* =============================================================================
3699 *
3700 * TEXT EDIT
3701 *
3702 * ============================================================================= */
3703enum nk_edit_flags {
3704 NK_EDIT_DEFAULT = 0,
3705 NK_EDIT_READ_ONLY = NK_FLAG(0),
3706 NK_EDIT_AUTO_SELECT = NK_FLAG(1),
3707 NK_EDIT_SIG_ENTER = NK_FLAG(2),
3708 NK_EDIT_ALLOW_TAB = NK_FLAG(3),
3709 NK_EDIT_NO_CURSOR = NK_FLAG(4),
3710 NK_EDIT_SELECTABLE = NK_FLAG(5),
3711 NK_EDIT_CLIPBOARD = NK_FLAG(6),
3712 NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7),
3713 NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8),
3714 NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9),
3715 NK_EDIT_MULTILINE = NK_FLAG(10),
3716 NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11)
3717};
3718enum nk_edit_types {
3719 NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE,
3720 NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD,
3721 NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD,
3722 NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD
3723};
3725 NK_EDIT_ACTIVE = NK_FLAG(0),
3726 NK_EDIT_INACTIVE = NK_FLAG(1),
3727 NK_EDIT_ACTIVATED = NK_FLAG(2),
3728 NK_EDIT_DEACTIVATED = NK_FLAG(3),
3729 NK_EDIT_COMMITED = NK_FLAG(4)
3731NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);
3732NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);
3733NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
3734NK_API void nk_edit_focus(struct nk_context*, nk_flags flags);
3735NK_API void nk_edit_unfocus(struct nk_context*);
3736/* =============================================================================
3737 *
3738 * CHART
3739 *
3740 * ============================================================================= */
3741NK_API nk_bool nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max);
3742NK_API nk_bool nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max);
3743NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value);
3744NK_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);
3745NK_API nk_flags nk_chart_push(struct nk_context*, float);
3746NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int);
3747NK_API void nk_chart_end(struct nk_context*);
3748NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset);
3749NK_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);
3750/* =============================================================================
3751 *
3752 * POPUP
3753 *
3754 * ============================================================================= */
3755NK_API nk_bool nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds);
3756NK_API void nk_popup_close(struct nk_context*);
3757NK_API void nk_popup_end(struct nk_context*);
3758NK_API void nk_popup_get_scroll(const struct nk_context*, nk_uint *offset_x, nk_uint *offset_y);
3759NK_API void nk_popup_set_scroll(struct nk_context*, nk_uint offset_x, nk_uint offset_y);
3760/* =============================================================================
3761 *
3762 * COMBOBOX
3763 *
3764 * ============================================================================= */
3765NK_API int nk_combo(struct nk_context*, const char *const *items, int count, int selected, int item_height, struct nk_vec2 size);
3766NK_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);
3767NK_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);
3768NK_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);
3769NK_API void nk_combobox(struct nk_context*, const char *const *items, int count, int *selected, int item_height, struct nk_vec2 size);
3770NK_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);
3771NK_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);
3772NK_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);
3773/* =============================================================================
3774 *
3775 * ABSTRACT COMBOBOX
3776 *
3777 * ============================================================================= */
3778NK_API nk_bool nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size);
3779NK_API nk_bool nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size);
3780NK_API nk_bool nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size);
3781NK_API nk_bool nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size);
3782NK_API nk_bool nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size);
3783NK_API nk_bool nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size);
3784NK_API nk_bool nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size);
3785NK_API nk_bool nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size);
3786NK_API nk_bool nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size);
3787NK_API nk_bool nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment);
3788NK_API nk_bool nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment);
3789NK_API nk_bool nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
3790NK_API nk_bool nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment);
3791NK_API nk_bool nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
3792NK_API nk_bool nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
3793NK_API void nk_combo_close(struct nk_context*);
3794NK_API void nk_combo_end(struct nk_context*);
3795/* =============================================================================
3796 *
3797 * CONTEXTUAL
3798 *
3799 * ============================================================================= */
3800NK_API nk_bool nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds);
3801NK_API nk_bool nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align);
3802NK_API nk_bool nk_contextual_item_label(struct nk_context*, const char*, nk_flags align);
3803NK_API nk_bool nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
3804NK_API nk_bool nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
3805NK_API nk_bool nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
3806NK_API nk_bool nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
3807NK_API void nk_contextual_close(struct nk_context*);
3808NK_API void nk_contextual_end(struct nk_context*);
3809/* =============================================================================
3810 *
3811 * TOOLTIP
3812 *
3813 * ============================================================================= */
3814NK_API void nk_tooltip(struct nk_context*, const char*);
3815#ifdef NK_INCLUDE_STANDARD_VARARGS
3816NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2);
3817NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);
3818#endif
3819NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width);
3820NK_API void nk_tooltip_end(struct nk_context*);
3821/* =============================================================================
3822 *
3823 * MENU
3824 *
3825 * ============================================================================= */
3826NK_API void nk_menubar_begin(struct nk_context*);
3827NK_API void nk_menubar_end(struct nk_context*);
3828NK_API nk_bool nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size);
3829NK_API nk_bool nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size);
3830NK_API nk_bool nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size);
3831NK_API nk_bool nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size);
3832NK_API nk_bool nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size);
3833NK_API nk_bool nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size);
3834NK_API nk_bool nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
3835NK_API nk_bool nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size);
3836NK_API nk_bool nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align);
3837NK_API nk_bool nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment);
3838NK_API nk_bool nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);
3839NK_API nk_bool nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);
3840NK_API nk_bool nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);
3841NK_API nk_bool nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);
3842NK_API void nk_menu_close(struct nk_context*);
3843NK_API void nk_menu_end(struct nk_context*);
3844/* =============================================================================
3845 *
3846 * STYLE
3847 *
3848 * ============================================================================= */
3849
3850#define NK_WIDGET_DISABLED_FACTOR 0.5f
3851
3852enum nk_style_colors {
3853 NK_COLOR_TEXT,
3854 NK_COLOR_WINDOW,
3855 NK_COLOR_HEADER,
3856 NK_COLOR_BORDER,
3857 NK_COLOR_BUTTON,
3858 NK_COLOR_BUTTON_HOVER,
3859 NK_COLOR_BUTTON_ACTIVE,
3860 NK_COLOR_TOGGLE,
3861 NK_COLOR_TOGGLE_HOVER,
3862 NK_COLOR_TOGGLE_CURSOR,
3863 NK_COLOR_SELECT,
3864 NK_COLOR_SELECT_ACTIVE,
3865 NK_COLOR_SLIDER,
3866 NK_COLOR_SLIDER_CURSOR,
3867 NK_COLOR_SLIDER_CURSOR_HOVER,
3868 NK_COLOR_SLIDER_CURSOR_ACTIVE,
3869 NK_COLOR_PROPERTY,
3870 NK_COLOR_EDIT,
3871 NK_COLOR_EDIT_CURSOR,
3872 NK_COLOR_COMBO,
3873 NK_COLOR_CHART,
3874 NK_COLOR_CHART_COLOR,
3875 NK_COLOR_CHART_COLOR_HIGHLIGHT,
3876 NK_COLOR_SCROLLBAR,
3877 NK_COLOR_SCROLLBAR_CURSOR,
3878 NK_COLOR_SCROLLBAR_CURSOR_HOVER,
3879 NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,
3880 NK_COLOR_TAB_HEADER,
3881 NK_COLOR_KNOB,
3882 NK_COLOR_KNOB_CURSOR,
3883 NK_COLOR_KNOB_CURSOR_HOVER,
3884 NK_COLOR_KNOB_CURSOR_ACTIVE,
3885 NK_COLOR_COUNT
3886};
3887enum nk_style_cursor {
3888 NK_CURSOR_ARROW,
3889 NK_CURSOR_TEXT,
3890 NK_CURSOR_MOVE,
3891 NK_CURSOR_RESIZE_VERTICAL,
3892 NK_CURSOR_RESIZE_HORIZONTAL,
3893 NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT,
3894 NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT,
3895 NK_CURSOR_COUNT
3896};
3897NK_API void nk_style_default(struct nk_context*);
3898NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*);
3899NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*);
3900NK_API void nk_style_load_all_cursors(struct nk_context*, const struct nk_cursor*);
3901NK_API const char* nk_style_get_color_by_name(enum nk_style_colors);
3902NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*);
3903NK_API nk_bool nk_style_set_cursor(struct nk_context*, enum nk_style_cursor);
3904NK_API void nk_style_show_cursor(struct nk_context*);
3905NK_API void nk_style_hide_cursor(struct nk_context*);
3906
3907NK_API nk_bool nk_style_push_font(struct nk_context*, const struct nk_user_font*);
3908NK_API nk_bool nk_style_push_float(struct nk_context*, float*, float);
3909NK_API nk_bool nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2);
3910NK_API nk_bool nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item);
3911NK_API nk_bool nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags);
3912NK_API nk_bool nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color);
3913
3914NK_API nk_bool nk_style_pop_font(struct nk_context*);
3915NK_API nk_bool nk_style_pop_float(struct nk_context*);
3916NK_API nk_bool nk_style_pop_vec2(struct nk_context*);
3917NK_API nk_bool nk_style_pop_style_item(struct nk_context*);
3918NK_API nk_bool nk_style_pop_flags(struct nk_context*);
3919NK_API nk_bool nk_style_pop_color(struct nk_context*);
3920/* =============================================================================
3921 *
3922 * COLOR
3923 *
3924 * ============================================================================= */
3925NK_API struct nk_color nk_rgb(int r, int g, int b);
3926NK_API struct nk_color nk_rgb_iv(const int *rgb);
3927NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb);
3928NK_API struct nk_color nk_rgb_f(float r, float g, float b);
3929NK_API struct nk_color nk_rgb_fv(const float *rgb);
3930NK_API struct nk_color nk_rgb_cf(struct nk_colorf c);
3931NK_API struct nk_color nk_rgb_hex(const char *rgb);
3932NK_API struct nk_color nk_rgb_factor(struct nk_color col, float factor);
3933
3934NK_API struct nk_color nk_rgba(int r, int g, int b, int a);
3935NK_API struct nk_color nk_rgba_u32(nk_uint);
3936NK_API struct nk_color nk_rgba_iv(const int *rgba);
3937NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba);
3938NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a);
3939NK_API struct nk_color nk_rgba_fv(const float *rgba);
3940NK_API struct nk_color nk_rgba_cf(struct nk_colorf c);
3941NK_API struct nk_color nk_rgba_hex(const char *rgb);
3942
3943NK_API struct nk_colorf nk_hsva_colorf(float h, float s, float v, float a);
3944NK_API struct nk_colorf nk_hsva_colorfv(const float *c);
3945NK_API void nk_colorf_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_colorf in);
3946NK_API void nk_colorf_hsva_fv(float *hsva, struct nk_colorf in);
3947
3948NK_API struct nk_color nk_hsv(int h, int s, int v);
3949NK_API struct nk_color nk_hsv_iv(const int *hsv);
3950NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv);
3951NK_API struct nk_color nk_hsv_f(float h, float s, float v);
3952NK_API struct nk_color nk_hsv_fv(const float *hsv);
3953
3954NK_API struct nk_color nk_hsva(int h, int s, int v, int a);
3955NK_API struct nk_color nk_hsva_iv(const int *hsva);
3956NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva);
3957NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a);
3958NK_API struct nk_color nk_hsva_fv(const float *hsva);
3959
3960/* color (conversion nuklear --> user) */
3961NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color);
3962NK_API void nk_color_fv(float *rgba_out, struct nk_color);
3963NK_API struct nk_colorf nk_color_cf(struct nk_color);
3964NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color);
3965NK_API void nk_color_dv(double *rgba_out, struct nk_color);
3966
3967NK_API nk_uint nk_color_u32(struct nk_color);
3968NK_API void nk_color_hex_rgba(char *output, struct nk_color);
3969NK_API void nk_color_hex_rgb(char *output, struct nk_color);
3970
3971NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color);
3972NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color);
3973NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color);
3974NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color);
3975NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color);
3976NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color);
3977
3978NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color);
3979NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color);
3980NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color);
3981NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color);
3982NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color);
3983NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color);
3984/* =============================================================================
3985 *
3986 * IMAGE
3987 *
3988 * ============================================================================= */
3989NK_API nk_handle nk_handle_ptr(void*);
3990NK_API nk_handle nk_handle_id(int);
3991NK_API struct nk_image nk_image_handle(nk_handle);
3992NK_API struct nk_image nk_image_ptr(void*);
3993NK_API struct nk_image nk_image_id(int);
3994NK_API nk_bool nk_image_is_subimage(const struct nk_image* img);
3995NK_API struct nk_image nk_subimage_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
3996NK_API struct nk_image nk_subimage_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
3997NK_API struct nk_image nk_subimage_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region);
3998/* =============================================================================
3999 *
4000 * 9-SLICE
4001 *
4002 * ============================================================================= */
4003NK_API struct nk_nine_slice nk_nine_slice_handle(nk_handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4004NK_API struct nk_nine_slice nk_nine_slice_ptr(void*, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4005NK_API struct nk_nine_slice nk_nine_slice_id(int, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4006NK_API int nk_nine_slice_is_sub9slice(const struct nk_nine_slice* img);
4007NK_API struct nk_nine_slice nk_sub9slice_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4008NK_API struct nk_nine_slice nk_sub9slice_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4009NK_API struct nk_nine_slice nk_sub9slice_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);
4010/* =============================================================================
4011 *
4012 * MATH
4013 *
4014 * ============================================================================= */
4015NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed);
4016NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading);
4017
4018NK_API struct nk_vec2 nk_vec2(float x, float y);
4019NK_API struct nk_vec2 nk_vec2i(int x, int y);
4020NK_API struct nk_vec2 nk_vec2v(const float *xy);
4021NK_API struct nk_vec2 nk_vec2iv(const int *xy);
4022
4023NK_API struct nk_rect nk_get_null_rect(void);
4024NK_API struct nk_rect nk_rect(float x, float y, float w, float h);
4025NK_API struct nk_rect nk_recti(int x, int y, int w, int h);
4026NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size);
4027NK_API struct nk_rect nk_rectv(const float *xywh);
4028NK_API struct nk_rect nk_rectiv(const int *xywh);
4029NK_API struct nk_vec2 nk_rect_pos(struct nk_rect);
4030NK_API struct nk_vec2 nk_rect_size(struct nk_rect);
4031/* =============================================================================
4032 *
4033 * STRING
4034 *
4035 * ============================================================================= */
4036NK_API int nk_strlen(const char *str);
4037NK_API int nk_stricmp(const char *s1, const char *s2);
4038NK_API int nk_stricmpn(const char *s1, const char *s2, int n);
4039NK_API int nk_strtoi(const char *str, char **endptr);
4040NK_API float nk_strtof(const char *str, char **endptr);
4041#ifndef NK_STRTOD
4042#define NK_STRTOD nk_strtod
4043NK_API double nk_strtod(const char *str, char **endptr);
4044#endif
4045NK_API int nk_strfilter(const char *text, const char *regexp);
4046NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score);
4047NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score);
4048/* =============================================================================
4049 *
4050 * UTF-8
4051 *
4052 * ============================================================================= */
4053NK_API int nk_utf_decode(const char*, nk_rune*, int);
4054NK_API int nk_utf_encode(nk_rune, char*, int);
4055NK_API int nk_utf_len(const char*, int byte_len);
4056NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len);
4057/* ===============================================================
4058 *
4059 * FONT
4060 *
4061 * ===============================================================*/
4214struct nk_user_font_glyph;
4215typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len);
4216typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,
4217 struct nk_user_font_glyph *glyph,
4218 nk_rune codepoint, nk_rune next_codepoint);
4219
4220#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT)
4221struct nk_user_font_glyph {
4222 struct nk_vec2 uv[2];
4223 struct nk_vec2 offset;
4224 float width, height;
4225 float xadvance;
4226};
4227#endif
4228
4230 nk_handle userdata;
4231 float height;
4232 nk_text_width_f width;
4233#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
4234 nk_query_font_glyph_f query;
4235 nk_handle texture;
4236#endif
4237};
4238
4239#ifdef NK_INCLUDE_FONT_BAKING
4240enum nk_font_coord_type {
4241 NK_COORD_UV,
4242 NK_COORD_PIXEL
4243};
4244
4245struct nk_font;
4246struct nk_baked_font {
4247 float height;
4248 float ascent;
4249 float descent;
4250 nk_rune glyph_offset;
4251 nk_rune glyph_count;
4252 const nk_rune *ranges;
4253};
4254
4255struct nk_font_config {
4256 struct nk_font_config *next;
4257 void *ttf_blob;
4258 nk_size ttf_size;
4260 unsigned char ttf_data_owned_by_atlas;
4261 unsigned char merge_mode;
4262 unsigned char pixel_snap;
4263 unsigned char oversample_v, oversample_h;
4264 unsigned char padding[3];
4265
4266 float size;
4267 enum nk_font_coord_type coord_type;
4268 struct nk_vec2 spacing;
4269 const nk_rune *range;
4270 struct nk_baked_font *font;
4271 nk_rune fallback_glyph;
4272 struct nk_font_config *n;
4273 struct nk_font_config *p;
4274};
4275
4276struct nk_font_glyph {
4277 nk_rune codepoint;
4278 float xadvance;
4279 float x0, y0, x1, y1, w, h;
4280 float u0, v0, u1, v1;
4281};
4282
4283struct nk_font {
4284 struct nk_font *next;
4285 struct nk_user_font handle;
4286 struct nk_baked_font info;
4287 float scale;
4288 struct nk_font_glyph *glyphs;
4289 const struct nk_font_glyph *fallback;
4290 nk_rune fallback_codepoint;
4291 nk_handle texture;
4292 struct nk_font_config *config;
4293};
4294
4295enum nk_font_atlas_format {
4296 NK_FONT_ATLAS_ALPHA8,
4297 NK_FONT_ATLAS_RGBA32
4298};
4299
4300struct nk_font_atlas {
4301 void *pixel;
4302 int tex_width;
4303 int tex_height;
4304
4305 struct nk_allocator permanent;
4306 struct nk_allocator temporary;
4307
4308 struct nk_recti custom;
4309 struct nk_cursor cursors[NK_CURSOR_COUNT];
4310
4311 int glyph_count;
4312 struct nk_font_glyph *glyphs;
4313 struct nk_font *default_font;
4314 struct nk_font *fonts;
4315 struct nk_font_config *config;
4316 int font_num;
4317};
4318
4320NK_API const nk_rune *nk_font_default_glyph_ranges(void);
4321NK_API const nk_rune *nk_font_chinese_glyph_ranges(void);
4322NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void);
4323NK_API const nk_rune *nk_font_korean_glyph_ranges(void);
4324
4325#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
4326NK_API void nk_font_atlas_init_default(struct nk_font_atlas*);
4327#endif
4328NK_API void nk_font_atlas_init(struct nk_font_atlas*, const struct nk_allocator*);
4329NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, const struct nk_allocator *persistent, const struct nk_allocator *transient);
4330NK_API void nk_font_atlas_begin(struct nk_font_atlas*);
4331NK_API struct nk_font_config nk_font_config(float pixel_height);
4332NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*);
4333#ifdef NK_INCLUDE_DEFAULT_FONT
4334NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*);
4335#endif
4336NK_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);
4337#ifdef NK_INCLUDE_STANDARD_IO
4338NK_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*);
4339#endif
4340NK_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*);
4341NK_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);
4342NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format);
4343NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*);
4344NK_API const struct nk_font_glyph* nk_font_find_glyph(const struct nk_font*, nk_rune unicode);
4345NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas);
4346NK_API void nk_font_atlas_clear(struct nk_font_atlas*);
4347
4348#endif
4349
4387 void *memory;
4388 unsigned int type;
4389 nk_size size;
4390 nk_size allocated;
4391 nk_size needed;
4392 nk_size calls;
4393};
4394
4395enum nk_allocation_type {
4396 NK_BUFFER_FIXED,
4397 NK_BUFFER_DYNAMIC
4398};
4399
4400enum nk_buffer_allocation_type {
4401 NK_BUFFER_FRONT,
4402 NK_BUFFER_BACK,
4403 NK_BUFFER_MAX
4404};
4405
4407 nk_bool active;
4408 nk_size offset;
4409};
4410
4411struct nk_memory {void *ptr;nk_size size;};
4413 struct nk_buffer_marker marker[NK_BUFFER_MAX];
4415 enum nk_allocation_type type;
4418 nk_size allocated;
4419 nk_size needed;
4420 nk_size calls;
4421 nk_size size;
4422};
4423
4424#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
4425NK_API void nk_buffer_init_default(struct nk_buffer*);
4426#endif
4427NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size);
4428NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size);
4429NK_API void nk_buffer_info(struct nk_memory_status*, const struct nk_buffer*);
4430NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align);
4431NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type);
4432NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type);
4433NK_API void nk_buffer_clear(struct nk_buffer*);
4434NK_API void nk_buffer_free(struct nk_buffer*);
4435NK_API void *nk_buffer_memory(struct nk_buffer*);
4436NK_API const void *nk_buffer_memory_const(const struct nk_buffer*);
4437NK_API nk_size nk_buffer_total(const struct nk_buffer*);
4438
4449struct nk_str {
4450 struct nk_buffer buffer;
4451 int len;
4452};
4453
4454#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
4455NK_API void nk_str_init_default(struct nk_str*);
4456#endif
4457NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size);
4458NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size);
4459NK_API void nk_str_clear(struct nk_str*);
4460NK_API void nk_str_free(struct nk_str*);
4461
4462NK_API int nk_str_append_text_char(struct nk_str*, const char*, int);
4463NK_API int nk_str_append_str_char(struct nk_str*, const char*);
4464NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int);
4465NK_API int nk_str_append_str_utf8(struct nk_str*, const char*);
4466NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int);
4467NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*);
4468
4469NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int);
4470NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int);
4471
4472NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int);
4473NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*);
4474NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int);
4475NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*);
4476NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int);
4477NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*);
4478
4479NK_API void nk_str_remove_chars(struct nk_str*, int len);
4480NK_API void nk_str_remove_runes(struct nk_str *str, int len);
4481NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len);
4482NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len);
4483
4484NK_API char *nk_str_at_char(struct nk_str*, int pos);
4485NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len);
4486NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos);
4487NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos);
4488NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len);
4489
4490NK_API char *nk_str_get(struct nk_str*);
4491NK_API const char *nk_str_get_const(const struct nk_str*);
4492NK_API int nk_str_len(const struct nk_str*);
4493NK_API int nk_str_len_char(const struct nk_str*);
4494
4526#ifndef NK_TEXTEDIT_UNDOSTATECOUNT
4527#define NK_TEXTEDIT_UNDOSTATECOUNT 99
4528#endif
4529
4530#ifndef NK_TEXTEDIT_UNDOCHARCOUNT
4531#define NK_TEXTEDIT_UNDOCHARCOUNT 999
4532#endif
4533
4534struct nk_text_edit;
4536 nk_handle userdata;
4537 nk_plugin_paste paste;
4538 nk_plugin_copy copy;
4539};
4540
4542 int where;
4543 short insert_length;
4544 short delete_length;
4545 short char_storage;
4546};
4547
4549 struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT];
4550 nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT];
4551 short undo_point;
4552 short redo_point;
4553 short undo_char_point;
4554 short redo_char_point;
4555};
4556
4557enum nk_text_edit_type {
4558 NK_TEXT_EDIT_SINGLE_LINE,
4559 NK_TEXT_EDIT_MULTI_LINE
4560};
4561
4562enum nk_text_edit_mode {
4563 NK_TEXT_EDIT_MODE_VIEW,
4564 NK_TEXT_EDIT_MODE_INSERT,
4565 NK_TEXT_EDIT_MODE_REPLACE
4566};
4567
4569 struct nk_clipboard clip;
4570 struct nk_str string;
4571 nk_plugin_filter filter;
4572 struct nk_vec2 scrollbar;
4573
4574 int cursor;
4575 int select_start;
4576 int select_end;
4577 unsigned char mode;
4578 unsigned char cursor_at_end_of_line;
4579 unsigned char initialized;
4580 unsigned char has_preferred_x;
4581 unsigned char single_line;
4582 unsigned char active;
4583 unsigned char padding1;
4584 float preferred_x;
4585 struct nk_text_undo_state undo;
4586};
4587
4589NK_API nk_bool nk_filter_default(const struct nk_text_edit*, nk_rune unicode);
4590NK_API nk_bool nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode);
4591NK_API nk_bool nk_filter_float(const struct nk_text_edit*, nk_rune unicode);
4592NK_API nk_bool nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode);
4593NK_API nk_bool nk_filter_hex(const struct nk_text_edit*, nk_rune unicode);
4594NK_API nk_bool nk_filter_oct(const struct nk_text_edit*, nk_rune unicode);
4595NK_API nk_bool nk_filter_binary(const struct nk_text_edit*, nk_rune unicode);
4596
4598#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
4599NK_API void nk_textedit_init_default(struct nk_text_edit*);
4600#endif
4601NK_API void nk_textedit_init(struct nk_text_edit*, const struct nk_allocator*, nk_size size);
4602NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size);
4603NK_API void nk_textedit_free(struct nk_text_edit*);
4604NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len);
4605NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len);
4606NK_API void nk_textedit_delete_selection(struct nk_text_edit*);
4607NK_API void nk_textedit_select_all(struct nk_text_edit*);
4608NK_API nk_bool nk_textedit_cut(struct nk_text_edit*);
4609NK_API nk_bool nk_textedit_paste(struct nk_text_edit*, char const*, int len);
4610NK_API void nk_textedit_undo(struct nk_text_edit*);
4611NK_API void nk_textedit_redo(struct nk_text_edit*);
4612
4613/* ===============================================================
4614 *
4615 * DRAWING
4616 *
4617 * ===============================================================*/
4667enum nk_command_type {
4668 NK_COMMAND_NOP,
4669 NK_COMMAND_SCISSOR,
4670 NK_COMMAND_LINE,
4671 NK_COMMAND_CURVE,
4672 NK_COMMAND_RECT,
4673 NK_COMMAND_RECT_FILLED,
4674 NK_COMMAND_RECT_MULTI_COLOR,
4675 NK_COMMAND_CIRCLE,
4676 NK_COMMAND_CIRCLE_FILLED,
4677 NK_COMMAND_ARC,
4678 NK_COMMAND_ARC_FILLED,
4679 NK_COMMAND_TRIANGLE,
4680 NK_COMMAND_TRIANGLE_FILLED,
4681 NK_COMMAND_POLYGON,
4682 NK_COMMAND_POLYGON_FILLED,
4683 NK_COMMAND_POLYLINE,
4684 NK_COMMAND_TEXT,
4685 NK_COMMAND_IMAGE,
4686 NK_COMMAND_CUSTOM
4687};
4688
4691 enum nk_command_type type;
4692 nk_size next;
4693#ifdef NK_INCLUDE_COMMAND_USERDATA
4694 nk_handle userdata;
4695#endif
4696};
4697
4699 struct nk_command header;
4700 short x, y;
4701 unsigned short w, h;
4702};
4703
4705 struct nk_command header;
4706 unsigned short line_thickness;
4707 struct nk_vec2i begin;
4708 struct nk_vec2i end;
4709 struct nk_color color;
4710};
4711
4713 struct nk_command header;
4714 unsigned short line_thickness;
4715 struct nk_vec2i begin;
4716 struct nk_vec2i end;
4717 struct nk_vec2i ctrl[2];
4718 struct nk_color color;
4719};
4720
4722 struct nk_command header;
4723 unsigned short rounding;
4724 unsigned short line_thickness;
4725 short x, y;
4726 unsigned short w, h;
4727 struct nk_color color;
4728};
4729
4731 struct nk_command header;
4732 unsigned short rounding;
4733 short x, y;
4734 unsigned short w, h;
4735 struct nk_color color;
4736};
4737
4739 struct nk_command header;
4740 short x, y;
4741 unsigned short w, h;
4742 struct nk_color left;
4743 struct nk_color top;
4744 struct nk_color bottom;
4745 struct nk_color right;
4746};
4747
4749 struct nk_command header;
4750 unsigned short line_thickness;
4751 struct nk_vec2i a;
4752 struct nk_vec2i b;
4753 struct nk_vec2i c;
4754 struct nk_color color;
4755};
4756
4758 struct nk_command header;
4759 struct nk_vec2i a;
4760 struct nk_vec2i b;
4761 struct nk_vec2i c;
4762 struct nk_color color;
4763};
4764
4766 struct nk_command header;
4767 short x, y;
4768 unsigned short line_thickness;
4769 unsigned short w, h;
4770 struct nk_color color;
4771};
4772
4774 struct nk_command header;
4775 short x, y;
4776 unsigned short w, h;
4777 struct nk_color color;
4778};
4779
4781 struct nk_command header;
4782 short cx, cy;
4783 unsigned short r;
4784 unsigned short line_thickness;
4785 float a[2];
4786 struct nk_color color;
4787};
4788
4790 struct nk_command header;
4791 short cx, cy;
4792 unsigned short r;
4793 float a[2];
4794 struct nk_color color;
4795};
4796
4798 struct nk_command header;
4799 struct nk_color color;
4800 unsigned short line_thickness;
4801 unsigned short point_count;
4802 struct nk_vec2i points[1];
4803};
4804
4806 struct nk_command header;
4807 struct nk_color color;
4808 unsigned short point_count;
4809 struct nk_vec2i points[1];
4810};
4811
4813 struct nk_command header;
4814 struct nk_color color;
4815 unsigned short line_thickness;
4816 unsigned short point_count;
4817 struct nk_vec2i points[1];
4818};
4819
4821 struct nk_command header;
4822 short x, y;
4823 unsigned short w, h;
4824 struct nk_image img;
4825 struct nk_color col;
4826};
4827
4828typedef void (*nk_command_custom_callback)(void *canvas, short x,short y,
4829 unsigned short w, unsigned short h, nk_handle callback_data);
4831 struct nk_command header;
4832 short x, y;
4833 unsigned short w, h;
4834 nk_handle callback_data;
4835 nk_command_custom_callback callback;
4836};
4837
4839 struct nk_command header;
4840 const struct nk_user_font *font;
4841 struct nk_color background;
4842 struct nk_color foreground;
4843 short x, y;
4844 unsigned short w, h;
4845 float height;
4846 int length;
4847 char string[2];
4848};
4849
4850enum nk_command_clipping {
4851 NK_CLIPPING_OFF = nk_false,
4852 NK_CLIPPING_ON = nk_true
4853};
4854
4856 struct nk_buffer *base;
4857 struct nk_rect clip;
4858 int use_clipping;
4859 nk_handle userdata;
4860 nk_size begin, end, last;
4861};
4862
4864NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color);
4865NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color);
4866NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color);
4867NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color);
4868NK_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);
4869NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color);
4870NK_API void nk_stroke_polyline(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color col);
4871NK_API void nk_stroke_polygon(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color);
4872
4874NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color);
4875NK_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);
4876NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color);
4877NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color);
4878NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color);
4879NK_API void nk_fill_polygon(struct nk_command_buffer*, const float *points, int point_count, struct nk_color);
4880
4882NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);
4883NK_API void nk_draw_nine_slice(struct nk_command_buffer*, struct nk_rect, const struct nk_nine_slice*, struct nk_color);
4884NK_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);
4885NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);
4886NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);
4887
4888/* ===============================================================
4889 *
4890 * INPUT
4891 *
4892 * ===============================================================*/
4894 nk_bool down;
4895 unsigned int clicked;
4896 struct nk_vec2 clicked_pos;
4897};
4898struct nk_mouse {
4899 struct nk_mouse_button buttons[NK_BUTTON_MAX];
4900 struct nk_vec2 pos;
4901#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
4902 struct nk_vec2 down_pos;
4903#endif
4904 struct nk_vec2 prev;
4905 struct nk_vec2 delta;
4906 struct nk_vec2 scroll_delta;
4907 unsigned char grab;
4908 unsigned char grabbed;
4909 unsigned char ungrab;
4910};
4911
4912struct nk_key {
4913 nk_bool down;
4914 unsigned int clicked;
4915};
4917 struct nk_key keys[NK_KEY_MAX];
4918 char text[NK_INPUT_MAX];
4919 int text_len;
4920};
4921
4922struct nk_input {
4923 struct nk_keyboard keyboard;
4924 struct nk_mouse mouse;
4925};
4926
4927NK_API nk_bool nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons);
4928NK_API nk_bool nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
4929NK_API nk_bool nk_input_has_mouse_click_in_button_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
4930NK_API nk_bool nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, nk_bool down);
4931NK_API nk_bool nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);
4932NK_API nk_bool nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, nk_bool down);
4933NK_API nk_bool nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect);
4934NK_API nk_bool nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect);
4935NK_API nk_bool nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect);
4936NK_API nk_bool nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect);
4937NK_API nk_bool nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons);
4938NK_API nk_bool nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons);
4939NK_API nk_bool nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons);
4940NK_API nk_bool nk_input_is_key_pressed(const struct nk_input*, enum nk_keys);
4941NK_API nk_bool nk_input_is_key_released(const struct nk_input*, enum nk_keys);
4942NK_API nk_bool nk_input_is_key_down(const struct nk_input*, enum nk_keys);
4943
4944/* ===============================================================
4945 *
4946 * DRAW LIST
4947 *
4948 * ===============================================================*/
4949#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
4966#ifdef NK_UINT_DRAW_INDEX
4967typedef nk_uint nk_draw_index;
4968#else
4969typedef nk_ushort nk_draw_index;
4970#endif
4971enum nk_draw_list_stroke {
4972 NK_STROKE_OPEN = nk_false, /***< build up path has no connection back to the beginning */
4973 NK_STROKE_CLOSED = nk_true /***< build up path has a connection back to the beginning */
4974};
4975
4976enum nk_draw_vertex_layout_attribute {
4977 NK_VERTEX_POSITION,
4978 NK_VERTEX_COLOR,
4979 NK_VERTEX_TEXCOORD,
4980 NK_VERTEX_ATTRIBUTE_COUNT
4981};
4982
4983enum nk_draw_vertex_layout_format {
4984 NK_FORMAT_SCHAR,
4985 NK_FORMAT_SSHORT,
4986 NK_FORMAT_SINT,
4987 NK_FORMAT_UCHAR,
4988 NK_FORMAT_USHORT,
4989 NK_FORMAT_UINT,
4990 NK_FORMAT_FLOAT,
4991 NK_FORMAT_DOUBLE,
4992
4993NK_FORMAT_COLOR_BEGIN,
4994 NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN,
4995 NK_FORMAT_R16G15B16,
4996 NK_FORMAT_R32G32B32,
4997
4998 NK_FORMAT_R8G8B8A8,
4999 NK_FORMAT_B8G8R8A8,
5000 NK_FORMAT_R16G15B16A16,
5001 NK_FORMAT_R32G32B32A32,
5002 NK_FORMAT_R32G32B32A32_FLOAT,
5003 NK_FORMAT_R32G32B32A32_DOUBLE,
5004
5005 NK_FORMAT_RGB32,
5006 NK_FORMAT_RGBA32,
5007NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32,
5008 NK_FORMAT_COUNT
5009};
5010
5011#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0
5012struct nk_draw_vertex_layout_element {
5013 enum nk_draw_vertex_layout_attribute attribute;
5014 enum nk_draw_vertex_layout_format format;
5015 nk_size offset;
5016};
5017
5018struct nk_draw_command {
5019 unsigned int elem_count;
5020 struct nk_rect clip_rect;
5021 nk_handle texture;
5022#ifdef NK_INCLUDE_COMMAND_USERDATA
5023 nk_handle userdata;
5024#endif
5025};
5026
5027struct nk_draw_list {
5028 struct nk_rect clip_rect;
5029 struct nk_vec2 circle_vtx[12];
5030 struct nk_convert_config config;
5031
5032 struct nk_buffer *buffer;
5033 struct nk_buffer *vertices;
5034 struct nk_buffer *elements;
5035
5036 unsigned int element_count;
5037 unsigned int vertex_count;
5038 unsigned int cmd_count;
5039 nk_size cmd_offset;
5040
5041 unsigned int path_count;
5042 unsigned int path_offset;
5043
5044 enum nk_anti_aliasing line_AA;
5045 enum nk_anti_aliasing shape_AA;
5046
5047#ifdef NK_INCLUDE_COMMAND_USERDATA
5048 nk_handle userdata;
5049#endif
5050};
5051
5052/* draw list */
5053NK_API void nk_draw_list_init(struct nk_draw_list*);
5054NK_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);
5055
5056/* drawing */
5057#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))
5058NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*);
5059NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*);
5060NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*);
5061
5062/* path */
5063NK_API void nk_draw_list_path_clear(struct nk_draw_list*);
5064NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos);
5065NK_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);
5066NK_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);
5067NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding);
5068NK_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);
5069NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color);
5070NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness);
5071
5072/* stroke */
5073NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness);
5074NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness);
5075NK_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);
5076NK_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);
5077NK_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);
5078NK_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);
5079
5080/* fill */
5081NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding);
5082NK_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);
5083NK_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);
5084NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs);
5085NK_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);
5086
5087/* misc */
5088NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color);
5089NK_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);
5090#ifdef NK_INCLUDE_COMMAND_USERDATA
5091NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata);
5092#endif
5093
5094#endif
5095
5096/* ===============================================================
5097 *
5098 * GUI
5099 *
5100 * ===============================================================*/
5101enum nk_style_item_type {
5102 NK_STYLE_ITEM_COLOR,
5103 NK_STYLE_ITEM_IMAGE,
5104 NK_STYLE_ITEM_NINE_SLICE
5105};
5106
5108 struct nk_color color;
5109 struct nk_image image;
5110 struct nk_nine_slice slice;
5111};
5112
5114 enum nk_style_item_type type;
5115 union nk_style_item_data data;
5116};
5117
5119 struct nk_color color;
5120 struct nk_vec2 padding;
5121 float color_factor;
5122 float disabled_factor;
5123};
5124
5126 /* background */
5127 struct nk_style_item normal;
5128 struct nk_style_item hover;
5129 struct nk_style_item active;
5130 struct nk_color border_color;
5131 float color_factor_background;
5132
5133 /* text */
5134 struct nk_color text_background;
5135 struct nk_color text_normal;
5136 struct nk_color text_hover;
5137 struct nk_color text_active;
5138 nk_flags text_alignment;
5139 float color_factor_text;
5140
5141 /* properties */
5142 float border;
5143 float rounding;
5144 struct nk_vec2 padding;
5145 struct nk_vec2 image_padding;
5146 struct nk_vec2 touch_padding;
5147 float disabled_factor;
5148
5149 /* optional user callbacks */
5150 nk_handle userdata;
5151 void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata);
5152 void(*draw_end)(struct nk_command_buffer*, nk_handle userdata);
5153};
5154
5156 /* background */
5157 struct nk_style_item normal;
5158 struct nk_style_item hover;
5159 struct nk_style_item active;
5160 struct nk_color border_color;
5161
5162 /* cursor */
5163 struct nk_style_item cursor_normal;
5164 struct nk_style_item cursor_hover;
5165
5166 /* text */
5167 struct nk_color text_normal;
5168 struct nk_color text_hover;
5169 struct nk_color text_active;
5170 struct nk_color text_background;
5171 nk_flags text_alignment;
5172
5173 /* properties */
5174 struct nk_vec2 padding;
5175 struct nk_vec2 touch_padding;
5176 float spacing;
5177 float border;
5178 float color_factor;
5179 float disabled_factor;
5180
5181 /* optional user callbacks */
5182 nk_handle userdata;
5183 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5184 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5185};
5186
5188 /* background (inactive) */
5189 struct nk_style_item normal;
5190 struct nk_style_item hover;
5191 struct nk_style_item pressed;
5192
5193 /* background (active) */
5194 struct nk_style_item normal_active;
5195 struct nk_style_item hover_active;
5196 struct nk_style_item pressed_active;
5197
5198 /* text color (inactive) */
5199 struct nk_color text_normal;
5200 struct nk_color text_hover;
5201 struct nk_color text_pressed;
5202
5203 /* text color (active) */
5204 struct nk_color text_normal_active;
5205 struct nk_color text_hover_active;
5206 struct nk_color text_pressed_active;
5207 struct nk_color text_background;
5208 nk_flags text_alignment;
5209
5210 /* properties */
5211 float rounding;
5212 struct nk_vec2 padding;
5213 struct nk_vec2 touch_padding;
5214 struct nk_vec2 image_padding;
5215 float color_factor;
5216 float disabled_factor;
5217
5218 /* optional user callbacks */
5219 nk_handle userdata;
5220 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5221 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5222};
5223
5225 /* background */
5226 struct nk_style_item normal;
5227 struct nk_style_item hover;
5228 struct nk_style_item active;
5229 struct nk_color border_color;
5230
5231 /* background bar */
5232 struct nk_color bar_normal;
5233 struct nk_color bar_hover;
5234 struct nk_color bar_active;
5235 struct nk_color bar_filled;
5236
5237 /* cursor */
5238 struct nk_style_item cursor_normal;
5239 struct nk_style_item cursor_hover;
5240 struct nk_style_item cursor_active;
5241
5242 /* properties */
5243 float border;
5244 float rounding;
5245 float bar_height;
5246 struct nk_vec2 padding;
5247 struct nk_vec2 spacing;
5248 struct nk_vec2 cursor_size;
5249 float color_factor;
5250 float disabled_factor;
5251
5252 /* optional buttons */
5253 int show_buttons;
5254 struct nk_style_button inc_button;
5255 struct nk_style_button dec_button;
5256 enum nk_symbol_type inc_symbol;
5257 enum nk_symbol_type dec_symbol;
5258
5259 /* optional user callbacks */
5260 nk_handle userdata;
5261 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5262 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5263};
5264
5266 /* background */
5267 struct nk_style_item normal;
5268 struct nk_style_item hover;
5269 struct nk_style_item active;
5270 struct nk_color border_color;
5271
5272 /* knob */
5273 struct nk_color knob_normal;
5274 struct nk_color knob_hover;
5275 struct nk_color knob_active;
5276 struct nk_color knob_border_color;
5277
5278 /* cursor */
5279 struct nk_color cursor_normal;
5280 struct nk_color cursor_hover;
5281 struct nk_color cursor_active;
5282
5283 /* properties */
5284 float border;
5285 float knob_border;
5286 struct nk_vec2 padding;
5287 struct nk_vec2 spacing;
5288 float cursor_width;
5289 float color_factor;
5290 float disabled_factor;
5291
5292 /* optional user callbacks */
5293 nk_handle userdata;
5294 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5295 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5296};
5297
5299 /* background */
5300 struct nk_style_item normal;
5301 struct nk_style_item hover;
5302 struct nk_style_item active;
5303 struct nk_color border_color;
5304
5305 /* cursor */
5306 struct nk_style_item cursor_normal;
5307 struct nk_style_item cursor_hover;
5308 struct nk_style_item cursor_active;
5309 struct nk_color cursor_border_color;
5310
5311 /* properties */
5312 float rounding;
5313 float border;
5314 float cursor_border;
5315 float cursor_rounding;
5316 struct nk_vec2 padding;
5317 float color_factor;
5318 float disabled_factor;
5319
5320 /* optional user callbacks */
5321 nk_handle userdata;
5322 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5323 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5324};
5325
5327 /* background */
5328 struct nk_style_item normal;
5329 struct nk_style_item hover;
5330 struct nk_style_item active;
5331 struct nk_color border_color;
5332
5333 /* cursor */
5334 struct nk_style_item cursor_normal;
5335 struct nk_style_item cursor_hover;
5336 struct nk_style_item cursor_active;
5337 struct nk_color cursor_border_color;
5338
5339 /* properties */
5340 float border;
5341 float rounding;
5342 float border_cursor;
5343 float rounding_cursor;
5344 struct nk_vec2 padding;
5345 float color_factor;
5346 float disabled_factor;
5347
5348 /* optional buttons */
5349 int show_buttons;
5350 struct nk_style_button inc_button;
5351 struct nk_style_button dec_button;
5352 enum nk_symbol_type inc_symbol;
5353 enum nk_symbol_type dec_symbol;
5354
5355 /* optional user callbacks */
5356 nk_handle userdata;
5357 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5358 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5359};
5360
5362 /* background */
5363 struct nk_style_item normal;
5364 struct nk_style_item hover;
5365 struct nk_style_item active;
5366 struct nk_color border_color;
5367 struct nk_style_scrollbar scrollbar;
5368
5369 /* cursor */
5370 struct nk_color cursor_normal;
5371 struct nk_color cursor_hover;
5372 struct nk_color cursor_text_normal;
5373 struct nk_color cursor_text_hover;
5374
5375 /* text (unselected) */
5376 struct nk_color text_normal;
5377 struct nk_color text_hover;
5378 struct nk_color text_active;
5379
5380 /* text (selected) */
5381 struct nk_color selected_normal;
5382 struct nk_color selected_hover;
5383 struct nk_color selected_text_normal;
5384 struct nk_color selected_text_hover;
5385
5386 /* properties */
5387 float border;
5388 float rounding;
5389 float cursor_size;
5390 struct nk_vec2 scrollbar_size;
5391 struct nk_vec2 padding;
5392 float row_padding;
5393 float color_factor;
5394 float disabled_factor;
5395};
5396
5398 /* background */
5399 struct nk_style_item normal;
5400 struct nk_style_item hover;
5401 struct nk_style_item active;
5402 struct nk_color border_color;
5403
5404 /* text */
5405 struct nk_color label_normal;
5406 struct nk_color label_hover;
5407 struct nk_color label_active;
5408
5409 /* symbols */
5410 enum nk_symbol_type sym_left;
5411 enum nk_symbol_type sym_right;
5412
5413 /* properties */
5414 float border;
5415 float rounding;
5416 struct nk_vec2 padding;
5417 float color_factor;
5418 float disabled_factor;
5419
5420 struct nk_style_edit edit;
5421 struct nk_style_button inc_button;
5422 struct nk_style_button dec_button;
5423
5424 /* optional user callbacks */
5425 nk_handle userdata;
5426 void(*draw_begin)(struct nk_command_buffer*, nk_handle);
5427 void(*draw_end)(struct nk_command_buffer*, nk_handle);
5428};
5429
5431 /* colors */
5432 struct nk_style_item background;
5433 struct nk_color border_color;
5434 struct nk_color selected_color;
5435 struct nk_color color;
5436
5437 /* properties */
5438 float border;
5439 float rounding;
5440 struct nk_vec2 padding;
5441 float color_factor;
5442 float disabled_factor;
5443 nk_bool show_markers;
5444};
5445
5447 /* background */
5448 struct nk_style_item normal;
5449 struct nk_style_item hover;
5450 struct nk_style_item active;
5451 struct nk_color border_color;
5452
5453 /* label */
5454 struct nk_color label_normal;
5455 struct nk_color label_hover;
5456 struct nk_color label_active;
5457
5458 /* symbol */
5459 struct nk_color symbol_normal;
5460 struct nk_color symbol_hover;
5461 struct nk_color symbol_active;
5462
5463 /* button */
5464 struct nk_style_button button;
5465 enum nk_symbol_type sym_normal;
5466 enum nk_symbol_type sym_hover;
5467 enum nk_symbol_type sym_active;
5468
5469 /* properties */
5470 float border;
5471 float rounding;
5472 struct nk_vec2 content_padding;
5473 struct nk_vec2 button_padding;
5474 struct nk_vec2 spacing;
5475 float color_factor;
5476 float disabled_factor;
5477};
5478
5480 /* background */
5481 struct nk_style_item background;
5482 struct nk_color border_color;
5483 struct nk_color text;
5484
5485 /* button */
5486 struct nk_style_button tab_maximize_button;
5487 struct nk_style_button tab_minimize_button;
5488 struct nk_style_button node_maximize_button;
5489 struct nk_style_button node_minimize_button;
5490 enum nk_symbol_type sym_minimize;
5491 enum nk_symbol_type sym_maximize;
5492
5493 /* properties */
5494 float border;
5495 float rounding;
5496 float indent;
5497 struct nk_vec2 padding;
5498 struct nk_vec2 spacing;
5499 float color_factor;
5500 float disabled_factor;
5501};
5502
5503enum nk_style_header_align {
5504 NK_HEADER_LEFT,
5505 NK_HEADER_RIGHT
5506};
5508 /* background */
5509 struct nk_style_item normal;
5510 struct nk_style_item hover;
5511 struct nk_style_item active;
5512
5513 /* button */
5514 struct nk_style_button close_button;
5515 struct nk_style_button minimize_button;
5516 enum nk_symbol_type close_symbol;
5517 enum nk_symbol_type minimize_symbol;
5518 enum nk_symbol_type maximize_symbol;
5519
5520 /* title */
5521 struct nk_color label_normal;
5522 struct nk_color label_hover;
5523 struct nk_color label_active;
5524
5525 /* properties */
5526 enum nk_style_header_align align;
5527 struct nk_vec2 padding;
5528 struct nk_vec2 label_padding;
5529 struct nk_vec2 spacing;
5530};
5531
5533 struct nk_style_window_header header;
5534 struct nk_style_item fixed_background;
5535 struct nk_color background;
5536
5537 struct nk_color border_color;
5538 struct nk_color popup_border_color;
5539 struct nk_color combo_border_color;
5540 struct nk_color contextual_border_color;
5541 struct nk_color menu_border_color;
5542 struct nk_color group_border_color;
5543 struct nk_color tooltip_border_color;
5544 struct nk_style_item scaler;
5545
5546 float border;
5547 float combo_border;
5548 float contextual_border;
5549 float menu_border;
5550 float group_border;
5551 float tooltip_border;
5552 float popup_border;
5553 float min_row_height_padding;
5554
5555 float rounding;
5556 struct nk_vec2 spacing;
5557 struct nk_vec2 scrollbar_size;
5558 struct nk_vec2 min_size;
5559
5560 struct nk_vec2 padding;
5561 struct nk_vec2 group_padding;
5562 struct nk_vec2 popup_padding;
5563 struct nk_vec2 combo_padding;
5564 struct nk_vec2 contextual_padding;
5565 struct nk_vec2 menu_padding;
5566 struct nk_vec2 tooltip_padding;
5567};
5568
5569struct nk_style {
5570 const struct nk_user_font *font;
5571 const struct nk_cursor *cursors[NK_CURSOR_COUNT];
5572 const struct nk_cursor *cursor_active;
5573 struct nk_cursor *cursor_last;
5574 int cursor_visible;
5575
5576 struct nk_style_text text;
5577 struct nk_style_button button;
5578 struct nk_style_button contextual_button;
5579 struct nk_style_button menu_button;
5580 struct nk_style_toggle option;
5581 struct nk_style_toggle checkbox;
5582 struct nk_style_selectable selectable;
5583 struct nk_style_slider slider;
5584 struct nk_style_knob knob;
5585 struct nk_style_progress progress;
5586 struct nk_style_property property;
5587 struct nk_style_edit edit;
5588 struct nk_style_chart chart;
5589 struct nk_style_scrollbar scrollh;
5590 struct nk_style_scrollbar scrollv;
5591 struct nk_style_tab tab;
5592 struct nk_style_combo combo;
5593 struct nk_style_window window;
5594};
5595
5596NK_API struct nk_style_item nk_style_item_color(struct nk_color);
5597NK_API struct nk_style_item nk_style_item_image(struct nk_image img);
5598NK_API struct nk_style_item nk_style_item_nine_slice(struct nk_nine_slice slice);
5599NK_API struct nk_style_item nk_style_item_hide(void);
5600
5601/*==============================================================
5602 * PANEL
5603 * =============================================================*/
5604#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS
5605#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16
5606#endif
5607#ifndef NK_CHART_MAX_SLOT
5608#define NK_CHART_MAX_SLOT 4
5609#endif
5610
5611enum nk_panel_type {
5612 NK_PANEL_NONE = 0,
5613 NK_PANEL_WINDOW = NK_FLAG(0),
5614 NK_PANEL_GROUP = NK_FLAG(1),
5615 NK_PANEL_POPUP = NK_FLAG(2),
5616 NK_PANEL_CONTEXTUAL = NK_FLAG(4),
5617 NK_PANEL_COMBO = NK_FLAG(5),
5618 NK_PANEL_MENU = NK_FLAG(6),
5619 NK_PANEL_TOOLTIP = NK_FLAG(7)
5620};
5621enum nk_panel_set {
5622 NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP,
5623 NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP,
5624 NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP
5625};
5626
5628 enum nk_chart_type type;
5629 struct nk_color color;
5630 struct nk_color highlight;
5631 float min, max, range;
5632 int count;
5633 struct nk_vec2 last;
5634 int index;
5635 nk_bool show_markers;
5636};
5637
5638struct nk_chart {
5639 int slot;
5640 float x, y, w, h;
5641 struct nk_chart_slot slots[NK_CHART_MAX_SLOT];
5642};
5643
5644enum nk_panel_row_layout_type {
5645 NK_LAYOUT_DYNAMIC_FIXED = 0,
5646 NK_LAYOUT_DYNAMIC_ROW,
5647 NK_LAYOUT_DYNAMIC_FREE,
5648 NK_LAYOUT_DYNAMIC,
5649 NK_LAYOUT_STATIC_FIXED,
5650 NK_LAYOUT_STATIC_ROW,
5651 NK_LAYOUT_STATIC_FREE,
5652 NK_LAYOUT_STATIC,
5653 NK_LAYOUT_TEMPLATE,
5654 NK_LAYOUT_COUNT
5655};
5657 enum nk_panel_row_layout_type type;
5658 int index;
5659 float height;
5660 float min_height;
5661 int columns;
5662 const float *ratio;
5663 float item_width;
5664 float item_height;
5665 float item_offset;
5666 float filled;
5667 struct nk_rect item;
5668 int tree_depth;
5669 float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS];
5670};
5671
5673 nk_size begin;
5674 nk_size parent;
5675 nk_size last;
5676 nk_size end;
5677 nk_bool active;
5678};
5679
5681 float x, y, w, h;
5682 struct nk_scroll offset;
5683};
5684
5685struct nk_panel {
5686 enum nk_panel_type type;
5687 nk_flags flags;
5688 struct nk_rect bounds;
5689 nk_uint *offset_x;
5690 nk_uint *offset_y;
5691 float at_x, at_y, max_x;
5692 float footer_height;
5693 float header_height;
5694 float border;
5695 unsigned int has_scrolling;
5696 struct nk_rect clip;
5697 struct nk_menu_state menu;
5698 struct nk_row_layout row;
5699 struct nk_chart chart;
5700 struct nk_command_buffer *buffer;
5701 struct nk_panel *parent;
5702};
5703
5704/*==============================================================
5705 * WINDOW
5706 * =============================================================*/
5707#ifndef NK_WINDOW_MAX_NAME
5708#define NK_WINDOW_MAX_NAME 64
5709#endif
5710
5711struct nk_table;
5713 NK_WINDOW_PRIVATE = NK_FLAG(11),
5714 NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE,
5715 NK_WINDOW_ROM = NK_FLAG(12),
5717 NK_WINDOW_HIDDEN = NK_FLAG(13),
5718 NK_WINDOW_CLOSED = NK_FLAG(14),
5719 NK_WINDOW_MINIMIZED = NK_FLAG(15),
5720 NK_WINDOW_REMOVE_ROM = NK_FLAG(16)
5722
5724 struct nk_window *win;
5725 enum nk_panel_type type;
5726 struct nk_popup_buffer buf;
5727 nk_hash name;
5728 nk_bool active;
5729 unsigned combo_count;
5730 unsigned con_count, con_old;
5731 unsigned active_con;
5732 struct nk_rect header;
5733};
5734
5736 nk_hash name;
5737 unsigned int seq;
5738 unsigned int old;
5739 int active, prev;
5740 int cursor;
5741 int sel_start;
5742 int sel_end;
5743 struct nk_scroll scrollbar;
5744 unsigned char mode;
5745 unsigned char single_line;
5746};
5747
5749 int active, prev;
5750 char buffer[NK_MAX_NUMBER_BUFFER];
5751 int length;
5752 int cursor;
5753 int select_start;
5754 int select_end;
5755 nk_hash name;
5756 unsigned int seq;
5757 unsigned int old;
5758 int state;
5759};
5760
5762 unsigned int seq;
5763 nk_hash name;
5764 char name_string[NK_WINDOW_MAX_NAME];
5765 nk_flags flags;
5766
5767 struct nk_rect bounds;
5768 struct nk_scroll scrollbar;
5769 struct nk_command_buffer buffer;
5770 struct nk_panel *layout;
5771 float scrollbar_hiding_timer;
5772
5773 /* persistent widget state */
5774 struct nk_property_state property;
5775 struct nk_popup_state popup;
5776 struct nk_edit_state edit;
5777 unsigned int scrolled;
5778 nk_bool widgets_disabled;
5779
5780 struct nk_table *tables;
5781 unsigned int table_count;
5782
5783 /* window list hooks */
5784 struct nk_window *next;
5785 struct nk_window *prev;
5786 struct nk_window *parent;
5787};
5788
5789/*==============================================================
5790 * STACK
5791 * =============================================================*/
5818#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE
5819#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8
5820#endif
5821
5822#ifndef NK_FONT_STACK_SIZE
5823#define NK_FONT_STACK_SIZE 8
5824#endif
5825
5826#ifndef NK_STYLE_ITEM_STACK_SIZE
5827#define NK_STYLE_ITEM_STACK_SIZE 16
5828#endif
5829
5830#ifndef NK_FLOAT_STACK_SIZE
5831#define NK_FLOAT_STACK_SIZE 32
5832#endif
5833
5834#ifndef NK_VECTOR_STACK_SIZE
5835#define NK_VECTOR_STACK_SIZE 16
5836#endif
5837
5838#ifndef NK_FLAGS_STACK_SIZE
5839#define NK_FLAGS_STACK_SIZE 32
5840#endif
5841
5842#ifndef NK_COLOR_STACK_SIZE
5843#define NK_COLOR_STACK_SIZE 32
5844#endif
5845
5846#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\
5847 struct nk_config_stack_##name##_element {\
5848 prefix##_##type *address;\
5849 prefix##_##type old_value;\
5850 }
5851#define NK_CONFIG_STACK(type,size)\
5852 struct nk_config_stack_##type {\
5853 int head;\
5854 struct nk_config_stack_##type##_element elements[size];\
5855 }
5856
5857#define nk_float float
5858NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item);
5859NK_CONFIGURATION_STACK_TYPE(nk ,float, float);
5860NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2);
5861NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags);
5862NK_CONFIGURATION_STACK_TYPE(struct nk, color, color);
5863NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*);
5864NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior);
5865
5866NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE);
5867NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE);
5868NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE);
5869NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE);
5870NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE);
5871NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE);
5872NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE);
5873
5875 struct nk_config_stack_style_item style_items;
5876 struct nk_config_stack_float floats;
5877 struct nk_config_stack_vec2 vectors;
5878 struct nk_config_stack_flags flags;
5879 struct nk_config_stack_color colors;
5880 struct nk_config_stack_user_font fonts;
5881 struct nk_config_stack_button_behavior button_behaviors;
5882};
5883
5884/*==============================================================
5885 * CONTEXT
5886 * =============================================================*/
5887#define NK_VALUE_PAGE_CAPACITY \
5888 (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2)
5889
5890struct nk_table {
5891 unsigned int seq;
5892 unsigned int size;
5893 nk_hash keys[NK_VALUE_PAGE_CAPACITY];
5894 nk_uint values[NK_VALUE_PAGE_CAPACITY];
5895 struct nk_table *next, *prev;
5896};
5897
5899 struct nk_table tbl;
5900 struct nk_panel pan;
5901 struct nk_window win;
5902};
5903
5905 union nk_page_data data;
5906 struct nk_page_element *next;
5907 struct nk_page_element *prev;
5908};
5909
5910struct nk_page {
5911 unsigned int size;
5912 struct nk_page *next;
5913 struct nk_page_element win[1];
5914};
5915
5916struct nk_pool {
5917 struct nk_allocator alloc;
5918 enum nk_allocation_type type;
5919 unsigned int page_count;
5920 struct nk_page *pages;
5921 struct nk_page_element *freelist;
5922 unsigned capacity;
5923 nk_size size;
5924 nk_size cap;
5925};
5926
5928/* public: can be accessed freely */
5929 struct nk_input input;
5930 struct nk_style style;
5931 struct nk_buffer memory;
5932 struct nk_clipboard clip;
5933 nk_flags last_widget_state;
5934 enum nk_button_behavior button_behavior;
5935 struct nk_configuration_stacks stacks;
5936 float delta_time_seconds;
5937
5938/* private:
5939 should only be accessed if you
5940 know what you are doing */
5941#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
5942 struct nk_draw_list draw_list;
5943#endif
5944#ifdef NK_INCLUDE_COMMAND_USERDATA
5945 nk_handle userdata;
5946#endif
5954
5957 int use_pool;
5958 struct nk_pool pool;
5959 struct nk_window *begin;
5960 struct nk_window *end;
5961 struct nk_window *active;
5962 struct nk_window *current;
5963 struct nk_page_element *freelist;
5964 unsigned int count;
5965 unsigned int seq;
5966};
5967
5968/* ==============================================================
5969 * MATH
5970 * =============================================================== */
5971#define NK_PI 3.141592654f
5972#define NK_PI_HALF 1.570796326f
5973#define NK_UTF_INVALID 0xFFFD
5974#define NK_MAX_FLOAT_PRECISION 2
5975
5976#define NK_UNUSED(x) ((void)(x))
5977#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x)))
5978#define NK_LEN(a) (sizeof(a)/sizeof(a)[0])
5979#define NK_ABS(a) (((a) < 0) ? -(a) : (a))
5980#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b))
5981#define NK_INBOX(px, py, x, y, w, h)\
5982 (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h))
5983#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \
5984 ((x1 < (x0 + w0)) && (x0 < (x1 + w1)) && \
5985 (y1 < (y0 + h0)) && (y0 < (y1 + h1)))
5986#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\
5987 (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh))
5988
5989#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y)
5990#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y)
5991#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y)
5992#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t))
5993
5994#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i))))
5995#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i))))
5996#define nk_zero_struct(s) nk_zero(&s, sizeof(s))
5997
5998/* ==============================================================
5999 * ALIGNMENT
6000 * =============================================================== */
6001/* Pointer to Integer type conversion for pointer alignment */
6002#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/
6003# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x))
6004# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x))
6005#elif !defined(__GNUC__) /* works for compilers other than LLVM */
6006# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x])
6007# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0))
6008#elif defined(NK_USE_FIXED_TYPES) /* used if we have <stdint.h> */
6009# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x))
6010# define NK_PTR_TO_UINT(x) ((uintptr_t)(x))
6011#else /* generates warning but works */
6012# define NK_UINT_TO_PTR(x) ((void*)(x))
6013# define NK_PTR_TO_UINT(x) ((nk_size)(x))
6014#endif
6015
6016#define NK_ALIGN_PTR(x, mask)\
6017 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1))))
6018#define NK_ALIGN_PTR_BACK(x, mask)\
6019 (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1))))
6020
6021#if ((defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)) && !defined(EMSCRIPTEN)
6022#define NK_OFFSETOF(st,m) (__builtin_offsetof(st,m))
6023#else
6024#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m))
6025#endif
6026
6027#ifdef __cplusplus
6028}
6029#endif
6030
6031#ifdef __cplusplus
6032template<typename T> struct nk_alignof;
6033template<typename T, int size_diff> struct nk_helper{enum {value = size_diff};};
6034template<typename T> struct nk_helper<T,0>{enum {value = nk_alignof<T>::value};};
6035template<typename T> struct nk_alignof{struct Big {T x; char c;}; enum {
6036 diff = sizeof(Big) - sizeof(T), value = nk_helper<Big, diff>::value};};
6037#define NK_ALIGNOF(t) (nk_alignof<t>::value)
6038#else
6039#define NK_ALIGNOF(t) NK_OFFSETOF(struct {char c; t _h;}, _h)
6040#endif
6041
6042#define NK_CONTAINER_OF(ptr,type,member)\
6043 (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member)))
6044
6045
6046
6047#endif /* NK_NUKLEAR_H_ */
6048
6049#ifdef NK_IMPLEMENTATION
6050
6051#ifndef NK_INTERNAL_H
6052#define NK_INTERNAL_H
6053
6054#ifndef NK_POOL_DEFAULT_CAPACITY
6055#define NK_POOL_DEFAULT_CAPACITY 16
6056#endif
6057
6058#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE
6059#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)
6060#endif
6061
6062#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE
6063#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)
6064#endif
6065
6066/* standard library headers */
6067#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6068#include <stdlib.h> /* malloc, free */
6069#endif
6070#ifdef NK_INCLUDE_STANDARD_IO
6071#include <stdio.h> /* fopen, fclose,... */
6072#endif
6073#ifdef NK_INCLUDE_STANDARD_VARARGS
6074#include <stdarg.h> /* valist, va_start, va_end, ... */
6075#endif
6076#ifndef NK_ASSERT
6077#include <assert.h>
6078#define NK_ASSERT(expr) assert(expr)
6079#endif
6080
6081#define NK_DEFAULT (-1)
6082
6083#ifndef NK_VSNPRINTF
6084/* If your compiler does support `vsnprintf` I would highly recommend
6085 * defining this to vsnprintf instead since `vsprintf` is basically
6086 * unbelievable unsafe and should *NEVER* be used. But I have to support
6087 * it since C89 only provides this unsafe version. */
6088 #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\
6089 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
6090 (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\
6091 (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\
6092 defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)
6093 #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)
6094 #else
6095 #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)
6096 #endif
6097#endif
6098
6099#define NK_SCHAR_MIN (-127)
6100#define NK_SCHAR_MAX 127
6101#define NK_UCHAR_MIN 0
6102#define NK_UCHAR_MAX 256
6103#define NK_SSHORT_MIN (-32767)
6104#define NK_SSHORT_MAX 32767
6105#define NK_USHORT_MIN 0
6106#define NK_USHORT_MAX 65535
6107#define NK_SINT_MIN (-2147483647)
6108#define NK_SINT_MAX 2147483647
6109#define NK_UINT_MIN 0
6110#define NK_UINT_MAX 4294967295u
6111
6112/* Make sure correct type size:
6113 * This will fire with a negative subscript error if the type sizes
6114 * are set incorrectly by the compiler, and compile out if not */
6115NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));
6116NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));
6117NK_STATIC_ASSERT(sizeof(nk_flags) >= 4);
6118NK_STATIC_ASSERT(sizeof(nk_rune) >= 4);
6119NK_STATIC_ASSERT(sizeof(nk_ushort) == 2);
6120NK_STATIC_ASSERT(sizeof(nk_short) == 2);
6121NK_STATIC_ASSERT(sizeof(nk_uint) == 4);
6122NK_STATIC_ASSERT(sizeof(nk_int) == 4);
6123NK_STATIC_ASSERT(sizeof(nk_byte) == 1);
6124#ifdef NK_INCLUDE_STANDARD_BOOL
6125NK_STATIC_ASSERT(sizeof(nk_bool) == sizeof(bool));
6126#else
6127NK_STATIC_ASSERT(sizeof(nk_bool) == 4);
6128#endif
6129
6130NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};
6131#define NK_FLOAT_PRECISION 0.00000000000001
6132
6133NK_GLOBAL const struct nk_color nk_red = {255,0,0,255};
6134NK_GLOBAL const struct nk_color nk_green = {0,255,0,255};
6135NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};
6136NK_GLOBAL const struct nk_color nk_white = {255,255,255,255};
6137NK_GLOBAL const struct nk_color nk_black = {0,0,0,255};
6138NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};
6139
6140/* widget */
6141#define nk_widget_state_reset(s)\
6142 if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\
6143 (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\
6144 else (*(s)) = NK_WIDGET_STATE_INACTIVE;
6145
6146/* math */
6147#ifndef NK_INV_SQRT
6148NK_LIB float nk_inv_sqrt(float n);
6149#endif
6150#ifndef NK_SIN
6151NK_LIB float nk_sin(float x);
6152#endif
6153#ifndef NK_COS
6154NK_LIB float nk_cos(float x);
6155#endif
6156#ifndef NK_ATAN
6157NK_LIB float nk_atan(float x);
6158#endif
6159#ifndef NK_ATAN2
6160NK_LIB float nk_atan2(float y, float x);
6161#endif
6162NK_LIB nk_uint nk_round_up_pow2(nk_uint v);
6163NK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount);
6164NK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad);
6165NK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1);
6166NK_LIB double nk_pow(double x, int n);
6167NK_LIB int nk_ifloord(double x);
6168NK_LIB int nk_ifloorf(float x);
6169NK_LIB int nk_iceilf(float x);
6170NK_LIB int nk_log10(double n);
6171NK_LIB float nk_roundf(float x);
6172
6173/* util */
6174enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};
6175NK_LIB nk_bool nk_is_lower(int c);
6176NK_LIB nk_bool nk_is_upper(int c);
6177NK_LIB int nk_to_upper(int c);
6178NK_LIB int nk_to_lower(int c);
6179
6180#ifndef NK_MEMCPY
6181NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);
6182#endif
6183#ifndef NK_MEMSET
6184NK_LIB void nk_memset(void *ptr, int c0, nk_size size);
6185#endif
6186NK_LIB void nk_zero(void *ptr, nk_size size);
6187NK_LIB char *nk_itoa(char *s, long n);
6188NK_LIB int nk_string_float_limit(char *string, int prec);
6189#ifndef NK_DTOA
6190NK_LIB char *nk_dtoa(char *s, double n);
6191#endif
6192NK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);
6193NK_LIB struct nk_vec2 nk_text_calculate_text_bounds(const struct nk_user_font *font, const char *begin, int byte_len, float row_height, const char **remaining, struct nk_vec2 *out_offset, int *glyphs, int op);
6194#ifdef NK_INCLUDE_STANDARD_VARARGS
6195NK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args);
6196#endif
6197#ifdef NK_INCLUDE_STANDARD_IO
6198NK_LIB char *nk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc);
6199#endif
6200
6201/* buffer */
6202#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
6203NK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size);
6204NK_LIB void nk_mfree(nk_handle unused, void *ptr);
6205#endif
6206NK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type);
6207NK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align);
6208NK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size);
6209
6210/* draw */
6211NK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip);
6212NK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b);
6213NK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size);
6214NK_LIB void nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, struct nk_rect content, struct nk_color background, struct nk_color foreground, float border_width, const struct nk_user_font *font);
6215
6216/* buffering */
6217NK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
6218NK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win);
6219NK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win);
6220NK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*);
6221NK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
6222NK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w);
6223NK_LIB void nk_build(struct nk_context *ctx);
6224
6225/* text editor */
6226NK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter);
6227NK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
6228NK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
6229NK_LIB void nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, const struct nk_user_font *font, float row_height);
6230
6231/* window */
6232enum nk_window_insert_location {
6233 NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */
6234 NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */
6235};
6236NK_LIB void *nk_create_window(struct nk_context *ctx);
6237NK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);
6238NK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);
6239NK_LIB struct nk_window *nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name);
6240NK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);
6241
6242/* pool */
6243NK_LIB void nk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc, unsigned int capacity);
6244NK_LIB void nk_pool_free(struct nk_pool *pool);
6245NK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size);
6246NK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool);
6247
6248/* page-element */
6249NK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx);
6250NK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem);
6251NK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem);
6252
6253/* table */
6254NK_LIB struct nk_table* nk_create_table(struct nk_context *ctx);
6255NK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
6256NK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
6257NK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);
6258NK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);
6259NK_LIB nk_uint *nk_find_value(const struct nk_window *win, nk_hash name);
6260
6261/* panel */
6262NK_LIB void *nk_create_panel(struct nk_context *ctx);
6263NK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan);
6264NK_LIB nk_bool nk_panel_has_header(nk_flags flags, const char *title);
6265NK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type);
6266NK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type);
6267NK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type);
6268NK_LIB nk_bool nk_panel_is_sub(enum nk_panel_type type);
6269NK_LIB nk_bool nk_panel_is_nonblock(enum nk_panel_type type);
6270NK_LIB nk_bool nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type);
6271NK_LIB void nk_panel_end(struct nk_context *ctx);
6272
6273/* layout */
6274NK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns);
6275NK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols);
6276NK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width);
6277NK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);
6278NK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);
6279NK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);
6280NK_LIB void nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx);
6281
6282/* popup */
6283NK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);
6284
6285/* text */
6286struct nk_text {
6287 struct nk_vec2 padding;
6288 struct nk_color background;
6289 struct nk_color text;
6290};
6291NK_LIB void nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, nk_flags a, const struct nk_user_font *f);
6292NK_LIB void nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, const struct nk_user_font *f);
6293
6294/* button */
6295NK_LIB nk_bool nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior);
6296NK_LIB const struct nk_style_item* nk_draw_button(struct nk_command_buffer *out, const struct nk_rect *bounds, nk_flags state, const struct nk_style_button *style);
6297NK_LIB nk_bool nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, const struct nk_style_button *style, const struct nk_input *in, enum nk_button_behavior behavior, struct nk_rect *content);
6298NK_LIB void nk_draw_button_text(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const char *txt, int len, nk_flags text_alignment, const struct nk_user_font *font);
6299NK_LIB nk_bool nk_do_button_text(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *string, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);
6300NK_LIB void nk_draw_button_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, enum nk_symbol_type type, const struct nk_user_font *font);
6301NK_LIB nk_bool nk_do_button_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);
6302NK_LIB void nk_draw_button_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const struct nk_image *img);
6303NK_LIB nk_bool nk_do_button_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, enum nk_button_behavior b, const struct nk_style_button *style, const struct nk_input *in);
6304NK_LIB void nk_draw_button_text_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, const char *str, int len, enum nk_symbol_type type, const struct nk_user_font *font);
6305NK_LIB nk_bool nk_do_button_text_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, const char *str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);
6306NK_LIB void nk_draw_button_text_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, const char *str, int len, const struct nk_user_font *font, const struct nk_image *img);
6307NK_LIB nk_bool nk_do_button_text_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, const char* str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);
6308
6309/* toggle */
6310enum nk_toggle_type {
6311 NK_TOGGLE_CHECK,
6312 NK_TOGGLE_OPTION
6313};
6314NK_LIB nk_bool nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, nk_bool active);
6315NK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);
6316NK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);
6317NK_LIB nk_bool nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, nk_bool *active, const char *str, int len, enum nk_toggle_type type, const struct nk_style_toggle *style, const struct nk_input *in, const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment);
6318
6319/* progress */
6320NK_LIB nk_size nk_progress_behavior(nk_flags *state, struct nk_input *in, struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable);
6321NK_LIB void nk_draw_progress(struct nk_command_buffer *out, nk_flags state, const struct nk_style_progress *style, const struct nk_rect *bounds, const struct nk_rect *scursor, nk_size value, nk_size max);
6322NK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, nk_bool modifiable, const struct nk_style_progress *style, struct nk_input *in);
6323
6324/* slider */
6325NK_LIB float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps);
6326NK_LIB void nk_draw_slider(struct nk_command_buffer *out, nk_flags state, const struct nk_style_slider *style, const struct nk_rect *bounds, const struct nk_rect *visual_cursor, float min, float value, float max);
6327NK_LIB float nk_do_slider(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, float min, float val, float max, float step, const struct nk_style_slider *style, struct nk_input *in, const struct nk_user_font *font);
6328
6329/* scrollbar */
6330NK_LIB float nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, int has_scrolling, const struct nk_rect *scroll, const struct nk_rect *cursor, const struct nk_rect *empty0, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o);
6331NK_LIB void nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, const struct nk_style_scrollbar *style, const struct nk_rect *bounds, const struct nk_rect *scroll);
6332NK_LIB float nk_do_scrollbarv(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);
6333NK_LIB float nk_do_scrollbarh(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);
6334
6335/* selectable */
6336NK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, nk_bool active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, const char *string, int len, nk_flags align, const struct nk_user_font *font);
6337NK_LIB nk_bool nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
6338NK_LIB nk_bool nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
6339
6340/* edit */
6341NK_LIB void nk_edit_draw_text(struct nk_command_buffer *out, const struct nk_style_edit *style, float pos_x, float pos_y, float x_offset, const char *text, int byte_len, float row_height, const struct nk_user_font *font, struct nk_color background, struct nk_color foreground, nk_bool is_selected);
6342NK_LIB nk_flags nk_do_edit(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, struct nk_text_edit *edit, const struct nk_style_edit *style, struct nk_input *in, const struct nk_user_font *font);
6343
6344/* color-picker */
6345NK_LIB nk_bool nk_color_picker_behavior(nk_flags *state, const struct nk_rect *bounds, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf *color, const struct nk_input *in);
6346NK_LIB void nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf col);
6347NK_LIB nk_bool nk_do_color_picker(nk_flags *state, struct nk_command_buffer *out, struct nk_colorf *col, enum nk_color_format fmt, struct nk_rect bounds, struct nk_vec2 padding, const struct nk_input *in, const struct nk_user_font *font);
6348
6349/* property */
6350enum nk_property_status {
6351 NK_PROPERTY_DEFAULT,
6352 NK_PROPERTY_EDIT,
6353 NK_PROPERTY_DRAG
6354};
6355enum nk_property_filter {
6356 NK_FILTER_INT,
6357 NK_FILTER_FLOAT
6358};
6359enum nk_property_kind {
6360 NK_PROPERTY_INT,
6361 NK_PROPERTY_FLOAT,
6362 NK_PROPERTY_DOUBLE
6363};
6364union nk_property {
6365 int i;
6366 float f;
6367 double d;
6368};
6369struct nk_property_variant {
6370 enum nk_property_kind kind;
6371 union nk_property value;
6372 union nk_property min_value;
6373 union nk_property max_value;
6374 union nk_property step;
6375};
6376NK_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step);
6377NK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step);
6378NK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step);
6379
6380NK_LIB void nk_drag_behavior(nk_flags *state, const struct nk_input *in, struct nk_rect drag, struct nk_property_variant *variant, float inc_per_pixel);
6381NK_LIB void nk_property_behavior(nk_flags *ws, const struct nk_input *in, struct nk_rect property, struct nk_rect label, struct nk_rect edit, struct nk_rect empty, int *state, struct nk_property_variant *variant, float inc_per_pixel);
6382NK_LIB void nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, const char *name, int len, const struct nk_user_font *font);
6383NK_LIB void nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, int *state, int *cursor, int *select_begin, int *select_end, const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, const struct nk_user_font *font, struct nk_text_edit *text_edit, enum nk_button_behavior behavior);
6384NK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, float inc_per_pixel, const enum nk_property_filter filter);
6385
6386#ifdef NK_INCLUDE_FONT_BAKING
6387
6393#ifndef NK_NO_STB_RECT_PACK_IMPLEMENTATION
6394#define STB_RECT_PACK_IMPLEMENTATION
6395#endif /* NK_NO_STB_RECT_PACK_IMPLEMENTATION */
6396
6402#ifndef NK_NO_STB_TRUETYPE_IMPLEMENTATION
6403#define STB_TRUETYPE_IMPLEMENTATION
6404#endif /* NK_NO_STB_TRUETYPE_IMPLEMENTATION */
6405
6406/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */
6407#ifndef STBTT_malloc
6408static void*
6409nk_stbtt_malloc(nk_size size, void *user_data) {
6410 struct nk_allocator *alloc = (struct nk_allocator *) user_data;
6411 return alloc->alloc(alloc->userdata, 0, size);
6412}
6413
6414static void
6415nk_stbtt_free(void *ptr, void *user_data) {
6416 struct nk_allocator *alloc = (struct nk_allocator *) user_data;
6417 alloc->free(alloc->userdata, ptr);
6418}
6419
6420#define STBTT_malloc(x,u) nk_stbtt_malloc(x,u)
6421#define STBTT_free(x,u) nk_stbtt_free(x,u)
6422
6423#endif /* STBTT_malloc */
6424
6425#endif /* NK_INCLUDE_FONT_BAKING */
6426
6427#endif
6428
6429
6430
6431
6432/* ===============================================================
6433 *
6434 * MATH
6435 *
6436 * ===============================================================*/
6437/*/// ### Math
6464*/
6465#ifndef NK_INV_SQRT
6466#define NK_INV_SQRT nk_inv_sqrt
6467NK_LIB float
6468nk_inv_sqrt(float n)
6469{
6470 float x2;
6471 const float threehalfs = 1.5f;
6472 union {nk_uint i; float f;} conv = {0};
6473 conv.f = n;
6474 x2 = n * 0.5f;
6475 conv.i = 0x5f375A84 - (conv.i >> 1);
6476 conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
6477 return conv.f;
6478}
6479#endif
6480#ifndef NK_SIN
6481#define NK_SIN nk_sin
6482NK_LIB float
6483nk_sin(float x)
6484{
6485 NK_STORAGE const float a0 = +1.91059300966915117e-31f;
6486 NK_STORAGE const float a1 = +1.00086760103908896f;
6487 NK_STORAGE const float a2 = -1.21276126894734565e-2f;
6488 NK_STORAGE const float a3 = -1.38078780785773762e-1f;
6489 NK_STORAGE const float a4 = -2.67353392911981221e-2f;
6490 NK_STORAGE const float a5 = +2.08026600266304389e-2f;
6491 NK_STORAGE const float a6 = -3.03996055049204407e-3f;
6492 NK_STORAGE const float a7 = +1.38235642404333740e-4f;
6493 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
6494}
6495#endif
6496#ifndef NK_COS
6497#define NK_COS nk_cos
6498NK_LIB float
6499nk_cos(float x)
6500{
6501 /* New implementation. Also generated using lolremez. */
6502 /* Old version significantly deviated from expected results. */
6503 NK_STORAGE const float a0 = 9.9995999154986614e-1f;
6504 NK_STORAGE const float a1 = 1.2548995793001028e-3f;
6505 NK_STORAGE const float a2 = -5.0648546280678015e-1f;
6506 NK_STORAGE const float a3 = 1.2942246466519995e-2f;
6507 NK_STORAGE const float a4 = 2.8668384702547972e-2f;
6508 NK_STORAGE const float a5 = 7.3726485210586547e-3f;
6509 NK_STORAGE const float a6 = -3.8510875386947414e-3f;
6510 NK_STORAGE const float a7 = 4.7196604604366623e-4f;
6511 NK_STORAGE const float a8 = -1.8776444013090451e-5f;
6512 return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));
6513}
6514#endif
6515#ifndef NK_ATAN
6516#define NK_ATAN nk_atan
6517NK_LIB float
6518nk_atan(float x)
6519{
6520 /* ./lolremez --progress --float -d 9 -r "0:pi*2" "atan(x)" */
6521 float u = -1.0989005e-05f;
6522 NK_ASSERT(x >= 0.0f && "TODO support negative floats");
6523 u = u * x + 0.00034117949f;
6524 u = u * x + -0.0044932296f;
6525 u = u * x + 0.032596264f;
6526 u = u * x + -0.14088021f;
6527 u = u * x + 0.36040401f;
6528 u = u * x + -0.47017866f;
6529 u = u * x + 0.00050198776f;
6530 u = u * x + 1.0077682f;
6531 u = u * x + -0.0004765437f;
6532 return u;
6533}
6534#endif
6535#ifndef NK_ATAN2
6536#define NK_ATAN2 nk_atan2
6537NK_LIB float
6538nk_atan2(float y, float x)
6539{
6540 float ax = NK_ABS(x),
6541 ay = NK_ABS(y);
6542 /* 0 = +y +x 1 = -y +x
6543 2 = +y -x 3 = -y -x */
6544 nk_uint signs = (y < 0) | ((x < 0) << 1);
6545
6546 float a;
6547 if(y == 0.0 && x == 0.0) return 0.0f;
6548 a = (ay > ax)
6549 ? NK_PI_HALF - NK_ATAN(ax / ay)
6550 : NK_ATAN(ay / ax);
6551
6552 switch(signs){
6553 case 0: return a;
6554 case 1: return -a;
6555 case 2: return -a + NK_PI;
6556 case 3: return a - NK_PI;
6557 }
6558 return 0.0f; /* prevents warning */
6559}
6560#endif
6561NK_LIB nk_uint
6562nk_round_up_pow2(nk_uint v)
6563{
6564 v--;
6565 v |= v >> 1;
6566 v |= v >> 2;
6567 v |= v >> 4;
6568 v |= v >> 8;
6569 v |= v >> 16;
6570 v++;
6571 return v;
6572}
6573NK_LIB double
6574nk_pow(double x, int n)
6575{
6576 /* check the sign of n */
6577 double r = 1;
6578 int plus = n >= 0;
6579 n = (plus) ? n : -n;
6580 while (n > 0) {
6581 if ((n & 1) == 1)
6582 r *= x;
6583 n /= 2;
6584 x *= x;
6585 }
6586 return plus ? r : 1.0 / r;
6587}
6588NK_LIB int
6589nk_ifloord(double x)
6590{
6591 x = (double)((int)x - ((x < 0.0) ? 1 : 0));
6592 return (int)x;
6593}
6594NK_LIB int
6595nk_ifloorf(float x)
6596{
6597 x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
6598 return (int)x;
6599}
6600NK_LIB int
6601nk_iceilf(float x)
6602{
6603 if (x >= 0) {
6604 int i = (int)x;
6605 return (x > i) ? i+1: i;
6606 } else {
6607 int t = (int)x;
6608 float r = x - (float)t;
6609 return (r > 0.0f) ? t+1: t;
6610 }
6611}
6612NK_LIB int
6613nk_log10(double n)
6614{
6615 int neg;
6616 int ret;
6617 int exp = 0;
6618
6619 neg = (n < 0) ? 1 : 0;
6620 ret = (neg) ? (int)-n : (int)n;
6621 while ((ret / 10) > 0) {
6622 ret /= 10;
6623 exp++;
6624 }
6625 if (neg) exp = -exp;
6626 return exp;
6627}
6628NK_LIB float
6629nk_roundf(float x)
6630{
6631 return (x >= 0.0f) ? (float)nk_ifloorf(x + 0.5f) : (float)nk_iceilf(x - 0.5f);
6632}
6633NK_API struct nk_rect
6634nk_get_null_rect(void)
6635{
6636 return nk_null_rect;
6637}
6638NK_API struct nk_rect
6639nk_rect(float x, float y, float w, float h)
6640{
6641 struct nk_rect r;
6642 r.x = x; r.y = y;
6643 r.w = w; r.h = h;
6644 return r;
6645}
6646NK_API struct nk_rect
6647nk_recti(int x, int y, int w, int h)
6648{
6649 struct nk_rect r;
6650 r.x = (float)x;
6651 r.y = (float)y;
6652 r.w = (float)w;
6653 r.h = (float)h;
6654 return r;
6655}
6656NK_API struct nk_rect
6657nk_recta(struct nk_vec2 pos, struct nk_vec2 size)
6658{
6659 return nk_rect(pos.x, pos.y, size.x, size.y);
6660}
6661NK_API struct nk_rect
6662nk_rectv(const float *r)
6663{
6664 return nk_rect(r[0], r[1], r[2], r[3]);
6665}
6666NK_API struct nk_rect
6667nk_rectiv(const int *r)
6668{
6669 return nk_recti(r[0], r[1], r[2], r[3]);
6670}
6671NK_API struct nk_vec2
6672nk_rect_pos(struct nk_rect r)
6673{
6674 struct nk_vec2 ret;
6675 ret.x = r.x; ret.y = r.y;
6676 return ret;
6677}
6678NK_API struct nk_vec2
6679nk_rect_size(struct nk_rect r)
6680{
6681 struct nk_vec2 ret;
6682 ret.x = r.w; ret.y = r.h;
6683 return ret;
6684}
6685NK_LIB struct nk_rect
6686nk_shrink_rect(struct nk_rect r, float amount)
6687{
6688 struct nk_rect res;
6689 r.w = NK_MAX(r.w, 2 * amount);
6690 r.h = NK_MAX(r.h, 2 * amount);
6691 res.x = r.x + amount;
6692 res.y = r.y + amount;
6693 res.w = r.w - 2 * amount;
6694 res.h = r.h - 2 * amount;
6695 return res;
6696}
6697NK_LIB struct nk_rect
6698nk_pad_rect(struct nk_rect r, struct nk_vec2 pad)
6699{
6700 r.w = NK_MAX(r.w, 2 * pad.x);
6701 r.h = NK_MAX(r.h, 2 * pad.y);
6702 r.x += pad.x; r.y += pad.y;
6703 r.w -= 2 * pad.x;
6704 r.h -= 2 * pad.y;
6705 return r;
6706}
6707NK_API struct nk_vec2
6708nk_vec2(float x, float y)
6709{
6710 struct nk_vec2 ret;
6711 ret.x = x; ret.y = y;
6712 return ret;
6713}
6714NK_API struct nk_vec2
6715nk_vec2i(int x, int y)
6716{
6717 struct nk_vec2 ret;
6718 ret.x = (float)x;
6719 ret.y = (float)y;
6720 return ret;
6721}
6722NK_API struct nk_vec2
6723nk_vec2v(const float *v)
6724{
6725 return nk_vec2(v[0], v[1]);
6726}
6727NK_API struct nk_vec2
6728nk_vec2iv(const int *v)
6729{
6730 return nk_vec2i(v[0], v[1]);
6731}
6732NK_LIB void
6733nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,
6734 float x1, float y1)
6735{
6736 NK_ASSERT(a);
6737 NK_ASSERT(clip);
6738 clip->x = NK_MAX(a->x, x0);
6739 clip->y = NK_MAX(a->y, y0);
6740 clip->w = NK_MIN(a->x + a->w, x1) - clip->x;
6741 clip->h = NK_MIN(a->y + a->h, y1) - clip->y;
6742 clip->w = NK_MAX(0, clip->w);
6743 clip->h = NK_MAX(0, clip->h);
6744}
6745
6746NK_API void
6747nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,
6748 float pad_x, float pad_y, enum nk_heading direction)
6749{
6750 float w_half, h_half;
6751 NK_ASSERT(result);
6752
6753 r.w = NK_MAX(2 * pad_x, r.w);
6754 r.h = NK_MAX(2 * pad_y, r.h);
6755 r.w = r.w - 2 * pad_x;
6756 r.h = r.h - 2 * pad_y;
6757
6758 r.x = r.x + pad_x;
6759 r.y = r.y + pad_y;
6760
6761 w_half = r.w / 2.0f;
6762 h_half = r.h / 2.0f;
6763
6764 if (direction == NK_UP) {
6765 result[0] = nk_vec2(r.x + w_half, r.y);
6766 result[1] = nk_vec2(r.x + r.w, r.y + r.h);
6767 result[2] = nk_vec2(r.x, r.y + r.h);
6768 } else if (direction == NK_RIGHT) {
6769 result[0] = nk_vec2(r.x, r.y);
6770 result[1] = nk_vec2(r.x + r.w, r.y + h_half);
6771 result[2] = nk_vec2(r.x, r.y + r.h);
6772 } else if (direction == NK_DOWN) {
6773 result[0] = nk_vec2(r.x, r.y);
6774 result[1] = nk_vec2(r.x + r.w, r.y);
6775 result[2] = nk_vec2(r.x + w_half, r.y + r.h);
6776 } else {
6777 result[0] = nk_vec2(r.x, r.y + h_half);
6778 result[1] = nk_vec2(r.x + r.w, r.y);
6779 result[2] = nk_vec2(r.x + r.w, r.y + r.h);
6780 }
6781}
6782
6783
6784
6785
6786
6787/* ===============================================================
6788 *
6789 * UTIL
6790 *
6791 * ===============================================================*/
6792NK_INTERN int nk_str_match_here(const char *regexp, const char *text);
6793NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);
6794NK_LIB nk_bool nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}
6795NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}
6796NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
6797NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}
6798
6799#ifndef NK_MEMCPY
6800#define NK_MEMCPY nk_memcopy
6801NK_LIB void*
6802nk_memcopy(void *dst0, const void *src0, nk_size length)
6803{
6804 nk_ptr t;
6805 char *dst = (char*)dst0;
6806 const char *src = (const char*)src0;
6807 if (length == 0 || dst == src)
6808 goto done;
6809
6810 #define nk_word int
6811 #define nk_wsize sizeof(nk_word)
6812 #define nk_wmask (nk_wsize-1)
6813 #define NK_TLOOP(s) if (t) NK_TLOOP1(s)
6814 #define NK_TLOOP1(s) do { s; } while (--t)
6815
6816 if (dst < src) {
6817 t = (nk_ptr)src; /* only need low bits */
6818 if ((t | (nk_ptr)dst) & nk_wmask) {
6819 if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)
6820 t = length;
6821 else
6822 t = nk_wsize - (t & nk_wmask);
6823 length -= t;
6824 NK_TLOOP1(*dst++ = *src++);
6825 }
6826 t = length / nk_wsize;
6827 NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;
6828 src += nk_wsize; dst += nk_wsize);
6829 t = length & nk_wmask;
6830 NK_TLOOP(*dst++ = *src++);
6831 } else {
6832 src += length;
6833 dst += length;
6834 t = (nk_ptr)src;
6835 if ((t | (nk_ptr)dst) & nk_wmask) {
6836 if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)
6837 t = length;
6838 else
6839 t &= nk_wmask;
6840 length -= t;
6841 NK_TLOOP1(*--dst = *--src);
6842 }
6843 t = length / nk_wsize;
6844 NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;
6845 *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);
6846 t = length & nk_wmask;
6847 NK_TLOOP(*--dst = *--src);
6848 }
6849 #undef nk_word
6850 #undef nk_wsize
6851 #undef nk_wmask
6852 #undef NK_TLOOP
6853 #undef NK_TLOOP1
6854done:
6855 return (dst0);
6856}
6857#endif
6858#ifndef NK_MEMSET
6859#define NK_MEMSET nk_memset
6860NK_LIB void
6861nk_memset(void *ptr, int c0, nk_size size)
6862{
6863 #define nk_word unsigned
6864 #define nk_wsize sizeof(nk_word)
6865 #define nk_wmask (nk_wsize - 1)
6866 nk_byte *dst = (nk_byte*)ptr;
6867 unsigned c = 0;
6868 nk_size t = 0;
6869
6870 if ((c = (nk_byte)c0) != 0) {
6871 c = (c << 8) | c; /* at least 16-bits */
6872 if (sizeof(unsigned int) > 2)
6873 c = (c << 16) | c; /* at least 32-bits*/
6874 }
6875
6876 /* too small of a word count */
6877 dst = (nk_byte*)ptr;
6878 if (size < 3 * nk_wsize) {
6879 while (size--) *dst++ = (nk_byte)c0;
6880 return;
6881 }
6882
6883 /* align destination */
6884 if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {
6885 t = nk_wsize -t;
6886 size -= t;
6887 do {
6888 *dst++ = (nk_byte)c0;
6889 } while (--t != 0);
6890 }
6891
6892 /* fill word */
6893 t = size / nk_wsize;
6894 do {
6895 *(nk_word*)((void*)dst) = c;
6896 dst += nk_wsize;
6897 } while (--t != 0);
6898
6899 /* fill trailing bytes */
6900 t = (size & nk_wmask);
6901 if (t != 0) {
6902 do {
6903 *dst++ = (nk_byte)c0;
6904 } while (--t != 0);
6905 }
6906
6907 #undef nk_word
6908 #undef nk_wsize
6909 #undef nk_wmask
6910}
6911#endif
6912NK_LIB void
6913nk_zero(void *ptr, nk_size size)
6914{
6915 NK_ASSERT(ptr);
6916 NK_MEMSET(ptr, 0, size);
6917}
6918NK_API int
6919nk_strlen(const char *str)
6920{
6921 int siz = 0;
6922 NK_ASSERT(str);
6923 while (str && *str++ != '\0') siz++;
6924 return siz;
6925}
6926NK_API int
6927nk_strtoi(const char *str, char **endptr)
6928{
6929 int neg = 1;
6930 const char *p = str;
6931 int value = 0;
6932
6933 NK_ASSERT(str);
6934 if (!str) return 0;
6935
6936 /* skip whitespace */
6937 while (*p == ' ') p++;
6938 if (*p == '-') {
6939 neg = -1;
6940 p++;
6941 }
6942 while (*p && *p >= '0' && *p <= '9') {
6943 value = value * 10 + (int) (*p - '0');
6944 p++;
6945 }
6946 if (endptr)
6947 *endptr = (char *)p;
6948 return neg*value;
6949}
6950NK_API double
6951nk_strtod(const char *str, char **endptr)
6952{
6953 double m;
6954 double neg = 1.0;
6955 char *p = (char *)str;
6956 double value = 0;
6957 double number = 0;
6958
6959 NK_ASSERT(str);
6960 if (!str) return 0;
6961
6962 /* skip whitespace */
6963 while (*p == ' ') p++;
6964 if (*p == '-') {
6965 neg = -1.0;
6966 p++;
6967 }
6968
6969 while (*p && *p != '.' && *p != 'e') {
6970 value = value * 10.0 + (double) (*p - '0');
6971 p++;
6972 }
6973
6974 if (*p == '.') {
6975 p++;
6976 for(m = 0.1; *p && *p != 'e'; p++ ) {
6977 value = value + (double) (*p - '0') * m;
6978 m *= 0.1;
6979 }
6980 }
6981 if (*p == 'e') {
6982 int i, pow, div;
6983 p++;
6984 if (*p == '-') {
6985 div = nk_true;
6986 p++;
6987 } else if (*p == '+') {
6988 div = nk_false;
6989 p++;
6990 } else div = nk_false;
6991
6992 for (pow = 0; *p; p++)
6993 pow = pow * 10 + (int) (*p - '0');
6994
6995 for (m = 1.0, i = 0; i < pow; i++)
6996 m *= 10.0;
6997
6998 if (div)
6999 value /= m;
7000 else value *= m;
7001 }
7002 number = value * neg;
7003 if (endptr)
7004 *endptr = p;
7005 return number;
7006}
7007NK_API float
7008nk_strtof(const char *str, char **endptr)
7009{
7010 float float_value;
7011 double double_value;
7012 double_value = NK_STRTOD(str, endptr);
7013 float_value = (float)double_value;
7014 return float_value;
7015}
7016NK_API int
7017nk_stricmp(const char *s1, const char *s2)
7018{
7019 nk_int c1,c2,d;
7020 do {
7021 c1 = *s1++;
7022 c2 = *s2++;
7023 d = c1 - c2;
7024 while (d) {
7025 if (c1 <= 'Z' && c1 >= 'A') {
7026 d += ('a' - 'A');
7027 if (!d) break;
7028 }
7029 if (c2 <= 'Z' && c2 >= 'A') {
7030 d -= ('a' - 'A');
7031 if (!d) break;
7032 }
7033 return ((d >= 0) << 1) - 1;
7034 }
7035 } while (c1);
7036 return 0;
7037}
7038NK_API int
7039nk_stricmpn(const char *s1, const char *s2, int n)
7040{
7041 int c1,c2,d;
7042 NK_ASSERT(n >= 0);
7043 do {
7044 c1 = *s1++;
7045 c2 = *s2++;
7046 if (!n--) return 0;
7047
7048 d = c1 - c2;
7049 while (d) {
7050 if (c1 <= 'Z' && c1 >= 'A') {
7051 d += ('a' - 'A');
7052 if (!d) break;
7053 }
7054 if (c2 <= 'Z' && c2 >= 'A') {
7055 d -= ('a' - 'A');
7056 if (!d) break;
7057 }
7058 return ((d >= 0) << 1) - 1;
7059 }
7060 } while (c1);
7061 return 0;
7062}
7063NK_INTERN int
7064nk_str_match_here(const char *regexp, const char *text)
7065{
7066 if (regexp[0] == '\0')
7067 return 1;
7068 if (regexp[1] == '*')
7069 return nk_str_match_star(regexp[0], regexp+2, text);
7070 if (regexp[0] == '$' && regexp[1] == '\0')
7071 return *text == '\0';
7072 if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
7073 return nk_str_match_here(regexp+1, text+1);
7074 return 0;
7075}
7076NK_INTERN int
7077nk_str_match_star(int c, const char *regexp, const char *text)
7078{
7079 do {/* a '* matches zero or more instances */
7080 if (nk_str_match_here(regexp, text))
7081 return 1;
7082 } while (*text != '\0' && (*text++ == c || c == '.'));
7083 return 0;
7084}
7085NK_API int
7086nk_strfilter(const char *text, const char *regexp)
7087{
7088 /*
7089 c matches any literal character c
7090 . matches any single character
7091 ^ matches the beginning of the input string
7092 $ matches the end of the input string
7093 * matches zero or more occurrences of the previous character*/
7094 if (regexp[0] == '^')
7095 return nk_str_match_here(regexp+1, text);
7096 do { /* must look even if string is empty */
7097 if (nk_str_match_here(regexp, text))
7098 return 1;
7099 } while (*text++ != '\0');
7100 return 0;
7101}
7102NK_API int
7103nk_strmatch_fuzzy_text(const char *str, int str_len,
7104 const char *pattern, int *out_score)
7105{
7106 /* Returns true if each character in pattern is found sequentially within str
7107 * if found then out_score is also set. Score value has no intrinsic meaning.
7108 * Range varies with pattern. Can only compare scores with same search pattern. */
7109
7110 /* bonus for adjacent matches */
7111 #define NK_ADJACENCY_BONUS 5
7112 /* bonus if match occurs after a separator */
7113 #define NK_SEPARATOR_BONUS 10
7114 /* bonus if match is uppercase and prev is lower */
7115 #define NK_CAMEL_BONUS 10
7116 /* penalty applied for every letter in str before the first match */
7117 #define NK_LEADING_LETTER_PENALTY (-3)
7118 /* maximum penalty for leading letters */
7119 #define NK_MAX_LEADING_LETTER_PENALTY (-9)
7120 /* penalty for every letter that doesn't matter */
7121 #define NK_UNMATCHED_LETTER_PENALTY (-1)
7122
7123 /* loop variables */
7124 int score = 0;
7125 char const * pattern_iter = pattern;
7126 int str_iter = 0;
7127 int prev_matched = nk_false;
7128 int prev_lower = nk_false;
7129 /* true so if first letter match gets separator bonus*/
7130 int prev_separator = nk_true;
7131
7132 /* use "best" matched letter if multiple string letters match the pattern */
7133 char const * best_letter = 0;
7134 int best_letter_score = 0;
7135
7136 /* loop over strings */
7137 NK_ASSERT(str);
7138 NK_ASSERT(pattern);
7139 if (!str || !str_len || !pattern) return 0;
7140 while (str_iter < str_len)
7141 {
7142 const char pattern_letter = *pattern_iter;
7143 const char str_letter = str[str_iter];
7144
7145 int next_match = *pattern_iter != '\0' &&
7146 nk_to_lower(pattern_letter) == nk_to_lower(str_letter);
7147 int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);
7148
7149 int advanced = next_match && best_letter;
7150 int pattern_repeat = best_letter && *pattern_iter != '\0';
7151 pattern_repeat = pattern_repeat &&
7152 nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);
7153
7154 if (advanced || pattern_repeat) {
7155 score += best_letter_score;
7156 best_letter = 0;
7157 best_letter_score = 0;
7158 }
7159
7160 if (next_match || rematch)
7161 {
7162 int new_score = 0;
7163 /* Apply penalty for each letter before the first pattern match */
7164 if (pattern_iter == pattern) {
7165 int count = (int)(&str[str_iter] - str);
7166 int penalty = NK_LEADING_LETTER_PENALTY * count;
7167 if (penalty < NK_MAX_LEADING_LETTER_PENALTY)
7168 penalty = NK_MAX_LEADING_LETTER_PENALTY;
7169
7170 score += penalty;
7171 }
7172
7173 /* apply bonus for consecutive bonuses */
7174 if (prev_matched)
7175 new_score += NK_ADJACENCY_BONUS;
7176
7177 /* apply bonus for matches after a separator */
7178 if (prev_separator)
7179 new_score += NK_SEPARATOR_BONUS;
7180
7181 /* apply bonus across camel case boundaries */
7182 if (prev_lower && nk_is_upper(str_letter))
7183 new_score += NK_CAMEL_BONUS;
7184
7185 /* update pattern iter IFF the next pattern letter was matched */
7186 if (next_match)
7187 ++pattern_iter;
7188
7189 /* update best letter in str which may be for a "next" letter or a rematch */
7190 if (new_score >= best_letter_score) {
7191 /* apply penalty for now skipped letter */
7192 if (best_letter != 0)
7193 score += NK_UNMATCHED_LETTER_PENALTY;
7194
7195 best_letter = &str[str_iter];
7196 best_letter_score = new_score;
7197 }
7198 prev_matched = nk_true;
7199 } else {
7200 score += NK_UNMATCHED_LETTER_PENALTY;
7201 prev_matched = nk_false;
7202 }
7203
7204 /* separators should be more easily defined */
7205 prev_lower = nk_is_lower(str_letter) != 0;
7206 prev_separator = str_letter == '_' || str_letter == ' ';
7207
7208 ++str_iter;
7209 }
7210
7211 /* apply score for last match */
7212 if (best_letter)
7213 score += best_letter_score;
7214
7215 /* did not match full pattern */
7216 if (*pattern_iter != '\0')
7217 return nk_false;
7218
7219 if (out_score)
7220 *out_score = score;
7221 return nk_true;
7222}
7223NK_API int
7224nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)
7225{
7226 return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);
7227}
7228NK_LIB int
7229nk_string_float_limit(char *string, int prec)
7230{
7231 int dot = 0;
7232 char *c = string;
7233 while (*c) {
7234 if (*c == '.') {
7235 dot = 1;
7236 c++;
7237 continue;
7238 }
7239 if (dot == (prec+1)) {
7240 *c = 0;
7241 break;
7242 }
7243 if (dot > 0) dot++;
7244 c++;
7245 }
7246 return (int)(c - string);
7247}
7248NK_INTERN void
7249nk_strrev_ascii(char *s)
7250{
7251 int len = nk_strlen(s);
7252 int end = len / 2;
7253 int i = 0;
7254 char t;
7255 for (; i < end; ++i) {
7256 t = s[i];
7257 s[i] = s[len - 1 - i];
7258 s[len -1 - i] = t;
7259 }
7260}
7261NK_LIB char*
7262nk_itoa(char *s, long n)
7263{
7264 long i = 0;
7265 if (n == 0) {
7266 s[i++] = '0';
7267 s[i] = 0;
7268 return s;
7269 }
7270 if (n < 0) {
7271 s[i++] = '-';
7272 n = -n;
7273 }
7274 while (n > 0) {
7275 s[i++] = (char)('0' + (n % 10));
7276 n /= 10;
7277 }
7278 s[i] = 0;
7279 if (s[0] == '-')
7280 ++s;
7281
7282 nk_strrev_ascii(s);
7283 return s;
7284}
7285#ifndef NK_DTOA
7286#define NK_DTOA nk_dtoa
7287NK_LIB char*
7288nk_dtoa(char *s, double n)
7289{
7290 int useExp = 0;
7291 int digit = 0, m = 0, m1 = 0;
7292 char *c = s;
7293 int neg = 0;
7294
7295 NK_ASSERT(s);
7296 if (!s) return 0;
7297
7298 if (n == 0.0) {
7299 s[0] = '0'; s[1] = '\0';
7300 return s;
7301 }
7302
7303 neg = (n < 0);
7304 if (neg) n = -n;
7305
7306 /* calculate magnitude */
7307 m = nk_log10(n);
7308 useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
7309 if (neg) *(c++) = '-';
7310
7311 /* set up for scientific notation */
7312 if (useExp) {
7313 if (m < 0)
7314 m -= 1;
7315 n = n / (double)nk_pow(10.0, m);
7316 m1 = m;
7317 m = 0;
7318 }
7319 if (m < 1.0) {
7320 m = 0;
7321 }
7322
7323 /* convert the number */
7324 while (n > NK_FLOAT_PRECISION || m >= 0) {
7325 double weight = nk_pow(10.0, m);
7326 if (weight > 0) {
7327 double t = (double)n / weight;
7328 digit = nk_ifloord(t);
7329 n -= ((double)digit * weight);
7330 *(c++) = (char)('0' + (char)digit);
7331 }
7332 if (m == 0 && n > 0)
7333 *(c++) = '.';
7334 m--;
7335 }
7336
7337 if (useExp) {
7338 /* convert the exponent */
7339 int i, j;
7340 *(c++) = 'e';
7341 if (m1 > 0) {
7342 *(c++) = '+';
7343 } else {
7344 *(c++) = '-';
7345 m1 = -m1;
7346 }
7347 m = 0;
7348 while (m1 > 0) {
7349 *(c++) = (char)('0' + (char)(m1 % 10));
7350 m1 /= 10;
7351 m++;
7352 }
7353 c -= m;
7354 for (i = 0, j = m-1; i<j; i++, j--) {
7355 /* swap without temporary */
7356 c[i] ^= c[j];
7357 c[j] ^= c[i];
7358 c[i] ^= c[j];
7359 }
7360 c += m;
7361 }
7362 *(c) = '\0';
7363 return s;
7364}
7365#endif
7366#ifdef NK_INCLUDE_STANDARD_VARARGS
7367#ifndef NK_INCLUDE_STANDARD_IO
7368NK_INTERN int
7369nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)
7370{
7371 enum nk_arg_type {
7372 NK_ARG_TYPE_CHAR,
7373 NK_ARG_TYPE_SHORT,
7374 NK_ARG_TYPE_DEFAULT,
7375 NK_ARG_TYPE_LONG
7376 };
7377 enum nk_arg_flags {
7378 NK_ARG_FLAG_LEFT = 0x01,
7379 NK_ARG_FLAG_PLUS = 0x02,
7380 NK_ARG_FLAG_SPACE = 0x04,
7381 NK_ARG_FLAG_NUM = 0x10,
7382 NK_ARG_FLAG_ZERO = 0x20
7383 };
7384
7385 char number_buffer[NK_MAX_NUMBER_BUFFER];
7386 enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;
7387 int precision = NK_DEFAULT;
7388 int width = NK_DEFAULT;
7389 nk_flags flag = 0;
7390
7391 int len = 0;
7392 int result = -1;
7393 const char *iter = fmt;
7394
7395 NK_ASSERT(buf);
7396 NK_ASSERT(buf_size);
7397 if (!buf || !buf_size || !fmt) return 0;
7398 for (iter = fmt; *iter && len < buf_size; iter++) {
7399 /* copy all non-format characters */
7400 while (*iter && (*iter != '%') && (len < buf_size))
7401 buf[len++] = *iter++;
7402 if (!(*iter) || len >= buf_size) break;
7403 iter++;
7404
7405 /* flag arguments */
7406 while (*iter) {
7407 if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;
7408 else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;
7409 else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;
7410 else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;
7411 else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;
7412 else break;
7413 iter++;
7414 }
7415
7416 /* width argument */
7417 width = NK_DEFAULT;
7418 if (*iter >= '1' && *iter <= '9') {
7419 char *end;
7420 width = nk_strtoi(iter, &end);
7421 if (end == iter)
7422 width = -1;
7423 else iter = end;
7424 } else if (*iter == '*') {
7425 width = va_arg(args, int);
7426 iter++;
7427 }
7428
7429 /* precision argument */
7430 precision = NK_DEFAULT;
7431 if (*iter == '.') {
7432 iter++;
7433 if (*iter == '*') {
7434 precision = va_arg(args, int);
7435 iter++;
7436 } else {
7437 char *end;
7438 precision = nk_strtoi(iter, &end);
7439 if (end == iter)
7440 precision = -1;
7441 else iter = end;
7442 }
7443 }
7444
7445 /* length modifier */
7446 if (*iter == 'h') {
7447 if (*(iter+1) == 'h') {
7448 arg_type = NK_ARG_TYPE_CHAR;
7449 iter++;
7450 } else arg_type = NK_ARG_TYPE_SHORT;
7451 iter++;
7452 } else if (*iter == 'l') {
7453 arg_type = NK_ARG_TYPE_LONG;
7454 iter++;
7455 } else arg_type = NK_ARG_TYPE_DEFAULT;
7456
7457 /* specifier */
7458 if (*iter == '%') {
7459 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
7460 NK_ASSERT(precision == NK_DEFAULT);
7461 NK_ASSERT(width == NK_DEFAULT);
7462 if (len < buf_size)
7463 buf[len++] = '%';
7464 } else if (*iter == 's') {
7465 /* string */
7466 const char *str = va_arg(args, const char*);
7467 NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!");
7468 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
7469 NK_ASSERT(precision == NK_DEFAULT);
7470 NK_ASSERT(width == NK_DEFAULT);
7471 if (str == buf) return -1;
7472 while (str && *str && len < buf_size)
7473 buf[len++] = *str++;
7474 } else if (*iter == 'n') {
7475 /* current length callback */
7476 signed int *n = va_arg(args, int*);
7477 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
7478 NK_ASSERT(precision == NK_DEFAULT);
7479 NK_ASSERT(width == NK_DEFAULT);
7480 if (n) *n = len;
7481 } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {
7482 /* signed integer */
7483 long value = 0;
7484 const char *num_iter;
7485 int num_len, num_print, padding;
7486 int cur_precision = NK_MAX(precision, 1);
7487 int cur_width = NK_MAX(width, 0);
7488
7489 /* retrieve correct value type */
7490 if (arg_type == NK_ARG_TYPE_CHAR)
7491 value = (signed char)va_arg(args, int);
7492 else if (arg_type == NK_ARG_TYPE_SHORT)
7493 value = (signed short)va_arg(args, int);
7494 else if (arg_type == NK_ARG_TYPE_LONG)
7495 value = va_arg(args, signed long);
7496 else if (*iter == 'c')
7497 value = (unsigned char)va_arg(args, int);
7498 else value = va_arg(args, signed int);
7499
7500 /* convert number to string */
7501 nk_itoa(number_buffer, value);
7502 num_len = nk_strlen(number_buffer);
7503 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
7504 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
7505 padding = NK_MAX(padding-1, 0);
7506
7507 /* fill left padding up to a total of `width` characters */
7508 if (!(flag & NK_ARG_FLAG_LEFT)) {
7509 while (padding-- > 0 && (len < buf_size)) {
7510 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
7511 buf[len++] = '0';
7512 else buf[len++] = ' ';
7513 }
7514 }
7515
7516 /* copy string value representation into buffer */
7517 if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)
7518 buf[len++] = '+';
7519 else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)
7520 buf[len++] = ' ';
7521
7522 /* fill up to precision number of digits with '0' */
7523 num_print = NK_MAX(cur_precision, num_len);
7524 while (precision && (num_print > num_len) && (len < buf_size)) {
7525 buf[len++] = '0';
7526 num_print--;
7527 }
7528
7529 /* copy string value representation into buffer */
7530 num_iter = number_buffer;
7531 while (precision && *num_iter && len < buf_size)
7532 buf[len++] = *num_iter++;
7533
7534 /* fill right padding up to width characters */
7535 if (flag & NK_ARG_FLAG_LEFT) {
7536 while ((padding-- > 0) && (len < buf_size))
7537 buf[len++] = ' ';
7538 }
7539 } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {
7540 /* unsigned integer */
7541 unsigned long value = 0;
7542 int num_len = 0, num_print, padding = 0;
7543 int cur_precision = NK_MAX(precision, 1);
7544 int cur_width = NK_MAX(width, 0);
7545 unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;
7546
7547 /* print oct/hex/dec value */
7548 const char *upper_output_format = "0123456789ABCDEF";
7549 const char *lower_output_format = "0123456789abcdef";
7550 const char *output_format = (*iter == 'x') ?
7551 lower_output_format: upper_output_format;
7552
7553 /* retrieve correct value type */
7554 if (arg_type == NK_ARG_TYPE_CHAR)
7555 value = (unsigned char)va_arg(args, int);
7556 else if (arg_type == NK_ARG_TYPE_SHORT)
7557 value = (unsigned short)va_arg(args, int);
7558 else if (arg_type == NK_ARG_TYPE_LONG)
7559 value = va_arg(args, unsigned long);
7560 else value = va_arg(args, unsigned int);
7561
7562 do {
7563 /* convert decimal number into hex/oct number */
7564 int digit = output_format[value % base];
7565 if (num_len < NK_MAX_NUMBER_BUFFER)
7566 number_buffer[num_len++] = (char)digit;
7567 value /= base;
7568 } while (value > 0);
7569
7570 num_print = NK_MAX(cur_precision, num_len);
7571 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
7572 if (flag & NK_ARG_FLAG_NUM)
7573 padding = NK_MAX(padding-1, 0);
7574
7575 /* fill left padding up to a total of `width` characters */
7576 if (!(flag & NK_ARG_FLAG_LEFT)) {
7577 while ((padding-- > 0) && (len < buf_size)) {
7578 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
7579 buf[len++] = '0';
7580 else buf[len++] = ' ';
7581 }
7582 }
7583
7584 /* fill up to precision number of digits */
7585 if (num_print && (flag & NK_ARG_FLAG_NUM)) {
7586 if ((*iter == 'o') && (len < buf_size)) {
7587 buf[len++] = '0';
7588 } else if ((*iter == 'x') && ((len+1) < buf_size)) {
7589 buf[len++] = '0';
7590 buf[len++] = 'x';
7591 } else if ((*iter == 'X') && ((len+1) < buf_size)) {
7592 buf[len++] = '0';
7593 buf[len++] = 'X';
7594 }
7595 }
7596 while (precision && (num_print > num_len) && (len < buf_size)) {
7597 buf[len++] = '0';
7598 num_print--;
7599 }
7600
7601 /* reverse number direction */
7602 while (num_len > 0) {
7603 if (precision && (len < buf_size))
7604 buf[len++] = number_buffer[num_len-1];
7605 num_len--;
7606 }
7607
7608 /* fill right padding up to width characters */
7609 if (flag & NK_ARG_FLAG_LEFT) {
7610 while ((padding-- > 0) && (len < buf_size))
7611 buf[len++] = ' ';
7612 }
7613 } else if (*iter == 'f') {
7614 /* floating point */
7615 const char *num_iter;
7616 int cur_precision = (precision < 0) ? 6: precision;
7617 int prefix, cur_width = NK_MAX(width, 0);
7618 double value = va_arg(args, double);
7619 int num_len = 0, frac_len = 0, dot = 0;
7620 int padding = 0;
7621
7622 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
7623 NK_DTOA(number_buffer, value);
7624 num_len = nk_strlen(number_buffer);
7625
7626 /* calculate padding */
7627 num_iter = number_buffer;
7628 while (*num_iter && *num_iter != '.')
7629 num_iter++;
7630
7631 prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;
7632 padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);
7633 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
7634 padding = NK_MAX(padding-1, 0);
7635
7636 /* fill left padding up to a total of `width` characters */
7637 if (!(flag & NK_ARG_FLAG_LEFT)) {
7638 while (padding-- > 0 && (len < buf_size)) {
7639 if (flag & NK_ARG_FLAG_ZERO)
7640 buf[len++] = '0';
7641 else buf[len++] = ' ';
7642 }
7643 }
7644
7645 /* copy string value representation into buffer */
7646 num_iter = number_buffer;
7647 if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))
7648 buf[len++] = '+';
7649 else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))
7650 buf[len++] = ' ';
7651 while (*num_iter) {
7652 if (dot) frac_len++;
7653 if (len < buf_size)
7654 buf[len++] = *num_iter;
7655 if (*num_iter == '.') dot = 1;
7656 if (frac_len >= cur_precision) break;
7657 num_iter++;
7658 }
7659
7660 /* fill number up to precision */
7661 while (frac_len < cur_precision) {
7662 if (!dot && len < buf_size) {
7663 buf[len++] = '.';
7664 dot = 1;
7665 }
7666 if (len < buf_size)
7667 buf[len++] = '0';
7668 frac_len++;
7669 }
7670
7671 /* fill right padding up to width characters */
7672 if (flag & NK_ARG_FLAG_LEFT) {
7673 while ((padding-- > 0) && (len < buf_size))
7674 buf[len++] = ' ';
7675 }
7676 } else {
7677 /* Specifier not supported: g,G,e,E,p,z */
7678 NK_ASSERT(0 && "specifier is not supported!");
7679 return result;
7680 }
7681 }
7682 buf[(len >= buf_size)?(buf_size-1):len] = 0;
7683 result = (len >= buf_size)?-1:len;
7684 return result;
7685}
7686#endif
7687NK_LIB int
7688nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)
7689{
7690 int result = -1;
7691 NK_ASSERT(buf);
7692 NK_ASSERT(buf_size);
7693 if (!buf || !buf_size || !fmt) return 0;
7694#ifdef NK_INCLUDE_STANDARD_IO
7695 result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);
7696 result = (result >= buf_size) ? -1: result;
7697 buf[buf_size-1] = 0;
7698#else
7699 result = nk_vsnprintf(buf, buf_size, fmt, args);
7700#endif
7701 return result;
7702}
7703#endif
7704NK_API nk_hash
7705nk_murmur_hash(const void * key, int len, nk_hash seed)
7706{
7707 /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/
7708 #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))
7709
7710 nk_uint h1 = seed;
7711 nk_uint k1;
7712 const nk_byte *data = (const nk_byte*)key;
7713 const nk_byte *keyptr = data;
7714 nk_byte *k1ptr;
7715 const int bsize = sizeof(k1);
7716 const int nblocks = len/4;
7717
7718 const nk_uint c1 = 0xcc9e2d51;
7719 const nk_uint c2 = 0x1b873593;
7720 const nk_byte *tail;
7721 int i;
7722
7723 /* body */
7724 if (!key) return 0;
7725 for (i = 0; i < nblocks; ++i, keyptr += bsize) {
7726 k1ptr = (nk_byte*)&k1;
7727 k1ptr[0] = keyptr[0];
7728 k1ptr[1] = keyptr[1];
7729 k1ptr[2] = keyptr[2];
7730 k1ptr[3] = keyptr[3];
7731
7732 k1 *= c1;
7733 k1 = NK_ROTL(k1,15);
7734 k1 *= c2;
7735
7736 h1 ^= k1;
7737 h1 = NK_ROTL(h1,13);
7738 h1 = h1*5+0xe6546b64;
7739 }
7740
7741 /* tail */
7742 tail = (const nk_byte*)(data + nblocks*4);
7743 k1 = 0;
7744 switch (len & 3) {
7745 case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */
7746 case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */
7747 case 1: k1 ^= tail[0];
7748 k1 *= c1;
7749 k1 = NK_ROTL(k1,15);
7750 k1 *= c2;
7751 h1 ^= k1;
7752 break;
7753 default: break;
7754 }
7755
7756 /* finalization */
7757 h1 ^= (nk_uint)len;
7758 /* fmix32 */
7759 h1 ^= h1 >> 16;
7760 h1 *= 0x85ebca6b;
7761 h1 ^= h1 >> 13;
7762 h1 *= 0xc2b2ae35;
7763 h1 ^= h1 >> 16;
7764
7765 #undef NK_ROTL
7766 return h1;
7767}
7768#ifdef NK_INCLUDE_STANDARD_IO
7769NK_LIB char*
7770nk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc)
7771{
7772 char *buf;
7773 FILE *fd;
7774 long ret;
7775
7776 NK_ASSERT(path);
7777 NK_ASSERT(siz);
7778 NK_ASSERT(alloc);
7779 if (!path || !siz || !alloc)
7780 return 0;
7781
7782 fd = fopen(path, "rb");
7783 if (!fd) return 0;
7784 fseek(fd, 0, SEEK_END);
7785 ret = ftell(fd);
7786 if (ret < 0) {
7787 fclose(fd);
7788 return 0;
7789 }
7790 *siz = (nk_size)ret;
7791 fseek(fd, 0, SEEK_SET);
7792 buf = (char*)alloc->alloc(alloc->userdata,0, *siz);
7793 NK_ASSERT(buf);
7794 if (!buf) {
7795 fclose(fd);
7796 return 0;
7797 }
7798 *siz = (nk_size)fread(buf, 1,*siz, fd);
7799 fclose(fd);
7800 return buf;
7801}
7802#endif
7803NK_LIB int
7804nk_text_clamp(const struct nk_user_font *font, const char *text,
7805 int text_len, float space, int *glyphs, float *text_width,
7806 nk_rune *sep_list, int sep_count)
7807{
7808 int i = 0;
7809 int glyph_len = 0;
7810 float last_width = 0;
7811 nk_rune unicode = 0;
7812 float width = 0;
7813 int len = 0;
7814 int g = 0;
7815 float s;
7816
7817 int sep_len = 0;
7818 int sep_g = 0;
7819 float sep_width = 0;
7820 sep_count = NK_MAX(sep_count,0);
7821
7822 glyph_len = nk_utf_decode(text, &unicode, text_len);
7823 while (glyph_len && (width < space) && (len < text_len)) {
7824 len += glyph_len;
7825 s = font->width(font->userdata, font->height, text, len);
7826 for (i = 0; i < sep_count; ++i) {
7827 if (unicode != sep_list[i]) continue;
7828 sep_width = last_width = width;
7829 sep_g = g+1;
7830 sep_len = len;
7831 break;
7832 }
7833 if (i == sep_count){
7834 last_width = sep_width = width;
7835 sep_g = g+1;
7836 }
7837 width = s;
7838 glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);
7839 g++;
7840 }
7841 if (len >= text_len) {
7842 *glyphs = g;
7843 *text_width = last_width;
7844 return len;
7845 } else {
7846 *glyphs = sep_g;
7847 *text_width = sep_width;
7848 return (!sep_len) ? len: sep_len;
7849 }
7850}
7851NK_LIB struct nk_vec2
7852nk_text_calculate_text_bounds(const struct nk_user_font *font,
7853 const char *begin, int byte_len, float row_height, const char **remaining,
7854 struct nk_vec2 *out_offset, int *glyphs, int op)
7855{
7856 float line_height = row_height;
7857 struct nk_vec2 text_size = nk_vec2(0,0);
7858 float line_width = 0.0f;
7859
7860 float glyph_width;
7861 int glyph_len = 0;
7862 nk_rune unicode = 0;
7863 int text_len = 0;
7864 if (!begin || byte_len <= 0 || !font)
7865 return nk_vec2(0,row_height);
7866
7867 glyph_len = nk_utf_decode(begin, &unicode, byte_len);
7868 if (!glyph_len) return text_size;
7869 glyph_width = font->width(font->userdata, font->height, begin, glyph_len);
7870
7871 *glyphs = 0;
7872 while ((text_len < byte_len) && glyph_len) {
7873 if (unicode == '\n') {
7874 text_size.x = NK_MAX(text_size.x, line_width);
7875 text_size.y += line_height;
7876 line_width = 0;
7877 *glyphs+=1;
7878 if (op == NK_STOP_ON_NEW_LINE)
7879 break;
7880
7881 text_len++;
7882 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
7883 continue;
7884 }
7885
7886 if (unicode == '\r') {
7887 text_len++;
7888 *glyphs+=1;
7889 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
7890 continue;
7891 }
7892
7893 *glyphs = *glyphs + 1;
7894 text_len += glyph_len;
7895 line_width += (float)glyph_width;
7896 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
7897 glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);
7898 continue;
7899 }
7900
7901 if (text_size.x < line_width)
7902 text_size.x = line_width;
7903 if (out_offset)
7904 *out_offset = nk_vec2(line_width, text_size.y + line_height);
7905 if (line_width > 0 || text_size.y == 0.0f)
7906 text_size.y += line_height;
7907 if (remaining)
7908 *remaining = begin+text_len;
7909 return text_size;
7910}
7911
7912
7913
7914
7915
7916/* ==============================================================
7917 *
7918 * COLOR
7919 *
7920 * ===============================================================*/
7921NK_INTERN int
7922nk_parse_hex(const char *p, int length)
7923{
7924 int i = 0;
7925 int len = 0;
7926 while (len < length) {
7927 i <<= 4;
7928 if (p[len] >= 'a' && p[len] <= 'f')
7929 i += ((p[len] - 'a') + 10);
7930 else if (p[len] >= 'A' && p[len] <= 'F')
7931 i += ((p[len] - 'A') + 10);
7932 else i += (p[len] - '0');
7933 len++;
7934 }
7935 return i;
7936}
7937NK_API struct nk_color
7938nk_rgb_factor(struct nk_color col, float factor)
7939{
7940 if (factor == 1.0f)
7941 return col;
7942 col.r = (nk_byte)(col.r * factor);
7943 col.g = (nk_byte)(col.g * factor);
7944 col.b = (nk_byte)(col.b * factor);
7945 return col;
7946}
7947NK_API struct nk_color
7948nk_rgba(int r, int g, int b, int a)
7949{
7950 struct nk_color ret;
7951 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
7952 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
7953 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
7954 ret.a = (nk_byte)NK_CLAMP(0, a, 255);
7955 return ret;
7956}
7957NK_API struct nk_color
7958nk_rgb_hex(const char *rgb)
7959{
7960 struct nk_color col;
7961 const char *c = rgb;
7962 if (*c == '#') c++;
7963 col.r = (nk_byte)nk_parse_hex(c, 2);
7964 col.g = (nk_byte)nk_parse_hex(c+2, 2);
7965 col.b = (nk_byte)nk_parse_hex(c+4, 2);
7966 col.a = 255;
7967 return col;
7968}
7969NK_API struct nk_color
7970nk_rgba_hex(const char *rgb)
7971{
7972 struct nk_color col;
7973 const char *c = rgb;
7974 if (*c == '#') c++;
7975 col.r = (nk_byte)nk_parse_hex(c, 2);
7976 col.g = (nk_byte)nk_parse_hex(c+2, 2);
7977 col.b = (nk_byte)nk_parse_hex(c+4, 2);
7978 col.a = (nk_byte)nk_parse_hex(c+6, 2);
7979 return col;
7980}
7981NK_API void
7982nk_color_hex_rgba(char *output, struct nk_color col)
7983{
7984 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
7985 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
7986 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
7987 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
7988 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
7989 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
7990 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
7991 output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);
7992 output[7] = (char)NK_TO_HEX((col.a & 0x0F));
7993 output[8] = '\0';
7994 #undef NK_TO_HEX
7995}
7996NK_API void
7997nk_color_hex_rgb(char *output, struct nk_color col)
7998{
7999 #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))
8000 output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);
8001 output[1] = (char)NK_TO_HEX((col.r & 0x0F));
8002 output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);
8003 output[3] = (char)NK_TO_HEX((col.g & 0x0F));
8004 output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);
8005 output[5] = (char)NK_TO_HEX((col.b & 0x0F));
8006 output[6] = '\0';
8007 #undef NK_TO_HEX
8008}
8009NK_API struct nk_color
8010nk_rgba_iv(const int *c)
8011{
8012 return nk_rgba(c[0], c[1], c[2], c[3]);
8013}
8014NK_API struct nk_color
8015nk_rgba_bv(const nk_byte *c)
8016{
8017 return nk_rgba(c[0], c[1], c[2], c[3]);
8018}
8019NK_API struct nk_color
8020nk_rgb(int r, int g, int b)
8021{
8022 struct nk_color ret;
8023 ret.r = (nk_byte)NK_CLAMP(0, r, 255);
8024 ret.g = (nk_byte)NK_CLAMP(0, g, 255);
8025 ret.b = (nk_byte)NK_CLAMP(0, b, 255);
8026 ret.a = (nk_byte)255;
8027 return ret;
8028}
8029NK_API struct nk_color
8030nk_rgb_iv(const int *c)
8031{
8032 return nk_rgb(c[0], c[1], c[2]);
8033}
8034NK_API struct nk_color
8035nk_rgb_bv(const nk_byte* c)
8036{
8037 return nk_rgb(c[0], c[1], c[2]);
8038}
8039NK_API struct nk_color
8040nk_rgba_u32(nk_uint in)
8041{
8042 struct nk_color ret;
8043 ret.r = (in & 0xFF);
8044 ret.g = ((in >> 8) & 0xFF);
8045 ret.b = ((in >> 16) & 0xFF);
8046 ret.a = (nk_byte)((in >> 24) & 0xFF);
8047 return ret;
8048}
8049NK_API struct nk_color
8050nk_rgba_f(float r, float g, float b, float a)
8051{
8052 struct nk_color ret;
8053 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
8054 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
8055 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
8056 ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);
8057 return ret;
8058}
8059NK_API struct nk_color
8060nk_rgba_fv(const float *c)
8061{
8062 return nk_rgba_f(c[0], c[1], c[2], c[3]);
8063}
8064NK_API struct nk_color
8065nk_rgba_cf(struct nk_colorf c)
8066{
8067 return nk_rgba_f(c.r, c.g, c.b, c.a);
8068}
8069NK_API struct nk_color
8070nk_rgb_f(float r, float g, float b)
8071{
8072 struct nk_color ret;
8073 ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);
8074 ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);
8075 ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);
8076 ret.a = 255;
8077 return ret;
8078}
8079NK_API struct nk_color
8080nk_rgb_fv(const float *c)
8081{
8082 return nk_rgb_f(c[0], c[1], c[2]);
8083}
8084NK_API struct nk_color
8085nk_rgb_cf(struct nk_colorf c)
8086{
8087 return nk_rgb_f(c.r, c.g, c.b);
8088}
8089NK_API struct nk_color
8090nk_hsv(int h, int s, int v)
8091{
8092 return nk_hsva(h, s, v, 255);
8093}
8094NK_API struct nk_color
8095nk_hsv_iv(const int *c)
8096{
8097 return nk_hsv(c[0], c[1], c[2]);
8098}
8099NK_API struct nk_color
8100nk_hsv_bv(const nk_byte *c)
8101{
8102 return nk_hsv(c[0], c[1], c[2]);
8103}
8104NK_API struct nk_color
8105nk_hsv_f(float h, float s, float v)
8106{
8107 return nk_hsva_f(h, s, v, 1.0f);
8108}
8109NK_API struct nk_color
8110nk_hsv_fv(const float *c)
8111{
8112 return nk_hsv_f(c[0], c[1], c[2]);
8113}
8114NK_API struct nk_color
8115nk_hsva(int h, int s, int v, int a)
8116{
8117 float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;
8118 float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;
8119 float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;
8120 float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;
8121 return nk_hsva_f(hf, sf, vf, af);
8122}
8123NK_API struct nk_color
8124nk_hsva_iv(const int *c)
8125{
8126 return nk_hsva(c[0], c[1], c[2], c[3]);
8127}
8128NK_API struct nk_color
8129nk_hsva_bv(const nk_byte *c)
8130{
8131 return nk_hsva(c[0], c[1], c[2], c[3]);
8132}
8133NK_API struct nk_colorf
8134nk_hsva_colorf(float h, float s, float v, float a)
8135{
8136 int i;
8137 float p, q, t, f;
8138 struct nk_colorf out = {0,0,0,0};
8139 if (s <= 0.0f) {
8140 out.r = v; out.g = v; out.b = v; out.a = a;
8141 return out;
8142 }
8143 h = h / (60.0f/360.0f);
8144 i = (int)h;
8145 f = h - (float)i;
8146 p = v * (1.0f - s);
8147 q = v * (1.0f - (s * f));
8148 t = v * (1.0f - s * (1.0f - f));
8149
8150 switch (i) {
8151 case 0: default: out.r = v; out.g = t; out.b = p; break;
8152 case 1: out.r = q; out.g = v; out.b = p; break;
8153 case 2: out.r = p; out.g = v; out.b = t; break;
8154 case 3: out.r = p; out.g = q; out.b = v; break;
8155 case 4: out.r = t; out.g = p; out.b = v; break;
8156 case 5: out.r = v; out.g = p; out.b = q; break;}
8157 out.a = a;
8158 return out;
8159}
8160NK_API struct nk_colorf
8161nk_hsva_colorfv(const float *c)
8162{
8163 return nk_hsva_colorf(c[0], c[1], c[2], c[3]);
8164}
8165NK_API struct nk_color
8166nk_hsva_f(float h, float s, float v, float a)
8167{
8168 struct nk_colorf c = nk_hsva_colorf(h, s, v, a);
8169 return nk_rgba_f(c.r, c.g, c.b, c.a);
8170}
8171NK_API struct nk_color
8172nk_hsva_fv(const float *c)
8173{
8174 return nk_hsva_f(c[0], c[1], c[2], c[3]);
8175}
8176NK_API nk_uint
8177nk_color_u32(struct nk_color in)
8178{
8179 nk_uint out = (nk_uint)in.r;
8180 out |= ((nk_uint)in.g << 8);
8181 out |= ((nk_uint)in.b << 16);
8182 out |= ((nk_uint)in.a << 24);
8183 return out;
8184}
8185NK_API void
8186nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)
8187{
8188 NK_STORAGE const float s = 1.0f/255.0f;
8189 *r = (float)in.r * s;
8190 *g = (float)in.g * s;
8191 *b = (float)in.b * s;
8192 *a = (float)in.a * s;
8193}
8194NK_API void
8195nk_color_fv(float *c, struct nk_color in)
8196{
8197 nk_color_f(&c[0], &c[1], &c[2], &c[3], in);
8198}
8199NK_API struct nk_colorf
8200nk_color_cf(struct nk_color in)
8201{
8202 struct nk_colorf o;
8203 nk_color_f(&o.r, &o.g, &o.b, &o.a, in);
8204 return o;
8205}
8206NK_API void
8207nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)
8208{
8209 NK_STORAGE const double s = 1.0/255.0;
8210 *r = (double)in.r * s;
8211 *g = (double)in.g * s;
8212 *b = (double)in.b * s;
8213 *a = (double)in.a * s;
8214}
8215NK_API void
8216nk_color_dv(double *c, struct nk_color in)
8217{
8218 nk_color_d(&c[0], &c[1], &c[2], &c[3], in);
8219}
8220NK_API void
8221nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)
8222{
8223 float a;
8224 nk_color_hsva_f(out_h, out_s, out_v, &a, in);
8225}
8226NK_API void
8227nk_color_hsv_fv(float *out, struct nk_color in)
8228{
8229 float a;
8230 nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);
8231}
8232NK_API void
8233nk_colorf_hsva_f(float *out_h, float *out_s,
8234 float *out_v, float *out_a, struct nk_colorf in)
8235{
8236 float chroma;
8237 float K = 0.0f;
8238 if (in.g < in.b) {
8239 const float t = in.g; in.g = in.b; in.b = t;
8240 K = -1.f;
8241 }
8242 if (in.r < in.g) {
8243 const float t = in.r; in.r = in.g; in.g = t;
8244 K = -2.f/6.0f - K;
8245 }
8246 chroma = in.r - ((in.g < in.b) ? in.g: in.b);
8247 *out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f));
8248 *out_s = chroma / (in.r + 1e-20f);
8249 *out_v = in.r;
8250 *out_a = in.a;
8251
8252}
8253NK_API void
8254nk_colorf_hsva_fv(float *hsva, struct nk_colorf in)
8255{
8256 nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in);
8257}
8258NK_API void
8259nk_color_hsva_f(float *out_h, float *out_s,
8260 float *out_v, float *out_a, struct nk_color in)
8261{
8262 struct nk_colorf col;
8263 nk_color_f(&col.r,&col.g,&col.b,&col.a, in);
8264 nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col);
8265}
8266NK_API void
8267nk_color_hsva_fv(float *out, struct nk_color in)
8268{
8269 nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);
8270}
8271NK_API void
8272nk_color_hsva_i(int *out_h, int *out_s, int *out_v,
8273 int *out_a, struct nk_color in)
8274{
8275 float h,s,v,a;
8276 nk_color_hsva_f(&h, &s, &v, &a, in);
8277 *out_h = (nk_byte)(h * 255.0f);
8278 *out_s = (nk_byte)(s * 255.0f);
8279 *out_v = (nk_byte)(v * 255.0f);
8280 *out_a = (nk_byte)(a * 255.0f);
8281}
8282NK_API void
8283nk_color_hsva_iv(int *out, struct nk_color in)
8284{
8285 nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);
8286}
8287NK_API void
8288nk_color_hsva_bv(nk_byte *out, struct nk_color in)
8289{
8290 int tmp[4];
8291 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
8292 out[0] = (nk_byte)tmp[0];
8293 out[1] = (nk_byte)tmp[1];
8294 out[2] = (nk_byte)tmp[2];
8295 out[3] = (nk_byte)tmp[3];
8296}
8297NK_API void
8298nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)
8299{
8300 int tmp[4];
8301 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
8302 *h = (nk_byte)tmp[0];
8303 *s = (nk_byte)tmp[1];
8304 *v = (nk_byte)tmp[2];
8305 *a = (nk_byte)tmp[3];
8306}
8307NK_API void
8308nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)
8309{
8310 int a;
8311 nk_color_hsva_i(out_h, out_s, out_v, &a, in);
8312}
8313NK_API void
8314nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)
8315{
8316 int tmp[4];
8317 nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);
8318 *out_h = (nk_byte)tmp[0];
8319 *out_s = (nk_byte)tmp[1];
8320 *out_v = (nk_byte)tmp[2];
8321}
8322NK_API void
8323nk_color_hsv_iv(int *out, struct nk_color in)
8324{
8325 nk_color_hsv_i(&out[0], &out[1], &out[2], in);
8326}
8327NK_API void
8328nk_color_hsv_bv(nk_byte *out, struct nk_color in)
8329{
8330 int tmp[4];
8331 nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);
8332 out[0] = (nk_byte)tmp[0];
8333 out[1] = (nk_byte)tmp[1];
8334 out[2] = (nk_byte)tmp[2];
8335}
8336
8337
8338
8339
8340/* ===============================================================
8341 *
8342 * UTF-8
8343 *
8344 * ===============================================================*/
8345NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
8346NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
8347NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};
8348NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
8349
8350NK_INTERN int
8351nk_utf_validate(nk_rune *u, int i)
8352{
8353 NK_ASSERT(u);
8354 if (!u) return 0;
8355 if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||
8356 NK_BETWEEN(*u, 0xD800, 0xDFFF))
8357 *u = NK_UTF_INVALID;
8358 for (i = 1; *u > nk_utfmax[i]; ++i);
8359 return i;
8360}
8361NK_INTERN nk_rune
8362nk_utf_decode_byte(char c, int *i)
8363{
8364 NK_ASSERT(i);
8365 if (!i) return 0;
8366 for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {
8367 if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])
8368 return (nk_byte)(c & ~nk_utfmask[*i]);
8369 }
8370 return 0;
8371}
8372NK_API int
8373nk_utf_decode(const char *c, nk_rune *u, int clen)
8374{
8375 int i, j, len, type=0;
8376 nk_rune udecoded;
8377
8378 NK_ASSERT(c);
8379 NK_ASSERT(u);
8380
8381 if (!c || !u) return 0;
8382 if (!clen) return 0;
8383 *u = NK_UTF_INVALID;
8384
8385 udecoded = nk_utf_decode_byte(c[0], &len);
8386 if (!NK_BETWEEN(len, 1, NK_UTF_SIZE))
8387 return 1;
8388
8389 for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
8390 udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);
8391 if (type != 0)
8392 return j;
8393 }
8394 if (j < len)
8395 return 0;
8396 *u = udecoded;
8397 nk_utf_validate(u, len);
8398 return len;
8399}
8400NK_INTERN char
8401nk_utf_encode_byte(nk_rune u, int i)
8402{
8403 return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));
8404}
8405NK_API int
8406nk_utf_encode(nk_rune u, char *c, int clen)
8407{
8408 int len, i;
8409 len = nk_utf_validate(&u, 0);
8410 if (clen < len || !len || len > NK_UTF_SIZE)
8411 return 0;
8412
8413 for (i = len - 1; i != 0; --i) {
8414 c[i] = nk_utf_encode_byte(u, 0);
8415 u >>= 6;
8416 }
8417 c[0] = nk_utf_encode_byte(u, len);
8418 return len;
8419}
8420NK_API int
8421nk_utf_len(const char *str, int len)
8422{
8423 const char *text;
8424 int glyphs = 0;
8425 int text_len;
8426 int glyph_len;
8427 int src_len = 0;
8428 nk_rune unicode;
8429
8430 NK_ASSERT(str);
8431 if (!str || !len) return 0;
8432
8433 text = str;
8434 text_len = len;
8435 glyph_len = nk_utf_decode(text, &unicode, text_len);
8436 while (glyph_len && src_len < len) {
8437 glyphs++;
8438 src_len = src_len + glyph_len;
8439 glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);
8440 }
8441 return glyphs;
8442}
8443NK_API const char*
8444nk_utf_at(const char *buffer, int length, int index,
8445 nk_rune *unicode, int *len)
8446{
8447 int i = 0;
8448 int src_len = 0;
8449 int glyph_len = 0;
8450 const char *text;
8451 int text_len;
8452
8453 NK_ASSERT(buffer);
8454 NK_ASSERT(unicode);
8455 NK_ASSERT(len);
8456
8457 if (!buffer || !unicode || !len) return 0;
8458 if (index < 0) {
8459 *unicode = NK_UTF_INVALID;
8460 *len = 0;
8461 return 0;
8462 }
8463
8464 text = buffer;
8465 text_len = length;
8466 glyph_len = nk_utf_decode(text, unicode, text_len);
8467 while (glyph_len) {
8468 if (i == index) {
8469 *len = glyph_len;
8470 break;
8471 }
8472
8473 i++;
8474 src_len = src_len + glyph_len;
8475 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
8476 }
8477 if (i != index) return 0;
8478 return buffer + src_len;
8479}
8480
8481
8482
8483
8484
8485/* ==============================================================
8486 *
8487 * BUFFER
8488 *
8489 * ===============================================================*/
8490#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
8491NK_LIB void*
8492nk_malloc(nk_handle unused, void *old,nk_size size)
8493{
8494 NK_UNUSED(unused);
8495 NK_UNUSED(old);
8496 return malloc(size);
8497}
8498NK_LIB void
8499nk_mfree(nk_handle unused, void *ptr)
8500{
8501 NK_UNUSED(unused);
8502 free(ptr);
8503}
8504NK_API void
8505nk_buffer_init_default(struct nk_buffer *buffer)
8506{
8507 struct nk_allocator alloc;
8508 alloc.userdata.ptr = 0;
8509 alloc.alloc = nk_malloc;
8510 alloc.free = nk_mfree;
8511 nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);
8512}
8513#endif
8514
8515NK_API void
8516nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,
8517 nk_size initial_size)
8518{
8519 NK_ASSERT(b);
8520 NK_ASSERT(a);
8521 NK_ASSERT(initial_size);
8522 if (!b || !a || !initial_size) return;
8523
8524 nk_zero(b, sizeof(*b));
8525 b->type = NK_BUFFER_DYNAMIC;
8526 b->memory.ptr = a->alloc(a->userdata,0, initial_size);
8527 b->memory.size = initial_size;
8528 b->size = initial_size;
8529 b->grow_factor = 2.0f;
8530 b->pool = *a;
8531}
8532NK_API void
8533nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)
8534{
8535 NK_ASSERT(b);
8536 NK_ASSERT(m);
8537 NK_ASSERT(size);
8538 if (!b || !m || !size) return;
8539
8540 nk_zero(b, sizeof(*b));
8541 b->type = NK_BUFFER_FIXED;
8542 b->memory.ptr = m;
8543 b->memory.size = size;
8544 b->size = size;
8545}
8546NK_LIB void*
8547nk_buffer_align(void *unaligned,
8548 nk_size align, nk_size *alignment,
8549 enum nk_buffer_allocation_type type)
8550{
8551 void *memory = 0;
8552 switch (type) {
8553 default:
8554 case NK_BUFFER_MAX:
8555 case NK_BUFFER_FRONT:
8556 if (align) {
8557 memory = NK_ALIGN_PTR(unaligned, align);
8558 *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
8559 } else {
8560 memory = unaligned;
8561 *alignment = 0;
8562 }
8563 break;
8564 case NK_BUFFER_BACK:
8565 if (align) {
8566 memory = NK_ALIGN_PTR_BACK(unaligned, align);
8567 *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);
8568 } else {
8569 memory = unaligned;
8570 *alignment = 0;
8571 }
8572 break;
8573 }
8574 return memory;
8575}
8576NK_LIB void*
8577nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)
8578{
8579 void *temp;
8580 nk_size buffer_size;
8581
8582 NK_ASSERT(b);
8583 NK_ASSERT(size);
8584 if (!b || !size || !b->pool.alloc || !b->pool.free)
8585 return 0;
8586
8587 buffer_size = b->memory.size;
8588 temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);
8589 NK_ASSERT(temp);
8590 if (!temp) return 0;
8591
8592 *size = capacity;
8593 if (temp != b->memory.ptr) {
8594 NK_MEMCPY(temp, b->memory.ptr, buffer_size);
8595 b->pool.free(b->pool.userdata, b->memory.ptr);
8596 }
8597
8598 if (b->size == buffer_size) {
8599 /* no back buffer so just set correct size */
8600 b->size = capacity;
8601 return temp;
8602 } else {
8603 /* copy back buffer to the end of the new buffer */
8604 void *dst, *src;
8605 nk_size back_size;
8606 back_size = buffer_size - b->size;
8607 dst = nk_ptr_add(void, temp, capacity - back_size);
8608 src = nk_ptr_add(void, temp, b->size);
8609 NK_MEMCPY(dst, src, back_size);
8610 b->size = capacity - back_size;
8611 }
8612 return temp;
8613}
8614NK_LIB void*
8615nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,
8616 nk_size size, nk_size align)
8617{
8618 int full;
8619 nk_size alignment;
8620 void *unaligned;
8621 void *memory;
8622
8623 NK_ASSERT(b);
8624 NK_ASSERT(size);
8625 if (!b || !size) return 0;
8626 b->needed += size;
8627
8628 /* calculate total size with needed alignment + size */
8629 if (type == NK_BUFFER_FRONT)
8630 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
8631 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
8632 memory = nk_buffer_align(unaligned, align, &alignment, type);
8633
8634 /* check if buffer has enough memory*/
8635 if (type == NK_BUFFER_FRONT)
8636 full = ((b->allocated + size + alignment) > b->size);
8637 else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);
8638
8639 if (full) {
8640 nk_size capacity;
8641 if (b->type != NK_BUFFER_DYNAMIC)
8642 return 0;
8643 NK_ASSERT(b->pool.alloc && b->pool.free);
8644 if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)
8645 return 0;
8646
8647 /* buffer is full so allocate bigger buffer if dynamic */
8648 capacity = (nk_size)((float)b->memory.size * b->grow_factor);
8649 capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));
8650 b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);
8651 if (!b->memory.ptr) return 0;
8652
8653 /* align newly allocated pointer */
8654 if (type == NK_BUFFER_FRONT)
8655 unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);
8656 else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);
8657 memory = nk_buffer_align(unaligned, align, &alignment, type);
8658 }
8659 if (type == NK_BUFFER_FRONT)
8660 b->allocated += size + alignment;
8661 else b->size -= (size + alignment);
8662 b->needed += alignment;
8663 b->calls++;
8664 return memory;
8665}
8666NK_API void
8667nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,
8668 const void *memory, nk_size size, nk_size align)
8669{
8670 void *mem = nk_buffer_alloc(b, type, size, align);
8671 if (!mem) return;
8672 NK_MEMCPY(mem, memory, size);
8673}
8674NK_API void
8675nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
8676{
8677 NK_ASSERT(buffer);
8678 if (!buffer) return;
8679 buffer->marker[type].active = nk_true;
8680 if (type == NK_BUFFER_BACK)
8681 buffer->marker[type].offset = buffer->size;
8682 else buffer->marker[type].offset = buffer->allocated;
8683}
8684NK_API void
8685nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)
8686{
8687 NK_ASSERT(buffer);
8688 if (!buffer) return;
8689 if (type == NK_BUFFER_BACK) {
8690 /* reset back buffer either back to marker or empty */
8691 buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);
8692 if (buffer->marker[type].active)
8693 buffer->size = buffer->marker[type].offset;
8694 else buffer->size = buffer->memory.size;
8695 buffer->marker[type].active = nk_false;
8696 } else {
8697 /* reset front buffer either back to back marker or empty */
8698 buffer->needed -= (buffer->allocated - buffer->marker[type].offset);
8699 if (buffer->marker[type].active)
8700 buffer->allocated = buffer->marker[type].offset;
8701 else buffer->allocated = 0;
8702 buffer->marker[type].active = nk_false;
8703 }
8704}
8705NK_API void
8706nk_buffer_clear(struct nk_buffer *b)
8707{
8708 NK_ASSERT(b);
8709 if (!b) return;
8710 b->allocated = 0;
8711 b->size = b->memory.size;
8712 b->calls = 0;
8713 b->needed = 0;
8714}
8715NK_API void
8716nk_buffer_free(struct nk_buffer *b)
8717{
8718 NK_ASSERT(b);
8719 if (!b || !b->memory.ptr) return;
8720 if (b->type == NK_BUFFER_FIXED) return;
8721 if (!b->pool.free) return;
8722 NK_ASSERT(b->pool.free);
8723 b->pool.free(b->pool.userdata, b->memory.ptr);
8724}
8725NK_API void
8726nk_buffer_info(struct nk_memory_status *s, const struct nk_buffer *b)
8727{
8728 NK_ASSERT(b);
8729 NK_ASSERT(s);
8730 if (!s || !b) return;
8731 s->allocated = b->allocated;
8732 s->size = b->memory.size;
8733 s->needed = b->needed;
8734 s->memory = b->memory.ptr;
8735 s->calls = b->calls;
8736}
8737NK_API void*
8738nk_buffer_memory(struct nk_buffer *buffer)
8739{
8740 NK_ASSERT(buffer);
8741 if (!buffer) return 0;
8742 return buffer->memory.ptr;
8743}
8744NK_API const void*
8745nk_buffer_memory_const(const struct nk_buffer *buffer)
8746{
8747 NK_ASSERT(buffer);
8748 if (!buffer) return 0;
8749 return buffer->memory.ptr;
8750}
8751NK_API nk_size
8752nk_buffer_total(const struct nk_buffer *buffer)
8753{
8754 NK_ASSERT(buffer);
8755 if (!buffer) return 0;
8756 return buffer->memory.size;
8757}
8758
8759
8760
8761
8762/* ===============================================================
8763 *
8764 * STRING
8765 *
8766 * ===============================================================*/
8767#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
8768NK_API void
8769nk_str_init_default(struct nk_str *str)
8770{
8771 struct nk_allocator alloc;
8772 alloc.userdata.ptr = 0;
8773 alloc.alloc = nk_malloc;
8774 alloc.free = nk_mfree;
8775 nk_buffer_init(&str->buffer, &alloc, 32);
8776 str->len = 0;
8777}
8778#endif
8779
8780NK_API void
8781nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)
8782{
8783 nk_buffer_init(&str->buffer, alloc, size);
8784 str->len = 0;
8785}
8786NK_API void
8787nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)
8788{
8789 nk_buffer_init_fixed(&str->buffer, memory, size);
8790 str->len = 0;
8791}
8792NK_API int
8793nk_str_append_text_char(struct nk_str *s, const char *str, int len)
8794{
8795 char *mem;
8796 NK_ASSERT(s);
8797 NK_ASSERT(str);
8798 if (!s || !str || !len) return 0;
8799 mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
8800 if (!mem) return 0;
8801 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
8802 s->len += nk_utf_len(str, len);
8803 return len;
8804}
8805NK_API int
8806nk_str_append_str_char(struct nk_str *s, const char *str)
8807{
8808 return nk_str_append_text_char(s, str, nk_strlen(str));
8809}
8810NK_API int
8811nk_str_append_text_utf8(struct nk_str *str, const char *text, int len)
8812{
8813 int i = 0;
8814 int byte_len = 0;
8815 nk_rune unicode;
8816 if (!str || !text || !len) return 0;
8817 for (i = 0; i < len; ++i)
8818 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
8819 nk_str_append_text_char(str, text, byte_len);
8820 return len;
8821}
8822NK_API int
8823nk_str_append_str_utf8(struct nk_str *str, const char *text)
8824{
8825 int byte_len = 0;
8826 int num_runes = 0;
8827 int glyph_len = 0;
8828 nk_rune unicode;
8829 if (!str || !text) return 0;
8830
8831 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
8832 while (unicode != '\0' && glyph_len) {
8833 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
8834 byte_len += glyph_len;
8835 num_runes++;
8836 }
8837 nk_str_append_text_char(str, text, byte_len);
8838 return num_runes;
8839}
8840NK_API int
8841nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)
8842{
8843 int i = 0;
8844 int byte_len = 0;
8845 nk_glyph glyph;
8846
8847 NK_ASSERT(str);
8848 if (!str || !text || !len) return 0;
8849 for (i = 0; i < len; ++i) {
8850 byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);
8851 if (!byte_len) break;
8852 nk_str_append_text_char(str, glyph, byte_len);
8853 }
8854 return len;
8855}
8856NK_API int
8857nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)
8858{
8859 int i = 0;
8860 nk_glyph glyph;
8861 int byte_len;
8862 NK_ASSERT(str);
8863 if (!str || !runes) return 0;
8864 while (runes[i] != '\0') {
8865 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
8866 nk_str_append_text_char(str, glyph, byte_len);
8867 i++;
8868 }
8869 return i;
8870}
8871NK_API int
8872nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)
8873{
8874 int i;
8875 void *mem;
8876 char *src;
8877 char *dst;
8878
8879 int copylen;
8880 NK_ASSERT(s);
8881 NK_ASSERT(str);
8882 NK_ASSERT(len >= 0);
8883 if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;
8884 if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&
8885 (s->buffer.type == NK_BUFFER_FIXED)) return 0;
8886
8887 copylen = (int)s->buffer.allocated - pos;
8888 if (!copylen) {
8889 nk_str_append_text_char(s, str, len);
8890 return 1;
8891 }
8892 mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);
8893 if (!mem) return 0;
8894
8895 /* memmove */
8896 NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);
8897 NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);
8898 dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));
8899 src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));
8900 for (i = 0; i < copylen; ++i) *dst-- = *src--;
8901 mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);
8902 NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));
8903 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
8904 return 1;
8905}
8906NK_API int
8907nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)
8908{
8909 int glyph_len;
8910 nk_rune unicode;
8911 const char *begin;
8912 const char *buffer;
8913
8914 NK_ASSERT(str);
8915 NK_ASSERT(cstr);
8916 NK_ASSERT(len);
8917 if (!str || !cstr || !len) return 0;
8918 begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);
8919 if (!str->len)
8920 return nk_str_append_text_char(str, cstr, len);
8921 buffer = nk_str_get_const(str);
8922 if (!begin) return 0;
8923 return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);
8924}
8925NK_API int
8926nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)
8927{
8928 return nk_str_insert_text_utf8(str, pos, text, len);
8929}
8930NK_API int
8931nk_str_insert_str_char(struct nk_str *str, int pos, const char *text)
8932{
8933 return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));
8934}
8935NK_API int
8936nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
8937{
8938 int i = 0;
8939 int byte_len = 0;
8940 nk_rune unicode;
8941
8942 NK_ASSERT(str);
8943 NK_ASSERT(text);
8944 if (!str || !text || !len) return 0;
8945 for (i = 0; i < len; ++i)
8946 byte_len += nk_utf_decode(text+byte_len, &unicode, 4);
8947 nk_str_insert_at_rune(str, pos, text, byte_len);
8948 return len;
8949}
8950NK_API int
8951nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
8952{
8953 int byte_len = 0;
8954 int num_runes = 0;
8955 int glyph_len = 0;
8956 nk_rune unicode;
8957 if (!str || !text) return 0;
8958
8959 glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);
8960 while (unicode != '\0' && glyph_len) {
8961 glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);
8962 byte_len += glyph_len;
8963 num_runes++;
8964 }
8965 nk_str_insert_at_rune(str, pos, text, byte_len);
8966 return num_runes;
8967}
8968NK_API int
8969nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)
8970{
8971 int i = 0;
8972 int byte_len = 0;
8973 nk_glyph glyph;
8974
8975 NK_ASSERT(str);
8976 if (!str || !runes || !len) return 0;
8977 for (i = 0; i < len; ++i) {
8978 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
8979 if (!byte_len) break;
8980 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
8981 }
8982 return len;
8983}
8984NK_API int
8985nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)
8986{
8987 int i = 0;
8988 nk_glyph glyph;
8989 int byte_len;
8990 NK_ASSERT(str);
8991 if (!str || !runes) return 0;
8992 while (runes[i] != '\0') {
8993 byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);
8994 nk_str_insert_at_rune(str, pos+i, glyph, byte_len);
8995 i++;
8996 }
8997 return i;
8998}
8999NK_API void
9000nk_str_remove_chars(struct nk_str *s, int len)
9001{
9002 NK_ASSERT(s);
9003 NK_ASSERT(len >= 0);
9004 if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;
9005 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
9006 s->buffer.allocated -= (nk_size)len;
9007 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
9008}
9009NK_API void
9010nk_str_remove_runes(struct nk_str *str, int len)
9011{
9012 int index;
9013 const char *begin;
9014 const char *end;
9015 nk_rune unicode;
9016
9017 NK_ASSERT(str);
9018 NK_ASSERT(len >= 0);
9019 if (!str || len < 0) return;
9020 if (len >= str->len) {
9021 str->len = 0;
9022 return;
9023 }
9024
9025 index = str->len - len;
9026 begin = nk_str_at_rune(str, index, &unicode, &len);
9027 end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;
9028 nk_str_remove_chars(str, (int)(end-begin)+1);
9029}
9030NK_API void
9031nk_str_delete_chars(struct nk_str *s, int pos, int len)
9032{
9033 NK_ASSERT(s);
9034 if (!s || !len || (nk_size)pos > s->buffer.allocated ||
9035 (nk_size)(pos + len) > s->buffer.allocated) return;
9036
9037 if ((nk_size)(pos + len) < s->buffer.allocated) {
9038 /* memmove */
9039 char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);
9040 char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);
9041 NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));
9042 NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);
9043 s->buffer.allocated -= (nk_size)len;
9044 } else nk_str_remove_chars(s, len);
9045 s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);
9046}
9047NK_API void
9048nk_str_delete_runes(struct nk_str *s, int pos, int len)
9049{
9050 char *temp;
9051 nk_rune unicode;
9052 char *begin;
9053 char *end;
9054 int unused;
9055
9056 NK_ASSERT(s);
9057 NK_ASSERT(s->len >= pos + len);
9058 if (s->len < pos + len)
9059 len = NK_CLAMP(0, (s->len - pos), s->len);
9060 if (!len) return;
9061
9062 temp = (char *)s->buffer.memory.ptr;
9063 begin = nk_str_at_rune(s, pos, &unicode, &unused);
9064 if (!begin) return;
9065 s->buffer.memory.ptr = begin;
9066 end = nk_str_at_rune(s, len, &unicode, &unused);
9067 s->buffer.memory.ptr = temp;
9068 if (!end) return;
9069 nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));
9070}
9071NK_API char*
9072nk_str_at_char(struct nk_str *s, int pos)
9073{
9074 NK_ASSERT(s);
9075 if (!s || pos > (int)s->buffer.allocated) return 0;
9076 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
9077}
9078NK_API char*
9079nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)
9080{
9081 int i = 0;
9082 int src_len = 0;
9083 int glyph_len = 0;
9084 char *text;
9085 int text_len;
9086
9087 NK_ASSERT(str);
9088 NK_ASSERT(unicode);
9089 NK_ASSERT(len);
9090
9091 if (!str || !unicode || !len) return 0;
9092 if (pos < 0) {
9093 *unicode = 0;
9094 *len = 0;
9095 return 0;
9096 }
9097
9098 text = (char*)str->buffer.memory.ptr;
9099 text_len = (int)str->buffer.allocated;
9100 glyph_len = nk_utf_decode(text, unicode, text_len);
9101 while (glyph_len) {
9102 if (i == pos) {
9103 *len = glyph_len;
9104 break;
9105 }
9106
9107 i++;
9108 src_len = src_len + glyph_len;
9109 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
9110 }
9111 if (i != pos) return 0;
9112 return text + src_len;
9113}
9114NK_API const char*
9115nk_str_at_char_const(const struct nk_str *s, int pos)
9116{
9117 NK_ASSERT(s);
9118 if (!s || pos > (int)s->buffer.allocated) return 0;
9119 return nk_ptr_add(char, s->buffer.memory.ptr, pos);
9120}
9121NK_API const char*
9122nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)
9123{
9124 int i = 0;
9125 int src_len = 0;
9126 int glyph_len = 0;
9127 char *text;
9128 int text_len;
9129
9130 NK_ASSERT(str);
9131 NK_ASSERT(unicode);
9132 NK_ASSERT(len);
9133
9134 if (!str || !unicode || !len) return 0;
9135 if (pos < 0) {
9136 *unicode = 0;
9137 *len = 0;
9138 return 0;
9139 }
9140
9141 text = (char*)str->buffer.memory.ptr;
9142 text_len = (int)str->buffer.allocated;
9143 glyph_len = nk_utf_decode(text, unicode, text_len);
9144 while (glyph_len) {
9145 if (i == pos) {
9146 *len = glyph_len;
9147 break;
9148 }
9149
9150 i++;
9151 src_len = src_len + glyph_len;
9152 glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);
9153 }
9154 if (i != pos) return 0;
9155 return text + src_len;
9156}
9157NK_API nk_rune
9158nk_str_rune_at(const struct nk_str *str, int pos)
9159{
9160 int len;
9161 nk_rune unicode = 0;
9162 nk_str_at_const(str, pos, &unicode, &len);
9163 return unicode;
9164}
9165NK_API char*
9166nk_str_get(struct nk_str *s)
9167{
9168 NK_ASSERT(s);
9169 if (!s || !s->len || !s->buffer.allocated) return 0;
9170 return (char*)s->buffer.memory.ptr;
9171}
9172NK_API const char*
9173nk_str_get_const(const struct nk_str *s)
9174{
9175 NK_ASSERT(s);
9176 if (!s || !s->len || !s->buffer.allocated) return 0;
9177 return (const char*)s->buffer.memory.ptr;
9178}
9179NK_API int
9180nk_str_len(const struct nk_str *s)
9181{
9182 NK_ASSERT(s);
9183 if (!s || !s->len || !s->buffer.allocated) return 0;
9184 return s->len;
9185}
9186NK_API int
9187nk_str_len_char(const struct nk_str *s)
9188{
9189 NK_ASSERT(s);
9190 if (!s || !s->len || !s->buffer.allocated) return 0;
9191 return (int)s->buffer.allocated;
9192}
9193NK_API void
9194nk_str_clear(struct nk_str *str)
9195{
9196 NK_ASSERT(str);
9197 nk_buffer_clear(&str->buffer);
9198 str->len = 0;
9199}
9200NK_API void
9201nk_str_free(struct nk_str *str)
9202{
9203 NK_ASSERT(str);
9204 nk_buffer_free(&str->buffer);
9205 str->len = 0;
9206}
9207
9208
9209
9210
9211/* ==============================================================
9212 *
9213 * DRAW
9214 *
9215 * ===============================================================*/
9216NK_LIB void
9217nk_command_buffer_init(struct nk_command_buffer *cb,
9218 struct nk_buffer *b, enum nk_command_clipping clip)
9219{
9220 NK_ASSERT(cb);
9221 NK_ASSERT(b);
9222 if (!cb || !b) return;
9223 cb->base = b;
9224 cb->use_clipping = (int)clip;
9225 cb->begin = b->allocated;
9226 cb->end = b->allocated;
9227 cb->last = b->allocated;
9228}
9229NK_LIB void
9230nk_command_buffer_reset(struct nk_command_buffer *b)
9231{
9232 NK_ASSERT(b);
9233 if (!b) return;
9234 b->begin = 0;
9235 b->end = 0;
9236 b->last = 0;
9237 b->clip = nk_null_rect;
9238#ifdef NK_INCLUDE_COMMAND_USERDATA
9239 b->userdata.ptr = 0;
9240#endif
9241}
9242NK_LIB void*
9243nk_command_buffer_push(struct nk_command_buffer* b,
9244 enum nk_command_type t, nk_size size)
9245{
9246 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);
9247 struct nk_command *cmd;
9248 nk_size alignment;
9249 void *unaligned;
9250 void *memory;
9251
9252 NK_ASSERT(b);
9253 NK_ASSERT(b->base);
9254 if (!b) return 0;
9255 cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);
9256 if (!cmd) return 0;
9257
9258 /* make sure the offset to the next command is aligned */
9259 b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);
9260 unaligned = (nk_byte*)cmd + size;
9261 memory = NK_ALIGN_PTR(unaligned, align);
9262 alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
9263#ifdef NK_ZERO_COMMAND_MEMORY
9264 NK_MEMSET(cmd, 0, size + alignment);
9265#endif
9266
9267 cmd->type = t;
9268 cmd->next = b->base->allocated + alignment;
9269#ifdef NK_INCLUDE_COMMAND_USERDATA
9270 cmd->userdata = b->userdata;
9271#endif
9272 b->end = cmd->next;
9273 return cmd;
9274}
9275NK_API void
9276nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)
9277{
9278 struct nk_command_scissor *cmd;
9279 NK_ASSERT(b);
9280 if (!b) return;
9281
9282 b->clip.x = r.x;
9283 b->clip.y = r.y;
9284 b->clip.w = r.w;
9285 b->clip.h = r.h;
9286 cmd = (struct nk_command_scissor*)
9287 nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));
9288
9289 if (!cmd) return;
9290 cmd->x = (short)r.x;
9291 cmd->y = (short)r.y;
9292 cmd->w = (unsigned short)NK_MAX(0, r.w);
9293 cmd->h = (unsigned short)NK_MAX(0, r.h);
9294}
9295NK_API void
9296nk_stroke_line(struct nk_command_buffer *b, float x0, float y0,
9297 float x1, float y1, float line_thickness, struct nk_color c)
9298{
9299 struct nk_command_line *cmd;
9300 NK_ASSERT(b);
9301 if (!b || line_thickness <= 0) return;
9302 cmd = (struct nk_command_line*)
9303 nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));
9304 if (!cmd) return;
9305 cmd->line_thickness = (unsigned short)line_thickness;
9306 cmd->begin.x = (short)x0;
9307 cmd->begin.y = (short)y0;
9308 cmd->end.x = (short)x1;
9309 cmd->end.y = (short)y1;
9310 cmd->color = c;
9311}
9312NK_API void
9313nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,
9314 float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,
9315 float bx, float by, float line_thickness, struct nk_color col)
9316{
9317 struct nk_command_curve *cmd;
9318 NK_ASSERT(b);
9319 if (!b || col.a == 0 || line_thickness <= 0) return;
9320
9321 cmd = (struct nk_command_curve*)
9322 nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));
9323 if (!cmd) return;
9324 cmd->line_thickness = (unsigned short)line_thickness;
9325 cmd->begin.x = (short)ax;
9326 cmd->begin.y = (short)ay;
9327 cmd->ctrl[0].x = (short)ctrl0x;
9328 cmd->ctrl[0].y = (short)ctrl0y;
9329 cmd->ctrl[1].x = (short)ctrl1x;
9330 cmd->ctrl[1].y = (short)ctrl1y;
9331 cmd->end.x = (short)bx;
9332 cmd->end.y = (short)by;
9333 cmd->color = col;
9334}
9335NK_API void
9336nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,
9337 float rounding, float line_thickness, struct nk_color c)
9338{
9339 struct nk_command_rect *cmd;
9340 NK_ASSERT(b);
9341 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;
9342 if (b->use_clipping) {
9343 const struct nk_rect *clip = &b->clip;
9344 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
9345 clip->x, clip->y, clip->w, clip->h)) return;
9346 }
9347 cmd = (struct nk_command_rect*)
9348 nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));
9349 if (!cmd) return;
9350 cmd->rounding = (unsigned short)rounding;
9351 cmd->line_thickness = (unsigned short)line_thickness;
9352 cmd->x = (short)rect.x;
9353 cmd->y = (short)rect.y;
9354 cmd->w = (unsigned short)NK_MAX(0, rect.w);
9355 cmd->h = (unsigned short)NK_MAX(0, rect.h);
9356 cmd->color = c;
9357}
9358NK_API void
9359nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,
9360 float rounding, struct nk_color c)
9361{
9362 struct nk_command_rect_filled *cmd;
9363 NK_ASSERT(b);
9364 if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
9365 if (b->use_clipping) {
9366 const struct nk_rect *clip = &b->clip;
9367 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
9368 clip->x, clip->y, clip->w, clip->h)) return;
9369 }
9370
9371 cmd = (struct nk_command_rect_filled*)
9372 nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));
9373 if (!cmd) return;
9374 cmd->rounding = (unsigned short)rounding;
9375 cmd->x = (short)rect.x;
9376 cmd->y = (short)rect.y;
9377 cmd->w = (unsigned short)NK_MAX(0, rect.w);
9378 cmd->h = (unsigned short)NK_MAX(0, rect.h);
9379 cmd->color = c;
9380}
9381NK_API void
9382nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,
9383 struct nk_color left, struct nk_color top, struct nk_color right,
9384 struct nk_color bottom)
9385{
9386 struct nk_command_rect_multi_color *cmd;
9387 NK_ASSERT(b);
9388 if (!b || rect.w == 0 || rect.h == 0) return;
9389 if (b->use_clipping) {
9390 const struct nk_rect *clip = &b->clip;
9391 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
9392 clip->x, clip->y, clip->w, clip->h)) return;
9393 }
9394
9395 cmd = (struct nk_command_rect_multi_color*)
9396 nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));
9397 if (!cmd) return;
9398 cmd->x = (short)rect.x;
9399 cmd->y = (short)rect.y;
9400 cmd->w = (unsigned short)NK_MAX(0, rect.w);
9401 cmd->h = (unsigned short)NK_MAX(0, rect.h);
9402 cmd->left = left;
9403 cmd->top = top;
9404 cmd->right = right;
9405 cmd->bottom = bottom;
9406}
9407NK_API void
9408nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,
9409 float line_thickness, struct nk_color c)
9410{
9411 struct nk_command_circle *cmd;
9412 if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;
9413 if (b->use_clipping) {
9414 const struct nk_rect *clip = &b->clip;
9415 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
9416 return;
9417 }
9418
9419 cmd = (struct nk_command_circle*)
9420 nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));
9421 if (!cmd) return;
9422 cmd->line_thickness = (unsigned short)line_thickness;
9423 cmd->x = (short)r.x;
9424 cmd->y = (short)r.y;
9425 cmd->w = (unsigned short)NK_MAX(r.w, 0);
9426 cmd->h = (unsigned short)NK_MAX(r.h, 0);
9427 cmd->color = c;
9428}
9429NK_API void
9430nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)
9431{
9432 struct nk_command_circle_filled *cmd;
9433 NK_ASSERT(b);
9434 if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;
9435 if (b->use_clipping) {
9436 const struct nk_rect *clip = &b->clip;
9437 if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
9438 return;
9439 }
9440
9441 cmd = (struct nk_command_circle_filled*)
9442 nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));
9443 if (!cmd) return;
9444 cmd->x = (short)r.x;
9445 cmd->y = (short)r.y;
9446 cmd->w = (unsigned short)NK_MAX(r.w, 0);
9447 cmd->h = (unsigned short)NK_MAX(r.h, 0);
9448 cmd->color = c;
9449}
9450NK_API void
9451nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
9452 float a_min, float a_max, float line_thickness, struct nk_color c)
9453{
9454 struct nk_command_arc *cmd;
9455 if (!b || c.a == 0 || line_thickness <= 0) return;
9456 cmd = (struct nk_command_arc*)
9457 nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));
9458 if (!cmd) return;
9459 cmd->line_thickness = (unsigned short)line_thickness;
9460 cmd->cx = (short)cx;
9461 cmd->cy = (short)cy;
9462 cmd->r = (unsigned short)radius;
9463 cmd->a[0] = a_min;
9464 cmd->a[1] = a_max;
9465 cmd->color = c;
9466}
9467NK_API void
9468nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
9469 float a_min, float a_max, struct nk_color c)
9470{
9471 struct nk_command_arc_filled *cmd;
9472 NK_ASSERT(b);
9473 if (!b || c.a == 0) return;
9474 cmd = (struct nk_command_arc_filled*)
9475 nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));
9476 if (!cmd) return;
9477 cmd->cx = (short)cx;
9478 cmd->cy = (short)cy;
9479 cmd->r = (unsigned short)radius;
9480 cmd->a[0] = a_min;
9481 cmd->a[1] = a_max;
9482 cmd->color = c;
9483}
9484NK_API void
9485nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
9486 float y1, float x2, float y2, float line_thickness, struct nk_color c)
9487{
9488 struct nk_command_triangle *cmd;
9489 NK_ASSERT(b);
9490 if (!b || c.a == 0 || line_thickness <= 0) return;
9491 if (b->use_clipping) {
9492 const struct nk_rect *clip = &b->clip;
9493 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
9494 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
9495 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
9496 return;
9497 }
9498
9499 cmd = (struct nk_command_triangle*)
9500 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));
9501 if (!cmd) return;
9502 cmd->line_thickness = (unsigned short)line_thickness;
9503 cmd->a.x = (short)x0;
9504 cmd->a.y = (short)y0;
9505 cmd->b.x = (short)x1;
9506 cmd->b.y = (short)y1;
9507 cmd->c.x = (short)x2;
9508 cmd->c.y = (short)y2;
9509 cmd->color = c;
9510}
9511NK_API void
9512nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
9513 float y1, float x2, float y2, struct nk_color c)
9514{
9515 struct nk_command_triangle_filled *cmd;
9516 NK_ASSERT(b);
9517 if (!b || c.a == 0) return;
9518 if (!b) return;
9519 if (b->use_clipping) {
9520 const struct nk_rect *clip = &b->clip;
9521 if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
9522 !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
9523 !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
9524 return;
9525 }
9526
9527 cmd = (struct nk_command_triangle_filled*)
9528 nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));
9529 if (!cmd) return;
9530 cmd->a.x = (short)x0;
9531 cmd->a.y = (short)y0;
9532 cmd->b.x = (short)x1;
9533 cmd->b.y = (short)y1;
9534 cmd->c.x = (short)x2;
9535 cmd->c.y = (short)y2;
9536 cmd->color = c;
9537}
9538NK_API void
9539nk_stroke_polygon(struct nk_command_buffer *b, const float *points, int point_count,
9540 float line_thickness, struct nk_color col)
9541{
9542 int i;
9543 nk_size size = 0;
9544 struct nk_command_polygon *cmd;
9545
9546 NK_ASSERT(b);
9547 if (!b || col.a == 0 || line_thickness <= 0) return;
9548 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
9549 cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);
9550 if (!cmd) return;
9551 cmd->color = col;
9552 cmd->line_thickness = (unsigned short)line_thickness;
9553 cmd->point_count = (unsigned short)point_count;
9554 for (i = 0; i < point_count; ++i) {
9555 cmd->points[i].x = (short)points[i*2];
9556 cmd->points[i].y = (short)points[i*2+1];
9557 }
9558}
9559NK_API void
9560nk_fill_polygon(struct nk_command_buffer *b, const float *points, int point_count,
9561 struct nk_color col)
9562{
9563 int i;
9564 nk_size size = 0;
9565 struct nk_command_polygon_filled *cmd;
9566
9567 NK_ASSERT(b);
9568 if (!b || col.a == 0) return;
9569 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
9570 cmd = (struct nk_command_polygon_filled*)
9571 nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);
9572 if (!cmd) return;
9573 cmd->color = col;
9574 cmd->point_count = (unsigned short)point_count;
9575 for (i = 0; i < point_count; ++i) {
9576 cmd->points[i].x = (short)points[i*2+0];
9577 cmd->points[i].y = (short)points[i*2+1];
9578 }
9579}
9580NK_API void
9581nk_stroke_polyline(struct nk_command_buffer *b, const float *points, int point_count,
9582 float line_thickness, struct nk_color col)
9583{
9584 int i;
9585 nk_size size = 0;
9586 struct nk_command_polyline *cmd;
9587
9588 NK_ASSERT(b);
9589 if (!b || col.a == 0 || line_thickness <= 0) return;
9590 size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
9591 cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);
9592 if (!cmd) return;
9593 cmd->color = col;
9594 cmd->point_count = (unsigned short)point_count;
9595 cmd->line_thickness = (unsigned short)line_thickness;
9596 for (i = 0; i < point_count; ++i) {
9597 cmd->points[i].x = (short)points[i*2];
9598 cmd->points[i].y = (short)points[i*2+1];
9599 }
9600}
9601NK_API void
9602nk_draw_image(struct nk_command_buffer *b, struct nk_rect r,
9603 const struct nk_image *img, struct nk_color col)
9604{
9605 struct nk_command_image *cmd;
9606 NK_ASSERT(b);
9607 if (!b) return;
9608 if (b->use_clipping) {
9609 const struct nk_rect *c = &b->clip;
9610 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))
9611 return;
9612 }
9613
9614 cmd = (struct nk_command_image*)
9615 nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));
9616 if (!cmd) return;
9617 cmd->x = (short)r.x;
9618 cmd->y = (short)r.y;
9619 cmd->w = (unsigned short)NK_MAX(0, r.w);
9620 cmd->h = (unsigned short)NK_MAX(0, r.h);
9621 cmd->img = *img;
9622 cmd->col = col;
9623}
9624NK_API void
9625nk_draw_nine_slice(struct nk_command_buffer *b, struct nk_rect r,
9626 const struct nk_nine_slice *slc, struct nk_color col)
9627{
9628 struct nk_image img;
9629 const struct nk_image *slcimg = (const struct nk_image*)slc;
9630 nk_ushort rgnX, rgnY, rgnW, rgnH;
9631 rgnX = slcimg->region[0];
9632 rgnY = slcimg->region[1];
9633 rgnW = slcimg->region[2];
9634 rgnH = slcimg->region[3];
9635
9636 /* top-left */
9637 img.handle = slcimg->handle;
9638 img.w = slcimg->w;
9639 img.h = slcimg->h;
9640 img.region[0] = rgnX;
9641 img.region[1] = rgnY;
9642 img.region[2] = slc->l;
9643 img.region[3] = slc->t;
9644
9645 nk_draw_image(b,
9646 nk_rect(r.x, r.y, (float)slc->l, (float)slc->t),
9647 &img, col);
9648
9649#define IMG_RGN(x, y, w, h) img.region[0] = (nk_ushort)(x); img.region[1] = (nk_ushort)(y); img.region[2] = (nk_ushort)(w); img.region[3] = (nk_ushort)(h);
9650
9651 /* top-center */
9652 IMG_RGN(rgnX + slc->l, rgnY, rgnW - slc->l - slc->r, slc->t);
9653 nk_draw_image(b,
9654 nk_rect(r.x + (float)slc->l, r.y, (float)(r.w - slc->l - slc->r), (float)slc->t),
9655 &img, col);
9656
9657 /* top-right */
9658 IMG_RGN(rgnX + rgnW - slc->r, rgnY, slc->r, slc->t);
9659 nk_draw_image(b,
9660 nk_rect(r.x + r.w - (float)slc->r, r.y, (float)slc->r, (float)slc->t),
9661 &img, col);
9662
9663 /* center-left */
9664 IMG_RGN(rgnX, rgnY + slc->t, slc->l, rgnH - slc->t - slc->b);
9665 nk_draw_image(b,
9666 nk_rect(r.x, r.y + (float)slc->t, (float)slc->l, (float)(r.h - slc->t - slc->b)),
9667 &img, col);
9668
9669 /* center */
9670 IMG_RGN(rgnX + slc->l, rgnY + slc->t, rgnW - slc->l - slc->r, rgnH - slc->t - slc->b);
9671 nk_draw_image(b,
9672 nk_rect(r.x + (float)slc->l, r.y + (float)slc->t, (float)(r.w - slc->l - slc->r), (float)(r.h - slc->t - slc->b)),
9673 &img, col);
9674
9675 /* center-right */
9676 IMG_RGN(rgnX + rgnW - slc->r, rgnY + slc->t, slc->r, rgnH - slc->t - slc->b);
9677 nk_draw_image(b,
9678 nk_rect(r.x + r.w - (float)slc->r, r.y + (float)slc->t, (float)slc->r, (float)(r.h - slc->t - slc->b)),
9679 &img, col);
9680
9681 /* bottom-left */
9682 IMG_RGN(rgnX, rgnY + rgnH - slc->b, slc->l, slc->b);
9683 nk_draw_image(b,
9684 nk_rect(r.x, r.y + r.h - (float)slc->b, (float)slc->l, (float)slc->b),
9685 &img, col);
9686
9687 /* bottom-center */
9688 IMG_RGN(rgnX + slc->l, rgnY + rgnH - slc->b, rgnW - slc->l - slc->r, slc->b);
9689 nk_draw_image(b,
9690 nk_rect(r.x + (float)slc->l, r.y + r.h - (float)slc->b, (float)(r.w - slc->l - slc->r), (float)slc->b),
9691 &img, col);
9692
9693 /* bottom-right */
9694 IMG_RGN(rgnX + rgnW - slc->r, rgnY + rgnH - slc->b, slc->r, slc->b);
9695 nk_draw_image(b,
9696 nk_rect(r.x + r.w - (float)slc->r, r.y + r.h - (float)slc->b, (float)slc->r, (float)slc->b),
9697 &img, col);
9698
9699#undef IMG_RGN
9700}
9701NK_API void
9702nk_push_custom(struct nk_command_buffer *b, struct nk_rect r,
9703 nk_command_custom_callback cb, nk_handle usr)
9704{
9705 struct nk_command_custom *cmd;
9706 NK_ASSERT(b);
9707 if (!b) return;
9708 if (b->use_clipping) {
9709 const struct nk_rect *c = &b->clip;
9710 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))
9711 return;
9712 }
9713
9714 cmd = (struct nk_command_custom*)
9715 nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));
9716 if (!cmd) return;
9717 cmd->x = (short)r.x;
9718 cmd->y = (short)r.y;
9719 cmd->w = (unsigned short)NK_MAX(0, r.w);
9720 cmd->h = (unsigned short)NK_MAX(0, r.h);
9721 cmd->callback_data = usr;
9722 cmd->callback = cb;
9723}
9724NK_API void
9725nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
9726 const char *string, int length, const struct nk_user_font *font,
9727 struct nk_color bg, struct nk_color fg)
9728{
9729 float text_width = 0;
9730 struct nk_command_text *cmd;
9731
9732 NK_ASSERT(b);
9733 NK_ASSERT(font);
9734 if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;
9735 if (b->use_clipping) {
9736 const struct nk_rect *c = &b->clip;
9737 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))
9738 return;
9739 }
9740
9741 /* make sure text fits inside bounds */
9742 text_width = font->width(font->userdata, font->height, string, length);
9743 if (text_width > r.w){
9744 int glyphs = 0;
9745 float txt_width = (float)text_width;
9746 length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);
9747 }
9748
9749 if (!length) return;
9750 cmd = (struct nk_command_text*)
9751 nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));
9752 if (!cmd) return;
9753 cmd->x = (short)r.x;
9754 cmd->y = (short)r.y;
9755 cmd->w = (unsigned short)r.w;
9756 cmd->h = (unsigned short)r.h;
9757 cmd->background = bg;
9758 cmd->foreground = fg;
9759 cmd->font = font;
9760 cmd->length = length;
9761 cmd->height = font->height;
9762 NK_MEMCPY(cmd->string, string, (nk_size)length);
9763 cmd->string[length] = '\0';
9764}
9765
9766
9767
9768
9769/* ===============================================================
9770 *
9771 * VERTEX
9772 *
9773 * ===============================================================*/
9774#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
9775NK_API void
9776nk_draw_list_init(struct nk_draw_list *list)
9777{
9778 nk_size i = 0;
9779 NK_ASSERT(list);
9780 if (!list) return;
9781 nk_zero(list, sizeof(*list));
9782 for (i = 0; i < NK_LEN(list->circle_vtx); ++i) {
9783 const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI;
9784 list->circle_vtx[i].x = (float)NK_COS(a);
9785 list->circle_vtx[i].y = (float)NK_SIN(a);
9786 }
9787}
9788NK_API void
9789nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config,
9790 struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements,
9791 enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa)
9792{
9793 NK_ASSERT(canvas);
9794 NK_ASSERT(config);
9795 NK_ASSERT(cmds);
9796 NK_ASSERT(vertices);
9797 NK_ASSERT(elements);
9798 if (!canvas || !config || !cmds || !vertices || !elements)
9799 return;
9800
9801 canvas->buffer = cmds;
9802 canvas->config = *config;
9803 canvas->elements = elements;
9804 canvas->vertices = vertices;
9805 canvas->line_AA = line_aa;
9806 canvas->shape_AA = shape_aa;
9807 canvas->clip_rect = nk_null_rect;
9808
9809 canvas->cmd_offset = 0;
9810 canvas->element_count = 0;
9811 canvas->vertex_count = 0;
9812 canvas->cmd_offset = 0;
9813 canvas->cmd_count = 0;
9814 canvas->path_count = 0;
9815}
9816NK_API const struct nk_draw_command*
9817nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
9818{
9819 nk_byte *memory;
9820 nk_size offset;
9821 const struct nk_draw_command *cmd;
9822
9823 NK_ASSERT(buffer);
9824 if (!buffer || !buffer->size || !canvas->cmd_count)
9825 return 0;
9826
9827 memory = (nk_byte*)buffer->memory.ptr;
9828 offset = buffer->memory.size - canvas->cmd_offset;
9829 cmd = nk_ptr_add(const struct nk_draw_command, memory, offset);
9830 return cmd;
9831}
9832NK_API const struct nk_draw_command*
9833nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)
9834{
9835 nk_size size;
9836 nk_size offset;
9837 nk_byte *memory;
9838 const struct nk_draw_command *end;
9839
9840 NK_ASSERT(buffer);
9841 NK_ASSERT(canvas);
9842 if (!buffer || !canvas)
9843 return 0;
9844
9845 memory = (nk_byte*)buffer->memory.ptr;
9846 size = buffer->memory.size;
9847 offset = size - canvas->cmd_offset;
9848 end = nk_ptr_add(const struct nk_draw_command, memory, offset);
9849 end -= (canvas->cmd_count-1);
9850 return end;
9851}
9852NK_API const struct nk_draw_command*
9853nk__draw_list_next(const struct nk_draw_command *cmd,
9854 const struct nk_buffer *buffer, const struct nk_draw_list *canvas)
9855{
9856 const struct nk_draw_command *end;
9857 NK_ASSERT(buffer);
9858 NK_ASSERT(canvas);
9859 if (!cmd || !buffer || !canvas)
9860 return 0;
9861
9862 end = nk__draw_list_end(canvas, buffer);
9863 if (cmd <= end) return 0;
9864 return (cmd-1);
9865}
9866NK_INTERN struct nk_vec2*
9867nk_draw_list_alloc_path(struct nk_draw_list *list, int count)
9868{
9869 struct nk_vec2 *points;
9870 NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2);
9871 NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2);
9872 points = (struct nk_vec2*)
9873 nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT,
9874 point_size * (nk_size)count, point_align);
9875
9876 if (!points) return 0;
9877 if (!list->path_offset) {
9878 void *memory = nk_buffer_memory(list->buffer);
9879 list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory);
9880 }
9881 list->path_count += (unsigned int)count;
9882 return points;
9883}
9884NK_INTERN struct nk_vec2
9885nk_draw_list_path_last(struct nk_draw_list *list)
9886{
9887 void *memory;
9888 struct nk_vec2 *point;
9889 NK_ASSERT(list->path_count);
9890 memory = nk_buffer_memory(list->buffer);
9891 point = nk_ptr_add(struct nk_vec2, memory, list->path_offset);
9892 point += (list->path_count-1);
9893 return *point;
9894}
9895NK_INTERN struct nk_draw_command*
9896nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip,
9897 nk_handle texture)
9898{
9899 NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command);
9900 NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command);
9901 struct nk_draw_command *cmd;
9902
9903 NK_ASSERT(list);
9904 cmd = (struct nk_draw_command*)
9905 nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align);
9906
9907 if (!cmd) return 0;
9908 if (!list->cmd_count) {
9909 nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer);
9910 nk_size total = nk_buffer_total(list->buffer);
9911 memory = nk_ptr_add(nk_byte, memory, total);
9912 list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd);
9913 }
9914
9915 cmd->elem_count = 0;
9916 cmd->clip_rect = clip;
9917 cmd->texture = texture;
9918#ifdef NK_INCLUDE_COMMAND_USERDATA
9919 cmd->userdata = list->userdata;
9920#endif
9921
9922 list->cmd_count++;
9923 list->clip_rect = clip;
9924 return cmd;
9925}
9926NK_INTERN struct nk_draw_command*
9927nk_draw_list_command_last(struct nk_draw_list *list)
9928{
9929 void *memory;
9930 nk_size size;
9931 struct nk_draw_command *cmd;
9932 NK_ASSERT(list->cmd_count);
9933
9934 memory = nk_buffer_memory(list->buffer);
9935 size = nk_buffer_total(list->buffer);
9936 cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset);
9937 return (cmd - (list->cmd_count-1));
9938}
9939NK_INTERN void
9940nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)
9941{
9942 NK_ASSERT(list);
9943 if (!list) return;
9944 if (!list->cmd_count) {
9945 nk_draw_list_push_command(list, rect, list->config.tex_null.texture);
9946 } else {
9947 struct nk_draw_command *prev = nk_draw_list_command_last(list);
9948 if (prev->elem_count == 0)
9949 prev->clip_rect = rect;
9950 nk_draw_list_push_command(list, rect, prev->texture);
9951 }
9952}
9953NK_INTERN void
9954nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture)
9955{
9956 NK_ASSERT(list);
9957 if (!list) return;
9958 if (!list->cmd_count) {
9959 nk_draw_list_push_command(list, nk_null_rect, texture);
9960 } else {
9961 struct nk_draw_command *prev = nk_draw_list_command_last(list);
9962 if (prev->elem_count == 0) {
9963 prev->texture = texture;
9964 #ifdef NK_INCLUDE_COMMAND_USERDATA
9965 prev->userdata = list->userdata;
9966 #endif
9967 } else if (prev->texture.id != texture.id
9968 #ifdef NK_INCLUDE_COMMAND_USERDATA
9969 || prev->userdata.id != list->userdata.id
9970 #endif
9971 ) {
9972 nk_draw_list_push_command(list, prev->clip_rect, texture);
9973 }
9974 }
9975}
9976#ifdef NK_INCLUDE_COMMAND_USERDATA
9977NK_API void
9978nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata)
9979{
9980 list->userdata = userdata;
9981}
9982#endif
9983NK_INTERN void*
9984nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count)
9985{
9986 void *vtx;
9987 NK_ASSERT(list);
9988 if (!list) return 0;
9989 vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT,
9990 list->config.vertex_size*count, list->config.vertex_alignment);
9991 if (!vtx) return 0;
9992 list->vertex_count += (unsigned int)count;
9993
9994 /* This assert triggers because your are drawing a lot of stuff and nuklear
9995 * defined `nk_draw_index` as `nk_ushort` to safe space be default.
9996 *
9997 * So you reached the maximum number of indices or rather vertexes.
9998 * To solve this issue please change typedef `nk_draw_index` to `nk_uint`
9999 * and don't forget to specify the new element size in your drawing
10000 * backend (OpenGL, DirectX, ...). For example in OpenGL for `glDrawElements`
10001 * instead of specifying `GL_UNSIGNED_SHORT` you have to define `GL_UNSIGNED_INT`.
10002 * Sorry for the inconvenience. */
10003 if(sizeof(nk_draw_index)==2) NK_ASSERT((list->vertex_count < NK_USHORT_MAX &&
10004 "To many vertices for 16-bit vertex indices. Please read comment above on how to solve this problem"));
10005 return vtx;
10006}
10007NK_INTERN nk_draw_index*
10008nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count)
10009{
10010 nk_draw_index *ids;
10011 struct nk_draw_command *cmd;
10012 NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index);
10013 NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index);
10014 NK_ASSERT(list);
10015 if (!list) return 0;
10016
10017 ids = (nk_draw_index*)
10018 nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align);
10019 if (!ids) return 0;
10020 cmd = nk_draw_list_command_last(list);
10021 list->element_count += (unsigned int)count;
10022 cmd->elem_count += (unsigned int)count;
10023 return ids;
10024}
10025NK_INTERN int
10026nk_draw_vertex_layout_element_is_end_of_layout(
10027 const struct nk_draw_vertex_layout_element *element)
10028{
10029 return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT ||
10030 element->format == NK_FORMAT_COUNT);
10031}
10032NK_INTERN void
10033nk_draw_vertex_color(void *attr, const float *vals,
10034 enum nk_draw_vertex_layout_format format)
10035{
10036 /* if this triggers you tried to provide a value format for a color */
10037 float val[4];
10038 NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN);
10039 NK_ASSERT(format <= NK_FORMAT_COLOR_END);
10040 if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return;
10041
10042 val[0] = NK_SATURATE(vals[0]);
10043 val[1] = NK_SATURATE(vals[1]);
10044 val[2] = NK_SATURATE(vals[2]);
10045 val[3] = NK_SATURATE(vals[3]);
10046
10047 switch (format) {
10048 default: NK_ASSERT(0 && "Invalid vertex layout color format"); break;
10049 case NK_FORMAT_R8G8B8A8:
10050 case NK_FORMAT_R8G8B8: {
10051 struct nk_color col = nk_rgba_fv(val);
10052 NK_MEMCPY(attr, &col.r, sizeof(col));
10053 } break;
10054 case NK_FORMAT_B8G8R8A8: {
10055 struct nk_color col = nk_rgba_fv(val);
10056 struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a);
10057 NK_MEMCPY(attr, &bgra, sizeof(bgra));
10058 } break;
10059 case NK_FORMAT_R16G15B16: {
10060 nk_ushort col[3];
10061 col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);
10062 col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);
10063 col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);
10064 NK_MEMCPY(attr, col, sizeof(col));
10065 } break;
10066 case NK_FORMAT_R16G15B16A16: {
10067 nk_ushort col[4];
10068 col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);
10069 col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);
10070 col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);
10071 col[3] = (nk_ushort)(val[3]*(float)NK_USHORT_MAX);
10072 NK_MEMCPY(attr, col, sizeof(col));
10073 } break;
10074 case NK_FORMAT_R32G32B32: {
10075 nk_uint col[3];
10076 col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);
10077 col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);
10078 col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);
10079 NK_MEMCPY(attr, col, sizeof(col));
10080 } break;
10081 case NK_FORMAT_R32G32B32A32: {
10082 nk_uint col[4];
10083 col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);
10084 col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);
10085 col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);
10086 col[3] = (nk_uint)(val[3]*(float)NK_UINT_MAX);
10087 NK_MEMCPY(attr, col, sizeof(col));
10088 } break;
10089 case NK_FORMAT_R32G32B32A32_FLOAT:
10090 NK_MEMCPY(attr, val, sizeof(float)*4);
10091 break;
10092 case NK_FORMAT_R32G32B32A32_DOUBLE: {
10093 double col[4];
10094 col[0] = (double)val[0];
10095 col[1] = (double)val[1];
10096 col[2] = (double)val[2];
10097 col[3] = (double)val[3];
10098 NK_MEMCPY(attr, col, sizeof(col));
10099 } break;
10100 case NK_FORMAT_RGB32:
10101 case NK_FORMAT_RGBA32: {
10102 struct nk_color col = nk_rgba_fv(val);
10103 nk_uint color = nk_color_u32(col);
10104 NK_MEMCPY(attr, &color, sizeof(color));
10105 } break; }
10106}
10107NK_INTERN void
10108nk_draw_vertex_element(void *dst, const float *values, int value_count,
10109 enum nk_draw_vertex_layout_format format)
10110{
10111 int value_index;
10112 void *attribute = dst;
10113 /* if this triggers you tried to provide a color format for a value */
10114 NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN);
10115 if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return;
10116 for (value_index = 0; value_index < value_count; ++value_index) {
10117 switch (format) {
10118 default: NK_ASSERT(0 && "invalid vertex layout format"); break;
10119 case NK_FORMAT_SCHAR: {
10120 char value = (char)NK_CLAMP((float)NK_SCHAR_MIN, values[value_index], (float)NK_SCHAR_MAX);
10121 NK_MEMCPY(attribute, &value, sizeof(value));
10122 attribute = (void*)((char*)attribute + sizeof(char));
10123 } break;
10124 case NK_FORMAT_SSHORT: {
10125 nk_short value = (nk_short)NK_CLAMP((float)NK_SSHORT_MIN, values[value_index], (float)NK_SSHORT_MAX);
10126 NK_MEMCPY(attribute, &value, sizeof(value));
10127 attribute = (void*)((char*)attribute + sizeof(value));
10128 } break;
10129 case NK_FORMAT_SINT: {
10130 nk_int value = (nk_int)NK_CLAMP((float)NK_SINT_MIN, values[value_index], (float)NK_SINT_MAX);
10131 NK_MEMCPY(attribute, &value, sizeof(value));
10132 attribute = (void*)((char*)attribute + sizeof(nk_int));
10133 } break;
10134 case NK_FORMAT_UCHAR: {
10135 unsigned char value = (unsigned char)NK_CLAMP((float)NK_UCHAR_MIN, values[value_index], (float)NK_UCHAR_MAX);
10136 NK_MEMCPY(attribute, &value, sizeof(value));
10137 attribute = (void*)((char*)attribute + sizeof(unsigned char));
10138 } break;
10139 case NK_FORMAT_USHORT: {
10140 nk_ushort value = (nk_ushort)NK_CLAMP((float)NK_USHORT_MIN, values[value_index], (float)NK_USHORT_MAX);
10141 NK_MEMCPY(attribute, &value, sizeof(value));
10142 attribute = (void*)((char*)attribute + sizeof(value));
10143 } break;
10144 case NK_FORMAT_UINT: {
10145 nk_uint value = (nk_uint)NK_CLAMP((float)NK_UINT_MIN, values[value_index], (float)NK_UINT_MAX);
10146 NK_MEMCPY(attribute, &value, sizeof(value));
10147 attribute = (void*)((char*)attribute + sizeof(nk_uint));
10148 } break;
10149 case NK_FORMAT_FLOAT:
10150 NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index]));
10151 attribute = (void*)((char*)attribute + sizeof(float));
10152 break;
10153 case NK_FORMAT_DOUBLE: {
10154 double value = (double)values[value_index];
10155 NK_MEMCPY(attribute, &value, sizeof(value));
10156 attribute = (void*)((char*)attribute + sizeof(double));
10157 } break;
10158 }
10159 }
10160}
10161NK_INTERN void*
10162nk_draw_vertex(void *dst, const struct nk_convert_config *config,
10163 struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color)
10164{
10165 void *result = (void*)((char*)dst + config->vertex_size);
10166 const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout;
10167 while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) {
10168 void *address = (void*)((char*)dst + elem_iter->offset);
10169 switch (elem_iter->attribute) {
10170 case NK_VERTEX_ATTRIBUTE_COUNT:
10171 default: NK_ASSERT(0 && "wrong element attribute"); break;
10172 case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break;
10173 case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break;
10174 case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break;
10175 }
10176 elem_iter++;
10177 }
10178 return result;
10179}
10180NK_API void
10181nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points,
10182 const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed,
10183 float thickness, enum nk_anti_aliasing aliasing)
10184{
10185 nk_size count;
10186 int thick_line;
10187 struct nk_colorf col;
10188 struct nk_colorf col_trans;
10189 NK_ASSERT(list);
10190 if (!list || points_count < 2) return;
10191
10192 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
10193 count = points_count;
10194 if (!closed) count = points_count-1;
10195 thick_line = thickness > 1.0f;
10196
10197#ifdef NK_INCLUDE_COMMAND_USERDATA
10198 nk_draw_list_push_userdata(list, list->userdata);
10199#endif
10200
10201 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
10202 nk_color_fv(&col.r, color);
10203 col_trans = col;
10204 col_trans.a = 0;
10205
10206 if (aliasing == NK_ANTI_ALIASING_ON) {
10207 /* ANTI-ALIASED STROKE */
10208 const float AA_SIZE = 1.0f;
10209 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
10210 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
10211
10212 /* allocate vertices and elements */
10213 nk_size i1 = 0;
10214 nk_size vertex_offset;
10215 nk_size index = list->vertex_count;
10216
10217 const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12);
10218 const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3);
10219
10220 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
10221 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
10222
10223 nk_size size;
10224 struct nk_vec2 *normals, *temp;
10225 if (!vtx || !ids) return;
10226
10227 /* temporary allocate normals + points */
10228 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
10229 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
10230 size = pnt_size * ((thick_line) ? 5 : 3) * points_count;
10231 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
10232 if (!normals) return;
10233 temp = normals + points_count;
10234
10235 /* make sure vertex pointer is still correct */
10236 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
10237
10238 /* calculate normals */
10239 for (i1 = 0; i1 < count; ++i1) {
10240 const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
10241 struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]);
10242 float len;
10243
10244 /* vec2 inverted length */
10245 len = nk_vec2_len_sqr(diff);
10246 if (len != 0.0f)
10247 len = NK_INV_SQRT(len);
10248 else len = 1.0f;
10249
10250 diff = nk_vec2_muls(diff, len);
10251 normals[i1].x = diff.y;
10252 normals[i1].y = -diff.x;
10253 }
10254
10255 if (!closed)
10256 normals[points_count-1] = normals[points_count-2];
10257
10258 if (!thick_line) {
10259 nk_size idx1, i;
10260 if (!closed) {
10261 struct nk_vec2 d;
10262 temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE));
10263 temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE));
10264 d = nk_vec2_muls(normals[points_count-1], AA_SIZE);
10265 temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d);
10266 temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d);
10267 }
10268
10269 /* fill elements */
10270 idx1 = index;
10271 for (i1 = 0; i1 < count; i1++) {
10272 struct nk_vec2 dm;
10273 float dmr2;
10274 nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);
10275 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3);
10276
10277 /* average normals */
10278 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
10279 dmr2 = dm.x * dm.x + dm.y* dm.y;
10280 if (dmr2 > 0.000001f) {
10281 float scale = 1.0f/dmr2;
10282 scale = NK_MIN(100.0f, scale);
10283 dm = nk_vec2_muls(dm, scale);
10284 }
10285
10286 dm = nk_vec2_muls(dm, AA_SIZE);
10287 temp[i2*2+0] = nk_vec2_add(points[i2], dm);
10288 temp[i2*2+1] = nk_vec2_sub(points[i2], dm);
10289
10290 ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0);
10291 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
10292 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0);
10293 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
10294 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
10295 ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1);
10296 ids += 12;
10297 idx1 = idx2;
10298 }
10299
10300 /* fill vertices */
10301 for (i = 0; i < points_count; ++i) {
10302 const struct nk_vec2 uv = list->config.tex_null.uv;
10303 vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);
10304 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);
10305 vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);
10306 }
10307 } else {
10308 nk_size idx1, i;
10309 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
10310 if (!closed) {
10311 struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE);
10312 struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness);
10313
10314 temp[0] = nk_vec2_add(points[0], d1);
10315 temp[1] = nk_vec2_add(points[0], d2);
10316 temp[2] = nk_vec2_sub(points[0], d2);
10317 temp[3] = nk_vec2_sub(points[0], d1);
10318
10319 d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE);
10320 d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness);
10321
10322 temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1);
10323 temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2);
10324 temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2);
10325 temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1);
10326 }
10327
10328 /* add all elements */
10329 idx1 = index;
10330 for (i1 = 0; i1 < count; ++i1) {
10331 struct nk_vec2 dm_out, dm_in;
10332 const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1);
10333 nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4);
10334
10335 /* average normals */
10336 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);
10337 float dmr2 = dm.x * dm.x + dm.y* dm.y;
10338 if (dmr2 > 0.000001f) {
10339 float scale = 1.0f/dmr2;
10340 scale = NK_MIN(100.0f, scale);
10341 dm = nk_vec2_muls(dm, scale);
10342 }
10343
10344 dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE));
10345 dm_in = nk_vec2_muls(dm, half_inner_thickness);
10346 temp[i2*4+0] = nk_vec2_add(points[i2], dm_out);
10347 temp[i2*4+1] = nk_vec2_add(points[i2], dm_in);
10348 temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in);
10349 temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out);
10350
10351 /* add indexes */
10352 ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1);
10353 ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);
10354 ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1);
10355 ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);
10356 ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);
10357 ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1);
10358 ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2);
10359 ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3);
10360 ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2);
10361 ids += 18;
10362 idx1 = idx2;
10363 }
10364
10365 /* add vertices */
10366 for (i = 0; i < points_count; ++i) {
10367 const struct nk_vec2 uv = list->config.tex_null.uv;
10368 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);
10369 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);
10370 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);
10371 vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans);
10372 }
10373 }
10374 /* free temporary normals + points */
10375 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
10376 } else {
10377 /* NON ANTI-ALIASED STROKE */
10378 nk_size i1 = 0;
10379 nk_size idx = list->vertex_count;
10380 const nk_size idx_count = count * 6;
10381 const nk_size vtx_count = count * 4;
10382 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
10383 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
10384 if (!vtx || !ids) return;
10385
10386 for (i1 = 0; i1 < count; ++i1) {
10387 float dx, dy;
10388 const struct nk_vec2 uv = list->config.tex_null.uv;
10389 const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;
10390 const struct nk_vec2 p1 = points[i1];
10391 const struct nk_vec2 p2 = points[i2];
10392 struct nk_vec2 diff = nk_vec2_sub(p2, p1);
10393 float len;
10394
10395 /* vec2 inverted length */
10396 len = nk_vec2_len_sqr(diff);
10397 if (len != 0.0f)
10398 len = NK_INV_SQRT(len);
10399 else len = 1.0f;
10400 diff = nk_vec2_muls(diff, len);
10401
10402 /* add vertices */
10403 dx = diff.x * (thickness * 0.5f);
10404 dy = diff.y * (thickness * 0.5f);
10405
10406 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col);
10407 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col);
10408 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col);
10409 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col);
10410
10411 ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1);
10412 ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0);
10413 ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3);
10414
10415 ids += 6;
10416 idx += 4;
10417 }
10418 }
10419}
10420NK_API void
10421nk_draw_list_fill_poly_convex(struct nk_draw_list *list,
10422 const struct nk_vec2 *points, const unsigned int points_count,
10423 struct nk_color color, enum nk_anti_aliasing aliasing)
10424{
10425 struct nk_colorf col;
10426 struct nk_colorf col_trans;
10427
10428 NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);
10429 NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);
10430 NK_ASSERT(list);
10431 if (!list || points_count < 3) return;
10432
10433#ifdef NK_INCLUDE_COMMAND_USERDATA
10434 nk_draw_list_push_userdata(list, list->userdata);
10435#endif
10436
10437 color.a = (nk_byte)((float)color.a * list->config.global_alpha);
10438 nk_color_fv(&col.r, color);
10439 col_trans = col;
10440 col_trans.a = 0;
10441
10442 if (aliasing == NK_ANTI_ALIASING_ON) {
10443 nk_size i = 0;
10444 nk_size i0 = 0;
10445 nk_size i1 = 0;
10446
10447 const float AA_SIZE = 1.0f;
10448 nk_size vertex_offset = 0;
10449 nk_size index = list->vertex_count;
10450
10451 const nk_size idx_count = (points_count-2)*3 + points_count*6;
10452 const nk_size vtx_count = (points_count*2);
10453
10454 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
10455 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
10456
10457 nk_size size = 0;
10458 struct nk_vec2 *normals = 0;
10459 unsigned int vtx_inner_idx = (unsigned int)(index + 0);
10460 unsigned int vtx_outer_idx = (unsigned int)(index + 1);
10461 if (!vtx || !ids) return;
10462
10463 /* temporary allocate normals */
10464 vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);
10465 nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);
10466 size = pnt_size * points_count;
10467 normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);
10468 if (!normals) return;
10469 vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);
10470
10471 /* add elements */
10472 for (i = 2; i < points_count; i++) {
10473 ids[0] = (nk_draw_index)(vtx_inner_idx);
10474 ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1));
10475 ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1));
10476 ids += 3;
10477 }
10478
10479 /* compute normals */
10480 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
10481 struct nk_vec2 p0 = points[i0];
10482 struct nk_vec2 p1 = points[i1];
10483 struct nk_vec2 diff = nk_vec2_sub(p1, p0);
10484
10485 /* vec2 inverted length */
10486 float len = nk_vec2_len_sqr(diff);
10487 if (len != 0.0f)
10488 len = NK_INV_SQRT(len);
10489 else len = 1.0f;
10490 diff = nk_vec2_muls(diff, len);
10491
10492 normals[i0].x = diff.y;
10493 normals[i0].y = -diff.x;
10494 }
10495
10496 /* add vertices + indexes */
10497 for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
10498 const struct nk_vec2 uv = list->config.tex_null.uv;
10499 struct nk_vec2 n0 = normals[i0];
10500 struct nk_vec2 n1 = normals[i1];
10501 struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);
10502 float dmr2 = dm.x*dm.x + dm.y*dm.y;
10503 if (dmr2 > 0.000001f) {
10504 float scale = 1.0f / dmr2;
10505 scale = NK_MIN(scale, 100.0f);
10506 dm = nk_vec2_muls(dm, scale);
10507 }
10508 dm = nk_vec2_muls(dm, AA_SIZE * 0.5f);
10509
10510 /* add vertices */
10511 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col);
10512 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans);
10513
10514 /* add indexes */
10515 ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
10516 ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1));
10517 ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
10518 ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1));
10519 ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1));
10520 ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1));
10521 ids += 6;
10522 }
10523 /* free temporary normals + points */
10524 nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);
10525 } else {
10526 nk_size i = 0;
10527 nk_size index = list->vertex_count;
10528 const nk_size idx_count = (points_count-2)*3;
10529 const nk_size vtx_count = points_count;
10530 void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);
10531 nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);
10532
10533 if (!vtx || !ids) return;
10534 for (i = 0; i < vtx_count; ++i)
10535 vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.tex_null.uv, col);
10536 for (i = 2; i < points_count; ++i) {
10537 ids[0] = (nk_draw_index)index;
10538 ids[1] = (nk_draw_index)(index+ i - 1);
10539 ids[2] = (nk_draw_index)(index+i);
10540 ids += 3;
10541 }
10542 }
10543}
10544NK_API void
10545nk_draw_list_path_clear(struct nk_draw_list *list)
10546{
10547 NK_ASSERT(list);
10548 if (!list) return;
10549 nk_buffer_reset(list->buffer, NK_BUFFER_FRONT);
10550 list->path_count = 0;
10551 list->path_offset = 0;
10552}
10553NK_API void
10554nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)
10555{
10556 struct nk_vec2 *points = 0;
10557 struct nk_draw_command *cmd = 0;
10558 NK_ASSERT(list);
10559 if (!list) return;
10560 if (!list->cmd_count)
10561 nk_draw_list_add_clip(list, nk_null_rect);
10562
10563 cmd = nk_draw_list_command_last(list);
10564 if (cmd && cmd->texture.ptr != list->config.tex_null.texture.ptr)
10565 nk_draw_list_push_image(list, list->config.tex_null.texture);
10566
10567 points = nk_draw_list_alloc_path(list, 1);
10568 if (!points) return;
10569 points[0] = pos;
10570}
10571NK_API void
10572nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center,
10573 float radius, int a_min, int a_max)
10574{
10575 int a = 0;
10576 NK_ASSERT(list);
10577 if (!list) return;
10578 if (a_min <= a_max) {
10579 for (a = a_min; a <= a_max; a++) {
10580 const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)];
10581 const float x = center.x + c.x * radius;
10582 const float y = center.y + c.y * radius;
10583 nk_draw_list_path_line_to(list, nk_vec2(x, y));
10584 }
10585 }
10586}
10587NK_API void
10588nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center,
10589 float radius, float a_min, float a_max, unsigned int segments)
10590{
10591 unsigned int i = 0;
10592 NK_ASSERT(list);
10593 if (!list) return;
10594 if (radius == 0.0f) return;
10595
10596 /* This algorithm for arc drawing relies on these two trigonometric identities[1]:
10597 sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b)
10598 cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b)
10599
10600 Two coordinates (x, y) of a point on a circle centered on
10601 the origin can be written in polar form as:
10602 x = r * cos(a)
10603 y = r * sin(a)
10604 where r is the radius of the circle,
10605 a is the angle between (x, y) and the origin.
10606
10607 This allows us to rotate the coordinates around the
10608 origin by an angle b using the following transformation:
10609 x' = r * cos(a + b) = x * cos(b) - y * sin(b)
10610 y' = r * sin(a + b) = y * cos(b) + x * sin(b)
10611
10612 [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities
10613 */
10614 {const float d_angle = (a_max - a_min) / (float)segments;
10615 const float sin_d = (float)NK_SIN(d_angle);
10616 const float cos_d = (float)NK_COS(d_angle);
10617
10618 float cx = (float)NK_COS(a_min) * radius;
10619 float cy = (float)NK_SIN(a_min) * radius;
10620 for(i = 0; i <= segments; ++i) {
10621 float new_cx, new_cy;
10622 const float x = center.x + cx;
10623 const float y = center.y + cy;
10624 nk_draw_list_path_line_to(list, nk_vec2(x, y));
10625
10626 new_cx = cx * cos_d - cy * sin_d;
10627 new_cy = cy * cos_d + cx * sin_d;
10628 cx = new_cx;
10629 cy = new_cy;
10630 }}
10631}
10632NK_API void
10633nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a,
10634 struct nk_vec2 b, float rounding)
10635{
10636 float r;
10637 NK_ASSERT(list);
10638 if (!list) return;
10639 r = rounding;
10640 r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x));
10641 r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y));
10642
10643 if (r == 0.0f) {
10644 nk_draw_list_path_line_to(list, a);
10645 nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y));
10646 nk_draw_list_path_line_to(list, b);
10647 nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y));
10648 } else {
10649 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9);
10650 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12);
10651 nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3);
10652 nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6);
10653 }
10654}
10655NK_API void
10656nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2,
10657 struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments)
10658{
10659 float t_step;
10660 unsigned int i_step;
10661 struct nk_vec2 p1;
10662
10663 NK_ASSERT(list);
10664 NK_ASSERT(list->path_count);
10665 if (!list || !list->path_count) return;
10666 num_segments = NK_MAX(num_segments, 1);
10667
10668 p1 = nk_draw_list_path_last(list);
10669 t_step = 1.0f/(float)num_segments;
10670 for (i_step = 1; i_step <= num_segments; ++i_step) {
10671 float t = t_step * (float)i_step;
10672 float u = 1.0f - t;
10673 float w1 = u*u*u;
10674 float w2 = 3*u*u*t;
10675 float w3 = 3*u*t*t;
10676 float w4 = t * t *t;
10677 float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
10678 float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
10679 nk_draw_list_path_line_to(list, nk_vec2(x,y));
10680 }
10681}
10682NK_API void
10683nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color)
10684{
10685 struct nk_vec2 *points;
10686 NK_ASSERT(list);
10687 if (!list) return;
10688 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
10689 nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA);
10690 nk_draw_list_path_clear(list);
10691}
10692NK_API void
10693nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color,
10694 enum nk_draw_list_stroke closed, float thickness)
10695{
10696 struct nk_vec2 *points;
10697 NK_ASSERT(list);
10698 if (!list) return;
10699 points = (struct nk_vec2*)nk_buffer_memory(list->buffer);
10700 nk_draw_list_stroke_poly_line(list, points, list->path_count, color,
10701 closed, thickness, list->config.line_AA);
10702 nk_draw_list_path_clear(list);
10703}
10704NK_API void
10705nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a,
10706 struct nk_vec2 b, struct nk_color col, float thickness)
10707{
10708 NK_ASSERT(list);
10709 if (!list || !col.a) return;
10710 if (list->line_AA == NK_ANTI_ALIASING_ON) {
10711 nk_draw_list_path_line_to(list, a);
10712 nk_draw_list_path_line_to(list, b);
10713 } else {
10714 nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f)));
10715 nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f)));
10716 }
10717 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
10718}
10719NK_API void
10720nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect,
10721 struct nk_color col, float rounding)
10722{
10723 NK_ASSERT(list);
10724 if (!list || !col.a) return;
10725
10726 if (list->line_AA == NK_ANTI_ALIASING_ON) {
10727 nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),
10728 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
10729 } else {
10730 nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),
10731 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
10732 } nk_draw_list_path_fill(list, col);
10733}
10734NK_API void
10735nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect,
10736 struct nk_color col, float rounding, float thickness)
10737{
10738 NK_ASSERT(list);
10739 if (!list || !col.a) return;
10740 if (list->line_AA == NK_ANTI_ALIASING_ON) {
10741 nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),
10742 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
10743 } else {
10744 nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),
10745 nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);
10746 } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
10747}
10748NK_API void
10749nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect,
10750 struct nk_color left, struct nk_color top, struct nk_color right,
10751 struct nk_color bottom)
10752{
10753 void *vtx;
10754 struct nk_colorf col_left, col_top;
10755 struct nk_colorf col_right, col_bottom;
10756 nk_draw_index *idx;
10757 nk_draw_index index;
10758
10759 nk_color_fv(&col_left.r, left);
10760 nk_color_fv(&col_right.r, right);
10761 nk_color_fv(&col_top.r, top);
10762 nk_color_fv(&col_bottom.r, bottom);
10763
10764 NK_ASSERT(list);
10765 if (!list) return;
10766
10767 nk_draw_list_push_image(list, list->config.tex_null.texture);
10768 index = (nk_draw_index)list->vertex_count;
10769 vtx = nk_draw_list_alloc_vertices(list, 4);
10770 idx = nk_draw_list_alloc_elements(list, 6);
10771 if (!vtx || !idx) return;
10772
10773 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
10774 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
10775 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
10776
10777 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.tex_null.uv, col_left);
10778 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.tex_null.uv, col_top);
10779 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.tex_null.uv, col_right);
10780 vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.tex_null.uv, col_bottom);
10781}
10782NK_API void
10783nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,
10784 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col)
10785{
10786 NK_ASSERT(list);
10787 if (!list || !col.a) return;
10788 nk_draw_list_path_line_to(list, a);
10789 nk_draw_list_path_line_to(list, b);
10790 nk_draw_list_path_line_to(list, c);
10791 nk_draw_list_path_fill(list, col);
10792}
10793NK_API void
10794nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a,
10795 struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness)
10796{
10797 NK_ASSERT(list);
10798 if (!list || !col.a) return;
10799 nk_draw_list_path_line_to(list, a);
10800 nk_draw_list_path_line_to(list, b);
10801 nk_draw_list_path_line_to(list, c);
10802 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
10803}
10804NK_API void
10805nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center,
10806 float radius, struct nk_color col, unsigned int segs)
10807{
10808 float a_max;
10809 NK_ASSERT(list);
10810 if (!list || !col.a) return;
10811 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
10812 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
10813 nk_draw_list_path_fill(list, col);
10814}
10815NK_API void
10816nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center,
10817 float radius, struct nk_color col, unsigned int segs, float thickness)
10818{
10819 float a_max;
10820 NK_ASSERT(list);
10821 if (!list || !col.a) return;
10822 a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;
10823 nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);
10824 nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);
10825}
10826NK_API void
10827nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0,
10828 struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1,
10829 struct nk_color col, unsigned int segments, float thickness)
10830{
10831 NK_ASSERT(list);
10832 if (!list || !col.a) return;
10833 nk_draw_list_path_line_to(list, p0);
10834 nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments);
10835 nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);
10836}
10837NK_INTERN void
10838nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a,
10839 struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc,
10840 struct nk_color color)
10841{
10842 void *vtx;
10843 struct nk_vec2 uvb;
10844 struct nk_vec2 uvd;
10845 struct nk_vec2 b;
10846 struct nk_vec2 d;
10847
10848 struct nk_colorf col;
10849 nk_draw_index *idx;
10850 nk_draw_index index;
10851 NK_ASSERT(list);
10852 if (!list) return;
10853
10854 nk_color_fv(&col.r, color);
10855 uvb = nk_vec2(uvc.x, uva.y);
10856 uvd = nk_vec2(uva.x, uvc.y);
10857 b = nk_vec2(c.x, a.y);
10858 d = nk_vec2(a.x, c.y);
10859
10860 index = (nk_draw_index)list->vertex_count;
10861 vtx = nk_draw_list_alloc_vertices(list, 4);
10862 idx = nk_draw_list_alloc_elements(list, 6);
10863 if (!vtx || !idx) return;
10864
10865 idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);
10866 idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
10867 idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
10868
10869 vtx = nk_draw_vertex(vtx, &list->config, a, uva, col);
10870 vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col);
10871 vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col);
10872 vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col);
10873}
10874NK_API void
10875nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture,
10876 struct nk_rect rect, struct nk_color color)
10877{
10878 NK_ASSERT(list);
10879 if (!list) return;
10880 /* push new command with given texture */
10881 nk_draw_list_push_image(list, texture.handle);
10882 if (nk_image_is_subimage(&texture)) {
10883 /* add region inside of the texture */
10884 struct nk_vec2 uv[2];
10885 uv[0].x = (float)texture.region[0]/(float)texture.w;
10886 uv[0].y = (float)texture.region[1]/(float)texture.h;
10887 uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w;
10888 uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h;
10889 nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
10890 nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color);
10891 } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),
10892 nk_vec2(rect.x + rect.w, rect.y + rect.h),
10893 nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color);
10894}
10895NK_API void
10896nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font,
10897 struct nk_rect rect, const char *text, int len, float font_height,
10898 struct nk_color fg)
10899{
10900 float x = 0;
10901 int text_len = 0;
10902 nk_rune unicode = 0;
10903 nk_rune next = 0;
10904 int glyph_len = 0;
10905 int next_glyph_len = 0;
10906 struct nk_user_font_glyph g;
10907
10908 NK_ASSERT(list);
10909 if (!list || !len || !text) return;
10910 if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
10911 list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return;
10912
10913 nk_draw_list_push_image(list, font->texture);
10914 x = rect.x;
10915 glyph_len = nk_utf_decode(text, &unicode, len);
10916 if (!glyph_len) return;
10917
10918 /* draw every glyph image */
10919 fg.a = (nk_byte)((float)fg.a * list->config.global_alpha);
10920 while (text_len < len && glyph_len) {
10921 float gx, gy, gh, gw;
10922 float char_width = 0;
10923 if (unicode == NK_UTF_INVALID) break;
10924
10925 /* query currently drawn glyph information */
10926 next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);
10927 font->query(font->userdata, font_height, &g, unicode,
10928 (next == NK_UTF_INVALID) ? '\0' : next);
10929
10930 /* calculate and draw glyph drawing rectangle and image */
10931 gx = x + g.offset.x;
10932 gy = rect.y + g.offset.y;
10933 gw = g.width; gh = g.height;
10934 char_width = g.xadvance;
10935 nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh),
10936 g.uv[0], g.uv[1], fg);
10937
10938 /* offset next glyph */
10939 text_len += glyph_len;
10940 x += char_width;
10941 glyph_len = next_glyph_len;
10942 unicode = next;
10943 }
10944}
10945NK_API nk_flags
10946nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,
10947 struct nk_buffer *vertices, struct nk_buffer *elements,
10948 const struct nk_convert_config *config)
10949{
10950 nk_flags res = NK_CONVERT_SUCCESS;
10951 const struct nk_command *cmd;
10952 NK_ASSERT(ctx);
10953 NK_ASSERT(cmds);
10954 NK_ASSERT(vertices);
10955 NK_ASSERT(elements);
10956 NK_ASSERT(config);
10957 NK_ASSERT(config->vertex_layout);
10958 NK_ASSERT(config->vertex_size);
10959 if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout)
10960 return NK_CONVERT_INVALID_PARAM;
10961
10962 nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements,
10963 config->line_AA, config->shape_AA);
10964 nk_foreach(cmd, ctx)
10965 {
10966#ifdef NK_INCLUDE_COMMAND_USERDATA
10967 ctx->draw_list.userdata = cmd->userdata;
10968#endif
10969 switch (cmd->type) {
10970 case NK_COMMAND_NOP: break;
10971 case NK_COMMAND_SCISSOR: {
10972 const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;
10973 nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h));
10974 } break;
10975 case NK_COMMAND_LINE: {
10976 const struct nk_command_line *l = (const struct nk_command_line*)cmd;
10977 nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y),
10978 nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness);
10979 } break;
10980 case NK_COMMAND_CURVE: {
10981 const struct nk_command_curve *q = (const struct nk_command_curve*)cmd;
10982 nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y),
10983 nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x,
10984 q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color,
10985 config->curve_segment_count, q->line_thickness);
10986 } break;
10987 case NK_COMMAND_RECT: {
10988 const struct nk_command_rect *r = (const struct nk_command_rect*)cmd;
10989 nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
10990 r->color, (float)r->rounding, r->line_thickness);
10991 } break;
10992 case NK_COMMAND_RECT_FILLED: {
10993 const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd;
10994 nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
10995 r->color, (float)r->rounding);
10996 } break;
10997 case NK_COMMAND_RECT_MULTI_COLOR: {
10998 const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd;
10999 nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),
11000 r->left, r->top, r->right, r->bottom);
11001 } break;
11002 case NK_COMMAND_CIRCLE: {
11003 const struct nk_command_circle *c = (const struct nk_command_circle*)cmd;
11004 nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
11005 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
11006 config->circle_segment_count, c->line_thickness);
11007 } break;
11008 case NK_COMMAND_CIRCLE_FILLED: {
11009 const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
11010 nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,
11011 (float)c->y + (float)c->h/2), (float)c->w/2, c->color,
11012 config->circle_segment_count);
11013 } break;
11014 case NK_COMMAND_ARC: {
11015 const struct nk_command_arc *c = (const struct nk_command_arc*)cmd;
11016 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
11017 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
11018 c->a[0], c->a[1], config->arc_segment_count);
11019 nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness);
11020 } break;
11021 case NK_COMMAND_ARC_FILLED: {
11022 const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd;
11023 nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));
11024 nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,
11025 c->a[0], c->a[1], config->arc_segment_count);
11026 nk_draw_list_path_fill(&ctx->draw_list, c->color);
11027 } break;
11028 case NK_COMMAND_TRIANGLE: {
11029 const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;
11030 nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
11031 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color,
11032 t->line_thickness);
11033 } break;
11034 case NK_COMMAND_TRIANGLE_FILLED: {
11035 const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;
11036 nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),
11037 nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color);
11038 } break;
11039 case NK_COMMAND_POLYGON: {
11040 int i;
11041 const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd;
11042 for (i = 0; i < p->point_count; ++i) {
11043 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
11044 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
11045 }
11046 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness);
11047 } break;
11048 case NK_COMMAND_POLYGON_FILLED: {
11049 int i;
11050 const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;
11051 for (i = 0; i < p->point_count; ++i) {
11052 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
11053 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
11054 }
11055 nk_draw_list_path_fill(&ctx->draw_list, p->color);
11056 } break;
11057 case NK_COMMAND_POLYLINE: {
11058 int i;
11059 const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd;
11060 for (i = 0; i < p->point_count; ++i) {
11061 struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);
11062 nk_draw_list_path_line_to(&ctx->draw_list, pnt);
11063 }
11064 nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness);
11065 } break;
11066 case NK_COMMAND_TEXT: {
11067 const struct nk_command_text *t = (const struct nk_command_text*)cmd;
11068 nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h),
11069 t->string, t->length, t->height, t->foreground);
11070 } break;
11071 case NK_COMMAND_IMAGE: {
11072 const struct nk_command_image *i = (const struct nk_command_image*)cmd;
11073 nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col);
11074 } break;
11075 case NK_COMMAND_CUSTOM: {
11076 const struct nk_command_custom *c = (const struct nk_command_custom*)cmd;
11077 c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data);
11078 } break;
11079 default: break;
11080 }
11081 }
11082 res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0;
11083 res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0;
11084 res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0;
11085 return res;
11086}
11087NK_API const struct nk_draw_command*
11088nk__draw_begin(const struct nk_context *ctx,
11089 const struct nk_buffer *buffer)
11090{
11091 return nk__draw_list_begin(&ctx->draw_list, buffer);
11092}
11093NK_API const struct nk_draw_command*
11094nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer)
11095{
11096 return nk__draw_list_end(&ctx->draw_list, buffer);
11097}
11098NK_API const struct nk_draw_command*
11099nk__draw_next(const struct nk_draw_command *cmd,
11100 const struct nk_buffer *buffer, const struct nk_context *ctx)
11101{
11102 return nk__draw_list_next(cmd, buffer, &ctx->draw_list);
11103}
11104#endif
11105
11106
11107/* stb_rect_pack.h - v1.01 - public domain - rectangle packing */
11108/* Sean Barrett 2014 */
11109/* */
11110/* Useful for e.g. packing rectangular textures into an atlas. */
11111/* Does not do rotation. */
11112/* */
11113/* Before #including, */
11114/* */
11115/* #define STB_RECT_PACK_IMPLEMENTATION */
11116/* */
11117/* in the file that you want to have the implementation. */
11118/* */
11119/* Not necessarily the awesomest packing method, but better than */
11120/* the totally naive one in stb_truetype (which is primarily what */
11121/* this is meant to replace). */
11122/* */
11123/* Has only had a few tests run, may have issues. */
11124/* */
11125/* More docs to come. */
11126/* */
11127/* No memory allocations; uses qsort() and assert() from stdlib. */
11128/* Can override those by defining STBRP_SORT and STBRP_ASSERT. */
11129/* */
11130/* This library currently uses the Skyline Bottom-Left algorithm. */
11131/* */
11132/* Please note: better rectangle packers are welcome! Please */
11133/* implement them to the same API, but with a different init */
11134/* function. */
11135/* */
11136/* Credits */
11137/* */
11138/* Library */
11139/* Sean Barrett */
11140/* Minor features */
11141/* Martins Mozeiko */
11142/* github:IntellectualKitty */
11143/* */
11144/* Bugfixes / warning fixes */
11145/* Jeremy Jaussaud */
11146/* Fabian Giesen */
11147/* */
11148/* Version history: */
11149/* */
11150/* 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section */
11151/* 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles */
11152/* 0.99 (2019-02-07) warning fixes */
11153/* 0.11 (2017-03-03) return packing success/fail result */
11154/* 0.10 (2016-10-25) remove cast-away-const to avoid warnings */
11155/* 0.09 (2016-08-27) fix compiler warnings */
11156/* 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) */
11157/* 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) */
11158/* 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort */
11159/* 0.05: added STBRP_ASSERT to allow replacing assert */
11160/* 0.04: fixed minor bug in STBRP_LARGE_RECTS support */
11161/* 0.01: initial release */
11162/* */
11163/* LICENSE */
11164/* */
11165/* See end of file for license information. */
11166
11167/* //////////////////////////////////////////////////////////////////////////// */
11168/* */
11169/* INCLUDE SECTION */
11170/* */
11171
11172#ifndef STB_INCLUDE_STB_RECT_PACK_H
11173#define STB_INCLUDE_STB_RECT_PACK_H
11174
11175#define STB_RECT_PACK_VERSION 1
11176
11177#ifdef STBRP_STATIC
11178#define STBRP_DEF static
11179#else
11180#define STBRP_DEF extern
11181#endif
11182
11183#ifdef __cplusplus
11184extern "C" {
11185#endif
11186
11187typedef struct stbrp_context stbrp_context;
11188typedef struct stbrp_node stbrp_node;
11189typedef struct stbrp_rect stbrp_rect;
11190
11191typedef int stbrp_coord;
11192
11193#define STBRP__MAXVAL 0x7fffffff
11194/* Mostly for internal use, but this is the maximum supported coordinate value. */
11195
11196STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
11197/* Assign packed locations to rectangles. The rectangles are of type */
11198/* 'stbrp_rect' defined below, stored in the array 'rects', and there */
11199/* are 'num_rects' many of them. */
11200/* */
11201/* Rectangles which are successfully packed have the 'was_packed' flag */
11202/* set to a non-zero value and 'x' and 'y' store the minimum location */
11203/* on each axis (i.e. bottom-left in cartesian coordinates, top-left */
11204/* if you imagine y increasing downwards). Rectangles which do not fit */
11205/* have the 'was_packed' flag set to 0. */
11206/* */
11207/* You should not try to access the 'rects' array from another thread */
11208/* while this function is running, as the function temporarily reorders */
11209/* the array while it executes. */
11210/* */
11211/* To pack into another rectangle, you need to call stbrp_init_target */
11212/* again. To continue packing into the same rectangle, you can call */
11213/* this function again. Calling this multiple times with multiple rect */
11214/* arrays will probably produce worse packing results than calling it */
11215/* a single time with the full rectangle array, but the option is */
11216/* available. */
11217/* */
11218/* The function returns 1 if all of the rectangles were successfully */
11219/* packed and 0 otherwise. */
11220
11221struct stbrp_rect
11222{
11223 /* reserved for your use: */
11224 int id;
11225
11226 /* input: */
11227 stbrp_coord w, h;
11228
11229 /* output: */
11230 stbrp_coord x, y;
11231 int was_packed; /* non-zero if valid packing */
11232
11233}; /* 16 bytes, nominally */
11234
11235
11236STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
11237/* Initialize a rectangle packer to: */
11238/* pack a rectangle that is 'width' by 'height' in dimensions */
11239/* using temporary storage provided by the array 'nodes', which is 'num_nodes' long */
11240/* */
11241/* You must call this function every time you start packing into a new target. */
11242/* */
11243/* There is no "shutdown" function. The 'nodes' memory must stay valid for */
11244/* the following stbrp_pack_rects() call (or calls), but can be freed after */
11245/* the call (or calls) finish. */
11246/* */
11247/* Note: to guarantee best results, either: */
11248/* 1. make sure 'num_nodes' >= 'width' */
11249/* or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' */
11250/* */
11251/* If you don't do either of the above things, widths will be quantized to multiples */
11252/* of small integers to guarantee the algorithm doesn't run out of temporary storage. */
11253/* */
11254/* If you do #2, then the non-quantized algorithm will be used, but the algorithm */
11255/* may run out of temporary storage and be unable to pack some rectangles. */
11256
11257STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
11258/* Optionally call this function after init but before doing any packing to */
11259/* change the handling of the out-of-temp-memory scenario, described above. */
11260/* If you call init again, this will be reset to the default (false). */
11261
11262
11263STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
11264/* Optionally select which packing heuristic the library should use. Different */
11265/* heuristics will produce better/worse results for different data sets. */
11266/* If you call init again, this will be reset to the default. */
11267
11268enum
11269{
11270 STBRP_HEURISTIC_Skyline_default=0,
11271 STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
11272 STBRP_HEURISTIC_Skyline_BF_sortHeight
11273};
11274
11275
11276/* //////////////////////////////////////////////////////////////////////////// */
11277/* */
11278/* the details of the following structures don't matter to you, but they must */
11279/* be visible so you can handle the memory allocations for them */
11280
11281struct stbrp_node
11282{
11283 stbrp_coord x,y;
11284 stbrp_node *next;
11285};
11286
11287struct stbrp_context
11288{
11289 int width;
11290 int height;
11291 int align;
11292 int init_mode;
11293 int heuristic;
11294 int num_nodes;
11295 stbrp_node *active_head;
11296 stbrp_node *free_head;
11297 stbrp_node extra[2]; /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */
11298};
11299
11300#ifdef __cplusplus
11301}
11302#endif
11303
11304#endif
11305
11306/* //////////////////////////////////////////////////////////////////////////// */
11307/* */
11308/* IMPLEMENTATION SECTION */
11309/* */
11310
11311#ifdef STB_RECT_PACK_IMPLEMENTATION
11312#ifndef STBRP_SORT
11313#include <stdlib.h>
11314#define STBRP_SORT qsort
11315#endif
11316
11317#ifndef STBRP_ASSERT
11318#include <assert.h>
11319#define STBRP_ASSERT assert
11320#endif
11321
11322#ifdef _MSC_VER
11323#define STBRP__NOTUSED(v) (void)(v)
11324#define STBRP__CDECL __cdecl
11325#else
11326#define STBRP__NOTUSED(v) (void)sizeof(v)
11327#define STBRP__CDECL
11328#endif
11329
11330enum
11331{
11332 STBRP__INIT_skyline = 1
11333};
11334
11335STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
11336{
11337 switch (context->init_mode) {
11338 case STBRP__INIT_skyline:
11339 STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
11340 context->heuristic = heuristic;
11341 break;
11342 default:
11343 STBRP_ASSERT(0);
11344 }
11345}
11346
11347STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
11348{
11349 if (allow_out_of_mem)
11350 /* if it's ok to run out of memory, then don't bother aligning them; */
11351 /* this gives better packing, but may fail due to OOM (even though */
11352 /* the rectangles easily fit). @TODO a smarter approach would be to only */
11353 /* quantize once we've hit OOM, then we could get rid of this parameter. */
11354 context->align = 1;
11355 else {
11356 /* if it's not ok to run out of memory, then quantize the widths */
11357 /* so that num_nodes is always enough nodes. */
11358 /* */
11359 /* I.e. num_nodes * align >= width */
11360 /* align >= width / num_nodes */
11361 /* align = ceil(width/num_nodes) */
11362
11363 context->align = (context->width + context->num_nodes-1) / context->num_nodes;
11364 }
11365}
11366
11367STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
11368{
11369 int i;
11370
11371 for (i=0; i < num_nodes-1; ++i)
11372 nodes[i].next = &nodes[i+1];
11373 nodes[i].next = NULL;
11374 context->init_mode = STBRP__INIT_skyline;
11375 context->heuristic = STBRP_HEURISTIC_Skyline_default;
11376 context->free_head = &nodes[0];
11377 context->active_head = &context->extra[0];
11378 context->width = width;
11379 context->height = height;
11380 context->num_nodes = num_nodes;
11381 stbrp_setup_allow_out_of_mem(context, 0);
11382
11383 /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */
11384 context->extra[0].x = 0;
11385 context->extra[0].y = 0;
11386 context->extra[0].next = &context->extra[1];
11387 context->extra[1].x = (stbrp_coord) width;
11388 context->extra[1].y = (1<<30);
11389 context->extra[1].next = NULL;
11390}
11391
11392/* find minimum y position if it starts at x1 */
11393static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
11394{
11395 stbrp_node *node = first;
11396 int x1 = x0 + width;
11397 int min_y, visited_width, waste_area;
11398
11399 STBRP__NOTUSED(c);
11400
11401 STBRP_ASSERT(first->x <= x0);
11402
11403 #if 0
11404 /* skip in case we're past the node */
11405 while (node->next->x <= x0)
11406 ++node;
11407 #else
11408 STBRP_ASSERT(node->next->x > x0); /* we ended up handling this in the caller for efficiency */
11409 #endif
11410
11411 STBRP_ASSERT(node->x <= x0);
11412
11413 min_y = 0;
11414 waste_area = 0;
11415 visited_width = 0;
11416 while (node->x < x1) {
11417 if (node->y > min_y) {
11418 /* raise min_y higher. */
11419 /* we've accounted for all waste up to min_y, */
11420 /* but we'll now add more waste for everything we've visited */
11421 waste_area += visited_width * (node->y - min_y);
11422 min_y = node->y;
11423 /* the first time through, visited_width might be reduced */
11424 if (node->x < x0)
11425 visited_width += node->next->x - x0;
11426 else
11427 visited_width += node->next->x - node->x;
11428 } else {
11429 /* add waste area */
11430 int under_width = node->next->x - node->x;
11431 if (under_width + visited_width > width)
11432 under_width = width - visited_width;
11433 waste_area += under_width * (min_y - node->y);
11434 visited_width += under_width;
11435 }
11436 node = node->next;
11437 }
11438
11439 *pwaste = waste_area;
11440 return min_y;
11441}
11442
11443typedef struct
11444{
11445 int x,y;
11446 stbrp_node **prev_link;
11447} stbrp__findresult;
11448
11449static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
11450{
11451 int best_waste = (1<<30), best_x, best_y = (1 << 30);
11452 stbrp__findresult fr;
11453 stbrp_node **prev, *node, *tail, **best = NULL;
11454
11455 /* align to multiple of c->align */
11456 width = (width + c->align - 1);
11457 width -= width % c->align;
11458 STBRP_ASSERT(width % c->align == 0);
11459
11460 /* if it can't possibly fit, bail immediately */
11461 if (width > c->width || height > c->height) {
11462 fr.prev_link = NULL;
11463 fr.x = fr.y = 0;
11464 return fr;
11465 }
11466
11467 node = c->active_head;
11468 prev = &c->active_head;
11469 while (node->x + width <= c->width) {
11470 int y,waste;
11471 y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
11472 if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { /* actually just want to test BL */
11473 /* bottom left */
11474 if (y < best_y) {
11475 best_y = y;
11476 best = prev;
11477 }
11478 } else {
11479 /* best-fit */
11480 if (y + height <= c->height) {
11481 /* can only use it if it first vertically */
11482 if (y < best_y || (y == best_y && waste < best_waste)) {
11483 best_y = y;
11484 best_waste = waste;
11485 best = prev;
11486 }
11487 }
11488 }
11489 prev = &node->next;
11490 node = node->next;
11491 }
11492
11493 best_x = (best == NULL) ? 0 : (*best)->x;
11494
11495 /* if doing best-fit (BF), we also have to try aligning right edge to each node position */
11496 /* */
11497 /* e.g, if fitting */
11498 /* */
11499 /* ____________________ */
11500 /* |____________________| */
11501 /* */
11502 /* into */
11503 /* */
11504 /* | | */
11505 /* | ____________| */
11506 /* |____________| */
11507 /* */
11508 /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */
11509 /* */
11510 /* This makes BF take about 2x the time */
11511
11512 if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
11513 tail = c->active_head;
11514 node = c->active_head;
11515 prev = &c->active_head;
11516 /* find first node that's admissible */
11517 while (tail->x < width)
11518 tail = tail->next;
11519 while (tail) {
11520 int xpos = tail->x - width;
11521 int y,waste;
11522 STBRP_ASSERT(xpos >= 0);
11523 /* find the left position that matches this */
11524 while (node->next->x <= xpos) {
11525 prev = &node->next;
11526 node = node->next;
11527 }
11528 STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
11529 y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
11530 if (y + height <= c->height) {
11531 if (y <= best_y) {
11532 if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
11533 best_x = xpos;
11534 STBRP_ASSERT(y <= best_y);
11535 best_y = y;
11536 best_waste = waste;
11537 best = prev;
11538 }
11539 }
11540 }
11541 tail = tail->next;
11542 }
11543 }
11544
11545 fr.prev_link = best;
11546 fr.x = best_x;
11547 fr.y = best_y;
11548 return fr;
11549}
11550
11551static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
11552{
11553 /* find best position according to heuristic */
11554 stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
11555 stbrp_node *node, *cur;
11556
11557 /* bail if: */
11558 /* 1. it failed */
11559 /* 2. the best node doesn't fit (we don't always check this) */
11560 /* 3. we're out of memory */
11561 if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
11562 res.prev_link = NULL;
11563 return res;
11564 }
11565
11566 /* on success, create new node */
11567 node = context->free_head;
11568 node->x = (stbrp_coord) res.x;
11569 node->y = (stbrp_coord) (res.y + height);
11570
11571 context->free_head = node->next;
11572
11573 /* insert the new node into the right starting point, and */
11574 /* let 'cur' point to the remaining nodes needing to be */
11575 /* stitched back in */
11576
11577 cur = *res.prev_link;
11578 if (cur->x < res.x) {
11579 /* preserve the existing one, so start testing with the next one */
11580 stbrp_node *next = cur->next;
11581 cur->next = node;
11582 cur = next;
11583 } else {
11584 *res.prev_link = node;
11585 }
11586
11587 /* from here, traverse cur and free the nodes, until we get to one */
11588 /* that shouldn't be freed */
11589 while (cur->next && cur->next->x <= res.x + width) {
11590 stbrp_node *next = cur->next;
11591 /* move the current node to the free list */
11592 cur->next = context->free_head;
11593 context->free_head = cur;
11594 cur = next;
11595 }
11596
11597 /* stitch the list back in */
11598 node->next = cur;
11599
11600 if (cur->x < res.x + width)
11601 cur->x = (stbrp_coord) (res.x + width);
11602
11603#ifdef _DEBUG
11604 cur = context->active_head;
11605 while (cur->x < context->width) {
11606 STBRP_ASSERT(cur->x < cur->next->x);
11607 cur = cur->next;
11608 }
11609 STBRP_ASSERT(cur->next == NULL);
11610
11611 {
11612 int count=0;
11613 cur = context->active_head;
11614 while (cur) {
11615 cur = cur->next;
11616 ++count;
11617 }
11618 cur = context->free_head;
11619 while (cur) {
11620 cur = cur->next;
11621 ++count;
11622 }
11623 STBRP_ASSERT(count == context->num_nodes+2);
11624 }
11625#endif
11626
11627 return res;
11628}
11629
11630static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
11631{
11632 const stbrp_rect *p = (const stbrp_rect *) a;
11633 const stbrp_rect *q = (const stbrp_rect *) b;
11634 if (p->h > q->h)
11635 return -1;
11636 if (p->h < q->h)
11637 return 1;
11638 return (p->w > q->w) ? -1 : (p->w < q->w);
11639}
11640
11641static int STBRP__CDECL rect_original_order(const void *a, const void *b)
11642{
11643 const stbrp_rect *p = (const stbrp_rect *) a;
11644 const stbrp_rect *q = (const stbrp_rect *) b;
11645 return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
11646}
11647
11648STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
11649{
11650 int i, all_rects_packed = 1;
11651
11652 /* we use the 'was_packed' field internally to allow sorting/unsorting */
11653 for (i=0; i < num_rects; ++i) {
11654 rects[i].was_packed = i;
11655 }
11656
11657 /* sort according to heuristic */
11658 STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
11659
11660 for (i=0; i < num_rects; ++i) {
11661 if (rects[i].w == 0 || rects[i].h == 0) {
11662 rects[i].x = rects[i].y = 0; /* empty rect needs no space */
11663 } else {
11664 stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
11665 if (fr.prev_link) {
11666 rects[i].x = (stbrp_coord) fr.x;
11667 rects[i].y = (stbrp_coord) fr.y;
11668 } else {
11669 rects[i].x = rects[i].y = STBRP__MAXVAL;
11670 }
11671 }
11672 }
11673
11674 /* unsort */
11675 STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
11676
11677 /* set was_packed flags and all_rects_packed status */
11678 for (i=0; i < num_rects; ++i) {
11679 rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
11680 if (!rects[i].was_packed)
11681 all_rects_packed = 0;
11682 }
11683
11684 /* return the all_rects_packed status */
11685 return all_rects_packed;
11686}
11687#endif
11688
11689/*
11690------------------------------------------------------------------------------
11691This software is available under 2 licenses -- choose whichever you prefer.
11692------------------------------------------------------------------------------
11693ALTERNATIVE A - MIT License
11694Copyright (c) 2017 Sean Barrett
11695Permission is hereby granted, free of charge, to any person obtaining a copy of
11696this software and associated documentation files (the "Software"), to deal in
11697the Software without restriction, including without limitation the rights to
11698use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11699of the Software, and to permit persons to whom the Software is furnished to do
11700so, subject to the following conditions:
11701The above copyright notice and this permission notice shall be included in all
11702copies or substantial portions of the Software.
11703THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11704IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11705FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11706AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11707LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11708OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
11709SOFTWARE.
11710------------------------------------------------------------------------------
11711ALTERNATIVE B - Public Domain (www.unlicense.org)
11712This is free and unencumbered software released into the public domain.
11713Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
11714software, either in source code form or as a compiled binary, for any purpose,
11715commercial or non-commercial, and by any means.
11716In jurisdictions that recognize copyright laws, the author or authors of this
11717software dedicate any and all copyright interest in the software to the public
11718domain. We make this dedication for the benefit of the public at large and to
11719the detriment of our heirs and successors. We intend this dedication to be an
11720overt act of relinquishment in perpetuity of all present and future rights to
11721this software under copyright law.
11722THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11723IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11724FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11725AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
11726ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11727WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11728------------------------------------------------------------------------------
11729*/
11730
11731/* stb_truetype.h - v1.26 - public domain */
11732/* authored from 2009-2021 by Sean Barrett / RAD Game Tools */
11733/* */
11734/* ======================================================================= */
11735/* */
11736/* NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES */
11737/* */
11738/* This library does no range checking of the offsets found in the file, */
11739/* meaning an attacker can use it to read arbitrary memory. */
11740/* */
11741/* ======================================================================= */
11742/* */
11743/* This library processes TrueType files: */
11744/* parse files */
11745/* extract glyph metrics */
11746/* extract glyph shapes */
11747/* render glyphs to one-channel bitmaps with antialiasing (box filter) */
11748/* render glyphs to one-channel SDF bitmaps (signed-distance field/function) */
11749/* */
11750/* Todo: */
11751/* non-MS cmaps */
11752/* crashproof on bad data */
11753/* hinting? (no longer patented) */
11754/* cleartype-style AA? */
11755/* optimize: use simple memory allocator for intermediates */
11756/* optimize: build edge-list directly from curves */
11757/* optimize: rasterize directly from curves? */
11758/* */
11759/* ADDITIONAL CONTRIBUTORS */
11760/* */
11761/* Mikko Mononen: compound shape support, more cmap formats */
11762/* Tor Andersson: kerning, subpixel rendering */
11763/* Dougall Johnson: OpenType / Type 2 font handling */
11764/* Daniel Ribeiro Maciel: basic GPOS-based kerning */
11765/* */
11766/* Misc other: */
11767/* Ryan Gordon */
11768/* Simon Glass */
11769/* github:IntellectualKitty */
11770/* Imanol Celaya */
11771/* Daniel Ribeiro Maciel */
11772/* */
11773/* Bug/warning reports/fixes: */
11774/* "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe */
11775/* Cass Everitt Martins Mozeiko github:aloucks */
11776/* stoiko (Haemimont Games) Cap Petschulat github:oyvindjam */
11777/* Brian Hook Omar Cornut github:vassvik */
11778/* Walter van Niftrik Ryan Griege */
11779/* David Gow Peter LaValle */
11780/* David Given Sergey Popov */
11781/* Ivan-Assen Ivanov Giumo X. Clanjor */
11782/* Anthony Pesch Higor Euripedes */
11783/* Johan Duparc Thomas Fields */
11784/* Hou Qiming Derek Vinyard */
11785/* Rob Loach Cort Stratton */
11786/* Kenney Phillis Jr. Brian Costabile */
11787/* Ken Voskuil (kaesve) */
11788/* */
11789/* VERSION HISTORY */
11790/* */
11791/* 1.26 (2021-08-28) fix broken rasterizer */
11792/* 1.25 (2021-07-11) many fixes */
11793/* 1.24 (2020-02-05) fix warning */
11794/* 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) */
11795/* 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined */
11796/* 1.21 (2019-02-25) fix warning */
11797/* 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() */
11798/* 1.19 (2018-02-11) GPOS kerning, STBTT_fmod */
11799/* 1.18 (2018-01-29) add missing function */
11800/* 1.17 (2017-07-23) make more arguments const; doc fix */
11801/* 1.16 (2017-07-12) SDF support */
11802/* 1.15 (2017-03-03) make more arguments const */
11803/* 1.14 (2017-01-16) num-fonts-in-TTC function */
11804/* 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */
11805/* 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */
11806/* 1.11 (2016-04-02) fix unused-variable warning */
11807/* 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef */
11808/* 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly */
11809/* 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */
11810/* 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */
11811/* variant PackFontRanges to pack and render in separate phases; */
11812/* fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */
11813/* fixed an assert() bug in the new rasterizer */
11814/* replace assert() with STBTT_assert() in new rasterizer */
11815/* */
11816/* Full history can be found at the end of this file. */
11817/* */
11818/* LICENSE */
11819/* */
11820/* See end of file for license information. */
11821/* */
11822/* USAGE */
11823/* */
11824/* Include this file in whatever places need to refer to it. In ONE C/C++ */
11825/* file, write: */
11826/* #define STB_TRUETYPE_IMPLEMENTATION */
11827/* before the #include of this file. This expands out the actual */
11828/* implementation into that C/C++ file. */
11829/* */
11830/* To make the implementation private to the file that generates the implementation, */
11831/* #define STBTT_STATIC */
11832/* */
11833/* Simple 3D API (don't ship this, but it's fine for tools and quick start) */
11834/* stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture */
11835/* stbtt_GetBakedQuad() -- compute quad to draw for a given char */
11836/* */
11837/* Improved 3D API (more shippable): */
11838/* #include "stb_rect_pack.h" -- optional, but you really want it */
11839/* stbtt_PackBegin() */
11840/* stbtt_PackSetOversampling() -- for improved quality on small fonts */
11841/* stbtt_PackFontRanges() -- pack and renders */
11842/* stbtt_PackEnd() */
11843/* stbtt_GetPackedQuad() */
11844/* */
11845/* "Load" a font file from a memory buffer (you have to keep the buffer loaded) */
11846/* stbtt_InitFont() */
11847/* stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections */
11848/* stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections */
11849/* */
11850/* Render a unicode codepoint to a bitmap */
11851/* stbtt_GetCodepointBitmap() -- allocates and returns a bitmap */
11852/* stbtt_MakeCodepointBitmap() -- renders into bitmap you provide */
11853/* stbtt_GetCodepointBitmapBox() -- how big the bitmap must be */
11854/* */
11855/* Character advance/positioning */
11856/* stbtt_GetCodepointHMetrics() */
11857/* stbtt_GetFontVMetrics() */
11858/* stbtt_GetFontVMetricsOS2() */
11859/* stbtt_GetCodepointKernAdvance() */
11860/* */
11861/* Starting with version 1.06, the rasterizer was replaced with a new, */
11862/* faster and generally-more-precise rasterizer. The new rasterizer more */
11863/* accurately measures pixel coverage for anti-aliasing, except in the case */
11864/* where multiple shapes overlap, in which case it overestimates the AA pixel */
11865/* coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If */
11866/* this turns out to be a problem, you can re-enable the old rasterizer with */
11867/* #define STBTT_RASTERIZER_VERSION 1 */
11868/* which will incur about a 15% speed hit. */
11869/* */
11870/* ADDITIONAL DOCUMENTATION */
11871/* */
11872/* Immediately after this block comment are a series of sample programs. */
11873/* */
11874/* After the sample programs is the "header file" section. This section */
11875/* includes documentation for each API function. */
11876/* */
11877/* Some important concepts to understand to use this library: */
11878/* */
11879/* Codepoint */
11880/* Characters are defined by unicode codepoints, e.g. 65 is */
11881/* uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is */
11882/* the hiragana for "ma". */
11883/* */
11884/* Glyph */
11885/* A visual character shape (every codepoint is rendered as */
11886/* some glyph) */
11887/* */
11888/* Glyph index */
11889/* A font-specific integer ID representing a glyph */
11890/* */
11891/* Baseline */
11892/* Glyph shapes are defined relative to a baseline, which is the */
11893/* bottom of uppercase characters. Characters extend both above */
11894/* and below the baseline. */
11895/* */
11896/* Current Point */
11897/* As you draw text to the screen, you keep track of a "current point" */
11898/* which is the origin of each character. The current point's vertical */
11899/* position is the baseline. Even "baked fonts" use this model. */
11900/* */
11901/* Vertical Font Metrics */
11902/* The vertical qualities of the font, used to vertically position */
11903/* and space the characters. See docs for stbtt_GetFontVMetrics. */
11904/* */
11905/* Font Size in Pixels or Points */
11906/* The preferred interface for specifying font sizes in stb_truetype */
11907/* is to specify how tall the font's vertical extent should be in pixels. */
11908/* If that sounds good enough, skip the next paragraph. */
11909/* */
11910/* Most font APIs instead use "points", which are a common typographic */
11911/* measurement for describing font size, defined as 72 points per inch. */
11912/* stb_truetype provides a point API for compatibility. However, true */
11913/* "per inch" conventions don't make much sense on computer displays */
11914/* since different monitors have different number of pixels per */
11915/* inch. For example, Windows traditionally uses a convention that */
11916/* there are 96 pixels per inch, thus making 'inch' measurements have */
11917/* nothing to do with inches, and thus effectively defining a point to */
11918/* be 1.333 pixels. Additionally, the TrueType font data provides */
11919/* an explicit scale factor to scale a given font's glyphs to points, */
11920/* but the author has observed that this scale factor is often wrong */
11921/* for non-commercial fonts, thus making fonts scaled in points */
11922/* according to the TrueType spec incoherently sized in practice. */
11923/* */
11924/* DETAILED USAGE: */
11925/* */
11926/* Scale: */
11927/* Select how high you want the font to be, in points or pixels. */
11928/* Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute */
11929/* a scale factor SF that will be used by all other functions. */
11930/* */
11931/* Baseline: */
11932/* You need to select a y-coordinate that is the baseline of where */
11933/* your text will appear. Call GetFontBoundingBox to get the baseline-relative */
11934/* bounding box for all characters. SF*-y0 will be the distance in pixels */
11935/* that the worst-case character could extend above the baseline, so if */
11936/* you want the top edge of characters to appear at the top of the */
11937/* screen where y=0, then you would set the baseline to SF*-y0. */
11938/* */
11939/* Current point: */
11940/* Set the current point where the first character will appear. The */
11941/* first character could extend left of the current point; this is font */
11942/* dependent. You can either choose a current point that is the leftmost */
11943/* point and hope, or add some padding, or check the bounding box or */
11944/* left-side-bearing of the first character to be displayed and set */
11945/* the current point based on that. */
11946/* */
11947/* Displaying a character: */
11948/* Compute the bounding box of the character. It will contain signed values */
11949/* relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1, */
11950/* then the character should be displayed in the rectangle from */
11951/* <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1). */
11952/* */
11953/* Advancing for the next character: */
11954/* Call GlyphHMetrics, and compute 'current_point += SF * advance'. */
11955/* */
11956/* */
11957/* ADVANCED USAGE */
11958/* */
11959/* Quality: */
11960/* */
11961/* - Use the functions with Subpixel at the end to allow your characters */
11962/* to have subpixel positioning. Since the font is anti-aliased, not */
11963/* hinted, this is very import for quality. (This is not possible with */
11964/* baked fonts.) */
11965/* */
11966/* - Kerning is now supported, and if you're supporting subpixel rendering */
11967/* then kerning is worth using to give your text a polished look. */
11968/* */
11969/* Performance: */
11970/* */
11971/* - Convert Unicode codepoints to glyph indexes and operate on the glyphs; */
11972/* if you don't do this, stb_truetype is forced to do the conversion on */
11973/* every call. */
11974/* */
11975/* - There are a lot of memory allocations. We should modify it to take */
11976/* a temp buffer and allocate from the temp buffer (without freeing), */
11977/* should help performance a lot. */
11978/* */
11979/* NOTES */
11980/* */
11981/* The system uses the raw data found in the .ttf file without changing it */
11982/* and without building auxiliary data structures. This is a bit inefficient */
11983/* on little-endian systems (the data is big-endian), but assuming you're */
11984/* caching the bitmaps or glyph shapes this shouldn't be a big deal. */
11985/* */
11986/* It appears to be very hard to programmatically determine what font a */
11987/* given file is in a general way. I provide an API for this, but I don't */
11988/* recommend it. */
11989/* */
11990/* */
11991/* PERFORMANCE MEASUREMENTS FOR 1.06: */
11992/* */
11993/* 32-bit 64-bit */
11994/* Previous release: 8.83 s 7.68 s */
11995/* Pool allocations: 7.72 s 6.34 s */
11996/* Inline sort : 6.54 s 5.65 s */
11997/* New rasterizer : 5.63 s 5.00 s */
11998
11999/* //////////////////////////////////////////////////////////////////////////// */
12000/* //////////////////////////////////////////////////////////////////////////// */
12001/* // */
12002/* // SAMPLE PROGRAMS */
12003/* // */
12004/* */
12005/* Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. */
12006/* See "tests/truetype_demo_win32.c" for a complete version. */
12007#if 0
12008#define STB_TRUETYPE_IMPLEMENTATION /* force following include to generate implementation */
12009#include "stb_truetype.h"
12010
12011unsigned char ttf_buffer[1<<20];
12012unsigned char temp_bitmap[512*512];
12013
12014stbtt_bakedchar cdata[96]; /* ASCII 32..126 is 95 glyphs */
12015GLuint ftex;
12016
12017void my_stbtt_initfont(void)
12018{
12019 fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
12020 stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); /* no guarantee this fits! */
12021 /* can free ttf_buffer at this point */
12022 glGenTextures(1, &ftex);
12023 glBindTexture(GL_TEXTURE_2D, ftex);
12024 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
12025 /* can free temp_bitmap at this point */
12026 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
12027}
12028
12029void my_stbtt_print(float x, float y, char *text)
12030{
12031 /* assume orthographic projection with units = screen pixels, origin at top left */
12032 glEnable(GL_BLEND);
12033 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
12034 glEnable(GL_TEXTURE_2D);
12035 glBindTexture(GL_TEXTURE_2D, ftex);
12036 glBegin(GL_QUADS);
12037 while (*text) {
12038 if (*text >= 32 && *text < 128) {
12039 stbtt_aligned_quad q;
12040 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);/* 1=opengl & d3d10+,0=d3d9 */
12041 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
12042 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
12043 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
12044 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
12045 }
12046 ++text;
12047 }
12048 glEnd();
12049}
12050#endif
12051/* */
12052/* */
12053/* //////////////////////////////////////////////////////////////////////////// */
12054/* */
12055/* Complete program (this compiles): get a single bitmap, print as ASCII art */
12056/* */
12057#if 0
12058#include <stdio.h>
12059#define STB_TRUETYPE_IMPLEMENTATION /* force following include to generate implementation */
12060#include "stb_truetype.h"
12061
12062char ttf_buffer[1<<25];
12063
12064int main(int argc, char **argv)
12065{
12066 stbtt_fontinfo font;
12067 unsigned char *bitmap;
12068 int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
12069
12070 fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
12071
12072 stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
12073 bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
12074
12075 for (j=0; j < h; ++j) {
12076 for (i=0; i < w; ++i)
12077 putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
12078 putchar('\n');
12079 }
12080 return 0;
12081}
12082#endif
12083/* */
12084/* Output: */
12085/* */
12086/* .ii. */
12087/* @@@@@@. */
12088/* V@Mio@@o */
12089/* :i. V@V */
12090/* :oM@@M */
12091/* :@@@MM@M */
12092/* @@o o@M */
12093/* :@@. M@M */
12094/* @@@o@@@@ */
12095/* :M@@V:@@. */
12096/* */
12097/* //////////////////////////////////////////////////////////////////////////// */
12098/* */
12099/* Complete program: print "Hello World!" banner, with bugs */
12100/* */
12101#if 0
12102char buffer[24<<20];
12103unsigned char screen[20][79];
12104
12105int main(int arg, char **argv)
12106{
12107 stbtt_fontinfo font;
12108 int i,j,ascent,baseline,ch=0;
12109 float scale, xpos=2; /* leave a little padding in case the character extends left */
12110 char *text = "Heljo World!"; /* intentionally misspelled to show 'lj' brokenness */
12111
12112 fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
12113 stbtt_InitFont(&font, buffer, 0);
12114
12115 scale = stbtt_ScaleForPixelHeight(&font, 15);
12116 stbtt_GetFontVMetrics(&font, &ascent,0,0);
12117 baseline = (int) (ascent*scale);
12118
12119 while (text[ch]) {
12120 int advance,lsb,x0,y0,x1,y1;
12121 float x_shift = xpos - (float) floor(xpos);
12122 stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
12123 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
12124 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
12125 /* note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong */
12126 /* because this API is really for baking character bitmaps into textures. if you want to render */
12127 /* a sequence of characters, you really need to render each bitmap to a temp buffer, then */
12128 /* "alpha blend" that into the working buffer */
12129 xpos += (advance * scale);
12130 if (text[ch+1])
12131 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
12132 ++ch;
12133 }
12134
12135 for (j=0; j < 20; ++j) {
12136 for (i=0; i < 78; ++i)
12137 putchar(" .:ioVM@"[screen[j][i]>>5]);
12138 putchar('\n');
12139 }
12140
12141 return 0;
12142}
12143#endif
12144
12145
12146/* //////////////////////////////////////////////////////////////////////////// */
12147/* //////////////////////////////////////////////////////////////////////////// */
12148/* // */
12149/* // INTEGRATION WITH YOUR CODEBASE */
12150/* // */
12151/* // The following sections allow you to supply alternate definitions */
12152/* // of C library functions used by stb_truetype, e.g. if you don't */
12153/* // link with the C runtime library. */
12154
12155#ifdef STB_TRUETYPE_IMPLEMENTATION
12156 /* #define your own (u)stbtt_int8/16/32 before including to override this */
12157 #ifndef stbtt_uint8
12158 typedef unsigned char stbtt_uint8;
12159 typedef signed char stbtt_int8;
12160 typedef unsigned short stbtt_uint16;
12161 typedef signed short stbtt_int16;
12162 typedef unsigned int stbtt_uint32;
12163 typedef signed int stbtt_int32;
12164 #endif
12165
12166 typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
12167 typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
12168
12169 /* e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h */
12170 #ifndef STBTT_ifloor
12171 #include <math.h>
12172 #define STBTT_ifloor(x) ((int) floor(x))
12173 #define STBTT_iceil(x) ((int) ceil(x))
12174 #endif
12175
12176 #ifndef STBTT_sqrt
12177 #include <math.h>
12178 #define STBTT_sqrt(x) sqrt(x)
12179 #define STBTT_pow(x,y) pow(x,y)
12180 #endif
12181
12182 #ifndef STBTT_fmod
12183 #include <math.h>
12184 #define STBTT_fmod(x,y) fmod(x,y)
12185 #endif
12186
12187 #ifndef STBTT_cos
12188 #include <math.h>
12189 #define STBTT_cos(x) cos(x)
12190 #define STBTT_acos(x) acos(x)
12191 #endif
12192
12193 #ifndef STBTT_fabs
12194 #include <math.h>
12195 #define STBTT_fabs(x) fabs(x)
12196 #endif
12197
12198 /* #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h */
12199 #ifndef STBTT_malloc
12200 #include <stdlib.h>
12201 #define STBTT_malloc(x,u) ((void)(u),malloc(x))
12202 #define STBTT_free(x,u) ((void)(u),free(x))
12203 #endif
12204
12205 #ifndef STBTT_assert
12206 #include <assert.h>
12207 #define STBTT_assert(x) assert(x)
12208 #endif
12209
12210 #ifndef STBTT_strlen
12211 #include <string.h>
12212 #define STBTT_strlen(x) strlen(x)
12213 #endif
12214
12215 #ifndef STBTT_memcpy
12216 #include <string.h>
12217 #define STBTT_memcpy memcpy
12218 #define STBTT_memset memset
12219 #endif
12220#endif
12221
12222/* ///////////////////////////////////////////////////////////////////////////// */
12223/* ///////////////////////////////////////////////////////////////////////////// */
12224/* // */
12225/* // INTERFACE */
12226/* // */
12227/* // */
12228
12229#ifndef __STB_INCLUDE_STB_TRUETYPE_H__
12230#define __STB_INCLUDE_STB_TRUETYPE_H__
12231
12232#ifdef STBTT_STATIC
12233#define STBTT_DEF static
12234#else
12235#define STBTT_DEF extern
12236#endif
12237
12238#ifdef __cplusplus
12239extern "C" {
12240#endif
12241
12242/* private structure */
12243typedef struct
12244{
12245 unsigned char *data;
12246 int cursor;
12247 int size;
12248} stbtt__buf;
12249
12250/* //////////////////////////////////////////////////////////////////////////// */
12251/* */
12252/* TEXTURE BAKING API */
12253/* */
12254/* If you use this API, you only have to call two functions ever. */
12255/* */
12256
12257typedef struct
12258{
12259 unsigned short x0,y0,x1,y1; /* coordinates of bbox in bitmap */
12260 float xoff,yoff,xadvance;
12261} stbtt_bakedchar;
12262
12263STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, /* font location (use offset=0 for plain .ttf) */
12264 float pixel_height, /* height of font in pixels */
12265 unsigned char *pixels, int pw, int ph, /* bitmap to be filled in */
12266 int first_char, int num_chars, /* characters to bake */
12267 stbtt_bakedchar *chardata); /* you allocate this, it's num_chars long */
12268/* if return is positive, the first unused row of the bitmap */
12269/* if return is negative, returns the negative of the number of characters that fit */
12270/* if return is 0, no characters fit and no rows were used */
12271/* This uses a very crappy packing. */
12272
12273typedef struct
12274{
12275 float x0,y0,s0,t0; /* top-left */
12276 float x1,y1,s1,t1; /* bottom-right */
12277} stbtt_aligned_quad;
12278
12279STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, /* same data as above */
12280 int char_index, /* character to display */
12281 float *xpos, float *ypos, /* pointers to current position in screen pixel space */
12282 stbtt_aligned_quad *q, /* output: quad to draw */
12283 int opengl_fillrule); /* true if opengl fill rule; false if DX9 or earlier */
12284/* Call GetBakedQuad with char_index = 'character - first_char', and it */
12285/* creates the quad you need to draw and advances the current position. */
12286/* */
12287/* The coordinate system used assumes y increases downwards. */
12288/* */
12289/* Characters will extend both above and below the current position; */
12290/* see discussion of "BASELINE" above. */
12291/* */
12292/* It's inefficient; you might want to c&p it and optimize it. */
12293
12294STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
12295/* Query the font vertical metrics without having to create a font first. */
12296
12297
12298/* //////////////////////////////////////////////////////////////////////////// */
12299/* */
12300/* NEW TEXTURE BAKING API */
12301/* */
12302/* This provides options for packing multiple fonts into one atlas, not */
12303/* perfectly but better than nothing. */
12304
12305typedef struct
12306{
12307 unsigned short x0,y0,x1,y1; /* coordinates of bbox in bitmap */
12308 float xoff,yoff,xadvance;
12309 float xoff2,yoff2;
12310} stbtt_packedchar;
12311
12312typedef struct stbtt_pack_context stbtt_pack_context;
12313typedef struct stbtt_fontinfo stbtt_fontinfo;
12314#ifndef STB_RECT_PACK_VERSION
12315typedef struct stbrp_rect stbrp_rect;
12316#endif
12317
12318STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
12319/* Initializes a packing context stored in the passed-in stbtt_pack_context. */
12320/* Future calls using this context will pack characters into the bitmap passed */
12321/* in here: a 1-channel bitmap that is width * height. stride_in_bytes is */
12322/* the distance from one row to the next (or 0 to mean they are packed tightly */
12323/* together). "padding" is the amount of padding to leave between each */
12324/* character (normally you want '1' for bitmaps you'll use as textures with */
12325/* bilinear filtering). */
12326/* */
12327/* Returns 0 on failure, 1 on success. */
12328
12329STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
12330/* Cleans up the packing context and frees all memory. */
12331
12332#define STBTT_POINT_SIZE(x) (-(x))
12333
12334STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
12335 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
12336/* Creates character bitmaps from the font_index'th font found in fontdata (use */
12337/* font_index=0 if you don't know what that is). It creates num_chars_in_range */
12338/* bitmaps for characters with unicode values starting at first_unicode_char_in_range */
12339/* and increasing. Data for how to render them is stored in chardata_for_range; */
12340/* pass these to stbtt_GetPackedQuad to get back renderable quads. */
12341/* */
12342/* font_size is the full height of the character from ascender to descender, */
12343/* as computed by stbtt_ScaleForPixelHeight. To use a point size as computed */
12344/* by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() */
12345/* and pass that result as 'font_size': */
12346/* ..., 20 , ... // font max minus min y is 20 pixels tall */
12347/* ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall */
12348
12349typedef struct
12350{
12351 float font_size;
12352 int first_unicode_codepoint_in_range; /* if non-zero, then the chars are continuous, and this is the first codepoint */
12353 int *array_of_unicode_codepoints; /* if non-zero, then this is an array of unicode codepoints */
12354 int num_chars;
12355 stbtt_packedchar *chardata_for_range; /* output */
12356 unsigned char h_oversample, v_oversample; /* don't set these, they're used internally */
12357} stbtt_pack_range;
12358
12359STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
12360/* Creates character bitmaps from multiple ranges of characters stored in */
12361/* ranges. This will usually create a better-packed bitmap than multiple */
12362/* calls to stbtt_PackFontRange. Note that you can call this multiple */
12363/* times within a single PackBegin/PackEnd. */
12364
12365STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
12366/* Oversampling a font increases the quality by allowing higher-quality subpixel */
12367/* positioning, and is especially valuable at smaller text sizes. */
12368/* */
12369/* This function sets the amount of oversampling for all following calls to */
12370/* stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given */
12371/* pack context. The default (no oversampling) is achieved by h_oversample=1 */
12372/* and v_oversample=1. The total number of pixels required is */
12373/* h_oversample*v_oversample larger than the default; for example, 2x2 */
12374/* oversampling requires 4x the storage of 1x1. For best results, render */
12375/* oversampled textures with bilinear filtering. Look at the readme in */
12376/* stb/tests/oversample for information about oversampled fonts */
12377/* */
12378/* To use with PackFontRangesGather etc., you must set it before calls */
12379/* call to PackFontRangesGatherRects. */
12380
12381STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
12382/* If skip != 0, this tells stb_truetype to skip any codepoints for which */
12383/* there is no corresponding glyph. If skip=0, which is the default, then */
12384/* codepoints without a glyph recived the font's "missing character" glyph, */
12385/* typically an empty box by convention. */
12386
12387STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, /* same data as above */
12388 int char_index, /* character to display */
12389 float *xpos, float *ypos, /* pointers to current position in screen pixel space */
12390 stbtt_aligned_quad *q, /* output: quad to draw */
12391 int align_to_integer);
12392
12393STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
12394STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
12395STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
12396/* Calling these functions in sequence is roughly equivalent to calling */
12397/* stbtt_PackFontRanges(). If you more control over the packing of multiple */
12398/* fonts, or if you want to pack custom data into a font texture, take a look */
12399/* at the source to of stbtt_PackFontRanges() and create a custom version */
12400/* using these functions, e.g. call GatherRects multiple times, */
12401/* building up a single array of rects, then call PackRects once, */
12402/* then call RenderIntoRects repeatedly. This may result in a */
12403/* better packing than calling PackFontRanges multiple times */
12404/* (or it may not). */
12405
12406/* this is an opaque structure that you shouldn't mess with which holds */
12407/* all the context needed from PackBegin to PackEnd. */
12408struct stbtt_pack_context {
12409 void *user_allocator_context;
12410 void *pack_info;
12411 int width;
12412 int height;
12413 int stride_in_bytes;
12414 int padding;
12415 int skip_missing;
12416 unsigned int h_oversample, v_oversample;
12417 unsigned char *pixels;
12418 void *nodes;
12419};
12420
12421/* //////////////////////////////////////////////////////////////////////////// */
12422/* */
12423/* FONT LOADING */
12424/* */
12425/* */
12426
12427STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
12428/* This function will determine the number of fonts in a font file. TrueType */
12429/* collection (.ttc) files may contain multiple fonts, while TrueType font */
12430/* (.ttf) files only contain one font. The number of fonts can be used for */
12431/* indexing with the previous function where the index is between zero and one */
12432/* less than the total fonts. If an error occurs, -1 is returned. */
12433
12434STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
12435/* Each .ttf/.ttc file may have more than one font. Each font has a sequential */
12436/* index number starting from 0. Call this function to get the font offset for */
12437/* a given index; it returns -1 if the index is out of range. A regular .ttf */
12438/* file will only define one font and it always be at offset 0, so it will */
12439/* return '0' for index 0, and -1 for all other indices. */
12440
12441/* The following structure is defined publicly so you can declare one on */
12442/* the stack or as a global or etc, but you should treat it as opaque. */
12443struct stbtt_fontinfo
12444{
12445 void * userdata;
12446 unsigned char * data; /* pointer to .ttf file */
12447 int fontstart; /* offset of start of font */
12448
12449 int numGlyphs; /* number of glyphs, needed for range checking */
12450
12451 int loca,head,glyf,hhea,hmtx,kern,gpos,svg; /* table locations as offset from start of .ttf */
12452 int index_map; /* a cmap mapping for our chosen character encoding */
12453 int indexToLocFormat; /* format needed to map from glyph index to glyph */
12454
12455 stbtt__buf cff; /* cff font data */
12456 stbtt__buf charstrings; /* the charstring index */
12457 stbtt__buf gsubrs; /* global charstring subroutines index */
12458 stbtt__buf subrs; /* private charstring subroutines index */
12459 stbtt__buf fontdicts; /* array of font dicts */
12460 stbtt__buf fdselect; /* map from glyph to fontdict */
12461};
12462
12463STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
12464/* Given an offset into the file that defines a font, this function builds */
12465/* the necessary cached info for the rest of the system. You must allocate */
12466/* the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't */
12467/* need to do anything special to free it, because the contents are pure */
12468/* value data with no additional data structures. Returns 0 on failure. */
12469
12470
12471/* //////////////////////////////////////////////////////////////////////////// */
12472/* */
12473/* CHARACTER TO GLYPH-INDEX CONVERSIOn */
12474
12475STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
12476/* If you're going to perform multiple operations on the same character */
12477/* and you want a speed-up, call this function with the character you're */
12478/* going to process, then use glyph-based functions instead of the */
12479/* codepoint-based functions. */
12480/* Returns 0 if the character codepoint is not defined in the font. */
12481
12482
12483/* //////////////////////////////////////////////////////////////////////////// */
12484/* */
12485/* CHARACTER PROPERTIES */
12486/* */
12487
12488STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
12489/* computes a scale factor to produce a font whose "height" is 'pixels' tall. */
12490/* Height is measured as the distance from the highest ascender to the lowest */
12491/* descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics */
12492/* and computing: */
12493/* scale = pixels / (ascent - descent) */
12494/* so if you prefer to measure height by the ascent only, use a similar calculation. */
12495
12496STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
12497/* computes a scale factor to produce a font whose EM size is mapped to */
12498/* 'pixels' tall. This is probably what traditional APIs compute, but */
12499/* I'm not positive. */
12500
12501STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
12502/* ascent is the coordinate above the baseline the font extends; descent */
12503/* is the coordinate below the baseline the font extends (i.e. it is typically negative) */
12504/* lineGap is the spacing between one row's descent and the next row's ascent... */
12505/* so you should advance the vertical position by "*ascent - *descent + *lineGap" */
12506/* these are expressed in unscaled coordinates, so you must multiply by */
12507/* the scale factor for a given size */
12508
12509STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
12510/* analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 */
12511/* table (specific to MS/Windows TTF files). */
12512/* */
12513/* Returns 1 on success (table present), 0 on failure. */
12514
12515STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
12516/* the bounding box around all possible characters */
12517
12518STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
12519/* leftSideBearing is the offset from the current horizontal position to the left edge of the character */
12520/* advanceWidth is the offset from the current horizontal position to the next horizontal position */
12521/* these are expressed in unscaled coordinates */
12522
12523STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
12524/* an additional amount to add to the 'advance' value between ch1 and ch2 */
12525
12526STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
12527/* Gets the bounding box of the visible part of the glyph, in unscaled coordinates */
12528
12529STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
12530STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
12531STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
12532/* as above, but takes one or more glyph indices for greater efficiency */
12533
12534typedef struct stbtt_kerningentry
12535{
12536 int glyph1; /* use stbtt_FindGlyphIndex */
12537 int glyph2;
12538 int advance;
12539} stbtt_kerningentry;
12540
12541STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
12542STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
12543/* Retrieves a complete list of all of the kerning pairs provided by the font */
12544/* stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. */
12545/* The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) */
12546
12547/* //////////////////////////////////////////////////////////////////////////// */
12548/* */
12549/* GLYPH SHAPES (you probably don't need these, but they have to go before */
12550/* the bitmaps for C declaration-order reasons) */
12551/* */
12552
12553#ifndef STBTT_vmove /* you can predefine these to use different values (but why?) */
12554 enum {
12555 STBTT_vmove=1,
12556 STBTT_vline,
12557 STBTT_vcurve,
12558 STBTT_vcubic
12559 };
12560#endif
12561
12562#ifndef stbtt_vertex /* you can predefine this to use different values */
12563 /* (we share this with other code at RAD) */
12564 #define stbtt_vertex_type short /* can't use stbtt_int16 because that's not visible in the header file */
12565 typedef struct
12566 {
12567 stbtt_vertex_type x,y,cx,cy,cx1,cy1;
12568 unsigned char type,padding;
12569 } stbtt_vertex;
12570#endif
12571
12572STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
12573/* returns non-zero if nothing is drawn for this glyph */
12574
12575STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
12576STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
12577/* returns # of vertices and fills *vertices with the pointer to them */
12578/* these are expressed in "unscaled" coordinates */
12579/* */
12580/* The shape is a series of contours. Each one starts with */
12581/* a STBTT_moveto, then consists of a series of mixed */
12582/* STBTT_lineto and STBTT_curveto segments. A lineto */
12583/* draws a line from previous endpoint to its x,y; a curveto */
12584/* draws a quadratic bezier from previous endpoint to */
12585/* its x,y, using cx,cy as the bezier control point. */
12586
12587STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
12588/* frees the data allocated above */
12589
12590STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
12591STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
12592STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
12593/* fills svg with the character's SVG data. */
12594/* returns data size or 0 if SVG not found. */
12595
12596/* //////////////////////////////////////////////////////////////////////////// */
12597/* */
12598/* BITMAP RENDERING */
12599/* */
12600
12601STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
12602/* frees the bitmap allocated below */
12603
12604STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
12605/* allocates a large-enough single-channel 8bpp bitmap and renders the */
12606/* specified character/glyph at the specified scale into it, with */
12607/* antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). */
12608/* *width & *height are filled out with the width & height of the bitmap, */
12609/* which is stored left-to-right, top-to-bottom. */
12610/* */
12611/* xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap */
12612
12613STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
12614/* the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel */
12615/* shift for the character */
12616
12617STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
12618/* the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap */
12619/* in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap */
12620/* is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the */
12621/* width and height and positioning info for it first. */
12622
12623STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
12624/* same as stbtt_MakeCodepointBitmap, but you can specify a subpixel */
12625/* shift for the character */
12626
12627STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
12628/* same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering */
12629/* is performed (see stbtt_PackSetOversampling) */
12630
12631STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
12632/* get the bbox of the bitmap centered around the glyph origin; so the */
12633/* bitmap width is ix1-ix0, height is iy1-iy0, and location to place */
12634/* the bitmap top left is (leftSideBearing*scale,iy0). */
12635/* (Note that the bitmap uses y-increases-down, but the shape uses */
12636/* y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) */
12637
12638STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
12639/* same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel */
12640/* shift for the character */
12641
12642/* the following functions are equivalent to the above functions, but operate */
12643/* on glyph indices instead of Unicode codepoints (for efficiency) */
12644STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
12645STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
12646STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
12647STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
12648STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
12649STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
12650STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
12651
12652
12653/* @TODO: don't expose this structure */
12654typedef struct
12655{
12656 int w,h,stride;
12657 unsigned char *pixels;
12658} stbtt__bitmap;
12659
12660/* rasterize a shape with quadratic beziers into a bitmap */
12661STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, /* 1-channel bitmap to draw into */
12662 float flatness_in_pixels, /* allowable error of curve in pixels */
12663 stbtt_vertex *vertices, /* array of vertices defining shape */
12664 int num_verts, /* number of vertices in above array */
12665 float scale_x, float scale_y, /* scale applied to input vertices */
12666 float shift_x, float shift_y, /* translation applied to input vertices */
12667 int x_off, int y_off, /* another translation applied to input */
12668 int invert, /* if non-zero, vertically flip shape */
12669 void *userdata); /* context for to STBTT_MALLOC */
12670
12671/* //////////////////////////////////////////////////////////////////////////// */
12672/* */
12673/* Signed Distance Function (or Field) rendering */
12674
12675STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
12676/* frees the SDF bitmap allocated below */
12677
12678STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
12679STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
12680/* These functions compute a discretized SDF field for a single character, suitable for storing */
12681/* in a single-channel texture, sampling with bilinear filtering, and testing against */
12682/* larger than some threshold to produce scalable fonts. */
12683/* info -- the font */
12684/* scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap */
12685/* glyph/codepoint -- the character to generate the SDF for */
12686/* padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), */
12687/* which allows effects like bit outlines */
12688/* onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) */
12689/* pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) */
12690/* if positive, > onedge_value is inside; if negative, < onedge_value is inside */
12691/* width,height -- output height & width of the SDF bitmap (including padding) */
12692/* xoff,yoff -- output origin of the character */
12693/* return value -- a 2D array of bytes 0..255, width*height in size */
12694/* */
12695/* pixel_dist_scale & onedge_value are a scale & bias that allows you to make */
12696/* optimal use of the limited 0..255 for your application, trading off precision */
12697/* and special effects. SDF values outside the range 0..255 are clamped to 0..255. */
12698/* */
12699/* Example: */
12700/* scale = stbtt_ScaleForPixelHeight(22) */
12701/* padding = 5 */
12702/* onedge_value = 180 */
12703/* pixel_dist_scale = 180/5.0 = 36.0 */
12704/* */
12705/* This will create an SDF bitmap in which the character is about 22 pixels */
12706/* high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled */
12707/* shape, sample the SDF at each pixel and fill the pixel if the SDF value */
12708/* is greater than or equal to 180/255. (You'll actually want to antialias, */
12709/* which is beyond the scope of this example.) Additionally, you can compute */
12710/* offset outlines (e.g. to stroke the character border inside & outside, */
12711/* or only outside). For example, to fill outside the character up to 3 SDF */
12712/* pixels, you would compare against (180-36.0*3)/255 = 72/255. The above */
12713/* choice of variables maps a range from 5 pixels outside the shape to */
12714/* 2 pixels inside the shape to 0..255; this is intended primarily for apply */
12715/* outside effects only (the interior range is needed to allow proper */
12716/* antialiasing of the font at *smaller* sizes) */
12717/* */
12718/* The function computes the SDF analytically at each SDF pixel, not by e.g. */
12719/* building a higher-res bitmap and approximating it. In theory the quality */
12720/* should be as high as possible for an SDF of this size & representation, but */
12721/* unclear if this is true in practice (perhaps building a higher-res bitmap */
12722/* and computing from that can allow drop-out prevention). */
12723/* */
12724/* The algorithm has not been optimized at all, so expect it to be slow */
12725/* if computing lots of characters or very large sizes. */
12726
12727
12728
12729/* //////////////////////////////////////////////////////////////////////////// */
12730/* */
12731/* Finding the right font... */
12732/* */
12733/* You should really just solve this offline, keep your own tables */
12734/* of what font is what, and don't try to get it out of the .ttf file. */
12735/* That's because getting it out of the .ttf file is really hard, because */
12736/* the names in the file can appear in many possible encodings, in many */
12737/* possible languages, and e.g. if you need a case-insensitive comparison, */
12738/* the details of that depend on the encoding & language in a complex way */
12739/* (actually underspecified in truetype, but also gigantic). */
12740/* */
12741/* But you can use the provided functions in two possible ways: */
12742/* stbtt_FindMatchingFont() will use *case-sensitive* comparisons on */
12743/* unicode-encoded names to try to find the font you want; */
12744/* you can run this before calling stbtt_InitFont() */
12745/* */
12746/* stbtt_GetFontNameString() lets you get any of the various strings */
12747/* from the file yourself and do your own comparisons on them. */
12748/* You have to have called stbtt_InitFont() first. */
12749
12750
12751STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
12752/* returns the offset (not index) of the font that matches, or -1 if none */
12753/* if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". */
12754/* if you use any other flag, use a font name like "Arial"; this checks */
12755/* the 'macStyle' header field; i don't know if fonts set this consistently */
12756#define STBTT_MACSTYLE_DONTCARE 0
12757#define STBTT_MACSTYLE_BOLD 1
12758#define STBTT_MACSTYLE_ITALIC 2
12759#define STBTT_MACSTYLE_UNDERSCORE 4
12760#define STBTT_MACSTYLE_NONE 8 /* <= not same as 0, this makes us check the bitfield is 0 */
12761
12762STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
12763/* returns 1/0 whether the first string interpreted as utf8 is identical to */
12764/* the second string interpreted as big-endian utf16... useful for strings from next func */
12765
12766STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
12767/* returns the string (which may be big-endian double byte, e.g. for unicode) */
12768/* and puts the length in bytes in *length. */
12769/* */
12770/* some of the values for the IDs are below; for more see the truetype spec: */
12771/* http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html */
12772/* http://www.microsoft.com/typography/otspec/name.htm */
12773
12774enum { /* platformID */
12775 STBTT_PLATFORM_ID_UNICODE =0,
12776 STBTT_PLATFORM_ID_MAC =1,
12777 STBTT_PLATFORM_ID_ISO =2,
12778 STBTT_PLATFORM_ID_MICROSOFT =3
12779};
12780
12781enum { /* encodingID for STBTT_PLATFORM_ID_UNICODE */
12782 STBTT_UNICODE_EID_UNICODE_1_0 =0,
12783 STBTT_UNICODE_EID_UNICODE_1_1 =1,
12784 STBTT_UNICODE_EID_ISO_10646 =2,
12785 STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
12786 STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
12787};
12788
12789enum { /* encodingID for STBTT_PLATFORM_ID_MICROSOFT */
12790 STBTT_MS_EID_SYMBOL =0,
12791 STBTT_MS_EID_UNICODE_BMP =1,
12792 STBTT_MS_EID_SHIFTJIS =2,
12793 STBTT_MS_EID_UNICODE_FULL =10
12794};
12795
12796enum { /* encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes */
12797 STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4,
12798 STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5,
12799 STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6,
12800 STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7
12801};
12802
12803enum { /* languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... */
12804 /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */
12805 STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410,
12806 STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411,
12807 STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412,
12808 STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,
12809 STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409,
12810 STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D
12811};
12812
12813enum { /* languageID for STBTT_PLATFORM_ID_MAC */
12814 STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11,
12815 STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23,
12816 STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32,
12817 STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 ,
12818 STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 ,
12819 STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
12820 STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19
12821};
12822
12823#ifdef __cplusplus
12824}
12825#endif
12826
12827#endif /* __STB_INCLUDE_STB_TRUETYPE_H__ */
12828
12829/* ///////////////////////////////////////////////////////////////////////////// */
12830/* ///////////////////////////////////////////////////////////////////////////// */
12831/* // */
12832/* // IMPLEMENTATION */
12833/* // */
12834/* // */
12835
12836#ifdef STB_TRUETYPE_IMPLEMENTATION
12837
12838#ifndef STBTT_MAX_OVERSAMPLE
12839#define STBTT_MAX_OVERSAMPLE 8
12840#endif
12841
12842#if STBTT_MAX_OVERSAMPLE > 255
12843#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
12844#endif
12845
12846typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
12847
12848#ifndef STBTT_RASTERIZER_VERSION
12849#define STBTT_RASTERIZER_VERSION 2
12850#endif
12851
12852#ifdef _MSC_VER
12853#define STBTT__NOTUSED(v) (void)(v)
12854#else
12855#define STBTT__NOTUSED(v) (void)sizeof(v)
12856#endif
12857
12858/* //////////////////////////////////////////////////////////////////////// */
12859/* */
12860/* stbtt__buf helpers to parse data from file */
12861/* */
12862
12863static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
12864{
12865 if (b->cursor >= b->size)
12866 return 0;
12867 return b->data[b->cursor++];
12868}
12869
12870static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
12871{
12872 if (b->cursor >= b->size)
12873 return 0;
12874 return b->data[b->cursor];
12875}
12876
12877static void stbtt__buf_seek(stbtt__buf *b, int o)
12878{
12879 STBTT_assert(!(o > b->size || o < 0));
12880 b->cursor = (o > b->size || o < 0) ? b->size : o;
12881}
12882
12883static void stbtt__buf_skip(stbtt__buf *b, int o)
12884{
12885 stbtt__buf_seek(b, b->cursor + o);
12886}
12887
12888static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
12889{
12890 stbtt_uint32 v = 0;
12891 int i;
12892 STBTT_assert(n >= 1 && n <= 4);
12893 for (i = 0; i < n; i++)
12894 v = (v << 8) | stbtt__buf_get8(b);
12895 return v;
12896}
12897
12898static stbtt__buf stbtt__new_buf(const void *p, size_t size)
12899{
12900 stbtt__buf r;
12901 STBTT_assert(size < 0x40000000);
12902 r.data = (stbtt_uint8*) p;
12903 r.size = (int) size;
12904 r.cursor = 0;
12905 return r;
12906}
12907
12908#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
12909#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
12910
12911static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
12912{
12913 stbtt__buf r = stbtt__new_buf(NULL, 0);
12914 if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
12915 r.data = b->data + o;
12916 r.size = s;
12917 return r;
12918}
12919
12920static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
12921{
12922 int count, start, offsize;
12923 start = b->cursor;
12924 count = stbtt__buf_get16(b);
12925 if (count) {
12926 offsize = stbtt__buf_get8(b);
12927 STBTT_assert(offsize >= 1 && offsize <= 4);
12928 stbtt__buf_skip(b, offsize * count);
12929 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
12930 }
12931 return stbtt__buf_range(b, start, b->cursor - start);
12932}
12933
12934static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
12935{
12936 int b0 = stbtt__buf_get8(b);
12937 if (b0 >= 32 && b0 <= 246) return b0 - 139;
12938 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
12939 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
12940 else if (b0 == 28) return stbtt__buf_get16(b);
12941 else if (b0 == 29) return stbtt__buf_get32(b);
12942 STBTT_assert(0);
12943 return 0;
12944}
12945
12946static void stbtt__cff_skip_operand(stbtt__buf *b) {
12947 int v, b0 = stbtt__buf_peek8(b);
12948 STBTT_assert(b0 >= 28);
12949 if (b0 == 30) {
12950 stbtt__buf_skip(b, 1);
12951 while (b->cursor < b->size) {
12952 v = stbtt__buf_get8(b);
12953 if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
12954 break;
12955 }
12956 } else {
12957 stbtt__cff_int(b);
12958 }
12959}
12960
12961static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
12962{
12963 stbtt__buf_seek(b, 0);
12964 while (b->cursor < b->size) {
12965 int start = b->cursor, end, op;
12966 while (stbtt__buf_peek8(b) >= 28)
12967 stbtt__cff_skip_operand(b);
12968 end = b->cursor;
12969 op = stbtt__buf_get8(b);
12970 if (op == 12) op = stbtt__buf_get8(b) | 0x100;
12971 if (op == key) return stbtt__buf_range(b, start, end-start);
12972 }
12973 return stbtt__buf_range(b, 0, 0);
12974}
12975
12976static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
12977{
12978 int i;
12979 stbtt__buf operands = stbtt__dict_get(b, key);
12980 for (i = 0; i < outcount && operands.cursor < operands.size; i++)
12981 out[i] = stbtt__cff_int(&operands);
12982}
12983
12984static int stbtt__cff_index_count(stbtt__buf *b)
12985{
12986 stbtt__buf_seek(b, 0);
12987 return stbtt__buf_get16(b);
12988}
12989
12990static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
12991{
12992 int count, offsize, start, end;
12993 stbtt__buf_seek(&b, 0);
12994 count = stbtt__buf_get16(&b);
12995 offsize = stbtt__buf_get8(&b);
12996 STBTT_assert(i >= 0 && i < count);
12997 STBTT_assert(offsize >= 1 && offsize <= 4);
12998 stbtt__buf_skip(&b, i*offsize);
12999 start = stbtt__buf_get(&b, offsize);
13000 end = stbtt__buf_get(&b, offsize);
13001 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
13002}
13003
13004/* //////////////////////////////////////////////////////////////////////// */
13005/* */
13006/* accessors to parse data from file */
13007/* */
13008
13009/* on platforms that don't allow misaligned reads, if we want to allow */
13010/* truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE */
13011
13012#define ttBYTE(p) (* (stbtt_uint8 *) (p))
13013#define ttCHAR(p) (* (stbtt_int8 *) (p))
13014#define ttFixed(p) ttLONG(p)
13015
13016static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
13017static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
13018static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
13019static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
13020
13021#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
13022#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
13023
13024static int stbtt__isfont(stbtt_uint8 *font)
13025{
13026 /* check the version number */
13027 if (stbtt_tag4(font, '1',0,0,0)) return 1; /* TrueType 1 */
13028 if (stbtt_tag(font, "typ1")) return 1; /* TrueType with type 1 font -- we don't support this! */
13029 if (stbtt_tag(font, "OTTO")) return 1; /* OpenType with CFF */
13030 if (stbtt_tag4(font, 0,1,0,0)) return 1; /* OpenType 1.0 */
13031 if (stbtt_tag(font, "true")) return 1; /* Apple specification for TrueType fonts */
13032 return 0;
13033}
13034
13035/* @OPTIMIZE: binary search */
13036static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
13037{
13038 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
13039 stbtt_uint32 tabledir = fontstart + 12;
13040 stbtt_int32 i;
13041 for (i=0; i < num_tables; ++i) {
13042 stbtt_uint32 loc = tabledir + 16*i;
13043 if (stbtt_tag(data+loc+0, tag))
13044 return ttULONG(data+loc+8);
13045 }
13046 return 0;
13047}
13048
13049static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
13050{
13051 /* if it's just a font, there's only one valid index */
13052 if (stbtt__isfont(font_collection))
13053 return index == 0 ? 0 : -1;
13054
13055 /* check if it's a TTC */
13056 if (stbtt_tag(font_collection, "ttcf")) {
13057 /* version 1? */
13058 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
13059 stbtt_int32 n = ttLONG(font_collection+8);
13060 if (index >= n)
13061 return -1;
13062 return ttULONG(font_collection+12+index*4);
13063 }
13064 }
13065 return -1;
13066}
13067
13068static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
13069{
13070 /* if it's just a font, there's only one valid font */
13071 if (stbtt__isfont(font_collection))
13072 return 1;
13073
13074 /* check if it's a TTC */
13075 if (stbtt_tag(font_collection, "ttcf")) {
13076 /* version 1? */
13077 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
13078 return ttLONG(font_collection+8);
13079 }
13080 }
13081 return 0;
13082}
13083
13084static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
13085{
13086 stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
13087 stbtt__buf pdict;
13088 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
13089 if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
13090 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
13091 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
13092 if (!subrsoff) return stbtt__new_buf(NULL, 0);
13093 stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
13094 return stbtt__cff_get_index(&cff);
13095}
13096
13097/* since most people won't use this, find this table the first time it's needed */
13098static int stbtt__get_svg(stbtt_fontinfo *info)
13099{
13100 stbtt_uint32 t;
13101 if (info->svg < 0) {
13102 t = stbtt__find_table(info->data, info->fontstart, "SVG ");
13103 if (t) {
13104 stbtt_uint32 offset = ttULONG(info->data + t + 2);
13105 info->svg = t + offset;
13106 } else {
13107 info->svg = 0;
13108 }
13109 }
13110 return info->svg;
13111}
13112
13113static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
13114{
13115 stbtt_uint32 cmap, t;
13116 stbtt_int32 i,numTables;
13117
13118 info->data = data;
13119 info->fontstart = fontstart;
13120 info->cff = stbtt__new_buf(NULL, 0);
13121
13122 cmap = stbtt__find_table(data, fontstart, "cmap"); /* required */
13123 info->loca = stbtt__find_table(data, fontstart, "loca"); /* required */
13124 info->head = stbtt__find_table(data, fontstart, "head"); /* required */
13125 info->glyf = stbtt__find_table(data, fontstart, "glyf"); /* required */
13126 info->hhea = stbtt__find_table(data, fontstart, "hhea"); /* required */
13127 info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); /* required */
13128 info->kern = stbtt__find_table(data, fontstart, "kern"); /* not required */
13129 info->gpos = stbtt__find_table(data, fontstart, "GPOS"); /* not required */
13130
13131 if (!cmap || !info->head || !info->hhea || !info->hmtx)
13132 return 0;
13133 if (info->glyf) {
13134 /* required for truetype */
13135 if (!info->loca) return 0;
13136 } else {
13137 /* initialization for CFF / Type2 fonts (OTF) */
13138 stbtt__buf b, topdict, topdictidx;
13139 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
13140 stbtt_uint32 cff;
13141
13142 cff = stbtt__find_table(data, fontstart, "CFF ");
13143 if (!cff) return 0;
13144
13145 info->fontdicts = stbtt__new_buf(NULL, 0);
13146 info->fdselect = stbtt__new_buf(NULL, 0);
13147
13148 /* @TODO this should use size from table (not 512MB) */
13149 info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
13150 b = info->cff;
13151
13152 /* read the header */
13153 stbtt__buf_skip(&b, 2);
13154 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); /* hdrsize */
13155
13156 /* @TODO the name INDEX could list multiple fonts, */
13157 /* but we just use the first one. */
13158 stbtt__cff_get_index(&b); /* name INDEX */
13159 topdictidx = stbtt__cff_get_index(&b);
13160 topdict = stbtt__cff_index_get(topdictidx, 0);
13161 stbtt__cff_get_index(&b); /* string INDEX */
13162 info->gsubrs = stbtt__cff_get_index(&b);
13163
13164 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
13165 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
13166 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
13167 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
13168 info->subrs = stbtt__get_subrs(b, topdict);
13169
13170 /* we only support Type 2 charstrings */
13171 if (cstype != 2) return 0;
13172 if (charstrings == 0) return 0;
13173
13174 if (fdarrayoff) {
13175 /* looks like a CID font */
13176 if (!fdselectoff) return 0;
13177 stbtt__buf_seek(&b, fdarrayoff);
13178 info->fontdicts = stbtt__cff_get_index(&b);
13179 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
13180 }
13181
13182 stbtt__buf_seek(&b, charstrings);
13183 info->charstrings = stbtt__cff_get_index(&b);
13184 }
13185
13186 t = stbtt__find_table(data, fontstart, "maxp");
13187 if (t)
13188 info->numGlyphs = ttUSHORT(data+t+4);
13189 else
13190 info->numGlyphs = 0xffff;
13191
13192 info->svg = -1;
13193
13194 /* find a cmap encoding table we understand *now* to avoid searching */
13195 /* later. (todo: could make this installable) */
13196 /* the same regardless of glyph. */
13197 numTables = ttUSHORT(data + cmap + 2);
13198 info->index_map = 0;
13199 for (i=0; i < numTables; ++i) {
13200 stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
13201 /* find an encoding we understand: */
13202 switch(ttUSHORT(data+encoding_record)) {
13203 case STBTT_PLATFORM_ID_MICROSOFT:
13204 switch (ttUSHORT(data+encoding_record+2)) {
13205 case STBTT_MS_EID_UNICODE_BMP:
13206 case STBTT_MS_EID_UNICODE_FULL:
13207 /* MS/Unicode */
13208 info->index_map = cmap + ttULONG(data+encoding_record+4);
13209 break;
13210 }
13211 break;
13212 case STBTT_PLATFORM_ID_UNICODE:
13213 /* Mac/iOS has these */
13214 /* all the encodingIDs are unicode, so we don't bother to check it */
13215 info->index_map = cmap + ttULONG(data+encoding_record+4);
13216 break;
13217 }
13218 }
13219 if (info->index_map == 0)
13220 return 0;
13221
13222 info->indexToLocFormat = ttUSHORT(data+info->head + 50);
13223 return 1;
13224}
13225
13226STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
13227{
13228 stbtt_uint8 *data = info->data;
13229 stbtt_uint32 index_map = info->index_map;
13230
13231 stbtt_uint16 format = ttUSHORT(data + index_map + 0);
13232 if (format == 0) { /* apple byte encoding */
13233 stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
13234 if (unicode_codepoint < bytes-6)
13235 return ttBYTE(data + index_map + 6 + unicode_codepoint);
13236 return 0;
13237 } else if (format == 6) {
13238 stbtt_uint32 first = ttUSHORT(data + index_map + 6);
13239 stbtt_uint32 count = ttUSHORT(data + index_map + 8);
13240 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
13241 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
13242 return 0;
13243 } else if (format == 2) {
13244 STBTT_assert(0); /* @TODO: high-byte mapping for japanese/chinese/korean */
13245 return 0;
13246 } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */
13247 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
13248 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
13249 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
13250 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
13251
13252 /* do a binary search of the segments */
13253 stbtt_uint32 endCount = index_map + 14;
13254 stbtt_uint32 search = endCount;
13255
13256 if (unicode_codepoint > 0xffff)
13257 return 0;
13258
13259 /* they lie from endCount .. endCount + segCount */
13260 /* but searchRange is the nearest power of two, so... */
13261 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
13262 search += rangeShift*2;
13263
13264 /* now decrement to bias correctly to find smallest */
13265 search -= 2;
13266 while (entrySelector) {
13267 stbtt_uint16 end;
13268 searchRange >>= 1;
13269 end = ttUSHORT(data + search + searchRange*2);
13270 if (unicode_codepoint > end)
13271 search += searchRange*2;
13272 --entrySelector;
13273 }
13274 search += 2;
13275
13276 {
13277 stbtt_uint16 offset, start, last;
13278 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
13279
13280 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
13281 last = ttUSHORT(data + endCount + 2*item);
13282 if (unicode_codepoint < start || unicode_codepoint > last)
13283 return 0;
13284
13285 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
13286 if (offset == 0)
13287 return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
13288
13289 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
13290 }
13291 } else if (format == 12 || format == 13) {
13292 stbtt_uint32 ngroups = ttULONG(data+index_map+12);
13293 stbtt_int32 low,high;
13294 low = 0; high = (stbtt_int32)ngroups;
13295 /* Binary search the right group. */
13296 while (low < high) {
13297 stbtt_int32 mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */
13298 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
13299 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
13300 if ((stbtt_uint32) unicode_codepoint < start_char)
13301 high = mid;
13302 else if ((stbtt_uint32) unicode_codepoint > end_char)
13303 low = mid+1;
13304 else {
13305 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
13306 if (format == 12)
13307 return start_glyph + unicode_codepoint-start_char;
13308 else /* format == 13 */
13309 return start_glyph;
13310 }
13311 }
13312 return 0; /* not found */
13313 }
13314 /* @TODO */
13315 STBTT_assert(0);
13316 return 0;
13317}
13318
13319STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
13320{
13321 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
13322}
13323
13324static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
13325{
13326 v->type = type;
13327 v->x = (stbtt_int16) x;
13328 v->y = (stbtt_int16) y;
13329 v->cx = (stbtt_int16) cx;
13330 v->cy = (stbtt_int16) cy;
13331}
13332
13333static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
13334{
13335 int g1,g2;
13336
13337 STBTT_assert(!info->cff.size);
13338
13339 if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */
13340 if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */
13341
13342 if (info->indexToLocFormat == 0) {
13343 g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
13344 g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
13345 } else {
13346 g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
13347 g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
13348 }
13349
13350 return g1==g2 ? -1 : g1; /* if length is 0, return -1 */
13351}
13352
13353static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
13354
13355STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
13356{
13357 if (info->cff.size) {
13358 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
13359 } else {
13360 int g = stbtt__GetGlyfOffset(info, glyph_index);
13361 if (g < 0) return 0;
13362
13363 if (x0) *x0 = ttSHORT(info->data + g + 2);
13364 if (y0) *y0 = ttSHORT(info->data + g + 4);
13365 if (x1) *x1 = ttSHORT(info->data + g + 6);
13366 if (y1) *y1 = ttSHORT(info->data + g + 8);
13367 }
13368 return 1;
13369}
13370
13371STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
13372{
13373 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
13374}
13375
13376STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
13377{
13378 stbtt_int16 numberOfContours;
13379 int g;
13380 if (info->cff.size)
13381 return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
13382 g = stbtt__GetGlyfOffset(info, glyph_index);
13383 if (g < 0) return 1;
13384 numberOfContours = ttSHORT(info->data + g);
13385 return numberOfContours == 0;
13386}
13387
13388static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
13389 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
13390{
13391 if (start_off) {
13392 if (was_off)
13393 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
13394 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
13395 } else {
13396 if (was_off)
13397 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
13398 else
13399 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
13400 }
13401 return num_vertices;
13402}
13403
13404static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
13405{
13406 stbtt_int16 numberOfContours;
13407 stbtt_uint8 *endPtsOfContours;
13408 stbtt_uint8 *data = info->data;
13409 stbtt_vertex *vertices=0;
13410 int num_vertices=0;
13411 int g = stbtt__GetGlyfOffset(info, glyph_index);
13412
13413 *pvertices = NULL;
13414
13415 if (g < 0) return 0;
13416
13417 numberOfContours = ttSHORT(data + g);
13418
13419 if (numberOfContours > 0) {
13420 stbtt_uint8 flags=0,flagcount;
13421 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
13422 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
13423 stbtt_uint8 *points;
13424 endPtsOfContours = (data + g + 10);
13425 ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
13426 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
13427
13428 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
13429
13430 m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */
13431 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
13432 if (vertices == 0)
13433 return 0;
13434
13435 next_move = 0;
13436 flagcount=0;
13437
13438 /* in first pass, we load uninterpreted data into the allocated array */
13439 /* above, shifted to the end of the array so we won't overwrite it when */
13440 /* we create our final data starting from the front */
13441
13442 off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */
13443
13444 /* first load flags */
13445
13446 for (i=0; i < n; ++i) {
13447 if (flagcount == 0) {
13448 flags = *points++;
13449 if (flags & 8)
13450 flagcount = *points++;
13451 } else
13452 --flagcount;
13453 vertices[off+i].type = flags;
13454 }
13455
13456 /* now load x coordinates */
13457 x=0;
13458 for (i=0; i < n; ++i) {
13459 flags = vertices[off+i].type;
13460 if (flags & 2) {
13461 stbtt_int16 dx = *points++;
13462 x += (flags & 16) ? dx : -dx; /* ??? */
13463 } else {
13464 if (!(flags & 16)) {
13465 x = x + (stbtt_int16) (points[0]*256 + points[1]);
13466 points += 2;
13467 }
13468 }
13469 vertices[off+i].x = (stbtt_int16) x;
13470 }
13471
13472 /* now load y coordinates */
13473 y=0;
13474 for (i=0; i < n; ++i) {
13475 flags = vertices[off+i].type;
13476 if (flags & 4) {
13477 stbtt_int16 dy = *points++;
13478 y += (flags & 32) ? dy : -dy; /* ??? */
13479 } else {
13480 if (!(flags & 32)) {
13481 y = y + (stbtt_int16) (points[0]*256 + points[1]);
13482 points += 2;
13483 }
13484 }
13485 vertices[off+i].y = (stbtt_int16) y;
13486 }
13487
13488 /* now convert them to our format */
13489 num_vertices=0;
13490 sx = sy = cx = cy = scx = scy = 0;
13491 for (i=0; i < n; ++i) {
13492 flags = vertices[off+i].type;
13493 x = (stbtt_int16) vertices[off+i].x;
13494 y = (stbtt_int16) vertices[off+i].y;
13495
13496 if (next_move == i) {
13497 if (i != 0)
13498 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
13499
13500 /* now start the new one */
13501 start_off = !(flags & 1);
13502 if (start_off) {
13503 /* if we start off with an off-curve point, then when we need to find a point on the curve */
13504 /* where we can start, and we need to save some state for when we wraparound. */
13505 scx = x;
13506 scy = y;
13507 if (!(vertices[off+i+1].type & 1)) {
13508 /* next point is also a curve point, so interpolate an on-point curve */
13509 sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
13510 sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
13511 } else {
13512 /* otherwise just use the next point as our start point */
13513 sx = (stbtt_int32) vertices[off+i+1].x;
13514 sy = (stbtt_int32) vertices[off+i+1].y;
13515 ++i; /* we're using point i+1 as the starting point, so skip it */
13516 }
13517 } else {
13518 sx = x;
13519 sy = y;
13520 }
13521 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
13522 was_off = 0;
13523 next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
13524 ++j;
13525 } else {
13526 if (!(flags & 1)) { /* if it's a curve */
13527 if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */
13528 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
13529 cx = x;
13530 cy = y;
13531 was_off = 1;
13532 } else {
13533 if (was_off)
13534 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
13535 else
13536 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
13537 was_off = 0;
13538 }
13539 }
13540 }
13541 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
13542 } else if (numberOfContours < 0) {
13543 /* Compound shapes. */
13544 int more = 1;
13545 stbtt_uint8 *comp = data + g + 10;
13546 num_vertices = 0;
13547 vertices = 0;
13548 while (more) {
13549 stbtt_uint16 flags, gidx;
13550 int comp_num_verts = 0, i;
13551 stbtt_vertex *comp_verts = 0, *tmp = 0;
13552 float mtx[6] = {1,0,0,1,0,0}, m, n;
13553
13554 flags = ttSHORT(comp); comp+=2;
13555 gidx = ttSHORT(comp); comp+=2;
13556
13557 if (flags & 2) { /* XY values */
13558 if (flags & 1) { /* shorts */
13559 mtx[4] = ttSHORT(comp); comp+=2;
13560 mtx[5] = ttSHORT(comp); comp+=2;
13561 } else {
13562 mtx[4] = ttCHAR(comp); comp+=1;
13563 mtx[5] = ttCHAR(comp); comp+=1;
13564 }
13565 }
13566 else {
13567 /* @TODO handle matching point */
13568 STBTT_assert(0);
13569 }
13570 if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */
13571 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
13572 mtx[1] = mtx[2] = 0;
13573 } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */
13574 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
13575 mtx[1] = mtx[2] = 0;
13576 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
13577 } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */
13578 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
13579 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
13580 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
13581 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
13582 }
13583
13584 /* Find transformation scales. */
13585 m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
13586 n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
13587
13588 /* Get indexed glyph. */
13589 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
13590 if (comp_num_verts > 0) {
13591 /* Transform vertices. */
13592 for (i = 0; i < comp_num_verts; ++i) {
13593 stbtt_vertex* v = &comp_verts[i];
13594 stbtt_vertex_type x,y;
13595 x=v->x; y=v->y;
13596 v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
13597 v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
13598 x=v->cx; y=v->cy;
13599 v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
13600 v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
13601 }
13602 /* Append vertices. */
13603 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
13604 if (!tmp) {
13605 if (vertices) STBTT_free(vertices, info->userdata);
13606 if (comp_verts) STBTT_free(comp_verts, info->userdata);
13607 return 0;
13608 }
13609 if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
13610 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
13611 if (vertices) STBTT_free(vertices, info->userdata);
13612 vertices = tmp;
13613 STBTT_free(comp_verts, info->userdata);
13614 num_vertices += comp_num_verts;
13615 }
13616 /* More components ? */
13617 more = flags & (1<<5);
13618 }
13619 } else {
13620 /* numberOfCounters == 0, do nothing */
13621 }
13622
13623 *pvertices = vertices;
13624 return num_vertices;
13625}
13626
13627typedef struct
13628{
13629 int bounds;
13630 int started;
13631 float first_x, first_y;
13632 float x, y;
13633 stbtt_int32 min_x, max_x, min_y, max_y;
13634
13635 stbtt_vertex *pvertices;
13636 int num_vertices;
13637} stbtt__csctx;
13638
13639#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
13640
13641static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
13642{
13643 if (x > c->max_x || !c->started) c->max_x = x;
13644 if (y > c->max_y || !c->started) c->max_y = y;
13645 if (x < c->min_x || !c->started) c->min_x = x;
13646 if (y < c->min_y || !c->started) c->min_y = y;
13647 c->started = 1;
13648}
13649
13650static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
13651{
13652 if (c->bounds) {
13653 stbtt__track_vertex(c, x, y);
13654 if (type == STBTT_vcubic) {
13655 stbtt__track_vertex(c, cx, cy);
13656 stbtt__track_vertex(c, cx1, cy1);
13657 }
13658 } else {
13659 stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
13660 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
13661 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
13662 }
13663 c->num_vertices++;
13664}
13665
13666static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
13667{
13668 if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
13669 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
13670}
13671
13672static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
13673{
13674 stbtt__csctx_close_shape(ctx);
13675 ctx->first_x = ctx->x = ctx->x + dx;
13676 ctx->first_y = ctx->y = ctx->y + dy;
13677 stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
13678}
13679
13680static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
13681{
13682 ctx->x += dx;
13683 ctx->y += dy;
13684 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
13685}
13686
13687static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
13688{
13689 float cx1 = ctx->x + dx1;
13690 float cy1 = ctx->y + dy1;
13691 float cx2 = cx1 + dx2;
13692 float cy2 = cy1 + dy2;
13693 ctx->x = cx2 + dx3;
13694 ctx->y = cy2 + dy3;
13695 stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
13696}
13697
13698static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
13699{
13700 int count = stbtt__cff_index_count(&idx);
13701 int bias = 107;
13702 if (count >= 33900)
13703 bias = 32768;
13704 else if (count >= 1240)
13705 bias = 1131;
13706 n += bias;
13707 if (n < 0 || n >= count)
13708 return stbtt__new_buf(NULL, 0);
13709 return stbtt__cff_index_get(idx, n);
13710}
13711
13712static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
13713{
13714 stbtt__buf fdselect = info->fdselect;
13715 int nranges, start, end, v, fmt, fdselector = -1, i;
13716
13717 stbtt__buf_seek(&fdselect, 0);
13718 fmt = stbtt__buf_get8(&fdselect);
13719 if (fmt == 0) {
13720 /* untested */
13721 stbtt__buf_skip(&fdselect, glyph_index);
13722 fdselector = stbtt__buf_get8(&fdselect);
13723 } else if (fmt == 3) {
13724 nranges = stbtt__buf_get16(&fdselect);
13725 start = stbtt__buf_get16(&fdselect);
13726 for (i = 0; i < nranges; i++) {
13727 v = stbtt__buf_get8(&fdselect);
13728 end = stbtt__buf_get16(&fdselect);
13729 if (glyph_index >= start && glyph_index < end) {
13730 fdselector = v;
13731 break;
13732 }
13733 start = end;
13734 }
13735 }
13736 if (fdselector == -1) stbtt__new_buf(NULL, 0);
13737 return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
13738}
13739
13740static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
13741{
13742 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
13743 int has_subrs = 0, clear_stack;
13744 float s[48];
13745 stbtt__buf subr_stack[10], subrs = info->subrs, b;
13746 float f;
13747
13748#define STBTT__CSERR(s) (0)
13749
13750 /* this currently ignores the initial width value, which isn't needed if we have hmtx */
13751 b = stbtt__cff_index_get(info->charstrings, glyph_index);
13752 while (b.cursor < b.size) {
13753 i = 0;
13754 clear_stack = 1;
13755 b0 = stbtt__buf_get8(&b);
13756 switch (b0) {
13757 /* @TODO implement hinting */
13758 case 0x13: /* hintmask */
13759 case 0x14: /* cntrmask */
13760 if (in_header)
13761 maskbits += (sp / 2); /* implicit "vstem" */
13762 in_header = 0;
13763 stbtt__buf_skip(&b, (maskbits + 7) / 8);
13764 break;
13765
13766 case 0x01: /* hstem */
13767 case 0x03: /* vstem */
13768 case 0x12: /* hstemhm */
13769 case 0x17: /* vstemhm */
13770 maskbits += (sp / 2);
13771 break;
13772
13773 case 0x15: /* rmoveto */
13774 in_header = 0;
13775 if (sp < 2) return STBTT__CSERR("rmoveto stack");
13776 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
13777 break;
13778 case 0x04: /* vmoveto */
13779 in_header = 0;
13780 if (sp < 1) return STBTT__CSERR("vmoveto stack");
13781 stbtt__csctx_rmove_to(c, 0, s[sp-1]);
13782 break;
13783 case 0x16: /* hmoveto */
13784 in_header = 0;
13785 if (sp < 1) return STBTT__CSERR("hmoveto stack");
13786 stbtt__csctx_rmove_to(c, s[sp-1], 0);
13787 break;
13788
13789 case 0x05: /* rlineto */
13790 if (sp < 2) return STBTT__CSERR("rlineto stack");
13791 for (; i + 1 < sp; i += 2)
13792 stbtt__csctx_rline_to(c, s[i], s[i+1]);
13793 break;
13794
13795 /* hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical */
13796 /* starting from a different place. */
13797
13798 case 0x07: /* vlineto */
13799 if (sp < 1) return STBTT__CSERR("vlineto stack");
13800 goto vlineto;
13801 case 0x06: /* hlineto */
13802 if (sp < 1) return STBTT__CSERR("hlineto stack");
13803 for (;;) {
13804 if (i >= sp) break;
13805 stbtt__csctx_rline_to(c, s[i], 0);
13806 i++;
13807 vlineto:
13808 if (i >= sp) break;
13809 stbtt__csctx_rline_to(c, 0, s[i]);
13810 i++;
13811 }
13812 break;
13813
13814 case 0x1F: /* hvcurveto */
13815 if (sp < 4) return STBTT__CSERR("hvcurveto stack");
13816 goto hvcurveto;
13817 case 0x1E: /* vhcurveto */
13818 if (sp < 4) return STBTT__CSERR("vhcurveto stack");
13819 for (;;) {
13820 if (i + 3 >= sp) break;
13821 stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
13822 i += 4;
13823 hvcurveto:
13824 if (i + 3 >= sp) break;
13825 stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
13826 i += 4;
13827 }
13828 break;
13829
13830 case 0x08: /* rrcurveto */
13831 if (sp < 6) return STBTT__CSERR("rcurveline stack");
13832 for (; i + 5 < sp; i += 6)
13833 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
13834 break;
13835
13836 case 0x18: /* rcurveline */
13837 if (sp < 8) return STBTT__CSERR("rcurveline stack");
13838 for (; i + 5 < sp - 2; i += 6)
13839 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
13840 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
13841 stbtt__csctx_rline_to(c, s[i], s[i+1]);
13842 break;
13843
13844 case 0x19: /* rlinecurve */
13845 if (sp < 8) return STBTT__CSERR("rlinecurve stack");
13846 for (; i + 1 < sp - 6; i += 2)
13847 stbtt__csctx_rline_to(c, s[i], s[i+1]);
13848 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
13849 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
13850 break;
13851
13852 case 0x1A: /* vvcurveto */
13853 case 0x1B: /* hhcurveto */
13854 if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
13855 f = 0.0;
13856 if (sp & 1) { f = s[i]; i++; }
13857 for (; i + 3 < sp; i += 4) {
13858 if (b0 == 0x1B)
13859 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
13860 else
13861 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
13862 f = 0.0;
13863 }
13864 break;
13865
13866 case 0x0A: /* callsubr */
13867 if (!has_subrs) {
13868 if (info->fdselect.size)
13869 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
13870 has_subrs = 1;
13871 }
13872 /* FALLTHROUGH */
13873 case 0x1D: /* callgsubr */
13874 if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
13875 v = (int) s[--sp];
13876 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
13877 subr_stack[subr_stack_height++] = b;
13878 b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
13879 if (b.size == 0) return STBTT__CSERR("subr not found");
13880 b.cursor = 0;
13881 clear_stack = 0;
13882 break;
13883
13884 case 0x0B: /* return */
13885 if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
13886 b = subr_stack[--subr_stack_height];
13887 clear_stack = 0;
13888 break;
13889
13890 case 0x0E: /* endchar */
13891 stbtt__csctx_close_shape(c);
13892 return 1;
13893
13894 case 0x0C: { /* two-byte escape */
13895 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
13896 float dx, dy;
13897 int b1 = stbtt__buf_get8(&b);
13898 switch (b1) {
13899 /* @TODO These "flex" implementations ignore the flex-depth and resolution, */
13900 /* and always draw beziers. */
13901 case 0x22: /* hflex */
13902 if (sp < 7) return STBTT__CSERR("hflex stack");
13903 dx1 = s[0];
13904 dx2 = s[1];
13905 dy2 = s[2];
13906 dx3 = s[3];
13907 dx4 = s[4];
13908 dx5 = s[5];
13909 dx6 = s[6];
13910 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
13911 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
13912 break;
13913
13914 case 0x23: /* flex */
13915 if (sp < 13) return STBTT__CSERR("flex stack");
13916 dx1 = s[0];
13917 dy1 = s[1];
13918 dx2 = s[2];
13919 dy2 = s[3];
13920 dx3 = s[4];
13921 dy3 = s[5];
13922 dx4 = s[6];
13923 dy4 = s[7];
13924 dx5 = s[8];
13925 dy5 = s[9];
13926 dx6 = s[10];
13927 dy6 = s[11];
13928 /* fd is s[12] */
13929 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
13930 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
13931 break;
13932
13933 case 0x24: /* hflex1 */
13934 if (sp < 9) return STBTT__CSERR("hflex1 stack");
13935 dx1 = s[0];
13936 dy1 = s[1];
13937 dx2 = s[2];
13938 dy2 = s[3];
13939 dx3 = s[4];
13940 dx4 = s[5];
13941 dx5 = s[6];
13942 dy5 = s[7];
13943 dx6 = s[8];
13944 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
13945 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
13946 break;
13947
13948 case 0x25: /* flex1 */
13949 if (sp < 11) return STBTT__CSERR("flex1 stack");
13950 dx1 = s[0];
13951 dy1 = s[1];
13952 dx2 = s[2];
13953 dy2 = s[3];
13954 dx3 = s[4];
13955 dy3 = s[5];
13956 dx4 = s[6];
13957 dy4 = s[7];
13958 dx5 = s[8];
13959 dy5 = s[9];
13960 dx6 = dy6 = s[10];
13961 dx = dx1+dx2+dx3+dx4+dx5;
13962 dy = dy1+dy2+dy3+dy4+dy5;
13963 if (STBTT_fabs(dx) > STBTT_fabs(dy))
13964 dy6 = -dy;
13965 else
13966 dx6 = -dx;
13967 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
13968 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
13969 break;
13970
13971 default:
13972 return STBTT__CSERR("unimplemented");
13973 }
13974 } break;
13975
13976 default:
13977 if (b0 != 255 && b0 != 28 && b0 < 32)
13978 return STBTT__CSERR("reserved operator");
13979
13980 /* push immediate */
13981 if (b0 == 255) {
13982 f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
13983 } else {
13984 stbtt__buf_skip(&b, -1);
13985 f = (float)(stbtt_int16)stbtt__cff_int(&b);
13986 }
13987 if (sp >= 48) return STBTT__CSERR("push stack overflow");
13988 s[sp++] = f;
13989 clear_stack = 0;
13990 break;
13991 }
13992 if (clear_stack) sp = 0;
13993 }
13994 return STBTT__CSERR("no endchar");
13995
13996#undef STBTT__CSERR
13997}
13998
13999static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
14000{
14001 /* runs the charstring twice, once to count and once to output (to avoid realloc) */
14002 stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
14003 stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
14004 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
14005 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
14006 output_ctx.pvertices = *pvertices;
14007 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
14008 STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
14009 return output_ctx.num_vertices;
14010 }
14011 }
14012 *pvertices = NULL;
14013 return 0;
14014}
14015
14016static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
14017{
14018 stbtt__csctx c = STBTT__CSCTX_INIT(1);
14019 int r = stbtt__run_charstring(info, glyph_index, &c);
14020 if (x0) *x0 = r ? c.min_x : 0;
14021 if (y0) *y0 = r ? c.min_y : 0;
14022 if (x1) *x1 = r ? c.max_x : 0;
14023 if (y1) *y1 = r ? c.max_y : 0;
14024 return r ? c.num_vertices : 0;
14025}
14026
14027STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
14028{
14029 if (!info->cff.size)
14030 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
14031 else
14032 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
14033}
14034
14035STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
14036{
14037 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
14038 if (glyph_index < numOfLongHorMetrics) {
14039 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index);
14040 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
14041 } else {
14042 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
14043 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
14044 }
14045}
14046
14047STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
14048{
14049 stbtt_uint8 *data = info->data + info->kern;
14050
14051 /* we only look at the first table. it must be 'horizontal' and format 0. */
14052 if (!info->kern)
14053 return 0;
14054 if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */
14055 return 0;
14056 if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */
14057 return 0;
14058
14059 return ttUSHORT(data+10);
14060}
14061
14062STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
14063{
14064 stbtt_uint8 *data = info->data + info->kern;
14065 int k, length;
14066
14067 /* we only look at the first table. it must be 'horizontal' and format 0. */
14068 if (!info->kern)
14069 return 0;
14070 if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */
14071 return 0;
14072 if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */
14073 return 0;
14074
14075 length = ttUSHORT(data+10);
14076 if (table_length < length)
14077 length = table_length;
14078
14079 for (k = 0; k < length; k++)
14080 {
14081 table[k].glyph1 = ttUSHORT(data+18+(k*6));
14082 table[k].glyph2 = ttUSHORT(data+20+(k*6));
14083 table[k].advance = ttSHORT(data+22+(k*6));
14084 }
14085
14086 return length;
14087}
14088
14089static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
14090{
14091 stbtt_uint8 *data = info->data + info->kern;
14092 stbtt_uint32 needle, straw;
14093 int l, r, m;
14094
14095 /* we only look at the first table. it must be 'horizontal' and format 0. */
14096 if (!info->kern)
14097 return 0;
14098 if (ttUSHORT(data+2) < 1) /* number of tables, need at least 1 */
14099 return 0;
14100 if (ttUSHORT(data+8) != 1) /* horizontal flag must be set in format */
14101 return 0;
14102
14103 l = 0;
14104 r = ttUSHORT(data+10) - 1;
14105 needle = glyph1 << 16 | glyph2;
14106 while (l <= r) {
14107 m = (l + r) >> 1;
14108 straw = ttULONG(data+18+(m*6)); /* note: unaligned read */
14109 if (needle < straw)
14110 r = m - 1;
14111 else if (needle > straw)
14112 l = m + 1;
14113 else
14114 return ttSHORT(data+22+(m*6));
14115 }
14116 return 0;
14117}
14118
14119static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
14120{
14121 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
14122 switch (coverageFormat) {
14123 case 1: {
14124 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
14125
14126 /* Binary search. */
14127 stbtt_int32 l=0, r=glyphCount-1, m;
14128 int straw, needle=glyph;
14129 while (l <= r) {
14130 stbtt_uint8 *glyphArray = coverageTable + 4;
14131 stbtt_uint16 glyphID;
14132 m = (l + r) >> 1;
14133 glyphID = ttUSHORT(glyphArray + 2 * m);
14134 straw = glyphID;
14135 if (needle < straw)
14136 r = m - 1;
14137 else if (needle > straw)
14138 l = m + 1;
14139 else {
14140 return m;
14141 }
14142 }
14143 break;
14144 }
14145
14146 case 2: {
14147 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
14148 stbtt_uint8 *rangeArray = coverageTable + 4;
14149
14150 /* Binary search. */
14151 stbtt_int32 l=0, r=rangeCount-1, m;
14152 int strawStart, strawEnd, needle=glyph;
14153 while (l <= r) {
14154 stbtt_uint8 *rangeRecord;
14155 m = (l + r) >> 1;
14156 rangeRecord = rangeArray + 6 * m;
14157 strawStart = ttUSHORT(rangeRecord);
14158 strawEnd = ttUSHORT(rangeRecord + 2);
14159 if (needle < strawStart)
14160 r = m - 1;
14161 else if (needle > strawEnd)
14162 l = m + 1;
14163 else {
14164 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
14165 return startCoverageIndex + glyph - strawStart;
14166 }
14167 }
14168 break;
14169 }
14170
14171 default: return -1; /* unsupported */
14172 }
14173
14174 return -1;
14175}
14176
14177static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
14178{
14179 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
14180 switch (classDefFormat)
14181 {
14182 case 1: {
14183 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
14184 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
14185 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
14186
14187 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
14188 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
14189 break;
14190 }
14191
14192 case 2: {
14193 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
14194 stbtt_uint8 *classRangeRecords = classDefTable + 4;
14195
14196 /* Binary search. */
14197 stbtt_int32 l=0, r=classRangeCount-1, m;
14198 int strawStart, strawEnd, needle=glyph;
14199 while (l <= r) {
14200 stbtt_uint8 *classRangeRecord;
14201 m = (l + r) >> 1;
14202 classRangeRecord = classRangeRecords + 6 * m;
14203 strawStart = ttUSHORT(classRangeRecord);
14204 strawEnd = ttUSHORT(classRangeRecord + 2);
14205 if (needle < strawStart)
14206 r = m - 1;
14207 else if (needle > strawEnd)
14208 l = m + 1;
14209 else
14210 return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
14211 }
14212 break;
14213 }
14214
14215 default:
14216 return -1; /* Unsupported definition type, return an error. */
14217 }
14218
14219 /* "All glyphs not assigned to a class fall into class 0". (OpenType spec) */
14220 return 0;
14221}
14222
14223/* Define to STBTT_assert(x) if you want to break on unimplemented formats. */
14224#define STBTT_GPOS_TODO_assert(x)
14225
14226static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
14227{
14228 stbtt_uint16 lookupListOffset;
14229 stbtt_uint8 *lookupList;
14230 stbtt_uint16 lookupCount;
14231 stbtt_uint8 *data;
14232 stbtt_int32 i, sti;
14233
14234 if (!info->gpos) return 0;
14235
14236 data = info->data + info->gpos;
14237
14238 if (ttUSHORT(data+0) != 1) return 0; /* Major version 1 */
14239 if (ttUSHORT(data+2) != 0) return 0; /* Minor version 0 */
14240
14241 lookupListOffset = ttUSHORT(data+8);
14242 lookupList = data + lookupListOffset;
14243 lookupCount = ttUSHORT(lookupList);
14244
14245 for (i=0; i<lookupCount; ++i) {
14246 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
14247 stbtt_uint8 *lookupTable = lookupList + lookupOffset;
14248
14249 stbtt_uint16 lookupType = ttUSHORT(lookupTable);
14250 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
14251 stbtt_uint8 *subTableOffsets = lookupTable + 6;
14252 if (lookupType != 2) /* Pair Adjustment Positioning Subtable */
14253 continue;
14254
14255 for (sti=0; sti<subTableCount; sti++) {
14256 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
14257 stbtt_uint8 *table = lookupTable + subtableOffset;
14258 stbtt_uint16 posFormat = ttUSHORT(table);
14259 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
14260 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
14261 if (coverageIndex == -1) continue;
14262
14263 switch (posFormat) {
14264 case 1: {
14265 stbtt_int32 l, r, m;
14266 int straw, needle;
14267 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
14268 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
14269 if (valueFormat1 == 4 && valueFormat2 == 0) { /* Support more formats? */
14270 stbtt_int32 valueRecordPairSizeInBytes = 2;
14271 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
14272 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
14273 stbtt_uint8 *pairValueTable = table + pairPosOffset;
14274 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
14275 stbtt_uint8 *pairValueArray = pairValueTable + 2;
14276
14277 if (coverageIndex >= pairSetCount) return 0;
14278
14279 needle=glyph2;
14280 r=pairValueCount-1;
14281 l=0;
14282
14283 /* Binary search. */
14284 while (l <= r) {
14285 stbtt_uint16 secondGlyph;
14286 stbtt_uint8 *pairValue;
14287 m = (l + r) >> 1;
14288 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
14289 secondGlyph = ttUSHORT(pairValue);
14290 straw = secondGlyph;
14291 if (needle < straw)
14292 r = m - 1;
14293 else if (needle > straw)
14294 l = m + 1;
14295 else {
14296 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
14297 return xAdvance;
14298 }
14299 }
14300 } else
14301 return 0;
14302 break;
14303 }
14304
14305 case 2: {
14306 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
14307 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
14308 if (valueFormat1 == 4 && valueFormat2 == 0) { /* Support more formats? */
14309 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
14310 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
14311 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
14312 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
14313
14314 stbtt_uint16 class1Count = ttUSHORT(table + 12);
14315 stbtt_uint16 class2Count = ttUSHORT(table + 14);
14316 stbtt_uint8 *class1Records, *class2Records;
14317 stbtt_int16 xAdvance;
14318
14319 if (glyph1class < 0 || glyph1class >= class1Count) return 0; /* malformed */
14320 if (glyph2class < 0 || glyph2class >= class2Count) return 0; /* malformed */
14321
14322 class1Records = table + 16;
14323 class2Records = class1Records + 2 * (glyph1class * class2Count);
14324 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
14325 return xAdvance;
14326 } else
14327 return 0;
14328 break;
14329 }
14330
14331 default:
14332 return 0; /* Unsupported position format */
14333 }
14334 }
14335 }
14336
14337 return 0;
14338}
14339
14340STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
14341{
14342 int xAdvance = 0;
14343
14344 if (info->gpos)
14345 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
14346 else if (info->kern)
14347 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
14348
14349 return xAdvance;
14350}
14351
14352STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
14353{
14354 if (!info->kern && !info->gpos) /* if no kerning table, don't waste time looking up both codepoint->glyphs */
14355 return 0;
14356 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
14357}
14358
14359STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
14360{
14361 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
14362}
14363
14364STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
14365{
14366 if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4);
14367 if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
14368 if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
14369}
14370
14371STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
14372{
14373 int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
14374 if (!tab)
14375 return 0;
14376 if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68);
14377 if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
14378 if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
14379 return 1;
14380}
14381
14382STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
14383{
14384 *x0 = ttSHORT(info->data + info->head + 36);
14385 *y0 = ttSHORT(info->data + info->head + 38);
14386 *x1 = ttSHORT(info->data + info->head + 40);
14387 *y1 = ttSHORT(info->data + info->head + 42);
14388}
14389
14390STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
14391{
14392 int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
14393 return (float) height / fheight;
14394}
14395
14396STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
14397{
14398 int unitsPerEm = ttUSHORT(info->data + info->head + 18);
14399 return pixels / unitsPerEm;
14400}
14401
14402STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
14403{
14404 STBTT_free(v, info->userdata);
14405}
14406
14407STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
14408{
14409 int i;
14410 stbtt_uint8 *data = info->data;
14411 stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
14412
14413 int numEntries = ttUSHORT(svg_doc_list);
14414 stbtt_uint8 *svg_docs = svg_doc_list + 2;
14415
14416 for(i=0; i<numEntries; i++) {
14417 stbtt_uint8 *svg_doc = svg_docs + (12 * i);
14418 if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
14419 return svg_doc;
14420 }
14421 return 0;
14422}
14423
14424STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
14425{
14426 stbtt_uint8 *data = info->data;
14427 stbtt_uint8 *svg_doc;
14428
14429 if (info->svg == 0)
14430 return 0;
14431
14432 svg_doc = stbtt_FindSVGDoc(info, gl);
14433 if (svg_doc != NULL) {
14434 *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
14435 return ttULONG(svg_doc + 8);
14436 } else {
14437 return 0;
14438 }
14439}
14440
14441STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
14442{
14443 return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
14444}
14445
14446/* //////////////////////////////////////////////////////////////////////////// */
14447/* */
14448/* antialiasing software rasterizer */
14449/* */
14450
14451STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
14452{
14453 int x0=0,y0=0,x1,y1; /* =0 suppresses compiler warning */
14454 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
14455 /* e.g. space character */
14456 if (ix0) *ix0 = 0;
14457 if (iy0) *iy0 = 0;
14458 if (ix1) *ix1 = 0;
14459 if (iy1) *iy1 = 0;
14460 } else {
14461 /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */
14462 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
14463 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
14464 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
14465 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
14466 }
14467}
14468
14469STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
14470{
14471 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
14472}
14473
14474STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
14475{
14476 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
14477}
14478
14479STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
14480{
14481 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
14482}
14483
14484/* //////////////////////////////////////////////////////////////////////////// */
14485/* */
14486/* Rasterizer */
14487
14488typedef struct stbtt__hheap_chunk
14489{
14490 struct stbtt__hheap_chunk *next;
14491} stbtt__hheap_chunk;
14492
14493typedef struct stbtt__hheap
14494{
14495 struct stbtt__hheap_chunk *head;
14496 void *first_free;
14497 int num_remaining_in_head_chunk;
14498} stbtt__hheap;
14499
14500static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
14501{
14502 if (hh->first_free) {
14503 void *p = hh->first_free;
14504 hh->first_free = * (void **) p;
14505 return p;
14506 } else {
14507 if (hh->num_remaining_in_head_chunk == 0) {
14508 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
14509 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
14510 if (c == NULL)
14511 return NULL;
14512 c->next = hh->head;
14513 hh->head = c;
14514 hh->num_remaining_in_head_chunk = count;
14515 }
14516 --hh->num_remaining_in_head_chunk;
14517 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
14518 }
14519}
14520
14521static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
14522{
14523 *(void **) p = hh->first_free;
14524 hh->first_free = p;
14525}
14526
14527static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
14528{
14529 stbtt__hheap_chunk *c = hh->head;
14530 while (c) {
14531 stbtt__hheap_chunk *n = c->next;
14532 STBTT_free(c, userdata);
14533 c = n;
14534 }
14535}
14536
14537typedef struct stbtt__edge {
14538 float x0,y0, x1,y1;
14539 int invert;
14540} stbtt__edge;
14541
14542
14543typedef struct stbtt__active_edge
14544{
14545 struct stbtt__active_edge *next;
14546 #if STBTT_RASTERIZER_VERSION==1
14547 int x,dx;
14548 float ey;
14549 int direction;
14550 #elif STBTT_RASTERIZER_VERSION==2
14551 float fx,fdx,fdy;
14552 float direction;
14553 float sy;
14554 float ey;
14555 #else
14556 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
14557 #endif
14558} stbtt__active_edge;
14559
14560#if STBTT_RASTERIZER_VERSION == 1
14561#define STBTT_FIXSHIFT 10
14562#define STBTT_FIX (1 << STBTT_FIXSHIFT)
14563#define STBTT_FIXMASK (STBTT_FIX-1)
14564
14565static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
14566{
14567 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
14568 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
14569 STBTT_assert(z != NULL);
14570 if (!z) return z;
14571
14572 /* round dx down to avoid overshooting */
14573 if (dxdy < 0)
14574 z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
14575 else
14576 z->dx = STBTT_ifloor(STBTT_FIX * dxdy);
14577
14578 z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); /* use z->dx so when we offset later it's by the same amount */
14579 z->x -= off_x * STBTT_FIX;
14580
14581 z->ey = e->y1;
14582 z->next = 0;
14583 z->direction = e->invert ? 1 : -1;
14584 return z;
14585}
14586#elif STBTT_RASTERIZER_VERSION == 2
14587static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
14588{
14589 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
14590 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
14591 STBTT_assert(z != NULL);
14592 /* STBTT_assert(e->y0 <= start_point); */
14593 if (!z) return z;
14594 z->fdx = dxdy;
14595 z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
14596 z->fx = e->x0 + dxdy * (start_point - e->y0);
14597 z->fx -= off_x;
14598 z->direction = e->invert ? 1.0f : -1.0f;
14599 z->sy = e->y0;
14600 z->ey = e->y1;
14601 z->next = 0;
14602 return z;
14603}
14604#else
14605#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
14606#endif
14607
14608#if STBTT_RASTERIZER_VERSION == 1
14609/* note: this routine clips fills that extend off the edges... ideally this */
14610/* wouldn't happen, but it could happen if the truetype glyph bounding boxes */
14611/* are wrong, or if the user supplies a too-small bitmap */
14612static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
14613{
14614 /* non-zero winding fill */
14615 int x0=0, w=0;
14616
14617 while (e) {
14618 if (w == 0) {
14619 /* if we're currently at zero, we need to record the edge start point */
14620 x0 = e->x; w += e->direction;
14621 } else {
14622 int x1 = e->x; w += e->direction;
14623 /* if we went to zero, we need to draw */
14624 if (w == 0) {
14625 int i = x0 >> STBTT_FIXSHIFT;
14626 int j = x1 >> STBTT_FIXSHIFT;
14627
14628 if (i < len && j >= 0) {
14629 if (i == j) {
14630 /* x0,x1 are the same pixel, so compute combined coverage */
14631 scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
14632 } else {
14633 if (i >= 0) /* add antialiasing for x0 */
14634 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
14635 else
14636 i = -1; /* clip */
14637
14638 if (j < len) /* add antialiasing for x1 */
14639 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
14640 else
14641 j = len; /* clip */
14642
14643 for (++i; i < j; ++i) /* fill pixels between x0 and x1 */
14644 scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
14645 }
14646 }
14647 }
14648 }
14649
14650 e = e->next;
14651 }
14652}
14653
14654static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
14655{
14656 stbtt__hheap hh = { 0, 0, 0 };
14657 stbtt__active_edge *active = NULL;
14658 int y,j=0;
14659 int max_weight = (255 / vsubsample); /* weight per vertical scanline */
14660 int s; /* vertical subsample index */
14661 unsigned char scanline_data[512], *scanline;
14662
14663 if (result->w > 512)
14664 scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
14665 else
14666 scanline = scanline_data;
14667
14668 y = off_y * vsubsample;
14669 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
14670
14671 while (j < result->h) {
14672 STBTT_memset(scanline, 0, result->w);
14673 for (s=0; s < vsubsample; ++s) {
14674 /* find center of pixel for this scanline */
14675 float scan_y = y + 0.5f;
14676 stbtt__active_edge **step = &active;
14677
14678 /* update all active edges; */
14679 /* remove all active edges that terminate before the center of this scanline */
14680 while (*step) {
14681 stbtt__active_edge * z = *step;
14682 if (z->ey <= scan_y) {
14683 *step = z->next; /* delete from list */
14684 STBTT_assert(z->direction);
14685 z->direction = 0;
14686 stbtt__hheap_free(&hh, z);
14687 } else {
14688 z->x += z->dx; /* advance to position for current scanline */
14689 step = &((*step)->next); /* advance through list */
14690 }
14691 }
14692
14693 /* resort the list if needed */
14694 for(;;) {
14695 int changed=0;
14696 step = &active;
14697 while (*step && (*step)->next) {
14698 if ((*step)->x > (*step)->next->x) {
14699 stbtt__active_edge *t = *step;
14700 stbtt__active_edge *q = t->next;
14701
14702 t->next = q->next;
14703 q->next = t;
14704 *step = q;
14705 changed = 1;
14706 }
14707 step = &(*step)->next;
14708 }
14709 if (!changed) break;
14710 }
14711
14712 /* insert all edges that start before the center of this scanline -- omit ones that also end on this scanline */
14713 while (e->y0 <= scan_y) {
14714 if (e->y1 > scan_y) {
14715 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
14716 if (z != NULL) {
14717 /* find insertion point */
14718 if (active == NULL)
14719 active = z;
14720 else if (z->x < active->x) {
14721 /* insert at front */
14722 z->next = active;
14723 active = z;
14724 } else {
14725 /* find thing to insert AFTER */
14726 stbtt__active_edge *p = active;
14727 while (p->next && p->next->x < z->x)
14728 p = p->next;
14729 /* at this point, p->next->x is NOT < z->x */
14730 z->next = p->next;
14731 p->next = z;
14732 }
14733 }
14734 }
14735 ++e;
14736 }
14737
14738 /* now process all active edges in XOR fashion */
14739 if (active)
14740 stbtt__fill_active_edges(scanline, result->w, active, max_weight);
14741
14742 ++y;
14743 }
14744 STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
14745 ++j;
14746 }
14747
14748 stbtt__hheap_cleanup(&hh, userdata);
14749
14750 if (scanline != scanline_data)
14751 STBTT_free(scanline, userdata);
14752}
14753
14754#elif STBTT_RASTERIZER_VERSION == 2
14755
14756/* the edge passed in here does not cross the vertical line at x or the vertical line at x+1 */
14757/* (i.e. it has already been clipped to those) */
14758static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
14759{
14760 if (y0 == y1) return;
14761 STBTT_assert(y0 < y1);
14762 STBTT_assert(e->sy <= e->ey);
14763 if (y0 > e->ey) return;
14764 if (y1 < e->sy) return;
14765 if (y0 < e->sy) {
14766 x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
14767 y0 = e->sy;
14768 }
14769 if (y1 > e->ey) {
14770 x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
14771 y1 = e->ey;
14772 }
14773
14774 if (x0 == x)
14775 STBTT_assert(x1 <= x+1);
14776 else if (x0 == x+1)
14777 STBTT_assert(x1 >= x);
14778 else if (x0 <= x)
14779 STBTT_assert(x1 <= x);
14780 else if (x0 >= x+1)
14781 STBTT_assert(x1 >= x+1);
14782 else
14783 STBTT_assert(x1 >= x && x1 <= x+1);
14784
14785 if (x0 <= x && x1 <= x)
14786 scanline[x] += e->direction * (y1-y0);
14787 else if (x0 >= x+1 && x1 >= x+1)
14788 ;
14789 else {
14790 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
14791 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); /* coverage = 1 - average x position */
14792 }
14793}
14794
14795static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
14796{
14797 STBTT_assert(top_width >= 0);
14798 STBTT_assert(bottom_width >= 0);
14799 return (top_width + bottom_width) / 2.0f * height;
14800}
14801
14802static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
14803{
14804 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
14805}
14806
14807static float stbtt__sized_triangle_area(float height, float width)
14808{
14809 return height * width / 2;
14810}
14811
14812static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
14813{
14814 float y_bottom = y_top+1;
14815
14816 while (e) {
14817 /* brute force every pixel */
14818
14819 /* compute intersection points with top & bottom */
14820 STBTT_assert(e->ey >= y_top);
14821
14822 if (e->fdx == 0) {
14823 float x0 = e->fx;
14824 if (x0 < len) {
14825 if (x0 >= 0) {
14826 stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
14827 stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
14828 } else {
14829 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
14830 }
14831 }
14832 } else {
14833 float x0 = e->fx;
14834 float dx = e->fdx;
14835 float xb = x0 + dx;
14836 float x_top, x_bottom;
14837 float sy0,sy1;
14838 float dy = e->fdy;
14839 STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);
14840
14841 /* compute endpoints of line segment clipped to this scanline (if the */
14842 /* line segment starts on this scanline. x0 is the intersection of the */
14843 /* line with y_top, but that may be off the line segment. */
14844 if (e->sy > y_top) {
14845 x_top = x0 + dx * (e->sy - y_top);
14846 sy0 = e->sy;
14847 } else {
14848 x_top = x0;
14849 sy0 = y_top;
14850 }
14851 if (e->ey < y_bottom) {
14852 x_bottom = x0 + dx * (e->ey - y_top);
14853 sy1 = e->ey;
14854 } else {
14855 x_bottom = xb;
14856 sy1 = y_bottom;
14857 }
14858
14859 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
14860 /* from here on, we don't have to range check x values */
14861
14862 if ((int) x_top == (int) x_bottom) {
14863 float height;
14864 /* simple case, only spans one pixel */
14865 int x = (int) x_top;
14866 height = (sy1 - sy0) * e->direction;
14867 STBTT_assert(x >= 0 && x < len);
14868 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
14869 scanline_fill[x] += height; /* everything right of this pixel is filled */
14870 } else {
14871 int x,x1,x2;
14872 float y_crossing, y_final, step, sign, area;
14873 /* covers 2+ pixels */
14874 if (x_top > x_bottom) {
14875 /* flip scanline vertically; signed area is the same */
14876 float t;
14877 sy0 = y_bottom - (sy0 - y_top);
14878 sy1 = y_bottom - (sy1 - y_top);
14879 t = sy0, sy0 = sy1, sy1 = t;
14880 t = x_bottom, x_bottom = x_top, x_top = t;
14881 dx = -dx;
14882 dy = -dy;
14883 t = x0, x0 = xb, xb = t;
14884 }
14885 STBTT_assert(dy >= 0);
14886 STBTT_assert(dx >= 0);
14887
14888 x1 = (int) x_top;
14889 x2 = (int) x_bottom;
14890 /* compute intersection with y axis at x1+1 */
14891 y_crossing = y_top + dy * (x1+1 - x0);
14892
14893 /* compute intersection with y axis at x2 */
14894 y_final = y_top + dy * (x2 - x0);
14895
14896 /* x1 x_top x2 x_bottom */
14897 /* y_top +------|-----+------------+------------+--------|---+------------+ */
14898 /* | | | | | | */
14899 /* | | | | | | */
14900 /* sy0 | Txxxxx|............|............|............|............| */
14901 /* y_crossing | *xxxxx.......|............|............|............| */
14902 /* | | xxxxx..|............|............|............| */
14903 /* | | /- xx*xxxx........|............|............| */
14904 /* | | dy < | xxxxxx..|............|............| */
14905 /* y_final | | \- | xx*xxx.........|............| */
14906 /* sy1 | | | | xxxxxB...|............| */
14907 /* | | | | | | */
14908 /* | | | | | | */
14909 /* y_bottom +------------+------------+------------+------------+------------+ */
14910 /* */
14911 /* goal is to measure the area covered by '.' in each pixel */
14912
14913 /* if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 */
14914 /* @TODO: maybe test against sy1 rather than y_bottom? */
14915 if (y_crossing > y_bottom)
14916 y_crossing = y_bottom;
14917
14918 sign = e->direction;
14919
14920 /* area of the rectangle covered from sy0..y_crossing */
14921 area = sign * (y_crossing-sy0);
14922
14923 /* area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) */
14924 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
14925
14926 /* check if final y_crossing is blown up; no test case for this */
14927 if (y_final > y_bottom) {
14928 y_final = y_bottom;
14929 dy = (y_final - y_crossing ) / (x2 - (x1+1)); /* if denom=0, y_final = y_crossing, so y_final <= y_bottom */
14930 }
14931
14932 /* in second pixel, area covered by line segment found in first pixel */
14933 /* is always a rectangle 1 wide * the height of that line segment; this */
14934 /* is exactly what the variable 'area' stores. it also gets a contribution */
14935 /* from the line segment within it. the THIRD pixel will get the first */
14936 /* pixel's rectangle contribution, the second pixel's rectangle contribution, */
14937 /* and its own contribution. the 'own contribution' is the same in every pixel except */
14938 /* the leftmost and rightmost, a trapezoid that slides down in each pixel. */
14939 /* the second pixel's contribution to the third pixel will be the */
14940 /* rectangle 1 wide times the height change in the second pixel, which is dy. */
14941
14942 step = sign * dy * 1; /* dy is dy/dx, change in y for every 1 change in x, */
14943 /* which multiplied by 1-pixel-width is how much pixel area changes for each step in x */
14944 /* so the area advances by 'step' every time */
14945
14946 for (x = x1+1; x < x2; ++x) {
14947 scanline[x] += area + step/2; /* area of trapezoid is 1*step/2 */
14948 area += step;
14949 }
14950 STBTT_assert(STBTT_fabs(area) <= 1.01f); /* accumulated error from area += step unless we round step down */
14951 STBTT_assert(sy1 > y_final-0.01f);
14952
14953 /* area covered in the last pixel is the rectangle from all the pixels to the left, */
14954 /* plus the trapezoid filled by the line segment in this pixel all the way to the right edge */
14955 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
14956
14957 /* the rest of the line is filled based on the total height of the line segment in this pixel */
14958 scanline_fill[x2] += sign * (sy1-sy0);
14959 }
14960 } else {
14961 /* if edge goes outside of box we're drawing, we require */
14962 /* clipping logic. since this does not match the intended use */
14963 /* of this library, we use a different, very slow brute */
14964 /* force implementation */
14965 /* note though that this does happen some of the time because */
14966 /* x_top and x_bottom can be extrapolated at the top & bottom of */
14967 /* the shape and actually lie outside the bounding box */
14968 int x;
14969 for (x=0; x < len; ++x) {
14970 /* cases: */
14971 /* */
14972 /* there can be up to two intersections with the pixel. any intersection */
14973 /* with left or right edges can be handled by splitting into two (or three) */
14974 /* regions. intersections with top & bottom do not necessitate case-wise logic. */
14975 /* */
14976 /* the old way of doing this found the intersections with the left & right edges, */
14977 /* then used some simple logic to produce up to three segments in sorted order */
14978 /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */
14979 /* across the x border, then the corresponding y position might not be distinct */
14980 /* from the other y segment, and it might ignored as an empty segment. to avoid */
14981 /* that, we need to explicitly produce segments based on x positions. */
14982
14983 /* rename variables to clearly-defined pairs */
14984 float y0 = y_top;
14985 float x1 = (float) (x);
14986 float x2 = (float) (x+1);
14987 float x3 = xb;
14988 float y3 = y_bottom;
14989
14990 /* x = e->x + e->dx * (y-y_top) */
14991 /* (y-y_top) = (x - e->x) / e->dx */
14992 /* y = (x - e->x) / e->dx + y_top */
14993 float y1 = (x - x0) / dx + y_top;
14994 float y2 = (x+1 - x0) / dx + y_top;
14995
14996 if (x0 < x1 && x3 > x2) { /* three segments descending down-right */
14997 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
14998 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
14999 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
15000 } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */
15001 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
15002 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
15003 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
15004 } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */
15005 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
15006 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
15007 } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */
15008 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
15009 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
15010 } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */
15011 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
15012 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
15013 } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */
15014 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
15015 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
15016 } else { /* one segment */
15017 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
15018 }
15019 }
15020 }
15021 }
15022 e = e->next;
15023 }
15024}
15025
15026/* directly AA rasterize edges w/o supersampling */
15027static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
15028{
15029 stbtt__hheap hh = { 0, 0, 0 };
15030 stbtt__active_edge *active = NULL;
15031 int y,j=0, i;
15032 float scanline_data[129], *scanline, *scanline2;
15033
15034 STBTT__NOTUSED(vsubsample);
15035
15036 if (result->w > 64)
15037 scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
15038 else
15039 scanline = scanline_data;
15040
15041 scanline2 = scanline + result->w;
15042
15043 y = off_y;
15044 e[n].y0 = (float) (off_y + result->h) + 1;
15045
15046 while (j < result->h) {
15047 /* find center of pixel for this scanline */
15048 float scan_y_top = y + 0.0f;
15049 float scan_y_bottom = y + 1.0f;
15050 stbtt__active_edge **step = &active;
15051
15052 STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
15053 STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
15054
15055 /* update all active edges; */
15056 /* remove all active edges that terminate before the top of this scanline */
15057 while (*step) {
15058 stbtt__active_edge * z = *step;
15059 if (z->ey <= scan_y_top) {
15060 *step = z->next; /* delete from list */
15061 STBTT_assert(z->direction);
15062 z->direction = 0;
15063 stbtt__hheap_free(&hh, z);
15064 } else {
15065 step = &((*step)->next); /* advance through list */
15066 }
15067 }
15068
15069 /* insert all edges that start before the bottom of this scanline */
15070 while (e->y0 <= scan_y_bottom) {
15071 if (e->y0 != e->y1) {
15072 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
15073 if (z != NULL) {
15074 if (j == 0 && off_y != 0) {
15075 if (z->ey < scan_y_top) {
15076 /* this can happen due to subpixel positioning and some kind of fp rounding error i think */
15077 z->ey = scan_y_top;
15078 }
15079 }
15080 STBTT_assert(z->ey >= scan_y_top); /* if we get really unlucky a tiny bit of an edge can be out of bounds */
15081 /* insert at front */
15082 z->next = active;
15083 active = z;
15084 }
15085 }
15086 ++e;
15087 }
15088
15089 /* now process all active edges */
15090 if (active)
15091 stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
15092
15093 {
15094 float sum = 0;
15095 for (i=0; i < result->w; ++i) {
15096 float k;
15097 int m;
15098 sum += scanline2[i];
15099 k = scanline[i] + sum;
15100 k = (float) STBTT_fabs(k)*255 + 0.5f;
15101 m = (int) k;
15102 if (m > 255) m = 255;
15103 result->pixels[j*result->stride + i] = (unsigned char) m;
15104 }
15105 }
15106 /* advance all the edges */
15107 step = &active;
15108 while (*step) {
15109 stbtt__active_edge *z = *step;
15110 z->fx += z->fdx; /* advance to position for current scanline */
15111 step = &((*step)->next); /* advance through list */
15112 }
15113
15114 ++y;
15115 ++j;
15116 }
15117
15118 stbtt__hheap_cleanup(&hh, userdata);
15119
15120 if (scanline != scanline_data)
15121 STBTT_free(scanline, userdata);
15122}
15123#else
15124#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
15125#endif
15126
15127#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0)
15128
15129static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
15130{
15131 int i,j;
15132 for (i=1; i < n; ++i) {
15133 stbtt__edge t = p[i], *a = &t;
15134 j = i;
15135 while (j > 0) {
15136 stbtt__edge *b = &p[j-1];
15137 int c = STBTT__COMPARE(a,b);
15138 if (!c) break;
15139 p[j] = p[j-1];
15140 --j;
15141 }
15142 if (i != j)
15143 p[j] = t;
15144 }
15145}
15146
15147static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
15148{
15149 /* threshold for transitioning to insertion sort */
15150 while (n > 12) {
15151 stbtt__edge t;
15152 int c01,c12,c,m,i,j;
15153
15154 /* compute median of three */
15155 m = n >> 1;
15156 c01 = STBTT__COMPARE(&p[0],&p[m]);
15157 c12 = STBTT__COMPARE(&p[m],&p[n-1]);
15158 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
15159 if (c01 != c12) {
15160 /* otherwise, we'll need to swap something else to middle */
15161 int z;
15162 c = STBTT__COMPARE(&p[0],&p[n-1]);
15163 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
15164 /* 0<mid && mid>n: 0>n => 0; 0<n => n */
15165 z = (c == c12) ? 0 : n-1;
15166 t = p[z];
15167 p[z] = p[m];
15168 p[m] = t;
15169 }
15170 /* now p[m] is the median-of-three */
15171 /* swap it to the beginning so it won't move around */
15172 t = p[0];
15173 p[0] = p[m];
15174 p[m] = t;
15175
15176 /* partition loop */
15177 i=1;
15178 j=n-1;
15179 for(;;) {
15180 /* handling of equality is crucial here */
15181 /* for sentinels & efficiency with duplicates */
15182 for (;;++i) {
15183 if (!STBTT__COMPARE(&p[i], &p[0])) break;
15184 }
15185 for (;;--j) {
15186 if (!STBTT__COMPARE(&p[0], &p[j])) break;
15187 }
15188 /* make sure we haven't crossed */
15189 if (i >= j) break;
15190 t = p[i];
15191 p[i] = p[j];
15192 p[j] = t;
15193
15194 ++i;
15195 --j;
15196 }
15197 /* recurse on smaller side, iterate on larger */
15198 if (j < (n-i)) {
15199 stbtt__sort_edges_quicksort(p,j);
15200 p = p+i;
15201 n = n-i;
15202 } else {
15203 stbtt__sort_edges_quicksort(p+i, n-i);
15204 n = j;
15205 }
15206 }
15207}
15208
15209static void stbtt__sort_edges(stbtt__edge *p, int n)
15210{
15211 stbtt__sort_edges_quicksort(p, n);
15212 stbtt__sort_edges_ins_sort(p, n);
15213}
15214
15215typedef struct
15216{
15217 float x,y;
15218} stbtt__point;
15219
15220static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
15221{
15222 float y_scale_inv = invert ? -scale_y : scale_y;
15223 stbtt__edge *e;
15224 int n,i,j,k,m;
15225#if STBTT_RASTERIZER_VERSION == 1
15226 int vsubsample = result->h < 8 ? 15 : 5;
15227#elif STBTT_RASTERIZER_VERSION == 2
15228 int vsubsample = 1;
15229#else
15230 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
15231#endif
15232 /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */
15233
15234 /* now we have to blow out the windings into explicit edge lists */
15235 n = 0;
15236 for (i=0; i < windings; ++i)
15237 n += wcount[i];
15238
15239 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); /* add an extra one as a sentinel */
15240 if (e == 0) return;
15241 n = 0;
15242
15243 m=0;
15244 for (i=0; i < windings; ++i) {
15245 stbtt__point *p = pts + m;
15246 m += wcount[i];
15247 j = wcount[i]-1;
15248 for (k=0; k < wcount[i]; j=k++) {
15249 int a=k,b=j;
15250 /* skip the edge if horizontal */
15251 if (p[j].y == p[k].y)
15252 continue;
15253 /* add edge from j to k to the list */
15254 e[n].invert = 0;
15255 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
15256 e[n].invert = 1;
15257 a=j,b=k;
15258 }
15259 e[n].x0 = p[a].x * scale_x + shift_x;
15260 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
15261 e[n].x1 = p[b].x * scale_x + shift_x;
15262 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
15263 ++n;
15264 }
15265 }
15266
15267 /* now sort the edges by their highest point (should snap to integer, and then by x) */
15268 /* STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */
15269 stbtt__sort_edges(e, n);
15270
15271 /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */
15272 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
15273
15274 STBTT_free(e, userdata);
15275}
15276
15277static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
15278{
15279 if (!points) return; /* during first pass, it's unallocated */
15280 points[n].x = x;
15281 points[n].y = y;
15282}
15283
15284/* tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching */
15285static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
15286{
15287 /* midpoint */
15288 float mx = (x0 + 2*x1 + x2)/4;
15289 float my = (y0 + 2*y1 + y2)/4;
15290 /* versus directly drawn line */
15291 float dx = (x0+x2)/2 - mx;
15292 float dy = (y0+y2)/2 - my;
15293 if (n > 16) /* 65536 segments on one curve better be enough! */
15294 return 1;
15295 if (dx*dx+dy*dy > objspace_flatness_squared) { /* half-pixel error allowed... need to be smaller if AA */
15296 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
15297 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
15298 } else {
15299 stbtt__add_point(points, *num_points,x2,y2);
15300 *num_points = *num_points+1;
15301 }
15302 return 1;
15303}
15304
15305static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
15306{
15307 /* @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough */
15308 float dx0 = x1-x0;
15309 float dy0 = y1-y0;
15310 float dx1 = x2-x1;
15311 float dy1 = y2-y1;
15312 float dx2 = x3-x2;
15313 float dy2 = y3-y2;
15314 float dx = x3-x0;
15315 float dy = y3-y0;
15316 float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
15317 float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
15318 float flatness_squared = longlen*longlen-shortlen*shortlen;
15319
15320 if (n > 16) /* 65536 segments on one curve better be enough! */
15321 return;
15322
15323 if (flatness_squared > objspace_flatness_squared) {
15324 float x01 = (x0+x1)/2;
15325 float y01 = (y0+y1)/2;
15326 float x12 = (x1+x2)/2;
15327 float y12 = (y1+y2)/2;
15328 float x23 = (x2+x3)/2;
15329 float y23 = (y2+y3)/2;
15330
15331 float xa = (x01+x12)/2;
15332 float ya = (y01+y12)/2;
15333 float xb = (x12+x23)/2;
15334 float yb = (y12+y23)/2;
15335
15336 float mx = (xa+xb)/2;
15337 float my = (ya+yb)/2;
15338
15339 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
15340 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
15341 } else {
15342 stbtt__add_point(points, *num_points,x3,y3);
15343 *num_points = *num_points+1;
15344 }
15345}
15346
15347/* returns number of contours */
15348static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
15349{
15350 stbtt__point *points=0;
15351 int num_points=0;
15352
15353 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
15354 int i,n=0,start=0, pass;
15355
15356 /* count how many "moves" there are to get the contour count */
15357 for (i=0; i < num_verts; ++i)
15358 if (vertices[i].type == STBTT_vmove)
15359 ++n;
15360
15361 *num_contours = n;
15362 if (n == 0) return 0;
15363
15364 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
15365
15366 if (*contour_lengths == 0) {
15367 *num_contours = 0;
15368 return 0;
15369 }
15370
15371 /* make two passes through the points so we don't need to realloc */
15372 for (pass=0; pass < 2; ++pass) {
15373 float x=0,y=0;
15374 if (pass == 1) {
15375 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
15376 if (points == NULL) goto error;
15377 }
15378 num_points = 0;
15379 n= -1;
15380 for (i=0; i < num_verts; ++i) {
15381 switch (vertices[i].type) {
15382 case STBTT_vmove:
15383 /* start the next contour */
15384 if (n >= 0)
15385 (*contour_lengths)[n] = num_points - start;
15386 ++n;
15387 start = num_points;
15388
15389 x = vertices[i].x, y = vertices[i].y;
15390 stbtt__add_point(points, num_points++, x,y);
15391 break;
15392 case STBTT_vline:
15393 x = vertices[i].x, y = vertices[i].y;
15394 stbtt__add_point(points, num_points++, x, y);
15395 break;
15396 case STBTT_vcurve:
15397 stbtt__tesselate_curve(points, &num_points, x,y,
15398 vertices[i].cx, vertices[i].cy,
15399 vertices[i].x, vertices[i].y,
15400 objspace_flatness_squared, 0);
15401 x = vertices[i].x, y = vertices[i].y;
15402 break;
15403 case STBTT_vcubic:
15404 stbtt__tesselate_cubic(points, &num_points, x,y,
15405 vertices[i].cx, vertices[i].cy,
15406 vertices[i].cx1, vertices[i].cy1,
15407 vertices[i].x, vertices[i].y,
15408 objspace_flatness_squared, 0);
15409 x = vertices[i].x, y = vertices[i].y;
15410 break;
15411 }
15412 }
15413 (*contour_lengths)[n] = num_points - start;
15414 }
15415
15416 return points;
15417error:
15418 STBTT_free(points, userdata);
15419 STBTT_free(*contour_lengths, userdata);
15420 *contour_lengths = 0;
15421 *num_contours = 0;
15422 return NULL;
15423}
15424
15425STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
15426{
15427 float scale = scale_x > scale_y ? scale_y : scale_x;
15428 int winding_count = 0;
15429 int *winding_lengths = NULL;
15430 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
15431 if (windings) {
15432 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
15433 STBTT_free(winding_lengths, userdata);
15434 STBTT_free(windings, userdata);
15435 }
15436}
15437
15438STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
15439{
15440 STBTT_free(bitmap, userdata);
15441}
15442
15443STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
15444{
15445 int ix0,iy0,ix1,iy1;
15446 stbtt__bitmap gbm;
15447 stbtt_vertex *vertices;
15448 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
15449
15450 if (scale_x == 0) scale_x = scale_y;
15451 if (scale_y == 0) {
15452 if (scale_x == 0) {
15453 STBTT_free(vertices, info->userdata);
15454 return NULL;
15455 }
15456 scale_y = scale_x;
15457 }
15458
15459 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
15460
15461 /* now we get the size */
15462 gbm.w = (ix1 - ix0);
15463 gbm.h = (iy1 - iy0);
15464 gbm.pixels = NULL; /* in case we error */
15465
15466 if (width ) *width = gbm.w;
15467 if (height) *height = gbm.h;
15468 if (xoff ) *xoff = ix0;
15469 if (yoff ) *yoff = iy0;
15470
15471 if (gbm.w && gbm.h) {
15472 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
15473 if (gbm.pixels) {
15474 gbm.stride = gbm.w;
15475
15476 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
15477 }
15478 }
15479 STBTT_free(vertices, info->userdata);
15480 return gbm.pixels;
15481}
15482
15483STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
15484{
15485 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
15486}
15487
15488STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
15489{
15490 int ix0,iy0;
15491 stbtt_vertex *vertices;
15492 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
15493 stbtt__bitmap gbm;
15494
15495 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
15496 gbm.pixels = output;
15497 gbm.w = out_w;
15498 gbm.h = out_h;
15499 gbm.stride = out_stride;
15500
15501 if (gbm.w && gbm.h)
15502 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
15503
15504 STBTT_free(vertices, info->userdata);
15505}
15506
15507STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
15508{
15509 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
15510}
15511
15512STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
15513{
15514 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
15515}
15516
15517STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
15518{
15519 stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
15520}
15521
15522STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
15523{
15524 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
15525}
15526
15527STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
15528{
15529 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
15530}
15531
15532STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
15533{
15534 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
15535}
15536
15537/* //////////////////////////////////////////////////////////////////////////// */
15538/* */
15539/* bitmap baking */
15540/* */
15541/* This is SUPER-CRAPPY packing to keep source code small */
15542
15543static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, /* font location (use offset=0 for plain .ttf) */
15544 float pixel_height, /* height of font in pixels */
15545 unsigned char *pixels, int pw, int ph, /* bitmap to be filled in */
15546 int first_char, int num_chars, /* characters to bake */
15547 stbtt_bakedchar *chardata)
15548{
15549 float scale;
15550 int x,y,bottom_y, i;
15551 stbtt_fontinfo f;
15552 f.userdata = NULL;
15553 if (!stbtt_InitFont(&f, data, offset))
15554 return -1;
15555 STBTT_memset(pixels, 0, pw*ph); /* background of 0 around pixels */
15556 x=y=1;
15557 bottom_y = 1;
15558
15559 scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
15560
15561 for (i=0; i < num_chars; ++i) {
15562 int advance, lsb, x0,y0,x1,y1,gw,gh;
15563 int g = stbtt_FindGlyphIndex(&f, first_char + i);
15564 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
15565 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
15566 gw = x1-x0;
15567 gh = y1-y0;
15568 if (x + gw + 1 >= pw)
15569 y = bottom_y, x = 1; /* advance to next row */
15570 if (y + gh + 1 >= ph) /* check if it fits vertically AFTER potentially moving to next row */
15571 return -i;
15572 STBTT_assert(x+gw < pw);
15573 STBTT_assert(y+gh < ph);
15574 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
15575 chardata[i].x0 = (stbtt_int16) x;
15576 chardata[i].y0 = (stbtt_int16) y;
15577 chardata[i].x1 = (stbtt_int16) (x + gw);
15578 chardata[i].y1 = (stbtt_int16) (y + gh);
15579 chardata[i].xadvance = scale * advance;
15580 chardata[i].xoff = (float) x0;
15581 chardata[i].yoff = (float) y0;
15582 x = x + gw + 1;
15583 if (y+gh+1 > bottom_y)
15584 bottom_y = y+gh+1;
15585 }
15586 return bottom_y;
15587}
15588
15589STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
15590{
15591 float d3d_bias = opengl_fillrule ? 0 : -0.5f;
15592 float ipw = 1.0f / pw, iph = 1.0f / ph;
15593 const stbtt_bakedchar *b = chardata + char_index;
15594 int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
15595 int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
15596
15597 q->x0 = round_x + d3d_bias;
15598 q->y0 = round_y + d3d_bias;
15599 q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
15600 q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
15601
15602 q->s0 = b->x0 * ipw;
15603 q->t0 = b->y0 * iph;
15604 q->s1 = b->x1 * ipw;
15605 q->t1 = b->y1 * iph;
15606
15607 *xpos += b->xadvance;
15608}
15609
15610/* //////////////////////////////////////////////////////////////////////////// */
15611/* */
15612/* rectangle packing replacement routines if you don't have stb_rect_pack.h */
15613/* */
15614
15615#ifndef STB_RECT_PACK_VERSION
15616
15617typedef int stbrp_coord;
15618
15619/* ////////////////////////////////////////////////////////////////////////////////// */
15620/* // */
15621/* // */
15622/* COMPILER WARNING ?!?!? // */
15623/* // */
15624/* // */
15625/* if you get a compile warning due to these symbols being defined more than // */
15626/* once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // */
15627/* // */
15628/* ////////////////////////////////////////////////////////////////////////////////// */
15629
15630typedef struct
15631{
15632 int width,height;
15633 int x,y,bottom_y;
15634} stbrp_context;
15635
15636typedef struct
15637{
15638 unsigned char x;
15639} stbrp_node;
15640
15641struct stbrp_rect
15642{
15643 stbrp_coord x,y;
15644 int id,w,h,was_packed;
15645};
15646
15647static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
15648{
15649 con->width = pw;
15650 con->height = ph;
15651 con->x = 0;
15652 con->y = 0;
15653 con->bottom_y = 0;
15654 STBTT__NOTUSED(nodes);
15655 STBTT__NOTUSED(num_nodes);
15656}
15657
15658static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
15659{
15660 int i;
15661 for (i=0; i < num_rects; ++i) {
15662 if (con->x + rects[i].w > con->width) {
15663 con->x = 0;
15664 con->y = con->bottom_y;
15665 }
15666 if (con->y + rects[i].h > con->height)
15667 break;
15668 rects[i].x = con->x;
15669 rects[i].y = con->y;
15670 rects[i].was_packed = 1;
15671 con->x += rects[i].w;
15672 if (con->y + rects[i].h > con->bottom_y)
15673 con->bottom_y = con->y + rects[i].h;
15674 }
15675 for ( ; i < num_rects; ++i)
15676 rects[i].was_packed = 0;
15677}
15678#endif
15679
15680/* //////////////////////////////////////////////////////////////////////////// */
15681/* */
15682/* bitmap baking */
15683/* */
15684/* This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If */
15685/* stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. */
15686
15687STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
15688{
15689 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context);
15690 int num_nodes = pw - padding;
15691 stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context);
15692
15693 if (context == NULL || nodes == NULL) {
15694 if (context != NULL) STBTT_free(context, alloc_context);
15695 if (nodes != NULL) STBTT_free(nodes , alloc_context);
15696 return 0;
15697 }
15698
15699 spc->user_allocator_context = alloc_context;
15700 spc->width = pw;
15701 spc->height = ph;
15702 spc->pixels = pixels;
15703 spc->pack_info = context;
15704 spc->nodes = nodes;
15705 spc->padding = padding;
15706 spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
15707 spc->h_oversample = 1;
15708 spc->v_oversample = 1;
15709 spc->skip_missing = 0;
15710
15711 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
15712
15713 if (pixels)
15714 STBTT_memset(pixels, 0, pw*ph); /* background of 0 around pixels */
15715
15716 return 1;
15717}
15718
15719STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc)
15720{
15721 STBTT_free(spc->nodes , spc->user_allocator_context);
15722 STBTT_free(spc->pack_info, spc->user_allocator_context);
15723}
15724
15725STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)
15726{
15727 STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
15728 STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
15729 if (h_oversample <= STBTT_MAX_OVERSAMPLE)
15730 spc->h_oversample = h_oversample;
15731 if (v_oversample <= STBTT_MAX_OVERSAMPLE)
15732 spc->v_oversample = v_oversample;
15733}
15734
15735STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
15736{
15737 spc->skip_missing = skip;
15738}
15739
15740#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
15741
15742static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
15743{
15744 unsigned char buffer[STBTT_MAX_OVERSAMPLE];
15745 int safe_w = w - kernel_width;
15746 int j;
15747 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /* suppress bogus warning from VS2013 -analyze */
15748 for (j=0; j < h; ++j) {
15749 int i;
15750 unsigned int total;
15751 STBTT_memset(buffer, 0, kernel_width);
15752
15753 total = 0;
15754
15755 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
15756 switch (kernel_width) {
15757 case 2:
15758 for (i=0; i <= safe_w; ++i) {
15759 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
15760 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
15761 pixels[i] = (unsigned char) (total / 2);
15762 }
15763 break;
15764 case 3:
15765 for (i=0; i <= safe_w; ++i) {
15766 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
15767 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
15768 pixels[i] = (unsigned char) (total / 3);
15769 }
15770 break;
15771 case 4:
15772 for (i=0; i <= safe_w; ++i) {
15773 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
15774 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
15775 pixels[i] = (unsigned char) (total / 4);
15776 }
15777 break;
15778 case 5:
15779 for (i=0; i <= safe_w; ++i) {
15780 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
15781 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
15782 pixels[i] = (unsigned char) (total / 5);
15783 }
15784 break;
15785 default:
15786 for (i=0; i <= safe_w; ++i) {
15787 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
15788 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
15789 pixels[i] = (unsigned char) (total / kernel_width);
15790 }
15791 break;
15792 }
15793
15794 for (; i < w; ++i) {
15795 STBTT_assert(pixels[i] == 0);
15796 total -= buffer[i & STBTT__OVER_MASK];
15797 pixels[i] = (unsigned char) (total / kernel_width);
15798 }
15799
15800 pixels += stride_in_bytes;
15801 }
15802}
15803
15804static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
15805{
15806 unsigned char buffer[STBTT_MAX_OVERSAMPLE];
15807 int safe_h = h - kernel_width;
15808 int j;
15809 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /* suppress bogus warning from VS2013 -analyze */
15810 for (j=0; j < w; ++j) {
15811 int i;
15812 unsigned int total;
15813 STBTT_memset(buffer, 0, kernel_width);
15814
15815 total = 0;
15816
15817 /* make kernel_width a constant in common cases so compiler can optimize out the divide */
15818 switch (kernel_width) {
15819 case 2:
15820 for (i=0; i <= safe_h; ++i) {
15821 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
15822 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
15823 pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
15824 }
15825 break;
15826 case 3:
15827 for (i=0; i <= safe_h; ++i) {
15828 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
15829 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
15830 pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
15831 }
15832 break;
15833 case 4:
15834 for (i=0; i <= safe_h; ++i) {
15835 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
15836 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
15837 pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
15838 }
15839 break;
15840 case 5:
15841 for (i=0; i <= safe_h; ++i) {
15842 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
15843 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
15844 pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
15845 }
15846 break;
15847 default:
15848 for (i=0; i <= safe_h; ++i) {
15849 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
15850 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
15851 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
15852 }
15853 break;
15854 }
15855
15856 for (; i < h; ++i) {
15857 STBTT_assert(pixels[i*stride_in_bytes] == 0);
15858 total -= buffer[i & STBTT__OVER_MASK];
15859 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
15860 }
15861
15862 pixels += 1;
15863 }
15864}
15865
15866static float stbtt__oversample_shift(int oversample)
15867{
15868 if (!oversample)
15869 return 0.0f;
15870
15871 /* The prefilter is a box filter of width "oversample", */
15872 /* which shifts phase by (oversample - 1)/2 pixels in */
15873 /* oversampled space. We want to shift in the opposite */
15874 /* direction to counter this. */
15875 return (float)-(oversample - 1) / (2.0f * (float)oversample);
15876}
15877
15878/* rects array must be big enough to accommodate all characters in the given ranges */
15879STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
15880{
15881 int i,j,k;
15882 int missing_glyph_added = 0;
15883
15884 k=0;
15885 for (i=0; i < num_ranges; ++i) {
15886 float fh = ranges[i].font_size;
15887 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
15888 ranges[i].h_oversample = (unsigned char) spc->h_oversample;
15889 ranges[i].v_oversample = (unsigned char) spc->v_oversample;
15890 for (j=0; j < ranges[i].num_chars; ++j) {
15891 int x0,y0,x1,y1;
15892 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
15893 int glyph = stbtt_FindGlyphIndex(info, codepoint);
15894 if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
15895 rects[k].w = rects[k].h = 0;
15896 } else {
15897 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
15898 scale * spc->h_oversample,
15899 scale * spc->v_oversample,
15900 0,0,
15901 &x0,&y0,&x1,&y1);
15902 rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
15903 rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
15904 if (glyph == 0)
15905 missing_glyph_added = 1;
15906 }
15907 ++k;
15908 }
15909 }
15910
15911 return k;
15912}
15913
15914STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
15915{
15916 stbtt_MakeGlyphBitmapSubpixel(info,
15917 output,
15918 out_w - (prefilter_x - 1),
15919 out_h - (prefilter_y - 1),
15920 out_stride,
15921 scale_x,
15922 scale_y,
15923 shift_x,
15924 shift_y,
15925 glyph);
15926
15927 if (prefilter_x > 1)
15928 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
15929
15930 if (prefilter_y > 1)
15931 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
15932
15933 *sub_x = stbtt__oversample_shift(prefilter_x);
15934 *sub_y = stbtt__oversample_shift(prefilter_y);
15935}
15936
15937/* rects array must be big enough to accommodate all characters in the given ranges */
15938STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
15939{
15940 int i,j,k, missing_glyph = -1, return_value = 1;
15941
15942 /* save current values */
15943 int old_h_over = spc->h_oversample;
15944 int old_v_over = spc->v_oversample;
15945
15946 k = 0;
15947 for (i=0; i < num_ranges; ++i) {
15948 float fh = ranges[i].font_size;
15949 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
15950 float recip_h,recip_v,sub_x,sub_y;
15951 spc->h_oversample = ranges[i].h_oversample;
15952 spc->v_oversample = ranges[i].v_oversample;
15953 recip_h = 1.0f / spc->h_oversample;
15954 recip_v = 1.0f / spc->v_oversample;
15955 sub_x = stbtt__oversample_shift(spc->h_oversample);
15956 sub_y = stbtt__oversample_shift(spc->v_oversample);
15957 for (j=0; j < ranges[i].num_chars; ++j) {
15958 stbrp_rect *r = &rects[k];
15959 if (r->was_packed && r->w != 0 && r->h != 0) {
15960 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
15961 int advance, lsb, x0,y0,x1,y1;
15962 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
15963 int glyph = stbtt_FindGlyphIndex(info, codepoint);
15964 stbrp_coord pad = (stbrp_coord) spc->padding;
15965
15966 /* pad on left and top */
15967 r->x += pad;
15968 r->y += pad;
15969 r->w -= pad;
15970 r->h -= pad;
15971 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
15972 stbtt_GetGlyphBitmapBox(info, glyph,
15973 scale * spc->h_oversample,
15974 scale * spc->v_oversample,
15975 &x0,&y0,&x1,&y1);
15976 stbtt_MakeGlyphBitmapSubpixel(info,
15977 spc->pixels + r->x + r->y*spc->stride_in_bytes,
15978 r->w - spc->h_oversample+1,
15979 r->h - spc->v_oversample+1,
15980 spc->stride_in_bytes,
15981 scale * spc->h_oversample,
15982 scale * spc->v_oversample,
15983 0,0,
15984 glyph);
15985
15986 if (spc->h_oversample > 1)
15987 stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
15988 r->w, r->h, spc->stride_in_bytes,
15989 spc->h_oversample);
15990
15991 if (spc->v_oversample > 1)
15992 stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
15993 r->w, r->h, spc->stride_in_bytes,
15994 spc->v_oversample);
15995
15996 bc->x0 = (stbtt_int16) r->x;
15997 bc->y0 = (stbtt_int16) r->y;
15998 bc->x1 = (stbtt_int16) (r->x + r->w);
15999 bc->y1 = (stbtt_int16) (r->y + r->h);
16000 bc->xadvance = scale * advance;
16001 bc->xoff = (float) x0 * recip_h + sub_x;
16002 bc->yoff = (float) y0 * recip_v + sub_y;
16003 bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
16004 bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
16005
16006 if (glyph == 0)
16007 missing_glyph = j;
16008 } else if (spc->skip_missing) {
16009 return_value = 0;
16010 } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
16011 ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
16012 } else {
16013 return_value = 0; /* if any fail, report failure */
16014 }
16015
16016 ++k;
16017 }
16018 }
16019
16020 /* restore original values */
16021 spc->h_oversample = old_h_over;
16022 spc->v_oversample = old_v_over;
16023
16024 return return_value;
16025}
16026
16027STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
16028{
16029 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
16030}
16031
16032STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
16033{
16034 stbtt_fontinfo info;
16035 int i,j,n, return_value = 1;
16036 /* stbrp_context *context = (stbrp_context *) spc->pack_info; */
16037 stbrp_rect *rects;
16038
16039 /* flag all characters as NOT packed */
16040 for (i=0; i < num_ranges; ++i)
16041 for (j=0; j < ranges[i].num_chars; ++j)
16042 ranges[i].chardata_for_range[j].x0 =
16043 ranges[i].chardata_for_range[j].y0 =
16044 ranges[i].chardata_for_range[j].x1 =
16045 ranges[i].chardata_for_range[j].y1 = 0;
16046
16047 n = 0;
16048 for (i=0; i < num_ranges; ++i)
16049 n += ranges[i].num_chars;
16050
16051 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
16052 if (rects == NULL)
16053 return 0;
16054
16055 info.userdata = spc->user_allocator_context;
16056 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
16057
16058 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
16059
16060 stbtt_PackFontRangesPackRects(spc, rects, n);
16061
16062 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
16063
16064 STBTT_free(rects, spc->user_allocator_context);
16065 return return_value;
16066}
16067
16068STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
16069 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
16070{
16071 stbtt_pack_range range;
16072 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
16073 range.array_of_unicode_codepoints = NULL;
16074 range.num_chars = num_chars_in_range;
16075 range.chardata_for_range = chardata_for_range;
16076 range.font_size = font_size;
16077 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
16078}
16079
16080STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
16081{
16082 int i_ascent, i_descent, i_lineGap;
16083 float scale;
16084 stbtt_fontinfo info;
16085 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
16086 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
16087 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
16088 *ascent = (float) i_ascent * scale;
16089 *descent = (float) i_descent * scale;
16090 *lineGap = (float) i_lineGap * scale;
16091}
16092
16093STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
16094{
16095 float ipw = 1.0f / pw, iph = 1.0f / ph;
16096 const stbtt_packedchar *b = chardata + char_index;
16097
16098 if (align_to_integer) {
16099 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
16100 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
16101 q->x0 = x;
16102 q->y0 = y;
16103 q->x1 = x + b->xoff2 - b->xoff;
16104 q->y1 = y + b->yoff2 - b->yoff;
16105 } else {
16106 q->x0 = *xpos + b->xoff;
16107 q->y0 = *ypos + b->yoff;
16108 q->x1 = *xpos + b->xoff2;
16109 q->y1 = *ypos + b->yoff2;
16110 }
16111
16112 q->s0 = b->x0 * ipw;
16113 q->t0 = b->y0 * iph;
16114 q->s1 = b->x1 * ipw;
16115 q->t1 = b->y1 * iph;
16116
16117 *xpos += b->xadvance;
16118}
16119
16120/* //////////////////////////////////////////////////////////////////////////// */
16121/* */
16122/* sdf computation */
16123/* */
16124
16125#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
16126#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
16127
16128static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
16129{
16130 float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
16131 float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
16132 float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
16133 float roperp = orig[1]*ray[0] - orig[0]*ray[1];
16134
16135 float a = q0perp - 2*q1perp + q2perp;
16136 float b = q1perp - q0perp;
16137 float c = q0perp - roperp;
16138
16139 float s0 = 0., s1 = 0.;
16140 int num_s = 0;
16141
16142 if (a != 0.0) {
16143 float discr = b*b - a*c;
16144 if (discr > 0.0) {
16145 float rcpna = -1 / a;
16146 float d = (float) STBTT_sqrt(discr);
16147 s0 = (b+d) * rcpna;
16148 s1 = (b-d) * rcpna;
16149 if (s0 >= 0.0 && s0 <= 1.0)
16150 num_s = 1;
16151 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
16152 if (num_s == 0) s0 = s1;
16153 ++num_s;
16154 }
16155 }
16156 } else {
16157 /* 2*b*s + c = 0 */
16158 /* s = -c / (2*b) */
16159 s0 = c / (-2 * b);
16160 if (s0 >= 0.0 && s0 <= 1.0)
16161 num_s = 1;
16162 }
16163
16164 if (num_s == 0)
16165 return 0;
16166 else {
16167 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
16168 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
16169
16170 float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
16171 float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
16172 float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
16173 float rod = orig[0]*rayn_x + orig[1]*rayn_y;
16174
16175 float q10d = q1d - q0d;
16176 float q20d = q2d - q0d;
16177 float q0rd = q0d - rod;
16178
16179 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
16180 hits[0][1] = a*s0+b;
16181
16182 if (num_s > 1) {
16183 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
16184 hits[1][1] = a*s1+b;
16185 return 2;
16186 } else {
16187 return 1;
16188 }
16189 }
16190}
16191
16192static int equal(float *a, float *b)
16193{
16194 return (a[0] == b[0] && a[1] == b[1]);
16195}
16196
16197static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
16198{
16199 int i;
16200 float orig[2], ray[2] = { 1, 0 };
16201 float y_frac;
16202 int winding = 0;
16203
16204 /* make sure y never passes through a vertex of the shape */
16205 y_frac = (float) STBTT_fmod(y, 1.0f);
16206 if (y_frac < 0.01f)
16207 y += 0.01f;
16208 else if (y_frac > 0.99f)
16209 y -= 0.01f;
16210
16211 orig[0] = x;
16212 orig[1] = y;
16213
16214 /* test a ray from (-infinity,y) to (x,y) */
16215 for (i=0; i < nverts; ++i) {
16216 if (verts[i].type == STBTT_vline) {
16217 int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
16218 int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
16219 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
16220 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
16221 if (x_inter < x)
16222 winding += (y0 < y1) ? 1 : -1;
16223 }
16224 }
16225 if (verts[i].type == STBTT_vcurve) {
16226 int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
16227 int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy;
16228 int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ;
16229 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
16230 int by = STBTT_max(y0,STBTT_max(y1,y2));
16231 if (y > ay && y < by && x > ax) {
16232 float q0[2],q1[2],q2[2];
16233 float hits[2][2];
16234 q0[0] = (float)x0;
16235 q0[1] = (float)y0;
16236 q1[0] = (float)x1;
16237 q1[1] = (float)y1;
16238 q2[0] = (float)x2;
16239 q2[1] = (float)y2;
16240 if (equal(q0,q1) || equal(q1,q2)) {
16241 x0 = (int)verts[i-1].x;
16242 y0 = (int)verts[i-1].y;
16243 x1 = (int)verts[i ].x;
16244 y1 = (int)verts[i ].y;
16245 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
16246 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
16247 if (x_inter < x)
16248 winding += (y0 < y1) ? 1 : -1;
16249 }
16250 } else {
16251 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
16252 if (num_hits >= 1)
16253 if (hits[0][0] < 0)
16254 winding += (hits[0][1] < 0 ? -1 : 1);
16255 if (num_hits >= 2)
16256 if (hits[1][0] < 0)
16257 winding += (hits[1][1] < 0 ? -1 : 1);
16258 }
16259 }
16260 }
16261 }
16262 return winding;
16263}
16264
16265static float stbtt__cuberoot( float x )
16266{
16267 if (x<0)
16268 return -(float) STBTT_pow(-x,1.0f/3.0f);
16269 else
16270 return (float) STBTT_pow( x,1.0f/3.0f);
16271}
16272
16273/* x^3 + a*x^2 + b*x + c = 0 */
16274static int stbtt__solve_cubic(float a, float b, float c, float* r)
16275{
16276 float s = -a / 3;
16277 float p = b - a*a / 3;
16278 float q = a * (2*a*a - 9*b) / 27 + c;
16279 float p3 = p*p*p;
16280 float d = q*q + 4*p3 / 27;
16281 if (d >= 0) {
16282 float z = (float) STBTT_sqrt(d);
16283 float u = (-q + z) / 2;
16284 float v = (-q - z) / 2;
16285 u = stbtt__cuberoot(u);
16286 v = stbtt__cuberoot(v);
16287 r[0] = s + u + v;
16288 return 1;
16289 } else {
16290 float u = (float) STBTT_sqrt(-p/3);
16291 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; /* p3 must be negative, since d is negative */
16292 float m = (float) STBTT_cos(v);
16293 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
16294 r[0] = s + u * 2 * m;
16295 r[1] = s - u * (m + n);
16296 r[2] = s - u * (m - n);
16297
16298 /* STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? */
16299 /* STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); */
16300 /* STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); */
16301 return 3;
16302 }
16303}
16304
16305STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
16306{
16307 float scale_x = scale, scale_y = scale;
16308 int ix0,iy0,ix1,iy1;
16309 int w,h;
16310 unsigned char *data;
16311
16312 if (scale == 0) return NULL;
16313
16314 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
16315
16316 /* if empty, return NULL */
16317 if (ix0 == ix1 || iy0 == iy1)
16318 return NULL;
16319
16320 ix0 -= padding;
16321 iy0 -= padding;
16322 ix1 += padding;
16323 iy1 += padding;
16324
16325 w = (ix1 - ix0);
16326 h = (iy1 - iy0);
16327
16328 if (width ) *width = w;
16329 if (height) *height = h;
16330 if (xoff ) *xoff = ix0;
16331 if (yoff ) *yoff = iy0;
16332
16333 /* invert for y-downwards bitmaps */
16334 scale_y = -scale_y;
16335
16336 {
16337 int x,y,i,j;
16338 float *precompute;
16339 stbtt_vertex *verts;
16340 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
16341 data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
16342 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
16343
16344 for (i=0,j=num_verts-1; i < num_verts; j=i++) {
16345 if (verts[i].type == STBTT_vline) {
16346 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
16347 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
16348 float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
16349 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
16350 } else if (verts[i].type == STBTT_vcurve) {
16351 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
16352 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
16353 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
16354 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
16355 float len2 = bx*bx + by*by;
16356 if (len2 != 0.0f)
16357 precompute[i] = 1.0f / (bx*bx + by*by);
16358 else
16359 precompute[i] = 0.0f;
16360 } else
16361 precompute[i] = 0.0f;
16362 }
16363
16364 for (y=iy0; y < iy1; ++y) {
16365 for (x=ix0; x < ix1; ++x) {
16366 float val;
16367 float min_dist = 999999.0f;
16368 float sx = (float) x + 0.5f;
16369 float sy = (float) y + 0.5f;
16370 float x_gspace = (sx / scale_x);
16371 float y_gspace = (sy / scale_y);
16372
16373 int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); /* @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path */
16374
16375 for (i=0; i < num_verts; ++i) {
16376 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
16377
16378 if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
16379 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
16380
16381 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
16382 if (dist2 < min_dist*min_dist)
16383 min_dist = (float) STBTT_sqrt(dist2);
16384
16385 /* coarse culling against bbox */
16386 /* if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && */
16387 /* sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) */
16388 dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
16389 STBTT_assert(i != 0);
16390 if (dist < min_dist) {
16391 /* check position along line */
16392 /* x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) */
16393 /* minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) */
16394 float dx = x1-x0, dy = y1-y0;
16395 float px = x0-sx, py = y0-sy;
16396 /* minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy */
16397 /* derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve */
16398 float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
16399 if (t >= 0.0f && t <= 1.0f)
16400 min_dist = dist;
16401 }
16402 } else if (verts[i].type == STBTT_vcurve) {
16403 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
16404 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
16405 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
16406 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
16407 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
16408 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
16409 /* coarse culling against bbox to avoid computing cubic unnecessarily */
16410 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
16411 int num=0;
16412 float ax = x1-x0, ay = y1-y0;
16413 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
16414 float mx = x0 - sx, my = y0 - sy;
16415 float res[3] = {0.f,0.f,0.f};
16416 float px,py,t,it,dist2;
16417 float a_inv = precompute[i];
16418 if (a_inv == 0.0) { /* if a_inv is 0, it's 2nd degree so use quadratic formula */
16419 float a = 3*(ax*bx + ay*by);
16420 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
16421 float c = mx*ax+my*ay;
16422 if (a == 0.0) { /* if a is 0, it's linear */
16423 if (b != 0.0) {
16424 res[num++] = -c/b;
16425 }
16426 } else {
16427 float discriminant = b*b - 4*a*c;
16428 if (discriminant < 0)
16429 num = 0;
16430 else {
16431 float root = (float) STBTT_sqrt(discriminant);
16432 res[0] = (-b - root)/(2*a);
16433 res[1] = (-b + root)/(2*a);
16434 num = 2; /* don't bother distinguishing 1-solution case, as code below will still work */
16435 }
16436 }
16437 } else {
16438 float b = 3*(ax*bx + ay*by) * a_inv; /* could precompute this as it doesn't depend on sample point */
16439 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
16440 float d = (mx*ax+my*ay) * a_inv;
16441 num = stbtt__solve_cubic(b, c, d, res);
16442 }
16443 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
16444 if (dist2 < min_dist*min_dist)
16445 min_dist = (float) STBTT_sqrt(dist2);
16446
16447 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
16448 t = res[0], it = 1.0f - t;
16449 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
16450 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
16451 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
16452 if (dist2 < min_dist * min_dist)
16453 min_dist = (float) STBTT_sqrt(dist2);
16454 }
16455 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
16456 t = res[1], it = 1.0f - t;
16457 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
16458 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
16459 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
16460 if (dist2 < min_dist * min_dist)
16461 min_dist = (float) STBTT_sqrt(dist2);
16462 }
16463 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
16464 t = res[2], it = 1.0f - t;
16465 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
16466 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
16467 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
16468 if (dist2 < min_dist * min_dist)
16469 min_dist = (float) STBTT_sqrt(dist2);
16470 }
16471 }
16472 }
16473 }
16474 if (winding == 0)
16475 min_dist = -min_dist; /* if outside the shape, value is negative */
16476 val = onedge_value + pixel_dist_scale * min_dist;
16477 if (val < 0)
16478 val = 0;
16479 else if (val > 255)
16480 val = 255;
16481 data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
16482 }
16483 }
16484 STBTT_free(precompute, info->userdata);
16485 STBTT_free(verts, info->userdata);
16486 }
16487 return data;
16488}
16489
16490STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
16491{
16492 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
16493}
16494
16495STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
16496{
16497 STBTT_free(bitmap, userdata);
16498}
16499
16500/* //////////////////////////////////////////////////////////////////////////// */
16501/* */
16502/* font name matching -- recommended not to use this */
16503/* */
16504
16505/* check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string */
16506static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
16507{
16508 stbtt_int32 i=0;
16509
16510 /* convert utf16 to utf8 and compare the results while converting */
16511 while (len2) {
16512 stbtt_uint16 ch = s2[0]*256 + s2[1];
16513 if (ch < 0x80) {
16514 if (i >= len1) return -1;
16515 if (s1[i++] != ch) return -1;
16516 } else if (ch < 0x800) {
16517 if (i+1 >= len1) return -1;
16518 if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
16519 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
16520 } else if (ch >= 0xd800 && ch < 0xdc00) {
16521 stbtt_uint32 c;
16522 stbtt_uint16 ch2 = s2[2]*256 + s2[3];
16523 if (i+3 >= len1) return -1;
16524 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
16525 if (s1[i++] != 0xf0 + (c >> 18)) return -1;
16526 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
16527 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
16528 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1;
16529 s2 += 2; /* plus another 2 below */
16530 len2 -= 2;
16531 } else if (ch >= 0xdc00 && ch < 0xe000) {
16532 return -1;
16533 } else {
16534 if (i+2 >= len1) return -1;
16535 if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
16536 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
16537 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1;
16538 }
16539 s2 += 2;
16540 len2 -= 2;
16541 }
16542 return i;
16543}
16544
16545static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
16546{
16547 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
16548}
16549
16550/* returns results in whatever encoding you request... but note that 2-byte encodings */
16551/* will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare */
16552STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
16553{
16554 stbtt_int32 i,count,stringOffset;
16555 stbtt_uint8 *fc = font->data;
16556 stbtt_uint32 offset = font->fontstart;
16557 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
16558 if (!nm) return NULL;
16559
16560 count = ttUSHORT(fc+nm+2);
16561 stringOffset = nm + ttUSHORT(fc+nm+4);
16562 for (i=0; i < count; ++i) {
16563 stbtt_uint32 loc = nm + 6 + 12 * i;
16564 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
16565 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
16566 *length = ttUSHORT(fc+loc+8);
16567 return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
16568 }
16569 }
16570 return NULL;
16571}
16572
16573static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
16574{
16575 stbtt_int32 i;
16576 stbtt_int32 count = ttUSHORT(fc+nm+2);
16577 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
16578
16579 for (i=0; i < count; ++i) {
16580 stbtt_uint32 loc = nm + 6 + 12 * i;
16581 stbtt_int32 id = ttUSHORT(fc+loc+6);
16582 if (id == target_id) {
16583 /* find the encoding */
16584 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
16585
16586 /* is this a Unicode encoding? */
16587 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
16588 stbtt_int32 slen = ttUSHORT(fc+loc+8);
16589 stbtt_int32 off = ttUSHORT(fc+loc+10);
16590
16591 /* check if there's a prefix match */
16592 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
16593 if (matchlen >= 0) {
16594 /* check for target_id+1 immediately following, with same encoding & language */
16595 if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
16596 slen = ttUSHORT(fc+loc+12+8);
16597 off = ttUSHORT(fc+loc+12+10);
16598 if (slen == 0) {
16599 if (matchlen == nlen)
16600 return 1;
16601 } else if (matchlen < nlen && name[matchlen] == ' ') {
16602 ++matchlen;
16603 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
16604 return 1;
16605 }
16606 } else {
16607 /* if nothing immediately following */
16608 if (matchlen == nlen)
16609 return 1;
16610 }
16611 }
16612 }
16613
16614 /* @TODO handle other encodings */
16615 }
16616 }
16617 return 0;
16618}
16619
16620static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
16621{
16622 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
16623 stbtt_uint32 nm,hd;
16624 if (!stbtt__isfont(fc+offset)) return 0;
16625
16626 /* check italics/bold/underline flags in macStyle... */
16627 if (flags) {
16628 hd = stbtt__find_table(fc, offset, "head");
16629 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
16630 }
16631
16632 nm = stbtt__find_table(fc, offset, "name");
16633 if (!nm) return 0;
16634
16635 if (flags) {
16636 /* if we checked the macStyle flags, then just check the family and ignore the subfamily */
16637 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1;
16638 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1;
16639 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
16640 } else {
16641 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1;
16642 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1;
16643 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
16644 }
16645
16646 return 0;
16647}
16648
16649static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
16650{
16651 stbtt_int32 i;
16652 for (i=0;;++i) {
16653 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
16654 if (off < 0) return off;
16655 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
16656 return off;
16657 }
16658}
16659
16660#if defined(__GNUC__) || defined(__clang__)
16661#pragma GCC diagnostic push
16662#pragma GCC diagnostic ignored "-Wcast-qual"
16663#endif
16664
16665STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
16666 float pixel_height, unsigned char *pixels, int pw, int ph,
16667 int first_char, int num_chars, stbtt_bakedchar *chardata)
16668{
16669 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
16670}
16671
16672STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
16673{
16674 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
16675}
16676
16677STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
16678{
16679 return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
16680}
16681
16682STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
16683{
16684 return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
16685}
16686
16687STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
16688{
16689 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
16690}
16691
16692STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
16693{
16694 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
16695}
16696
16697#if defined(__GNUC__) || defined(__clang__)
16698#pragma GCC diagnostic pop
16699#endif
16700
16701#endif /* STB_TRUETYPE_IMPLEMENTATION */
16702
16703
16704/* FULL VERSION HISTORY */
16705/* */
16706/* 1.25 (2021-07-11) many fixes */
16707/* 1.24 (2020-02-05) fix warning */
16708/* 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) */
16709/* 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined */
16710/* 1.21 (2019-02-25) fix warning */
16711/* 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() */
16712/* 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod */
16713/* 1.18 (2018-01-29) add missing function */
16714/* 1.17 (2017-07-23) make more arguments const; doc fix */
16715/* 1.16 (2017-07-12) SDF support */
16716/* 1.15 (2017-03-03) make more arguments const */
16717/* 1.14 (2017-01-16) num-fonts-in-TTC function */
16718/* 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */
16719/* 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */
16720/* 1.11 (2016-04-02) fix unused-variable warning */
16721/* 1.10 (2016-04-02) allow user-defined fabs() replacement */
16722/* fix memory leak if fontsize=0.0 */
16723/* fix warning from duplicate typedef */
16724/* 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges */
16725/* 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */
16726/* 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */
16727/* allow PackFontRanges to pack and render in separate phases; */
16728/* fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */
16729/* fixed an assert() bug in the new rasterizer */
16730/* replace assert() with STBTT_assert() in new rasterizer */
16731/* 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) */
16732/* also more precise AA rasterizer, except if shapes overlap */
16733/* remove need for STBTT_sort */
16734/* 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC */
16735/* 1.04 (2015-04-15) typo in example */
16736/* 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes */
16737/* 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ */
16738/* 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match */
16739/* non-oversampled; STBTT_POINT_SIZE for packed case only */
16740/* 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling */
16741/* 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) */
16742/* 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID */
16743/* 0.8b (2014-07-07) fix a warning */
16744/* 0.8 (2014-05-25) fix a few more warnings */
16745/* 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back */
16746/* 0.6c (2012-07-24) improve documentation */
16747/* 0.6b (2012-07-20) fix a few more warnings */
16748/* 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, */
16749/* stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty */
16750/* 0.5 (2011-12-09) bugfixes: */
16751/* subpixel glyph renderer computed wrong bounding box */
16752/* first vertex of shape can be off-curve (FreeSans) */
16753/* 0.4b (2011-12-03) fixed an error in the font baking example */
16754/* 0.4 (2011-12-01) kerning, subpixel rendering (tor) */
16755/* bugfixes for: */
16756/* codepoint-to-glyph conversion using table fmt=12 */
16757/* codepoint-to-glyph conversion using table fmt=4 */
16758/* stbtt_GetBakedQuad with non-square texture (Zer) */
16759/* updated Hello World! sample to use kerning and subpixel */
16760/* fixed some warnings */
16761/* 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) */
16762/* userdata, malloc-from-userdata, non-zero fill (stb) */
16763/* 0.2 (2009-03-11) Fix unsigned/signed char warnings */
16764/* 0.1 (2009-03-09) First public release */
16765/* */
16766
16767/*
16768------------------------------------------------------------------------------
16769This software is available under 2 licenses -- choose whichever you prefer.
16770------------------------------------------------------------------------------
16771ALTERNATIVE A - MIT License
16772Copyright (c) 2017 Sean Barrett
16773Permission is hereby granted, free of charge, to any person obtaining a copy of
16774this software and associated documentation files (the "Software"), to deal in
16775the Software without restriction, including without limitation the rights to
16776use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16777of the Software, and to permit persons to whom the Software is furnished to do
16778so, subject to the following conditions:
16779The above copyright notice and this permission notice shall be included in all
16780copies or substantial portions of the Software.
16781THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16782IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16783FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16784AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16785LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16786OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16787SOFTWARE.
16788------------------------------------------------------------------------------
16789ALTERNATIVE B - Public Domain (www.unlicense.org)
16790This is free and unencumbered software released into the public domain.
16791Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
16792software, either in source code form or as a compiled binary, for any purpose,
16793commercial or non-commercial, and by any means.
16794In jurisdictions that recognize copyright laws, the author or authors of this
16795software dedicate any and all copyright interest in the software to the public
16796domain. We make this dedication for the benefit of the public at large and to
16797the detriment of our heirs and successors. We intend this dedication to be an
16798overt act of relinquishment in perpetuity of all present and future rights to
16799this software under copyright law.
16800THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16801IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16802FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16803AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16804ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
16805WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16806------------------------------------------------------------------------------
16807*/
16808
16809
16810
16811
16812#ifdef NK_INCLUDE_FONT_BAKING
16813/* -------------------------------------------------------------
16814 *
16815 * RECT PACK
16816 *
16817 * --------------------------------------------------------------*/
16818
16819
16820
16821/*
16822 * ==============================================================
16823 *
16824 * TRUETYPE
16825 *
16826 * ===============================================================
16827 */
16828#define STBTT_MAX_OVERSAMPLE 8
16829
16830
16831/* -------------------------------------------------------------
16832 *
16833 * FONT BAKING
16834 *
16835 * --------------------------------------------------------------*/
16836struct nk_font_bake_data {
16837 struct stbtt_fontinfo info;
16838 struct stbrp_rect *rects;
16839 stbtt_pack_range *ranges;
16840 nk_rune range_count;
16841};
16842
16843struct nk_font_baker {
16844 struct nk_allocator alloc;
16845 struct stbtt_pack_context spc;
16846 struct nk_font_bake_data *build;
16847 stbtt_packedchar *packed_chars;
16848 struct stbrp_rect *rects;
16849 stbtt_pack_range *ranges;
16850};
16851
16852NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct stbrp_rect);
16853NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(stbtt_pack_range);
16854NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(stbtt_packedchar);
16855NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data);
16856NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker);
16857
16858NK_INTERN int
16859nk_range_count(const nk_rune *range)
16860{
16861 const nk_rune *iter = range;
16862 NK_ASSERT(range);
16863 if (!range) return 0;
16864 while (*(iter++) != 0);
16865 return (iter == range) ? 0 : (int)((iter - range)/2);
16866}
16867NK_INTERN int
16868nk_range_glyph_count(const nk_rune *range, int count)
16869{
16870 int i = 0;
16871 int total_glyphs = 0;
16872 for (i = 0; i < count; ++i) {
16873 int diff;
16874 nk_rune f = range[(i*2)+0];
16875 nk_rune t = range[(i*2)+1];
16876 NK_ASSERT(t >= f);
16877 diff = (int)((t - f) + 1);
16878 total_glyphs += diff;
16879 }
16880 return total_glyphs;
16881}
16882NK_API const nk_rune*
16883nk_font_default_glyph_ranges(void)
16884{
16885 NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0};
16886 return ranges;
16887}
16888NK_API const nk_rune*
16889nk_font_chinese_glyph_ranges(void)
16890{
16891 NK_STORAGE const nk_rune ranges[] = {
16892 0x0020, 0x00FF,
16893 0x3000, 0x30FF,
16894 0x31F0, 0x31FF,
16895 0xFF00, 0xFFEF,
16896 0x4E00, 0x9FAF,
16897 0
16898 };
16899 return ranges;
16900}
16901NK_API const nk_rune*
16902nk_font_cyrillic_glyph_ranges(void)
16903{
16904 NK_STORAGE const nk_rune ranges[] = {
16905 0x0020, 0x00FF,
16906 0x0400, 0x052F,
16907 0x2DE0, 0x2DFF,
16908 0xA640, 0xA69F,
16909 0
16910 };
16911 return ranges;
16912}
16913NK_API const nk_rune*
16914nk_font_korean_glyph_ranges(void)
16915{
16916 NK_STORAGE const nk_rune ranges[] = {
16917 0x0020, 0x00FF,
16918 0x3131, 0x3163,
16919 0xAC00, 0xD79D,
16920 0
16921 };
16922 return ranges;
16923}
16924NK_INTERN void
16925nk_font_baker_memory(nk_size *temp, int *glyph_count,
16926 struct nk_font_config *config_list, int count)
16927{
16928 int range_count = 0;
16929 int total_range_count = 0;
16930 struct nk_font_config *iter, *i;
16931
16932 NK_ASSERT(config_list);
16933 NK_ASSERT(glyph_count);
16934 if (!config_list) {
16935 *temp = 0;
16936 *glyph_count = 0;
16937 return;
16938 }
16939 *glyph_count = 0;
16940 for (iter = config_list; iter; iter = iter->next) {
16941 i = iter;
16942 do {if (!i->range) iter->range = nk_font_default_glyph_ranges();
16943 range_count = nk_range_count(i->range);
16944 total_range_count += range_count;
16945 *glyph_count += nk_range_glyph_count(i->range, range_count);
16946 } while ((i = i->n) != iter);
16947 }
16948 *temp = (nk_size)*glyph_count * sizeof(struct stbrp_rect);
16949 *temp += (nk_size)total_range_count * sizeof(stbtt_pack_range);
16950 *temp += (nk_size)*glyph_count * sizeof(stbtt_packedchar);
16951 *temp += (nk_size)count * sizeof(struct nk_font_bake_data);
16952 *temp += sizeof(struct nk_font_baker);
16953 *temp += nk_rect_align + nk_range_align + nk_char_align;
16954 *temp += nk_build_align + nk_baker_align;
16955}
16956NK_INTERN struct nk_font_baker*
16957nk_font_baker(void *memory, int glyph_count, int count, const struct nk_allocator *alloc)
16958{
16959 struct nk_font_baker *baker;
16960 if (!memory) return 0;
16961 /* setup baker inside a memory block */
16962 baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align);
16963 baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align);
16964 baker->packed_chars = (stbtt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align);
16965 baker->rects = (struct stbrp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align);
16966 baker->ranges = (stbtt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align);
16967 baker->alloc = *alloc;
16968 return baker;
16969}
16970NK_INTERN int
16971nk_font_bake_pack(struct nk_font_baker *baker,
16972 nk_size *image_memory, int *width, int *height, struct nk_recti *custom,
16973 const struct nk_font_config *config_list, int count,
16974 const struct nk_allocator *alloc)
16975{
16976 NK_STORAGE const nk_size max_height = 1024 * 32;
16977 const struct nk_font_config *config_iter, *it;
16978 int total_glyph_count = 0;
16979 int total_range_count = 0;
16980 int range_count = 0;
16981 int i = 0;
16982
16983 NK_ASSERT(image_memory);
16984 NK_ASSERT(width);
16985 NK_ASSERT(height);
16986 NK_ASSERT(config_list);
16987 NK_ASSERT(count);
16988 NK_ASSERT(alloc);
16989
16990 if (!image_memory || !width || !height || !config_list || !count) return nk_false;
16991 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
16992 it = config_iter;
16993 do {range_count = nk_range_count(it->range);
16994 total_range_count += range_count;
16995 total_glyph_count += nk_range_glyph_count(it->range, range_count);
16996 } while ((it = it->n) != config_iter);
16997 }
16998 /* setup font baker from temporary memory */
16999 for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
17000 it = config_iter;
17001 do {
17002 struct stbtt_fontinfo *font_info = &baker->build[i++].info;
17003 font_info->userdata = (void*)alloc;
17004
17005 if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, stbtt_GetFontOffsetForIndex((const unsigned char*)it->ttf_blob, 0)))
17006 return nk_false;
17007 } while ((it = it->n) != config_iter);
17008 }
17009 *height = 0;
17010 *width = (total_glyph_count > 1000) ? 1024 : 512;
17011 stbtt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, (void*)alloc);
17012 {
17013 int input_i = 0;
17014 int range_n = 0;
17015 int rect_n = 0;
17016 int char_n = 0;
17017
17018 if (custom) {
17019 /* pack custom user data first so it will be in the upper left corner*/
17020 struct stbrp_rect custom_space;
17021 nk_zero(&custom_space, sizeof(custom_space));
17022 custom_space.w = (stbrp_coord)(custom->w);
17023 custom_space.h = (stbrp_coord)(custom->h);
17024
17025 stbtt_PackSetOversampling(&baker->spc, 1, 1);
17026 stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, &custom_space, 1);
17027 *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h));
17028
17029 custom->x = (short)custom_space.x;
17030 custom->y = (short)custom_space.y;
17031 custom->w = (short)custom_space.w;
17032 custom->h = (short)custom_space.h;
17033 }
17034
17035 /* first font pass: pack all glyphs */
17036 for (input_i = 0, config_iter = config_list; input_i < count && config_iter;
17037 config_iter = config_iter->next) {
17038 it = config_iter;
17039 do {int n = 0;
17040 int glyph_count;
17041 const nk_rune *in_range;
17042 const struct nk_font_config *cfg = it;
17043 struct nk_font_bake_data *tmp = &baker->build[input_i++];
17044
17045 /* count glyphs + ranges in current font */
17046 glyph_count = 0; range_count = 0;
17047 for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) {
17048 glyph_count += (int)(in_range[1] - in_range[0]) + 1;
17049 range_count++;
17050 }
17051
17052 /* setup ranges */
17053 tmp->ranges = baker->ranges + range_n;
17054 tmp->range_count = (nk_rune)range_count;
17055 range_n += range_count;
17056 for (i = 0; i < range_count; ++i) {
17057 in_range = &cfg->range[i * 2];
17058 tmp->ranges[i].font_size = cfg->size;
17059 tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0];
17060 tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1;
17061 tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n;
17062 char_n += tmp->ranges[i].num_chars;
17063 }
17064
17065 /* pack */
17066 tmp->rects = baker->rects + rect_n;
17067 rect_n += glyph_count;
17068 stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
17069 n = stbtt_PackFontRangesGatherRects(&baker->spc, &tmp->info,
17070 tmp->ranges, (int)tmp->range_count, tmp->rects);
17071 stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, tmp->rects, (int)n);
17072
17073 /* texture height */
17074 for (i = 0; i < n; ++i) {
17075 if (tmp->rects[i].was_packed)
17076 *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h);
17077 }
17078 } while ((it = it->n) != config_iter);
17079 }
17080 NK_ASSERT(rect_n == total_glyph_count);
17081 NK_ASSERT(char_n == total_glyph_count);
17082 NK_ASSERT(range_n == total_range_count);
17083 }
17084 *height = (int)nk_round_up_pow2((nk_uint)*height);
17085 *image_memory = (nk_size)(*width) * (nk_size)(*height);
17086 return nk_true;
17087}
17088NK_INTERN void
17089nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height,
17090 struct nk_font_glyph *glyphs, int glyphs_count,
17091 const struct nk_font_config *config_list, int font_count)
17092{
17093 int input_i = 0;
17094 nk_rune glyph_n = 0;
17095 const struct nk_font_config *config_iter;
17096 const struct nk_font_config *it;
17097
17098 NK_ASSERT(image_memory);
17099 NK_ASSERT(width);
17100 NK_ASSERT(height);
17101 NK_ASSERT(config_list);
17102 NK_ASSERT(baker);
17103 NK_ASSERT(font_count);
17104 NK_ASSERT(glyphs_count);
17105 if (!image_memory || !width || !height || !config_list ||
17106 !font_count || !glyphs || !glyphs_count)
17107 return;
17108
17109 /* second font pass: render glyphs */
17110 nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height));
17111 baker->spc.pixels = (unsigned char*)image_memory;
17112 baker->spc.height = (int)height;
17113 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
17114 config_iter = config_iter->next) {
17115 it = config_iter;
17116 do {const struct nk_font_config *cfg = it;
17117 struct nk_font_bake_data *tmp = &baker->build[input_i++];
17118 stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);
17119 stbtt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, (int)tmp->range_count, tmp->rects);
17120 } while ((it = it->n) != config_iter);
17121 } stbtt_PackEnd(&baker->spc);
17122
17123 /* third pass: setup font and glyphs */
17124 for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;
17125 config_iter = config_iter->next) {
17126 it = config_iter;
17127 do {nk_size i = 0;
17128 int char_idx = 0;
17129 nk_rune glyph_count = 0;
17130 const struct nk_font_config *cfg = it;
17131 struct nk_font_bake_data *tmp = &baker->build[input_i++];
17132 struct nk_baked_font *dst_font = cfg->font;
17133
17134 float font_scale = stbtt_ScaleForPixelHeight(&tmp->info, cfg->size);
17135 int unscaled_ascent, unscaled_descent, unscaled_line_gap;
17136 stbtt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent,
17137 &unscaled_line_gap);
17138
17139 /* fill baked font */
17140 if (!cfg->merge_mode) {
17141 dst_font->ranges = cfg->range;
17142 dst_font->height = cfg->size;
17143 dst_font->ascent = ((float)unscaled_ascent * font_scale);
17144 dst_font->descent = ((float)unscaled_descent * font_scale);
17145 dst_font->glyph_offset = glyph_n;
17146 /*
17147 Need to zero this, or it will carry over from a previous
17148 bake, and cause a segfault when accessing glyphs[].
17149 */
17150 dst_font->glyph_count = 0;
17151 }
17152
17153 /* fill own baked font glyph array */
17154 for (i = 0; i < tmp->range_count; ++i) {
17155 stbtt_pack_range *range = &tmp->ranges[i];
17156 for (char_idx = 0; char_idx < range->num_chars; char_idx++)
17157 {
17158 nk_rune codepoint = 0;
17159 float dummy_x = 0, dummy_y = 0;
17160 stbtt_aligned_quad q;
17161 struct nk_font_glyph *glyph;
17162
17163 /* query glyph bounds from stb_truetype */
17164 const stbtt_packedchar *pc = &range->chardata_for_range[char_idx];
17165 codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx);
17166 stbtt_GetPackedQuad(range->chardata_for_range, (int)width,
17167 (int)height, char_idx, &dummy_x, &dummy_y, &q, 0);
17168
17169 /* fill own glyph type with data */
17170 glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count];
17171 glyph->codepoint = codepoint;
17172 glyph->x0 = q.x0; glyph->y0 = q.y0;
17173 glyph->x1 = q.x1; glyph->y1 = q.y1;
17174 glyph->y0 += (dst_font->ascent + 0.5f);
17175 glyph->y1 += (dst_font->ascent + 0.5f);
17176 glyph->w = glyph->x1 - glyph->x0 + 0.5f;
17177 glyph->h = glyph->y1 - glyph->y0;
17178
17179 if (cfg->coord_type == NK_COORD_PIXEL) {
17180 glyph->u0 = q.s0 * (float)width;
17181 glyph->v0 = q.t0 * (float)height;
17182 glyph->u1 = q.s1 * (float)width;
17183 glyph->v1 = q.t1 * (float)height;
17184 } else {
17185 glyph->u0 = q.s0;
17186 glyph->v0 = q.t0;
17187 glyph->u1 = q.s1;
17188 glyph->v1 = q.t1;
17189 }
17190 glyph->xadvance = (pc->xadvance + cfg->spacing.x);
17191 if (cfg->pixel_snap)
17192 glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f);
17193 glyph_count++;
17194 }
17195 }
17196 dst_font->glyph_count += glyph_count;
17197 glyph_n += glyph_count;
17198 } while ((it = it->n) != config_iter);
17199 }
17200}
17201NK_INTERN void
17202nk_font_bake_custom_data(void *img_memory, int img_width, int img_height,
17203 struct nk_recti img_dst, const char *texture_data_mask, int tex_width,
17204 int tex_height, char white, char black)
17205{
17206 nk_byte *pixels;
17207 int y = 0;
17208 int x = 0;
17209 int n = 0;
17210
17211 NK_ASSERT(img_memory);
17212 NK_ASSERT(img_width);
17213 NK_ASSERT(img_height);
17214 NK_ASSERT(texture_data_mask);
17215 NK_UNUSED(tex_height);
17216 if (!img_memory || !img_width || !img_height || !texture_data_mask)
17217 return;
17218
17219 pixels = (nk_byte*)img_memory;
17220 for (y = 0, n = 0; y < tex_height; ++y) {
17221 for (x = 0; x < tex_width; ++x, ++n) {
17222 const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width);
17223 const int off1 = off0 + 1 + tex_width;
17224 pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00;
17225 pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00;
17226 }
17227 }
17228}
17229NK_INTERN void
17230nk_font_bake_convert(void *out_memory, int img_width, int img_height,
17231 const void *in_memory)
17232{
17233 int n = 0;
17234 nk_rune *dst;
17235 const nk_byte *src;
17236
17237 NK_ASSERT(out_memory);
17238 NK_ASSERT(in_memory);
17239 NK_ASSERT(img_width);
17240 NK_ASSERT(img_height);
17241 if (!out_memory || !in_memory || !img_height || !img_width) return;
17242
17243 dst = (nk_rune*)out_memory;
17244 src = (const nk_byte*)in_memory;
17245 for (n = (int)(img_width * img_height); n > 0; n--)
17246 *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF;
17247}
17248
17249/* -------------------------------------------------------------
17250 *
17251 * FONT
17252 *
17253 * --------------------------------------------------------------*/
17254NK_INTERN float
17255nk_font_text_width(nk_handle handle, float height, const char *text, int len)
17256{
17257 nk_rune unicode;
17258 int text_len = 0;
17259 float text_width = 0;
17260 int glyph_len = 0;
17261 float scale = 0;
17262
17263 struct nk_font *font = (struct nk_font*)handle.ptr;
17264 NK_ASSERT(font);
17265 NK_ASSERT(font->glyphs);
17266 if (!font || !text || !len)
17267 return 0;
17268
17269 scale = height/font->info.height;
17270 glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len);
17271 if (!glyph_len) return 0;
17272 while (text_len <= (int)len && glyph_len) {
17273 const struct nk_font_glyph *g;
17274 if (unicode == NK_UTF_INVALID) break;
17275
17276 /* query currently drawn glyph information */
17277 g = nk_font_find_glyph(font, unicode);
17278 text_width += g->xadvance * scale;
17279
17280 /* offset next glyph */
17281 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len);
17282 text_len += glyph_len;
17283 }
17284 return text_width;
17285}
17286#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
17287NK_INTERN void
17288nk_font_query_font_glyph(nk_handle handle, float height,
17289 struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
17290{
17291 float scale;
17292 const struct nk_font_glyph *g;
17293 struct nk_font *font;
17294
17295 NK_ASSERT(glyph);
17296 NK_UNUSED(next_codepoint);
17297
17298 font = (struct nk_font*)handle.ptr;
17299 NK_ASSERT(font);
17300 NK_ASSERT(font->glyphs);
17301 if (!font || !glyph)
17302 return;
17303
17304 scale = height/font->info.height;
17305 g = nk_font_find_glyph(font, codepoint);
17306 glyph->width = (g->x1 - g->x0) * scale;
17307 glyph->height = (g->y1 - g->y0) * scale;
17308 glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);
17309 glyph->xadvance = (g->xadvance * scale);
17310 glyph->uv[0] = nk_vec2(g->u0, g->v0);
17311 glyph->uv[1] = nk_vec2(g->u1, g->v1);
17312}
17313#endif
17314NK_API const struct nk_font_glyph*
17315nk_font_find_glyph(const struct nk_font *font, nk_rune unicode)
17316{
17317 int i = 0;
17318 int count;
17319 int total_glyphs = 0;
17320 const struct nk_font_glyph *glyph = 0;
17321 const struct nk_font_config *iter = 0;
17322
17323 NK_ASSERT(font);
17324 NK_ASSERT(font->glyphs);
17325 NK_ASSERT(font->info.ranges);
17326 if (!font || !font->glyphs) return 0;
17327
17328 glyph = font->fallback;
17329 iter = font->config;
17330 do {count = nk_range_count(iter->range);
17331 for (i = 0; i < count; ++i) {
17332 nk_rune f = iter->range[(i*2)+0];
17333 nk_rune t = iter->range[(i*2)+1];
17334 int diff = (int)((t - f) + 1);
17335 if (unicode >= f && unicode <= t)
17336 return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))];
17337 total_glyphs += diff;
17338 }
17339 } while ((iter = iter->n) != font->config);
17340 return glyph;
17341}
17342NK_INTERN void
17343nk_font_init(struct nk_font *font, float pixel_height,
17344 nk_rune fallback_codepoint, struct nk_font_glyph *glyphs,
17345 const struct nk_baked_font *baked_font, nk_handle atlas)
17346{
17347 struct nk_baked_font baked;
17348 NK_ASSERT(font);
17349 NK_ASSERT(glyphs);
17350 NK_ASSERT(baked_font);
17351 if (!font || !glyphs || !baked_font)
17352 return;
17353
17354 baked = *baked_font;
17355 font->fallback = 0;
17356 font->info = baked;
17357 font->scale = (float)pixel_height / (float)font->info.height;
17358 font->glyphs = &glyphs[baked_font->glyph_offset];
17359 font->texture = atlas;
17360 font->fallback_codepoint = fallback_codepoint;
17361 font->fallback = nk_font_find_glyph(font, fallback_codepoint);
17362
17363 font->handle.height = font->info.height * font->scale;
17364 font->handle.width = nk_font_text_width;
17365 font->handle.userdata.ptr = font;
17366#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
17367 font->handle.query = nk_font_query_font_glyph;
17368 font->handle.texture = font->texture;
17369#endif
17370}
17371
17372/* ---------------------------------------------------------------------------
17373 *
17374 * DEFAULT FONT
17375 *
17376 * ProggyClean.ttf
17377 * Copyright (c) 2004, 2005 Tristan Grimmer
17378 * MIT license https://github.com/bluescan/proggyfonts/blob/master/LICENSE
17379 * Download and more information at https://github.com/bluescan/proggyfonts
17380 *-----------------------------------------------------------------------------*/
17381#ifdef __clang__
17382#pragma clang diagnostic push
17383#pragma clang diagnostic ignored "-Woverlength-strings"
17384#elif defined(__GNUC__) || defined(__GNUG__)
17385#pragma GCC diagnostic push
17386#pragma GCC diagnostic ignored "-Woverlength-strings"
17387#endif
17388
17389#ifdef NK_INCLUDE_DEFAULT_FONT
17390
17391NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] =
17392 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
17393 "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#"
17394 "`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"
17395 "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"
17396 "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"
17397 "*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)"
17398 "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"
17399 "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."
17400 "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"
17401 "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(,)"
17402 "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#"
17403 "'/###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"
17404 "_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"
17405 "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/"
17406 "/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"
17407 "%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&#"
17408 "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)("
17409 "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"
17410 "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"
17411 "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^-"
17412 "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-"
17413 "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"
17414 "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%"
17415 "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]"
17416 "%(?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"
17417 "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:"
17418 "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("
17419 "$/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<"
17420 "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'?"
17421 "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/;"
17422 ")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"
17423 "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("
17424 "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"
17425 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
17426 "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<-"
17427 "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"
17428 "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"
17429 ".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@@"
17430 "$&)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*"
17431 "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"
17432 "@-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&#"
17433 "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#"
17434 "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"
17435 "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"
17436 "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&#"
17437 "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"
17438 ":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+"
17439 "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*"
17440 "$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"
17441 ":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"
17442 "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"
17443 "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"
17444 "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"
17445 ":^#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@&]>"
17446 "_>@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%"
17447 "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;"
17448 "^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:"
17449 "+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%"
17450 "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-"
17451 "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*"
17452 "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"
17453 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
17454 "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`"
17455 "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]%/"
17456 "+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"
17457 "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"
17458 "?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"
17459 "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"
17460 ">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'>"
17461 "[%$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"
17462 "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#"
17463 "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$"
17464 "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,)"
17465 "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"
17466 "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"
17467 "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"
17468 "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(#"
17469 ";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&>"
17470 "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#"
17471 "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"
17472 "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#"
17473 "/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-#"
17474 "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#"
17475 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
17476 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
17477 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
17478
17479#endif /* NK_INCLUDE_DEFAULT_FONT */
17480
17481#define NK_CURSOR_DATA_W 90
17482#define NK_CURSOR_DATA_H 27
17483NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] =
17484{
17485 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
17486 "..- -X.....X- X.X - X.X -X.....X - X.....X"
17487 "--- -XXX.XXX- X...X - X...X -X....X - X....X"
17488 "X - X.X - X.....X - X.....X -X...X - X...X"
17489 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
17490 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
17491 "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
17492 "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
17493 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
17494 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
17495 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
17496 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
17497 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
17498 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
17499 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
17500 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
17501 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
17502 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
17503 "X.X X..X - -X.......X- X.......X - XX XX - "
17504 "XX X..X - - X.....X - X.....X - X.X X.X - "
17505 " X..X - X...X - X...X - X..X X..X - "
17506 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
17507 "------------ - X - X -X.....................X- "
17508 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
17509 " - X..X X..X - "
17510 " - X.X X.X - "
17511 " - XX XX - "
17512};
17513
17514#ifdef __clang__
17515#pragma clang diagnostic pop
17516#elif defined(__GNUC__) || defined(__GNUG__)
17517#pragma GCC diagnostic pop
17518#endif
17519
17520NK_GLOBAL unsigned char *nk__barrier;
17521NK_GLOBAL unsigned char *nk__barrier2;
17522NK_GLOBAL unsigned char *nk__barrier3;
17523NK_GLOBAL unsigned char *nk__barrier4;
17524NK_GLOBAL unsigned char *nk__dout;
17525
17526NK_INTERN unsigned int
17527nk_decompress_length(unsigned char *input)
17528{
17529 return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]);
17530}
17531NK_INTERN void
17532nk__match(unsigned char *data, unsigned int length)
17533{
17534 /* INVERSE of memmove... write each byte before copying the next...*/
17535 NK_ASSERT (nk__dout + length <= nk__barrier);
17536 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
17537 if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; }
17538 while (length--) *nk__dout++ = *data++;
17539}
17540NK_INTERN void
17541nk__lit(unsigned char *data, unsigned int length)
17542{
17543 NK_ASSERT (nk__dout + length <= nk__barrier);
17544 if (nk__dout + length > nk__barrier) { nk__dout += length; return; }
17545 if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; }
17546 NK_MEMCPY(nk__dout, data, length);
17547 nk__dout += length;
17548}
17549NK_INTERN unsigned char*
17550nk_decompress_token(unsigned char *i)
17551{
17552 #define nk__in2(x) ((i[x] << 8) + i[(x)+1])
17553 #define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1))
17554 #define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1))
17555
17556 if (*i >= 0x20) { /* use fewer if's for cases that expand small */
17557 if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2;
17558 else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3;
17559 else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
17560 } else { /* more ifs for cases that expand large, since overhead is amortized */
17561 if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4;
17562 else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5;
17563 else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1);
17564 else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1);
17565 else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5;
17566 else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6;
17567 }
17568 return i;
17569}
17570NK_INTERN unsigned int
17571nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
17572{
17573 const unsigned long ADLER_MOD = 65521;
17574 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
17575 unsigned long blocklen, i;
17576
17577 blocklen = buflen % 5552;
17578 while (buflen) {
17579 for (i=0; i + 7 < blocklen; i += 8) {
17580 s1 += buffer[0]; s2 += s1;
17581 s1 += buffer[1]; s2 += s1;
17582 s1 += buffer[2]; s2 += s1;
17583 s1 += buffer[3]; s2 += s1;
17584 s1 += buffer[4]; s2 += s1;
17585 s1 += buffer[5]; s2 += s1;
17586 s1 += buffer[6]; s2 += s1;
17587 s1 += buffer[7]; s2 += s1;
17588 buffer += 8;
17589 }
17590 for (; i < blocklen; ++i) {
17591 s1 += *buffer++; s2 += s1;
17592 }
17593
17594 s1 %= ADLER_MOD; s2 %= ADLER_MOD;
17595 buflen -= (unsigned int)blocklen;
17596 blocklen = 5552;
17597 }
17598 return (unsigned int)(s2 << 16) + (unsigned int)s1;
17599}
17600NK_INTERN unsigned int
17601nk_decompress(unsigned char *output, unsigned char *i, unsigned int length)
17602{
17603 unsigned int olen;
17604 if (nk__in4(0) != 0x57bC0000) return 0;
17605 if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */
17606 olen = nk_decompress_length(i);
17607 nk__barrier2 = i;
17608 nk__barrier3 = i+length;
17609 nk__barrier = output + olen;
17610 nk__barrier4 = output;
17611 i += 16;
17612
17613 nk__dout = output;
17614 for (;;) {
17615 unsigned char *old_i = i;
17616 i = nk_decompress_token(i);
17617 if (i == old_i) {
17618 if (*i == 0x05 && i[1] == 0xfa) {
17619 NK_ASSERT(nk__dout == output + olen);
17620 if (nk__dout != output + olen) return 0;
17621 if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2))
17622 return 0;
17623 return olen;
17624 } else {
17625 NK_ASSERT(0); /* NOTREACHED */
17626 return 0;
17627 }
17628 }
17629 NK_ASSERT(nk__dout <= output + olen);
17630 if (nk__dout > output + olen)
17631 return 0;
17632 }
17633}
17634NK_INTERN unsigned int
17635nk_decode_85_byte(char c)
17636{
17637 return (unsigned int)((c >= '\\') ? c-36 : c-35);
17638}
17639NK_INTERN void
17640nk_decode_85(unsigned char* dst, const unsigned char* src)
17641{
17642 while (*src)
17643 {
17644 unsigned int tmp =
17645 nk_decode_85_byte((char)src[0]) +
17646 85 * (nk_decode_85_byte((char)src[1]) +
17647 85 * (nk_decode_85_byte((char)src[2]) +
17648 85 * (nk_decode_85_byte((char)src[3]) +
17649 85 * nk_decode_85_byte((char)src[4]))));
17650
17651 /* we can't assume little-endianess. */
17652 dst[0] = (unsigned char)((tmp >> 0) & 0xFF);
17653 dst[1] = (unsigned char)((tmp >> 8) & 0xFF);
17654 dst[2] = (unsigned char)((tmp >> 16) & 0xFF);
17655 dst[3] = (unsigned char)((tmp >> 24) & 0xFF);
17656
17657 src += 5;
17658 dst += 4;
17659 }
17660}
17661
17662/* -------------------------------------------------------------
17663 *
17664 * FONT ATLAS
17665 *
17666 * --------------------------------------------------------------*/
17667NK_API struct nk_font_config
17668nk_font_config(float pixel_height)
17669{
17670 struct nk_font_config cfg;
17671 nk_zero_struct(cfg);
17672 cfg.ttf_blob = 0;
17673 cfg.ttf_size = 0;
17674 cfg.ttf_data_owned_by_atlas = 0;
17675 cfg.size = pixel_height;
17676 cfg.oversample_h = 3;
17677 cfg.oversample_v = 1;
17678 cfg.pixel_snap = 0;
17679 cfg.coord_type = NK_COORD_UV;
17680 cfg.spacing = nk_vec2(0,0);
17681 cfg.range = nk_font_default_glyph_ranges();
17682 cfg.merge_mode = 0;
17683 cfg.fallback_glyph = '?';
17684 cfg.font = 0;
17685 cfg.n = 0;
17686 return cfg;
17687}
17688#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
17689NK_API void
17690nk_font_atlas_init_default(struct nk_font_atlas *atlas)
17691{
17692 NK_ASSERT(atlas);
17693 if (!atlas) return;
17694 nk_zero_struct(*atlas);
17695 atlas->temporary.userdata.ptr = 0;
17696 atlas->temporary.alloc = nk_malloc;
17697 atlas->temporary.free = nk_mfree;
17698 atlas->permanent.userdata.ptr = 0;
17699 atlas->permanent.alloc = nk_malloc;
17700 atlas->permanent.free = nk_mfree;
17701}
17702#endif
17703NK_API void
17704nk_font_atlas_init(struct nk_font_atlas *atlas, const struct nk_allocator *alloc)
17705{
17706 NK_ASSERT(atlas);
17707 NK_ASSERT(alloc);
17708 if (!atlas || !alloc) return;
17709 nk_zero_struct(*atlas);
17710 atlas->permanent = *alloc;
17711 atlas->temporary = *alloc;
17712}
17713NK_API void
17714nk_font_atlas_init_custom(struct nk_font_atlas *atlas,
17715 const struct nk_allocator *permanent, const struct nk_allocator *temporary)
17716{
17717 NK_ASSERT(atlas);
17718 NK_ASSERT(permanent);
17719 NK_ASSERT(temporary);
17720 if (!atlas || !permanent || !temporary) return;
17721 nk_zero_struct(*atlas);
17722 atlas->permanent = *permanent;
17723 atlas->temporary = *temporary;
17724}
17725NK_API void
17726nk_font_atlas_begin(struct nk_font_atlas *atlas)
17727{
17728 NK_ASSERT(atlas);
17729 NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free);
17730 NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free);
17731 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free ||
17732 !atlas->temporary.alloc || !atlas->temporary.free) return;
17733 if (atlas->glyphs) {
17734 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
17735 atlas->glyphs = 0;
17736 }
17737 if (atlas->pixel) {
17738 atlas->permanent.free(atlas->permanent.userdata, atlas->pixel);
17739 atlas->pixel = 0;
17740 }
17741}
17742NK_API struct nk_font*
17743nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config)
17744{
17745 struct nk_font *font = 0;
17746 struct nk_font_config *cfg;
17747
17748 NK_ASSERT(atlas);
17749 NK_ASSERT(atlas->permanent.alloc);
17750 NK_ASSERT(atlas->permanent.free);
17751 NK_ASSERT(atlas->temporary.alloc);
17752 NK_ASSERT(atlas->temporary.free);
17753
17754 NK_ASSERT(config);
17755 NK_ASSERT(config->ttf_blob);
17756 NK_ASSERT(config->ttf_size);
17757 NK_ASSERT(config->size > 0.0f);
17758
17759 if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f||
17760 !atlas->permanent.alloc || !atlas->permanent.free ||
17761 !atlas->temporary.alloc || !atlas->temporary.free)
17762 return 0;
17763
17764 /* allocate font config */
17765 cfg = (struct nk_font_config*)
17766 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config));
17767 NK_MEMCPY(cfg, config, sizeof(*config));
17768 cfg->n = cfg;
17769 cfg->p = cfg;
17770
17771 if (!config->merge_mode) {
17772 /* insert font config into list */
17773 if (!atlas->config) {
17774 atlas->config = cfg;
17775 cfg->next = 0;
17776 } else {
17777 struct nk_font_config *i = atlas->config;
17778 while (i->next) i = i->next;
17779 i->next = cfg;
17780 cfg->next = 0;
17781 }
17782 /* allocate new font */
17783 font = (struct nk_font*)
17784 atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font));
17785 NK_ASSERT(font);
17786 nk_zero(font, sizeof(*font));
17787 if (!font) return 0;
17788 font->config = cfg;
17789
17790 /* insert font into list */
17791 if (!atlas->fonts) {
17792 atlas->fonts = font;
17793 font->next = 0;
17794 } else {
17795 struct nk_font *i = atlas->fonts;
17796 while (i->next) i = i->next;
17797 i->next = font;
17798 font->next = 0;
17799 }
17800 cfg->font = &font->info;
17801 } else {
17802 /* extend previously added font */
17803 struct nk_font *f = 0;
17804 struct nk_font_config *c = 0;
17805 NK_ASSERT(atlas->font_num);
17806 f = atlas->fonts;
17807 c = f->config;
17808 cfg->font = &f->info;
17809
17810 cfg->n = c;
17811 cfg->p = c->p;
17812 c->p->n = cfg;
17813 c->p = cfg;
17814 }
17815 /* create own copy of .TTF font blob */
17816 if (!config->ttf_data_owned_by_atlas) {
17817 cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size);
17818 NK_ASSERT(cfg->ttf_blob);
17819 if (!cfg->ttf_blob) {
17820 atlas->font_num++;
17821 return 0;
17822 }
17823 NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size);
17824 cfg->ttf_data_owned_by_atlas = 1;
17825 }
17826 atlas->font_num++;
17827 return font;
17828}
17829NK_API struct nk_font*
17830nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory,
17831 nk_size size, float height, const struct nk_font_config *config)
17832{
17833 struct nk_font_config cfg;
17834 NK_ASSERT(memory);
17835 NK_ASSERT(size);
17836
17837 NK_ASSERT(atlas);
17838 NK_ASSERT(atlas->temporary.alloc);
17839 NK_ASSERT(atlas->temporary.free);
17840 NK_ASSERT(atlas->permanent.alloc);
17841 NK_ASSERT(atlas->permanent.free);
17842 if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size ||
17843 !atlas->permanent.alloc || !atlas->permanent.free)
17844 return 0;
17845
17846 cfg = (config) ? *config: nk_font_config(height);
17847 cfg.ttf_blob = memory;
17848 cfg.ttf_size = size;
17849 cfg.size = height;
17850 cfg.ttf_data_owned_by_atlas = 0;
17851 return nk_font_atlas_add(atlas, &cfg);
17852}
17853#ifdef NK_INCLUDE_STANDARD_IO
17854NK_API struct nk_font*
17855nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path,
17856 float height, const struct nk_font_config *config)
17857{
17858 nk_size size;
17859 char *memory;
17860 struct nk_font_config cfg;
17861
17862 NK_ASSERT(atlas);
17863 NK_ASSERT(atlas->temporary.alloc);
17864 NK_ASSERT(atlas->temporary.free);
17865 NK_ASSERT(atlas->permanent.alloc);
17866 NK_ASSERT(atlas->permanent.free);
17867
17868 if (!atlas || !file_path) return 0;
17869 memory = nk_file_load(file_path, &size, &atlas->permanent);
17870 if (!memory) return 0;
17871
17872 cfg = (config) ? *config: nk_font_config(height);
17873 cfg.ttf_blob = memory;
17874 cfg.ttf_size = size;
17875 cfg.size = height;
17876 cfg.ttf_data_owned_by_atlas = 1;
17877 return nk_font_atlas_add(atlas, &cfg);
17878}
17879#endif
17880NK_API struct nk_font*
17881nk_font_atlas_add_compressed(struct nk_font_atlas *atlas,
17882 void *compressed_data, nk_size compressed_size, float height,
17883 const struct nk_font_config *config)
17884{
17885 unsigned int decompressed_size;
17886 void *decompressed_data;
17887 struct nk_font_config cfg;
17888
17889 NK_ASSERT(atlas);
17890 NK_ASSERT(atlas->temporary.alloc);
17891 NK_ASSERT(atlas->temporary.free);
17892 NK_ASSERT(atlas->permanent.alloc);
17893 NK_ASSERT(atlas->permanent.free);
17894
17895 NK_ASSERT(compressed_data);
17896 NK_ASSERT(compressed_size);
17897 if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free ||
17898 !atlas->permanent.alloc || !atlas->permanent.free)
17899 return 0;
17900
17901 decompressed_size = nk_decompress_length((unsigned char*)compressed_data);
17902 decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size);
17903 NK_ASSERT(decompressed_data);
17904 if (!decompressed_data) return 0;
17905 nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data,
17906 (unsigned int)compressed_size);
17907
17908 cfg = (config) ? *config: nk_font_config(height);
17909 cfg.ttf_blob = decompressed_data;
17910 cfg.ttf_size = decompressed_size;
17911 cfg.size = height;
17912 cfg.ttf_data_owned_by_atlas = 1;
17913 return nk_font_atlas_add(atlas, &cfg);
17914}
17915NK_API struct nk_font*
17916nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas,
17917 const char *data_base85, float height, const struct nk_font_config *config)
17918{
17919 int compressed_size;
17920 void *compressed_data;
17921 struct nk_font *font;
17922
17923 NK_ASSERT(atlas);
17924 NK_ASSERT(atlas->temporary.alloc);
17925 NK_ASSERT(atlas->temporary.free);
17926 NK_ASSERT(atlas->permanent.alloc);
17927 NK_ASSERT(atlas->permanent.free);
17928
17929 NK_ASSERT(data_base85);
17930 if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free ||
17931 !atlas->permanent.alloc || !atlas->permanent.free)
17932 return 0;
17933
17934 compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4;
17935 compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size);
17936 NK_ASSERT(compressed_data);
17937 if (!compressed_data) return 0;
17938 nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85);
17939 font = nk_font_atlas_add_compressed(atlas, compressed_data,
17940 (nk_size)compressed_size, height, config);
17941 atlas->temporary.free(atlas->temporary.userdata, compressed_data);
17942 return font;
17943}
17944
17945#ifdef NK_INCLUDE_DEFAULT_FONT
17946NK_API struct nk_font*
17947nk_font_atlas_add_default(struct nk_font_atlas *atlas,
17948 float pixel_height, const struct nk_font_config *config)
17949{
17950 NK_ASSERT(atlas);
17951 NK_ASSERT(atlas->temporary.alloc);
17952 NK_ASSERT(atlas->temporary.free);
17953 NK_ASSERT(atlas->permanent.alloc);
17954 NK_ASSERT(atlas->permanent.free);
17955 return nk_font_atlas_add_compressed_base85(atlas,
17956 nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config);
17957}
17958#endif
17959NK_API const void*
17960nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height,
17961 enum nk_font_atlas_format fmt)
17962{
17963 int i = 0;
17964 void *tmp = 0;
17965 nk_size tmp_size, img_size;
17966 struct nk_font *font_iter;
17967 struct nk_font_baker *baker;
17968
17969 NK_ASSERT(atlas);
17970 NK_ASSERT(atlas->temporary.alloc);
17971 NK_ASSERT(atlas->temporary.free);
17972 NK_ASSERT(atlas->permanent.alloc);
17973 NK_ASSERT(atlas->permanent.free);
17974
17975 NK_ASSERT(width);
17976 NK_ASSERT(height);
17977 if (!atlas || !width || !height ||
17978 !atlas->temporary.alloc || !atlas->temporary.free ||
17979 !atlas->permanent.alloc || !atlas->permanent.free)
17980 return 0;
17981
17982#ifdef NK_INCLUDE_DEFAULT_FONT
17983 /* no font added so just use default font */
17984 if (!atlas->font_num)
17985 atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0);
17986#endif
17987 NK_ASSERT(atlas->font_num);
17988 if (!atlas->font_num) return 0;
17989
17990 /* allocate temporary baker memory required for the baking process */
17991 nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num);
17992 tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size);
17993 NK_ASSERT(tmp);
17994 if (!tmp) goto failed;
17995 NK_MEMSET(tmp,0,tmp_size);
17996
17997 /* allocate glyph memory for all fonts */
17998 baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary);
17999 atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc(
18000 atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count);
18001 NK_ASSERT(atlas->glyphs);
18002 if (!atlas->glyphs)
18003 goto failed;
18004
18005 /* pack all glyphs into a tight fit space */
18006 atlas->custom.w = (NK_CURSOR_DATA_W*2)+1;
18007 atlas->custom.h = NK_CURSOR_DATA_H + 1;
18008 if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom,
18009 atlas->config, atlas->font_num, &atlas->temporary))
18010 goto failed;
18011
18012 /* allocate memory for the baked image font atlas */
18013 atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size);
18014 NK_ASSERT(atlas->pixel);
18015 if (!atlas->pixel)
18016 goto failed;
18017
18018 /* bake glyphs and custom white pixel into image */
18019 nk_font_bake(baker, atlas->pixel, *width, *height,
18020 atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num);
18021 nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom,
18022 nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X');
18023
18024 if (fmt == NK_FONT_ATLAS_RGBA32) {
18025 /* convert alpha8 image into rgba32 image */
18026 void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0,
18027 (nk_size)(*width * *height * 4));
18028 NK_ASSERT(img_rgba);
18029 if (!img_rgba) goto failed;
18030 nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel);
18031 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
18032 atlas->pixel = img_rgba;
18033 }
18034 atlas->tex_width = *width;
18035 atlas->tex_height = *height;
18036
18037 /* initialize each font */
18038 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
18039 struct nk_font *font = font_iter;
18040 struct nk_font_config *config = font->config;
18041 nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs,
18042 config->font, nk_handle_ptr(0));
18043 }
18044
18045 /* initialize each cursor */
18046 {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = {
18047 /* Pos Size Offset */
18048 {{ 0, 3}, {12,19}, { 0, 0}},
18049 {{13, 0}, { 7,16}, { 4, 8}},
18050 {{31, 0}, {23,23}, {11,11}},
18051 {{21, 0}, { 9, 23}, { 5,11}},
18052 {{55,18}, {23, 9}, {11, 5}},
18053 {{73, 0}, {17,17}, { 9, 9}},
18054 {{55, 0}, {17,17}, { 9, 9}}
18055 };
18056 for (i = 0; i < NK_CURSOR_COUNT; ++i) {
18057 struct nk_cursor *cursor = &atlas->cursors[i];
18058 cursor->img.w = (unsigned short)*width;
18059 cursor->img.h = (unsigned short)*height;
18060 cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x);
18061 cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y);
18062 cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x;
18063 cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y;
18064 cursor->size = nk_cursor_data[i][1];
18065 cursor->offset = nk_cursor_data[i][2];
18066 }}
18067 /* free temporary memory */
18068 atlas->temporary.free(atlas->temporary.userdata, tmp);
18069 return atlas->pixel;
18070
18071failed:
18072 /* error so cleanup all memory */
18073 if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp);
18074 if (atlas->glyphs) {
18075 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
18076 atlas->glyphs = 0;
18077 }
18078 if (atlas->pixel) {
18079 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
18080 atlas->pixel = 0;
18081 }
18082 return 0;
18083}
18084NK_API void
18085nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,
18086 struct nk_draw_null_texture *tex_null)
18087{
18088 int i = 0;
18089 struct nk_font *font_iter;
18090 NK_ASSERT(atlas);
18091 if (!atlas) {
18092 if (!tex_null) return;
18093 tex_null->texture = texture;
18094 tex_null->uv = nk_vec2(0.5f,0.5f);
18095 }
18096 if (tex_null) {
18097 tex_null->texture = texture;
18098 tex_null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;
18099 tex_null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;
18100 }
18101 for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
18102 font_iter->texture = texture;
18103#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
18104 font_iter->handle.texture = texture;
18105#endif
18106 }
18107 for (i = 0; i < NK_CURSOR_COUNT; ++i)
18108 atlas->cursors[i].img.handle = texture;
18109
18110 atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);
18111 atlas->pixel = 0;
18112 atlas->tex_width = 0;
18113 atlas->tex_height = 0;
18114 atlas->custom.x = 0;
18115 atlas->custom.y = 0;
18116 atlas->custom.w = 0;
18117 atlas->custom.h = 0;
18118}
18119NK_API void
18120nk_font_atlas_cleanup(struct nk_font_atlas *atlas)
18121{
18122 NK_ASSERT(atlas);
18123 NK_ASSERT(atlas->temporary.alloc);
18124 NK_ASSERT(atlas->temporary.free);
18125 NK_ASSERT(atlas->permanent.alloc);
18126 NK_ASSERT(atlas->permanent.free);
18127 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
18128 if (atlas->config) {
18129 struct nk_font_config *iter;
18130 for (iter = atlas->config; iter; iter = iter->next) {
18131 struct nk_font_config *i;
18132 for (i = iter->n; i != iter; i = i->n) {
18133 atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);
18134 i->ttf_blob = 0;
18135 }
18136 atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);
18137 iter->ttf_blob = 0;
18138 }
18139 }
18140}
18141NK_API void
18142nk_font_atlas_clear(struct nk_font_atlas *atlas)
18143{
18144 NK_ASSERT(atlas);
18145 NK_ASSERT(atlas->temporary.alloc);
18146 NK_ASSERT(atlas->temporary.free);
18147 NK_ASSERT(atlas->permanent.alloc);
18148 NK_ASSERT(atlas->permanent.free);
18149 if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;
18150
18151 if (atlas->config) {
18152 struct nk_font_config *iter, *next;
18153 for (iter = atlas->config; iter; iter = next) {
18154 struct nk_font_config *i, *n;
18155 for (i = iter->n; i != iter; i = n) {
18156 n = i->n;
18157 if (i->ttf_blob)
18158 atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);
18159 atlas->permanent.free(atlas->permanent.userdata, i);
18160 }
18161 next = iter->next;
18162 if (i->ttf_blob)
18163 atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);
18164 atlas->permanent.free(atlas->permanent.userdata, iter);
18165 }
18166 atlas->config = 0;
18167 }
18168 if (atlas->fonts) {
18169 struct nk_font *iter, *next;
18170 for (iter = atlas->fonts; iter; iter = next) {
18171 next = iter->next;
18172 atlas->permanent.free(atlas->permanent.userdata, iter);
18173 }
18174 atlas->fonts = 0;
18175 }
18176 if (atlas->glyphs)
18177 atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);
18178 nk_zero_struct(*atlas);
18179}
18180#endif
18181
18182
18183
18184
18185/* ===============================================================
18186 *
18187 * INPUT
18188 *
18189 * ===============================================================*/
18190NK_API void
18191nk_input_begin(struct nk_context *ctx)
18192{
18193 int i;
18194 struct nk_input *in;
18195 NK_ASSERT(ctx);
18196 if (!ctx) return;
18197 in = &ctx->input;
18198 for (i = 0; i < NK_BUTTON_MAX; ++i)
18199 in->mouse.buttons[i].clicked = 0;
18200
18201 in->keyboard.text_len = 0;
18202 in->mouse.scroll_delta = nk_vec2(0,0);
18203 in->mouse.prev.x = in->mouse.pos.x;
18204 in->mouse.prev.y = in->mouse.pos.y;
18205 in->mouse.delta.x = 0;
18206 in->mouse.delta.y = 0;
18207 for (i = 0; i < NK_KEY_MAX; i++)
18208 in->keyboard.keys[i].clicked = 0;
18209}
18210NK_API void
18211nk_input_end(struct nk_context *ctx)
18212{
18213 struct nk_input *in;
18214 NK_ASSERT(ctx);
18215 if (!ctx) return;
18216 in = &ctx->input;
18217 if (in->mouse.grab)
18218 in->mouse.grab = 0;
18219 if (in->mouse.ungrab) {
18220 in->mouse.grabbed = 0;
18221 in->mouse.ungrab = 0;
18222 in->mouse.grab = 0;
18223 }
18224}
18225NK_API void
18226nk_input_motion(struct nk_context *ctx, int x, int y)
18227{
18228 struct nk_input *in;
18229 NK_ASSERT(ctx);
18230 if (!ctx) return;
18231 in = &ctx->input;
18232 in->mouse.pos.x = (float)x;
18233 in->mouse.pos.y = (float)y;
18234 in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;
18235 in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;
18236}
18237NK_API void
18238nk_input_key(struct nk_context *ctx, enum nk_keys key, nk_bool down)
18239{
18240 struct nk_input *in;
18241 NK_ASSERT(ctx);
18242 if (!ctx) return;
18243 in = &ctx->input;
18244#ifdef NK_KEYSTATE_BASED_INPUT
18245 if (in->keyboard.keys[key].down != down)
18246 in->keyboard.keys[key].clicked++;
18247#else
18248 in->keyboard.keys[key].clicked++;
18249#endif
18250 in->keyboard.keys[key].down = down;
18251}
18252NK_API void
18253nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, nk_bool down)
18254{
18255 struct nk_mouse_button *btn;
18256 struct nk_input *in;
18257 NK_ASSERT(ctx);
18258 if (!ctx) return;
18259 in = &ctx->input;
18260 if (in->mouse.buttons[id].down == down) return;
18261
18262 btn = &in->mouse.buttons[id];
18263 btn->clicked_pos.x = (float)x;
18264 btn->clicked_pos.y = (float)y;
18265 btn->down = down;
18266 btn->clicked++;
18267
18268 /* Fix Click-Drag for touch events. */
18269 in->mouse.delta.x = 0;
18270 in->mouse.delta.y = 0;
18271#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
18272 if (down == 1 && id == NK_BUTTON_LEFT)
18273 {
18274 in->mouse.down_pos.x = btn->clicked_pos.x;
18275 in->mouse.down_pos.y = btn->clicked_pos.y;
18276 }
18277#endif
18278}
18279NK_API void
18280nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)
18281{
18282 NK_ASSERT(ctx);
18283 if (!ctx) return;
18284 ctx->input.mouse.scroll_delta.x += val.x;
18285 ctx->input.mouse.scroll_delta.y += val.y;
18286}
18287NK_API void
18288nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)
18289{
18290 int len = 0;
18291 nk_rune unicode;
18292 struct nk_input *in;
18293
18294 NK_ASSERT(ctx);
18295 if (!ctx) return;
18296 in = &ctx->input;
18297
18298 len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);
18299 if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {
18300 nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],
18301 NK_INPUT_MAX - in->keyboard.text_len);
18302 in->keyboard.text_len += len;
18303 }
18304}
18305NK_API void
18306nk_input_char(struct nk_context *ctx, char c)
18307{
18308 nk_glyph glyph = {0};
18309 NK_ASSERT(ctx);
18310 if (!ctx) return;
18311 glyph[0] = c;
18312 nk_input_glyph(ctx, glyph);
18313}
18314NK_API void
18315nk_input_unicode(struct nk_context *ctx, nk_rune unicode)
18316{
18317 nk_glyph rune;
18318 NK_ASSERT(ctx);
18319 if (!ctx) return;
18320 nk_utf_encode(unicode, rune, NK_UTF_SIZE);
18321 nk_input_glyph(ctx, rune);
18322}
18323NK_API nk_bool
18324nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)
18325{
18326 const struct nk_mouse_button *btn;
18327 if (!i) return nk_false;
18328 btn = &i->mouse.buttons[id];
18329 return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;
18330}
18331NK_API nk_bool
18332nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
18333 struct nk_rect b)
18334{
18335 const struct nk_mouse_button *btn;
18336 if (!i) return nk_false;
18337 btn = &i->mouse.buttons[id];
18338 if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
18339 return nk_false;
18340 return nk_true;
18341}
18342NK_API nk_bool
18343nk_input_has_mouse_click_in_button_rect(const struct nk_input *i, enum nk_buttons id,
18344 struct nk_rect b)
18345{
18346 const struct nk_mouse_button *btn;
18347 if (!i) return nk_false;
18348 btn = &i->mouse.buttons[id];
18349#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
18350 if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)
18351 || !NK_INBOX(i->mouse.down_pos.x,i->mouse.down_pos.y,b.x,b.y,b.w,b.h))
18352#else
18353 if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
18354#endif
18355 return nk_false;
18356 return nk_true;
18357}
18358NK_API nk_bool
18359nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
18360 struct nk_rect b, nk_bool down)
18361{
18362 const struct nk_mouse_button *btn;
18363 if (!i) return nk_false;
18364 btn = &i->mouse.buttons[id];
18365 return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);
18366}
18367NK_API nk_bool
18368nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,
18369 struct nk_rect b)
18370{
18371 const struct nk_mouse_button *btn;
18372 if (!i) return nk_false;
18373 btn = &i->mouse.buttons[id];
18374 return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&
18375 btn->clicked) ? nk_true : nk_false;
18376}
18377NK_API nk_bool
18378nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
18379 struct nk_rect b, nk_bool down)
18380{
18381 const struct nk_mouse_button *btn;
18382 if (!i) return nk_false;
18383 btn = &i->mouse.buttons[id];
18384 return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&
18385 btn->clicked) ? nk_true : nk_false;
18386}
18387NK_API nk_bool
18388nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)
18389{
18390 int i, down = 0;
18391 for (i = 0; i < NK_BUTTON_MAX; ++i)
18392 down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);
18393 return down;
18394}
18395NK_API nk_bool
18396nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)
18397{
18398 if (!i) return nk_false;
18399 return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);
18400}
18401NK_API nk_bool
18402nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)
18403{
18404 if (!i) return nk_false;
18405 return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);
18406}
18407NK_API nk_bool
18408nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)
18409{
18410 if (!i) return nk_false;
18411 if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;
18412 return nk_input_is_mouse_click_in_rect(i, id, rect);
18413}
18414NK_API nk_bool
18415nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)
18416{
18417 if (!i) return nk_false;
18418 return i->mouse.buttons[id].down;
18419}
18420NK_API nk_bool
18421nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)
18422{
18423 const struct nk_mouse_button *b;
18424 if (!i) return nk_false;
18425 b = &i->mouse.buttons[id];
18426 if (b->down && b->clicked)
18427 return nk_true;
18428 return nk_false;
18429}
18430NK_API nk_bool
18431nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)
18432{
18433 if (!i) return nk_false;
18434 return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);
18435}
18436NK_API nk_bool
18437nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)
18438{
18439 const struct nk_key *k;
18440 if (!i) return nk_false;
18441 k = &i->keyboard.keys[key];
18442 if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))
18443 return nk_true;
18444 return nk_false;
18445}
18446NK_API nk_bool
18447nk_input_is_key_released(const struct nk_input *i, enum nk_keys key)
18448{
18449 const struct nk_key *k;
18450 if (!i) return nk_false;
18451 k = &i->keyboard.keys[key];
18452 if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))
18453 return nk_true;
18454 return nk_false;
18455}
18456NK_API nk_bool
18457nk_input_is_key_down(const struct nk_input *i, enum nk_keys key)
18458{
18459 const struct nk_key *k;
18460 if (!i) return nk_false;
18461 k = &i->keyboard.keys[key];
18462 if (k->down) return nk_true;
18463 return nk_false;
18464}
18465
18466
18467
18468
18469
18470/* ===============================================================
18471 *
18472 * STYLE
18473 *
18474 * ===============================================================*/
18475NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}
18476#define NK_COLOR_MAP(NK_COLOR)\
18477 NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \
18478 NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \
18479 NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \
18480 NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \
18481 NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \
18482 NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \
18483 NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \
18484 NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \
18485 NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \
18486 NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \
18487 NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \
18488 NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \
18489 NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \
18490 NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \
18491 NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \
18492 NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \
18493 NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \
18494 NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \
18495 NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \
18496 NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \
18497 NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \
18498 NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \
18499 NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT, 255, 0, 0, 255) \
18500 NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \
18501 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \
18502 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER, 120,120,120,255) \
18503 NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, 150,150,150,255) \
18504 NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255) \
18505 NK_COLOR(NK_COLOR_KNOB, 38, 38, 38, 255) \
18506 NK_COLOR(NK_COLOR_KNOB_CURSOR, 100,100,100,255) \
18507 NK_COLOR(NK_COLOR_KNOB_CURSOR_HOVER, 120,120,120,255) \
18508 NK_COLOR(NK_COLOR_KNOB_CURSOR_ACTIVE, 150,150,150,255)
18509
18510NK_GLOBAL const struct nk_color
18511nk_default_color_style[NK_COLOR_COUNT] = {
18512#define NK_COLOR(a,b,c,d,e) {b,c,d,e},
18513 NK_COLOR_MAP(NK_COLOR)
18514#undef NK_COLOR
18515};
18516NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {
18517#define NK_COLOR(a,b,c,d,e) #a,
18518 NK_COLOR_MAP(NK_COLOR)
18519#undef NK_COLOR
18520};
18521
18522NK_API const char*
18523nk_style_get_color_by_name(enum nk_style_colors c)
18524{
18525 return nk_color_names[c];
18526}
18527NK_API struct nk_style_item
18528nk_style_item_color(struct nk_color col)
18529{
18530 struct nk_style_item i;
18531 i.type = NK_STYLE_ITEM_COLOR;
18532 i.data.color = col;
18533 return i;
18534}
18535NK_API struct nk_style_item
18536nk_style_item_image(struct nk_image img)
18537{
18538 struct nk_style_item i;
18539 i.type = NK_STYLE_ITEM_IMAGE;
18540 i.data.image = img;
18541 return i;
18542}
18543NK_API struct nk_style_item
18544nk_style_item_nine_slice(struct nk_nine_slice slice)
18545{
18546 struct nk_style_item i;
18547 i.type = NK_STYLE_ITEM_NINE_SLICE;
18548 i.data.slice = slice;
18549 return i;
18550}
18551NK_API struct nk_style_item
18552nk_style_item_hide(void)
18553{
18554 struct nk_style_item i;
18555 i.type = NK_STYLE_ITEM_COLOR;
18556 i.data.color = nk_rgba(0,0,0,0);
18557 return i;
18558}
18559NK_API void
18560nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
18561{
18562 struct nk_style *style;
18563 struct nk_style_text *text;
18564 struct nk_style_button *button;
18565 struct nk_style_toggle *toggle;
18566 struct nk_style_selectable *select;
18567 struct nk_style_slider *slider;
18568 struct nk_style_knob *knob;
18569 struct nk_style_progress *prog;
18570 struct nk_style_scrollbar *scroll;
18571 struct nk_style_edit *edit;
18572 struct nk_style_property *property;
18573 struct nk_style_combo *combo;
18574 struct nk_style_chart *chart;
18575 struct nk_style_tab *tab;
18576 struct nk_style_window *win;
18577
18578 NK_ASSERT(ctx);
18579 if (!ctx) return;
18580 style = &ctx->style;
18581 table = (!table) ? nk_default_color_style: table;
18582
18583 /* default text */
18584 text = &style->text;
18585 text->color = table[NK_COLOR_TEXT];
18586 text->padding = nk_vec2(0,0);
18587 text->color_factor = 1.0f;
18588 text->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18589
18590 /* default button */
18591 button = &style->button;
18592 nk_zero_struct(*button);
18593 button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]);
18594 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
18595 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
18596 button->border_color = table[NK_COLOR_BORDER];
18597 button->text_background = table[NK_COLOR_BUTTON];
18598 button->text_normal = table[NK_COLOR_TEXT];
18599 button->text_hover = table[NK_COLOR_TEXT];
18600 button->text_active = table[NK_COLOR_TEXT];
18601 button->padding = nk_vec2(2.0f,2.0f);
18602 button->image_padding = nk_vec2(0.0f,0.0f);
18603 button->touch_padding = nk_vec2(0.0f, 0.0f);
18604 button->userdata = nk_handle_ptr(0);
18605 button->text_alignment = NK_TEXT_CENTERED;
18606 button->border = 1.0f;
18607 button->rounding = 4.0f;
18608 button->color_factor_text = 1.0f;
18609 button->color_factor_background = 1.0f;
18610 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18611 button->draw_begin = 0;
18612 button->draw_end = 0;
18613
18614 /* contextual button */
18615 button = &style->contextual_button;
18616 nk_zero_struct(*button);
18617 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
18618 button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);
18619 button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);
18620 button->border_color = table[NK_COLOR_WINDOW];
18621 button->text_background = table[NK_COLOR_WINDOW];
18622 button->text_normal = table[NK_COLOR_TEXT];
18623 button->text_hover = table[NK_COLOR_TEXT];
18624 button->text_active = table[NK_COLOR_TEXT];
18625 button->padding = nk_vec2(2.0f,2.0f);
18626 button->touch_padding = nk_vec2(0.0f,0.0f);
18627 button->userdata = nk_handle_ptr(0);
18628 button->text_alignment = NK_TEXT_CENTERED;
18629 button->border = 0.0f;
18630 button->rounding = 0.0f;
18631 button->color_factor_text = 1.0f;
18632 button->color_factor_background = 1.0f;
18633 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18634 button->draw_begin = 0;
18635 button->draw_end = 0;
18636
18637 /* menu button */
18638 button = &style->menu_button;
18639 nk_zero_struct(*button);
18640 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
18641 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
18642 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
18643 button->border_color = table[NK_COLOR_WINDOW];
18644 button->text_background = table[NK_COLOR_WINDOW];
18645 button->text_normal = table[NK_COLOR_TEXT];
18646 button->text_hover = table[NK_COLOR_TEXT];
18647 button->text_active = table[NK_COLOR_TEXT];
18648 button->padding = nk_vec2(2.0f,2.0f);
18649 button->touch_padding = nk_vec2(0.0f,0.0f);
18650 button->userdata = nk_handle_ptr(0);
18651 button->text_alignment = NK_TEXT_CENTERED;
18652 button->border = 0.0f;
18653 button->rounding = 1.0f;
18654 button->color_factor_text = 1.0f;
18655 button->color_factor_background = 1.0f;
18656 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18657 button->draw_begin = 0;
18658 button->draw_end = 0;
18659
18660 /* checkbox toggle */
18661 toggle = &style->checkbox;
18662 nk_zero_struct(*toggle);
18663 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
18664 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
18665 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
18666 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
18667 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
18668 toggle->userdata = nk_handle_ptr(0);
18669 toggle->text_background = table[NK_COLOR_WINDOW];
18670 toggle->text_normal = table[NK_COLOR_TEXT];
18671 toggle->text_hover = table[NK_COLOR_TEXT];
18672 toggle->text_active = table[NK_COLOR_TEXT];
18673 toggle->padding = nk_vec2(2.0f, 2.0f);
18674 toggle->touch_padding = nk_vec2(0,0);
18675 toggle->border_color = nk_rgba(0,0,0,0);
18676 toggle->border = 0.0f;
18677 toggle->spacing = 4;
18678 toggle->color_factor = 1.0f;
18679 toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18680
18681 /* option toggle */
18682 toggle = &style->option;
18683 nk_zero_struct(*toggle);
18684 toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]);
18685 toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
18686 toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);
18687 toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
18688 toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);
18689 toggle->userdata = nk_handle_ptr(0);
18690 toggle->text_background = table[NK_COLOR_WINDOW];
18691 toggle->text_normal = table[NK_COLOR_TEXT];
18692 toggle->text_hover = table[NK_COLOR_TEXT];
18693 toggle->text_active = table[NK_COLOR_TEXT];
18694 toggle->padding = nk_vec2(3.0f, 3.0f);
18695 toggle->touch_padding = nk_vec2(0,0);
18696 toggle->border_color = nk_rgba(0,0,0,0);
18697 toggle->border = 0.0f;
18698 toggle->spacing = 4;
18699 toggle->color_factor = 1.0f;
18700 toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18701
18702 /* selectable */
18703 select = &style->selectable;
18704 nk_zero_struct(*select);
18705 select->normal = nk_style_item_color(table[NK_COLOR_SELECT]);
18706 select->hover = nk_style_item_color(table[NK_COLOR_SELECT]);
18707 select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]);
18708 select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
18709 select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
18710 select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);
18711 select->text_normal = table[NK_COLOR_TEXT];
18712 select->text_hover = table[NK_COLOR_TEXT];
18713 select->text_pressed = table[NK_COLOR_TEXT];
18714 select->text_normal_active = table[NK_COLOR_TEXT];
18715 select->text_hover_active = table[NK_COLOR_TEXT];
18716 select->text_pressed_active = table[NK_COLOR_TEXT];
18717 select->padding = nk_vec2(2.0f,2.0f);
18718 select->image_padding = nk_vec2(2.0f,2.0f);
18719 select->touch_padding = nk_vec2(0,0);
18720 select->userdata = nk_handle_ptr(0);
18721 select->rounding = 0.0f;
18722 select->color_factor = 1.0f;
18723 select->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18724 select->draw_begin = 0;
18725 select->draw_end = 0;
18726
18727 /* slider */
18728 slider = &style->slider;
18729 nk_zero_struct(*slider);
18730 slider->normal = nk_style_item_hide();
18731 slider->hover = nk_style_item_hide();
18732 slider->active = nk_style_item_hide();
18733 slider->bar_normal = table[NK_COLOR_SLIDER];
18734 slider->bar_hover = table[NK_COLOR_SLIDER];
18735 slider->bar_active = table[NK_COLOR_SLIDER];
18736 slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR];
18737 slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
18738 slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
18739 slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
18740 slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT;
18741 slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT;
18742 slider->cursor_size = nk_vec2(16,16);
18743 slider->padding = nk_vec2(2,2);
18744 slider->spacing = nk_vec2(2,2);
18745 slider->userdata = nk_handle_ptr(0);
18746 slider->show_buttons = nk_false;
18747 slider->bar_height = 8;
18748 slider->rounding = 0;
18749 slider->color_factor = 1.0f;
18750 slider->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18751 slider->draw_begin = 0;
18752 slider->draw_end = 0;
18753
18754 /* slider buttons */
18755 button = &style->slider.inc_button;
18756 button->normal = nk_style_item_color(nk_rgb(40,40,40));
18757 button->hover = nk_style_item_color(nk_rgb(42,42,42));
18758 button->active = nk_style_item_color(nk_rgb(44,44,44));
18759 button->border_color = nk_rgb(65,65,65);
18760 button->text_background = nk_rgb(40,40,40);
18761 button->text_normal = nk_rgb(175,175,175);
18762 button->text_hover = nk_rgb(175,175,175);
18763 button->text_active = nk_rgb(175,175,175);
18764 button->padding = nk_vec2(8.0f,8.0f);
18765 button->touch_padding = nk_vec2(0.0f,0.0f);
18766 button->userdata = nk_handle_ptr(0);
18767 button->text_alignment = NK_TEXT_CENTERED;
18768 button->border = 1.0f;
18769 button->rounding = 0.0f;
18770 button->color_factor_text = 1.0f;
18771 button->color_factor_background = 1.0f;
18772 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18773 button->draw_begin = 0;
18774 button->draw_end = 0;
18775 style->slider.dec_button = style->slider.inc_button;
18776
18777 /* knob */
18778 knob = &style->knob;
18779 nk_zero_struct(*knob);
18780 knob->normal = nk_style_item_hide();
18781 knob->hover = nk_style_item_hide();
18782 knob->active = nk_style_item_hide();
18783 knob->knob_normal = table[NK_COLOR_KNOB];
18784 knob->knob_hover = table[NK_COLOR_KNOB];
18785 knob->knob_active = table[NK_COLOR_KNOB];
18786 knob->cursor_normal = table[NK_COLOR_KNOB_CURSOR];
18787 knob->cursor_hover = table[NK_COLOR_KNOB_CURSOR_HOVER];
18788 knob->cursor_active = table[NK_COLOR_KNOB_CURSOR_ACTIVE];
18789
18790 knob->knob_border_color = table[NK_COLOR_BORDER];
18791 knob->knob_border = 1.0f;
18792
18793 knob->padding = nk_vec2(2,2);
18794 knob->spacing = nk_vec2(2,2);
18795 knob->cursor_width = 2;
18796 knob->color_factor = 1.0f;
18797 knob->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18798
18799 knob->userdata = nk_handle_ptr(0);
18800 knob->draw_begin = 0;
18801 knob->draw_end = 0;
18802
18803 /* progressbar */
18804 prog = &style->progress;
18805 nk_zero_struct(*prog);
18806 prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]);
18807 prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]);
18808 prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]);
18809 prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);
18810 prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);
18811 prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);
18812 prog->border_color = nk_rgba(0,0,0,0);
18813 prog->cursor_border_color = nk_rgba(0,0,0,0);
18814 prog->userdata = nk_handle_ptr(0);
18815 prog->padding = nk_vec2(4,4);
18816 prog->rounding = 0;
18817 prog->border = 0;
18818 prog->cursor_rounding = 0;
18819 prog->cursor_border = 0;
18820 prog->color_factor = 1.0f;
18821 prog->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18822 prog->draw_begin = 0;
18823 prog->draw_end = 0;
18824
18825 /* scrollbars */
18826 scroll = &style->scrollh;
18827 nk_zero_struct(*scroll);
18828 scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
18829 scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
18830 scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);
18831 scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);
18832 scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);
18833 scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);
18834 scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID;
18835 scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID;
18836 scroll->userdata = nk_handle_ptr(0);
18837 scroll->border_color = table[NK_COLOR_SCROLLBAR];
18838 scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];
18839 scroll->padding = nk_vec2(0,0);
18840 scroll->show_buttons = nk_false;
18841 scroll->border = 0;
18842 scroll->rounding = 0;
18843 scroll->border_cursor = 0;
18844 scroll->rounding_cursor = 0;
18845 scroll->color_factor = 1.0f;
18846 scroll->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18847 scroll->draw_begin = 0;
18848 scroll->draw_end = 0;
18849 style->scrollv = style->scrollh;
18850
18851 /* scrollbars buttons */
18852 button = &style->scrollh.inc_button;
18853 button->normal = nk_style_item_color(nk_rgb(40,40,40));
18854 button->hover = nk_style_item_color(nk_rgb(42,42,42));
18855 button->active = nk_style_item_color(nk_rgb(44,44,44));
18856 button->border_color = nk_rgb(65,65,65);
18857 button->text_background = nk_rgb(40,40,40);
18858 button->text_normal = nk_rgb(175,175,175);
18859 button->text_hover = nk_rgb(175,175,175);
18860 button->text_active = nk_rgb(175,175,175);
18861 button->padding = nk_vec2(4.0f,4.0f);
18862 button->touch_padding = nk_vec2(0.0f,0.0f);
18863 button->userdata = nk_handle_ptr(0);
18864 button->text_alignment = NK_TEXT_CENTERED;
18865 button->border = 1.0f;
18866 button->rounding = 0.0f;
18867 button->color_factor_text = 1.0f;
18868 button->color_factor_background = 1.0f;
18869 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18870 button->draw_begin = 0;
18871 button->draw_end = 0;
18872 style->scrollh.dec_button = style->scrollh.inc_button;
18873 style->scrollv.inc_button = style->scrollh.inc_button;
18874 style->scrollv.dec_button = style->scrollh.inc_button;
18875
18876 /* edit */
18877 edit = &style->edit;
18878 nk_zero_struct(*edit);
18879 edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]);
18880 edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]);
18881 edit->active = nk_style_item_color(table[NK_COLOR_EDIT]);
18882 edit->cursor_normal = table[NK_COLOR_TEXT];
18883 edit->cursor_hover = table[NK_COLOR_TEXT];
18884 edit->cursor_text_normal= table[NK_COLOR_EDIT];
18885 edit->cursor_text_hover = table[NK_COLOR_EDIT];
18886 edit->border_color = table[NK_COLOR_BORDER];
18887 edit->text_normal = table[NK_COLOR_TEXT];
18888 edit->text_hover = table[NK_COLOR_TEXT];
18889 edit->text_active = table[NK_COLOR_TEXT];
18890 edit->selected_normal = table[NK_COLOR_TEXT];
18891 edit->selected_hover = table[NK_COLOR_TEXT];
18892 edit->selected_text_normal = table[NK_COLOR_EDIT];
18893 edit->selected_text_hover = table[NK_COLOR_EDIT];
18894 edit->scrollbar_size = nk_vec2(10,10);
18895 edit->scrollbar = style->scrollv;
18896 edit->padding = nk_vec2(4,4);
18897 edit->row_padding = 2;
18898 edit->cursor_size = 4;
18899 edit->border = 1;
18900 edit->rounding = 0;
18901 edit->color_factor = 1.0f;
18902 edit->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18903
18904 /* property */
18905 property = &style->property;
18906 nk_zero_struct(*property);
18907 property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18908 property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18909 property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18910 property->border_color = table[NK_COLOR_BORDER];
18911 property->label_normal = table[NK_COLOR_TEXT];
18912 property->label_hover = table[NK_COLOR_TEXT];
18913 property->label_active = table[NK_COLOR_TEXT];
18914 property->sym_left = NK_SYMBOL_TRIANGLE_LEFT;
18915 property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT;
18916 property->userdata = nk_handle_ptr(0);
18917 property->padding = nk_vec2(4,4);
18918 property->border = 1;
18919 property->rounding = 10;
18920 property->draw_begin = 0;
18921 property->draw_end = 0;
18922 property->color_factor = 1.0f;
18923 property->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18924
18925 /* property buttons */
18926 button = &style->property.dec_button;
18927 nk_zero_struct(*button);
18928 button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18929 button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18930 button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18931 button->border_color = nk_rgba(0,0,0,0);
18932 button->text_background = table[NK_COLOR_PROPERTY];
18933 button->text_normal = table[NK_COLOR_TEXT];
18934 button->text_hover = table[NK_COLOR_TEXT];
18935 button->text_active = table[NK_COLOR_TEXT];
18936 button->padding = nk_vec2(0.0f,0.0f);
18937 button->touch_padding = nk_vec2(0.0f,0.0f);
18938 button->userdata = nk_handle_ptr(0);
18939 button->text_alignment = NK_TEXT_CENTERED;
18940 button->border = 0.0f;
18941 button->rounding = 0.0f;
18942 button->color_factor_text = 1.0f;
18943 button->color_factor_background = 1.0f;
18944 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18945 button->draw_begin = 0;
18946 button->draw_end = 0;
18947 style->property.inc_button = style->property.dec_button;
18948
18949 /* property edit */
18950 edit = &style->property.edit;
18951 nk_zero_struct(*edit);
18952 edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18953 edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18954 edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]);
18955 edit->border_color = nk_rgba(0,0,0,0);
18956 edit->cursor_normal = table[NK_COLOR_TEXT];
18957 edit->cursor_hover = table[NK_COLOR_TEXT];
18958 edit->cursor_text_normal= table[NK_COLOR_EDIT];
18959 edit->cursor_text_hover = table[NK_COLOR_EDIT];
18960 edit->text_normal = table[NK_COLOR_TEXT];
18961 edit->text_hover = table[NK_COLOR_TEXT];
18962 edit->text_active = table[NK_COLOR_TEXT];
18963 edit->selected_normal = table[NK_COLOR_TEXT];
18964 edit->selected_hover = table[NK_COLOR_TEXT];
18965 edit->selected_text_normal = table[NK_COLOR_EDIT];
18966 edit->selected_text_hover = table[NK_COLOR_EDIT];
18967 edit->padding = nk_vec2(0,0);
18968 edit->cursor_size = 8;
18969 edit->border = 0;
18970 edit->rounding = 0;
18971 edit->color_factor = 1.0f;
18972 edit->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18973
18974 /* chart */
18975 chart = &style->chart;
18976 nk_zero_struct(*chart);
18977 chart->background = nk_style_item_color(table[NK_COLOR_CHART]);
18978 chart->border_color = table[NK_COLOR_BORDER];
18979 chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];
18980 chart->color = table[NK_COLOR_CHART_COLOR];
18981 chart->padding = nk_vec2(4,4);
18982 chart->border = 0;
18983 chart->rounding = 0;
18984 chart->color_factor = 1.0f;
18985 chart->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
18986 chart->show_markers = nk_true;
18987
18988 /* combo */
18989 combo = &style->combo;
18990 combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
18991 combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
18992 combo->active = nk_style_item_color(table[NK_COLOR_COMBO]);
18993 combo->border_color = table[NK_COLOR_BORDER];
18994 combo->label_normal = table[NK_COLOR_TEXT];
18995 combo->label_hover = table[NK_COLOR_TEXT];
18996 combo->label_active = table[NK_COLOR_TEXT];
18997 combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN;
18998 combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN;
18999 combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN;
19000 combo->content_padding = nk_vec2(4,4);
19001 combo->button_padding = nk_vec2(0,4);
19002 combo->spacing = nk_vec2(4,0);
19003 combo->border = 1;
19004 combo->rounding = 0;
19005 combo->color_factor = 1.0f;
19006 combo->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19007
19008 /* combo button */
19009 button = &style->combo.button;
19010 nk_zero_struct(*button);
19011 button->normal = nk_style_item_color(table[NK_COLOR_COMBO]);
19012 button->hover = nk_style_item_color(table[NK_COLOR_COMBO]);
19013 button->active = nk_style_item_color(table[NK_COLOR_COMBO]);
19014 button->border_color = nk_rgba(0,0,0,0);
19015 button->text_background = table[NK_COLOR_COMBO];
19016 button->text_normal = table[NK_COLOR_TEXT];
19017 button->text_hover = table[NK_COLOR_TEXT];
19018 button->text_active = table[NK_COLOR_TEXT];
19019 button->padding = nk_vec2(2.0f,2.0f);
19020 button->touch_padding = nk_vec2(0.0f,0.0f);
19021 button->userdata = nk_handle_ptr(0);
19022 button->text_alignment = NK_TEXT_CENTERED;
19023 button->border = 0.0f;
19024 button->rounding = 0.0f;
19025 button->color_factor_text = 1.0f;
19026 button->color_factor_background = 1.0f;
19027 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19028 button->draw_begin = 0;
19029 button->draw_end = 0;
19030
19031 /* tab */
19032 tab = &style->tab;
19033 tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
19034 tab->border_color = table[NK_COLOR_BORDER];
19035 tab->text = table[NK_COLOR_TEXT];
19036 tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT;
19037 tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN;
19038 tab->padding = nk_vec2(4,4);
19039 tab->spacing = nk_vec2(4,4);
19040 tab->indent = 10.0f;
19041 tab->border = 1;
19042 tab->rounding = 0;
19043 tab->color_factor = 1.0f;
19044 tab->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19045
19046 /* tab button */
19047 button = &style->tab.tab_minimize_button;
19048 nk_zero_struct(*button);
19049 button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
19050 button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
19051 button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);
19052 button->border_color = nk_rgba(0,0,0,0);
19053 button->text_background = table[NK_COLOR_TAB_HEADER];
19054 button->text_normal = table[NK_COLOR_TEXT];
19055 button->text_hover = table[NK_COLOR_TEXT];
19056 button->text_active = table[NK_COLOR_TEXT];
19057 button->padding = nk_vec2(2.0f,2.0f);
19058 button->touch_padding = nk_vec2(0.0f,0.0f);
19059 button->userdata = nk_handle_ptr(0);
19060 button->text_alignment = NK_TEXT_CENTERED;
19061 button->border = 0.0f;
19062 button->rounding = 0.0f;
19063 button->color_factor_text = 1.0f;
19064 button->color_factor_background = 1.0f;
19065 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19066 button->draw_begin = 0;
19067 button->draw_end = 0;
19068 style->tab.tab_maximize_button =*button;
19069
19070 /* node button */
19071 button = &style->tab.node_minimize_button;
19072 nk_zero_struct(*button);
19073 button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]);
19074 button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]);
19075 button->active = nk_style_item_color(table[NK_COLOR_WINDOW]);
19076 button->border_color = nk_rgba(0,0,0,0);
19077 button->text_background = table[NK_COLOR_TAB_HEADER];
19078 button->text_normal = table[NK_COLOR_TEXT];
19079 button->text_hover = table[NK_COLOR_TEXT];
19080 button->text_active = table[NK_COLOR_TEXT];
19081 button->padding = nk_vec2(2.0f,2.0f);
19082 button->touch_padding = nk_vec2(0.0f,0.0f);
19083 button->userdata = nk_handle_ptr(0);
19084 button->text_alignment = NK_TEXT_CENTERED;
19085 button->border = 0.0f;
19086 button->rounding = 0.0f;
19087 button->color_factor_text = 1.0f;
19088 button->color_factor_background = 1.0f;
19089 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19090 button->draw_begin = 0;
19091 button->draw_end = 0;
19092 style->tab.node_maximize_button =*button;
19093
19094 /* window header */
19095 win = &style->window;
19096 win->header.align = NK_HEADER_RIGHT;
19097 win->header.close_symbol = NK_SYMBOL_X;
19098 win->header.minimize_symbol = NK_SYMBOL_MINUS;
19099 win->header.maximize_symbol = NK_SYMBOL_PLUS;
19100 win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);
19101 win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);
19102 win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);
19103 win->header.label_normal = table[NK_COLOR_TEXT];
19104 win->header.label_hover = table[NK_COLOR_TEXT];
19105 win->header.label_active = table[NK_COLOR_TEXT];
19106 win->header.label_padding = nk_vec2(4,4);
19107 win->header.padding = nk_vec2(4,4);
19108 win->header.spacing = nk_vec2(0,0);
19109
19110 /* window header close button */
19111 button = &style->window.header.close_button;
19112 nk_zero_struct(*button);
19113 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
19114 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
19115 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
19116 button->border_color = nk_rgba(0,0,0,0);
19117 button->text_background = table[NK_COLOR_HEADER];
19118 button->text_normal = table[NK_COLOR_TEXT];
19119 button->text_hover = table[NK_COLOR_TEXT];
19120 button->text_active = table[NK_COLOR_TEXT];
19121 button->padding = nk_vec2(0.0f,0.0f);
19122 button->touch_padding = nk_vec2(0.0f,0.0f);
19123 button->userdata = nk_handle_ptr(0);
19124 button->text_alignment = NK_TEXT_CENTERED;
19125 button->border = 0.0f;
19126 button->rounding = 0.0f;
19127 button->color_factor_text = 1.0f;
19128 button->color_factor_background = 1.0f;
19129 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19130 button->draw_begin = 0;
19131 button->draw_end = 0;
19132
19133 /* window header minimize button */
19134 button = &style->window.header.minimize_button;
19135 nk_zero_struct(*button);
19136 button->normal = nk_style_item_color(table[NK_COLOR_HEADER]);
19137 button->hover = nk_style_item_color(table[NK_COLOR_HEADER]);
19138 button->active = nk_style_item_color(table[NK_COLOR_HEADER]);
19139 button->border_color = nk_rgba(0,0,0,0);
19140 button->text_background = table[NK_COLOR_HEADER];
19141 button->text_normal = table[NK_COLOR_TEXT];
19142 button->text_hover = table[NK_COLOR_TEXT];
19143 button->text_active = table[NK_COLOR_TEXT];
19144 button->padding = nk_vec2(0.0f,0.0f);
19145 button->touch_padding = nk_vec2(0.0f,0.0f);
19146 button->userdata = nk_handle_ptr(0);
19147 button->text_alignment = NK_TEXT_CENTERED;
19148 button->border = 0.0f;
19149 button->rounding = 0.0f;
19150 button->color_factor_text = 1.0f;
19151 button->color_factor_background = 1.0f;
19152 button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;
19153 button->draw_begin = 0;
19154 button->draw_end = 0;
19155
19156 /* window */
19157 win->background = table[NK_COLOR_WINDOW];
19158 win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);
19159 win->border_color = table[NK_COLOR_BORDER];
19160 win->popup_border_color = table[NK_COLOR_BORDER];
19161 win->combo_border_color = table[NK_COLOR_BORDER];
19162 win->contextual_border_color = table[NK_COLOR_BORDER];
19163 win->menu_border_color = table[NK_COLOR_BORDER];
19164 win->group_border_color = table[NK_COLOR_BORDER];
19165 win->tooltip_border_color = table[NK_COLOR_BORDER];
19166 win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);
19167
19168 win->rounding = 0.0f;
19169 win->spacing = nk_vec2(4,4);
19170 win->scrollbar_size = nk_vec2(10,10);
19171 win->min_size = nk_vec2(64,64);
19172
19173 win->combo_border = 1.0f;
19174 win->contextual_border = 1.0f;
19175 win->menu_border = 1.0f;
19176 win->group_border = 1.0f;
19177 win->tooltip_border = 1.0f;
19178 win->popup_border = 1.0f;
19179 win->border = 2.0f;
19180 win->min_row_height_padding = 8;
19181
19182 win->padding = nk_vec2(4,4);
19183 win->group_padding = nk_vec2(4,4);
19184 win->popup_padding = nk_vec2(4,4);
19185 win->combo_padding = nk_vec2(4,4);
19186 win->contextual_padding = nk_vec2(4,4);
19187 win->menu_padding = nk_vec2(4,4);
19188 win->tooltip_padding = nk_vec2(4,4);
19189}
19190NK_API void
19191nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)
19192{
19193 struct nk_style *style;
19194 NK_ASSERT(ctx);
19195
19196 if (!ctx) return;
19197 style = &ctx->style;
19198 style->font = font;
19199 ctx->stacks.fonts.head = 0;
19200 if (ctx->current)
19202}
19203NK_API nk_bool
19204nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font)
19205{
19206 struct nk_config_stack_user_font *font_stack;
19207 struct nk_config_stack_user_font_element *element;
19208
19209 NK_ASSERT(ctx);
19210 if (!ctx) return 0;
19211
19212 font_stack = &ctx->stacks.fonts;
19213 NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));
19214 if (font_stack->head >= (int)NK_LEN(font_stack->elements))
19215 return 0;
19216
19217 element = &font_stack->elements[font_stack->head++];
19218 element->address = &ctx->style.font;
19219 element->old_value = ctx->style.font;
19220 ctx->style.font = font;
19221 return 1;
19222}
19223NK_API nk_bool
19224nk_style_pop_font(struct nk_context *ctx)
19225{
19226 struct nk_config_stack_user_font *font_stack;
19227 struct nk_config_stack_user_font_element *element;
19228
19229 NK_ASSERT(ctx);
19230 if (!ctx) return 0;
19231
19232 font_stack = &ctx->stacks.fonts;
19233 NK_ASSERT(font_stack->head > 0);
19234 if (font_stack->head < 1)
19235 return 0;
19236
19237 element = &font_stack->elements[--font_stack->head];
19238 *element->address = element->old_value;
19239 return 1;
19240}
19241#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \
19242nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\
19243{\
19244 struct nk_config_stack_##type * type_stack;\
19245 struct nk_config_stack_##type##_element *element;\
19246 NK_ASSERT(ctx);\
19247 if (!ctx) return 0;\
19248 type_stack = &ctx->stacks.stack;\
19249 NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\
19250 if (type_stack->head >= (int)NK_LEN(type_stack->elements))\
19251 return 0;\
19252 element = &type_stack->elements[type_stack->head++];\
19253 element->address = address;\
19254 element->old_value = *address;\
19255 *address = value;\
19256 return 1;\
19257}
19258#define NK_STYLE_POP_IMPLEMENATION(type, stack) \
19259nk_style_pop_##type(struct nk_context *ctx)\
19260{\
19261 struct nk_config_stack_##type *type_stack;\
19262 struct nk_config_stack_##type##_element *element;\
19263 NK_ASSERT(ctx);\
19264 if (!ctx) return 0;\
19265 type_stack = &ctx->stacks.stack;\
19266 NK_ASSERT(type_stack->head > 0);\
19267 if (type_stack->head < 1)\
19268 return 0;\
19269 element = &type_stack->elements[--type_stack->head];\
19270 *element->address = element->old_value;\
19271 return 1;\
19272}
19273NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)
19274NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)
19275NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)
19276NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)
19277NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)
19278
19279NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(style_item, style_items)
19280NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(float,floats)
19281NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(vec2, vectors)
19282NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(flags,flags)
19283NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(color,colors)
19284
19285NK_API nk_bool
19286nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)
19287{
19288 struct nk_style *style;
19289 NK_ASSERT(ctx);
19290 if (!ctx) return 0;
19291 style = &ctx->style;
19292 if (style->cursors[c]) {
19293 style->cursor_active = style->cursors[c];
19294 return 1;
19295 }
19296 return 0;
19297}
19298NK_API void
19299nk_style_show_cursor(struct nk_context *ctx)
19300{
19301 ctx->style.cursor_visible = nk_true;
19302}
19303NK_API void
19304nk_style_hide_cursor(struct nk_context *ctx)
19305{
19306 ctx->style.cursor_visible = nk_false;
19307}
19308NK_API void
19309nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,
19310 const struct nk_cursor *c)
19311{
19312 struct nk_style *style;
19313 NK_ASSERT(ctx);
19314 if (!ctx) return;
19315 style = &ctx->style;
19316 style->cursors[cursor] = c;
19317}
19318NK_API void
19319nk_style_load_all_cursors(struct nk_context *ctx, const struct nk_cursor *cursors)
19320{
19321 int i = 0;
19322 struct nk_style *style;
19323 NK_ASSERT(ctx);
19324 if (!ctx) return;
19325 style = &ctx->style;
19326 for (i = 0; i < NK_CURSOR_COUNT; ++i)
19327 style->cursors[i] = &cursors[i];
19328 style->cursor_visible = nk_true;
19329}
19330
19331
19332
19333
19334/* ==============================================================
19335 *
19336 * CONTEXT
19337 *
19338 * ===============================================================*/
19339NK_INTERN void
19340nk_setup(struct nk_context *ctx, const struct nk_user_font *font)
19341{
19342 NK_ASSERT(ctx);
19343 if (!ctx) return;
19344 nk_zero_struct(*ctx);
19345 nk_style_default(ctx);
19346 ctx->seq = 1;
19347 if (font) ctx->style.font = font;
19348#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT
19349 nk_draw_list_init(&ctx->draw_list);
19350#endif
19351}
19352#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
19353NK_API nk_bool
19354nk_init_default(struct nk_context *ctx, const struct nk_user_font *font)
19355{
19356 struct nk_allocator alloc;
19357 alloc.userdata.ptr = 0;
19358 alloc.alloc = nk_malloc;
19359 alloc.free = nk_mfree;
19360 return nk_init(ctx, &alloc, font);
19361}
19362#endif
19363NK_API nk_bool
19364nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,
19365 const struct nk_user_font *font)
19366{
19367 NK_ASSERT(memory);
19368 if (!memory) return 0;
19369 nk_setup(ctx, font);
19370 nk_buffer_init_fixed(&ctx->memory, memory, size);
19371 ctx->use_pool = nk_false;
19372 return 1;
19373}
19374NK_API nk_bool
19375nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,
19376 struct nk_buffer *pool, const struct nk_user_font *font)
19377{
19378 NK_ASSERT(cmds);
19379 NK_ASSERT(pool);
19380 if (!cmds || !pool) return 0;
19381
19382 nk_setup(ctx, font);
19383 ctx->memory = *cmds;
19384 if (pool->type == NK_BUFFER_FIXED) {
19385 /* take memory from buffer and alloc fixed pool */
19386 nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);
19387 } else {
19388 /* create dynamic pool from buffer allocator */
19389 struct nk_allocator *alloc = &pool->pool;
19390 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
19391 }
19392 ctx->use_pool = nk_true;
19393 return 1;
19394}
19395NK_API nk_bool
19396nk_init(struct nk_context *ctx, const struct nk_allocator *alloc,
19397 const struct nk_user_font *font)
19398{
19399 NK_ASSERT(alloc);
19400 if (!alloc) return 0;
19401 nk_setup(ctx, font);
19402 nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);
19403 nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);
19404 ctx->use_pool = nk_true;
19405 return 1;
19406}
19407#ifdef NK_INCLUDE_COMMAND_USERDATA
19408NK_API void
19409nk_set_user_data(struct nk_context *ctx, nk_handle handle)
19410{
19411 if (!ctx) return;
19412 ctx->userdata = handle;
19413 if (ctx->current)
19414 ctx->current->buffer.userdata = handle;
19415}
19416#endif
19417NK_API void
19418nk_free(struct nk_context *ctx)
19419{
19420 NK_ASSERT(ctx);
19421 if (!ctx) return;
19422 nk_buffer_free(&ctx->memory);
19423 if (ctx->use_pool)
19424 nk_pool_free(&ctx->pool);
19425
19426 nk_zero(&ctx->input, sizeof(ctx->input));
19427 nk_zero(&ctx->style, sizeof(ctx->style));
19428 nk_zero(&ctx->memory, sizeof(ctx->memory));
19429
19430 ctx->seq = 0;
19431 ctx->build = 0;
19432 ctx->begin = 0;
19433 ctx->end = 0;
19434 ctx->active = 0;
19435 ctx->current = 0;
19436 ctx->freelist = 0;
19437 ctx->count = 0;
19438}
19439NK_API void
19440nk_clear(struct nk_context *ctx)
19441{
19442 struct nk_window *iter;
19443 struct nk_window *next;
19444 NK_ASSERT(ctx);
19445
19446 if (!ctx) return;
19447 if (ctx->use_pool)
19448 nk_buffer_clear(&ctx->memory);
19449 else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);
19450
19451 ctx->build = 0;
19452 ctx->memory.calls = 0;
19453 ctx->last_widget_state = 0;
19454 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
19455 NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));
19456
19457 /* garbage collector */
19458 iter = ctx->begin;
19459 while (iter) {
19460 /* make sure valid minimized windows do not get removed */
19461 if ((iter->flags & NK_WINDOW_MINIMIZED) &&
19462 !(iter->flags & NK_WINDOW_CLOSED) &&
19463 iter->seq == ctx->seq) {
19464 iter = iter->next;
19465 continue;
19466 }
19467 /* remove hotness from hidden or closed windows*/
19468 if (((iter->flags & NK_WINDOW_HIDDEN) ||
19469 (iter->flags & NK_WINDOW_CLOSED)) &&
19470 iter == ctx->active) {
19471 ctx->active = iter->prev;
19472 ctx->end = iter->prev;
19473 if (!ctx->end)
19474 ctx->begin = 0;
19475 if (ctx->active)
19476 ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;
19477 }
19478 /* free unused popup windows */
19479 if (iter->popup.win && iter->popup.win->seq != ctx->seq) {
19480 nk_free_window(ctx, iter->popup.win);
19481 iter->popup.win = 0;
19482 }
19483 /* remove unused window state tables */
19484 {struct nk_table *n, *it = iter->tables;
19485 while (it) {
19486 n = it->next;
19487 if (it->seq != ctx->seq) {
19488 nk_remove_table(iter, it);
19489 nk_zero(it, sizeof(union nk_page_data));
19490 nk_free_table(ctx, it);
19491 if (it == iter->tables)
19492 iter->tables = n;
19493 } it = n;
19494 }}
19495 /* window itself is not used anymore so free */
19496 if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {
19497 next = iter->next;
19498 nk_remove_window(ctx, iter);
19499 nk_free_window(ctx, iter);
19500 iter = next;
19501 } else iter = iter->next;
19502 }
19503 ctx->seq++;
19504}
19505NK_LIB void
19506nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
19507{
19508 NK_ASSERT(ctx);
19509 NK_ASSERT(buffer);
19510 if (!ctx || !buffer) return;
19511 buffer->begin = ctx->memory.allocated;
19512 buffer->end = buffer->begin;
19513 buffer->last = buffer->begin;
19514 buffer->clip = nk_null_rect;
19515}
19516NK_LIB void
19517nk_start(struct nk_context *ctx, struct nk_window *win)
19518{
19519 NK_ASSERT(ctx);
19520 NK_ASSERT(win);
19521 nk_start_buffer(ctx, &win->buffer);
19522}
19523NK_LIB void
19524nk_start_popup(struct nk_context *ctx, struct nk_window *win)
19525{
19526 struct nk_popup_buffer *buf;
19527 NK_ASSERT(ctx);
19528 NK_ASSERT(win);
19529 if (!ctx || !win) return;
19530
19531 /* save buffer fill state for popup */
19532 buf = &win->popup.buf;
19533 buf->begin = win->buffer.end;
19534 buf->end = win->buffer.end;
19535 buf->parent = win->buffer.last;
19536 buf->last = buf->begin;
19537 buf->active = nk_true;
19538}
19539NK_LIB void
19540nk_finish_popup(struct nk_context *ctx, struct nk_window *win)
19541{
19542 struct nk_popup_buffer *buf;
19543 NK_ASSERT(ctx);
19544 NK_ASSERT(win);
19545 if (!ctx || !win) return;
19546
19547 buf = &win->popup.buf;
19548 buf->last = win->buffer.last;
19549 buf->end = win->buffer.end;
19550}
19551NK_LIB void
19552nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)
19553{
19554 NK_ASSERT(ctx);
19555 NK_ASSERT(buffer);
19556 if (!ctx || !buffer) return;
19557 buffer->end = ctx->memory.allocated;
19558}
19559NK_LIB void
19560nk_finish(struct nk_context *ctx, struct nk_window *win)
19561{
19562 struct nk_popup_buffer *buf;
19563 struct nk_command *parent_last;
19564 void *memory;
19565
19566 NK_ASSERT(ctx);
19567 NK_ASSERT(win);
19568 if (!ctx || !win) return;
19569 nk_finish_buffer(ctx, &win->buffer);
19570 if (!win->popup.buf.active) return;
19571
19572 buf = &win->popup.buf;
19573 memory = ctx->memory.memory.ptr;
19574 parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);
19575 parent_last->next = buf->end;
19576}
19577NK_LIB void
19578nk_build(struct nk_context *ctx)
19579{
19580 struct nk_window *it = 0;
19581 struct nk_command *cmd = 0;
19582 nk_byte *buffer = 0;
19583
19584 /* draw cursor overlay */
19585 if (!ctx->style.cursor_active)
19586 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];
19587 if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {
19588 struct nk_rect mouse_bounds;
19589 const struct nk_cursor *cursor = ctx->style.cursor_active;
19590 nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);
19591 nk_start_buffer(ctx, &ctx->overlay);
19592
19593 mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;
19594 mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;
19595 mouse_bounds.w = cursor->size.x;
19596 mouse_bounds.h = cursor->size.y;
19597
19598 nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);
19599 nk_finish_buffer(ctx, &ctx->overlay);
19600 }
19601 /* build one big draw command list out of all window buffers */
19602 it = ctx->begin;
19603 buffer = (nk_byte*)ctx->memory.memory.ptr;
19604 while (it != 0) {
19605 struct nk_window *next = it->next;
19606 if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||
19607 it->seq != ctx->seq)
19608 goto cont;
19609
19610 cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);
19611 while (next && ((next->buffer.last == next->buffer.begin) ||
19612 (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))
19613 next = next->next; /* skip empty command buffers */
19614
19615 if (next) cmd->next = next->buffer.begin;
19616 cont: it = next;
19617 }
19618 /* append all popup draw commands into lists */
19619 it = ctx->begin;
19620 while (it != 0) {
19621 struct nk_window *next = it->next;
19622 struct nk_popup_buffer *buf;
19623 if (!it->popup.buf.active)
19624 goto skip;
19625
19626 buf = &it->popup.buf;
19627 cmd->next = buf->begin;
19628 cmd = nk_ptr_add(struct nk_command, buffer, buf->last);
19629 buf->active = nk_false;
19630 skip: it = next;
19631 }
19632 if (cmd) {
19633 /* append overlay commands */
19634 if (ctx->overlay.end != ctx->overlay.begin)
19635 cmd->next = ctx->overlay.begin;
19636 else cmd->next = ctx->memory.allocated;
19637 }
19638}
19639NK_API const struct nk_command*
19640nk__begin(struct nk_context *ctx)
19641{
19642 struct nk_window *iter;
19643 nk_byte *buffer;
19644 NK_ASSERT(ctx);
19645 if (!ctx) return 0;
19646 if (!ctx->count) return 0;
19647
19648 buffer = (nk_byte*)ctx->memory.memory.ptr;
19649 if (!ctx->build) {
19650 nk_build(ctx);
19651 ctx->build = nk_true;
19652 }
19653 iter = ctx->begin;
19654 while (iter && ((iter->buffer.begin == iter->buffer.end) ||
19655 (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))
19656 iter = iter->next;
19657 if (!iter) return 0;
19658 return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);
19659}
19660
19661NK_API const struct nk_command*
19662nk__next(struct nk_context *ctx, const struct nk_command *cmd)
19663{
19664 nk_byte *buffer;
19665 const struct nk_command *next;
19666 NK_ASSERT(ctx);
19667 if (!ctx || !cmd || !ctx->count) return 0;
19668 if (cmd->next >= ctx->memory.allocated) return 0;
19669 buffer = (nk_byte*)ctx->memory.memory.ptr;
19670 next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);
19671 return next;
19672}
19673
19674
19675
19676
19677
19678
19679/* ===============================================================
19680 *
19681 * POOL
19682 *
19683 * ===============================================================*/
19684NK_LIB void
19685nk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc,
19686 unsigned int capacity)
19687{
19688 NK_ASSERT(capacity >= 1);
19689 nk_zero(pool, sizeof(*pool));
19690 pool->alloc = *alloc;
19691 pool->capacity = capacity;
19692 pool->type = NK_BUFFER_DYNAMIC;
19693 pool->pages = 0;
19694}
19695NK_LIB void
19696nk_pool_free(struct nk_pool *pool)
19697{
19698 struct nk_page *iter;
19699 if (!pool) return;
19700 iter = pool->pages;
19701 if (pool->type == NK_BUFFER_FIXED) return;
19702 while (iter) {
19703 struct nk_page *next = iter->next;
19704 pool->alloc.free(pool->alloc.userdata, iter);
19705 iter = next;
19706 }
19707}
19708NK_LIB void
19709nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)
19710{
19711 nk_zero(pool, sizeof(*pool));
19712 NK_ASSERT(size >= sizeof(struct nk_page));
19713 if (size < sizeof(struct nk_page)) return;
19714 /* first nk_page_element is embedded in nk_page, additional elements follow in adjacent space */
19715 pool->capacity = (unsigned)(1 + (size - sizeof(struct nk_page)) / sizeof(struct nk_page_element));
19716 pool->pages = (struct nk_page*)memory;
19717 pool->type = NK_BUFFER_FIXED;
19718 pool->size = size;
19719}
19720NK_LIB struct nk_page_element*
19721nk_pool_alloc(struct nk_pool *pool)
19722{
19723 if (!pool->pages || pool->pages->size >= pool->capacity) {
19724 /* allocate new page */
19725 struct nk_page *page;
19726 if (pool->type == NK_BUFFER_FIXED) {
19727 NK_ASSERT(pool->pages);
19728 if (!pool->pages) return 0;
19729 NK_ASSERT(pool->pages->size < pool->capacity);
19730 return 0;
19731 } else {
19732 nk_size size = sizeof(struct nk_page);
19733 size += (pool->capacity - 1) * sizeof(struct nk_page_element);
19734 page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);
19735 page->next = pool->pages;
19736 pool->pages = page;
19737 page->size = 0;
19738 }
19739 } return &pool->pages->win[pool->pages->size++];
19740}
19741
19742
19743
19744
19745
19746/* ===============================================================
19747 *
19748 * PAGE ELEMENT
19749 *
19750 * ===============================================================*/
19751NK_LIB struct nk_page_element*
19752nk_create_page_element(struct nk_context *ctx)
19753{
19754 struct nk_page_element *elem;
19755 if (ctx->freelist) {
19756 /* unlink page element from free list */
19757 elem = ctx->freelist;
19758 ctx->freelist = elem->next;
19759 } else if (ctx->use_pool) {
19760 /* allocate page element from memory pool */
19761 elem = nk_pool_alloc(&ctx->pool);
19762 NK_ASSERT(elem);
19763 if (!elem) return 0;
19764 } else {
19765 /* allocate new page element from back of fixed size memory buffer */
19766 NK_STORAGE const nk_size size = sizeof(struct nk_page_element);
19767 NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);
19768 elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);
19769 NK_ASSERT(elem);
19770 if (!elem) return 0;
19771 }
19772 nk_zero_struct(*elem);
19773 elem->next = 0;
19774 elem->prev = 0;
19775 return elem;
19776}
19777NK_LIB void
19778nk_link_page_element_into_freelist(struct nk_context *ctx,
19779 struct nk_page_element *elem)
19780{
19781 /* link table into freelist */
19782 if (!ctx->freelist) {
19783 ctx->freelist = elem;
19784 } else {
19785 elem->next = ctx->freelist;
19786 ctx->freelist = elem;
19787 }
19788}
19789NK_LIB void
19790nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)
19791{
19792 /* we have a pool so just add to free list */
19793 if (ctx->use_pool) {
19794 nk_link_page_element_into_freelist(ctx, elem);
19795 return;
19796 }
19797 /* if possible remove last element from back of fixed memory buffer */
19798 {void *elem_end = (void*)(elem + 1);
19799 void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;
19800 if (elem_end == buffer_end)
19801 ctx->memory.size -= sizeof(struct nk_page_element);
19802 else nk_link_page_element_into_freelist(ctx, elem);}
19803}
19804
19805
19806
19807
19808
19809/* ===============================================================
19810 *
19811 * TABLE
19812 *
19813 * ===============================================================*/
19814NK_LIB struct nk_table*
19815nk_create_table(struct nk_context *ctx)
19816{
19817 struct nk_page_element *elem;
19818 elem = nk_create_page_element(ctx);
19819 if (!elem) return 0;
19820 nk_zero_struct(*elem);
19821 return &elem->data.tbl;
19822}
19823NK_LIB void
19824nk_free_table(struct nk_context *ctx, struct nk_table *tbl)
19825{
19826 union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);
19827 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
19828 nk_free_page_element(ctx, pe);
19829}
19830NK_LIB void
19831nk_push_table(struct nk_window *win, struct nk_table *tbl)
19832{
19833 if (!win->tables) {
19834 win->tables = tbl;
19835 tbl->next = 0;
19836 tbl->prev = 0;
19837 tbl->size = 0;
19838 win->table_count = 1;
19839 return;
19840 }
19841 win->tables->prev = tbl;
19842 tbl->next = win->tables;
19843 tbl->prev = 0;
19844 tbl->size = 0;
19845 win->tables = tbl;
19846 win->table_count++;
19847}
19848NK_LIB void
19849nk_remove_table(struct nk_window *win, struct nk_table *tbl)
19850{
19851 if (win->tables == tbl)
19852 win->tables = tbl->next;
19853 if (tbl->next)
19854 tbl->next->prev = tbl->prev;
19855 if (tbl->prev)
19856 tbl->prev->next = tbl->next;
19857 tbl->next = 0;
19858 tbl->prev = 0;
19859}
19860NK_LIB nk_uint*
19861nk_add_value(struct nk_context *ctx, struct nk_window *win,
19862 nk_hash name, nk_uint value)
19863{
19864 NK_ASSERT(ctx);
19865 NK_ASSERT(win);
19866 if (!win || !ctx) return 0;
19867 if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) {
19868 struct nk_table *tbl = nk_create_table(ctx);
19869 NK_ASSERT(tbl);
19870 if (!tbl) return 0;
19871 nk_push_table(win, tbl);
19872 }
19873 win->tables->seq = win->seq;
19874 win->tables->keys[win->tables->size] = name;
19875 win->tables->values[win->tables->size] = value;
19876 return &win->tables->values[win->tables->size++];
19877}
19878NK_LIB nk_uint*
19879nk_find_value(const struct nk_window *win, nk_hash name)
19880{
19881 struct nk_table *iter = win->tables;
19882 while (iter) {
19883 unsigned int i = 0;
19884 unsigned int size = iter->size;
19885 for (i = 0; i < size; ++i) {
19886 if (iter->keys[i] == name) {
19887 iter->seq = win->seq;
19888 return &iter->values[i];
19889 }
19890 } size = NK_VALUE_PAGE_CAPACITY;
19891 iter = iter->next;
19892 }
19893 return 0;
19894}
19895
19896
19897
19898
19899/* ===============================================================
19900 *
19901 * PANEL
19902 *
19903 * ===============================================================*/
19904NK_LIB void*
19905nk_create_panel(struct nk_context *ctx)
19906{
19907 struct nk_page_element *elem;
19908 elem = nk_create_page_element(ctx);
19909 if (!elem) return 0;
19910 nk_zero_struct(*elem);
19911 return &elem->data.pan;
19912}
19913NK_LIB void
19914nk_free_panel(struct nk_context *ctx, struct nk_panel *pan)
19915{
19916 union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);
19917 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
19918 nk_free_page_element(ctx, pe);
19919}
19920NK_LIB nk_bool
19921nk_panel_has_header(nk_flags flags, const char *title)
19922{
19923 nk_bool active = 0;
19924 active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));
19925 active = active || (flags & NK_WINDOW_TITLE);
19926 active = active && !(flags & NK_WINDOW_HIDDEN) && title;
19927 return active;
19928}
19929NK_LIB struct nk_vec2
19930nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)
19931{
19932 switch (type) {
19933 default:
19934 case NK_PANEL_WINDOW: return style->window.padding;
19935 case NK_PANEL_GROUP: return style->window.group_padding;
19936 case NK_PANEL_POPUP: return style->window.popup_padding;
19937 case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;
19938 case NK_PANEL_COMBO: return style->window.combo_padding;
19939 case NK_PANEL_MENU: return style->window.menu_padding;
19940 case NK_PANEL_TOOLTIP: return style->window.menu_padding;}
19941}
19942NK_LIB float
19943nk_panel_get_border(const struct nk_style *style, nk_flags flags,
19944 enum nk_panel_type type)
19945{
19946 if (flags & NK_WINDOW_BORDER) {
19947 switch (type) {
19948 default:
19949 case NK_PANEL_WINDOW: return style->window.border;
19950 case NK_PANEL_GROUP: return style->window.group_border;
19951 case NK_PANEL_POPUP: return style->window.popup_border;
19952 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;
19953 case NK_PANEL_COMBO: return style->window.combo_border;
19954 case NK_PANEL_MENU: return style->window.menu_border;
19955 case NK_PANEL_TOOLTIP: return style->window.menu_border;
19956 }} else return 0;
19957}
19958NK_LIB struct nk_color
19959nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)
19960{
19961 switch (type) {
19962 default:
19963 case NK_PANEL_WINDOW: return style->window.border_color;
19964 case NK_PANEL_GROUP: return style->window.group_border_color;
19965 case NK_PANEL_POPUP: return style->window.popup_border_color;
19966 case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;
19967 case NK_PANEL_COMBO: return style->window.combo_border_color;
19968 case NK_PANEL_MENU: return style->window.menu_border_color;
19969 case NK_PANEL_TOOLTIP: return style->window.menu_border_color;}
19970}
19971NK_LIB nk_bool
19972nk_panel_is_sub(enum nk_panel_type type)
19973{
19974 return ((int)type & (int)NK_PANEL_SET_SUB)?1:0;
19975}
19976NK_LIB nk_bool
19977nk_panel_is_nonblock(enum nk_panel_type type)
19978{
19979 return ((int)type & (int)NK_PANEL_SET_NONBLOCK)?1:0;
19980}
19981NK_LIB nk_bool
19982nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)
19983{
19984 struct nk_input *in;
19985 struct nk_window *win;
19986 struct nk_panel *layout;
19987 struct nk_command_buffer *out;
19988 const struct nk_style *style;
19989 const struct nk_user_font *font;
19990
19991 struct nk_vec2 scrollbar_size;
19992 struct nk_vec2 panel_padding;
19993
19994 NK_ASSERT(ctx);
19995 NK_ASSERT(ctx->current);
19996 NK_ASSERT(ctx->current->layout);
19997 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
19998 nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));
19999 if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {
20000 nk_zero(ctx->current->layout, sizeof(struct nk_panel));
20001 ctx->current->layout->type = panel_type;
20002 return 0;
20003 }
20004 /* pull state into local stack */
20005 style = &ctx->style;
20006 font = style->font;
20007 win = ctx->current;
20008 layout = win->layout;
20009 out = &win->buffer;
20010 in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;
20011#ifdef NK_INCLUDE_COMMAND_USERDATA
20012 win->buffer.userdata = ctx->userdata;
20013#endif
20014 /* pull style configuration into local stack */
20015 scrollbar_size = style->window.scrollbar_size;
20016 panel_padding = nk_panel_get_padding(style, panel_type);
20017
20018 /* window movement */
20019 if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {
20020 nk_bool left_mouse_down;
20021 unsigned int left_mouse_clicked;
20022 int left_mouse_click_in_cursor;
20023
20024 /* calculate draggable window space */
20025 struct nk_rect header;
20026 header.x = win->bounds.x;
20027 header.y = win->bounds.y;
20028 header.w = win->bounds.w;
20029 if (nk_panel_has_header(win->flags, title)) {
20030 header.h = font->height + 2.0f * style->window.header.padding.y;
20031 header.h += 2.0f * style->window.header.label_padding.y;
20032 } else header.h = panel_padding.y;
20033
20034 /* window movement by dragging */
20035 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
20036 left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;
20037 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
20038 NK_BUTTON_LEFT, header, nk_true);
20039 if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {
20040 win->bounds.x = win->bounds.x + in->mouse.delta.x;
20041 win->bounds.y = win->bounds.y + in->mouse.delta.y;
20042 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;
20043 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;
20044 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];
20045 }
20046 }
20047
20048 /* setup panel */
20049 layout->type = panel_type;
20050 layout->flags = win->flags;
20051 layout->bounds = win->bounds;
20052 layout->bounds.x += panel_padding.x;
20053 layout->bounds.w -= 2*panel_padding.x;
20054 if (win->flags & NK_WINDOW_BORDER) {
20055 layout->border = nk_panel_get_border(style, win->flags, panel_type);
20056 layout->bounds = nk_shrink_rect(layout->bounds, layout->border);
20057 } else layout->border = 0;
20058 layout->at_y = layout->bounds.y;
20059 layout->at_x = layout->bounds.x;
20060 layout->max_x = 0;
20061 layout->header_height = 0;
20062 layout->footer_height = 0;
20064 layout->row.index = 0;
20065 layout->row.columns = 0;
20066 layout->row.ratio = 0;
20067 layout->row.item_width = 0;
20068 layout->row.tree_depth = 0;
20069 layout->row.height = panel_padding.y;
20070 layout->has_scrolling = nk_true;
20071 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))
20072 layout->bounds.w -= scrollbar_size.x;
20073 if (!nk_panel_is_nonblock(panel_type)) {
20074 layout->footer_height = 0;
20075 if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)
20076 layout->footer_height = scrollbar_size.y;
20077 layout->bounds.h -= layout->footer_height;
20078 }
20079
20080 /* panel header */
20081 if (nk_panel_has_header(win->flags, title))
20082 {
20083 struct nk_text text;
20084 struct nk_rect header;
20085 const struct nk_style_item *background = 0;
20086
20087 /* calculate header bounds */
20088 header.x = win->bounds.x;
20089 header.y = win->bounds.y;
20090 header.w = win->bounds.w;
20091 header.h = font->height + 2.0f * style->window.header.padding.y;
20092 header.h += (2.0f * style->window.header.label_padding.y);
20093
20094 /* shrink panel by header */
20095 layout->header_height = header.h;
20096 layout->bounds.y += header.h;
20097 layout->bounds.h -= header.h;
20098 layout->at_y += header.h;
20099
20100 /* select correct header background and text color */
20101 if (ctx->active == win) {
20102 background = &style->window.header.active;
20103 text.text = style->window.header.label_active;
20104 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {
20105 background = &style->window.header.hover;
20106 text.text = style->window.header.label_hover;
20107 } else {
20108 background = &style->window.header.normal;
20109 text.text = style->window.header.label_normal;
20110 }
20111
20112 /* draw header background */
20113 header.h += 1.0f;
20114
20115 switch(background->type) {
20116 case NK_STYLE_ITEM_IMAGE:
20117 text.background = nk_rgba(0,0,0,0);
20118 nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
20119 break;
20120 case NK_STYLE_ITEM_NINE_SLICE:
20121 text.background = nk_rgba(0, 0, 0, 0);
20122 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
20123 break;
20124 case NK_STYLE_ITEM_COLOR:
20125 text.background = background->data.color;
20126 nk_fill_rect(out, header, 0, background->data.color);
20127 break;
20128 }
20129
20130 /* window close button */
20131 {struct nk_rect button;
20132 button.y = header.y + style->window.header.padding.y;
20133 button.h = header.h - 2 * style->window.header.padding.y;
20134 button.w = button.h;
20135 if (win->flags & NK_WINDOW_CLOSABLE) {
20136 nk_flags ws = 0;
20137 if (style->window.header.align == NK_HEADER_RIGHT) {
20138 button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);
20139 header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;
20140 } else {
20141 button.x = header.x + style->window.header.padding.x;
20142 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
20143 }
20144
20145 if (nk_do_button_symbol(&ws, &win->buffer, button,
20146 style->window.header.close_symbol, NK_BUTTON_DEFAULT,
20147 &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
20148 {
20149 layout->flags |= NK_WINDOW_HIDDEN;
20150 layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;
20151 }
20152 }
20153
20154 /* window minimize button */
20155 if (win->flags & NK_WINDOW_MINIMIZABLE) {
20156 nk_flags ws = 0;
20157 if (style->window.header.align == NK_HEADER_RIGHT) {
20158 button.x = (header.w + header.x) - button.w;
20159 if (!(win->flags & NK_WINDOW_CLOSABLE)) {
20160 button.x -= style->window.header.padding.x;
20161 header.w -= style->window.header.padding.x;
20162 }
20163 header.w -= button.w + style->window.header.spacing.x;
20164 } else {
20165 button.x = header.x;
20166 header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;
20167 }
20168 if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?
20169 style->window.header.maximize_symbol: style->window.header.minimize_symbol,
20170 NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))
20171 layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?
20172 layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:
20173 layout->flags | NK_WINDOW_MINIMIZED;
20174 }}
20175
20176 {/* window header title */
20177 int text_len = nk_strlen(title);
20178 struct nk_rect label = {0,0,0,0};
20179 float t = font->width(font->userdata, font->height, title, text_len);
20180 text.padding = nk_vec2(0,0);
20181
20182 label.x = header.x + style->window.header.padding.x;
20183 label.x += style->window.header.label_padding.x;
20184 label.y = header.y + style->window.header.label_padding.y;
20185 label.h = font->height + 2 * style->window.header.label_padding.y;
20186 label.w = t + 2 * style->window.header.spacing.x;
20187 label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);
20188 nk_widget_text(out, label, (const char*)title, text_len, &text, NK_TEXT_LEFT, font);}
20189 }
20190
20191 /* draw window background */
20192 if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {
20193 struct nk_rect body;
20194 body.x = win->bounds.x;
20195 body.w = win->bounds.w;
20196 body.y = (win->bounds.y + layout->header_height);
20197 body.h = (win->bounds.h - layout->header_height);
20198
20199 switch(style->window.fixed_background.type) {
20200 case NK_STYLE_ITEM_IMAGE:
20201 nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);
20202 break;
20203 case NK_STYLE_ITEM_NINE_SLICE:
20204 nk_draw_nine_slice(out, body, &style->window.fixed_background.data.slice, nk_white);
20205 break;
20206 case NK_STYLE_ITEM_COLOR:
20207 nk_fill_rect(out, body, style->window.rounding, style->window.fixed_background.data.color);
20208 break;
20209 }
20210 }
20211
20212 /* set clipping rectangle */
20213 {struct nk_rect clip;
20214 layout->clip = layout->bounds;
20215 nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,
20216 layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);
20217 nk_push_scissor(out, clip);
20218 layout->clip = clip;}
20219 return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);
20220}
20221NK_LIB void
20222nk_panel_end(struct nk_context *ctx)
20223{
20224 struct nk_input *in;
20225 struct nk_window *window;
20226 struct nk_panel *layout;
20227 const struct nk_style *style;
20228 struct nk_command_buffer *out;
20229
20230 struct nk_vec2 scrollbar_size;
20231 struct nk_vec2 panel_padding;
20232
20233 NK_ASSERT(ctx);
20234 NK_ASSERT(ctx->current);
20235 NK_ASSERT(ctx->current->layout);
20236 if (!ctx || !ctx->current || !ctx->current->layout)
20237 return;
20238
20239 window = ctx->current;
20240 layout = window->layout;
20241 style = &ctx->style;
20242 out = &window->buffer;
20243 in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;
20244 if (!nk_panel_is_sub(layout->type))
20245 nk_push_scissor(out, nk_null_rect);
20246
20247 /* cache configuration data */
20248 scrollbar_size = style->window.scrollbar_size;
20249 panel_padding = nk_panel_get_padding(style, layout->type);
20250
20251 /* update the current cursor Y-position to point over the last added widget */
20252 layout->at_y += layout->row.height;
20253
20254 /* dynamic panels */
20255 if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))
20256 {
20257 /* update panel height to fit dynamic growth */
20258 struct nk_rect empty_space;
20259 if (layout->at_y < (layout->bounds.y + layout->bounds.h))
20260 layout->bounds.h = layout->at_y - layout->bounds.y;
20261
20262 /* fill top empty space */
20263 empty_space.x = window->bounds.x;
20264 empty_space.y = layout->bounds.y;
20265 empty_space.h = panel_padding.y;
20266 empty_space.w = window->bounds.w;
20267 nk_fill_rect(out, empty_space, 0, style->window.background);
20268
20269 /* fill left empty space */
20270 empty_space.x = window->bounds.x;
20271 empty_space.y = layout->bounds.y;
20272 empty_space.w = panel_padding.x + layout->border;
20273 empty_space.h = layout->bounds.h;
20274 nk_fill_rect(out, empty_space, 0, style->window.background);
20275
20276 /* fill right empty space */
20277 empty_space.x = layout->bounds.x + layout->bounds.w;
20278 empty_space.y = layout->bounds.y;
20279 empty_space.w = panel_padding.x + layout->border;
20280 empty_space.h = layout->bounds.h;
20281 if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))
20282 empty_space.w += scrollbar_size.x;
20283 nk_fill_rect(out, empty_space, 0, style->window.background);
20284
20285 /* fill bottom empty space */
20286 if (layout->footer_height > 0) {
20287 empty_space.x = window->bounds.x;
20288 empty_space.y = layout->bounds.y + layout->bounds.h;
20289 empty_space.w = window->bounds.w;
20290 empty_space.h = layout->footer_height;
20291 nk_fill_rect(out, empty_space, 0, style->window.background);
20292 }
20293 }
20294
20295 /* scrollbars */
20296 if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&
20297 !(layout->flags & NK_WINDOW_MINIMIZED) &&
20298 window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)
20299 {
20300 struct nk_rect scroll;
20301 int scroll_has_scrolling;
20302 float scroll_target;
20303 float scroll_offset;
20304 float scroll_step;
20305 float scroll_inc;
20306
20307 /* mouse wheel scrolling */
20308 if (nk_panel_is_sub(layout->type))
20309 {
20310 /* sub-window mouse wheel scrolling */
20311 struct nk_window *root_window = window;
20312 struct nk_panel *root_panel = window->layout;
20313 while (root_panel->parent)
20314 root_panel = root_panel->parent;
20315 while (root_window->parent)
20316 root_window = root_window->parent;
20317
20318 /* only allow scrolling if parent window is active */
20319 scroll_has_scrolling = nk_false;
20320 if ((root_window == ctx->active) && layout->has_scrolling) {
20321 /* and panel is being hovered and inside clip rect*/
20322 if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&
20323 NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,
20324 root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))
20325 {
20326 /* deactivate all parent scrolling */
20327 root_panel = window->layout;
20328 while (root_panel->parent) {
20329 root_panel->has_scrolling = nk_false;
20330 root_panel = root_panel->parent;
20331 }
20332 root_panel->has_scrolling = nk_false;
20333 scroll_has_scrolling = nk_true;
20334 }
20335 }
20336 } else {
20337 /* window mouse wheel scrolling */
20338 scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;
20339 if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)
20340 window->scrolled = nk_true;
20341 else window->scrolled = nk_false;
20342 }
20343
20344 {
20345 /* vertical scrollbar */
20346 nk_flags state = 0;
20347 scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
20348 scroll.y = layout->bounds.y;
20349 scroll.w = scrollbar_size.x;
20350 scroll.h = layout->bounds.h;
20351
20352 scroll_offset = (float)*layout->offset_y;
20353 scroll_step = scroll.h * 0.10f;
20354 scroll_inc = scroll.h * 0.01f;
20355 scroll_target = (float)(int)(layout->at_y - scroll.y);
20356 scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,
20357 scroll_offset, scroll_target, scroll_step, scroll_inc,
20358 &ctx->style.scrollv, in, style->font);
20359 *layout->offset_y = (nk_uint)scroll_offset;
20360 if (in && scroll_has_scrolling)
20361 in->mouse.scroll_delta.y = 0;
20362 }
20363 {
20364 /* horizontal scrollbar */
20365 nk_flags state = 0;
20366 scroll.x = layout->bounds.x;
20367 scroll.y = layout->bounds.y + layout->bounds.h;
20368 scroll.w = layout->bounds.w;
20369 scroll.h = scrollbar_size.y;
20370
20371 scroll_offset = (float)*layout->offset_x;
20372 scroll_target = (float)(int)(layout->max_x - scroll.x);
20373 scroll_step = layout->max_x * 0.05f;
20374 scroll_inc = layout->max_x * 0.005f;
20375 scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,
20376 scroll_offset, scroll_target, scroll_step, scroll_inc,
20377 &ctx->style.scrollh, in, style->font);
20378 *layout->offset_x = (nk_uint)scroll_offset;
20379 }
20380 }
20381
20382 /* hide scroll if no user input */
20383 if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {
20384 int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0;
20385 int is_window_hovered = nk_window_is_hovered(ctx);
20386 int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
20387 if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))
20388 window->scrollbar_hiding_timer += ctx->delta_time_seconds;
20389 else window->scrollbar_hiding_timer = 0;
20390 } else window->scrollbar_hiding_timer = 0;
20391
20392 /* window border */
20393 if (layout->flags & NK_WINDOW_BORDER)
20394 {
20395 struct nk_color border_color = nk_panel_get_border_color(style, layout->type);
20396 const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED)
20397 ? (style->window.border + window->bounds.y + layout->header_height)
20398 : ((layout->flags & NK_WINDOW_DYNAMIC)
20399 ? (layout->bounds.y + layout->bounds.h + layout->footer_height)
20400 : (window->bounds.y + window->bounds.h));
20401 struct nk_rect b = window->bounds;
20402 b.h = padding_y - window->bounds.y;
20403 nk_stroke_rect(out, b, style->window.rounding, layout->border, border_color);
20404 }
20405
20406 /* scaler */
20407 if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))
20408 {
20409 /* calculate scaler bounds */
20410 struct nk_rect scaler;
20411 scaler.w = scrollbar_size.x;
20412 scaler.h = scrollbar_size.y;
20413 scaler.y = layout->bounds.y + layout->bounds.h;
20414 if (layout->flags & NK_WINDOW_SCALE_LEFT)
20415 scaler.x = layout->bounds.x - panel_padding.x * 0.5f;
20416 else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;
20417 if (layout->flags & NK_WINDOW_NO_SCROLLBAR)
20418 scaler.x -= scaler.w;
20419
20420 /* draw scaler */
20421 {const struct nk_style_item *item = &style->window.scaler;
20422 if (item->type == NK_STYLE_ITEM_IMAGE)
20423 nk_draw_image(out, scaler, &item->data.image, nk_white);
20424 else {
20425 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
20426 nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,
20427 scaler.y + scaler.h, scaler.x + scaler.w,
20428 scaler.y + scaler.h, item->data.color);
20429 } else {
20430 nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,
20431 scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);
20432 }
20433 }}
20434
20435 /* do window scaling */
20436 if (!(window->flags & NK_WINDOW_ROM)) {
20437 struct nk_vec2 window_size = style->window.min_size;
20438 int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
20439 int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,
20440 NK_BUTTON_LEFT, scaler, nk_true);
20441
20442 if (left_mouse_down && left_mouse_click_in_scaler) {
20443 float delta_x = in->mouse.delta.x;
20444 if (layout->flags & NK_WINDOW_SCALE_LEFT) {
20445 delta_x = -delta_x;
20446 window->bounds.x += in->mouse.delta.x;
20447 }
20448 /* dragging in x-direction */
20449 if (window->bounds.w + delta_x >= window_size.x) {
20450 if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) {
20451 window->bounds.w = window->bounds.w + delta_x;
20452 scaler.x += in->mouse.delta.x;
20453 }
20454 }
20455 /* dragging in y-direction (only possible if static window) */
20456 if (!(layout->flags & NK_WINDOW_DYNAMIC)) {
20457 if (window_size.y < window->bounds.h + in->mouse.delta.y) {
20458 if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) {
20459 window->bounds.h = window->bounds.h + in->mouse.delta.y;
20460 scaler.y += in->mouse.delta.y;
20461 }
20462 }
20463 }
20464 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];
20465 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;
20466 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;
20467 }
20468 }
20469 }
20470 if (!nk_panel_is_sub(layout->type)) {
20471 /* window is hidden so clear command buffer */
20472 if (layout->flags & NK_WINDOW_HIDDEN)
20473 nk_command_buffer_reset(&window->buffer);
20474 /* window is visible and not tab */
20475 else nk_finish(ctx, window);
20476 }
20477
20478 /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */
20479 if (layout->flags & NK_WINDOW_REMOVE_ROM) {
20480 layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
20481 layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
20482 }
20483 window->flags = layout->flags;
20484
20485 /* property garbage collector */
20486 if (window->property.active && window->property.old != window->property.seq &&
20487 window->property.active == window->property.prev) {
20488 nk_zero(&window->property, sizeof(window->property));
20489 } else {
20490 window->property.old = window->property.seq;
20491 window->property.prev = window->property.active;
20492 window->property.seq = 0;
20493 }
20494 /* edit garbage collector */
20495 if (window->edit.active && window->edit.old != window->edit.seq &&
20496 window->edit.active == window->edit.prev) {
20497 nk_zero(&window->edit, sizeof(window->edit));
20498 } else {
20499 window->edit.old = window->edit.seq;
20500 window->edit.prev = window->edit.active;
20501 window->edit.seq = 0;
20502 }
20503 /* contextual garbage collector */
20504 if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {
20505 window->popup.con_count = 0;
20506 window->popup.con_old = 0;
20507 window->popup.active_con = 0;
20508 } else {
20509 window->popup.con_old = window->popup.con_count;
20510 window->popup.con_count = 0;
20511 }
20512 window->popup.combo_count = 0;
20513 /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */
20514 NK_ASSERT(!layout->row.tree_depth);
20515}
20516
20517
20518
20519
20520
20521/* ===============================================================
20522 *
20523 * WINDOW
20524 *
20525 * ===============================================================*/
20526NK_LIB void*
20527nk_create_window(struct nk_context *ctx)
20528{
20529 struct nk_page_element *elem;
20530 elem = nk_create_page_element(ctx);
20531 if (!elem) return 0;
20532 elem->data.win.seq = ctx->seq;
20533 return &elem->data.win;
20534}
20535NK_LIB void
20536nk_free_window(struct nk_context *ctx, struct nk_window *win)
20537{
20538 /* unlink windows from list */
20539 struct nk_table *it = win->tables;
20540 if (win->popup.win) {
20541 nk_free_window(ctx, win->popup.win);
20542 win->popup.win = 0;
20543 }
20544 win->next = 0;
20545 win->prev = 0;
20546
20547 while (it) {
20548 /*free window state tables */
20549 struct nk_table *n = it->next;
20550 nk_remove_table(win, it);
20551 nk_free_table(ctx, it);
20552 if (it == win->tables)
20553 win->tables = n;
20554 it = n;
20555 }
20556
20557 /* link windows into freelist */
20558 {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);
20559 struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);
20560 nk_free_page_element(ctx, pe);}
20561}
20562NK_LIB struct nk_window*
20563nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name)
20564{
20565 struct nk_window *iter;
20566 iter = ctx->begin;
20567 while (iter) {
20568 NK_ASSERT(iter != iter->next);
20569 if (iter->name == hash) {
20570 int max_len = nk_strlen(iter->name_string);
20571 if (!nk_stricmpn(iter->name_string, name, max_len))
20572 return iter;
20573 }
20574 iter = iter->next;
20575 }
20576 return 0;
20577}
20578NK_LIB void
20579nk_insert_window(struct nk_context *ctx, struct nk_window *win,
20580 enum nk_window_insert_location loc)
20581{
20582 const struct nk_window *iter;
20583 NK_ASSERT(ctx);
20584 NK_ASSERT(win);
20585 if (!win || !ctx) return;
20586
20587 iter = ctx->begin;
20588 while (iter) {
20589 NK_ASSERT(iter != iter->next);
20590 NK_ASSERT(iter != win);
20591 if (iter == win) return;
20592 iter = iter->next;
20593 }
20594
20595 if (!ctx->begin) {
20596 win->next = 0;
20597 win->prev = 0;
20598 ctx->begin = win;
20599 ctx->end = win;
20600 ctx->count = 1;
20601 return;
20602 }
20603 if (loc == NK_INSERT_BACK) {
20604 struct nk_window *end;
20605 end = ctx->end;
20606 end->flags |= NK_WINDOW_ROM;
20607 end->next = win;
20608 win->prev = ctx->end;
20609 win->next = 0;
20610 ctx->end = win;
20611 ctx->active = ctx->end;
20612 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
20613 } else {
20614 /*ctx->end->flags |= NK_WINDOW_ROM;*/
20615 ctx->begin->prev = win;
20616 win->next = ctx->begin;
20617 win->prev = 0;
20618 ctx->begin = win;
20619 ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;
20620 }
20621 ctx->count++;
20622}
20623NK_LIB void
20624nk_remove_window(struct nk_context *ctx, struct nk_window *win)
20625{
20626 if (win == ctx->begin || win == ctx->end) {
20627 if (win == ctx->begin) {
20628 ctx->begin = win->next;
20629 if (win->next)
20630 win->next->prev = 0;
20631 }
20632 if (win == ctx->end) {
20633 ctx->end = win->prev;
20634 if (win->prev)
20635 win->prev->next = 0;
20636 }
20637 } else {
20638 if (win->next)
20639 win->next->prev = win->prev;
20640 if (win->prev)
20641 win->prev->next = win->next;
20642 }
20643 if (win == ctx->active || !ctx->active) {
20644 ctx->active = ctx->end;
20645 if (ctx->end)
20646 ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;
20647 }
20648 win->next = 0;
20649 win->prev = 0;
20650 ctx->count--;
20651}
20652NK_API nk_bool
20653nk_begin(struct nk_context *ctx, const char *title,
20654 struct nk_rect bounds, nk_flags flags)
20655{
20656 return nk_begin_titled(ctx, title, title, bounds, flags);
20657}
20658NK_API nk_bool
20659nk_begin_titled(struct nk_context *ctx, const char *name, const char *title,
20660 struct nk_rect bounds, nk_flags flags)
20661{
20662 struct nk_window *win;
20663 struct nk_style *style;
20664 nk_hash name_hash;
20665 int name_len;
20666 int ret = 0;
20667
20668 NK_ASSERT(ctx);
20669 NK_ASSERT(name);
20670 NK_ASSERT(title);
20671 NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font");
20672 NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call");
20673 if (!ctx || ctx->current || !title || !name)
20674 return 0;
20675
20676 /* find or create window */
20677 style = &ctx->style;
20678 name_len = (int)nk_strlen(name);
20679 name_hash = nk_murmur_hash(name, (int)name_len, NK_WINDOW_TITLE);
20680 win = nk_find_window(ctx, name_hash, name);
20681 if (!win) {
20682 /* create new window */
20683 nk_size name_length = (nk_size)name_len;
20684 win = (struct nk_window*)nk_create_window(ctx);
20685 NK_ASSERT(win);
20686 if (!win) return 0;
20687
20688 if (flags & NK_WINDOW_BACKGROUND)
20689 nk_insert_window(ctx, win, NK_INSERT_FRONT);
20690 else nk_insert_window(ctx, win, NK_INSERT_BACK);
20691 nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);
20692
20693 win->flags = flags;
20694 win->bounds = bounds;
20695 win->name = name_hash;
20696 name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);
20697 NK_MEMCPY(win->name_string, name, name_length);
20698 win->name_string[name_length] = 0;
20699 win->popup.win = 0;
20700 win->widgets_disabled = nk_false;
20701 if (!ctx->active)
20702 ctx->active = win;
20703 } else {
20704 /* update window */
20705 win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);
20706 win->flags |= flags;
20707 if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))
20708 win->bounds = bounds;
20709 /* If this assert triggers you either:
20710 *
20711 * I.) Have more than one window with the same name or
20712 * II.) You forgot to actually draw the window.
20713 * More specific you did not call `nk_clear` (nk_clear will be
20714 * automatically called for you if you are using one of the
20715 * provided demo backends). */
20716 NK_ASSERT(win->seq != ctx->seq);
20717 win->seq = ctx->seq;
20718 if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) {
20719 ctx->active = win;
20720 ctx->end = win;
20721 }
20722 }
20723 if (win->flags & NK_WINDOW_HIDDEN) {
20724 ctx->current = win;
20725 win->layout = 0;
20726 return 0;
20727 } else nk_start(ctx, win);
20728
20729 /* window overlapping */
20730 if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))
20731 {
20732 int inpanel, ishovered;
20733 struct nk_window *iter = win;
20734 float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +
20735 (2.0f * style->window.header.label_padding.y);
20736 struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?
20737 win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);
20738
20739 /* activate window if hovered and no other window is overlapping this window */
20740 inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);
20741 inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;
20742 ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);
20743 if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {
20744 iter = win->next;
20745 while (iter) {
20746 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
20747 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
20748 if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
20749 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
20750 (!(iter->flags & NK_WINDOW_HIDDEN)))
20751 break;
20752
20753 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
20754 NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
20755 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
20756 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
20757 break;
20758 iter = iter->next;
20759 }
20760 }
20761
20762 /* activate window if clicked */
20763 if (iter && inpanel && (win != ctx->end)) {
20764 iter = win->next;
20765 while (iter) {
20766 /* try to find a panel with higher priority in the same position */
20767 struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?
20768 iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);
20769 if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,
20770 iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&
20771 !(iter->flags & NK_WINDOW_HIDDEN))
20772 break;
20773 if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&
20774 NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,
20775 iter->popup.win->bounds.x, iter->popup.win->bounds.y,
20776 iter->popup.win->bounds.w, iter->popup.win->bounds.h))
20777 break;
20778 iter = iter->next;
20779 }
20780 }
20781 if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) {
20782 win->flags |= (nk_flags)NK_WINDOW_ROM;
20783 iter->flags &= ~(nk_flags)NK_WINDOW_ROM;
20784 ctx->active = iter;
20785 if (!(iter->flags & NK_WINDOW_BACKGROUND)) {
20786 /* current window is active in that position so transfer to top
20787 * at the highest priority in stack */
20788 nk_remove_window(ctx, iter);
20789 nk_insert_window(ctx, iter, NK_INSERT_BACK);
20790 }
20791 } else {
20792 if (!iter && ctx->end != win) {
20793 if (!(win->flags & NK_WINDOW_BACKGROUND)) {
20794 /* current window is active in that position so transfer to top
20795 * at the highest priority in stack */
20796 nk_remove_window(ctx, win);
20797 nk_insert_window(ctx, win, NK_INSERT_BACK);
20798 }
20799 win->flags &= ~(nk_flags)NK_WINDOW_ROM;
20800 ctx->active = win;
20801 }
20802 if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))
20803 win->flags |= NK_WINDOW_ROM;
20804 }
20805 }
20806 win->layout = (struct nk_panel*)nk_create_panel(ctx);
20807 ctx->current = win;
20808 ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);
20809 win->layout->offset_x = &win->scrollbar.x;
20810 win->layout->offset_y = &win->scrollbar.y;
20811 return ret;
20812}
20813NK_API void
20814nk_end(struct nk_context *ctx)
20815{
20816 struct nk_panel *layout;
20817 NK_ASSERT(ctx);
20818 NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`");
20819 if (!ctx || !ctx->current)
20820 return;
20821
20822 layout = ctx->current->layout;
20823 if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {
20824 ctx->current = 0;
20825 return;
20826 }
20827 nk_panel_end(ctx);
20828 nk_free_panel(ctx, ctx->current->layout);
20829 ctx->current = 0;
20830}
20831NK_API struct nk_rect
20832nk_window_get_bounds(const struct nk_context *ctx)
20833{
20834 NK_ASSERT(ctx);
20835 NK_ASSERT(ctx->current);
20836 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
20837 return ctx->current->bounds;
20838}
20839NK_API struct nk_vec2
20840nk_window_get_position(const struct nk_context *ctx)
20841{
20842 NK_ASSERT(ctx);
20843 NK_ASSERT(ctx->current);
20844 if (!ctx || !ctx->current) return nk_vec2(0,0);
20845 return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);
20846}
20847NK_API struct nk_vec2
20848nk_window_get_size(const struct nk_context *ctx)
20849{
20850 NK_ASSERT(ctx);
20851 NK_ASSERT(ctx->current);
20852 if (!ctx || !ctx->current) return nk_vec2(0,0);
20853 return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);
20854}
20855NK_API float
20856nk_window_get_width(const struct nk_context *ctx)
20857{
20858 NK_ASSERT(ctx);
20859 NK_ASSERT(ctx->current);
20860 if (!ctx || !ctx->current) return 0;
20861 return ctx->current->bounds.w;
20862}
20863NK_API float
20864nk_window_get_height(const struct nk_context *ctx)
20865{
20866 NK_ASSERT(ctx);
20867 NK_ASSERT(ctx->current);
20868 if (!ctx || !ctx->current) return 0;
20869 return ctx->current->bounds.h;
20870}
20871NK_API struct nk_rect
20873{
20874 NK_ASSERT(ctx);
20875 NK_ASSERT(ctx->current);
20876 if (!ctx || !ctx->current) return nk_rect(0,0,0,0);
20877 return ctx->current->layout->clip;
20878}
20879NK_API struct nk_vec2
20881{
20882 NK_ASSERT(ctx);
20883 NK_ASSERT(ctx->current);
20884 NK_ASSERT(ctx->current->layout);
20885 if (!ctx || !ctx->current) return nk_vec2(0,0);
20886 return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);
20887}
20888NK_API struct nk_vec2
20890{
20891 NK_ASSERT(ctx);
20892 NK_ASSERT(ctx->current);
20893 NK_ASSERT(ctx->current->layout);
20894 if (!ctx || !ctx->current) return nk_vec2(0,0);
20895 return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,
20896 ctx->current->layout->clip.y + ctx->current->layout->clip.h);
20897}
20898NK_API struct nk_vec2
20900{
20901 NK_ASSERT(ctx);
20902 NK_ASSERT(ctx->current);
20903 NK_ASSERT(ctx->current->layout);
20904 if (!ctx || !ctx->current) return nk_vec2(0,0);
20905 return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);
20906}
20907NK_API struct nk_command_buffer*
20908nk_window_get_canvas(const struct nk_context *ctx)
20909{
20910 NK_ASSERT(ctx);
20911 NK_ASSERT(ctx->current);
20912 NK_ASSERT(ctx->current->layout);
20913 if (!ctx || !ctx->current) return 0;
20914 return &ctx->current->buffer;
20915}
20916NK_API struct nk_panel*
20917nk_window_get_panel(const struct nk_context *ctx)
20918{
20919 NK_ASSERT(ctx);
20920 NK_ASSERT(ctx->current);
20921 if (!ctx || !ctx->current) return 0;
20922 return ctx->current->layout;
20923}
20924NK_API void
20925nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
20926{
20927 struct nk_window *win;
20928 NK_ASSERT(ctx);
20929 NK_ASSERT(ctx->current);
20930 if (!ctx || !ctx->current)
20931 return ;
20932 win = ctx->current;
20933 if (offset_x)
20934 *offset_x = win->scrollbar.x;
20935 if (offset_y)
20936 *offset_y = win->scrollbar.y;
20937}
20938NK_API nk_bool
20939nk_window_has_focus(const struct nk_context *ctx)
20940{
20941 NK_ASSERT(ctx);
20942 NK_ASSERT(ctx->current);
20943 NK_ASSERT(ctx->current->layout);
20944 if (!ctx || !ctx->current) return 0;
20945 return ctx->current == ctx->active;
20946}
20947NK_API nk_bool
20948nk_window_is_hovered(const struct nk_context *ctx)
20949{
20950 NK_ASSERT(ctx);
20951 NK_ASSERT(ctx->current);
20952 if (!ctx || !ctx->current || (ctx->current->flags & NK_WINDOW_HIDDEN))
20953 return 0;
20954 else {
20955 struct nk_rect actual_bounds = ctx->current->bounds;
20956 if (ctx->begin->flags & NK_WINDOW_MINIMIZED) {
20957 actual_bounds.h = ctx->current->layout->header_height;
20958 }
20959 return nk_input_is_mouse_hovering_rect(&ctx->input, actual_bounds);
20960 }
20961}
20962NK_API nk_bool
20963nk_window_is_any_hovered(const struct nk_context *ctx)
20964{
20965 struct nk_window *iter;
20966 NK_ASSERT(ctx);
20967 if (!ctx) return 0;
20968 iter = ctx->begin;
20969 while (iter) {
20970 /* check if window is being hovered */
20971 if(!(iter->flags & NK_WINDOW_HIDDEN)) {
20972 /* check if window popup is being hovered */
20973 if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))
20974 return 1;
20975
20976 if (iter->flags & NK_WINDOW_MINIMIZED) {
20977 struct nk_rect header = iter->bounds;
20978 header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;
20979 if (nk_input_is_mouse_hovering_rect(&ctx->input, header))
20980 return 1;
20981 } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {
20982 return 1;
20983 }
20984 }
20985 iter = iter->next;
20986 }
20987 return 0;
20988}
20989NK_API nk_bool
20990nk_item_is_any_active(const struct nk_context *ctx)
20991{
20992 int any_hovered = nk_window_is_any_hovered(ctx);
20993 int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
20994 return any_hovered || any_active;
20995}
20996NK_API nk_bool
20997nk_window_is_collapsed(const struct nk_context *ctx, const char *name)
20998{
20999 int title_len;
21000 nk_hash title_hash;
21001 struct nk_window *win;
21002 NK_ASSERT(ctx);
21003 if (!ctx) return 0;
21004
21005 title_len = (int)nk_strlen(name);
21006 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21007 win = nk_find_window(ctx, title_hash, name);
21008 if (!win) return 0;
21009 return win->flags & NK_WINDOW_MINIMIZED;
21010}
21011NK_API nk_bool
21012nk_window_is_closed(const struct nk_context *ctx, const char *name)
21013{
21014 int title_len;
21015 nk_hash title_hash;
21016 struct nk_window *win;
21017 NK_ASSERT(ctx);
21018 if (!ctx) return 1;
21019
21020 title_len = (int)nk_strlen(name);
21021 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21022 win = nk_find_window(ctx, title_hash, name);
21023 if (!win) return 1;
21024 return (win->flags & NK_WINDOW_CLOSED);
21025}
21026NK_API nk_bool
21027nk_window_is_hidden(const struct nk_context *ctx, const char *name)
21028{
21029 int title_len;
21030 nk_hash title_hash;
21031 struct nk_window *win;
21032 NK_ASSERT(ctx);
21033 if (!ctx) return 1;
21034
21035 title_len = (int)nk_strlen(name);
21036 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21037 win = nk_find_window(ctx, title_hash, name);
21038 if (!win) return 1;
21039 return (win->flags & NK_WINDOW_HIDDEN);
21040}
21041NK_API nk_bool
21042nk_window_is_active(const struct nk_context *ctx, const char *name)
21043{
21044 int title_len;
21045 nk_hash title_hash;
21046 struct nk_window *win;
21047 NK_ASSERT(ctx);
21048 if (!ctx) return 0;
21049
21050 title_len = (int)nk_strlen(name);
21051 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21052 win = nk_find_window(ctx, title_hash, name);
21053 if (!win) return 0;
21054 return win == ctx->active;
21055}
21056NK_API struct nk_window*
21057nk_window_find(const struct nk_context *ctx, const char *name)
21058{
21059 int title_len;
21060 nk_hash title_hash;
21061 title_len = (int)nk_strlen(name);
21062 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21063 return nk_find_window(ctx, title_hash, name);
21064}
21065NK_API void
21066nk_window_close(struct nk_context *ctx, const char *name)
21067{
21068 struct nk_window *win;
21069 NK_ASSERT(ctx);
21070 if (!ctx) return;
21071 win = nk_window_find(ctx, name);
21072 if (!win) return;
21073 NK_ASSERT(ctx->current != win && "You cannot close a currently active window");
21074 if (ctx->current == win) return;
21075 win->flags |= NK_WINDOW_HIDDEN;
21076 win->flags |= NK_WINDOW_CLOSED;
21077}
21078NK_API void
21080 const char *name, struct nk_rect bounds)
21081{
21082 struct nk_window *win;
21083 NK_ASSERT(ctx);
21084 if (!ctx) return;
21085 win = nk_window_find(ctx, name);
21086 if (!win) return;
21087 win->bounds = bounds;
21088}
21089NK_API void
21091 const char *name, struct nk_vec2 pos)
21092{
21093 struct nk_window *win = nk_window_find(ctx, name);
21094 if (!win) return;
21095 win->bounds.x = pos.x;
21096 win->bounds.y = pos.y;
21097}
21098NK_API void
21099nk_window_set_size(struct nk_context *ctx,
21100 const char *name, struct nk_vec2 size)
21101{
21102 struct nk_window *win = nk_window_find(ctx, name);
21103 if (!win) return;
21104 win->bounds.w = size.x;
21105 win->bounds.h = size.y;
21106}
21107NK_API void
21108nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)
21109{
21110 struct nk_window *win;
21111 NK_ASSERT(ctx);
21112 NK_ASSERT(ctx->current);
21113 if (!ctx || !ctx->current)
21114 return;
21115 win = ctx->current;
21116 win->scrollbar.x = offset_x;
21117 win->scrollbar.y = offset_y;
21118}
21119NK_API void
21120nk_window_collapse(struct nk_context *ctx, const char *name,
21121 enum nk_collapse_states c)
21122{
21123 int title_len;
21124 nk_hash title_hash;
21125 struct nk_window *win;
21126 NK_ASSERT(ctx);
21127 if (!ctx) return;
21128
21129 title_len = (int)nk_strlen(name);
21130 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21131 win = nk_find_window(ctx, title_hash, name);
21132 if (!win) return;
21133 if (c == NK_MINIMIZED)
21134 win->flags |= NK_WINDOW_MINIMIZED;
21135 else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;
21136}
21137NK_API void
21138nk_window_collapse_if(struct nk_context *ctx, const char *name,
21139 enum nk_collapse_states c, int cond)
21140{
21141 NK_ASSERT(ctx);
21142 if (!ctx || !cond) return;
21143 nk_window_collapse(ctx, name, c);
21144}
21145NK_API void
21146nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)
21147{
21148 int title_len;
21149 nk_hash title_hash;
21150 struct nk_window *win;
21151 NK_ASSERT(ctx);
21152 if (!ctx) return;
21153
21154 title_len = (int)nk_strlen(name);
21155 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21156 win = nk_find_window(ctx, title_hash, name);
21157 if (!win) return;
21158 if (s == NK_HIDDEN) {
21159 win->flags |= NK_WINDOW_HIDDEN;
21160 } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;
21161}
21162NK_API void
21163nk_window_show_if(struct nk_context *ctx, const char *name,
21164 enum nk_show_states s, int cond)
21165{
21166 NK_ASSERT(ctx);
21167 if (!ctx || !cond) return;
21168 nk_window_show(ctx, name, s);
21169}
21170
21171NK_API void
21172nk_window_set_focus(struct nk_context *ctx, const char *name)
21173{
21174 int title_len;
21175 nk_hash title_hash;
21176 struct nk_window *win;
21177 NK_ASSERT(ctx);
21178 if (!ctx) return;
21179
21180 title_len = (int)nk_strlen(name);
21181 title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);
21182 win = nk_find_window(ctx, title_hash, name);
21183 if (win && ctx->end != win) {
21184 nk_remove_window(ctx, win);
21185 nk_insert_window(ctx, win, NK_INSERT_BACK);
21186 }
21187 ctx->active = win;
21188}
21189NK_API void
21190nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)
21191{
21192 struct nk_rect space;
21193 enum nk_widget_layout_states state = nk_widget(&space, ctx);
21194 struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
21195 if (!state) return;
21196 nk_fill_rect(canvas, space, rounding && space.h > 1.5f ? space.h / 2.0f : 0, color);
21197}
21198
21199
21200
21201
21202/* ===============================================================
21203 *
21204 * POPUP
21205 *
21206 * ===============================================================*/
21207NK_API nk_bool
21208nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,
21209 const char *title, nk_flags flags, struct nk_rect rect)
21210{
21211 struct nk_window *popup;
21212 struct nk_window *win;
21213 struct nk_panel *panel;
21214
21215 int title_len;
21216 nk_hash title_hash;
21217 nk_size allocated;
21218
21219 NK_ASSERT(ctx);
21220 NK_ASSERT(title);
21221 NK_ASSERT(ctx->current);
21222 NK_ASSERT(ctx->current->layout);
21223 if (!ctx || !ctx->current || !ctx->current->layout)
21224 return 0;
21225
21226 win = ctx->current;
21227 panel = win->layout;
21228 NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP) && "popups are not allowed to have popups");
21229 (void)panel;
21230 title_len = (int)nk_strlen(title);
21231 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);
21232
21233 popup = win->popup.win;
21234 if (!popup) {
21235 popup = (struct nk_window*)nk_create_window(ctx);
21236 popup->parent = win;
21237 win->popup.win = popup;
21238 win->popup.active = 0;
21239 win->popup.type = NK_PANEL_POPUP;
21240 }
21241
21242 /* make sure we have correct popup */
21243 if (win->popup.name != title_hash) {
21244 if (!win->popup.active) {
21245 nk_zero(popup, sizeof(*popup));
21246 win->popup.name = title_hash;
21247 win->popup.active = 1;
21248 win->popup.type = NK_PANEL_POPUP;
21249 } else return 0;
21250 }
21251
21252 /* popup position is local to window */
21253 ctx->current = popup;
21254 rect.x += win->layout->clip.x;
21255 rect.y += win->layout->clip.y;
21256
21257 /* setup popup data */
21258 popup->parent = win;
21259 popup->bounds = rect;
21260 popup->seq = ctx->seq;
21261 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
21262 popup->flags = flags;
21263 popup->flags |= NK_WINDOW_BORDER;
21264 if (type == NK_POPUP_DYNAMIC)
21265 popup->flags |= NK_WINDOW_DYNAMIC;
21266
21267 popup->buffer = win->buffer;
21268 nk_start_popup(ctx, win);
21269 allocated = ctx->memory.allocated;
21270 nk_push_scissor(&popup->buffer, nk_null_rect);
21271
21272 if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {
21273 /* popup is running therefore invalidate parent panels */
21274 struct nk_panel *root;
21275 root = win->layout;
21276 while (root) {
21277 root->flags |= NK_WINDOW_ROM;
21278 root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;
21279 root = root->parent;
21280 }
21281 win->popup.active = 1;
21282 popup->layout->offset_x = &popup->scrollbar.x;
21283 popup->layout->offset_y = &popup->scrollbar.y;
21284 popup->layout->parent = win->layout;
21285 return 1;
21286 } else {
21287 /* popup was closed/is invalid so cleanup */
21288 struct nk_panel *root;
21289 root = win->layout;
21290 while (root) {
21291 root->flags |= NK_WINDOW_REMOVE_ROM;
21292 root = root->parent;
21293 }
21294 win->popup.buf.active = 0;
21295 win->popup.active = 0;
21296 ctx->memory.allocated = allocated;
21297 ctx->current = win;
21298 nk_free_panel(ctx, popup->layout);
21299 popup->layout = 0;
21300 return 0;
21301 }
21302}
21303NK_LIB nk_bool
21304nk_nonblock_begin(struct nk_context *ctx,
21305 nk_flags flags, struct nk_rect body, struct nk_rect header,
21306 enum nk_panel_type panel_type)
21307{
21308 struct nk_window *popup;
21309 struct nk_window *win;
21310 struct nk_panel *panel;
21311 int is_active = nk_true;
21312
21313 NK_ASSERT(ctx);
21314 NK_ASSERT(ctx->current);
21315 NK_ASSERT(ctx->current->layout);
21316 if (!ctx || !ctx->current || !ctx->current->layout)
21317 return 0;
21318
21319 /* popups cannot have popups */
21320 win = ctx->current;
21321 panel = win->layout;
21322 NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP));
21323 (void)panel;
21324 popup = win->popup.win;
21325 if (!popup) {
21326 /* create window for nonblocking popup */
21327 popup = (struct nk_window*)nk_create_window(ctx);
21328 popup->parent = win;
21329 win->popup.win = popup;
21330 win->popup.type = panel_type;
21331 nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);
21332 } else {
21333 /* close the popup if user pressed outside or in the header */
21334 int pressed, in_body, in_header;
21335#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
21336 pressed = nk_input_is_mouse_released(&ctx->input, NK_BUTTON_LEFT);
21337#else
21338 pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
21339#endif
21340 in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
21341 in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);
21342 if (pressed && (!in_body || in_header))
21343 is_active = nk_false;
21344 }
21345 win->popup.header = header;
21346
21347 if (!is_active) {
21348 /* remove read only mode from all parent panels */
21349 struct nk_panel *root = win->layout;
21350 while (root) {
21351 root->flags |= NK_WINDOW_REMOVE_ROM;
21352 root = root->parent;
21353 }
21354 return is_active;
21355 }
21356 popup->bounds = body;
21357 popup->parent = win;
21358 popup->layout = (struct nk_panel*)nk_create_panel(ctx);
21359 popup->flags = flags;
21360 popup->flags |= NK_WINDOW_BORDER;
21361 popup->flags |= NK_WINDOW_DYNAMIC;
21362 popup->seq = ctx->seq;
21363 win->popup.active = 1;
21364 NK_ASSERT(popup->layout);
21365
21366 nk_start_popup(ctx, win);
21367 popup->buffer = win->buffer;
21368 nk_push_scissor(&popup->buffer, nk_null_rect);
21369 ctx->current = popup;
21370
21371 nk_panel_begin(ctx, 0, panel_type);
21372 win->buffer = popup->buffer;
21373 popup->layout->parent = win->layout;
21374 popup->layout->offset_x = &popup->scrollbar.x;
21375 popup->layout->offset_y = &popup->scrollbar.y;
21376
21377 /* set read only mode to all parent panels */
21378 {struct nk_panel *root;
21379 root = win->layout;
21380 while (root) {
21381 root->flags |= NK_WINDOW_ROM;
21382 root = root->parent;
21383 }}
21384 return is_active;
21385}
21386NK_API void
21387nk_popup_close(struct nk_context *ctx)
21388{
21389 struct nk_window *popup;
21390 NK_ASSERT(ctx);
21391 if (!ctx || !ctx->current) return;
21392
21393 popup = ctx->current;
21394 NK_ASSERT(popup->parent);
21395 NK_ASSERT((int)popup->layout->type & (int)NK_PANEL_SET_POPUP);
21396 popup->flags |= NK_WINDOW_HIDDEN;
21397}
21398NK_API void
21399nk_popup_end(struct nk_context *ctx)
21400{
21401 struct nk_window *win;
21402 struct nk_window *popup;
21403
21404 NK_ASSERT(ctx);
21405 NK_ASSERT(ctx->current);
21406 NK_ASSERT(ctx->current->layout);
21407 if (!ctx || !ctx->current || !ctx->current->layout)
21408 return;
21409
21410 popup = ctx->current;
21411 if (!popup->parent) return;
21412 win = popup->parent;
21413 if (popup->flags & NK_WINDOW_HIDDEN) {
21414 struct nk_panel *root;
21415 root = win->layout;
21416 while (root) {
21417 root->flags |= NK_WINDOW_REMOVE_ROM;
21418 root = root->parent;
21419 }
21420 win->popup.active = 0;
21421 }
21422 nk_push_scissor(&popup->buffer, nk_null_rect);
21423 nk_end(ctx);
21424
21425 win->buffer = popup->buffer;
21426 nk_finish_popup(ctx, win);
21427 ctx->current = win;
21428 nk_push_scissor(&win->buffer, win->layout->clip);
21429}
21430NK_API void
21431nk_popup_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
21432{
21433 struct nk_window *popup;
21434
21435 NK_ASSERT(ctx);
21436 NK_ASSERT(ctx->current);
21437 NK_ASSERT(ctx->current->layout);
21438 if (!ctx || !ctx->current || !ctx->current->layout)
21439 return;
21440
21441 popup = ctx->current;
21442 if (offset_x)
21443 *offset_x = popup->scrollbar.x;
21444 if (offset_y)
21445 *offset_y = popup->scrollbar.y;
21446}
21447NK_API void
21448nk_popup_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)
21449{
21450 struct nk_window *popup;
21451
21452 NK_ASSERT(ctx);
21453 NK_ASSERT(ctx->current);
21454 NK_ASSERT(ctx->current->layout);
21455 if (!ctx || !ctx->current || !ctx->current->layout)
21456 return;
21457
21458 popup = ctx->current;
21459 popup->scrollbar.x = offset_x;
21460 popup->scrollbar.y = offset_y;
21461}
21462
21463
21464
21465
21466/* ==============================================================
21467 *
21468 * CONTEXTUAL
21469 *
21470 * ===============================================================*/
21471NK_API nk_bool
21472nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,
21473 struct nk_rect trigger_bounds)
21474{
21475 struct nk_window *win;
21476 struct nk_window *popup;
21477 struct nk_rect body;
21478 struct nk_input* in;
21479
21480 NK_STORAGE const struct nk_rect null_rect = {-1,-1,0,0};
21481 int is_clicked = 0;
21482 int is_open = 0;
21483 int ret = 0;
21484
21485 NK_ASSERT(ctx);
21486 NK_ASSERT(ctx->current);
21487 NK_ASSERT(ctx->current->layout);
21488 if (!ctx || !ctx->current || !ctx->current->layout)
21489 return 0;
21490
21491 win = ctx->current;
21492 ++win->popup.con_count;
21493 if (ctx->current != ctx->active)
21494 return 0;
21495
21496 /* check if currently active contextual is active */
21497 popup = win->popup.win;
21498 is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);
21499 in = win->widgets_disabled ? 0 : &ctx->input;
21500 if (in) {
21501 is_clicked = nk_input_mouse_clicked(in, NK_BUTTON_RIGHT, trigger_bounds);
21502 if (win->popup.active_con && win->popup.con_count != win->popup.active_con)
21503 return 0;
21504 if (!is_open && win->popup.active_con)
21505 win->popup.active_con = 0;
21506 if ((!is_open && !is_clicked))
21507 return 0;
21508
21509 /* calculate contextual position on click */
21510 win->popup.active_con = win->popup.con_count;
21511 if (is_clicked) {
21512 body.x = in->mouse.pos.x;
21513 body.y = in->mouse.pos.y;
21514 } else {
21515 body.x = popup->bounds.x;
21516 body.y = popup->bounds.y;
21517 }
21518
21519 body.w = size.x;
21520 body.h = size.y;
21521
21522 /* start nonblocking contextual popup */
21523 ret = nk_nonblock_begin(ctx, flags | NK_WINDOW_NO_SCROLLBAR, body,
21524 null_rect, NK_PANEL_CONTEXTUAL);
21525 if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;
21526 else {
21527 win->popup.active_con = 0;
21528 win->popup.type = NK_PANEL_NONE;
21529 if (win->popup.win)
21530 win->popup.win->flags = 0;
21531 }
21532 }
21533 return ret;
21534}
21535NK_API nk_bool
21536nk_contextual_item_text(struct nk_context *ctx, const char *text, int len,
21537 nk_flags alignment)
21538{
21539 struct nk_window *win;
21540 const struct nk_input *in;
21541 const struct nk_style *style;
21542
21543 struct nk_rect bounds;
21544 enum nk_widget_layout_states state;
21545
21546 NK_ASSERT(ctx);
21547 NK_ASSERT(ctx->current);
21548 NK_ASSERT(ctx->current->layout);
21549 if (!ctx || !ctx->current || !ctx->current->layout)
21550 return 0;
21551
21552 win = ctx->current;
21553 style = &ctx->style;
21554 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21555 if (!state) return nk_false;
21556
21557 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21558 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
21559 text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {
21560 nk_contextual_close(ctx);
21561 return nk_true;
21562 }
21563 return nk_false;
21564}
21565NK_API nk_bool
21566nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)
21567{
21568 return nk_contextual_item_text(ctx, label, nk_strlen(label), align);
21569}
21570NK_API nk_bool
21571nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,
21572 const char *text, int len, nk_flags align)
21573{
21574 struct nk_window *win;
21575 const struct nk_input *in;
21576 const struct nk_style *style;
21577
21578 struct nk_rect bounds;
21579 enum nk_widget_layout_states state;
21580
21581 NK_ASSERT(ctx);
21582 NK_ASSERT(ctx->current);
21583 NK_ASSERT(ctx->current->layout);
21584 if (!ctx || !ctx->current || !ctx->current->layout)
21585 return 0;
21586
21587 win = ctx->current;
21588 style = &ctx->style;
21589 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21590 if (!state) return nk_false;
21591
21592 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21593 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,
21594 img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){
21595 nk_contextual_close(ctx);
21596 return nk_true;
21597 }
21598 return nk_false;
21599}
21600NK_API nk_bool
21601nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,
21602 const char *label, nk_flags align)
21603{
21604 return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);
21605}
21606NK_API nk_bool
21607nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
21608 const char *text, int len, nk_flags align)
21609{
21610 struct nk_window *win;
21611 const struct nk_input *in;
21612 const struct nk_style *style;
21613
21614 struct nk_rect bounds;
21615 enum nk_widget_layout_states state;
21616
21617 NK_ASSERT(ctx);
21618 NK_ASSERT(ctx->current);
21619 NK_ASSERT(ctx->current->layout);
21620 if (!ctx || !ctx->current || !ctx->current->layout)
21621 return 0;
21622
21623 win = ctx->current;
21624 style = &ctx->style;
21625 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
21626 if (!state) return nk_false;
21627
21628 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21629 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
21630 symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {
21631 nk_contextual_close(ctx);
21632 return nk_true;
21633 }
21634 return nk_false;
21635}
21636NK_API nk_bool
21637nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
21638 const char *text, nk_flags align)
21639{
21640 return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);
21641}
21642NK_API void
21643nk_contextual_close(struct nk_context *ctx)
21644{
21645 NK_ASSERT(ctx);
21646 NK_ASSERT(ctx->current);
21647 NK_ASSERT(ctx->current->layout);
21648 if (!ctx || !ctx->current || !ctx->current->layout) return;
21649 nk_popup_close(ctx);
21650}
21651NK_API void
21652nk_contextual_end(struct nk_context *ctx)
21653{
21654 struct nk_window *popup;
21655 struct nk_panel *panel;
21656 NK_ASSERT(ctx);
21657 NK_ASSERT(ctx->current);
21658 if (!ctx || !ctx->current) return;
21659
21660 popup = ctx->current;
21661 panel = popup->layout;
21662 NK_ASSERT(popup->parent);
21663 NK_ASSERT((int)panel->type & (int)NK_PANEL_SET_POPUP);
21664 if (panel->flags & NK_WINDOW_DYNAMIC) {
21665 /* Close behavior
21666 This is a bit of a hack solution since we do not know before we end our popup
21667 how big it will be. We therefore do not directly know when a
21668 click outside the non-blocking popup must close it at that direct frame.
21669 Instead it will be closed in the next frame.*/
21670 struct nk_rect body = {0,0,0,0};
21671 if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {
21672 struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);
21673 body = panel->bounds;
21674 body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);
21675 body.h = (panel->bounds.y + panel->bounds.h) - body.y;
21676 }
21677 {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
21678 int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
21679 if (pressed && in_body)
21680 popup->flags |= NK_WINDOW_HIDDEN;
21681 }
21682 }
21683 if (popup->flags & NK_WINDOW_HIDDEN)
21684 popup->seq = 0;
21685 nk_popup_end(ctx);
21686 return;
21687}
21688
21689
21690
21691
21692
21693/* ===============================================================
21694 *
21695 * MENU
21696 *
21697 * ===============================================================*/
21698NK_API void
21699nk_menubar_begin(struct nk_context *ctx)
21700{
21701 struct nk_panel *layout;
21702 NK_ASSERT(ctx);
21703 NK_ASSERT(ctx->current);
21704 NK_ASSERT(ctx->current->layout);
21705 if (!ctx || !ctx->current || !ctx->current->layout)
21706 return;
21707
21708 layout = ctx->current->layout;
21709 NK_ASSERT(layout->at_y == layout->bounds.y);
21710 /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.
21711 If you want a menubar the first nuklear function after `nk_begin` has to be a
21712 `nk_menubar_begin` call. Inside the menubar you then have to allocate space for
21713 widgets (also supports multiple rows).
21714 Example:
21715 if (nk_begin(...)) {
21716 nk_menubar_begin(...);
21717 nk_layout_xxxx(...);
21718 nk_button(...);
21719 nk_layout_xxxx(...);
21720 nk_button(...);
21721 nk_menubar_end(...);
21722 }
21723 nk_end(...);
21724 */
21725 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
21726 return;
21727
21728 layout->menu.x = layout->at_x;
21729 layout->menu.y = layout->at_y + layout->row.height;
21730 layout->menu.w = layout->bounds.w;
21731 layout->menu.offset.x = *layout->offset_x;
21732 layout->menu.offset.y = *layout->offset_y;
21733 *layout->offset_y = 0;
21734}
21735NK_API void
21736nk_menubar_end(struct nk_context *ctx)
21737{
21738 struct nk_window *win;
21739 struct nk_panel *layout;
21740 struct nk_command_buffer *out;
21741
21742 NK_ASSERT(ctx);
21743 NK_ASSERT(ctx->current);
21744 NK_ASSERT(ctx->current->layout);
21745 if (!ctx || !ctx->current || !ctx->current->layout)
21746 return;
21747
21748 win = ctx->current;
21749 out = &win->buffer;
21750 layout = win->layout;
21751 if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)
21752 return;
21753
21754 layout->menu.h = layout->at_y - layout->menu.y;
21755 layout->menu.h += layout->row.height + ctx->style.window.spacing.y;
21756
21757 layout->bounds.y += layout->menu.h;
21758 layout->bounds.h -= layout->menu.h;
21759
21760 *layout->offset_x = layout->menu.offset.x;
21761 *layout->offset_y = layout->menu.offset.y;
21762 layout->at_y = layout->bounds.y - layout->row.height;
21763
21764 layout->clip.y = layout->bounds.y;
21765 layout->clip.h = layout->bounds.h;
21766 nk_push_scissor(out, layout->clip);
21767}
21768NK_INTERN int
21769nk_menu_begin(struct nk_context *ctx, struct nk_window *win,
21770 const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)
21771{
21772 int is_open = 0;
21773 int is_active = 0;
21774 struct nk_rect body;
21775 struct nk_window *popup;
21776 nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);
21777
21778 NK_ASSERT(ctx);
21779 NK_ASSERT(ctx->current);
21780 NK_ASSERT(ctx->current->layout);
21781 if (!ctx || !ctx->current || !ctx->current->layout)
21782 return 0;
21783
21784 body.x = header.x;
21785 body.w = size.x;
21786 body.y = header.y + header.h;
21787 body.h = size.y;
21788
21789 popup = win->popup.win;
21790 is_open = popup ? nk_true : nk_false;
21791 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);
21792 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
21793 (!is_open && !is_active && !is_clicked)) return 0;
21794 if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))
21795 return 0;
21796
21797 win->popup.type = NK_PANEL_MENU;
21798 win->popup.name = hash;
21799 return 1;
21800}
21801NK_API nk_bool
21802nk_menu_begin_text(struct nk_context *ctx, const char *title, int len,
21803 nk_flags align, struct nk_vec2 size)
21804{
21805 struct nk_window *win;
21806 const struct nk_input *in;
21807 struct nk_rect header;
21808 int is_clicked = nk_false;
21809 nk_flags state;
21810
21811 NK_ASSERT(ctx);
21812 NK_ASSERT(ctx->current);
21813 NK_ASSERT(ctx->current->layout);
21814 if (!ctx || !ctx->current || !ctx->current->layout)
21815 return 0;
21816
21817 win = ctx->current;
21818 state = nk_widget(&header, ctx);
21819 if (!state) return 0;
21820 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21821 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,
21822 title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
21823 is_clicked = nk_true;
21824 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
21825}
21826NK_API nk_bool nk_menu_begin_label(struct nk_context *ctx,
21827 const char *text, nk_flags align, struct nk_vec2 size)
21828{
21829 return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);
21830}
21831NK_API nk_bool
21832nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,
21833 struct nk_vec2 size)
21834{
21835 struct nk_window *win;
21836 struct nk_rect header;
21837 const struct nk_input *in;
21838 int is_clicked = nk_false;
21839 nk_flags state;
21840
21841 NK_ASSERT(ctx);
21842 NK_ASSERT(ctx->current);
21843 NK_ASSERT(ctx->current->layout);
21844 if (!ctx || !ctx->current || !ctx->current->layout)
21845 return 0;
21846
21847 win = ctx->current;
21848 state = nk_widget(&header, ctx);
21849 if (!state) return 0;
21850 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21851 if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,
21852 img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))
21853 is_clicked = nk_true;
21854 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
21855}
21856NK_API nk_bool
21857nk_menu_begin_symbol(struct nk_context *ctx, const char *id,
21858 enum nk_symbol_type sym, struct nk_vec2 size)
21859{
21860 struct nk_window *win;
21861 const struct nk_input *in;
21862 struct nk_rect header;
21863 int is_clicked = nk_false;
21864 nk_flags state;
21865
21866 NK_ASSERT(ctx);
21867 NK_ASSERT(ctx->current);
21868 NK_ASSERT(ctx->current->layout);
21869 if (!ctx || !ctx->current || !ctx->current->layout)
21870 return 0;
21871
21872 win = ctx->current;
21873 state = nk_widget(&header, ctx);
21874 if (!state) return 0;
21875 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21876 if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header,
21877 sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))
21878 is_clicked = nk_true;
21879 return nk_menu_begin(ctx, win, id, is_clicked, header, size);
21880}
21881NK_API nk_bool
21882nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,
21883 nk_flags align, struct nk_image img, struct nk_vec2 size)
21884{
21885 struct nk_window *win;
21886 struct nk_rect header;
21887 const struct nk_input *in;
21888 int is_clicked = nk_false;
21889 nk_flags state;
21890
21891 NK_ASSERT(ctx);
21892 NK_ASSERT(ctx->current);
21893 NK_ASSERT(ctx->current->layout);
21894 if (!ctx || !ctx->current || !ctx->current->layout)
21895 return 0;
21896
21897 win = ctx->current;
21898 state = nk_widget(&header, ctx);
21899 if (!state) return 0;
21900 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21901 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
21902 header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
21903 ctx->style.font, in))
21904 is_clicked = nk_true;
21905 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
21906}
21907NK_API nk_bool
21908nk_menu_begin_image_label(struct nk_context *ctx,
21909 const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)
21910{
21911 return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);
21912}
21913NK_API nk_bool
21914nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,
21915 nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)
21916{
21917 struct nk_window *win;
21918 struct nk_rect header;
21919 const struct nk_input *in;
21920 int is_clicked = nk_false;
21921 nk_flags state;
21922
21923 NK_ASSERT(ctx);
21924 NK_ASSERT(ctx->current);
21925 NK_ASSERT(ctx->current->layout);
21926 if (!ctx || !ctx->current || !ctx->current->layout)
21927 return 0;
21928
21929 win = ctx->current;
21930 state = nk_widget(&header, ctx);
21931 if (!state) return 0;
21932
21933 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
21934 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,
21935 header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,
21936 ctx->style.font, in)) is_clicked = nk_true;
21937 return nk_menu_begin(ctx, win, title, is_clicked, header, size);
21938}
21939NK_API nk_bool
21940nk_menu_begin_symbol_label(struct nk_context *ctx,
21941 const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )
21942{
21943 return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);
21944}
21945NK_API nk_bool
21946nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)
21947{
21948 return nk_contextual_item_text(ctx, title, len, align);
21949}
21950NK_API nk_bool
21951nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)
21952{
21953 return nk_contextual_item_label(ctx, label, align);
21954}
21955NK_API nk_bool
21956nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,
21957 const char *label, nk_flags align)
21958{
21959 return nk_contextual_item_image_label(ctx, img, label, align);
21960}
21961NK_API nk_bool
21962nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,
21963 const char *text, int len, nk_flags align)
21964{
21965 return nk_contextual_item_image_text(ctx, img, text, len, align);
21966}
21967NK_API nk_bool nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
21968 const char *text, int len, nk_flags align)
21969{
21970 return nk_contextual_item_symbol_text(ctx, sym, text, len, align);
21971}
21972NK_API nk_bool nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
21973 const char *label, nk_flags align)
21974{
21975 return nk_contextual_item_symbol_label(ctx, sym, label, align);
21976}
21977NK_API void nk_menu_close(struct nk_context *ctx)
21978{
21979 nk_contextual_close(ctx);
21980}
21981NK_API void
21982nk_menu_end(struct nk_context *ctx)
21983{
21984 nk_contextual_end(ctx);
21985}
21986
21987
21988
21989
21990
21991/* ===============================================================
21992 *
21993 * LAYOUT
21994 *
21995 * ===============================================================*/
21996NK_API void
21997nk_layout_set_min_row_height(struct nk_context *ctx, float height)
21998{
21999 struct nk_window *win;
22000 struct nk_panel *layout;
22001
22002 NK_ASSERT(ctx);
22003 NK_ASSERT(ctx->current);
22004 NK_ASSERT(ctx->current->layout);
22005 if (!ctx || !ctx->current || !ctx->current->layout)
22006 return;
22007
22008 win = ctx->current;
22009 layout = win->layout;
22010 layout->row.min_height = height;
22011}
22012NK_API void
22014{
22015 struct nk_window *win;
22016 struct nk_panel *layout;
22017
22018 NK_ASSERT(ctx);
22019 NK_ASSERT(ctx->current);
22020 NK_ASSERT(ctx->current->layout);
22021 if (!ctx || !ctx->current || !ctx->current->layout)
22022 return;
22023
22024 win = ctx->current;
22025 layout = win->layout;
22026 layout->row.min_height = ctx->style.font->height;
22027 layout->row.min_height += ctx->style.text.padding.y*2;
22028 layout->row.min_height += ctx->style.window.min_row_height_padding*2;
22029}
22030NK_LIB float
22031nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
22032 float total_space, int columns)
22033{
22034 float panel_spacing;
22035 float panel_space;
22036
22037 struct nk_vec2 spacing;
22038
22039 NK_UNUSED(type);
22040
22041 spacing = style->window.spacing;
22042
22043 /* calculate the usable panel space */
22044 panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
22045 panel_space = total_space - panel_spacing;
22046 return panel_space;
22047}
22048NK_LIB void
22049nk_panel_layout(const struct nk_context *ctx, struct nk_window *win,
22050 float height, int cols)
22051{
22052 struct nk_panel *layout;
22053 const struct nk_style *style;
22054 struct nk_command_buffer *out;
22055
22056 struct nk_vec2 item_spacing;
22057 struct nk_color color;
22058
22059 NK_ASSERT(ctx);
22060 NK_ASSERT(ctx->current);
22061 NK_ASSERT(ctx->current->layout);
22062 if (!ctx || !ctx->current || !ctx->current->layout)
22063 return;
22064
22065 /* prefetch some configuration data */
22066 layout = win->layout;
22067 style = &ctx->style;
22068 out = &win->buffer;
22069 color = style->window.background;
22070 item_spacing = style->window.spacing;
22071
22072 /* if one of these triggers you forgot to add an `if` condition around either
22073 a window, group, popup, combobox or contextual menu `begin` and `end` block.
22074 Example:
22075 if (nk_begin(...) {...} nk_end(...); or
22076 if (nk_group_begin(...) { nk_group_end(...);} */
22077 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
22078 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
22079 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
22080
22081 /* update the current row and set the current row layout */
22082 layout->row.index = 0;
22083 layout->at_y += layout->row.height;
22084 layout->row.columns = cols;
22085 if (height == 0.0f)
22086 layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;
22087 else layout->row.height = height + item_spacing.y;
22088
22089 layout->row.item_offset = 0;
22090 if (layout->flags & NK_WINDOW_DYNAMIC) {
22091 /* draw background for dynamic panels */
22092 struct nk_rect background;
22093 background.x = win->bounds.x;
22094 background.w = win->bounds.w;
22095 background.y = layout->at_y - 1.0f;
22096 background.h = layout->row.height + 1.0f;
22097 nk_fill_rect(out, background, 0, color);
22098 }
22099}
22100NK_LIB void
22101nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
22102 float height, int cols, int width)
22103{
22104 /* update the current row and set the current row layout */
22105 struct nk_window *win;
22106 NK_ASSERT(ctx);
22107 NK_ASSERT(ctx->current);
22108 NK_ASSERT(ctx->current->layout);
22109 if (!ctx || !ctx->current || !ctx->current->layout)
22110 return;
22111
22112 win = ctx->current;
22113 nk_panel_layout(ctx, win, height, cols);
22114 if (fmt == NK_DYNAMIC)
22115 win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;
22116 else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;
22117
22118 win->layout->row.ratio = 0;
22119 win->layout->row.filled = 0;
22120 win->layout->row.item_offset = 0;
22121 win->layout->row.item_width = (float)width;
22122}
22123NK_API float
22124nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width)
22125{
22126 struct nk_window *win;
22127 NK_ASSERT(ctx);
22128 NK_ASSERT(pixel_width);
22129 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
22130 win = ctx->current;
22131 return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);
22132}
22133NK_API void
22134nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
22135{
22136 nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);
22137}
22138NK_API void
22139nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
22140{
22141 nk_row_layout(ctx, NK_STATIC, height, cols, item_width);
22142}
22143NK_API void
22144nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,
22145 float row_height, int cols)
22146{
22147 struct nk_window *win;
22148 struct nk_panel *layout;
22149
22150 NK_ASSERT(ctx);
22151 NK_ASSERT(ctx->current);
22152 NK_ASSERT(ctx->current->layout);
22153 if (!ctx || !ctx->current || !ctx->current->layout)
22154 return;
22155
22156 win = ctx->current;
22157 layout = win->layout;
22158 nk_panel_layout(ctx, win, row_height, cols);
22159 if (fmt == NK_DYNAMIC)
22160 layout->row.type = NK_LAYOUT_DYNAMIC_ROW;
22161 else layout->row.type = NK_LAYOUT_STATIC_ROW;
22162
22163 layout->row.ratio = 0;
22164 layout->row.filled = 0;
22165 layout->row.item_width = 0;
22166 layout->row.item_offset = 0;
22167 layout->row.columns = cols;
22168}
22169NK_API void
22170nk_layout_row_push(struct nk_context *ctx, float ratio_or_width)
22171{
22172 struct nk_window *win;
22173 struct nk_panel *layout;
22174
22175 NK_ASSERT(ctx);
22176 NK_ASSERT(ctx->current);
22177 NK_ASSERT(ctx->current->layout);
22178 if (!ctx || !ctx->current || !ctx->current->layout)
22179 return;
22180
22181 win = ctx->current;
22182 layout = win->layout;
22183 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
22184 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
22185 return;
22186
22187 if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {
22188 float ratio = ratio_or_width;
22189 if ((ratio + layout->row.filled) > 1.0f) return;
22190 if (ratio > 0.0f)
22191 layout->row.item_width = NK_SATURATE(ratio);
22192 else layout->row.item_width = 1.0f - layout->row.filled;
22193 } else layout->row.item_width = ratio_or_width;
22194}
22195NK_API void
22196nk_layout_row_end(struct nk_context *ctx)
22197{
22198 struct nk_window *win;
22199 struct nk_panel *layout;
22200
22201 NK_ASSERT(ctx);
22202 NK_ASSERT(ctx->current);
22203 NK_ASSERT(ctx->current->layout);
22204 if (!ctx || !ctx->current || !ctx->current->layout)
22205 return;
22206
22207 win = ctx->current;
22208 layout = win->layout;
22209 NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
22210 if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
22211 return;
22212 layout->row.item_width = 0;
22213 layout->row.item_offset = 0;
22214}
22215NK_API void
22216nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,
22217 float height, int cols, const float *ratio)
22218{
22219 int i;
22220 int n_undef = 0;
22221 struct nk_window *win;
22222 struct nk_panel *layout;
22223
22224 NK_ASSERT(ctx);
22225 NK_ASSERT(ctx->current);
22226 NK_ASSERT(ctx->current->layout);
22227 if (!ctx || !ctx->current || !ctx->current->layout)
22228 return;
22229
22230 win = ctx->current;
22231 layout = win->layout;
22232 nk_panel_layout(ctx, win, height, cols);
22233 if (fmt == NK_DYNAMIC) {
22234 /* calculate width of undefined widget ratios */
22235 float r = 0;
22236 layout->row.ratio = ratio;
22237 for (i = 0; i < cols; ++i) {
22238 if (ratio[i] < 0.0f)
22239 n_undef++;
22240 else r += ratio[i];
22241 }
22242 r = NK_SATURATE(1.0f - r);
22243 layout->row.type = NK_LAYOUT_DYNAMIC;
22244 layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;
22245 } else {
22246 layout->row.ratio = ratio;
22247 layout->row.type = NK_LAYOUT_STATIC;
22248 layout->row.item_width = 0;
22249 layout->row.item_offset = 0;
22250 }
22251 layout->row.item_offset = 0;
22252 layout->row.filled = 0;
22253}
22254NK_API void
22255nk_layout_row_template_begin(struct nk_context *ctx, float height)
22256{
22257 struct nk_window *win;
22258 struct nk_panel *layout;
22259
22260 NK_ASSERT(ctx);
22261 NK_ASSERT(ctx->current);
22262 NK_ASSERT(ctx->current->layout);
22263 if (!ctx || !ctx->current || !ctx->current->layout)
22264 return;
22265
22266 win = ctx->current;
22267 layout = win->layout;
22268 nk_panel_layout(ctx, win, height, 1);
22269 layout->row.type = NK_LAYOUT_TEMPLATE;
22270 layout->row.columns = 0;
22271 layout->row.ratio = 0;
22272 layout->row.item_width = 0;
22273 layout->row.item_height = 0;
22274 layout->row.item_offset = 0;
22275 layout->row.filled = 0;
22276 layout->row.item.x = 0;
22277 layout->row.item.y = 0;
22278 layout->row.item.w = 0;
22279 layout->row.item.h = 0;
22280}
22281NK_API void
22283{
22284 struct nk_window *win;
22285 struct nk_panel *layout;
22286
22287 NK_ASSERT(ctx);
22288 NK_ASSERT(ctx->current);
22289 NK_ASSERT(ctx->current->layout);
22290 if (!ctx || !ctx->current || !ctx->current->layout)
22291 return;
22292
22293 win = ctx->current;
22294 layout = win->layout;
22295 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
22296 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
22297 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
22298 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
22299 layout->row.templates[layout->row.columns++] = -1.0f;
22300}
22301NK_API void
22302nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)
22303{
22304 struct nk_window *win;
22305 struct nk_panel *layout;
22306
22307 NK_ASSERT(ctx);
22308 NK_ASSERT(ctx->current);
22309 NK_ASSERT(ctx->current->layout);
22310 if (!ctx || !ctx->current || !ctx->current->layout)
22311 return;
22312
22313 win = ctx->current;
22314 layout = win->layout;
22315 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
22316 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
22317 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
22318 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
22319 layout->row.templates[layout->row.columns++] = -min_width;
22320}
22321NK_API void
22322nk_layout_row_template_push_static(struct nk_context *ctx, float width)
22323{
22324 struct nk_window *win;
22325 struct nk_panel *layout;
22326
22327 NK_ASSERT(ctx);
22328 NK_ASSERT(ctx->current);
22329 NK_ASSERT(ctx->current->layout);
22330 if (!ctx || !ctx->current || !ctx->current->layout)
22331 return;
22332
22333 win = ctx->current;
22334 layout = win->layout;
22335 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
22336 NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
22337 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
22338 if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
22339 layout->row.templates[layout->row.columns++] = width;
22340}
22341NK_API void
22343{
22344 struct nk_window *win;
22345 struct nk_panel *layout;
22346
22347 int i = 0;
22348 int variable_count = 0;
22349 int min_variable_count = 0;
22350 float min_fixed_width = 0.0f;
22351 float total_fixed_width = 0.0f;
22352 float max_variable_width = 0.0f;
22353
22354 NK_ASSERT(ctx);
22355 NK_ASSERT(ctx->current);
22356 NK_ASSERT(ctx->current->layout);
22357 if (!ctx || !ctx->current || !ctx->current->layout)
22358 return;
22359
22360 win = ctx->current;
22361 layout = win->layout;
22362 NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
22363 if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
22364 for (i = 0; i < layout->row.columns; ++i) {
22365 float width = layout->row.templates[i];
22366 if (width >= 0.0f) {
22367 total_fixed_width += width;
22368 min_fixed_width += width;
22369 } else if (width < -1.0f) {
22370 width = -width;
22371 total_fixed_width += width;
22372 max_variable_width = NK_MAX(max_variable_width, width);
22373 variable_count++;
22374 } else {
22375 min_variable_count++;
22376 variable_count++;
22377 }
22378 }
22379 if (variable_count) {
22380 float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
22381 layout->bounds.w, layout->row.columns);
22382 float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;
22383 int enough_space = var_width >= max_variable_width;
22384 if (!enough_space)
22385 var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;
22386 for (i = 0; i < layout->row.columns; ++i) {
22387 float *width = &layout->row.templates[i];
22388 *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;
22389 }
22390 }
22391}
22392NK_API void
22393nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,
22394 float height, int widget_count)
22395{
22396 struct nk_window *win;
22397 struct nk_panel *layout;
22398
22399 NK_ASSERT(ctx);
22400 NK_ASSERT(ctx->current);
22401 NK_ASSERT(ctx->current->layout);
22402 if (!ctx || !ctx->current || !ctx->current->layout)
22403 return;
22404
22405 win = ctx->current;
22406 layout = win->layout;
22407 nk_panel_layout(ctx, win, height, widget_count);
22408 if (fmt == NK_STATIC)
22409 layout->row.type = NK_LAYOUT_STATIC_FREE;
22410 else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;
22411
22412 layout->row.ratio = 0;
22413 layout->row.filled = 0;
22414 layout->row.item_width = 0;
22415 layout->row.item_offset = 0;
22416}
22417NK_API void
22419{
22420 struct nk_window *win;
22421 struct nk_panel *layout;
22422
22423 NK_ASSERT(ctx);
22424 NK_ASSERT(ctx->current);
22425 NK_ASSERT(ctx->current->layout);
22426 if (!ctx || !ctx->current || !ctx->current->layout)
22427 return;
22428
22429 win = ctx->current;
22430 layout = win->layout;
22431 layout->row.item_width = 0;
22432 layout->row.item_height = 0;
22433 layout->row.item_offset = 0;
22434 nk_zero(&layout->row.item, sizeof(layout->row.item));
22435}
22436NK_API void
22437nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
22438{
22439 struct nk_window *win;
22440 struct nk_panel *layout;
22441
22442 NK_ASSERT(ctx);
22443 NK_ASSERT(ctx->current);
22444 NK_ASSERT(ctx->current->layout);
22445 if (!ctx || !ctx->current || !ctx->current->layout)
22446 return;
22447
22448 win = ctx->current;
22449 layout = win->layout;
22450 layout->row.item = rect;
22451}
22452NK_API struct nk_rect
22453nk_layout_space_bounds(const struct nk_context *ctx)
22454{
22455 struct nk_rect ret;
22456 struct nk_window *win;
22457 struct nk_panel *layout;
22458
22459 NK_ASSERT(ctx);
22460 NK_ASSERT(ctx->current);
22461 NK_ASSERT(ctx->current->layout);
22462 win = ctx->current;
22463 layout = win->layout;
22464
22465 ret.x = layout->clip.x;
22466 ret.y = layout->clip.y;
22467 ret.w = layout->clip.w;
22468 ret.h = layout->row.height;
22469 return ret;
22470}
22471NK_API struct nk_rect
22472nk_layout_widget_bounds(const struct nk_context *ctx)
22473{
22474 struct nk_rect ret;
22475 struct nk_window *win;
22476 struct nk_panel *layout;
22477
22478 NK_ASSERT(ctx);
22479 NK_ASSERT(ctx->current);
22480 NK_ASSERT(ctx->current->layout);
22481 win = ctx->current;
22482 layout = win->layout;
22483
22484 ret.x = layout->at_x;
22485 ret.y = layout->at_y;
22486 ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);
22487 ret.h = layout->row.height;
22488 return ret;
22489}
22490NK_API struct nk_vec2
22491nk_layout_space_to_screen(const struct nk_context *ctx, struct nk_vec2 ret)
22492{
22493 struct nk_window *win;
22494 struct nk_panel *layout;
22495
22496 NK_ASSERT(ctx);
22497 NK_ASSERT(ctx->current);
22498 NK_ASSERT(ctx->current->layout);
22499 win = ctx->current;
22500 layout = win->layout;
22501
22502 ret.x += layout->at_x - (float)*layout->offset_x;
22503 ret.y += layout->at_y - (float)*layout->offset_y;
22504 return ret;
22505}
22506NK_API struct nk_vec2
22507nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 ret)
22508{
22509 struct nk_window *win;
22510 struct nk_panel *layout;
22511
22512 NK_ASSERT(ctx);
22513 NK_ASSERT(ctx->current);
22514 NK_ASSERT(ctx->current->layout);
22515 win = ctx->current;
22516 layout = win->layout;
22517
22518 ret.x += -layout->at_x + (float)*layout->offset_x;
22519 ret.y += -layout->at_y + (float)*layout->offset_y;
22520 return ret;
22521}
22522NK_API struct nk_rect
22523nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect ret)
22524{
22525 struct nk_window *win;
22526 struct nk_panel *layout;
22527
22528 NK_ASSERT(ctx);
22529 NK_ASSERT(ctx->current);
22530 NK_ASSERT(ctx->current->layout);
22531 win = ctx->current;
22532 layout = win->layout;
22533
22534 ret.x += layout->at_x - (float)*layout->offset_x;
22535 ret.y += layout->at_y - (float)*layout->offset_y;
22536 return ret;
22537}
22538NK_API struct nk_rect
22539nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect ret)
22540{
22541 struct nk_window *win;
22542 struct nk_panel *layout;
22543
22544 NK_ASSERT(ctx);
22545 NK_ASSERT(ctx->current);
22546 NK_ASSERT(ctx->current->layout);
22547 win = ctx->current;
22548 layout = win->layout;
22549
22550 ret.x += -layout->at_x + (float)*layout->offset_x;
22551 ret.y += -layout->at_y + (float)*layout->offset_y;
22552 return ret;
22553}
22554NK_LIB void
22555nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)
22556{
22557 struct nk_panel *layout = win->layout;
22558 struct nk_vec2 spacing = ctx->style.window.spacing;
22559 const float row_height = layout->row.height - spacing.y;
22560 nk_panel_layout(ctx, win, row_height, layout->row.columns);
22561}
22562NK_LIB void
22563nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,
22564 struct nk_window *win, int modify)
22565{
22566 struct nk_panel *layout;
22567 const struct nk_style *style;
22568
22569 struct nk_vec2 spacing;
22570
22571 float item_offset = 0;
22572 float item_width = 0;
22573 float item_spacing = 0;
22574 float panel_space = 0;
22575
22576 NK_ASSERT(ctx);
22577 NK_ASSERT(ctx->current);
22578 NK_ASSERT(ctx->current->layout);
22579 if (!ctx || !ctx->current || !ctx->current->layout)
22580 return;
22581
22582 win = ctx->current;
22583 layout = win->layout;
22584 style = &ctx->style;
22585 NK_ASSERT(bounds);
22586
22587 spacing = style->window.spacing;
22588 panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
22589 layout->bounds.w, layout->row.columns);
22590
22591 #define NK_FRAC(x) (x - (float)(int)nk_roundf(x)) /* will be used to remove fookin gaps */
22592 /* calculate the width of one item inside the current layout space */
22593 switch (layout->row.type) {
22594 case NK_LAYOUT_DYNAMIC_FIXED: {
22595 /* scaling fixed size widgets item width */
22596 float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;
22597 item_offset = (float)layout->row.index * w;
22598 item_width = w + NK_FRAC(item_offset);
22599 item_spacing = (float)layout->row.index * spacing.x;
22600 } break;
22601 case NK_LAYOUT_DYNAMIC_ROW: {
22602 /* scaling single ratio widget width */
22603 float w = layout->row.item_width * panel_space;
22604 item_offset = layout->row.item_offset;
22605 item_width = w + NK_FRAC(item_offset);
22606 item_spacing = 0;
22607
22608 if (modify) {
22609 layout->row.item_offset += w + spacing.x;
22610 layout->row.filled += layout->row.item_width;
22611 layout->row.index = 0;
22612 }
22613 } break;
22614 case NK_LAYOUT_DYNAMIC_FREE: {
22615 /* panel width depended free widget placing */
22616 bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);
22617 bounds->x -= (float)*layout->offset_x;
22618 bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);
22619 bounds->y -= (float)*layout->offset_y;
22620 bounds->w = layout->bounds.w * layout->row.item.w + NK_FRAC(bounds->x);
22621 bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y);
22622 return;
22623 }
22624 case NK_LAYOUT_DYNAMIC: {
22625 /* scaling arrays of panel width ratios for every widget */
22626 float ratio, w;
22627 NK_ASSERT(layout->row.ratio);
22628 ratio = (layout->row.ratio[layout->row.index] < 0) ?
22629 layout->row.item_width : layout->row.ratio[layout->row.index];
22630
22631 w = (ratio * panel_space);
22632 item_spacing = (float)layout->row.index * spacing.x;
22633 item_offset = layout->row.item_offset;
22634 item_width = w + NK_FRAC(item_offset);
22635
22636 if (modify) {
22637 layout->row.item_offset += w;
22638 layout->row.filled += ratio;
22639 }
22640 } break;
22641 case NK_LAYOUT_STATIC_FIXED: {
22642 /* non-scaling fixed widgets item width */
22643 item_width = layout->row.item_width;
22644 item_offset = (float)layout->row.index * item_width;
22645 item_spacing = (float)layout->row.index * spacing.x;
22646 } break;
22647 case NK_LAYOUT_STATIC_ROW: {
22648 /* scaling single ratio widget width */
22649 item_width = layout->row.item_width;
22650 item_offset = layout->row.item_offset;
22651 item_spacing = (float)layout->row.index * spacing.x;
22652 if (modify) layout->row.item_offset += item_width;
22653 } break;
22654 case NK_LAYOUT_STATIC_FREE: {
22655 /* free widget placing */
22656 bounds->x = layout->at_x + layout->row.item.x;
22657 bounds->w = layout->row.item.w;
22658 if (((bounds->x + bounds->w) > layout->max_x) && modify)
22659 layout->max_x = (bounds->x + bounds->w);
22660 bounds->x -= (float)*layout->offset_x;
22661 bounds->y = layout->at_y + layout->row.item.y;
22662 bounds->y -= (float)*layout->offset_y;
22663 bounds->h = layout->row.item.h;
22664 return;
22665 }
22666 case NK_LAYOUT_STATIC: {
22667 /* non-scaling array of panel pixel width for every widget */
22668 item_spacing = (float)layout->row.index * spacing.x;
22669 item_width = layout->row.ratio[layout->row.index];
22670 item_offset = layout->row.item_offset;
22671 if (modify) layout->row.item_offset += item_width;
22672 } break;
22673 case NK_LAYOUT_TEMPLATE: {
22674 /* stretchy row layout with combined dynamic/static widget width*/
22675 float w;
22676 NK_ASSERT(layout->row.index < layout->row.columns);
22677 NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
22678 w = layout->row.templates[layout->row.index];
22679 item_offset = layout->row.item_offset;
22680 item_width = w + NK_FRAC(item_offset);
22681 item_spacing = (float)layout->row.index * spacing.x;
22682 if (modify) layout->row.item_offset += w;
22683 } break;
22684 #undef NK_FRAC
22685 default: NK_ASSERT(0); break;
22686 };
22687
22688 /* set the bounds of the newly allocated widget */
22689 bounds->w = item_width;
22690 bounds->h = layout->row.height - spacing.y;
22691 bounds->y = layout->at_y - (float)*layout->offset_y;
22692 bounds->x = layout->at_x + item_offset + item_spacing;
22693 if (((bounds->x + bounds->w) > layout->max_x) && modify)
22694 layout->max_x = bounds->x + bounds->w;
22695 bounds->x -= (float)*layout->offset_x;
22696}
22697NK_LIB void
22698nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
22699{
22700 struct nk_window *win;
22701 struct nk_panel *layout;
22702
22703 NK_ASSERT(ctx);
22704 NK_ASSERT(ctx->current);
22705 NK_ASSERT(ctx->current->layout);
22706 if (!ctx || !ctx->current || !ctx->current->layout)
22707 return;
22708
22709 /* check if the end of the row has been hit and begin new row if so */
22710 win = ctx->current;
22711 layout = win->layout;
22712 if (layout->row.index >= layout->row.columns)
22713 nk_panel_alloc_row(ctx, win);
22714
22715 /* calculate widget position and size */
22716 nk_layout_widget_space(bounds, ctx, win, nk_true);
22717 layout->row.index++;
22718}
22719NK_LIB void
22720nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx)
22721{
22722 float y;
22723 int index;
22724 struct nk_window *win;
22725 struct nk_panel *layout;
22726
22727 NK_ASSERT(ctx);
22728 NK_ASSERT(ctx->current);
22729 NK_ASSERT(ctx->current->layout);
22730 if (!ctx || !ctx->current || !ctx->current->layout) {
22731 *bounds = nk_rect(0,0,0,0);
22732 return;
22733 }
22734
22735 win = ctx->current;
22736 layout = win->layout;
22737 y = layout->at_y;
22738 index = layout->row.index;
22739 if (layout->row.index >= layout->row.columns) {
22740 layout->at_y += layout->row.height;
22741 layout->row.index = 0;
22742 }
22743 nk_layout_widget_space(bounds, ctx, win, nk_false);
22744 if (!layout->row.index) {
22745 bounds->x -= layout->row.item_offset;
22746 }
22747 layout->at_y = y;
22748 layout->row.index = index;
22749}
22750NK_API void
22751nk_spacer(struct nk_context *ctx )
22752{
22753 struct nk_rect dummy_rect = { 0, 0, 0, 0 };
22754 nk_panel_alloc_space( &dummy_rect, ctx );
22755}
22756
22757
22758
22759
22760/* ===============================================================
22761 *
22762 * TREE
22763 *
22764 * ===============================================================*/
22765NK_INTERN int
22766nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,
22767 struct nk_image *img, const char *title, enum nk_collapse_states *state)
22768{
22769 struct nk_window *win;
22770 struct nk_panel *layout;
22771 const struct nk_style *style;
22772 struct nk_command_buffer *out;
22773 const struct nk_input *in;
22774 const struct nk_style_button *button;
22775 enum nk_symbol_type symbol;
22776 float row_height;
22777
22778 struct nk_vec2 item_spacing;
22779 struct nk_rect header = {0,0,0,0};
22780 struct nk_rect sym = {0,0,0,0};
22781 struct nk_text text;
22782
22783 nk_flags ws = 0;
22784 enum nk_widget_layout_states widget_state;
22785
22786 NK_ASSERT(ctx);
22787 NK_ASSERT(ctx->current);
22788 NK_ASSERT(ctx->current->layout);
22789 if (!ctx || !ctx->current || !ctx->current->layout)
22790 return 0;
22791
22792 /* cache some data */
22793 win = ctx->current;
22794 layout = win->layout;
22795 out = &win->buffer;
22796 style = &ctx->style;
22797 item_spacing = style->window.spacing;
22798
22799 /* calculate header bounds and draw background */
22800 row_height = style->font->height + 2 * style->tab.padding.y;
22801 nk_layout_set_min_row_height(ctx, row_height);
22802 nk_layout_row_dynamic(ctx, row_height, 1);
22804
22805 widget_state = nk_widget(&header, ctx);
22806 if (type == NK_TREE_TAB) {
22807 const struct nk_style_item *background = &style->tab.background;
22808
22809 switch(background->type) {
22810 case NK_STYLE_ITEM_IMAGE:
22811 nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));
22812 break;
22813 case NK_STYLE_ITEM_NINE_SLICE:
22814 nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));
22815 break;
22816 case NK_STYLE_ITEM_COLOR:
22817 nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));
22818 nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
22819 style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));
22820 break;
22821 }
22822 } else text.background = style->window.background;
22823
22824 /* update node state */
22825 in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
22826 in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
22827 if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))
22828 *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;
22829
22830 /* select correct button style */
22831 if (*state == NK_MAXIMIZED) {
22832 symbol = style->tab.sym_maximize;
22833 if (type == NK_TREE_TAB)
22834 button = &style->tab.tab_maximize_button;
22835 else button = &style->tab.node_maximize_button;
22836 } else {
22837 symbol = style->tab.sym_minimize;
22838 if (type == NK_TREE_TAB)
22839 button = &style->tab.tab_minimize_button;
22840 else button = &style->tab.node_minimize_button;
22841 }
22842
22843 {/* draw triangle button */
22844 sym.w = sym.h = style->font->height;
22845 sym.y = header.y + style->tab.padding.y;
22846 sym.x = header.x + style->tab.padding.x;
22847 nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,
22848 button, 0, style->font);
22849
22850 if (img) {
22851 /* draw optional image icon */
22852 sym.x = sym.x + sym.w + 4 * item_spacing.x;
22853 nk_draw_image(&win->buffer, sym, img, nk_white);
22854 sym.w = style->font->height + style->tab.spacing.x;}
22855 }
22856
22857 {/* draw label */
22858 struct nk_rect label;
22859 header.w = NK_MAX(header.w, sym.w + item_spacing.x);
22860 label.x = sym.x + sym.w + item_spacing.x;
22861 label.y = sym.y;
22862 label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);
22863 label.h = style->font->height;
22864 text.text = nk_rgb_factor(style->tab.text, style->tab.color_factor);
22865 text.padding = nk_vec2(0,0);
22866 nk_widget_text(out, label, title, nk_strlen(title), &text,
22867 NK_TEXT_LEFT, style->font);}
22868
22869 /* increase x-axis cursor widget position pointer */
22870 if (*state == NK_MAXIMIZED) {
22871 layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
22872 layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
22873 layout->bounds.w -= (style->tab.indent + style->window.padding.x);
22874 layout->row.tree_depth++;
22875 return nk_true;
22876 } else return nk_false;
22877}
22878NK_INTERN int
22879nk_tree_base(struct nk_context *ctx, enum nk_tree_type type,
22880 struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
22881 const char *hash, int len, int line)
22882{
22883 struct nk_window *win = ctx->current;
22884 int title_len = 0;
22885 nk_hash tree_hash = 0;
22886 nk_uint *state = 0;
22887
22888 /* retrieve tree state from internal widget state tables */
22889 if (!hash) {
22890 title_len = (int)nk_strlen(title);
22891 tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
22892 } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
22893 state = nk_find_value(win, tree_hash);
22894 if (!state) {
22895 state = nk_add_value(ctx, win, tree_hash, 0);
22896 *state = initial_state;
22897 }
22898 return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);
22899}
22900NK_API nk_bool
22901nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,
22902 const char *title, enum nk_collapse_states *state)
22903{
22904 return nk_tree_state_base(ctx, type, 0, title, state);
22905}
22906NK_API nk_bool
22907nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,
22908 struct nk_image img, const char *title, enum nk_collapse_states *state)
22909{
22910 return nk_tree_state_base(ctx, type, &img, title, state);
22911}
22912NK_API void
22913nk_tree_state_pop(struct nk_context *ctx)
22914{
22915 struct nk_window *win = 0;
22916 struct nk_panel *layout = 0;
22917
22918 NK_ASSERT(ctx);
22919 NK_ASSERT(ctx->current);
22920 NK_ASSERT(ctx->current->layout);
22921 if (!ctx || !ctx->current || !ctx->current->layout)
22922 return;
22923
22924 win = ctx->current;
22925 layout = win->layout;
22926 layout->at_x -= ctx->style.tab.indent + (float)*layout->offset_x;
22927 layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;
22928 NK_ASSERT(layout->row.tree_depth);
22929 layout->row.tree_depth--;
22930}
22931NK_API nk_bool
22932nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
22933 const char *title, enum nk_collapse_states initial_state,
22934 const char *hash, int len, int line)
22935{
22936 return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);
22937}
22938NK_API nk_bool
22939nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
22940 struct nk_image img, const char *title, enum nk_collapse_states initial_state,
22941 const char *hash, int len,int seed)
22942{
22943 return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);
22944}
22945NK_API void
22946nk_tree_pop(struct nk_context *ctx)
22947{
22948 nk_tree_state_pop(ctx);
22949}
22950NK_INTERN int
22951nk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type,
22952 struct nk_image *img, const char *title, int title_len,
22953 enum nk_collapse_states *state, nk_bool *selected)
22954{
22955 struct nk_window *win;
22956 struct nk_panel *layout;
22957 const struct nk_style *style;
22958 struct nk_command_buffer *out;
22959 const struct nk_input *in;
22960 const struct nk_style_button *button;
22961 enum nk_symbol_type symbol;
22962 float row_height;
22963 struct nk_vec2 padding;
22964
22965 int text_len;
22966 float text_width;
22967
22968 struct nk_vec2 item_spacing;
22969 struct nk_rect header = {0,0,0,0};
22970 struct nk_rect sym = {0,0,0,0};
22971
22972 nk_flags ws = 0;
22973 enum nk_widget_layout_states widget_state;
22974
22975 NK_ASSERT(ctx);
22976 NK_ASSERT(ctx->current);
22977 NK_ASSERT(ctx->current->layout);
22978 if (!ctx || !ctx->current || !ctx->current->layout)
22979 return 0;
22980
22981 /* cache some data */
22982 win = ctx->current;
22983 layout = win->layout;
22984 out = &win->buffer;
22985 style = &ctx->style;
22986 item_spacing = style->window.spacing;
22987 padding = style->selectable.padding;
22988
22989 /* calculate header bounds and draw background */
22990 row_height = style->font->height + 2 * style->tab.padding.y;
22991 nk_layout_set_min_row_height(ctx, row_height);
22992 nk_layout_row_dynamic(ctx, row_height, 1);
22994
22995 widget_state = nk_widget(&header, ctx);
22996 if (type == NK_TREE_TAB) {
22997 const struct nk_style_item *background = &style->tab.background;
22998
22999 switch (background->type) {
23000 case NK_STYLE_ITEM_IMAGE:
23001 nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));
23002 break;
23003 case NK_STYLE_ITEM_NINE_SLICE:
23004 nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));
23005 break;
23006 case NK_STYLE_ITEM_COLOR:
23007 nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));
23008 nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
23009 style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));
23010
23011 break;
23012 }
23013 }
23014
23015 in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
23016 in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
23017
23018 /* select correct button style */
23019 if (*state == NK_MAXIMIZED) {
23020 symbol = style->tab.sym_maximize;
23021 if (type == NK_TREE_TAB)
23022 button = &style->tab.tab_maximize_button;
23023 else button = &style->tab.node_maximize_button;
23024 } else {
23025 symbol = style->tab.sym_minimize;
23026 if (type == NK_TREE_TAB)
23027 button = &style->tab.tab_minimize_button;
23028 else button = &style->tab.node_minimize_button;
23029 }
23030 {/* draw triangle button */
23031 sym.w = sym.h = style->font->height;
23032 sym.y = header.y + style->tab.padding.y;
23033 sym.x = header.x + style->tab.padding.x;
23034 if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font))
23035 *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;}
23036
23037 /* draw label */
23038 {nk_flags dummy = 0;
23039 struct nk_rect label;
23040 /* calculate size of the text and tooltip */
23041 text_len = nk_strlen(title);
23042 text_width = style->font->width(style->font->userdata, style->font->height, title, text_len);
23043 text_width += (4 * padding.x);
23044
23045 header.w = NK_MAX(header.w, sym.w + item_spacing.x);
23046 label.x = sym.x + sym.w + item_spacing.x;
23047 label.y = sym.y;
23048 label.w = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width);
23049 label.h = style->font->height;
23050
23051 if (img) {
23052 nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
23053 selected, img, &style->selectable, in, style->font);
23054 } else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
23055 selected, &style->selectable, in, style->font);
23056 }
23057 /* increase x-axis cursor widget position pointer */
23058 if (*state == NK_MAXIMIZED) {
23059 layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
23060 layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
23061 layout->bounds.w -= (style->tab.indent + style->window.padding.x);
23062 layout->row.tree_depth++;
23063 return nk_true;
23064 } else return nk_false;
23065}
23066NK_INTERN int
23067nk_tree_element_base(struct nk_context *ctx, enum nk_tree_type type,
23068 struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
23069 nk_bool *selected, const char *hash, int len, int line)
23070{
23071 struct nk_window *win = ctx->current;
23072 int title_len = 0;
23073 nk_hash tree_hash = 0;
23074 nk_uint *state = 0;
23075
23076 /* retrieve tree state from internal widget state tables */
23077 if (!hash) {
23078 title_len = (int)nk_strlen(title);
23079 tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
23080 } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
23081 state = nk_find_value(win, tree_hash);
23082 if (!state) {
23083 state = nk_add_value(ctx, win, tree_hash, 0);
23084 *state = initial_state;
23085 } return nk_tree_element_image_push_hashed_base(ctx, type, img, title,
23086 nk_strlen(title), (enum nk_collapse_states*)state, selected);
23087}
23088NK_API nk_bool
23089nk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
23090 const char *title, enum nk_collapse_states initial_state,
23091 nk_bool *selected, const char *hash, int len, int seed)
23092{
23093 return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed);
23094}
23095NK_API nk_bool
23096nk_tree_element_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
23097 struct nk_image img, const char *title, enum nk_collapse_states initial_state,
23098 nk_bool *selected, const char *hash, int len,int seed)
23099{
23100 return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed);
23101}
23102NK_API void
23103nk_tree_element_pop(struct nk_context *ctx)
23104{
23105 nk_tree_state_pop(ctx);
23106}
23107
23108
23109
23110
23111
23112/* ===============================================================
23113 *
23114 * GROUP
23115 *
23116 * ===============================================================*/
23117NK_API nk_bool
23119 nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)
23120{
23121 struct nk_rect bounds;
23122 struct nk_window panel;
23123 struct nk_window *win;
23124
23125 win = ctx->current;
23126 nk_panel_alloc_space(&bounds, ctx);
23127 {const struct nk_rect *c = &win->layout->clip;
23128 if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&
23129 !(flags & NK_WINDOW_MOVABLE)) {
23130 return 0;
23131 }}
23132 if (win->flags & NK_WINDOW_ROM)
23133 flags |= NK_WINDOW_ROM;
23134
23135 /* initialize a fake window to create the panel from */
23136 nk_zero(&panel, sizeof(panel));
23137 panel.bounds = bounds;
23138 panel.flags = flags;
23139 panel.scrollbar.x = *x_offset;
23140 panel.scrollbar.y = *y_offset;
23141 panel.buffer = win->buffer;
23142 panel.layout = (struct nk_panel*)nk_create_panel(ctx);
23143 ctx->current = &panel;
23144 nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);
23145
23146 win->buffer = panel.buffer;
23147 win->buffer.clip = panel.layout->clip;
23148 panel.layout->offset_x = x_offset;
23149 panel.layout->offset_y = y_offset;
23150 panel.layout->parent = win->layout;
23151 win->layout = panel.layout;
23152
23153 ctx->current = win;
23154 if ((panel.layout->flags & NK_WINDOW_CLOSED) ||
23155 (panel.layout->flags & NK_WINDOW_MINIMIZED))
23156 {
23157 nk_flags f = panel.layout->flags;
23159 if (f & NK_WINDOW_CLOSED)
23160 return NK_WINDOW_CLOSED;
23161 if (f & NK_WINDOW_MINIMIZED)
23162 return NK_WINDOW_MINIMIZED;
23163 }
23164 return 1;
23165}
23166NK_API void
23168{
23169 struct nk_window *win;
23170 struct nk_panel *parent;
23171 struct nk_panel *g;
23172
23173 struct nk_rect clip;
23174 struct nk_window pan;
23175 struct nk_vec2 panel_padding;
23176
23177 NK_ASSERT(ctx);
23178 NK_ASSERT(ctx->current);
23179 if (!ctx || !ctx->current)
23180 return;
23181
23182 /* make sure nk_group_begin was called correctly */
23183 NK_ASSERT(ctx->current);
23184 win = ctx->current;
23185 NK_ASSERT(win->layout);
23186 g = win->layout;
23187 NK_ASSERT(g->parent);
23188 parent = g->parent;
23189
23190 /* dummy window */
23191 nk_zero_struct(pan);
23192 panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);
23193 pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);
23194 pan.bounds.x = g->bounds.x - panel_padding.x;
23195 pan.bounds.w = g->bounds.w + 2 * panel_padding.x;
23196 pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;
23197 if (g->flags & NK_WINDOW_BORDER) {
23198 pan.bounds.x -= g->border;
23199 pan.bounds.y -= g->border;
23200 pan.bounds.w += 2*g->border;
23201 pan.bounds.h += 2*g->border;
23202 }
23203 if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {
23204 pan.bounds.w += ctx->style.window.scrollbar_size.x;
23205 pan.bounds.h += ctx->style.window.scrollbar_size.y;
23206 }
23207 pan.scrollbar.x = *g->offset_x;
23208 pan.scrollbar.y = *g->offset_y;
23209 pan.flags = g->flags;
23210 pan.buffer = win->buffer;
23211 pan.layout = g;
23212 pan.parent = win;
23213 ctx->current = &pan;
23214
23215 /* make sure group has correct clipping rectangle */
23216 nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,
23217 pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);
23218 nk_push_scissor(&pan.buffer, clip);
23219 nk_end(ctx);
23220
23221 win->buffer = pan.buffer;
23222 nk_push_scissor(&win->buffer, parent->clip);
23223 ctx->current = win;
23224 win->layout = parent;
23225 g->bounds = pan.bounds;
23226 return;
23227}
23228NK_API nk_bool
23230 struct nk_scroll *scroll, const char *title, nk_flags flags)
23231{
23232 return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);
23233}
23234NK_API nk_bool
23235nk_group_begin_titled(struct nk_context *ctx, const char *id,
23236 const char *title, nk_flags flags)
23237{
23238 int id_len;
23239 nk_hash id_hash;
23240 struct nk_window *win;
23241 nk_uint *x_offset;
23242 nk_uint *y_offset;
23243
23244 NK_ASSERT(ctx);
23245 NK_ASSERT(id);
23246 NK_ASSERT(ctx->current);
23247 NK_ASSERT(ctx->current->layout);
23248 if (!ctx || !ctx->current || !ctx->current->layout || !id)
23249 return 0;
23250
23251 /* find persistent group scrollbar value */
23252 win = ctx->current;
23253 id_len = (int)nk_strlen(id);
23254 id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);
23255 x_offset = nk_find_value(win, id_hash);
23256 if (!x_offset) {
23257 x_offset = nk_add_value(ctx, win, id_hash, 0);
23258 y_offset = nk_add_value(ctx, win, id_hash+1, 0);
23259
23260 NK_ASSERT(x_offset);
23261 NK_ASSERT(y_offset);
23262 if (!x_offset || !y_offset) return 0;
23263 *x_offset = *y_offset = 0;
23264 } else y_offset = nk_find_value(win, id_hash+1);
23265 return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
23266}
23267NK_API nk_bool
23268nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)
23269{
23270 return nk_group_begin_titled(ctx, title, title, flags);
23271}
23272NK_API void
23273nk_group_end(struct nk_context *ctx)
23274{
23276}
23277NK_API void
23278nk_group_get_scroll(struct nk_context *ctx, const char *id, nk_uint *x_offset, nk_uint *y_offset)
23279{
23280 int id_len;
23281 nk_hash id_hash;
23282 struct nk_window *win;
23283 nk_uint *x_offset_ptr;
23284 nk_uint *y_offset_ptr;
23285
23286 NK_ASSERT(ctx);
23287 NK_ASSERT(id);
23288 NK_ASSERT(ctx->current);
23289 NK_ASSERT(ctx->current->layout);
23290 if (!ctx || !ctx->current || !ctx->current->layout || !id)
23291 return;
23292
23293 /* find persistent group scrollbar value */
23294 win = ctx->current;
23295 id_len = (int)nk_strlen(id);
23296 id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);
23297 x_offset_ptr = nk_find_value(win, id_hash);
23298 if (!x_offset_ptr) {
23299 x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);
23300 y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);
23301
23302 NK_ASSERT(x_offset_ptr);
23303 NK_ASSERT(y_offset_ptr);
23304 if (!x_offset_ptr || !y_offset_ptr) return;
23305 *x_offset_ptr = *y_offset_ptr = 0;
23306 } else y_offset_ptr = nk_find_value(win, id_hash+1);
23307 if (x_offset)
23308 *x_offset = *x_offset_ptr;
23309 if (y_offset)
23310 *y_offset = *y_offset_ptr;
23311}
23312NK_API void
23313nk_group_set_scroll(struct nk_context *ctx, const char *id, nk_uint x_offset, nk_uint y_offset)
23314{
23315 int id_len;
23316 nk_hash id_hash;
23317 struct nk_window *win;
23318 nk_uint *x_offset_ptr;
23319 nk_uint *y_offset_ptr;
23320
23321 NK_ASSERT(ctx);
23322 NK_ASSERT(id);
23323 NK_ASSERT(ctx->current);
23324 NK_ASSERT(ctx->current->layout);
23325 if (!ctx || !ctx->current || !ctx->current->layout || !id)
23326 return;
23327
23328 /* find persistent group scrollbar value */
23329 win = ctx->current;
23330 id_len = (int)nk_strlen(id);
23331 id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);
23332 x_offset_ptr = nk_find_value(win, id_hash);
23333 if (!x_offset_ptr) {
23334 x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);
23335 y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);
23336
23337 NK_ASSERT(x_offset_ptr);
23338 NK_ASSERT(y_offset_ptr);
23339 if (!x_offset_ptr || !y_offset_ptr) return;
23340 *x_offset_ptr = *y_offset_ptr = 0;
23341 } else y_offset_ptr = nk_find_value(win, id_hash+1);
23342 *x_offset_ptr = x_offset;
23343 *y_offset_ptr = y_offset;
23344}
23345
23346
23347
23348
23349/* ===============================================================
23350 *
23351 * LIST VIEW
23352 *
23353 * ===============================================================*/
23354NK_API nk_bool
23355nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,
23356 const char *title, nk_flags flags, int row_height, int row_count)
23357{
23358 int title_len;
23359 nk_hash title_hash;
23360 nk_uint *x_offset;
23361 nk_uint *y_offset;
23362
23363 int result;
23364 struct nk_window *win;
23365 struct nk_panel *layout;
23366 const struct nk_style *style;
23367 struct nk_vec2 item_spacing;
23368
23369 NK_ASSERT(ctx);
23370 NK_ASSERT(view);
23371 NK_ASSERT(title);
23372 if (!ctx || !view || !title) return 0;
23373
23374 win = ctx->current;
23375 style = &ctx->style;
23376 item_spacing = style->window.spacing;
23377 row_height += NK_MAX(0, (int)item_spacing.y);
23378
23379 /* find persistent list view scrollbar offset */
23380 title_len = (int)nk_strlen(title);
23381 title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);
23382 x_offset = nk_find_value(win, title_hash);
23383 if (!x_offset) {
23384 x_offset = nk_add_value(ctx, win, title_hash, 0);
23385 y_offset = nk_add_value(ctx, win, title_hash+1, 0);
23386
23387 NK_ASSERT(x_offset);
23388 NK_ASSERT(y_offset);
23389 if (!x_offset || !y_offset) return 0;
23390 *x_offset = *y_offset = 0;
23391 } else y_offset = nk_find_value(win, title_hash+1);
23392 view->scroll_value = *y_offset;
23393 view->scroll_pointer = y_offset;
23394
23395 *y_offset = 0;
23396 result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
23397 win = ctx->current;
23398 layout = win->layout;
23399
23400 view->total_height = row_height * NK_MAX(row_count,1);
23401 view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);
23402 view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height),0);
23403 view->count = NK_MIN(view->count, row_count - view->begin);
23404 view->end = view->begin + view->count;
23405 view->ctx = ctx;
23406 return result;
23407}
23408NK_API void
23409nk_list_view_end(struct nk_list_view *view)
23410{
23411 struct nk_context *ctx;
23412 struct nk_window *win;
23413 struct nk_panel *layout;
23414
23415 NK_ASSERT(view);
23416 NK_ASSERT(view->ctx);
23417 NK_ASSERT(view->scroll_pointer);
23418 if (!view || !view->ctx) return;
23419
23420 ctx = view->ctx;
23421 win = ctx->current;
23422 layout = win->layout;
23423 layout->at_y = layout->bounds.y + (float)view->total_height;
23424 *view->scroll_pointer = *view->scroll_pointer + view->scroll_value;
23425 nk_group_end(view->ctx);
23426}
23427
23428
23429
23430
23431
23432/* ===============================================================
23433 *
23434 * WIDGET
23435 *
23436 * ===============================================================*/
23437NK_API struct nk_rect
23438nk_widget_bounds(const struct nk_context *ctx)
23439{
23440 struct nk_rect bounds;
23441 NK_ASSERT(ctx);
23442 NK_ASSERT(ctx->current);
23443 if (!ctx || !ctx->current)
23444 return nk_rect(0,0,0,0);
23445 nk_layout_peek(&bounds, ctx);
23446 return bounds;
23447}
23448NK_API struct nk_vec2
23449nk_widget_position(const struct nk_context *ctx)
23450{
23451 struct nk_rect bounds;
23452 NK_ASSERT(ctx);
23453 NK_ASSERT(ctx->current);
23454 if (!ctx || !ctx->current)
23455 return nk_vec2(0,0);
23456
23457 nk_layout_peek(&bounds, ctx);
23458 return nk_vec2(bounds.x, bounds.y);
23459}
23460NK_API struct nk_vec2
23461nk_widget_size(const struct nk_context *ctx)
23462{
23463 struct nk_rect bounds;
23464 NK_ASSERT(ctx);
23465 NK_ASSERT(ctx->current);
23466 if (!ctx || !ctx->current)
23467 return nk_vec2(0,0);
23468
23469 nk_layout_peek(&bounds, ctx);
23470 return nk_vec2(bounds.w, bounds.h);
23471}
23472NK_API float
23473nk_widget_width(const struct nk_context *ctx)
23474{
23475 struct nk_rect bounds;
23476 NK_ASSERT(ctx);
23477 NK_ASSERT(ctx->current);
23478 if (!ctx || !ctx->current)
23479 return 0;
23480
23481 nk_layout_peek(&bounds, ctx);
23482 return bounds.w;
23483}
23484NK_API float
23485nk_widget_height(const struct nk_context *ctx)
23486{
23487 struct nk_rect bounds;
23488 NK_ASSERT(ctx);
23489 NK_ASSERT(ctx->current);
23490 if (!ctx || !ctx->current)
23491 return 0;
23492
23493 nk_layout_peek(&bounds, ctx);
23494 return bounds.h;
23495}
23496NK_API nk_bool
23497nk_widget_is_hovered(const struct nk_context *ctx)
23498{
23499 struct nk_rect c, v;
23500 struct nk_rect bounds;
23501 NK_ASSERT(ctx);
23502 NK_ASSERT(ctx->current);
23503 if (!ctx || !ctx->current || ctx->active != ctx->current)
23504 return 0;
23505
23506 c = ctx->current->layout->clip;
23507 c.x = (float)((int)c.x);
23508 c.y = (float)((int)c.y);
23509 c.w = (float)((int)c.w);
23510 c.h = (float)((int)c.h);
23511
23512 nk_layout_peek(&bounds, ctx);
23513 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
23514 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
23515 return 0;
23516 return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
23517}
23518NK_API nk_bool
23519nk_widget_is_mouse_clicked(const struct nk_context *ctx, enum nk_buttons btn)
23520{
23521 struct nk_rect c, v;
23522 struct nk_rect bounds;
23523 NK_ASSERT(ctx);
23524 NK_ASSERT(ctx->current);
23525 if (!ctx || !ctx->current || ctx->active != ctx->current)
23526 return 0;
23527
23528 c = ctx->current->layout->clip;
23529 c.x = (float)((int)c.x);
23530 c.y = (float)((int)c.y);
23531 c.w = (float)((int)c.w);
23532 c.h = (float)((int)c.h);
23533
23534 nk_layout_peek(&bounds, ctx);
23535 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
23536 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
23537 return 0;
23538 return nk_input_mouse_clicked(&ctx->input, btn, bounds);
23539}
23540NK_API nk_bool
23541nk_widget_has_mouse_click_down(const struct nk_context *ctx, enum nk_buttons btn, nk_bool down)
23542{
23543 struct nk_rect c, v;
23544 struct nk_rect bounds;
23545 NK_ASSERT(ctx);
23546 NK_ASSERT(ctx->current);
23547 if (!ctx || !ctx->current || ctx->active != ctx->current)
23548 return 0;
23549
23550 c = ctx->current->layout->clip;
23551 c.x = (float)((int)c.x);
23552 c.y = (float)((int)c.y);
23553 c.w = (float)((int)c.w);
23554 c.h = (float)((int)c.h);
23555
23556 nk_layout_peek(&bounds, ctx);
23557 nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
23558 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
23559 return 0;
23560 return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);
23561}
23562NK_API enum nk_widget_layout_states
23563nk_widget(struct nk_rect *bounds, const struct nk_context *ctx)
23564{
23565 struct nk_rect c, v;
23566 struct nk_window *win;
23567 struct nk_panel *layout;
23568 const struct nk_input *in;
23569
23570 NK_ASSERT(ctx);
23571 NK_ASSERT(ctx->current);
23572 NK_ASSERT(ctx->current->layout);
23573 if (!ctx || !ctx->current || !ctx->current->layout)
23574 return NK_WIDGET_INVALID;
23575
23576 /* allocate space and check if the widget needs to be updated and drawn */
23577 nk_panel_alloc_space(bounds, ctx);
23578 win = ctx->current;
23579 layout = win->layout;
23580 in = &ctx->input;
23581 c = layout->clip;
23582
23583 /* if one of these triggers you forgot to add an `if` condition around either
23584 a window, group, popup, combobox or contextual menu `begin` and `end` block.
23585 Example:
23586 if (nk_begin(...) {...} nk_end(...); or
23587 if (nk_group_begin(...) { nk_group_end(...);} */
23588 NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
23589 NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
23590 NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
23591
23592 /* need to convert to int here to remove floating point errors */
23593 bounds->x = (float)((int)bounds->x);
23594 bounds->y = (float)((int)bounds->y);
23595 bounds->w = (float)((int)bounds->w);
23596 bounds->h = (float)((int)bounds->h);
23597
23598 c.x = (float)((int)c.x);
23599 c.y = (float)((int)c.y);
23600 c.w = (float)((int)c.w);
23601 c.h = (float)((int)c.h);
23602
23603 nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);
23604 if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))
23605 return NK_WIDGET_INVALID;
23606 if (win->widgets_disabled)
23607 return NK_WIDGET_DISABLED;
23608 if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))
23609 return NK_WIDGET_ROM;
23610 return NK_WIDGET_VALID;
23611}
23612NK_API enum nk_widget_layout_states
23613nk_widget_fitting(struct nk_rect *bounds, const struct nk_context *ctx,
23614 struct nk_vec2 item_padding)
23615{
23616 /* update the bounds to stand without padding */
23617 enum nk_widget_layout_states state;
23618 NK_UNUSED(item_padding);
23619
23620 NK_ASSERT(ctx);
23621 NK_ASSERT(ctx->current);
23622 NK_ASSERT(ctx->current->layout);
23623 if (!ctx || !ctx->current || !ctx->current->layout)
23624 return NK_WIDGET_INVALID;
23625
23626 state = nk_widget(bounds, ctx);
23627 return state;
23628}
23629NK_API void
23630nk_spacing(struct nk_context *ctx, int cols)
23631{
23632 struct nk_window *win;
23633 struct nk_panel *layout;
23634 struct nk_rect none;
23635 int i, index, rows;
23636
23637 NK_ASSERT(ctx);
23638 NK_ASSERT(ctx->current);
23639 NK_ASSERT(ctx->current->layout);
23640 if (!ctx || !ctx->current || !ctx->current->layout)
23641 return;
23642
23643 /* spacing over row boundaries */
23644 win = ctx->current;
23645 layout = win->layout;
23646 index = (layout->row.index + cols) % layout->row.columns;
23647 rows = (layout->row.index + cols) / layout->row.columns;
23648 if (rows) {
23649 for (i = 0; i < rows; ++i)
23650 nk_panel_alloc_row(ctx, win);
23651 cols = index;
23652 }
23653 /* non table layout need to allocate space */
23654 if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&
23655 layout->row.type != NK_LAYOUT_STATIC_FIXED) {
23656 for (i = 0; i < cols; ++i)
23657 nk_panel_alloc_space(&none, ctx);
23658 } layout->row.index = index;
23659}
23660NK_API void
23661nk_widget_disable_begin(struct nk_context* ctx)
23662{
23663 struct nk_window* win;
23664 struct nk_style* style;
23665
23666 NK_ASSERT(ctx);
23667 NK_ASSERT(ctx->current);
23668
23669 if (!ctx || !ctx->current)
23670 return;
23671
23672 win = ctx->current;
23673 style = &ctx->style;
23674
23675 win->widgets_disabled = nk_true;
23676
23677 style->button.color_factor_text = style->button.disabled_factor;
23678 style->button.color_factor_background = style->button.disabled_factor;
23679 style->chart.color_factor = style->chart.disabled_factor;
23680 style->checkbox.color_factor = style->checkbox.disabled_factor;
23681 style->combo.color_factor = style->combo.disabled_factor;
23682 style->combo.button.color_factor_text = style->combo.button.disabled_factor;
23683 style->combo.button.color_factor_background = style->combo.button.disabled_factor;
23684 style->contextual_button.color_factor_text = style->contextual_button.disabled_factor;
23685 style->contextual_button.color_factor_background = style->contextual_button.disabled_factor;
23686 style->edit.color_factor = style->edit.disabled_factor;
23687 style->edit.scrollbar.color_factor = style->edit.scrollbar.disabled_factor;
23688 style->menu_button.color_factor_text = style->menu_button.disabled_factor;
23689 style->menu_button.color_factor_background = style->menu_button.disabled_factor;
23690 style->option.color_factor = style->option.disabled_factor;
23691 style->progress.color_factor = style->progress.disabled_factor;
23692 style->property.color_factor = style->property.disabled_factor;
23693 style->property.inc_button.color_factor_text = style->property.inc_button.disabled_factor;
23694 style->property.inc_button.color_factor_background = style->property.inc_button.disabled_factor;
23695 style->property.dec_button.color_factor_text = style->property.dec_button.disabled_factor;
23696 style->property.dec_button.color_factor_background = style->property.dec_button.disabled_factor;
23697 style->property.edit.color_factor = style->property.edit.disabled_factor;
23698 style->scrollh.color_factor = style->scrollh.disabled_factor;
23699 style->scrollh.inc_button.color_factor_text = style->scrollh.inc_button.disabled_factor;
23700 style->scrollh.inc_button.color_factor_background = style->scrollh.inc_button.disabled_factor;
23701 style->scrollh.dec_button.color_factor_text = style->scrollh.dec_button.disabled_factor;
23702 style->scrollh.dec_button.color_factor_background = style->scrollh.dec_button.disabled_factor;
23703 style->scrollv.color_factor = style->scrollv.disabled_factor;
23704 style->scrollv.inc_button.color_factor_text = style->scrollv.inc_button.disabled_factor;
23705 style->scrollv.inc_button.color_factor_background = style->scrollv.inc_button.disabled_factor;
23706 style->scrollv.dec_button.color_factor_text = style->scrollv.dec_button.disabled_factor;
23707 style->scrollv.dec_button.color_factor_background = style->scrollv.dec_button.disabled_factor;
23708 style->selectable.color_factor = style->selectable.disabled_factor;
23709 style->slider.color_factor = style->slider.disabled_factor;
23710 style->slider.inc_button.color_factor_text = style->slider.inc_button.disabled_factor;
23711 style->slider.inc_button.color_factor_background = style->slider.inc_button.disabled_factor;
23712 style->slider.dec_button.color_factor_text = style->slider.dec_button.disabled_factor;
23713 style->slider.dec_button.color_factor_background = style->slider.dec_button.disabled_factor;
23714 style->tab.color_factor = style->tab.disabled_factor;
23715 style->tab.node_maximize_button.color_factor_text = style->tab.node_maximize_button.disabled_factor;
23716 style->tab.node_minimize_button.color_factor_text = style->tab.node_minimize_button.disabled_factor;
23717 style->tab.tab_maximize_button.color_factor_text = style->tab.tab_maximize_button.disabled_factor;
23718 style->tab.tab_maximize_button.color_factor_background = style->tab.tab_maximize_button.disabled_factor;
23719 style->tab.tab_minimize_button.color_factor_text = style->tab.tab_minimize_button.disabled_factor;
23720 style->tab.tab_minimize_button.color_factor_background = style->tab.tab_minimize_button.disabled_factor;
23721 style->text.color_factor = style->text.disabled_factor;
23722}
23723NK_API void
23724nk_widget_disable_end(struct nk_context* ctx)
23725{
23726 struct nk_window* win;
23727 struct nk_style* style;
23728
23729 NK_ASSERT(ctx);
23730 NK_ASSERT(ctx->current);
23731
23732 if (!ctx || !ctx->current)
23733 return;
23734
23735 win = ctx->current;
23736 style = &ctx->style;
23737
23738 win->widgets_disabled = nk_false;
23739
23740 style->button.color_factor_text = 1.0f;
23741 style->button.color_factor_background = 1.0f;
23742 style->chart.color_factor = 1.0f;
23743 style->checkbox.color_factor = 1.0f;
23744 style->combo.color_factor = 1.0f;
23745 style->combo.button.color_factor_text = 1.0f;
23746 style->combo.button.color_factor_background = 1.0f;
23747 style->contextual_button.color_factor_text = 1.0f;
23748 style->contextual_button.color_factor_background = 1.0f;
23749 style->edit.color_factor = 1.0f;
23750 style->edit.scrollbar.color_factor = 1.0f;
23751 style->menu_button.color_factor_text = 1.0f;
23752 style->menu_button.color_factor_background = 1.0f;
23753 style->option.color_factor = 1.0f;
23754 style->progress.color_factor = 1.0f;
23755 style->property.color_factor = 1.0f;
23756 style->property.inc_button.color_factor_text = 1.0f;
23757 style->property.inc_button.color_factor_background = 1.0f;
23758 style->property.dec_button.color_factor_text = 1.0f;
23759 style->property.dec_button.color_factor_background = 1.0f;
23760 style->property.edit.color_factor = 1.0f;
23761 style->scrollh.color_factor = 1.0f;
23762 style->scrollh.inc_button.color_factor_text = 1.0f;
23763 style->scrollh.inc_button.color_factor_background = 1.0f;
23764 style->scrollh.dec_button.color_factor_text = 1.0f;
23765 style->scrollh.dec_button.color_factor_background = 1.0f;
23766 style->scrollv.color_factor = 1.0f;
23767 style->scrollv.inc_button.color_factor_text = 1.0f;
23768 style->scrollv.inc_button.color_factor_background = 1.0f;
23769 style->scrollv.dec_button.color_factor_text = 1.0f;
23770 style->scrollv.dec_button.color_factor_background = 1.0f;
23771 style->selectable.color_factor = 1.0f;
23772 style->slider.color_factor = 1.0f;
23773 style->slider.inc_button.color_factor_text = 1.0f;
23774 style->slider.inc_button.color_factor_background = 1.0f;
23775 style->slider.dec_button.color_factor_text = 1.0f;
23776 style->slider.dec_button.color_factor_background = 1.0f;
23777 style->tab.color_factor = 1.0f;
23778 style->tab.node_maximize_button.color_factor_text = 1.0f;
23779 style->tab.node_minimize_button.color_factor_text = 1.0f;
23780 style->tab.tab_maximize_button.color_factor_text = 1.0f;
23781 style->tab.tab_maximize_button.color_factor_background = 1.0f;
23782 style->tab.tab_minimize_button.color_factor_text = 1.0f;
23783 style->tab.tab_minimize_button.color_factor_background = 1.0f;
23784 style->text.color_factor = 1.0f;
23785}
23786
23787
23788
23789
23790/* ===============================================================
23791 *
23792 * TEXT
23793 *
23794 * ===============================================================*/
23795NK_LIB void
23796nk_widget_text(struct nk_command_buffer *o, struct nk_rect b,
23797 const char *string, int len, const struct nk_text *t,
23798 nk_flags a, const struct nk_user_font *f)
23799{
23800 struct nk_rect label;
23801 float text_width;
23802
23803 NK_ASSERT(o);
23804 NK_ASSERT(t);
23805 if (!o || !t) return;
23806
23807 b.h = NK_MAX(b.h, 2 * t->padding.y);
23808 label.x = 0; label.w = 0;
23809 label.y = b.y + t->padding.y;
23810 label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);
23811
23812 text_width = f->width(f->userdata, f->height, (const char*)string, len);
23813 text_width += (2.0f * t->padding.x);
23814
23815 /* align in x-axis */
23816 if (a & NK_TEXT_ALIGN_LEFT) {
23817 label.x = b.x + t->padding.x;
23818 label.w = NK_MAX(0, b.w - 2 * t->padding.x);
23819 } else if (a & NK_TEXT_ALIGN_CENTERED) {
23820 label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);
23821 label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);
23822 label.x = NK_MAX(b.x + t->padding.x, label.x);
23823 label.w = NK_MIN(b.x + b.w, label.x + label.w);
23824 if (label.w >= label.x) label.w -= label.x;
23825 } else if (a & NK_TEXT_ALIGN_RIGHT) {
23826 label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));
23827 label.w = (float)text_width + 2 * t->padding.x;
23828 } else return;
23829
23830 /* align in y-axis */
23831 if (a & NK_TEXT_ALIGN_MIDDLE) {
23832 label.y = b.y + b.h/2.0f - (float)f->height/2.0f;
23833 label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));
23834 } else if (a & NK_TEXT_ALIGN_BOTTOM) {
23835 label.y = b.y + b.h - f->height;
23836 label.h = f->height;
23837 }
23838 nk_draw_text(o, label, (const char*)string, len, f, t->background, t->text);
23839}
23840NK_LIB void
23841nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,
23842 const char *string, int len, const struct nk_text *t,
23843 const struct nk_user_font *f)
23844{
23845 float width;
23846 int glyphs = 0;
23847 int fitting = 0;
23848 int done = 0;
23849 struct nk_rect line;
23850 struct nk_text text;
23851 NK_INTERN nk_rune seperator[] = {' '};
23852
23853 NK_ASSERT(o);
23854 NK_ASSERT(t);
23855 if (!o || !t) return;
23856
23857 text.padding = nk_vec2(0,0);
23858 text.background = t->background;
23859 text.text = t->text;
23860
23861 b.w = NK_MAX(b.w, 2 * t->padding.x);
23862 b.h = NK_MAX(b.h, 2 * t->padding.y);
23863 b.h = b.h - 2 * t->padding.y;
23864
23865 line.x = b.x + t->padding.x;
23866 line.y = b.y + t->padding.y;
23867 line.w = b.w - 2 * t->padding.x;
23868 line.h = 2 * t->padding.y + f->height;
23869
23870 fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
23871 while (done < len) {
23872 if (!fitting || line.y + line.h >= (b.y + b.h)) break;
23873 nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);
23874 done += fitting;
23875 line.y += f->height + 2 * t->padding.y;
23876 fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));
23877 }
23878}
23879NK_API void
23880nk_text_colored(struct nk_context *ctx, const char *str, int len,
23881 nk_flags alignment, struct nk_color color)
23882{
23883 struct nk_window *win;
23884 const struct nk_style *style;
23885
23886 struct nk_vec2 item_padding;
23887 struct nk_rect bounds;
23888 struct nk_text text;
23889
23890 NK_ASSERT(ctx);
23891 NK_ASSERT(ctx->current);
23892 NK_ASSERT(ctx->current->layout);
23893 if (!ctx || !ctx->current || !ctx->current->layout) return;
23894
23895 win = ctx->current;
23896 style = &ctx->style;
23897 nk_panel_alloc_space(&bounds, ctx);
23898 item_padding = style->text.padding;
23899
23900 text.padding.x = item_padding.x;
23901 text.padding.y = item_padding.y;
23902 text.background = style->window.background;
23903 text.text = nk_rgb_factor(color, style->text.color_factor);
23904 nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);
23905}
23906NK_API void
23907nk_text_wrap_colored(struct nk_context *ctx, const char *str,
23908 int len, struct nk_color color)
23909{
23910 struct nk_window *win;
23911 const struct nk_style *style;
23912
23913 struct nk_vec2 item_padding;
23914 struct nk_rect bounds;
23915 struct nk_text text;
23916
23917 NK_ASSERT(ctx);
23918 NK_ASSERT(ctx->current);
23919 NK_ASSERT(ctx->current->layout);
23920 if (!ctx || !ctx->current || !ctx->current->layout) return;
23921
23922 win = ctx->current;
23923 style = &ctx->style;
23924 nk_panel_alloc_space(&bounds, ctx);
23925 item_padding = style->text.padding;
23926
23927 text.padding.x = item_padding.x;
23928 text.padding.y = item_padding.y;
23929 text.background = style->window.background;
23930 text.text = nk_rgb_factor(color, style->text.color_factor);
23931 nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);
23932}
23933#ifdef NK_INCLUDE_STANDARD_VARARGS
23934NK_API void
23935nk_labelf_colored(struct nk_context *ctx, nk_flags flags,
23936 struct nk_color color, const char *fmt, ...)
23937{
23938 va_list args;
23939 va_start(args, fmt);
23940 nk_labelfv_colored(ctx, flags, color, fmt, args);
23941 va_end(args);
23942}
23943NK_API void
23944nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,
23945 const char *fmt, ...)
23946{
23947 va_list args;
23948 va_start(args, fmt);
23949 nk_labelfv_colored_wrap(ctx, color, fmt, args);
23950 va_end(args);
23951}
23952NK_API void
23953nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)
23954{
23955 va_list args;
23956 va_start(args, fmt);
23957 nk_labelfv(ctx, flags, fmt, args);
23958 va_end(args);
23959}
23960NK_API void
23961nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)
23962{
23963 va_list args;
23964 va_start(args, fmt);
23965 nk_labelfv_wrap(ctx, fmt, args);
23966 va_end(args);
23967}
23968NK_API void
23969nk_labelfv_colored(struct nk_context *ctx, nk_flags flags,
23970 struct nk_color color, const char *fmt, va_list args)
23971{
23972 char buf[256];
23973 nk_strfmt(buf, NK_LEN(buf), fmt, args);
23974 nk_label_colored(ctx, buf, flags, color);
23975}
23976
23977NK_API void
23978nk_labelfv_colored_wrap(struct nk_context *ctx, struct nk_color color,
23979 const char *fmt, va_list args)
23980{
23981 char buf[256];
23982 nk_strfmt(buf, NK_LEN(buf), fmt, args);
23983 nk_label_colored_wrap(ctx, buf, color);
23984}
23985
23986NK_API void
23987nk_labelfv(struct nk_context *ctx, nk_flags flags, const char *fmt, va_list args)
23988{
23989 char buf[256];
23990 nk_strfmt(buf, NK_LEN(buf), fmt, args);
23991 nk_label(ctx, buf, flags);
23992}
23993
23994NK_API void
23995nk_labelfv_wrap(struct nk_context *ctx, const char *fmt, va_list args)
23996{
23997 char buf[256];
23998 nk_strfmt(buf, NK_LEN(buf), fmt, args);
23999 nk_label_wrap(ctx, buf);
24000}
24001
24002NK_API void
24003nk_value_bool(struct nk_context *ctx, const char *prefix, int value)
24004{
24005 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));
24006}
24007NK_API void
24008nk_value_int(struct nk_context *ctx, const char *prefix, int value)
24009{
24010 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);
24011}
24012NK_API void
24013nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)
24014{
24015 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);
24016}
24017NK_API void
24018nk_value_float(struct nk_context *ctx, const char *prefix, float value)
24019{
24020 double double_value = (double)value;
24021 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value);
24022}
24023NK_API void
24024nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)
24025{
24026 nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);
24027}
24028NK_API void
24029nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)
24030{
24031 double c[4]; nk_color_dv(c, color);
24032 nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)",
24033 p, c[0], c[1], c[2], c[3]);
24034}
24035NK_API void
24036nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)
24037{
24038 char hex[16];
24039 nk_color_hex_rgba(hex, color);
24040 nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex);
24041}
24042#endif
24043NK_API void
24044nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)
24045{
24046 NK_ASSERT(ctx);
24047 if (!ctx) return;
24048 nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);
24049}
24050NK_API void
24051nk_text_wrap(struct nk_context *ctx, const char *str, int len)
24052{
24053 NK_ASSERT(ctx);
24054 if (!ctx) return;
24055 nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);
24056}
24057NK_API void
24058nk_label(struct nk_context *ctx, const char *str, nk_flags alignment)
24059{
24060 nk_text(ctx, str, nk_strlen(str), alignment);
24061}
24062NK_API void
24063nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,
24064 struct nk_color color)
24065{
24066 nk_text_colored(ctx, str, nk_strlen(str), align, color);
24067}
24068NK_API void
24069nk_label_wrap(struct nk_context *ctx, const char *str)
24070{
24071 nk_text_wrap(ctx, str, nk_strlen(str));
24072}
24073NK_API void
24074nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)
24075{
24076 nk_text_wrap_colored(ctx, str, nk_strlen(str), color);
24077}
24078
24079
24080
24081
24082
24083/* ===============================================================
24084 *
24085 * IMAGE
24086 *
24087 * ===============================================================*/
24088NK_API nk_handle
24089nk_handle_ptr(void *ptr)
24090{
24091 nk_handle handle = {0};
24092 handle.ptr = ptr;
24093 return handle;
24094}
24095NK_API nk_handle
24096nk_handle_id(int id)
24097{
24098 nk_handle handle;
24099 nk_zero_struct(handle);
24100 handle.id = id;
24101 return handle;
24102}
24103NK_API struct nk_image
24104nk_subimage_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect r)
24105{
24106 struct nk_image s;
24107 nk_zero(&s, sizeof(s));
24108 s.handle.ptr = ptr;
24109 s.w = w; s.h = h;
24110 s.region[0] = (nk_ushort)r.x;
24111 s.region[1] = (nk_ushort)r.y;
24112 s.region[2] = (nk_ushort)r.w;
24113 s.region[3] = (nk_ushort)r.h;
24114 return s;
24115}
24116NK_API struct nk_image
24117nk_subimage_id(int id, nk_ushort w, nk_ushort h, struct nk_rect r)
24118{
24119 struct nk_image s;
24120 nk_zero(&s, sizeof(s));
24121 s.handle.id = id;
24122 s.w = w; s.h = h;
24123 s.region[0] = (nk_ushort)r.x;
24124 s.region[1] = (nk_ushort)r.y;
24125 s.region[2] = (nk_ushort)r.w;
24126 s.region[3] = (nk_ushort)r.h;
24127 return s;
24128}
24129NK_API struct nk_image
24130nk_subimage_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect r)
24131{
24132 struct nk_image s;
24133 nk_zero(&s, sizeof(s));
24134 s.handle = handle;
24135 s.w = w; s.h = h;
24136 s.region[0] = (nk_ushort)r.x;
24137 s.region[1] = (nk_ushort)r.y;
24138 s.region[2] = (nk_ushort)r.w;
24139 s.region[3] = (nk_ushort)r.h;
24140 return s;
24141}
24142NK_API struct nk_image
24143nk_image_handle(nk_handle handle)
24144{
24145 struct nk_image s;
24146 nk_zero(&s, sizeof(s));
24147 s.handle = handle;
24148 s.w = 0; s.h = 0;
24149 s.region[0] = 0;
24150 s.region[1] = 0;
24151 s.region[2] = 0;
24152 s.region[3] = 0;
24153 return s;
24154}
24155NK_API struct nk_image
24156nk_image_ptr(void *ptr)
24157{
24158 struct nk_image s;
24159 nk_zero(&s, sizeof(s));
24160 NK_ASSERT(ptr);
24161 s.handle.ptr = ptr;
24162 s.w = 0; s.h = 0;
24163 s.region[0] = 0;
24164 s.region[1] = 0;
24165 s.region[2] = 0;
24166 s.region[3] = 0;
24167 return s;
24168}
24169NK_API struct nk_image
24170nk_image_id(int id)
24171{
24172 struct nk_image s;
24173 nk_zero(&s, sizeof(s));
24174 s.handle.id = id;
24175 s.w = 0; s.h = 0;
24176 s.region[0] = 0;
24177 s.region[1] = 0;
24178 s.region[2] = 0;
24179 s.region[3] = 0;
24180 return s;
24181}
24182NK_API nk_bool
24183nk_image_is_subimage(const struct nk_image* img)
24184{
24185 NK_ASSERT(img);
24186 return !(img->w == 0 && img->h == 0);
24187}
24188NK_API void
24189nk_image(struct nk_context *ctx, struct nk_image img)
24190{
24191 struct nk_window *win;
24192 struct nk_rect bounds;
24193
24194 NK_ASSERT(ctx);
24195 NK_ASSERT(ctx->current);
24196 NK_ASSERT(ctx->current->layout);
24197 if (!ctx || !ctx->current || !ctx->current->layout) return;
24198
24199 win = ctx->current;
24200 if (!nk_widget(&bounds, ctx)) return;
24201 nk_draw_image(&win->buffer, bounds, &img, nk_white);
24202}
24203NK_API void
24204nk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col)
24205{
24206 struct nk_window *win;
24207 struct nk_rect bounds;
24208
24209 NK_ASSERT(ctx);
24210 NK_ASSERT(ctx->current);
24211 NK_ASSERT(ctx->current->layout);
24212 if (!ctx || !ctx->current || !ctx->current->layout) return;
24213
24214 win = ctx->current;
24215 if (!nk_widget(&bounds, ctx)) return;
24216 nk_draw_image(&win->buffer, bounds, &img, col);
24217}
24218
24219
24220
24221
24222
24223/* ===============================================================
24224 *
24225 * 9-SLICE
24226 *
24227 * ===============================================================*/
24228NK_API struct nk_nine_slice
24229nk_sub9slice_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24230{
24231 struct nk_nine_slice s;
24232 struct nk_image *i = &s.img;
24233 nk_zero(&s, sizeof(s));
24234 i->handle.ptr = ptr;
24235 i->w = w; i->h = h;
24236 i->region[0] = (nk_ushort)rgn.x;
24237 i->region[1] = (nk_ushort)rgn.y;
24238 i->region[2] = (nk_ushort)rgn.w;
24239 i->region[3] = (nk_ushort)rgn.h;
24240 s.l = l; s.t = t; s.r = r; s.b = b;
24241 return s;
24242}
24243NK_API struct nk_nine_slice
24244nk_sub9slice_id(int id, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24245{
24246 struct nk_nine_slice s;
24247 struct nk_image *i = &s.img;
24248 nk_zero(&s, sizeof(s));
24249 i->handle.id = id;
24250 i->w = w; i->h = h;
24251 i->region[0] = (nk_ushort)rgn.x;
24252 i->region[1] = (nk_ushort)rgn.y;
24253 i->region[2] = (nk_ushort)rgn.w;
24254 i->region[3] = (nk_ushort)rgn.h;
24255 s.l = l; s.t = t; s.r = r; s.b = b;
24256 return s;
24257}
24258NK_API struct nk_nine_slice
24259nk_sub9slice_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24260{
24261 struct nk_nine_slice s;
24262 struct nk_image *i = &s.img;
24263 nk_zero(&s, sizeof(s));
24264 i->handle = handle;
24265 i->w = w; i->h = h;
24266 i->region[0] = (nk_ushort)rgn.x;
24267 i->region[1] = (nk_ushort)rgn.y;
24268 i->region[2] = (nk_ushort)rgn.w;
24269 i->region[3] = (nk_ushort)rgn.h;
24270 s.l = l; s.t = t; s.r = r; s.b = b;
24271 return s;
24272}
24273NK_API struct nk_nine_slice
24274nk_nine_slice_handle(nk_handle handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24275{
24276 struct nk_nine_slice s;
24277 struct nk_image *i = &s.img;
24278 nk_zero(&s, sizeof(s));
24279 i->handle = handle;
24280 i->w = 0; i->h = 0;
24281 i->region[0] = 0;
24282 i->region[1] = 0;
24283 i->region[2] = 0;
24284 i->region[3] = 0;
24285 s.l = l; s.t = t; s.r = r; s.b = b;
24286 return s;
24287}
24288NK_API struct nk_nine_slice
24289nk_nine_slice_ptr(void *ptr, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24290{
24291 struct nk_nine_slice s;
24292 struct nk_image *i = &s.img;
24293 nk_zero(&s, sizeof(s));
24294 NK_ASSERT(ptr);
24295 i->handle.ptr = ptr;
24296 i->w = 0; i->h = 0;
24297 i->region[0] = 0;
24298 i->region[1] = 0;
24299 i->region[2] = 0;
24300 i->region[3] = 0;
24301 s.l = l; s.t = t; s.r = r; s.b = b;
24302 return s;
24303}
24304NK_API struct nk_nine_slice
24305nk_nine_slice_id(int id, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
24306{
24307 struct nk_nine_slice s;
24308 struct nk_image *i = &s.img;
24309 nk_zero(&s, sizeof(s));
24310 i->handle.id = id;
24311 i->w = 0; i->h = 0;
24312 i->region[0] = 0;
24313 i->region[1] = 0;
24314 i->region[2] = 0;
24315 i->region[3] = 0;
24316 s.l = l; s.t = t; s.r = r; s.b = b;
24317 return s;
24318}
24319NK_API int
24320nk_nine_slice_is_sub9slice(const struct nk_nine_slice* slice)
24321{
24322 NK_ASSERT(slice);
24323 return !(slice->img.w == 0 && slice->img.h == 0);
24324}
24325
24326
24327
24328
24329
24330/* ==============================================================
24331 *
24332 * BUTTON
24333 *
24334 * ===============================================================*/
24335NK_LIB void
24336nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,
24337 struct nk_rect content, struct nk_color background, struct nk_color foreground,
24338 float border_width, const struct nk_user_font *font)
24339{
24340 switch (type) {
24341 case NK_SYMBOL_X:
24342 case NK_SYMBOL_UNDERSCORE:
24343 case NK_SYMBOL_PLUS:
24344 case NK_SYMBOL_MINUS: {
24345 /* single character text symbol */
24346 const char *X = (type == NK_SYMBOL_X) ? "x":
24347 (type == NK_SYMBOL_UNDERSCORE) ? "_":
24348 (type == NK_SYMBOL_PLUS) ? "+": "-";
24349 struct nk_text text;
24350 text.padding = nk_vec2(0,0);
24351 text.background = background;
24352 text.text = foreground;
24353 nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);
24354 } break;
24355 case NK_SYMBOL_CIRCLE_SOLID:
24356 case NK_SYMBOL_CIRCLE_OUTLINE:
24357 case NK_SYMBOL_RECT_SOLID:
24358 case NK_SYMBOL_RECT_OUTLINE: {
24359 /* simple empty/filled shapes */
24360 if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {
24361 nk_fill_rect(out, content, 0, foreground);
24362 if (type == NK_SYMBOL_RECT_OUTLINE)
24363 nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);
24364 } else {
24365 nk_fill_circle(out, content, foreground);
24366 if (type == NK_SYMBOL_CIRCLE_OUTLINE)
24367 nk_fill_circle(out, nk_shrink_rect(content, 1), background);
24368 }
24369 } break;
24370 case NK_SYMBOL_TRIANGLE_UP:
24371 case NK_SYMBOL_TRIANGLE_DOWN:
24372 case NK_SYMBOL_TRIANGLE_LEFT:
24373 case NK_SYMBOL_TRIANGLE_RIGHT: {
24374 enum nk_heading heading;
24375 struct nk_vec2 points[3];
24376 heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :
24377 (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:
24378 (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;
24379 nk_triangle_from_direction(points, content, 0, 0, heading);
24380 nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,
24381 points[2].x, points[2].y, foreground);
24382 } break;
24383 case NK_SYMBOL_TRIANGLE_UP_OUTLINE:
24384 case NK_SYMBOL_TRIANGLE_DOWN_OUTLINE:
24385 case NK_SYMBOL_TRIANGLE_LEFT_OUTLINE:
24386 case NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE: {
24387 enum nk_heading heading;
24388 struct nk_vec2 points[3];
24389 heading = (type == NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE) ? NK_RIGHT :
24390 (type == NK_SYMBOL_TRIANGLE_LEFT_OUTLINE) ? NK_LEFT:
24391 (type == NK_SYMBOL_TRIANGLE_UP_OUTLINE) ? NK_UP: NK_DOWN;
24392 nk_triangle_from_direction(points, content, 0, 0, heading);
24393 nk_stroke_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,
24394 points[2].x, points[2].y, border_width, foreground);
24395 } break;
24396 default:
24397 case NK_SYMBOL_NONE:
24398 case NK_SYMBOL_MAX: break;
24399 }
24400}
24401NK_LIB nk_bool
24402nk_button_behavior(nk_flags *state, struct nk_rect r,
24403 const struct nk_input *i, enum nk_button_behavior behavior)
24404{
24405 int ret = 0;
24406 nk_widget_state_reset(state);
24407 if (!i) return 0;
24408 if (nk_input_is_mouse_hovering_rect(i, r)) {
24409 *state = NK_WIDGET_STATE_HOVERED;
24410 if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))
24411 *state = NK_WIDGET_STATE_ACTIVE;
24412 if (nk_input_has_mouse_click_in_button_rect(i, NK_BUTTON_LEFT, r)) {
24413 ret = (behavior != NK_BUTTON_DEFAULT) ?
24414 nk_input_is_mouse_down(i, NK_BUTTON_LEFT):
24415#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
24416 nk_input_is_mouse_released(i, NK_BUTTON_LEFT);
24417#else
24418 nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);
24419#endif
24420 }
24421 }
24422 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))
24423 *state |= NK_WIDGET_STATE_ENTERED;
24424 else if (nk_input_is_mouse_prev_hovering_rect(i, r))
24425 *state |= NK_WIDGET_STATE_LEFT;
24426 return ret;
24427}
24428NK_LIB const struct nk_style_item*
24429nk_draw_button(struct nk_command_buffer *out,
24430 const struct nk_rect *bounds, nk_flags state,
24431 const struct nk_style_button *style)
24432{
24433 const struct nk_style_item *background;
24434 if (state & NK_WIDGET_STATE_HOVER)
24435 background = &style->hover;
24436 else if (state & NK_WIDGET_STATE_ACTIVED)
24437 background = &style->active;
24438 else background = &style->normal;
24439
24440 switch (background->type) {
24441 case NK_STYLE_ITEM_IMAGE:
24442 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor_background));
24443 break;
24444 case NK_STYLE_ITEM_NINE_SLICE:
24445 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor_background));
24446 break;
24447 case NK_STYLE_ITEM_COLOR:
24448 nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor_background));
24449 nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor_background));
24450 break;
24451 }
24452 return background;
24453}
24454NK_LIB nk_bool
24455nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,
24456 const struct nk_style_button *style, const struct nk_input *in,
24457 enum nk_button_behavior behavior, struct nk_rect *content)
24458{
24459 struct nk_rect bounds;
24460 NK_ASSERT(style);
24461 NK_ASSERT(state);
24462 NK_ASSERT(out);
24463 if (!out || !style)
24464 return nk_false;
24465
24466 /* calculate button content space */
24467 content->x = r.x + style->padding.x + style->border + style->rounding;
24468 content->y = r.y + style->padding.y + style->border + style->rounding;
24469 content->w = r.w - (2 * (style->padding.x + style->border + style->rounding));
24470 content->h = r.h - (2 * (style->padding.y + style->border + style->rounding));
24471
24472 /* execute button behavior */
24473 bounds.x = r.x - style->touch_padding.x;
24474 bounds.y = r.y - style->touch_padding.y;
24475 bounds.w = r.w + 2 * style->touch_padding.x;
24476 bounds.h = r.h + 2 * style->touch_padding.y;
24477 return nk_button_behavior(state, bounds, in, behavior);
24478}
24479NK_LIB void
24480nk_draw_button_text(struct nk_command_buffer *out,
24481 const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,
24482 const struct nk_style_button *style, const char *txt, int len,
24483 nk_flags text_alignment, const struct nk_user_font *font)
24484{
24485 struct nk_text text;
24486 const struct nk_style_item *background;
24487 background = nk_draw_button(out, bounds, state, style);
24488
24489 /* select correct colors/images */
24490 if (background->type == NK_STYLE_ITEM_COLOR)
24491 text.background = background->data.color;
24492 else text.background = style->text_background;
24493 if (state & NK_WIDGET_STATE_HOVER)
24494 text.text = style->text_hover;
24495 else if (state & NK_WIDGET_STATE_ACTIVED)
24496 text.text = style->text_active;
24497 else text.text = style->text_normal;
24498
24499 text.text = nk_rgb_factor(text.text, style->color_factor_text);
24500
24501 text.padding = nk_vec2(0,0);
24502 nk_widget_text(out, *content, txt, len, &text, text_alignment, font);
24503}
24504NK_LIB nk_bool
24505nk_do_button_text(nk_flags *state,
24506 struct nk_command_buffer *out, struct nk_rect bounds,
24507 const char *string, int len, nk_flags align, enum nk_button_behavior behavior,
24508 const struct nk_style_button *style, const struct nk_input *in,
24509 const struct nk_user_font *font)
24510{
24511 struct nk_rect content;
24512 int ret = nk_false;
24513
24514 NK_ASSERT(state);
24515 NK_ASSERT(style);
24516 NK_ASSERT(out);
24517 NK_ASSERT(string);
24518 NK_ASSERT(font);
24519 if (!out || !style || !font || !string)
24520 return nk_false;
24521
24522 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
24523 if (style->draw_begin) style->draw_begin(out, style->userdata);
24524 nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);
24525 if (style->draw_end) style->draw_end(out, style->userdata);
24526 return ret;
24527}
24528NK_LIB void
24529nk_draw_button_symbol(struct nk_command_buffer *out,
24530 const struct nk_rect *bounds, const struct nk_rect *content,
24531 nk_flags state, const struct nk_style_button *style,
24532 enum nk_symbol_type type, const struct nk_user_font *font)
24533{
24534 struct nk_color sym, bg;
24535 const struct nk_style_item *background;
24536
24537 /* select correct colors/images */
24538 background = nk_draw_button(out, bounds, state, style);
24539 if (background->type == NK_STYLE_ITEM_COLOR)
24540 bg = background->data.color;
24541 else bg = style->text_background;
24542
24543 if (state & NK_WIDGET_STATE_HOVER)
24544 sym = style->text_hover;
24545 else if (state & NK_WIDGET_STATE_ACTIVED)
24546 sym = style->text_active;
24547 else sym = style->text_normal;
24548
24549 sym = nk_rgb_factor(sym, style->color_factor_text);
24550 nk_draw_symbol(out, type, *content, bg, sym, 1, font);
24551}
24552NK_LIB nk_bool
24553nk_do_button_symbol(nk_flags *state,
24554 struct nk_command_buffer *out, struct nk_rect bounds,
24555 enum nk_symbol_type symbol, enum nk_button_behavior behavior,
24556 const struct nk_style_button *style, const struct nk_input *in,
24557 const struct nk_user_font *font)
24558{
24559 int ret;
24560 struct nk_rect content;
24561
24562 NK_ASSERT(state);
24563 NK_ASSERT(style);
24564 NK_ASSERT(font);
24565 NK_ASSERT(out);
24566 if (!out || !style || !font || !state)
24567 return nk_false;
24568
24569 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
24570 if (style->draw_begin) style->draw_begin(out, style->userdata);
24571 nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);
24572 if (style->draw_end) style->draw_end(out, style->userdata);
24573 return ret;
24574}
24575NK_LIB void
24576nk_draw_button_image(struct nk_command_buffer *out,
24577 const struct nk_rect *bounds, const struct nk_rect *content,
24578 nk_flags state, const struct nk_style_button *style, const struct nk_image *img)
24579{
24580 nk_draw_button(out, bounds, state, style);
24581 nk_draw_image(out, *content, img, nk_rgb_factor(nk_white, style->color_factor_background));
24582}
24583NK_LIB nk_bool
24584nk_do_button_image(nk_flags *state,
24585 struct nk_command_buffer *out, struct nk_rect bounds,
24586 struct nk_image img, enum nk_button_behavior b,
24587 const struct nk_style_button *style, const struct nk_input *in)
24588{
24589 int ret;
24590 struct nk_rect content;
24591
24592 NK_ASSERT(state);
24593 NK_ASSERT(style);
24594 NK_ASSERT(out);
24595 if (!out || !style || !state)
24596 return nk_false;
24597
24598 ret = nk_do_button(state, out, bounds, style, in, b, &content);
24599 content.x += style->image_padding.x;
24600 content.y += style->image_padding.y;
24601 content.w -= 2 * style->image_padding.x;
24602 content.h -= 2 * style->image_padding.y;
24603
24604 if (style->draw_begin) style->draw_begin(out, style->userdata);
24605 nk_draw_button_image(out, &bounds, &content, *state, style, &img);
24606 if (style->draw_end) style->draw_end(out, style->userdata);
24607 return ret;
24608}
24609NK_LIB void
24610nk_draw_button_text_symbol(struct nk_command_buffer *out,
24611 const struct nk_rect *bounds, const struct nk_rect *label,
24612 const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,
24613 const char *str, int len, enum nk_symbol_type type,
24614 const struct nk_user_font *font)
24615{
24616 struct nk_color sym;
24617 struct nk_text text;
24618 const struct nk_style_item *background;
24619
24620 /* select correct background colors/images */
24621 background = nk_draw_button(out, bounds, state, style);
24622 if (background->type == NK_STYLE_ITEM_COLOR)
24623 text.background = background->data.color;
24624 else text.background = style->text_background;
24625
24626 /* select correct text colors */
24627 if (state & NK_WIDGET_STATE_HOVER) {
24628 sym = style->text_hover;
24629 text.text = style->text_hover;
24630 } else if (state & NK_WIDGET_STATE_ACTIVED) {
24631 sym = style->text_active;
24632 text.text = style->text_active;
24633 } else {
24634 sym = style->text_normal;
24635 text.text = style->text_normal;
24636 }
24637
24638 sym = nk_rgb_factor(sym, style->color_factor_text);
24639 text.text = nk_rgb_factor(text.text, style->color_factor_text);
24640 text.padding = nk_vec2(0,0);
24641 nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);
24642 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
24643}
24644NK_LIB nk_bool
24645nk_do_button_text_symbol(nk_flags *state,
24646 struct nk_command_buffer *out, struct nk_rect bounds,
24647 enum nk_symbol_type symbol, const char *str, int len, nk_flags align,
24648 enum nk_button_behavior behavior, const struct nk_style_button *style,
24649 const struct nk_user_font *font, const struct nk_input *in)
24650{
24651 int ret;
24652 struct nk_rect tri = {0,0,0,0};
24653 struct nk_rect content;
24654
24655 NK_ASSERT(style);
24656 NK_ASSERT(out);
24657 NK_ASSERT(font);
24658 if (!out || !style || !font)
24659 return nk_false;
24660
24661 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
24662 tri.y = content.y + (content.h/2) - font->height/2;
24663 tri.w = font->height; tri.h = font->height;
24664 if (align & NK_TEXT_ALIGN_LEFT) {
24665 tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);
24666 tri.x = NK_MAX(tri.x, 0);
24667 } else tri.x = content.x + 2 * style->padding.x;
24668
24669 /* draw button */
24670 if (style->draw_begin) style->draw_begin(out, style->userdata);
24671 nk_draw_button_text_symbol(out, &bounds, &content, &tri,
24672 *state, style, str, len, symbol, font);
24673 if (style->draw_end) style->draw_end(out, style->userdata);
24674 return ret;
24675}
24676NK_LIB void
24677nk_draw_button_text_image(struct nk_command_buffer *out,
24678 const struct nk_rect *bounds, const struct nk_rect *label,
24679 const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,
24680 const char *str, int len, const struct nk_user_font *font,
24681 const struct nk_image *img)
24682{
24683 struct nk_text text;
24684 const struct nk_style_item *background;
24685 background = nk_draw_button(out, bounds, state, style);
24686
24687 /* select correct colors */
24688 if (background->type == NK_STYLE_ITEM_COLOR)
24689 text.background = background->data.color;
24690 else text.background = style->text_background;
24691 if (state & NK_WIDGET_STATE_HOVER)
24692 text.text = style->text_hover;
24693 else if (state & NK_WIDGET_STATE_ACTIVED)
24694 text.text = style->text_active;
24695 else text.text = style->text_normal;
24696
24697 text.text = nk_rgb_factor(text.text, style->color_factor_text);
24698 text.padding = nk_vec2(0, 0);
24699 nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);
24700 nk_draw_image(out, *image, img, nk_rgb_factor(nk_white, style->color_factor_background));
24701}
24702NK_LIB nk_bool
24703nk_do_button_text_image(nk_flags *state,
24704 struct nk_command_buffer *out, struct nk_rect bounds,
24705 struct nk_image img, const char* str, int len, nk_flags align,
24706 enum nk_button_behavior behavior, const struct nk_style_button *style,
24707 const struct nk_user_font *font, const struct nk_input *in)
24708{
24709 int ret;
24710 struct nk_rect icon;
24711 struct nk_rect content;
24712
24713 NK_ASSERT(style);
24714 NK_ASSERT(state);
24715 NK_ASSERT(font);
24716 NK_ASSERT(out);
24717 if (!out || !font || !style || !str)
24718 return nk_false;
24719
24720 ret = nk_do_button(state, out, bounds, style, in, behavior, &content);
24721 icon.y = bounds.y + style->padding.y;
24722 icon.w = icon.h = bounds.h - 2 * style->padding.y;
24723 if (align & NK_TEXT_ALIGN_LEFT) {
24724 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
24725 icon.x = NK_MAX(icon.x, 0);
24726 } else icon.x = bounds.x + 2 * style->padding.x;
24727
24728 icon.x += style->image_padding.x;
24729 icon.y += style->image_padding.y;
24730 icon.w -= 2 * style->image_padding.x;
24731 icon.h -= 2 * style->image_padding.y;
24732
24733 if (style->draw_begin) style->draw_begin(out, style->userdata);
24734 nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);
24735 if (style->draw_end) style->draw_end(out, style->userdata);
24736 return ret;
24737}
24738NK_API void
24739nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
24740{
24741 NK_ASSERT(ctx);
24742 if (!ctx) return;
24743 ctx->button_behavior = behavior;
24744}
24745NK_API nk_bool
24746nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)
24747{
24748 struct nk_config_stack_button_behavior *button_stack;
24749 struct nk_config_stack_button_behavior_element *element;
24750
24751 NK_ASSERT(ctx);
24752 if (!ctx) return 0;
24753
24754 button_stack = &ctx->stacks.button_behaviors;
24755 NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));
24756 if (button_stack->head >= (int)NK_LEN(button_stack->elements))
24757 return 0;
24758
24759 element = &button_stack->elements[button_stack->head++];
24760 element->address = &ctx->button_behavior;
24761 element->old_value = ctx->button_behavior;
24762 ctx->button_behavior = behavior;
24763 return 1;
24764}
24765NK_API nk_bool
24766nk_button_pop_behavior(struct nk_context *ctx)
24767{
24768 struct nk_config_stack_button_behavior *button_stack;
24769 struct nk_config_stack_button_behavior_element *element;
24770
24771 NK_ASSERT(ctx);
24772 if (!ctx) return 0;
24773
24774 button_stack = &ctx->stacks.button_behaviors;
24775 NK_ASSERT(button_stack->head > 0);
24776 if (button_stack->head < 1)
24777 return 0;
24778
24779 element = &button_stack->elements[--button_stack->head];
24780 *element->address = element->old_value;
24781 return 1;
24782}
24783NK_API nk_bool
24784nk_button_text_styled(struct nk_context *ctx,
24785 const struct nk_style_button *style, const char *title, int len)
24786{
24787 struct nk_window *win;
24788 struct nk_panel *layout;
24789 const struct nk_input *in;
24790
24791 struct nk_rect bounds;
24792 enum nk_widget_layout_states state;
24793
24794 NK_ASSERT(ctx);
24795 NK_ASSERT(style);
24796 NK_ASSERT(ctx->current);
24797 NK_ASSERT(ctx->current->layout);
24798 if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;
24799
24800 win = ctx->current;
24801 layout = win->layout;
24802 state = nk_widget(&bounds, ctx);
24803
24804 if (!state) return 0;
24805 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24806 return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
24807 title, len, style->text_alignment, ctx->button_behavior,
24808 style, in, ctx->style.font);
24809}
24810NK_API nk_bool
24811nk_button_text(struct nk_context *ctx, const char *title, int len)
24812{
24813 NK_ASSERT(ctx);
24814 if (!ctx) return 0;
24815 return nk_button_text_styled(ctx, &ctx->style.button, title, len);
24816}
24817NK_API nk_bool nk_button_label_styled(struct nk_context *ctx,
24818 const struct nk_style_button *style, const char *title)
24819{
24820 return nk_button_text_styled(ctx, style, title, nk_strlen(title));
24821}
24822NK_API nk_bool nk_button_label(struct nk_context *ctx, const char *title)
24823{
24824 return nk_button_text(ctx, title, nk_strlen(title));
24825}
24826NK_API nk_bool
24827nk_button_color(struct nk_context *ctx, struct nk_color color)
24828{
24829 struct nk_window *win;
24830 struct nk_panel *layout;
24831 const struct nk_input *in;
24832 struct nk_style_button button;
24833
24834 int ret = 0;
24835 struct nk_rect bounds;
24836 struct nk_rect content;
24837 enum nk_widget_layout_states state;
24838
24839 NK_ASSERT(ctx);
24840 NK_ASSERT(ctx->current);
24841 NK_ASSERT(ctx->current->layout);
24842 if (!ctx || !ctx->current || !ctx->current->layout)
24843 return 0;
24844
24845 win = ctx->current;
24846 layout = win->layout;
24847
24848 state = nk_widget(&bounds, ctx);
24849 if (!state) return 0;
24850 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24851
24852 button = ctx->style.button;
24853 button.normal = nk_style_item_color(color);
24854 button.hover = nk_style_item_color(color);
24855 button.active = nk_style_item_color(color);
24856 ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,
24857 &button, in, ctx->button_behavior, &content);
24858 nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);
24859 return ret;
24860}
24861NK_API nk_bool
24862nk_button_symbol_styled(struct nk_context *ctx,
24863 const struct nk_style_button *style, enum nk_symbol_type symbol)
24864{
24865 struct nk_window *win;
24866 struct nk_panel *layout;
24867 const struct nk_input *in;
24868
24869 struct nk_rect bounds;
24870 enum nk_widget_layout_states state;
24871
24872 NK_ASSERT(ctx);
24873 NK_ASSERT(ctx->current);
24874 NK_ASSERT(ctx->current->layout);
24875 if (!ctx || !ctx->current || !ctx->current->layout)
24876 return 0;
24877
24878 win = ctx->current;
24879 layout = win->layout;
24880 state = nk_widget(&bounds, ctx);
24881 if (!state) return 0;
24882 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24883 return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,
24884 symbol, ctx->button_behavior, style, in, ctx->style.font);
24885}
24886NK_API nk_bool
24887nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)
24888{
24889 NK_ASSERT(ctx);
24890 if (!ctx) return 0;
24891 return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);
24892}
24893NK_API nk_bool
24894nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,
24895 struct nk_image img)
24896{
24897 struct nk_window *win;
24898 struct nk_panel *layout;
24899 const struct nk_input *in;
24900
24901 struct nk_rect bounds;
24902 enum nk_widget_layout_states state;
24903
24904 NK_ASSERT(ctx);
24905 NK_ASSERT(ctx->current);
24906 NK_ASSERT(ctx->current->layout);
24907 if (!ctx || !ctx->current || !ctx->current->layout)
24908 return 0;
24909
24910 win = ctx->current;
24911 layout = win->layout;
24912
24913 state = nk_widget(&bounds, ctx);
24914 if (!state) return 0;
24915 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24916 return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,
24917 img, ctx->button_behavior, style, in);
24918}
24919NK_API nk_bool
24920nk_button_image(struct nk_context *ctx, struct nk_image img)
24921{
24922 NK_ASSERT(ctx);
24923 if (!ctx) return 0;
24924 return nk_button_image_styled(ctx, &ctx->style.button, img);
24925}
24926NK_API nk_bool
24927nk_button_symbol_text_styled(struct nk_context *ctx,
24928 const struct nk_style_button *style, enum nk_symbol_type symbol,
24929 const char *text, int len, nk_flags align)
24930{
24931 struct nk_window *win;
24932 struct nk_panel *layout;
24933 const struct nk_input *in;
24934
24935 struct nk_rect bounds;
24936 enum nk_widget_layout_states state;
24937
24938 NK_ASSERT(ctx);
24939 NK_ASSERT(ctx->current);
24940 NK_ASSERT(ctx->current->layout);
24941 if (!ctx || !ctx->current || !ctx->current->layout)
24942 return 0;
24943
24944 win = ctx->current;
24945 layout = win->layout;
24946
24947 state = nk_widget(&bounds, ctx);
24948 if (!state) return 0;
24949 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24950 return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
24951 symbol, text, len, align, ctx->button_behavior,
24952 style, ctx->style.font, in);
24953}
24954NK_API nk_bool
24955nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
24956 const char* text, int len, nk_flags align)
24957{
24958 NK_ASSERT(ctx);
24959 if (!ctx) return 0;
24960 return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);
24961}
24962NK_API nk_bool nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
24963 const char *label, nk_flags align)
24964{
24965 return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);
24966}
24967NK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx,
24968 const struct nk_style_button *style, enum nk_symbol_type symbol,
24969 const char *title, nk_flags align)
24970{
24971 return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);
24972}
24973NK_API nk_bool
24974nk_button_image_text_styled(struct nk_context *ctx,
24975 const struct nk_style_button *style, struct nk_image img, const char *text,
24976 int len, nk_flags align)
24977{
24978 struct nk_window *win;
24979 struct nk_panel *layout;
24980 const struct nk_input *in;
24981
24982 struct nk_rect bounds;
24983 enum nk_widget_layout_states state;
24984
24985 NK_ASSERT(ctx);
24986 NK_ASSERT(ctx->current);
24987 NK_ASSERT(ctx->current->layout);
24988 if (!ctx || !ctx->current || !ctx->current->layout)
24989 return 0;
24990
24991 win = ctx->current;
24992 layout = win->layout;
24993
24994 state = nk_widget(&bounds, ctx);
24995 if (!state) return 0;
24996 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
24997 return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,
24998 bounds, img, text, len, align, ctx->button_behavior,
24999 style, ctx->style.font, in);
25000}
25001NK_API nk_bool
25002nk_button_image_text(struct nk_context *ctx, struct nk_image img,
25003 const char *text, int len, nk_flags align)
25004{
25005 return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);
25006}
25007NK_API nk_bool nk_button_image_label(struct nk_context *ctx, struct nk_image img,
25008 const char *label, nk_flags align)
25009{
25010 return nk_button_image_text(ctx, img, label, nk_strlen(label), align);
25011}
25012NK_API nk_bool nk_button_image_label_styled(struct nk_context *ctx,
25013 const struct nk_style_button *style, struct nk_image img,
25014 const char *label, nk_flags text_alignment)
25015{
25016 return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);
25017}
25018
25019
25020
25021
25022
25023/* ===============================================================
25024 *
25025 * TOGGLE
25026 *
25027 * ===============================================================*/
25028NK_LIB nk_bool
25029nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
25030 nk_flags *state, nk_bool active)
25031{
25032 nk_widget_state_reset(state);
25033 if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {
25034 *state = NK_WIDGET_STATE_ACTIVE;
25035 active = !active;
25036 }
25037 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))
25038 *state |= NK_WIDGET_STATE_ENTERED;
25039 else if (nk_input_is_mouse_prev_hovering_rect(in, select))
25040 *state |= NK_WIDGET_STATE_LEFT;
25041 return active;
25042}
25043NK_LIB void
25044nk_draw_checkbox(struct nk_command_buffer *out,
25045 nk_flags state, const struct nk_style_toggle *style, nk_bool active,
25046 const struct nk_rect *label, const struct nk_rect *selector,
25047 const struct nk_rect *cursors, const char *string, int len,
25048 const struct nk_user_font *font, nk_flags text_alignment)
25049{
25050 const struct nk_style_item *background;
25051 const struct nk_style_item *cursor;
25052 struct nk_text text;
25053
25054 /* select correct colors/images */
25055 if (state & NK_WIDGET_STATE_HOVER) {
25056 background = &style->hover;
25057 cursor = &style->cursor_hover;
25058 text.text = style->text_hover;
25059 } else if (state & NK_WIDGET_STATE_ACTIVED) {
25060 background = &style->hover;
25061 cursor = &style->cursor_hover;
25062 text.text = style->text_active;
25063 } else {
25064 background = &style->normal;
25065 cursor = &style->cursor_normal;
25066 text.text = style->text_normal;
25067 }
25068
25069 text.text = nk_rgb_factor(text.text, style->color_factor);
25070 text.padding.x = 0;
25071 text.padding.y = 0;
25072 text.background = style->text_background;
25073 nk_widget_text(out, *label, string, len, &text, text_alignment, font);
25074
25075 /* draw background and cursor */
25076 if (background->type == NK_STYLE_ITEM_COLOR) {
25077 nk_fill_rect(out, *selector, 0, nk_rgb_factor(style->border_color, style->color_factor));
25078 nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, nk_rgb_factor(background->data.color, style->color_factor));
25079 } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
25080 if (active) {
25081 if (cursor->type == NK_STYLE_ITEM_IMAGE)
25082 nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));
25083 else nk_fill_rect(out, *cursors, 0, cursor->data.color);
25084 }
25085}
25086NK_LIB void
25087nk_draw_option(struct nk_command_buffer *out,
25088 nk_flags state, const struct nk_style_toggle *style, nk_bool active,
25089 const struct nk_rect *label, const struct nk_rect *selector,
25090 const struct nk_rect *cursors, const char *string, int len,
25091 const struct nk_user_font *font, nk_flags text_alignment)
25092{
25093 const struct nk_style_item *background;
25094 const struct nk_style_item *cursor;
25095 struct nk_text text;
25096
25097 /* select correct colors/images */
25098 if (state & NK_WIDGET_STATE_HOVER) {
25099 background = &style->hover;
25100 cursor = &style->cursor_hover;
25101 text.text = style->text_hover;
25102 } else if (state & NK_WIDGET_STATE_ACTIVED) {
25103 background = &style->hover;
25104 cursor = &style->cursor_hover;
25105 text.text = style->text_active;
25106 } else {
25107 background = &style->normal;
25108 cursor = &style->cursor_normal;
25109 text.text = style->text_normal;
25110 }
25111
25112 text.text = nk_rgb_factor(text.text, style->color_factor);
25113 text.padding.x = 0;
25114 text.padding.y = 0;
25115 text.background = style->text_background;
25116 nk_widget_text(out, *label, string, len, &text, text_alignment, font);
25117
25118 /* draw background and cursor */
25119 if (background->type == NK_STYLE_ITEM_COLOR) {
25120 nk_fill_circle(out, *selector, nk_rgb_factor(style->border_color, style->color_factor));
25121 nk_fill_circle(out, nk_shrink_rect(*selector, style->border), nk_rgb_factor(background->data.color, style->color_factor));
25122 } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
25123 if (active) {
25124 if (cursor->type == NK_STYLE_ITEM_IMAGE)
25125 nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));
25126 else nk_fill_circle(out, *cursors, cursor->data.color);
25127 }
25128}
25129NK_LIB nk_bool
25130nk_do_toggle(nk_flags *state,
25131 struct nk_command_buffer *out, struct nk_rect r,
25132 nk_bool *active, const char *str, int len, enum nk_toggle_type type,
25133 const struct nk_style_toggle *style, const struct nk_input *in,
25134 const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment)
25135{
25136 int was_active;
25137 struct nk_rect bounds;
25138 struct nk_rect select;
25139 struct nk_rect cursor;
25140 struct nk_rect label;
25141
25142 NK_ASSERT(style);
25143 NK_ASSERT(out);
25144 NK_ASSERT(font);
25145 if (!out || !style || !font || !active)
25146 return 0;
25147
25148 r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);
25149 r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);
25150
25151 /* add additional touch padding for touch screen devices */
25152 bounds.x = r.x - style->touch_padding.x;
25153 bounds.y = r.y - style->touch_padding.y;
25154 bounds.w = r.w + 2 * style->touch_padding.x;
25155 bounds.h = r.h + 2 * style->touch_padding.y;
25156
25157 /* calculate the selector space */
25158 select.w = font->height;
25159 select.h = select.w;
25160
25161 if (widget_alignment & NK_WIDGET_ALIGN_RIGHT) {
25162 select.x = r.x + r.w - font->height;
25163
25164 /* label in front of the selector */
25165 label.x = r.x;
25166 label.w = r.w - select.w - style->spacing * 2;
25167 } else if (widget_alignment & NK_WIDGET_ALIGN_CENTERED) {
25168 select.x = r.x + (r.w - select.w) / 2;
25169
25170 /* label in front of selector */
25171 label.x = r.x;
25172 label.w = (r.w - select.w - style->spacing * 2) / 2;
25173 } else { /* Default: NK_WIDGET_ALIGN_LEFT */
25174 select.x = r.x;
25175
25176 /* label behind the selector */
25177 label.x = select.x + select.w + style->spacing;
25178 label.w = NK_MAX(r.x + r.w, label.x) - label.x;
25179 }
25180
25181 if (widget_alignment & NK_WIDGET_ALIGN_TOP) {
25182 select.y = r.y;
25183 } else if (widget_alignment & NK_WIDGET_ALIGN_BOTTOM) {
25184 select.y = r.y + r.h - select.h - 2 * style->padding.y;
25185 } else { /* Default: NK_WIDGET_ALIGN_MIDDLE */
25186 select.y = r.y + r.h/2.0f - select.h/2.0f;
25187 }
25188
25189 label.y = select.y;
25190 label.h = select.w;
25191
25192 /* calculate the bounds of the cursor inside the selector */
25193 cursor.x = select.x + style->padding.x + style->border;
25194 cursor.y = select.y + style->padding.y + style->border;
25195 cursor.w = select.w - (2 * style->padding.x + 2 * style->border);
25196 cursor.h = select.h - (2 * style->padding.y + 2 * style->border);
25197
25198 /* update selector */
25199 was_active = *active;
25200 *active = nk_toggle_behavior(in, bounds, state, *active);
25201
25202 /* draw selector */
25203 if (style->draw_begin)
25204 style->draw_begin(out, style->userdata);
25205 if (type == NK_TOGGLE_CHECK) {
25206 nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);
25207 } else {
25208 nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);
25209 }
25210 if (style->draw_end)
25211 style->draw_end(out, style->userdata);
25212 return (was_active != *active);
25213}
25214/*----------------------------------------------------------------
25215 *
25216 * CHECKBOX
25217 *
25218 * --------------------------------------------------------------*/
25219NK_API nk_bool
25220nk_check_text(struct nk_context *ctx, const char *text, int len, nk_bool active)
25221{
25222 struct nk_window *win;
25223 struct nk_panel *layout;
25224 const struct nk_input *in;
25225 const struct nk_style *style;
25226
25227 struct nk_rect bounds;
25228 enum nk_widget_layout_states state;
25229
25230 NK_ASSERT(ctx);
25231 NK_ASSERT(ctx->current);
25232 NK_ASSERT(ctx->current->layout);
25233 if (!ctx || !ctx->current || !ctx->current->layout)
25234 return active;
25235
25236 win = ctx->current;
25237 style = &ctx->style;
25238 layout = win->layout;
25239
25240 state = nk_widget(&bounds, ctx);
25241 if (!state) return active;
25242 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25243 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
25244 text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);
25245 return active;
25246}
25247NK_API nk_bool
25248nk_check_text_align(struct nk_context *ctx, const char *text, int len, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)
25249{
25250 struct nk_window *win;
25251 struct nk_panel *layout;
25252 const struct nk_input *in;
25253 const struct nk_style *style;
25254
25255 struct nk_rect bounds;
25256 enum nk_widget_layout_states state;
25257
25258 NK_ASSERT(ctx);
25259 NK_ASSERT(ctx->current);
25260 NK_ASSERT(ctx->current->layout);
25261 if (!ctx || !ctx->current || !ctx->current->layout)
25262 return active;
25263
25264 win = ctx->current;
25265 style = &ctx->style;
25266 layout = win->layout;
25267
25268 state = nk_widget(&bounds, ctx);
25269 if (!state) return active;
25270 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25271 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
25272 text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, widget_alignment, text_alignment);
25273 return active;
25274}
25275NK_API unsigned int
25276nk_check_flags_text(struct nk_context *ctx, const char *text, int len,
25277 unsigned int flags, unsigned int value)
25278{
25279 int old_active;
25280 NK_ASSERT(ctx);
25281 NK_ASSERT(text);
25282 if (!ctx || !text) return flags;
25283 old_active = (int)((flags & value) & value);
25284 if (nk_check_text(ctx, text, len, old_active))
25285 flags |= value;
25286 else flags &= ~value;
25287 return flags;
25288}
25289NK_API nk_bool
25290nk_checkbox_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)
25291{
25292 int old_val;
25293 NK_ASSERT(ctx);
25294 NK_ASSERT(text);
25295 NK_ASSERT(active);
25296 if (!ctx || !text || !active) return 0;
25297 old_val = *active;
25298 *active = nk_check_text(ctx, text, len, *active);
25299 return old_val != *active;
25300}
25301NK_API nk_bool
25302nk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)
25303{
25304 int old_val;
25305 NK_ASSERT(ctx);
25306 NK_ASSERT(text);
25307 NK_ASSERT(active);
25308 if (!ctx || !text || !active) return 0;
25309 old_val = *active;
25310 *active = nk_check_text_align(ctx, text, len, *active, widget_alignment, text_alignment);
25311 return old_val != *active;
25312}
25313NK_API nk_bool
25314nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
25315 unsigned int *flags, unsigned int value)
25316{
25317 nk_bool active;
25318 NK_ASSERT(ctx);
25319 NK_ASSERT(text);
25320 NK_ASSERT(flags);
25321 if (!ctx || !text || !flags) return 0;
25322
25323 active = (int)((*flags & value) & value);
25324 if (nk_checkbox_text(ctx, text, len, &active)) {
25325 if (active) *flags |= value;
25326 else *flags &= ~value;
25327 return 1;
25328 }
25329 return 0;
25330}
25331NK_API nk_bool nk_check_label(struct nk_context *ctx, const char *label, nk_bool active)
25332{
25333 return nk_check_text(ctx, label, nk_strlen(label), active);
25334}
25335NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,
25336 unsigned int flags, unsigned int value)
25337{
25338 return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);
25339}
25340NK_API nk_bool nk_checkbox_label(struct nk_context *ctx, const char *label, nk_bool *active)
25341{
25342 return nk_checkbox_text(ctx, label, nk_strlen(label), active);
25343}
25344NK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)
25345{
25346 return nk_checkbox_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);
25347}
25348NK_API nk_bool nk_checkbox_flags_label(struct nk_context *ctx, const char *label,
25349 unsigned int *flags, unsigned int value)
25350{
25351 return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);
25352}
25353/*----------------------------------------------------------------
25354 *
25355 * OPTION
25356 *
25357 * --------------------------------------------------------------*/
25358NK_API nk_bool
25359nk_option_text(struct nk_context *ctx, const char *text, int len, nk_bool is_active)
25360{
25361 struct nk_window *win;
25362 struct nk_panel *layout;
25363 const struct nk_input *in;
25364 const struct nk_style *style;
25365
25366 struct nk_rect bounds;
25367 enum nk_widget_layout_states state;
25368
25369 NK_ASSERT(ctx);
25370 NK_ASSERT(ctx->current);
25371 NK_ASSERT(ctx->current->layout);
25372 if (!ctx || !ctx->current || !ctx->current->layout)
25373 return is_active;
25374
25375 win = ctx->current;
25376 style = &ctx->style;
25377 layout = win->layout;
25378
25379 state = nk_widget(&bounds, ctx);
25380 if (!state) return (int)state;
25381 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25382 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
25383 text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);
25384 return is_active;
25385}
25386NK_API nk_bool
25387nk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment)
25388{
25389 struct nk_window *win;
25390 struct nk_panel *layout;
25391 const struct nk_input *in;
25392 const struct nk_style *style;
25393
25394 struct nk_rect bounds;
25395 enum nk_widget_layout_states state;
25396
25397 NK_ASSERT(ctx);
25398 NK_ASSERT(ctx->current);
25399 NK_ASSERT(ctx->current->layout);
25400 if (!ctx || !ctx->current || !ctx->current->layout)
25401 return is_active;
25402
25403 win = ctx->current;
25404 style = &ctx->style;
25405 layout = win->layout;
25406
25407 state = nk_widget(&bounds, ctx);
25408 if (!state) return (int)state;
25409 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25410 nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
25411 text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, widget_alignment, text_alignment);
25412 return is_active;
25413}
25414NK_API nk_bool
25415nk_radio_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)
25416{
25417 int old_value;
25418 NK_ASSERT(ctx);
25419 NK_ASSERT(text);
25420 NK_ASSERT(active);
25421 if (!ctx || !text || !active) return 0;
25422 old_value = *active;
25423 *active = nk_option_text(ctx, text, len, old_value);
25424 return old_value != *active;
25425}
25426NK_API nk_bool
25427nk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)
25428{
25429 int old_value;
25430 NK_ASSERT(ctx);
25431 NK_ASSERT(text);
25432 NK_ASSERT(active);
25433 if (!ctx || !text || !active) return 0;
25434 old_value = *active;
25435 *active = nk_option_text_align(ctx, text, len, old_value, widget_alignment, text_alignment);
25436 return old_value != *active;
25437}
25438NK_API nk_bool
25439nk_option_label(struct nk_context *ctx, const char *label, nk_bool active)
25440{
25441 return nk_option_text(ctx, label, nk_strlen(label), active);
25442}
25443NK_API nk_bool
25444nk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)
25445{
25446 return nk_option_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);
25447}
25448NK_API nk_bool
25449nk_radio_label(struct nk_context *ctx, const char *label, nk_bool *active)
25450{
25451 return nk_radio_text(ctx, label, nk_strlen(label), active);
25452}
25453NK_API nk_bool
25454nk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)
25455{
25456 return nk_radio_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);
25457}
25458
25459
25460
25461
25462
25463/* ===============================================================
25464 *
25465 * SELECTABLE
25466 *
25467 * ===============================================================*/
25468NK_LIB void
25469nk_draw_selectable(struct nk_command_buffer *out,
25470 nk_flags state, const struct nk_style_selectable *style, nk_bool active,
25471 const struct nk_rect *bounds,
25472 const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym,
25473 const char *string, int len, nk_flags align, const struct nk_user_font *font)
25474{
25475 const struct nk_style_item *background;
25476 struct nk_text text;
25477 text.padding = style->padding;
25478
25479 /* select correct colors/images */
25480 if (!active) {
25481 if (state & NK_WIDGET_STATE_ACTIVED) {
25482 background = &style->pressed;
25483 text.text = style->text_pressed;
25484 } else if (state & NK_WIDGET_STATE_HOVER) {
25485 background = &style->hover;
25486 text.text = style->text_hover;
25487 } else {
25488 background = &style->normal;
25489 text.text = style->text_normal;
25490 }
25491 } else {
25492 if (state & NK_WIDGET_STATE_ACTIVED) {
25493 background = &style->pressed_active;
25494 text.text = style->text_pressed_active;
25495 } else if (state & NK_WIDGET_STATE_HOVER) {
25496 background = &style->hover_active;
25497 text.text = style->text_hover_active;
25498 } else {
25499 background = &style->normal_active;
25500 text.text = style->text_normal_active;
25501 }
25502 }
25503
25504 text.text = nk_rgb_factor(text.text, style->color_factor);
25505
25506 /* draw selectable background and text */
25507 switch (background->type) {
25508 case NK_STYLE_ITEM_IMAGE:
25509 text.background = nk_rgba(0, 0, 0, 0);
25510 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
25511 break;
25512 case NK_STYLE_ITEM_NINE_SLICE:
25513 text.background = nk_rgba(0, 0, 0, 0);
25514 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
25515 break;
25516 case NK_STYLE_ITEM_COLOR:
25517 text.background = background->data.color;
25518 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
25519 break;
25520 }
25521 if (icon) {
25522 if (img) nk_draw_image(out, *icon, img, nk_rgb_factor(nk_white, style->color_factor));
25523 else nk_draw_symbol(out, sym, *icon, text.background, text.text, 1, font);
25524 }
25525 nk_widget_text(out, *bounds, string, len, &text, align, font);
25526}
25527NK_LIB nk_bool
25528nk_do_selectable(nk_flags *state, struct nk_command_buffer *out,
25529 struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,
25530 const struct nk_style_selectable *style, const struct nk_input *in,
25531 const struct nk_user_font *font)
25532{
25533 int old_value;
25534 struct nk_rect touch;
25535
25536 NK_ASSERT(state);
25537 NK_ASSERT(out);
25538 NK_ASSERT(str);
25539 NK_ASSERT(len);
25540 NK_ASSERT(value);
25541 NK_ASSERT(style);
25542 NK_ASSERT(font);
25543
25544 if (!state || !out || !str || !len || !value || !style || !font) return 0;
25545 old_value = *value;
25546
25547 /* remove padding */
25548 touch.x = bounds.x - style->touch_padding.x;
25549 touch.y = bounds.y - style->touch_padding.y;
25550 touch.w = bounds.w + style->touch_padding.x * 2;
25551 touch.h = bounds.h + style->touch_padding.y * 2;
25552
25553 /* update button */
25554 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
25555 *value = !(*value);
25556
25557 /* draw selectable */
25558 if (style->draw_begin) style->draw_begin(out, style->userdata);
25559 nk_draw_selectable(out, *state, style, *value, &bounds, 0,0,NK_SYMBOL_NONE, str, len, align, font);
25560 if (style->draw_end) style->draw_end(out, style->userdata);
25561 return old_value != *value;
25562}
25563NK_LIB nk_bool
25564nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,
25565 struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,
25566 const struct nk_image *img, const struct nk_style_selectable *style,
25567 const struct nk_input *in, const struct nk_user_font *font)
25568{
25569 nk_bool old_value;
25570 struct nk_rect touch;
25571 struct nk_rect icon;
25572
25573 NK_ASSERT(state);
25574 NK_ASSERT(out);
25575 NK_ASSERT(str);
25576 NK_ASSERT(len);
25577 NK_ASSERT(value);
25578 NK_ASSERT(style);
25579 NK_ASSERT(font);
25580
25581 if (!state || !out || !str || !len || !value || !style || !font) return 0;
25582 old_value = *value;
25583
25584 /* toggle behavior */
25585 touch.x = bounds.x - style->touch_padding.x;
25586 touch.y = bounds.y - style->touch_padding.y;
25587 touch.w = bounds.w + style->touch_padding.x * 2;
25588 touch.h = bounds.h + style->touch_padding.y * 2;
25589 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
25590 *value = !(*value);
25591
25592 icon.y = bounds.y + style->padding.y;
25593 icon.w = icon.h = bounds.h - 2 * style->padding.y;
25594 if (align & NK_TEXT_ALIGN_LEFT) {
25595 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
25596 icon.x = NK_MAX(icon.x, 0);
25597 } else icon.x = bounds.x + 2 * style->padding.x;
25598
25599 icon.x += style->image_padding.x;
25600 icon.y += style->image_padding.y;
25601 icon.w -= 2 * style->image_padding.x;
25602 icon.h -= 2 * style->image_padding.y;
25603
25604 /* draw selectable */
25605 if (style->draw_begin) style->draw_begin(out, style->userdata);
25606 nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, NK_SYMBOL_NONE, str, len, align, font);
25607 if (style->draw_end) style->draw_end(out, style->userdata);
25608 return old_value != *value;
25609}
25610NK_LIB nk_bool
25611nk_do_selectable_symbol(nk_flags *state, struct nk_command_buffer *out,
25612 struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,
25613 enum nk_symbol_type sym, const struct nk_style_selectable *style,
25614 const struct nk_input *in, const struct nk_user_font *font)
25615{
25616 int old_value;
25617 struct nk_rect touch;
25618 struct nk_rect icon;
25619
25620 NK_ASSERT(state);
25621 NK_ASSERT(out);
25622 NK_ASSERT(str);
25623 NK_ASSERT(len);
25624 NK_ASSERT(value);
25625 NK_ASSERT(style);
25626 NK_ASSERT(font);
25627
25628 if (!state || !out || !str || !len || !value || !style || !font) return 0;
25629 old_value = *value;
25630
25631 /* toggle behavior */
25632 touch.x = bounds.x - style->touch_padding.x;
25633 touch.y = bounds.y - style->touch_padding.y;
25634 touch.w = bounds.w + style->touch_padding.x * 2;
25635 touch.h = bounds.h + style->touch_padding.y * 2;
25636 if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))
25637 *value = !(*value);
25638
25639 icon.y = bounds.y + style->padding.y;
25640 icon.w = icon.h = bounds.h - 2 * style->padding.y;
25641 if (align & NK_TEXT_ALIGN_LEFT) {
25642 icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);
25643 icon.x = NK_MAX(icon.x, 0);
25644 } else icon.x = bounds.x + 2 * style->padding.x;
25645
25646 icon.x += style->image_padding.x;
25647 icon.y += style->image_padding.y;
25648 icon.w -= 2 * style->image_padding.x;
25649 icon.h -= 2 * style->image_padding.y;
25650
25651 /* draw selectable */
25652 if (style->draw_begin) style->draw_begin(out, style->userdata);
25653 nk_draw_selectable(out, *state, style, *value, &bounds, &icon, 0, sym, str, len, align, font);
25654 if (style->draw_end) style->draw_end(out, style->userdata);
25655 return old_value != *value;
25656}
25657
25658NK_API nk_bool
25659nk_selectable_text(struct nk_context *ctx, const char *str, int len,
25660 nk_flags align, nk_bool *value)
25661{
25662 struct nk_window *win;
25663 struct nk_panel *layout;
25664 const struct nk_input *in;
25665 const struct nk_style *style;
25666
25667 enum nk_widget_layout_states state;
25668 struct nk_rect bounds;
25669
25670 NK_ASSERT(ctx);
25671 NK_ASSERT(value);
25672 NK_ASSERT(ctx->current);
25673 NK_ASSERT(ctx->current->layout);
25674 if (!ctx || !ctx->current || !ctx->current->layout || !value)
25675 return 0;
25676
25677 win = ctx->current;
25678 layout = win->layout;
25679 style = &ctx->style;
25680
25681 state = nk_widget(&bounds, ctx);
25682 if (!state) return 0;
25683 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25684 return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,
25685 str, len, align, value, &style->selectable, in, style->font);
25686}
25687NK_API nk_bool
25688nk_selectable_image_text(struct nk_context *ctx, struct nk_image img,
25689 const char *str, int len, nk_flags align, nk_bool *value)
25690{
25691 struct nk_window *win;
25692 struct nk_panel *layout;
25693 const struct nk_input *in;
25694 const struct nk_style *style;
25695
25696 enum nk_widget_layout_states state;
25697 struct nk_rect bounds;
25698
25699 NK_ASSERT(ctx);
25700 NK_ASSERT(value);
25701 NK_ASSERT(ctx->current);
25702 NK_ASSERT(ctx->current->layout);
25703 if (!ctx || !ctx->current || !ctx->current->layout || !value)
25704 return 0;
25705
25706 win = ctx->current;
25707 layout = win->layout;
25708 style = &ctx->style;
25709
25710 state = nk_widget(&bounds, ctx);
25711 if (!state) return 0;
25712 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25713 return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,
25714 str, len, align, value, &img, &style->selectable, in, style->font);
25715}
25716NK_API nk_bool
25717nk_selectable_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
25718 const char *str, int len, nk_flags align, nk_bool *value)
25719{
25720 struct nk_window *win;
25721 struct nk_panel *layout;
25722 const struct nk_input *in;
25723 const struct nk_style *style;
25724
25725 enum nk_widget_layout_states state;
25726 struct nk_rect bounds;
25727
25728 NK_ASSERT(ctx);
25729 NK_ASSERT(value);
25730 NK_ASSERT(ctx->current);
25731 NK_ASSERT(ctx->current->layout);
25732 if (!ctx || !ctx->current || !ctx->current->layout || !value)
25733 return 0;
25734
25735 win = ctx->current;
25736 layout = win->layout;
25737 style = &ctx->style;
25738
25739 state = nk_widget(&bounds, ctx);
25740 if (!state) return 0;
25741 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
25742 return nk_do_selectable_symbol(&ctx->last_widget_state, &win->buffer, bounds,
25743 str, len, align, value, sym, &style->selectable, in, style->font);
25744}
25745NK_API nk_bool
25746nk_selectable_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
25747 const char *title, nk_flags align, nk_bool *value)
25748{
25749 return nk_selectable_symbol_text(ctx, sym, title, nk_strlen(title), align, value);
25750}
25751NK_API nk_bool nk_select_text(struct nk_context *ctx, const char *str, int len,
25752 nk_flags align, nk_bool value)
25753{
25754 nk_selectable_text(ctx, str, len, align, &value);return value;
25755}
25756NK_API nk_bool nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool *value)
25757{
25758 return nk_selectable_text(ctx, str, nk_strlen(str), align, value);
25759}
25760NK_API nk_bool nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,
25761 const char *str, nk_flags align, nk_bool *value)
25762{
25763 return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);
25764}
25765NK_API nk_bool nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool value)
25766{
25767 nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;
25768}
25769NK_API nk_bool nk_select_image_label(struct nk_context *ctx, struct nk_image img,
25770 const char *str, nk_flags align, nk_bool value)
25771{
25772 nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;
25773}
25774NK_API nk_bool nk_select_image_text(struct nk_context *ctx, struct nk_image img,
25775 const char *str, int len, nk_flags align, nk_bool value)
25776{
25777 nk_selectable_image_text(ctx, img, str, len, align, &value);return value;
25778}
25779NK_API nk_bool
25780nk_select_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
25781 const char *title, int title_len, nk_flags align, nk_bool value)
25782{
25783 nk_selectable_symbol_text(ctx, sym, title, title_len, align, &value);return value;
25784}
25785NK_API nk_bool
25786nk_select_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
25787 const char *title, nk_flags align, nk_bool value)
25788{
25789 return nk_select_symbol_text(ctx, sym, title, nk_strlen(title), align, value);
25790}
25791
25792
25793
25794
25795
25796/* ===============================================================
25797 *
25798 * SLIDER
25799 *
25800 * ===============================================================*/
25801NK_LIB float
25802nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,
25803 struct nk_rect *visual_cursor, struct nk_input *in,
25804 struct nk_rect bounds, float slider_min, float slider_max, float slider_value,
25805 float slider_step, float slider_steps)
25806{
25807 int left_mouse_down;
25808 int left_mouse_click_in_cursor;
25809
25810 /* check if visual cursor is being dragged */
25811 nk_widget_state_reset(state);
25812 left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
25813 left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
25814 NK_BUTTON_LEFT, *visual_cursor, nk_true);
25815
25816 if (left_mouse_down && left_mouse_click_in_cursor) {
25817 float ratio = 0;
25818 const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);
25819 const float pxstep = bounds.w / slider_steps;
25820
25821 /* only update value if the next slider step is reached */
25822 *state = NK_WIDGET_STATE_ACTIVE;
25823 if (NK_ABS(d) >= pxstep) {
25824 const float steps = (float)((int)(NK_ABS(d) / pxstep));
25825 slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);
25826 slider_value = NK_CLAMP(slider_min, slider_value, slider_max);
25827 ratio = (slider_value - slider_min)/slider_step;
25828 logical_cursor->x = bounds.x + (logical_cursor->w * ratio);
25829 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;
25830 }
25831 }
25832
25833 /* slider widget state */
25834 if (nk_input_is_mouse_hovering_rect(in, bounds))
25835 *state = NK_WIDGET_STATE_HOVERED;
25836 if (*state & NK_WIDGET_STATE_HOVER &&
25837 !nk_input_is_mouse_prev_hovering_rect(in, bounds))
25838 *state |= NK_WIDGET_STATE_ENTERED;
25839 else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
25840 *state |= NK_WIDGET_STATE_LEFT;
25841 return slider_value;
25842}
25843NK_LIB void
25844nk_draw_slider(struct nk_command_buffer *out, nk_flags state,
25845 const struct nk_style_slider *style, const struct nk_rect *bounds,
25846 const struct nk_rect *visual_cursor, float min, float value, float max)
25847{
25848 struct nk_rect fill;
25849 struct nk_rect bar;
25850 const struct nk_style_item *background;
25851
25852 /* select correct slider images/colors */
25853 struct nk_color bar_color;
25854 const struct nk_style_item *cursor;
25855
25856 NK_UNUSED(min);
25857 NK_UNUSED(max);
25858 NK_UNUSED(value);
25859
25860 if (state & NK_WIDGET_STATE_ACTIVED) {
25861 background = &style->active;
25862 bar_color = style->bar_active;
25863 cursor = &style->cursor_active;
25864 } else if (state & NK_WIDGET_STATE_HOVER) {
25865 background = &style->hover;
25866 bar_color = style->bar_hover;
25867 cursor = &style->cursor_hover;
25868 } else {
25869 background = &style->normal;
25870 bar_color = style->bar_normal;
25871 cursor = &style->cursor_normal;
25872 }
25873
25874 /* calculate slider background bar */
25875 bar.x = bounds->x;
25876 bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;
25877 bar.w = bounds->w;
25878 bar.h = bounds->h/6;
25879
25880 /* filled background bar style */
25881 fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;
25882 fill.x = bar.x;
25883 fill.y = bar.y;
25884 fill.h = bar.h;
25885
25886 /* draw background */
25887 switch(background->type) {
25888 case NK_STYLE_ITEM_IMAGE:
25889 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
25890 break;
25891 case NK_STYLE_ITEM_NINE_SLICE:
25892 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
25893 break;
25894 case NK_STYLE_ITEM_COLOR:
25895 nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
25896 nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
25897 break;
25898 }
25899
25900 /* draw slider bar */
25901 nk_fill_rect(out, bar, style->rounding, nk_rgb_factor(bar_color, style->color_factor));
25902 nk_fill_rect(out, fill, style->rounding, nk_rgb_factor(style->bar_filled, style->color_factor));
25903
25904 /* draw cursor */
25905 if (cursor->type == NK_STYLE_ITEM_IMAGE)
25906 nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));
25907 else
25908 nk_fill_circle(out, *visual_cursor, nk_rgb_factor(cursor->data.color, style->color_factor));
25909}
25910NK_LIB float
25911nk_do_slider(nk_flags *state,
25912 struct nk_command_buffer *out, struct nk_rect bounds,
25913 float min, float val, float max, float step,
25914 const struct nk_style_slider *style, struct nk_input *in,
25915 const struct nk_user_font *font)
25916{
25917 float slider_range;
25918 float slider_min;
25919 float slider_max;
25920 float slider_value;
25921 float slider_steps;
25922 float cursor_offset;
25923
25924 struct nk_rect visual_cursor;
25925 struct nk_rect logical_cursor;
25926
25927 NK_ASSERT(style);
25928 NK_ASSERT(out);
25929 if (!out || !style)
25930 return 0;
25931
25932 /* remove padding from slider bounds */
25933 bounds.x = bounds.x + style->padding.x;
25934 bounds.y = bounds.y + style->padding.y;
25935 bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
25936 bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);
25937 bounds.w -= 2 * style->padding.x;
25938 bounds.h -= 2 * style->padding.y;
25939
25940 /* optional buttons */
25941 if (style->show_buttons) {
25942 nk_flags ws;
25943 struct nk_rect button;
25944 button.y = bounds.y;
25945 button.w = bounds.h;
25946 button.h = bounds.h;
25947
25948 /* decrement button */
25949 button.x = bounds.x;
25950 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,
25951 &style->dec_button, in, font))
25952 val -= step;
25953
25954 /* increment button */
25955 button.x = (bounds.x + bounds.w) - button.w;
25956 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,
25957 &style->inc_button, in, font))
25958 val += step;
25959
25960 bounds.x = bounds.x + button.w + style->spacing.x;
25961 bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);
25962 }
25963
25964 /* remove one cursor size to support visual cursor */
25965 bounds.x += style->cursor_size.x*0.5f;
25966 bounds.w -= style->cursor_size.x;
25967
25968 /* make sure the provided values are correct */
25969 slider_max = NK_MAX(min, max);
25970 slider_min = NK_MIN(min, max);
25971 slider_value = NK_CLAMP(slider_min, val, slider_max);
25972 slider_range = slider_max - slider_min;
25973 slider_steps = slider_range / step;
25974 cursor_offset = (slider_value - slider_min) / step;
25975
25976 /* calculate cursor
25977 Basically you have two cursors. One for visual representation and interaction
25978 and one for updating the actual cursor value. */
25979 logical_cursor.h = bounds.h;
25980 logical_cursor.w = bounds.w / slider_steps;
25981 logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);
25982 logical_cursor.y = bounds.y;
25983
25984 visual_cursor.h = style->cursor_size.y;
25985 visual_cursor.w = style->cursor_size.x;
25986 visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;
25987 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
25988
25989 slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,
25990 in, bounds, slider_min, slider_max, slider_value, step, slider_steps);
25991 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
25992
25993 /* draw slider */
25994 if (style->draw_begin) style->draw_begin(out, style->userdata);
25995 nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);
25996 if (style->draw_end) style->draw_end(out, style->userdata);
25997 return slider_value;
25998}
25999NK_API nk_bool
26000nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,
26001 float value_step)
26002{
26003 struct nk_window *win;
26004 struct nk_panel *layout;
26005 struct nk_input *in;
26006 const struct nk_style *style;
26007
26008 int ret = 0;
26009 float old_value;
26010 struct nk_rect bounds;
26011 enum nk_widget_layout_states state;
26012
26013 NK_ASSERT(ctx);
26014 NK_ASSERT(ctx->current);
26015 NK_ASSERT(ctx->current->layout);
26016 NK_ASSERT(value);
26017 if (!ctx || !ctx->current || !ctx->current->layout || !value)
26018 return ret;
26019
26020 win = ctx->current;
26021 style = &ctx->style;
26022 layout = win->layout;
26023
26024 state = nk_widget(&bounds, ctx);
26025 if (!state) return ret;
26026 in = (/*state == NK_WIDGET_ROM || */ state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
26027
26028 old_value = *value;
26029 *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,
26030 old_value, max_value, value_step, &style->slider, in, style->font);
26031 return (old_value > *value || old_value < *value);
26032}
26033NK_API float
26034nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)
26035{
26036 nk_slider_float(ctx, min, &val, max, step); return val;
26037}
26038NK_API int
26039nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)
26040{
26041 float value = (float)val;
26042 nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
26043 return (int)value;
26044}
26045NK_API nk_bool
26046nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)
26047{
26048 int ret;
26049 float value = (float)*val;
26050 ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
26051 *val = (int)value;
26052 return ret;
26053}
26054
26055
26056
26057
26058
26059/* ===============================================================
26060 *
26061 * KNOB
26062 *
26063 * ===============================================================*/
26064
26065NK_LIB float
26066nk_knob_behavior(nk_flags *state, struct nk_input *in,
26067 struct nk_rect bounds, float knob_min, float knob_max, float knob_value,
26068 float knob_step, float knob_steps,
26069 enum nk_heading zero_direction, float dead_zone_percent)
26070{
26071 struct nk_vec2 origin;
26072 float angle = 0.0f;
26073 origin.x = bounds.x + (bounds.w / 2);
26074 origin.y = bounds.y + (bounds.h / 2);
26075
26076 nk_widget_state_reset(state);
26077
26078 /* handle click and drag input */
26079 if(in &&
26080 in->mouse.buttons[NK_BUTTON_LEFT].down &&
26081 nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, bounds, nk_true)){
26082 /* calculate angle from origin and rotate */
26083 const float direction_rads[4] = {
26084 NK_PI * 2.5f, /* 90 NK_UP */
26085 NK_PI * 2.0f, /* 0 NK_RIGHT */
26086 NK_PI * 1.5f, /* 270 NK_DOWN */
26087 NK_PI, /* 180 NK_LEFT */
26088 };
26089 *state = NK_WIDGET_STATE_ACTIVE;
26090
26091 angle = NK_ATAN2(in->mouse.pos.y - origin.y, in->mouse.pos.x - origin.x) + direction_rads[zero_direction];
26092 angle -= (angle > NK_PI * 2) ? NK_PI * 3 : NK_PI;
26093
26094 /* account for dead space applied when drawing */
26095 angle *= 1.0f / (1.0f - dead_zone_percent);
26096 angle = NK_CLAMP(-NK_PI, angle, NK_PI);
26097
26098 /* convert -pi -> pi range to 0.0 -> 1.0 */
26099 angle = (angle + NK_PI) / (NK_PI * 2);
26100
26101 /* click to closest step */
26102 knob_value = knob_min + ( (int)(angle * knob_steps + (knob_step / 2)) ) * knob_step;
26103 knob_value = NK_CLAMP(knob_min, knob_value, knob_max);
26104 }
26105
26106 /* knob widget state */
26107 if (nk_input_is_mouse_hovering_rect(in, bounds)){
26108 *state = NK_WIDGET_STATE_HOVERED;
26109 /* handle scroll and arrow inputs */
26110 if (in->mouse.scroll_delta.y > 0 ||
26111 (in->keyboard.keys[NK_KEY_UP].down && in->keyboard.keys[NK_KEY_UP].clicked)) {
26112 knob_value += knob_step;
26113 }
26114
26115 if (in->mouse.scroll_delta.y < 0 ||
26116 (in->keyboard.keys[NK_KEY_DOWN].down && in->keyboard.keys[NK_KEY_DOWN].clicked)) {
26117 knob_value -= knob_step;
26118 }
26119 /* easiest way to disable scrolling of parent panels..knob eats scrolling */
26120 in->mouse.scroll_delta.y = 0;
26121 knob_value = NK_CLAMP(knob_min, knob_value, knob_max);
26122 }
26123 if (*state & NK_WIDGET_STATE_HOVER &&
26124 !nk_input_is_mouse_prev_hovering_rect(in, bounds))
26125 *state |= NK_WIDGET_STATE_ENTERED;
26126 else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
26127 *state |= NK_WIDGET_STATE_LEFT;
26128
26129 return knob_value;
26130}
26131NK_LIB void
26132nk_draw_knob(struct nk_command_buffer *out, nk_flags state,
26133 const struct nk_style_knob *style, const struct nk_rect *bounds, float min, float value, float max,
26134 enum nk_heading zero_direction, float dead_zone_percent)
26135{
26136 const struct nk_style_item *background;
26137 struct nk_color knob_color, cursor;
26138
26139 NK_UNUSED(min);
26140 NK_UNUSED(max);
26141 NK_UNUSED(value);
26142
26143 if (state & NK_WIDGET_STATE_ACTIVED) {
26144 background = &style->active;
26145 knob_color = style->knob_active;
26146 cursor = style->cursor_active;
26147 } else if (state & NK_WIDGET_STATE_HOVER) {
26148 background = &style->hover;
26149 knob_color = style->knob_hover;
26150 cursor = style->cursor_hover;
26151 } else {
26152 background = &style->normal;
26153 knob_color = style->knob_normal;
26154 cursor = style->cursor_normal;
26155 }
26156
26157 /* draw background */
26158 switch(background->type) {
26159 case NK_STYLE_ITEM_IMAGE:
26160 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
26161 break;
26162 case NK_STYLE_ITEM_NINE_SLICE:
26163 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
26164 break;
26165 case NK_STYLE_ITEM_COLOR:
26166 nk_fill_rect(out, *bounds, 0, nk_rgb_factor(background->data.color, style->color_factor));
26167 nk_stroke_rect(out, *bounds, 0, style->border, nk_rgb_factor(style->border_color, style->color_factor));
26168 break;
26169 }
26170
26171 /* draw knob */
26172 nk_fill_circle(out, *bounds, nk_rgb_factor(knob_color, style->color_factor));
26173 if(style->knob_border > 0){
26174 struct nk_rect border_bounds = *bounds;
26175 border_bounds.x += style->knob_border / 2;
26176 border_bounds.y += style->knob_border / 2;
26177 border_bounds.w -= style->knob_border;
26178 border_bounds.h -= style->knob_border;
26179 nk_stroke_circle(out, border_bounds, style->knob_border, nk_rgb_factor(style->knob_border_color, style->color_factor));
26180 }
26181 { /* calculate cursor line cords */
26182 float half_circle_size = (bounds->w / 2);
26183 float angle = (value - min) / (max - min);
26184 float alive_zone = 1.0f - dead_zone_percent;
26185 struct nk_vec2 cursor_start, cursor_end;
26186 const float direction_rads[4] = {
26187 NK_PI * 1.5f, /* 90 NK_UP */
26188 0.0f, /* 0 NK_RIGHT */
26189 NK_PI * 0.5f, /* 270 NK_DOWN */
26190 NK_PI, /* 180 NK_LEFT */
26191 };
26192 /* calculate + apply dead zone */
26193 angle = (angle * alive_zone) + (dead_zone_percent / 2);
26194
26195 /* percentage 0.0 -> 1.0 to radians, rads are 0.0 to (2*pi) NOT -pi to pi */
26196 angle *= NK_PI * 2;
26197
26198 /* apply zero angle */
26199 angle += direction_rads[zero_direction];
26200 if(angle > NK_PI * 2)
26201 angle -= NK_PI * 2;
26202
26203 cursor_start.x = bounds->x + half_circle_size + (angle > NK_PI);
26204 cursor_start.y = bounds->y + half_circle_size + (angle < NK_PI_HALF || angle > (NK_PI * 1.5f));
26205
26206 cursor_end.x = cursor_start.x + (half_circle_size * NK_COS(angle));
26207 cursor_end.y = cursor_start.y + (half_circle_size * NK_SIN(angle));
26208
26209 /* cut off half of the cursor */
26210 cursor_start.x = (cursor_start.x + cursor_end.x) / 2;
26211 cursor_start.y = (cursor_start.y + cursor_end.y) / 2;
26212
26213 /* draw cursor */
26214 nk_stroke_line(out, cursor_start.x, cursor_start.y, cursor_end.x, cursor_end.y, 2, nk_rgb_factor(cursor, style->color_factor));
26215 }
26216}
26217NK_LIB float
26218nk_do_knob(nk_flags *state,
26219 struct nk_command_buffer *out, struct nk_rect bounds,
26220 float min, float val, float max, float step,
26221 enum nk_heading zero_direction, float dead_zone_percent,
26222 const struct nk_style_knob *style, struct nk_input *in)
26223{
26224 float knob_range;
26225 float knob_min;
26226 float knob_max;
26227 float knob_value;
26228 float knob_steps;
26229
26230 NK_ASSERT(style);
26231 NK_ASSERT(out);
26232 if (!out || !style)
26233 return 0;
26234
26235 /* remove padding from knob bounds */
26236 bounds.y = bounds.y + style->padding.y;
26237 bounds.x = bounds.x + style->padding.x;
26238 bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
26239 bounds.w = NK_MAX(bounds.w, 2*style->padding.x);
26240 bounds.w -= 2 * style->padding.x;
26241 bounds.h -= 2 * style->padding.y;
26242 if(bounds.h < bounds.w){
26243 bounds.x += (bounds.w - bounds.h) / 2;
26244 bounds.w = bounds.h;
26245 }
26246
26247 /* make sure the provided values are correct */
26248 knob_max = NK_MAX(min, max);
26249 knob_min = NK_MIN(min, max);
26250 knob_value = NK_CLAMP(knob_min, val, knob_max);
26251 knob_range = knob_max - knob_min;
26252 knob_steps = knob_range / step;
26253
26254 knob_value = nk_knob_behavior(state, in, bounds, knob_min, knob_max, knob_value, step, knob_steps, zero_direction, dead_zone_percent);
26255
26256 /* draw knob */
26257 if (style->draw_begin) style->draw_begin(out, style->userdata);
26258 nk_draw_knob(out, *state, style, &bounds, knob_min, knob_value, knob_max, zero_direction, dead_zone_percent);
26259 if (style->draw_end) style->draw_end(out, style->userdata);
26260 return knob_value;
26261}
26262NK_API nk_bool
26263nk_knob_float(struct nk_context *ctx, float min_value, float *value, float max_value,
26264 float value_step, enum nk_heading zero_direction, float dead_zone_degrees)
26265{
26266 struct nk_window *win;
26267 struct nk_panel *layout;
26268 struct nk_input *in;
26269 const struct nk_style *style;
26270
26271 int ret = 0;
26272 float old_value;
26273 struct nk_rect bounds;
26274 enum nk_widget_layout_states state;
26275
26276 NK_ASSERT(ctx);
26277 NK_ASSERT(ctx->current);
26278 NK_ASSERT(ctx->current->layout);
26279 NK_ASSERT(value);
26280 NK_ASSERT(NK_BETWEEN(dead_zone_degrees, 0.0f, 360.0f));
26281 if (!ctx || !ctx->current || !ctx->current->layout || !value)
26282 return ret;
26283
26284 win = ctx->current;
26285 style = &ctx->style;
26286 layout = win->layout;
26287
26288 state = nk_widget(&bounds, ctx);
26289 if (!state) return ret;
26290 in = (state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
26291
26292 old_value = *value;
26293 *value = nk_do_knob(&ctx->last_widget_state, &win->buffer, bounds, min_value,
26294 old_value, max_value, value_step, zero_direction, dead_zone_degrees / 360.0f, &style->knob, in);
26295
26296 return (old_value > *value || old_value < *value);
26297}
26298NK_API nk_bool
26299nk_knob_int(struct nk_context *ctx, int min, int *val, int max, int step,
26300 enum nk_heading zero_direction, float dead_zone_degrees)
26301{
26302 int ret;
26303 float value = (float)*val;
26304 ret = nk_knob_float(ctx, (float)min, &value, (float)max, (float)step, zero_direction, dead_zone_degrees);
26305 *val = (int)value;
26306 return ret;
26307}
26308
26309
26310
26311
26312/* ===============================================================
26313 *
26314 * PROGRESS
26315 *
26316 * ===============================================================*/
26317NK_LIB nk_size
26318nk_progress_behavior(nk_flags *state, struct nk_input *in,
26319 struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable)
26320{
26321 int left_mouse_down = 0;
26322 int left_mouse_click_in_cursor = 0;
26323
26324 nk_widget_state_reset(state);
26325 if (!in || !modifiable) return value;
26326 left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
26327 left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
26328 NK_BUTTON_LEFT, cursor, nk_true);
26329 if (nk_input_is_mouse_hovering_rect(in, r))
26330 *state = NK_WIDGET_STATE_HOVERED;
26331
26332 if (in && left_mouse_down && left_mouse_click_in_cursor) {
26333 if (left_mouse_down && left_mouse_click_in_cursor) {
26334 float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w;
26335 value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max);
26336 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f;
26337 *state |= NK_WIDGET_STATE_ACTIVE;
26338 }
26339 }
26340 /* set progressbar widget state */
26341 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))
26342 *state |= NK_WIDGET_STATE_ENTERED;
26343 else if (nk_input_is_mouse_prev_hovering_rect(in, r))
26344 *state |= NK_WIDGET_STATE_LEFT;
26345 return value;
26346}
26347NK_LIB void
26348nk_draw_progress(struct nk_command_buffer *out, nk_flags state,
26349 const struct nk_style_progress *style, const struct nk_rect *bounds,
26350 const struct nk_rect *scursor, nk_size value, nk_size max)
26351{
26352 const struct nk_style_item *background;
26353 const struct nk_style_item *cursor;
26354
26355 NK_UNUSED(max);
26356 NK_UNUSED(value);
26357
26358 /* select correct colors/images to draw */
26359 if (state & NK_WIDGET_STATE_ACTIVED) {
26360 background = &style->active;
26361 cursor = &style->cursor_active;
26362 } else if (state & NK_WIDGET_STATE_HOVER){
26363 background = &style->hover;
26364 cursor = &style->cursor_hover;
26365 } else {
26366 background = &style->normal;
26367 cursor = &style->cursor_normal;
26368 }
26369
26370 /* draw background */
26371 switch(background->type) {
26372 case NK_STYLE_ITEM_IMAGE:
26373 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
26374 break;
26375 case NK_STYLE_ITEM_NINE_SLICE:
26376 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
26377 break;
26378 case NK_STYLE_ITEM_COLOR:
26379 nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
26380 nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
26381 break;
26382 }
26383
26384 /* draw cursor */
26385 switch(cursor->type) {
26386 case NK_STYLE_ITEM_IMAGE:
26387 nk_draw_image(out, *scursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));
26388 break;
26389 case NK_STYLE_ITEM_NINE_SLICE:
26390 nk_draw_nine_slice(out, *scursor, &cursor->data.slice, nk_rgb_factor(nk_white, style->color_factor));
26391 break;
26392 case NK_STYLE_ITEM_COLOR:
26393 nk_fill_rect(out, *scursor, style->rounding, nk_rgb_factor(cursor->data.color, style->color_factor));
26394 nk_stroke_rect(out, *scursor, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
26395 break;
26396 }
26397}
26398NK_LIB nk_size
26399nk_do_progress(nk_flags *state,
26400 struct nk_command_buffer *out, struct nk_rect bounds,
26401 nk_size value, nk_size max, nk_bool modifiable,
26402 const struct nk_style_progress *style, struct nk_input *in)
26403{
26404 float prog_scale;
26405 nk_size prog_value;
26406 struct nk_rect cursor;
26407
26408 NK_ASSERT(style);
26409 NK_ASSERT(out);
26410 if (!out || !style) return 0;
26411
26412 /* calculate progressbar cursor */
26413 cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);
26414 cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);
26415 cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));
26416 prog_scale = (float)value / (float)max;
26417
26418 /* update progressbar */
26419 prog_value = NK_MIN(value, max);
26420 prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable);
26421 cursor.w = cursor.w * prog_scale;
26422
26423 /* draw progressbar */
26424 if (style->draw_begin) style->draw_begin(out, style->userdata);
26425 nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);
26426 if (style->draw_end) style->draw_end(out, style->userdata);
26427 return prog_value;
26428}
26429NK_API nk_bool
26430nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, nk_bool is_modifyable)
26431{
26432 struct nk_window *win;
26433 struct nk_panel *layout;
26434 const struct nk_style *style;
26435 struct nk_input *in;
26436
26437 struct nk_rect bounds;
26438 enum nk_widget_layout_states state;
26439 nk_size old_value;
26440
26441 NK_ASSERT(ctx);
26442 NK_ASSERT(cur);
26443 NK_ASSERT(ctx->current);
26444 NK_ASSERT(ctx->current->layout);
26445 if (!ctx || !ctx->current || !ctx->current->layout || !cur)
26446 return 0;
26447
26448 win = ctx->current;
26449 style = &ctx->style;
26450 layout = win->layout;
26451 state = nk_widget(&bounds, ctx);
26452 if (!state) return 0;
26453
26454 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
26455 old_value = *cur;
26456 *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,
26457 *cur, max, is_modifyable, &style->progress, in);
26458 return (*cur != old_value);
26459}
26460NK_API nk_size
26461nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, nk_bool modifyable)
26462{
26463 nk_progress(ctx, &cur, max, modifyable);
26464 return cur;
26465}
26466
26467
26468
26469
26470
26471/* ===============================================================
26472 *
26473 * SCROLLBAR
26474 *
26475 * ===============================================================*/
26476NK_LIB float
26477nk_scrollbar_behavior(nk_flags *state, struct nk_input *in,
26478 int has_scrolling, const struct nk_rect *scroll,
26479 const struct nk_rect *cursor, const struct nk_rect *empty0,
26480 const struct nk_rect *empty1, float scroll_offset,
26481 float target, float scroll_step, enum nk_orientation o)
26482{
26483 nk_flags ws = 0;
26484 int left_mouse_down;
26485 unsigned int left_mouse_clicked;
26486 int left_mouse_click_in_cursor;
26487 float scroll_delta;
26488
26489 nk_widget_state_reset(state);
26490 if (!in) return scroll_offset;
26491
26492 left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;
26493 left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;
26494 left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
26495 NK_BUTTON_LEFT, *cursor, nk_true);
26496 if (nk_input_is_mouse_hovering_rect(in, *scroll))
26497 *state = NK_WIDGET_STATE_HOVERED;
26498
26499 scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;
26500 if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {
26501 /* update cursor by mouse dragging */
26502 float pixel, delta;
26503 *state = NK_WIDGET_STATE_ACTIVE;
26504 if (o == NK_VERTICAL) {
26505 float cursor_y;
26506 pixel = in->mouse.delta.y;
26507 delta = (pixel / scroll->h) * target;
26508 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);
26509 cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);
26510 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;
26511 } else {
26512 float cursor_x;
26513 pixel = in->mouse.delta.x;
26514 delta = (pixel / scroll->w) * target;
26515 scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);
26516 cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);
26517 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;
26518 }
26519 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||
26520 nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {
26521 /* scroll page up by click on empty space or shortcut */
26522 if (o == NK_VERTICAL)
26523 scroll_offset = NK_MAX(0, scroll_offset - scroll->h);
26524 else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);
26525 } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||
26526 nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {
26527 /* scroll page down by click on empty space or shortcut */
26528 if (o == NK_VERTICAL)
26529 scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);
26530 else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);
26531 } else if (has_scrolling) {
26532 if ((scroll_delta < 0 || (scroll_delta > 0))) {
26533 /* update cursor by mouse scrolling */
26534 scroll_offset = scroll_offset + scroll_step * (-scroll_delta);
26535 if (o == NK_VERTICAL)
26536 scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);
26537 else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);
26538 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {
26539 /* update cursor to the beginning */
26540 if (o == NK_VERTICAL) scroll_offset = 0;
26541 } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {
26542 /* update cursor to the end */
26543 if (o == NK_VERTICAL) scroll_offset = target - scroll->h;
26544 }
26545 }
26546 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))
26547 *state |= NK_WIDGET_STATE_ENTERED;
26548 else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))
26549 *state |= NK_WIDGET_STATE_LEFT;
26550 return scroll_offset;
26551}
26552NK_LIB void
26553nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,
26554 const struct nk_style_scrollbar *style, const struct nk_rect *bounds,
26555 const struct nk_rect *scroll)
26556{
26557 const struct nk_style_item *background;
26558 const struct nk_style_item *cursor;
26559
26560 /* select correct colors/images to draw */
26561 if (state & NK_WIDGET_STATE_ACTIVED) {
26562 background = &style->active;
26563 cursor = &style->cursor_active;
26564 } else if (state & NK_WIDGET_STATE_HOVER) {
26565 background = &style->hover;
26566 cursor = &style->cursor_hover;
26567 } else {
26568 background = &style->normal;
26569 cursor = &style->cursor_normal;
26570 }
26571
26572 /* draw background */
26573 switch (background->type) {
26574 case NK_STYLE_ITEM_IMAGE:
26575 nk_draw_image(out, *bounds, &background->data.image, nk_white);
26576 break;
26577 case NK_STYLE_ITEM_NINE_SLICE:
26578 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
26579 break;
26580 case NK_STYLE_ITEM_COLOR:
26581 nk_fill_rect(out, *bounds, style->rounding, background->data.color);
26582 nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);
26583 break;
26584 }
26585
26586 /* draw cursor */
26587 switch (cursor->type) {
26588 case NK_STYLE_ITEM_IMAGE:
26589 nk_draw_image(out, *scroll, &cursor->data.image, nk_white);
26590 break;
26591 case NK_STYLE_ITEM_NINE_SLICE:
26592 nk_draw_nine_slice(out, *scroll, &cursor->data.slice, nk_white);
26593 break;
26594 case NK_STYLE_ITEM_COLOR:
26595 nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);
26596 nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);
26597 break;
26598 }
26599}
26600NK_LIB float
26601nk_do_scrollbarv(nk_flags *state,
26602 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
26603 float offset, float target, float step, float button_pixel_inc,
26604 const struct nk_style_scrollbar *style, struct nk_input *in,
26605 const struct nk_user_font *font)
26606{
26607 struct nk_rect empty_north;
26608 struct nk_rect empty_south;
26609 struct nk_rect cursor;
26610
26611 float scroll_step;
26612 float scroll_offset;
26613 float scroll_off;
26614 float scroll_ratio;
26615
26616 NK_ASSERT(out);
26617 NK_ASSERT(style);
26618 NK_ASSERT(state);
26619 if (!out || !style) return 0;
26620
26621 scroll.w = NK_MAX(scroll.w, 1);
26622 scroll.h = NK_MAX(scroll.h, 0);
26623 if (target <= scroll.h) return 0;
26624
26625 /* optional scrollbar buttons */
26626 if (style->show_buttons) {
26627 nk_flags ws;
26628 float scroll_h;
26629 struct nk_rect button;
26630
26631 button.x = scroll.x;
26632 button.w = scroll.w;
26633 button.h = scroll.w;
26634
26635 scroll_h = NK_MAX(scroll.h - 2 * button.h,0);
26636 scroll_step = NK_MIN(step, button_pixel_inc);
26637
26638 /* decrement button */
26639 button.y = scroll.y;
26640 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
26641 NK_BUTTON_REPEATER, &style->dec_button, in, font))
26642 offset = offset - scroll_step;
26643
26644 /* increment button */
26645 button.y = scroll.y + scroll.h - button.h;
26646 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
26647 NK_BUTTON_REPEATER, &style->inc_button, in, font))
26648 offset = offset + scroll_step;
26649
26650 scroll.y = scroll.y + button.h;
26651 scroll.h = scroll_h;
26652 }
26653
26654 /* calculate scrollbar constants */
26655 scroll_step = NK_MIN(step, scroll.h);
26656 scroll_offset = NK_CLAMP(0, offset, target - scroll.h);
26657 scroll_ratio = scroll.h / target;
26658 scroll_off = scroll_offset / target;
26659
26660 /* calculate scrollbar cursor bounds */
26661 cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0);
26662 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;
26663 cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);
26664 cursor.x = scroll.x + style->border + style->padding.x;
26665
26666 /* calculate empty space around cursor */
26667 empty_north.x = scroll.x;
26668 empty_north.y = scroll.y;
26669 empty_north.w = scroll.w;
26670 empty_north.h = NK_MAX(cursor.y - scroll.y, 0);
26671
26672 empty_south.x = scroll.x;
26673 empty_south.y = cursor.y + cursor.h;
26674 empty_south.w = scroll.w;
26675 empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0);
26676
26677 /* update scrollbar */
26678 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
26679 &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);
26680 scroll_off = scroll_offset / target;
26681 cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;
26682
26683 /* draw scrollbar */
26684 if (style->draw_begin) style->draw_begin(out, style->userdata);
26685 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
26686 if (style->draw_end) style->draw_end(out, style->userdata);
26687 return scroll_offset;
26688}
26689NK_LIB float
26690nk_do_scrollbarh(nk_flags *state,
26691 struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,
26692 float offset, float target, float step, float button_pixel_inc,
26693 const struct nk_style_scrollbar *style, struct nk_input *in,
26694 const struct nk_user_font *font)
26695{
26696 struct nk_rect cursor;
26697 struct nk_rect empty_west;
26698 struct nk_rect empty_east;
26699
26700 float scroll_step;
26701 float scroll_offset;
26702 float scroll_off;
26703 float scroll_ratio;
26704
26705 NK_ASSERT(out);
26706 NK_ASSERT(style);
26707 if (!out || !style) return 0;
26708
26709 /* scrollbar background */
26710 scroll.h = NK_MAX(scroll.h, 1);
26711 scroll.w = NK_MAX(scroll.w, 2 * scroll.h);
26712 if (target <= scroll.w) return 0;
26713
26714 /* optional scrollbar buttons */
26715 if (style->show_buttons) {
26716 nk_flags ws;
26717 float scroll_w;
26718 struct nk_rect button;
26719 button.y = scroll.y;
26720 button.w = scroll.h;
26721 button.h = scroll.h;
26722
26723 scroll_w = scroll.w - 2 * button.w;
26724 scroll_step = NK_MIN(step, button_pixel_inc);
26725
26726 /* decrement button */
26727 button.x = scroll.x;
26728 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,
26729 NK_BUTTON_REPEATER, &style->dec_button, in, font))
26730 offset = offset - scroll_step;
26731
26732 /* increment button */
26733 button.x = scroll.x + scroll.w - button.w;
26734 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,
26735 NK_BUTTON_REPEATER, &style->inc_button, in, font))
26736 offset = offset + scroll_step;
26737
26738 scroll.x = scroll.x + button.w;
26739 scroll.w = scroll_w;
26740 }
26741
26742 /* calculate scrollbar constants */
26743 scroll_step = NK_MIN(step, scroll.w);
26744 scroll_offset = NK_CLAMP(0, offset, target - scroll.w);
26745 scroll_ratio = scroll.w / target;
26746 scroll_off = scroll_offset / target;
26747
26748 /* calculate cursor bounds */
26749 cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);
26750 cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;
26751 cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);
26752 cursor.y = scroll.y + style->border + style->padding.y;
26753
26754 /* calculate empty space around cursor */
26755 empty_west.x = scroll.x;
26756 empty_west.y = scroll.y;
26757 empty_west.w = cursor.x - scroll.x;
26758 empty_west.h = scroll.h;
26759
26760 empty_east.x = cursor.x + cursor.w;
26761 empty_east.y = scroll.y;
26762 empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);
26763 empty_east.h = scroll.h;
26764
26765 /* update scrollbar */
26766 scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,
26767 &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);
26768 scroll_off = scroll_offset / target;
26769 cursor.x = scroll.x + (scroll_off * scroll.w);
26770
26771 /* draw scrollbar */
26772 if (style->draw_begin) style->draw_begin(out, style->userdata);
26773 nk_draw_scrollbar(out, *state, style, &scroll, &cursor);
26774 if (style->draw_end) style->draw_end(out, style->userdata);
26775 return scroll_offset;
26776}
26777
26778
26779
26780
26781
26782/* ===============================================================
26783 *
26784 * TEXT EDITOR
26785 *
26786 * ===============================================================*/
26787/* stb_textedit.h - v1.8 - public domain - Sean Barrett */
26788struct nk_text_find {
26789 float x,y; /* position of n'th character */
26790 float height; /* height of line */
26791 int first_char, length; /* first char of row, and length */
26792 int prev_first; /*_ first char of previous row */
26793};
26794
26795struct nk_text_edit_row {
26796 float x0,x1;
26797 /* starting x location, end x location (allows for align=right, etc) */
26798 float baseline_y_delta;
26799 /* position of baseline relative to previous row's baseline*/
26800 float ymin,ymax;
26801 /* height of row above and below baseline */
26802 int num_chars;
26803};
26804
26805/* forward declarations */
26806NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int);
26807NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int);
26808NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int);
26809#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
26810
26811NK_INTERN float
26812nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id,
26813 const struct nk_user_font *font)
26814{
26815 int len = 0;
26816 nk_rune unicode = 0;
26817 const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len);
26818 return font->width(font->userdata, font->height, str, len);
26819}
26820NK_INTERN void
26821nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit,
26822 int line_start_id, float row_height, const struct nk_user_font *font)
26823{
26824 int l;
26825 int glyphs = 0;
26826 nk_rune unicode;
26827 const char *remaining;
26828 int len = nk_str_len_char(&edit->string);
26829 const char *end = nk_str_get_const(&edit->string) + len;
26830 const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l);
26831 const struct nk_vec2 size = nk_text_calculate_text_bounds(font,
26832 text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE);
26833
26834 r->x0 = 0.0f;
26835 r->x1 = size.x;
26836 r->baseline_y_delta = size.y;
26837 r->ymin = 0.0f;
26838 r->ymax = size.y;
26839 r->num_chars = glyphs;
26840}
26841NK_INTERN int
26842nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y,
26843 const struct nk_user_font *font, float row_height)
26844{
26845 struct nk_text_edit_row r;
26846 int n = edit->string.len;
26847 float base_y = 0, prev_x;
26848 int i=0, k;
26849
26850 r.x0 = r.x1 = 0;
26851 r.ymin = r.ymax = 0;
26852 r.num_chars = 0;
26853
26854 /* search rows to find one that straddles 'y' */
26855 while (i < n) {
26856 nk_textedit_layout_row(&r, edit, i, row_height, font);
26857 if (r.num_chars <= 0)
26858 return n;
26859
26860 if (i==0 && y < base_y + r.ymin)
26861 return 0;
26862
26863 if (y < base_y + r.ymax)
26864 break;
26865
26866 i += r.num_chars;
26867 base_y += r.baseline_y_delta;
26868 }
26869
26870 /* below all text, return 'after' last character */
26871 if (i >= n)
26872 return n;
26873
26874 /* check if it's before the beginning of the line */
26875 if (x < r.x0)
26876 return i;
26877
26878 /* check if it's before the end of the line */
26879 if (x < r.x1) {
26880 /* search characters in row for one that straddles 'x' */
26881 k = i;
26882 prev_x = r.x0;
26883 for (i=0; i < r.num_chars; ++i) {
26884 float w = nk_textedit_get_width(edit, k, i, font);
26885 if (x < prev_x+w) {
26886 if (x < prev_x+w/2)
26887 return k+i;
26888 else return k+i+1;
26889 }
26890 prev_x += w;
26891 }
26892 /* shouldn't happen, but if it does, fall through to end-of-line case */
26893 }
26894
26895 /* if the last character is a newline, return that.
26896 * otherwise return 'after' the last character */
26897 if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n')
26898 return i+r.num_chars-1;
26899 else return i+r.num_chars;
26900}
26901NK_LIB void
26902nk_textedit_click(struct nk_text_edit *state, float x, float y,
26903 const struct nk_user_font *font, float row_height)
26904{
26905 /* API click: on mouse down, move the cursor to the clicked location,
26906 * and reset the selection */
26907 state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height);
26908 state->select_start = state->cursor;
26909 state->select_end = state->cursor;
26910 state->has_preferred_x = 0;
26911}
26912NK_LIB void
26913nk_textedit_drag(struct nk_text_edit *state, float x, float y,
26914 const struct nk_user_font *font, float row_height)
26915{
26916 /* API drag: on mouse drag, move the cursor and selection endpoint
26917 * to the clicked location */
26918 int p = nk_textedit_locate_coord(state, x, y, font, row_height);
26919 if (state->select_start == state->select_end)
26920 state->select_start = state->cursor;
26921 state->cursor = state->select_end = p;
26922}
26923NK_INTERN void
26924nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state,
26925 int n, int single_line, const struct nk_user_font *font, float row_height)
26926{
26927 /* find the x/y location of a character, and remember info about the previous
26928 * row in case we get a move-up event (for page up, we'll have to rescan) */
26929 struct nk_text_edit_row r;
26930 int prev_start = 0;
26931 int z = state->string.len;
26932 int i=0, first;
26933
26934 nk_zero_struct(r);
26935 if (n == z) {
26936 /* if it's at the end, then find the last line -- simpler than trying to
26937 explicitly handle this case in the regular code */
26938 nk_textedit_layout_row(&r, state, 0, row_height, font);
26939 if (single_line) {
26940 find->first_char = 0;
26941 find->length = z;
26942 } else {
26943 while (i < z) {
26944 prev_start = i;
26945 i += r.num_chars;
26946 nk_textedit_layout_row(&r, state, i, row_height, font);
26947 }
26948
26949 find->first_char = i;
26950 find->length = r.num_chars;
26951 }
26952 find->x = r.x1;
26953 find->y = r.ymin;
26954 find->height = r.ymax - r.ymin;
26955 find->prev_first = prev_start;
26956 return;
26957 }
26958
26959 /* search rows to find the one that straddles character n */
26960 find->y = 0;
26961
26962 for(;;) {
26963 nk_textedit_layout_row(&r, state, i, row_height, font);
26964 if (n < i + r.num_chars) break;
26965 prev_start = i;
26966 i += r.num_chars;
26967 find->y += r.baseline_y_delta;
26968 }
26969
26970 find->first_char = first = i;
26971 find->length = r.num_chars;
26972 find->height = r.ymax - r.ymin;
26973 find->prev_first = prev_start;
26974
26975 /* now scan to find xpos */
26976 find->x = r.x0;
26977 for (i=0; first+i < n; ++i)
26978 find->x += nk_textedit_get_width(state, first, i, font);
26979}
26980NK_INTERN void
26981nk_textedit_clamp(struct nk_text_edit *state)
26982{
26983 /* make the selection/cursor state valid if client altered the string */
26984 int n = state->string.len;
26985 if (NK_TEXT_HAS_SELECTION(state)) {
26986 if (state->select_start > n) state->select_start = n;
26987 if (state->select_end > n) state->select_end = n;
26988 /* if clamping forced them to be equal, move the cursor to match */
26989 if (state->select_start == state->select_end)
26990 state->cursor = state->select_start;
26991 }
26992 if (state->cursor > n) state->cursor = n;
26993}
26994NK_API void
26995nk_textedit_delete(struct nk_text_edit *state, int where, int len)
26996{
26997 /* delete characters while updating undo */
26998 nk_textedit_makeundo_delete(state, where, len);
26999 nk_str_delete_runes(&state->string, where, len);
27000 state->has_preferred_x = 0;
27001}
27002NK_API void
27003nk_textedit_delete_selection(struct nk_text_edit *state)
27004{
27005 /* delete the section */
27006 nk_textedit_clamp(state);
27007 if (NK_TEXT_HAS_SELECTION(state)) {
27008 if (state->select_start < state->select_end) {
27009 nk_textedit_delete(state, state->select_start,
27010 state->select_end - state->select_start);
27011 state->select_end = state->cursor = state->select_start;
27012 } else {
27013 nk_textedit_delete(state, state->select_end,
27014 state->select_start - state->select_end);
27015 state->select_start = state->cursor = state->select_end;
27016 }
27017 state->has_preferred_x = 0;
27018 }
27019}
27020NK_INTERN void
27021nk_textedit_sortselection(struct nk_text_edit *state)
27022{
27023 /* canonicalize the selection so start <= end */
27024 if (state->select_end < state->select_start) {
27025 int temp = state->select_end;
27026 state->select_end = state->select_start;
27027 state->select_start = temp;
27028 }
27029}
27030NK_INTERN void
27031nk_textedit_move_to_first(struct nk_text_edit *state)
27032{
27033 /* move cursor to first character of selection */
27034 if (NK_TEXT_HAS_SELECTION(state)) {
27035 nk_textedit_sortselection(state);
27036 state->cursor = state->select_start;
27037 state->select_end = state->select_start;
27038 state->has_preferred_x = 0;
27039 }
27040}
27041NK_INTERN void
27042nk_textedit_move_to_last(struct nk_text_edit *state)
27043{
27044 /* move cursor to last character of selection */
27045 if (NK_TEXT_HAS_SELECTION(state)) {
27046 nk_textedit_sortselection(state);
27047 nk_textedit_clamp(state);
27048 state->cursor = state->select_end;
27049 state->select_start = state->select_end;
27050 state->has_preferred_x = 0;
27051 }
27052}
27053NK_INTERN int
27054nk_is_word_boundary( struct nk_text_edit *state, int idx)
27055{
27056 int len;
27057 nk_rune c;
27058 if (idx < 0) return 1;
27059 if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1;
27060#ifndef NK_IS_WORD_BOUNDARY
27061 return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' ||
27062 c == '\v' || c == 0x3000);
27063#else
27064 return NK_IS_WORD_BOUNDARY(c);
27065#endif
27066}
27067NK_INTERN int
27068nk_textedit_move_to_word_previous(struct nk_text_edit *state)
27069{
27070 int c = state->cursor - 1;
27071 if (c > 0) {
27072 if (nk_is_word_boundary(state, c)) {
27073 while (c > 0 && nk_is_word_boundary(state, --c));
27074 }
27075 while (!nk_is_word_boundary(state, --c));
27076 c++;
27077 } else {
27078 return 0;
27079 }
27080
27081 return c;
27082}
27083NK_INTERN int
27084nk_textedit_move_to_word_next(struct nk_text_edit *state)
27085{
27086 const int len = state->string.len;
27087 int c = state->cursor;
27088 if (c < len) {
27089 if (!nk_is_word_boundary(state, c)) {
27090 while (c < len && !nk_is_word_boundary(state, ++c));
27091 }
27092 while (c < len && nk_is_word_boundary(state, ++c));
27093 } else {
27094 return len;
27095 }
27096
27097 return c;
27098}
27099NK_INTERN void
27100nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state)
27101{
27102 /* update selection and cursor to match each other */
27103 if (!NK_TEXT_HAS_SELECTION(state))
27104 state->select_start = state->select_end = state->cursor;
27105 else state->cursor = state->select_end;
27106}
27107NK_API nk_bool
27108nk_textedit_cut(struct nk_text_edit *state)
27109{
27110 /* API cut: delete selection */
27111 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
27112 return 0;
27113 if (NK_TEXT_HAS_SELECTION(state)) {
27114 nk_textedit_delete_selection(state); /* implicitly clamps */
27115 state->has_preferred_x = 0;
27116 return 1;
27117 }
27118 return 0;
27119}
27120NK_API nk_bool
27121nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)
27122{
27123 /* API paste: replace existing selection with passed-in text */
27124 int glyphs;
27125 const char *text = (const char *) ctext;
27126 if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;
27127
27128 /* if there's a selection, the paste should delete it */
27129 nk_textedit_clamp(state);
27130 nk_textedit_delete_selection(state);
27131
27132 /* try to insert the characters */
27133 glyphs = nk_utf_len(ctext, len);
27134 if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {
27135 nk_textedit_makeundo_insert(state, state->cursor, glyphs);
27136 state->cursor += len;
27137 state->has_preferred_x = 0;
27138 return 1;
27139 }
27140 /* remove the undo since we didn't actually insert the characters */
27141 if (state->undo.undo_point)
27142 --state->undo.undo_point;
27143 return 0;
27144}
27145NK_API void
27146nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)
27147{
27148 nk_rune unicode;
27149 int glyph_len;
27150 int text_len = 0;
27151
27152 NK_ASSERT(state);
27153 NK_ASSERT(text);
27154 if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return;
27155
27156 glyph_len = nk_utf_decode(text, &unicode, total_len);
27157 while ((text_len < total_len) && glyph_len)
27158 {
27159 /* don't insert a backward delete, just process the event */
27160 if (unicode == 127) goto next;
27161 /* can't add newline in single-line mode */
27162 if (unicode == '\n' && state->single_line) goto next;
27163 /* filter incoming text */
27164 if (state->filter && !state->filter(state, unicode)) goto next;
27165
27166 if (!NK_TEXT_HAS_SELECTION(state) &&
27167 state->cursor < state->string.len)
27168 {
27169 if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) {
27170 nk_textedit_makeundo_replace(state, state->cursor, 1, 1);
27171 nk_str_delete_runes(&state->string, state->cursor, 1);
27172 }
27173 if (nk_str_insert_text_utf8(&state->string, state->cursor,
27174 text+text_len, 1))
27175 {
27176 ++state->cursor;
27177 state->has_preferred_x = 0;
27178 }
27179 } else {
27180 nk_textedit_delete_selection(state); /* implicitly clamps */
27181 if (nk_str_insert_text_utf8(&state->string, state->cursor,
27182 text+text_len, 1))
27183 {
27184 nk_textedit_makeundo_insert(state, state->cursor, 1);
27185 state->cursor = NK_MIN(state->cursor + 1, state->string.len);
27186 state->has_preferred_x = 0;
27187 }
27188 }
27189 next:
27190 text_len += glyph_len;
27191 glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len);
27192 }
27193}
27194NK_LIB void
27195nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod,
27196 const struct nk_user_font *font, float row_height)
27197{
27198retry:
27199 switch (key)
27200 {
27201 case NK_KEY_NONE:
27202 case NK_KEY_CTRL:
27203 case NK_KEY_ENTER:
27204 case NK_KEY_SHIFT:
27205 case NK_KEY_TAB:
27206 case NK_KEY_COPY:
27207 case NK_KEY_CUT:
27208 case NK_KEY_PASTE:
27209 case NK_KEY_MAX:
27210 default: break;
27211 case NK_KEY_TEXT_UNDO:
27212 nk_textedit_undo(state);
27213 state->has_preferred_x = 0;
27214 break;
27215
27216 case NK_KEY_TEXT_REDO:
27217 nk_textedit_redo(state);
27218 state->has_preferred_x = 0;
27219 break;
27220
27221 case NK_KEY_TEXT_SELECT_ALL:
27222 nk_textedit_select_all(state);
27223 state->has_preferred_x = 0;
27224 break;
27225
27226 case NK_KEY_TEXT_INSERT_MODE:
27227 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
27228 state->mode = NK_TEXT_EDIT_MODE_INSERT;
27229 break;
27230 case NK_KEY_TEXT_REPLACE_MODE:
27231 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
27232 state->mode = NK_TEXT_EDIT_MODE_REPLACE;
27233 break;
27234 case NK_KEY_TEXT_RESET_MODE:
27235 if (state->mode == NK_TEXT_EDIT_MODE_INSERT ||
27236 state->mode == NK_TEXT_EDIT_MODE_REPLACE)
27237 state->mode = NK_TEXT_EDIT_MODE_VIEW;
27238 break;
27239
27240 case NK_KEY_LEFT:
27241 if (shift_mod) {
27242 nk_textedit_clamp(state);
27243 nk_textedit_prep_selection_at_cursor(state);
27244 /* move selection left */
27245 if (state->select_end > 0)
27246 --state->select_end;
27247 state->cursor = state->select_end;
27248 state->has_preferred_x = 0;
27249 } else {
27250 /* if currently there's a selection,
27251 * move cursor to start of selection */
27252 if (NK_TEXT_HAS_SELECTION(state))
27253 nk_textedit_move_to_first(state);
27254 else if (state->cursor > 0)
27255 --state->cursor;
27256 state->has_preferred_x = 0;
27257 } break;
27258
27259 case NK_KEY_RIGHT:
27260 if (shift_mod) {
27261 nk_textedit_prep_selection_at_cursor(state);
27262 /* move selection right */
27263 ++state->select_end;
27264 nk_textedit_clamp(state);
27265 state->cursor = state->select_end;
27266 state->has_preferred_x = 0;
27267 } else {
27268 /* if currently there's a selection,
27269 * move cursor to end of selection */
27270 if (NK_TEXT_HAS_SELECTION(state))
27271 nk_textedit_move_to_last(state);
27272 else ++state->cursor;
27273 nk_textedit_clamp(state);
27274 state->has_preferred_x = 0;
27275 } break;
27276
27277 case NK_KEY_TEXT_WORD_LEFT:
27278 if (shift_mod) {
27279 if( !NK_TEXT_HAS_SELECTION( state ) )
27280 nk_textedit_prep_selection_at_cursor(state);
27281 state->cursor = nk_textedit_move_to_word_previous(state);
27282 state->select_end = state->cursor;
27283 nk_textedit_clamp(state );
27284 } else {
27285 if (NK_TEXT_HAS_SELECTION(state))
27286 nk_textedit_move_to_first(state);
27287 else {
27288 state->cursor = nk_textedit_move_to_word_previous(state);
27289 nk_textedit_clamp(state );
27290 }
27291 } break;
27292
27293 case NK_KEY_TEXT_WORD_RIGHT:
27294 if (shift_mod) {
27295 if( !NK_TEXT_HAS_SELECTION( state ) )
27296 nk_textedit_prep_selection_at_cursor(state);
27297 state->cursor = nk_textedit_move_to_word_next(state);
27298 state->select_end = state->cursor;
27299 nk_textedit_clamp(state);
27300 } else {
27301 if (NK_TEXT_HAS_SELECTION(state))
27302 nk_textedit_move_to_last(state);
27303 else {
27304 state->cursor = nk_textedit_move_to_word_next(state);
27305 nk_textedit_clamp(state );
27306 }
27307 } break;
27308
27309 case NK_KEY_DOWN: {
27310 struct nk_text_find find;
27311 struct nk_text_edit_row row;
27312 int i, sel = shift_mod;
27313
27314 if (state->single_line) {
27315 /* on windows, up&down in single-line behave like left&right */
27316 key = NK_KEY_RIGHT;
27317 goto retry;
27318 }
27319
27320 if (sel)
27321 nk_textedit_prep_selection_at_cursor(state);
27322 else if (NK_TEXT_HAS_SELECTION(state))
27323 nk_textedit_move_to_last(state);
27324
27325 /* compute current position of cursor point */
27326 nk_textedit_clamp(state);
27327 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
27328 font, row_height);
27329
27330 /* now find character position down a row */
27331 if (find.length)
27332 {
27333 float x;
27334 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
27335 int start = find.first_char + find.length;
27336
27337 state->cursor = start;
27338 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
27339 x = row.x0;
27340
27341 for (i=0; i < row.num_chars && x < row.x1; ++i) {
27342 float dx = nk_textedit_get_width(state, start, i, font);
27343 x += dx;
27344 if (x > goal_x)
27345 break;
27346 ++state->cursor;
27347 }
27348 nk_textedit_clamp(state);
27349
27350 state->has_preferred_x = 1;
27351 state->preferred_x = goal_x;
27352 if (sel)
27353 state->select_end = state->cursor;
27354 }
27355 } break;
27356
27357 case NK_KEY_UP: {
27358 struct nk_text_find find;
27359 struct nk_text_edit_row row;
27360 int i, sel = shift_mod;
27361
27362 if (state->single_line) {
27363 /* on windows, up&down become left&right */
27364 key = NK_KEY_LEFT;
27365 goto retry;
27366 }
27367
27368 if (sel)
27369 nk_textedit_prep_selection_at_cursor(state);
27370 else if (NK_TEXT_HAS_SELECTION(state))
27371 nk_textedit_move_to_first(state);
27372
27373 /* compute current position of cursor point */
27374 nk_textedit_clamp(state);
27375 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
27376 font, row_height);
27377
27378 /* can only go up if there's a previous row */
27379 if (find.prev_first != find.first_char) {
27380 /* now find character position up a row */
27381 float x;
27382 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
27383
27384 state->cursor = find.prev_first;
27385 nk_textedit_layout_row(&row, state, state->cursor, row_height, font);
27386 x = row.x0;
27387
27388 for (i=0; i < row.num_chars && x < row.x1; ++i) {
27389 float dx = nk_textedit_get_width(state, find.prev_first, i, font);
27390 x += dx;
27391 if (x > goal_x)
27392 break;
27393 ++state->cursor;
27394 }
27395 nk_textedit_clamp(state);
27396
27397 state->has_preferred_x = 1;
27398 state->preferred_x = goal_x;
27399 if (sel) state->select_end = state->cursor;
27400 }
27401 } break;
27402
27403 case NK_KEY_DEL:
27404 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
27405 break;
27406 if (NK_TEXT_HAS_SELECTION(state))
27407 nk_textedit_delete_selection(state);
27408 else {
27409 int n = state->string.len;
27410 if (state->cursor < n)
27411 nk_textedit_delete(state, state->cursor, 1);
27412 }
27413 state->has_preferred_x = 0;
27414 break;
27415
27416 case NK_KEY_BACKSPACE:
27417 if (state->mode == NK_TEXT_EDIT_MODE_VIEW)
27418 break;
27419 if (NK_TEXT_HAS_SELECTION(state))
27420 nk_textedit_delete_selection(state);
27421 else {
27422 nk_textedit_clamp(state);
27423 if (state->cursor > 0) {
27424 nk_textedit_delete(state, state->cursor-1, 1);
27425 --state->cursor;
27426 }
27427 }
27428 state->has_preferred_x = 0;
27429 break;
27430
27431 case NK_KEY_TEXT_START:
27432 if (shift_mod) {
27433 nk_textedit_prep_selection_at_cursor(state);
27434 state->cursor = state->select_end = 0;
27435 state->has_preferred_x = 0;
27436 } else {
27437 state->cursor = state->select_start = state->select_end = 0;
27438 state->has_preferred_x = 0;
27439 }
27440 break;
27441
27442 case NK_KEY_TEXT_END:
27443 if (shift_mod) {
27444 nk_textedit_prep_selection_at_cursor(state);
27445 state->cursor = state->select_end = state->string.len;
27446 state->has_preferred_x = 0;
27447 } else {
27448 state->cursor = state->string.len;
27449 state->select_start = state->select_end = 0;
27450 state->has_preferred_x = 0;
27451 }
27452 break;
27453
27454 case NK_KEY_TEXT_LINE_START: {
27455 if (shift_mod) {
27456 struct nk_text_find find;
27457 nk_textedit_clamp(state);
27458 nk_textedit_prep_selection_at_cursor(state);
27459 if (state->string.len && state->cursor == state->string.len)
27460 --state->cursor;
27461 nk_textedit_find_charpos(&find, state,state->cursor, state->single_line,
27462 font, row_height);
27463 state->cursor = state->select_end = find.first_char;
27464 state->has_preferred_x = 0;
27465 } else {
27466 struct nk_text_find find;
27467 if (state->string.len && state->cursor == state->string.len)
27468 --state->cursor;
27469 nk_textedit_clamp(state);
27470 nk_textedit_move_to_first(state);
27471 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
27472 font, row_height);
27473 state->cursor = find.first_char;
27474 state->has_preferred_x = 0;
27475 }
27476 } break;
27477
27478 case NK_KEY_TEXT_LINE_END: {
27479 if (shift_mod) {
27480 struct nk_text_find find;
27481 nk_textedit_clamp(state);
27482 nk_textedit_prep_selection_at_cursor(state);
27483 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
27484 font, row_height);
27485 state->has_preferred_x = 0;
27486 state->cursor = find.first_char + find.length;
27487 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
27488 --state->cursor;
27489 state->select_end = state->cursor;
27490 } else {
27491 struct nk_text_find find;
27492 nk_textedit_clamp(state);
27493 nk_textedit_move_to_first(state);
27494 nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,
27495 font, row_height);
27496
27497 state->has_preferred_x = 0;
27498 state->cursor = find.first_char + find.length;
27499 if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n')
27500 --state->cursor;
27501 }} break;
27502 }
27503}
27504NK_INTERN void
27505nk_textedit_flush_redo(struct nk_text_undo_state *state)
27506{
27507 state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
27508 state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
27509}
27510NK_INTERN void
27511nk_textedit_discard_undo(struct nk_text_undo_state *state)
27512{
27513 /* discard the oldest entry in the undo list */
27514 if (state->undo_point > 0) {
27515 /* if the 0th undo state has characters, clean those up */
27516 if (state->undo_rec[0].char_storage >= 0) {
27517 int n = state->undo_rec[0].insert_length, i;
27518 /* delete n characters from all other records */
27519 state->undo_char_point = (short)(state->undo_char_point - n);
27520 NK_MEMCPY(state->undo_char, state->undo_char + n,
27521 (nk_size)state->undo_char_point*sizeof(nk_rune));
27522 for (i=0; i < state->undo_point; ++i) {
27523 if (state->undo_rec[i].char_storage >= 0)
27524 state->undo_rec[i].char_storage = (short)
27525 (state->undo_rec[i].char_storage - n);
27526 }
27527 }
27528 --state->undo_point;
27529 NK_MEMCPY(state->undo_rec, state->undo_rec+1,
27530 (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0])));
27531 }
27532}
27533NK_INTERN void
27534nk_textedit_discard_redo(struct nk_text_undo_state *state)
27535{
27536/* discard the oldest entry in the redo list--it's bad if this
27537 ever happens, but because undo & redo have to store the actual
27538 characters in different cases, the redo character buffer can
27539 fill up even though the undo buffer didn't */
27540 nk_size num;
27541 int k = NK_TEXTEDIT_UNDOSTATECOUNT-1;
27542 if (state->redo_point <= k) {
27543 /* if the k'th undo state has characters, clean those up */
27544 if (state->undo_rec[k].char_storage >= 0) {
27545 int n = state->undo_rec[k].insert_length, i;
27546 /* delete n characters from all other records */
27547 state->redo_char_point = (short)(state->redo_char_point + n);
27548 num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point);
27549 NK_MEMCPY(state->undo_char + state->redo_char_point,
27550 state->undo_char + state->redo_char_point-n, num * sizeof(char));
27551 for (i = state->redo_point; i < k; ++i) {
27552 if (state->undo_rec[i].char_storage >= 0) {
27553 state->undo_rec[i].char_storage = (short)
27554 (state->undo_rec[i].char_storage + n);
27555 }
27556 }
27557 }
27558 ++state->redo_point;
27559 num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point);
27560 if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1,
27561 state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0]));
27562 }
27563}
27564NK_INTERN struct nk_text_undo_record*
27565nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars)
27566{
27567 /* any time we create a new undo record, we discard redo*/
27568 nk_textedit_flush_redo(state);
27569
27570 /* if we have no free records, we have to make room,
27571 * by sliding the existing records down */
27572 if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
27573 nk_textedit_discard_undo(state);
27574
27575 /* if the characters to store won't possibly fit in the buffer,
27576 * we can't undo */
27577 if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) {
27578 state->undo_point = 0;
27579 state->undo_char_point = 0;
27580 return 0;
27581 }
27582
27583 /* if we don't have enough free characters in the buffer,
27584 * we have to make room */
27585 while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT)
27586 nk_textedit_discard_undo(state);
27587 return &state->undo_rec[state->undo_point++];
27588}
27589NK_INTERN nk_rune*
27590nk_textedit_createundo(struct nk_text_undo_state *state, int pos,
27591 int insert_len, int delete_len)
27592{
27593 struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len);
27594 if (r == 0)
27595 return 0;
27596
27597 r->where = pos;
27598 r->insert_length = (short) insert_len;
27599 r->delete_length = (short) delete_len;
27600
27601 if (insert_len == 0) {
27602 r->char_storage = -1;
27603 return 0;
27604 } else {
27605 r->char_storage = state->undo_char_point;
27606 state->undo_char_point = (short)(state->undo_char_point + insert_len);
27607 return &state->undo_char[r->char_storage];
27608 }
27609}
27610NK_API void
27611nk_textedit_undo(struct nk_text_edit *state)
27612{
27613 struct nk_text_undo_state *s = &state->undo;
27614 struct nk_text_undo_record u, *r;
27615 if (s->undo_point == 0)
27616 return;
27617
27618 /* we need to do two things: apply the undo record, and create a redo record */
27619 u = s->undo_rec[s->undo_point-1];
27620 r = &s->undo_rec[s->redo_point-1];
27621 r->char_storage = -1;
27622
27623 r->insert_length = u.delete_length;
27624 r->delete_length = u.insert_length;
27625 r->where = u.where;
27626
27627 if (u.delete_length)
27628 {
27629 /* if the undo record says to delete characters, then the redo record will
27630 need to re-insert the characters that get deleted, so we need to store
27631 them.
27632 there are three cases:
27633 - there's enough room to store the characters
27634 - characters stored for *redoing* don't leave room for redo
27635 - characters stored for *undoing* don't leave room for redo
27636 if the last is true, we have to bail */
27637 if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) {
27638 /* the undo records take up too much character space; there's no space
27639 * to store the redo characters */
27640 r->insert_length = 0;
27641 } else {
27642 int i;
27643 /* there's definitely room to store the characters eventually */
27644 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
27645 /* there's currently not enough room, so discard a redo record */
27646 nk_textedit_discard_redo(s);
27647 /* should never happen: */
27648 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
27649 return;
27650 }
27651
27652 r = &s->undo_rec[s->redo_point-1];
27653 r->char_storage = (short)(s->redo_char_point - u.delete_length);
27654 s->redo_char_point = (short)(s->redo_char_point - u.delete_length);
27655
27656 /* now save the characters */
27657 for (i=0; i < u.delete_length; ++i)
27658 s->undo_char[r->char_storage + i] =
27659 nk_str_rune_at(&state->string, u.where + i);
27660 }
27661 /* now we can carry out the deletion */
27662 nk_str_delete_runes(&state->string, u.where, u.delete_length);
27663 }
27664
27665 /* check type of recorded action: */
27666 if (u.insert_length) {
27667 /* easy case: was a deletion, so we need to insert n characters */
27668 nk_str_insert_text_runes(&state->string, u.where,
27669 &s->undo_char[u.char_storage], u.insert_length);
27670 s->undo_char_point = (short)(s->undo_char_point - u.insert_length);
27671 }
27672 state->cursor = (short)(u.where + u.insert_length);
27673
27674 s->undo_point--;
27675 s->redo_point--;
27676}
27677NK_API void
27678nk_textedit_redo(struct nk_text_edit *state)
27679{
27680 struct nk_text_undo_state *s = &state->undo;
27681 struct nk_text_undo_record *u, r;
27682 if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)
27683 return;
27684
27685 /* we need to do two things: apply the redo record, and create an undo record */
27686 u = &s->undo_rec[s->undo_point];
27687 r = s->undo_rec[s->redo_point];
27688
27689 /* we KNOW there must be room for the undo record, because the redo record
27690 was derived from an undo record */
27691 u->delete_length = r.insert_length;
27692 u->insert_length = r.delete_length;
27693 u->where = r.where;
27694 u->char_storage = -1;
27695
27696 if (r.delete_length) {
27697 /* the redo record requires us to delete characters, so the undo record
27698 needs to store the characters */
27699 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
27700 u->insert_length = 0;
27701 u->delete_length = 0;
27702 } else {
27703 int i;
27704 u->char_storage = s->undo_char_point;
27705 s->undo_char_point = (short)(s->undo_char_point + u->insert_length);
27706
27707 /* now save the characters */
27708 for (i=0; i < u->insert_length; ++i) {
27709 s->undo_char[u->char_storage + i] =
27710 nk_str_rune_at(&state->string, u->where + i);
27711 }
27712 }
27713 nk_str_delete_runes(&state->string, r.where, r.delete_length);
27714 }
27715
27716 if (r.insert_length) {
27717 /* easy case: need to insert n characters */
27718 nk_str_insert_text_runes(&state->string, r.where,
27719 &s->undo_char[r.char_storage], r.insert_length);
27720 }
27721 state->cursor = r.where + r.insert_length;
27722
27723 s->undo_point++;
27724 s->redo_point++;
27725}
27726NK_INTERN void
27727nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length)
27728{
27729 nk_textedit_createundo(&state->undo, where, 0, length);
27730}
27731NK_INTERN void
27732nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length)
27733{
27734 int i;
27735 nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0);
27736 if (p) {
27737 for (i=0; i < length; ++i)
27738 p[i] = nk_str_rune_at(&state->string, where+i);
27739 }
27740}
27741NK_INTERN void
27742nk_textedit_makeundo_replace(struct nk_text_edit *state, int where,
27743 int old_length, int new_length)
27744{
27745 int i;
27746 nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length);
27747 if (p) {
27748 for (i=0; i < old_length; ++i)
27749 p[i] = nk_str_rune_at(&state->string, where+i);
27750 }
27751}
27752NK_LIB void
27753nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type,
27754 nk_plugin_filter filter)
27755{
27756 /* reset the state to default */
27757 state->undo.undo_point = 0;
27758 state->undo.undo_char_point = 0;
27759 state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;
27760 state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;
27761 state->select_end = state->select_start = 0;
27762 state->cursor = 0;
27763 state->has_preferred_x = 0;
27764 state->preferred_x = 0;
27765 state->cursor_at_end_of_line = 0;
27766 state->initialized = 1;
27767 state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE);
27768 state->mode = NK_TEXT_EDIT_MODE_VIEW;
27769 state->filter = filter;
27770 state->scrollbar = nk_vec2(0,0);
27771}
27772NK_API void
27773nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size)
27774{
27775 NK_ASSERT(state);
27776 NK_ASSERT(memory);
27777 if (!state || !memory || !size) return;
27778 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
27779 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
27780 nk_str_init_fixed(&state->string, memory, size);
27781}
27782NK_API void
27783nk_textedit_init(struct nk_text_edit *state, const struct nk_allocator *alloc, nk_size size)
27784{
27785 NK_ASSERT(state);
27786 NK_ASSERT(alloc);
27787 if (!state || !alloc) return;
27788 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
27789 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
27790 nk_str_init(&state->string, alloc, size);
27791}
27792#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
27793NK_API void
27794nk_textedit_init_default(struct nk_text_edit *state)
27795{
27796 NK_ASSERT(state);
27797 if (!state) return;
27798 NK_MEMSET(state, 0, sizeof(struct nk_text_edit));
27799 nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);
27800 nk_str_init_default(&state->string);
27801}
27802#endif
27803NK_API void
27804nk_textedit_select_all(struct nk_text_edit *state)
27805{
27806 NK_ASSERT(state);
27807 state->select_start = 0;
27808 state->select_end = state->string.len;
27809}
27810NK_API void
27811nk_textedit_free(struct nk_text_edit *state)
27812{
27813 NK_ASSERT(state);
27814 if (!state) return;
27815 nk_str_free(&state->string);
27816}
27817
27818
27819
27820
27821
27822/* ===============================================================
27823 *
27824 * FILTER
27825 *
27826 * ===============================================================*/
27827NK_API nk_bool
27828nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
27829{
27830 NK_UNUSED(unicode);
27831 NK_UNUSED(box);
27832 return nk_true;
27833}
27834NK_API nk_bool
27835nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)
27836{
27837 NK_UNUSED(box);
27838 if (unicode > 128) return nk_false;
27839 else return nk_true;
27840}
27841NK_API nk_bool
27842nk_filter_float(const struct nk_text_edit *box, nk_rune unicode)
27843{
27844 NK_UNUSED(box);
27845 if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
27846 return nk_false;
27847 else return nk_true;
27848}
27849NK_API nk_bool
27850nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)
27851{
27852 NK_UNUSED(box);
27853 if ((unicode < '0' || unicode > '9') && unicode != '-')
27854 return nk_false;
27855 else return nk_true;
27856}
27857NK_API nk_bool
27858nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)
27859{
27860 NK_UNUSED(box);
27861 if ((unicode < '0' || unicode > '9') &&
27862 (unicode < 'a' || unicode > 'f') &&
27863 (unicode < 'A' || unicode > 'F'))
27864 return nk_false;
27865 else return nk_true;
27866}
27867NK_API nk_bool
27868nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)
27869{
27870 NK_UNUSED(box);
27871 if (unicode < '0' || unicode > '7')
27872 return nk_false;
27873 else return nk_true;
27874}
27875NK_API nk_bool
27876nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)
27877{
27878 NK_UNUSED(box);
27879 if (unicode != '0' && unicode != '1')
27880 return nk_false;
27881 else return nk_true;
27882}
27883
27884/* ===============================================================
27885 *
27886 * EDIT
27887 *
27888 * ===============================================================*/
27889NK_LIB void
27890nk_edit_draw_text(struct nk_command_buffer *out,
27891 const struct nk_style_edit *style, float pos_x, float pos_y,
27892 float x_offset, const char *text, int byte_len, float row_height,
27893 const struct nk_user_font *font, struct nk_color background,
27894 struct nk_color foreground, nk_bool is_selected)
27895{
27896 NK_ASSERT(out);
27897 NK_ASSERT(font);
27898 NK_ASSERT(style);
27899 if (!text || !byte_len || !out || !style) return;
27900
27901 {int glyph_len = 0;
27902 nk_rune unicode = 0;
27903 int text_len = 0;
27904 float line_width = 0;
27905 float glyph_width;
27906 const char *line = text;
27907 float line_offset = 0;
27908 int line_count = 0;
27909
27910 struct nk_text txt;
27911 txt.padding = nk_vec2(0,0);
27912 txt.background = background;
27913 txt.text = foreground;
27914
27915 foreground = nk_rgb_factor(foreground, style->color_factor);
27916 background = nk_rgb_factor(background, style->color_factor);
27917
27918 glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
27919 if (!glyph_len) return;
27920 while ((text_len < byte_len) && glyph_len)
27921 {
27922 if (unicode == '\n') {
27923 /* new line separator so draw previous line */
27924 struct nk_rect label;
27925 label.y = pos_y + line_offset;
27926 label.h = row_height;
27927 label.w = line_width;
27928 label.x = pos_x;
27929 if (!line_count)
27930 label.x += x_offset;
27931
27932 if (is_selected) /* selection needs to draw different background color */
27933 nk_fill_rect(out, label, 0, background);
27934 nk_widget_text(out, label, line, (int)((text + text_len) - line),
27935 &txt, NK_TEXT_CENTERED, font);
27936
27937 text_len++;
27938 line_count++;
27939 line_width = 0;
27940 line = text + text_len;
27941 line_offset += row_height;
27942 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));
27943 continue;
27944 }
27945 if (unicode == '\r') {
27946 text_len++;
27947 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
27948 continue;
27949 }
27950 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
27951 line_width += (float)glyph_width;
27952 text_len += glyph_len;
27953 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
27954 continue;
27955 }
27956 if (line_width > 0) {
27957 /* draw last line */
27958 struct nk_rect label;
27959 label.y = pos_y + line_offset;
27960 label.h = row_height;
27961 label.w = line_width;
27962 label.x = pos_x;
27963 if (!line_count)
27964 label.x += x_offset;
27965
27966 if (is_selected)
27967 nk_fill_rect(out, label, 0, background);
27968 nk_widget_text(out, label, line, (int)((text + text_len) - line),
27969 &txt, NK_TEXT_LEFT, font);
27970 }}
27971}
27972NK_LIB nk_flags
27973nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
27974 struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,
27975 struct nk_text_edit *edit, const struct nk_style_edit *style,
27976 struct nk_input *in, const struct nk_user_font *font)
27977{
27978 struct nk_rect area;
27979 nk_flags ret = 0;
27980 float row_height;
27981 char prev_state = 0;
27982 char is_hovered = 0;
27983 char select_all = 0;
27984 char cursor_follow = 0;
27985 struct nk_rect old_clip;
27986 struct nk_rect clip;
27987
27988 NK_ASSERT(state);
27989 NK_ASSERT(out);
27990 NK_ASSERT(style);
27991 if (!state || !out || !style)
27992 return ret;
27993
27994 /* visible text area calculation */
27995 area.x = bounds.x + style->padding.x + style->border;
27996 area.y = bounds.y + style->padding.y + style->border;
27997 area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);
27998 area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);
27999 if (flags & NK_EDIT_MULTILINE)
28000 area.w = NK_MAX(0, area.w - style->scrollbar_size.x);
28001 row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;
28002
28003 /* calculate clipping rectangle */
28004 old_clip = out->clip;
28005 nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
28006
28007 /* update edit state */
28008 prev_state = (char)edit->active;
28009 if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {
28010 edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,
28011 bounds.x, bounds.y, bounds.w, bounds.h);
28012 }
28013
28014 /* (de)activate text editor */
28015 if (!prev_state && edit->active) {
28016 const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?
28017 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;
28018 /* keep scroll position when re-activating edit widget */
28019 struct nk_vec2 oldscrollbar = edit->scrollbar;
28020 nk_textedit_clear_state(edit, type, filter);
28021 edit->scrollbar = oldscrollbar;
28022 if (flags & NK_EDIT_AUTO_SELECT)
28023 select_all = nk_true;
28024 if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {
28025 edit->cursor = edit->string.len;
28026 in = 0;
28027 }
28028 } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;
28029 if (flags & NK_EDIT_READ_ONLY)
28030 edit->mode = NK_TEXT_EDIT_MODE_VIEW;
28031 else if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
28032 edit->mode = NK_TEXT_EDIT_MODE_INSERT;
28033
28034 ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;
28035 if (prev_state != edit->active)
28036 ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;
28037
28038 /* handle user input */
28039 if (edit->active && in)
28040 {
28041 int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;
28042 const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;
28043 const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;
28044
28045 /* mouse click handler */
28046 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);
28047 if (select_all) {
28048 nk_textedit_select_all(edit);
28049 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
28050 in->mouse.buttons[NK_BUTTON_LEFT].clicked) {
28051 nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);
28052 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
28053 (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) {
28054 nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);
28055 cursor_follow = nk_true;
28056 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&
28057 in->mouse.buttons[NK_BUTTON_RIGHT].down) {
28058 nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);
28059 nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);
28060 cursor_follow = nk_true;
28061 }
28062
28063 {int i; /* keyboard input */
28064 int old_mode = edit->mode;
28065 for (i = 0; i < NK_KEY_MAX; ++i) {
28066 if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */
28067 if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {
28068 nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);
28069 cursor_follow = nk_true;
28070 }
28071 }
28072 if (old_mode != edit->mode) {
28073 in->keyboard.text_len = 0;
28074 }}
28075
28076 /* text input */
28077 edit->filter = filter;
28078 if (in->keyboard.text_len) {
28079 nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);
28080 cursor_follow = nk_true;
28081 in->keyboard.text_len = 0;
28082 }
28083
28084 /* enter key handler */
28085 if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {
28086 cursor_follow = nk_true;
28087 if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)
28088 nk_textedit_text(edit, "\n", 1);
28089 else if (flags & NK_EDIT_SIG_ENTER)
28090 ret |= NK_EDIT_COMMITED;
28091 else nk_textedit_text(edit, "\n", 1);
28092 }
28093
28094 /* cut & copy handler */
28095 {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);
28096 int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);
28097 if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))
28098 {
28099 int glyph_len;
28100 nk_rune unicode;
28101 const char *text;
28102 int b = edit->select_start;
28103 int e = edit->select_end;
28104
28105 int begin = NK_MIN(b, e);
28106 int end = NK_MAX(b, e);
28107 text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);
28108 if (edit->clip.copy)
28109 edit->clip.copy(edit->clip.userdata, text, end - begin);
28110 if (cut && !(flags & NK_EDIT_READ_ONLY)){
28111 nk_textedit_cut(edit);
28112 cursor_follow = nk_true;
28113 }
28114 }}
28115
28116 /* paste handler */
28117 {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);
28118 if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {
28119 edit->clip.paste(edit->clip.userdata, edit);
28120 cursor_follow = nk_true;
28121 }}
28122
28123 /* tab handler */
28124 {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);
28125 if (tab && (flags & NK_EDIT_ALLOW_TAB)) {
28126 nk_textedit_text(edit, " ", 4);
28127 cursor_follow = nk_true;
28128 }}
28129 }
28130
28131 /* set widget state */
28132 if (edit->active)
28133 *state = NK_WIDGET_STATE_ACTIVE;
28134 else nk_widget_state_reset(state);
28135
28136 if (is_hovered)
28137 *state |= NK_WIDGET_STATE_HOVERED;
28138
28139 /* DRAW EDIT */
28140 {const char *text = nk_str_get_const(&edit->string);
28141 int len = nk_str_len_char(&edit->string);
28142
28143 {/* select background colors/images */
28144 const struct nk_style_item *background;
28145 if (*state & NK_WIDGET_STATE_ACTIVED)
28146 background = &style->active;
28147 else if (*state & NK_WIDGET_STATE_HOVER)
28148 background = &style->hover;
28149 else background = &style->normal;
28150
28151 /* draw background frame */
28152 switch(background->type) {
28153 case NK_STYLE_ITEM_IMAGE:
28154 nk_draw_image(out, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
28155 break;
28156 case NK_STYLE_ITEM_NINE_SLICE:
28157 nk_draw_nine_slice(out, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
28158 break;
28159 case NK_STYLE_ITEM_COLOR:
28160 nk_fill_rect(out, bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
28161 nk_stroke_rect(out, bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
28162 break;
28163 }}
28164
28165
28166 area.w = NK_MAX(0, area.w - style->cursor_size);
28167 if (edit->active)
28168 {
28169 int total_lines = 1;
28170 struct nk_vec2 text_size = nk_vec2(0,0);
28171
28172 /* text pointer positions */
28173 const char *cursor_ptr = 0;
28174 const char *select_begin_ptr = 0;
28175 const char *select_end_ptr = 0;
28176
28177 /* 2D pixel positions */
28178 struct nk_vec2 cursor_pos = nk_vec2(0,0);
28179 struct nk_vec2 selection_offset_start = nk_vec2(0,0);
28180 struct nk_vec2 selection_offset_end = nk_vec2(0,0);
28181
28182 int selection_begin = NK_MIN(edit->select_start, edit->select_end);
28183 int selection_end = NK_MAX(edit->select_start, edit->select_end);
28184
28185 /* calculate total line count + total space + cursor/selection position */
28186 float line_width = 0.0f;
28187 if (text && len)
28188 {
28189 /* utf8 encoding */
28190 float glyph_width;
28191 int glyph_len = 0;
28192 nk_rune unicode = 0;
28193 int text_len = 0;
28194 int glyphs = 0;
28195 int row_begin = 0;
28196
28197 glyph_len = nk_utf_decode(text, &unicode, len);
28198 glyph_width = font->width(font->userdata, font->height, text, glyph_len);
28199 line_width = 0;
28200
28201 /* iterate all lines */
28202 while ((text_len < len) && glyph_len)
28203 {
28204 /* set cursor 2D position and line */
28205 if (!cursor_ptr && glyphs == edit->cursor)
28206 {
28207 int glyph_offset;
28208 struct nk_vec2 out_offset;
28209 struct nk_vec2 row_size;
28210 const char *remaining;
28211
28212 /* calculate 2d position */
28213 cursor_pos.y = (float)(total_lines-1) * row_height;
28214 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
28215 text_len-row_begin, row_height, &remaining,
28216 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
28217 cursor_pos.x = row_size.x;
28218 cursor_ptr = text + text_len;
28219 }
28220
28221 /* set start selection 2D position and line */
28222 if (!select_begin_ptr && edit->select_start != edit->select_end &&
28223 glyphs == selection_begin)
28224 {
28225 int glyph_offset;
28226 struct nk_vec2 out_offset;
28227 struct nk_vec2 row_size;
28228 const char *remaining;
28229
28230 /* calculate 2d position */
28231 selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;
28232 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
28233 text_len-row_begin, row_height, &remaining,
28234 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
28235 selection_offset_start.x = row_size.x;
28236 select_begin_ptr = text + text_len;
28237 }
28238
28239 /* set end selection 2D position and line */
28240 if (!select_end_ptr && edit->select_start != edit->select_end &&
28241 glyphs == selection_end)
28242 {
28243 int glyph_offset;
28244 struct nk_vec2 out_offset;
28245 struct nk_vec2 row_size;
28246 const char *remaining;
28247
28248 /* calculate 2d position */
28249 selection_offset_end.y = (float)(total_lines-1) * row_height;
28250 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
28251 text_len-row_begin, row_height, &remaining,
28252 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
28253 selection_offset_end.x = row_size.x;
28254 select_end_ptr = text + text_len;
28255 }
28256 if (unicode == '\n') {
28257 text_size.x = NK_MAX(text_size.x, line_width);
28258 total_lines++;
28259 line_width = 0;
28260 text_len++;
28261 glyphs++;
28262 row_begin = text_len;
28263 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
28264 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
28265 continue;
28266 }
28267
28268 glyphs++;
28269 text_len += glyph_len;
28270 line_width += (float)glyph_width;
28271
28272 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
28273 glyph_width = font->width(font->userdata, font->height,
28274 text+text_len, glyph_len);
28275 continue;
28276 }
28277 text_size.y = (float)total_lines * row_height;
28278
28279 /* handle case when cursor is at end of text buffer */
28280 if (!cursor_ptr && edit->cursor == edit->string.len) {
28281 cursor_pos.x = line_width;
28282 cursor_pos.y = text_size.y - row_height;
28283 }
28284 }
28285 {
28286 /* scrollbar */
28287 if (cursor_follow)
28288 {
28289 /* update scrollbar to follow cursor */
28290 if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {
28291 /* horizontal scroll */
28292 const float scroll_increment = area.w * 0.25f;
28293 if (cursor_pos.x < edit->scrollbar.x)
28294 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);
28295 if (cursor_pos.x >= edit->scrollbar.x + area.w)
28296 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - area.w + scroll_increment);
28297 } else edit->scrollbar.x = 0;
28298
28299 if (flags & NK_EDIT_MULTILINE) {
28300 /* vertical scroll: like horizontal, it only adjusts if the
28301 * cursor leaves the visible area, and then only just enough
28302 * to keep it visible */
28303 if (cursor_pos.y < edit->scrollbar.y)
28304 edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y);
28305 if (cursor_pos.y > edit->scrollbar.y + area.h - row_height)
28306 edit->scrollbar.y = edit->scrollbar.y + row_height;
28307 } else edit->scrollbar.y = 0;
28308 }
28309
28310 /* scrollbar widget */
28311 if (flags & NK_EDIT_MULTILINE)
28312 {
28313 nk_flags ws;
28314 struct nk_rect scroll;
28315 float scroll_target;
28316 float scroll_offset;
28317 float scroll_step;
28318 float scroll_inc;
28319
28320 scroll = area;
28321 scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;
28322 scroll.w = style->scrollbar_size.x;
28323
28324 scroll_offset = edit->scrollbar.y;
28325 scroll_step = scroll.h * 0.10f;
28326 scroll_inc = scroll.h * 0.01f;
28327 scroll_target = text_size.y;
28328 edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, is_hovered,
28329 scroll_offset, scroll_target, scroll_step, scroll_inc,
28330 &style->scrollbar, in, font);
28331 /* Eat mouse scroll if we're active */
28332 if (is_hovered && in->mouse.scroll_delta.y) {
28333 in->mouse.scroll_delta.y = 0;
28334 }
28335 }
28336 }
28337
28338 /* draw text */
28339 {struct nk_color background_color;
28340 struct nk_color text_color;
28341 struct nk_color sel_background_color;
28342 struct nk_color sel_text_color;
28343 struct nk_color cursor_color;
28344 struct nk_color cursor_text_color;
28345 const struct nk_style_item *background;
28346 nk_push_scissor(out, clip);
28347
28348 /* select correct colors to draw */
28349 if (*state & NK_WIDGET_STATE_ACTIVED) {
28350 background = &style->active;
28351 text_color = style->text_active;
28352 sel_text_color = style->selected_text_hover;
28353 sel_background_color = style->selected_hover;
28354 cursor_color = style->cursor_hover;
28355 cursor_text_color = style->cursor_text_hover;
28356 } else if (*state & NK_WIDGET_STATE_HOVER) {
28357 background = &style->hover;
28358 text_color = style->text_hover;
28359 sel_text_color = style->selected_text_hover;
28360 sel_background_color = style->selected_hover;
28361 cursor_text_color = style->cursor_text_hover;
28362 cursor_color = style->cursor_hover;
28363 } else {
28364 background = &style->normal;
28365 text_color = style->text_normal;
28366 sel_text_color = style->selected_text_normal;
28367 sel_background_color = style->selected_normal;
28368 cursor_color = style->cursor_normal;
28369 cursor_text_color = style->cursor_text_normal;
28370 }
28371 if (background->type == NK_STYLE_ITEM_IMAGE)
28372 background_color = nk_rgba(0,0,0,0);
28373 else
28374 background_color = background->data.color;
28375
28376 cursor_color = nk_rgb_factor(cursor_color, style->color_factor);
28377 cursor_text_color = nk_rgb_factor(cursor_text_color, style->color_factor);
28378
28379 if (edit->select_start == edit->select_end) {
28380 /* no selection so just draw the complete text */
28381 const char *begin = nk_str_get_const(&edit->string);
28382 int l = nk_str_len_char(&edit->string);
28383 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
28384 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
28385 background_color, text_color, nk_false);
28386 } else {
28387 /* edit has selection so draw 1-3 text chunks */
28388 if (edit->select_start != edit->select_end && selection_begin > 0){
28389 /* draw unselected text before selection */
28390 const char *begin = nk_str_get_const(&edit->string);
28391 NK_ASSERT(select_begin_ptr);
28392 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
28393 area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),
28394 row_height, font, background_color, text_color, nk_false);
28395 }
28396 if (edit->select_start != edit->select_end) {
28397 /* draw selected text */
28398 NK_ASSERT(select_begin_ptr);
28399 if (!select_end_ptr) {
28400 const char *begin = nk_str_get_const(&edit->string);
28401 select_end_ptr = begin + nk_str_len_char(&edit->string);
28402 }
28403 nk_edit_draw_text(out, style,
28404 area.x - edit->scrollbar.x,
28405 area.y + selection_offset_start.y - edit->scrollbar.y,
28406 selection_offset_start.x,
28407 select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),
28408 row_height, font, sel_background_color, sel_text_color, nk_true);
28409 }
28410 if ((edit->select_start != edit->select_end &&
28411 selection_end < edit->string.len))
28412 {
28413 /* draw unselected text after selected text */
28414 const char *begin = select_end_ptr;
28415 const char *end = nk_str_get_const(&edit->string) +
28416 nk_str_len_char(&edit->string);
28417 NK_ASSERT(select_end_ptr);
28418 nk_edit_draw_text(out, style,
28419 area.x - edit->scrollbar.x,
28420 area.y + selection_offset_end.y - edit->scrollbar.y,
28421 selection_offset_end.x,
28422 begin, (int)(end - begin), row_height, font,
28423 background_color, text_color, nk_true);
28424 }
28425 }
28426
28427 /* cursor */
28428 if (edit->select_start == edit->select_end)
28429 {
28430 if (edit->cursor >= nk_str_len(&edit->string) ||
28431 (cursor_ptr && *cursor_ptr == '\n')) {
28432 /* draw cursor at end of line */
28433 struct nk_rect cursor;
28434 cursor.w = style->cursor_size;
28435 cursor.h = font->height;
28436 cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;
28437 cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;
28438 cursor.y -= edit->scrollbar.y;
28439 nk_fill_rect(out, cursor, 0, cursor_color);
28440 } else {
28441 /* draw cursor inside text */
28442 int glyph_len;
28443 struct nk_rect label;
28444 struct nk_text txt;
28445
28446 nk_rune unicode;
28447 NK_ASSERT(cursor_ptr);
28448 glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);
28449
28450 label.x = area.x + cursor_pos.x - edit->scrollbar.x;
28451 label.y = area.y + cursor_pos.y - edit->scrollbar.y;
28452 label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);
28453 label.h = row_height;
28454
28455 txt.padding = nk_vec2(0,0);
28456 txt.background = cursor_color;;
28457 txt.text = cursor_text_color;
28458 nk_fill_rect(out, label, 0, cursor_color);
28459 nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);
28460 }
28461 }}
28462 } else {
28463 /* not active so just draw text */
28464 int l = nk_str_len_char(&edit->string);
28465 const char *begin = nk_str_get_const(&edit->string);
28466
28467 const struct nk_style_item *background;
28468 struct nk_color background_color;
28469 struct nk_color text_color;
28470 nk_push_scissor(out, clip);
28471 if (*state & NK_WIDGET_STATE_ACTIVED) {
28472 background = &style->active;
28473 text_color = style->text_active;
28474 } else if (*state & NK_WIDGET_STATE_HOVER) {
28475 background = &style->hover;
28476 text_color = style->text_hover;
28477 } else {
28478 background = &style->normal;
28479 text_color = style->text_normal;
28480 }
28481 if (background->type == NK_STYLE_ITEM_IMAGE)
28482 background_color = nk_rgba(0,0,0,0);
28483 else
28484 background_color = background->data.color;
28485
28486 background_color = nk_rgb_factor(background_color, style->color_factor);
28487 text_color = nk_rgb_factor(text_color, style->color_factor);
28488
28489 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
28490 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
28491 background_color, text_color, nk_false);
28492 }
28493 nk_push_scissor(out, old_clip);}
28494 return ret;
28495}
28496NK_API void
28497nk_edit_focus(struct nk_context *ctx, nk_flags flags)
28498{
28499 nk_hash hash;
28500 struct nk_window *win;
28501
28502 NK_ASSERT(ctx);
28503 NK_ASSERT(ctx->current);
28504 if (!ctx || !ctx->current) return;
28505
28506 win = ctx->current;
28507 hash = win->edit.seq;
28508 win->edit.active = nk_true;
28509 win->edit.name = hash;
28510 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
28511 win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;
28512}
28513NK_API void
28514nk_edit_unfocus(struct nk_context *ctx)
28515{
28516 struct nk_window *win;
28517 NK_ASSERT(ctx);
28518 NK_ASSERT(ctx->current);
28519 if (!ctx || !ctx->current) return;
28520
28521 win = ctx->current;
28522 win->edit.active = nk_false;
28523 win->edit.name = 0;
28524}
28525NK_API nk_flags
28526nk_edit_string(struct nk_context *ctx, nk_flags flags,
28527 char *memory, int *len, int max, nk_plugin_filter filter)
28528{
28529 nk_hash hash;
28530 nk_flags state;
28531 struct nk_text_edit *edit;
28532 struct nk_window *win;
28533
28534 NK_ASSERT(ctx);
28535 NK_ASSERT(memory);
28536 NK_ASSERT(len);
28537 if (!ctx || !memory || !len)
28538 return 0;
28539
28540 filter = (!filter) ? nk_filter_default: filter;
28541 win = ctx->current;
28542 hash = win->edit.seq;
28543 edit = &ctx->text_edit;
28544 nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?
28545 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);
28546
28547 if (win->edit.active && hash == win->edit.name) {
28548 if (flags & NK_EDIT_NO_CURSOR)
28549 edit->cursor = nk_utf_len(memory, *len);
28550 else edit->cursor = win->edit.cursor;
28551 if (!(flags & NK_EDIT_SELECTABLE)) {
28552 edit->select_start = win->edit.cursor;
28553 edit->select_end = win->edit.cursor;
28554 } else {
28555 edit->select_start = win->edit.sel_start;
28556 edit->select_end = win->edit.sel_end;
28557 }
28558 edit->mode = win->edit.mode;
28559 edit->scrollbar.x = (float)win->edit.scrollbar.x;
28560 edit->scrollbar.y = (float)win->edit.scrollbar.y;
28561 edit->active = nk_true;
28562 } else edit->active = nk_false;
28563
28564 max = NK_MAX(1, max);
28565 *len = NK_MIN(*len, max-1);
28566 nk_str_init_fixed(&edit->string, memory, (nk_size)max);
28567 edit->string.buffer.allocated = (nk_size)*len;
28568 edit->string.len = nk_utf_len(memory, *len);
28569 state = nk_edit_buffer(ctx, flags, edit, filter);
28570 *len = (int)edit->string.buffer.allocated;
28571
28572 if (edit->active) {
28573 win->edit.cursor = edit->cursor;
28574 win->edit.sel_start = edit->select_start;
28575 win->edit.sel_end = edit->select_end;
28576 win->edit.mode = edit->mode;
28577 win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;
28578 win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;
28579 } return state;
28580}
28581NK_API nk_flags
28582nk_edit_buffer(struct nk_context *ctx, nk_flags flags,
28583 struct nk_text_edit *edit, nk_plugin_filter filter)
28584{
28585 struct nk_window *win;
28586 struct nk_style *style;
28587 struct nk_input *in;
28588
28589 enum nk_widget_layout_states state;
28590 struct nk_rect bounds;
28591
28592 nk_flags ret_flags = 0;
28593 unsigned char prev_state;
28594 nk_hash hash;
28595
28596 /* make sure correct values */
28597 NK_ASSERT(ctx);
28598 NK_ASSERT(edit);
28599 NK_ASSERT(ctx->current);
28600 NK_ASSERT(ctx->current->layout);
28601 if (!ctx || !ctx->current || !ctx->current->layout)
28602 return 0;
28603
28604 win = ctx->current;
28605 style = &ctx->style;
28606 state = nk_widget(&bounds, ctx);
28607 if (!state) return state;
28608 else if (state == NK_WIDGET_DISABLED)
28609 flags |= NK_EDIT_READ_ONLY;
28610 in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
28611
28612 /* check if edit is currently hot item */
28613 hash = win->edit.seq++;
28614 if (win->edit.active && hash == win->edit.name) {
28615 if (flags & NK_EDIT_NO_CURSOR)
28616 edit->cursor = edit->string.len;
28617 if (!(flags & NK_EDIT_SELECTABLE)) {
28618 edit->select_start = edit->cursor;
28619 edit->select_end = edit->cursor;
28620 }
28621 if (flags & NK_EDIT_CLIPBOARD)
28622 edit->clip = ctx->clip;
28623 edit->active = (unsigned char)win->edit.active;
28624 } else edit->active = nk_false;
28625 edit->mode = win->edit.mode;
28626
28627 filter = (!filter) ? nk_filter_default: filter;
28628 prev_state = (unsigned char)edit->active;
28629 in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
28630 ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,
28631 filter, edit, &style->edit, in, style->font);
28632
28633 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
28634 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
28635 if (edit->active && prev_state != edit->active) {
28636 /* current edit is now hot */
28637 win->edit.active = nk_true;
28638 win->edit.name = hash;
28639 } else if (prev_state && !edit->active) {
28640 /* current edit is now cold */
28641 win->edit.active = nk_false;
28642 } return ret_flags;
28643}
28644NK_API nk_flags
28645nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,
28646 char *buffer, int max, nk_plugin_filter filter)
28647{
28648 nk_flags result;
28649 int len = nk_strlen(buffer);
28650 result = nk_edit_string(ctx, flags, buffer, &len, max, filter);
28651 buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0';
28652 return result;
28653}
28654
28655
28656
28657
28658
28659/* ===============================================================
28660 *
28661 * PROPERTY
28662 *
28663 * ===============================================================*/
28664NK_LIB void
28665nk_drag_behavior(nk_flags *state, const struct nk_input *in,
28666 struct nk_rect drag, struct nk_property_variant *variant,
28667 float inc_per_pixel)
28668{
28669 int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
28670 int left_mouse_click_in_cursor = in &&
28671 nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);
28672
28673 nk_widget_state_reset(state);
28674 if (nk_input_is_mouse_hovering_rect(in, drag))
28675 *state = NK_WIDGET_STATE_HOVERED;
28676
28677 if (left_mouse_down && left_mouse_click_in_cursor) {
28678 float delta, pixels;
28679 pixels = in->mouse.delta.x;
28680 delta = pixels * inc_per_pixel;
28681 switch (variant->kind) {
28682 default: break;
28683 case NK_PROPERTY_INT:
28684 variant->value.i = variant->value.i + (int)delta;
28685 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
28686 break;
28687 case NK_PROPERTY_FLOAT:
28688 variant->value.f = variant->value.f + (float)delta;
28689 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
28690 break;
28691 case NK_PROPERTY_DOUBLE:
28692 variant->value.d = variant->value.d + (double)delta;
28693 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
28694 break;
28695 }
28696 *state = NK_WIDGET_STATE_ACTIVE;
28697 }
28698 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))
28699 *state |= NK_WIDGET_STATE_ENTERED;
28700 else if (nk_input_is_mouse_prev_hovering_rect(in, drag))
28701 *state |= NK_WIDGET_STATE_LEFT;
28702}
28703NK_LIB void
28704nk_property_behavior(nk_flags *ws, const struct nk_input *in,
28705 struct nk_rect property, struct nk_rect label, struct nk_rect edit,
28706 struct nk_rect empty, int *state, struct nk_property_variant *variant,
28707 float inc_per_pixel)
28708{
28709 nk_widget_state_reset(ws);
28710 if (in && *state == NK_PROPERTY_DEFAULT) {
28711 if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))
28712 *state = NK_PROPERTY_EDIT;
28713 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))
28714 *state = NK_PROPERTY_DRAG;
28715 else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))
28716 *state = NK_PROPERTY_DRAG;
28717 }
28718 if (*state == NK_PROPERTY_DRAG) {
28719 nk_drag_behavior(ws, in, property, variant, inc_per_pixel);
28720 if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;
28721 }
28722}
28723NK_LIB void
28724nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,
28725 const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,
28726 const char *name, int len, const struct nk_user_font *font)
28727{
28728 struct nk_text text;
28729 const struct nk_style_item *background;
28730
28731 /* select correct background and text color */
28732 if (state & NK_WIDGET_STATE_ACTIVED) {
28733 background = &style->active;
28734 text.text = style->label_active;
28735 } else if (state & NK_WIDGET_STATE_HOVER) {
28736 background = &style->hover;
28737 text.text = style->label_hover;
28738 } else {
28739 background = &style->normal;
28740 text.text = style->label_normal;
28741 }
28742
28743 text.text = nk_rgb_factor(text.text, style->color_factor);
28744
28745 /* draw background */
28746 switch(background->type) {
28747 case NK_STYLE_ITEM_IMAGE:
28748 text.background = nk_rgba(0, 0, 0, 0);
28749 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
28750 break;
28751 case NK_STYLE_ITEM_NINE_SLICE:
28752 text.background = nk_rgba(0, 0, 0, 0);
28753 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
28754 break;
28755 case NK_STYLE_ITEM_COLOR:
28756 text.background = background->data.color;
28757 nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
28758 nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
28759 break;
28760 }
28761
28762 /* draw label */
28763 text.padding = nk_vec2(0,0);
28764 if (name && name[0] != '#') {
28765 nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
28766 }
28767}
28768NK_LIB void
28769nk_do_property(nk_flags *ws,
28770 struct nk_command_buffer *out, struct nk_rect property,
28771 const char *name, struct nk_property_variant *variant,
28772 float inc_per_pixel, char *buffer, int *len,
28773 int *state, int *cursor, int *select_begin, int *select_end,
28774 const struct nk_style_property *style,
28775 enum nk_property_filter filter, struct nk_input *in,
28776 const struct nk_user_font *font, struct nk_text_edit *text_edit,
28777 enum nk_button_behavior behavior)
28778{
28779 const nk_plugin_filter filters[] = {
28780 nk_filter_decimal,
28781 nk_filter_float
28782 };
28783 nk_bool active, old;
28784 int num_len = 0, name_len = 0;
28785 char string[NK_MAX_NUMBER_BUFFER];
28786 float size;
28787
28788 char *dst = 0;
28789 int *length;
28790
28791 struct nk_rect left;
28792 struct nk_rect right;
28793 struct nk_rect label;
28794 struct nk_rect edit;
28795 struct nk_rect empty;
28796
28797 /* left decrement button */
28798 left.h = font->height/2;
28799 left.w = left.h;
28800 left.x = property.x + style->border + style->padding.x;
28801 left.y = property.y + style->border + property.h/2.0f - left.h/2;
28802
28803 /* text label */
28804 if (name && name[0] != '#') {
28805 name_len = nk_strlen(name);
28806 }
28807 size = font->width(font->userdata, font->height, name, name_len);
28808 label.x = left.x + left.w + style->padding.x;
28809 label.w = (float)size + 2 * style->padding.x;
28810 label.y = property.y + style->border + style->padding.y;
28811 label.h = property.h - (2 * style->border + 2 * style->padding.y);
28812
28813 /* right increment button */
28814 right.y = left.y;
28815 right.w = left.w;
28816 right.h = left.h;
28817 right.x = property.x + property.w - (right.w + style->padding.x);
28818
28819 /* edit */
28820 if (*state == NK_PROPERTY_EDIT) {
28821 size = font->width(font->userdata, font->height, buffer, *len);
28822 size += style->edit.cursor_size;
28823 length = len;
28824 dst = buffer;
28825 } else {
28826 switch (variant->kind) {
28827 default: break;
28828 case NK_PROPERTY_INT:
28829 nk_itoa(string, variant->value.i);
28830 num_len = nk_strlen(string);
28831 break;
28832 case NK_PROPERTY_FLOAT:
28833 NK_DTOA(string, (double)variant->value.f);
28834 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
28835 break;
28836 case NK_PROPERTY_DOUBLE:
28837 NK_DTOA(string, variant->value.d);
28838 num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
28839 break;
28840 }
28841 size = font->width(font->userdata, font->height, string, num_len);
28842 dst = string;
28843 length = &num_len;
28844 }
28845
28846 edit.w = (float)size + 2 * style->padding.x;
28847 edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));
28848 edit.x = right.x - (edit.w + style->padding.x);
28849 edit.y = property.y + style->border;
28850 edit.h = property.h - (2 * style->border);
28851
28852 /* empty left space activator */
28853 empty.w = edit.x - (label.x + label.w);
28854 empty.x = label.x + label.w;
28855 empty.y = property.y;
28856 empty.h = property.h;
28857
28858 /* update property */
28859 old = (*state == NK_PROPERTY_EDIT);
28860 nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);
28861
28862 /* draw property */
28863 if (style->draw_begin) style->draw_begin(out, style->userdata);
28864 nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);
28865 if (style->draw_end) style->draw_end(out, style->userdata);
28866
28867 /* execute right button */
28868 if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {
28869 switch (variant->kind) {
28870 default: break;
28871 case NK_PROPERTY_INT:
28872 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;
28873 case NK_PROPERTY_FLOAT:
28874 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;
28875 case NK_PROPERTY_DOUBLE:
28876 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;
28877 }
28878 }
28879 /* execute left button */
28880 if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {
28881 switch (variant->kind) {
28882 default: break;
28883 case NK_PROPERTY_INT:
28884 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;
28885 case NK_PROPERTY_FLOAT:
28886 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;
28887 case NK_PROPERTY_DOUBLE:
28888 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;
28889 }
28890 }
28891 if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) {
28892 /* property has been activated so setup buffer */
28893 NK_MEMCPY(buffer, dst, (nk_size)*length);
28894 *cursor = nk_utf_len(buffer, *length);
28895 *len = *length;
28896 length = len;
28897 dst = buffer;
28898 active = 0;
28899 } else active = (*state == NK_PROPERTY_EDIT);
28900
28901 /* execute and run text edit field */
28902 nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);
28903 text_edit->active = (unsigned char)active;
28904 text_edit->string.len = *length;
28905 text_edit->cursor = NK_CLAMP(0, *cursor, *length);
28906 text_edit->select_start = NK_CLAMP(0,*select_begin, *length);
28907 text_edit->select_end = NK_CLAMP(0,*select_end, *length);
28908 text_edit->string.buffer.allocated = (nk_size)*length;
28909 text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;
28910 text_edit->string.buffer.memory.ptr = dst;
28911 text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;
28912 text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;
28913 nk_do_edit(ws, out, edit, (int)NK_EDIT_FIELD|(int)NK_EDIT_AUTO_SELECT,
28914 filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);
28915
28916 *length = text_edit->string.len;
28917 *cursor = text_edit->cursor;
28918 *select_begin = text_edit->select_start;
28919 *select_end = text_edit->select_end;
28920 if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))
28921 text_edit->active = nk_false;
28922
28923 if (active && !text_edit->active) {
28924 /* property is now not active so convert edit text to value*/
28925 *state = NK_PROPERTY_DEFAULT;
28926 buffer[*len] = '\0';
28927 switch (variant->kind) {
28928 default: break;
28929 case NK_PROPERTY_INT:
28930 variant->value.i = nk_strtoi(buffer, 0);
28931 variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
28932 break;
28933 case NK_PROPERTY_FLOAT:
28934 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
28935 variant->value.f = nk_strtof(buffer, 0);
28936 variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
28937 break;
28938 case NK_PROPERTY_DOUBLE:
28939 nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
28940 variant->value.d = nk_strtod(buffer, 0);
28941 variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
28942 break;
28943 }
28944 }
28945}
28946NK_LIB struct nk_property_variant
28947nk_property_variant_int(int value, int min_value, int max_value, int step)
28948{
28949 struct nk_property_variant result;
28950 result.kind = NK_PROPERTY_INT;
28951 result.value.i = value;
28952 result.min_value.i = min_value;
28953 result.max_value.i = max_value;
28954 result.step.i = step;
28955 return result;
28956}
28957NK_LIB struct nk_property_variant
28958nk_property_variant_float(float value, float min_value, float max_value, float step)
28959{
28960 struct nk_property_variant result;
28961 result.kind = NK_PROPERTY_FLOAT;
28962 result.value.f = value;
28963 result.min_value.f = min_value;
28964 result.max_value.f = max_value;
28965 result.step.f = step;
28966 return result;
28967}
28968NK_LIB struct nk_property_variant
28969nk_property_variant_double(double value, double min_value, double max_value,
28970 double step)
28971{
28972 struct nk_property_variant result;
28973 result.kind = NK_PROPERTY_DOUBLE;
28974 result.value.d = value;
28975 result.min_value.d = min_value;
28976 result.max_value.d = max_value;
28977 result.step.d = step;
28978 return result;
28979}
28980NK_LIB void
28981nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,
28982 float inc_per_pixel, const enum nk_property_filter filter)
28983{
28984 struct nk_window *win;
28985 struct nk_panel *layout;
28986 struct nk_input *in;
28987 const struct nk_style *style;
28988
28989 struct nk_rect bounds;
28991
28992 int *state = 0;
28993 nk_hash hash = 0;
28994 char *buffer = 0;
28995 int *len = 0;
28996 int *cursor = 0;
28997 int *select_begin = 0;
28998 int *select_end = 0;
28999 int old_state;
29000
29001 char dummy_buffer[NK_MAX_NUMBER_BUFFER];
29002 int dummy_state = NK_PROPERTY_DEFAULT;
29003 int dummy_length = 0;
29004 int dummy_cursor = 0;
29005 int dummy_select_begin = 0;
29006 int dummy_select_end = 0;
29007
29008 NK_ASSERT(ctx);
29009 NK_ASSERT(ctx->current);
29010 NK_ASSERT(ctx->current->layout);
29011 if (!ctx || !ctx->current || !ctx->current->layout)
29012 return;
29013
29014 win = ctx->current;
29015 layout = win->layout;
29016 style = &ctx->style;
29017 s = nk_widget(&bounds, ctx);
29018 if (!s) return;
29019
29020 /* calculate hash from name */
29021 if (name[0] == '#') {
29022 hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);
29023 name++; /* special number hash */
29024 } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);
29025
29026 /* check if property is currently hot item */
29027 if (win->property.active && hash == win->property.name) {
29028 buffer = win->property.buffer;
29029 len = &win->property.length;
29030 cursor = &win->property.cursor;
29031 state = &win->property.state;
29032 select_begin = &win->property.select_start;
29033 select_end = &win->property.select_end;
29034 } else {
29035 buffer = dummy_buffer;
29036 len = &dummy_length;
29037 cursor = &dummy_cursor;
29038 state = &dummy_state;
29039 select_begin = &dummy_select_begin;
29040 select_end = &dummy_select_end;
29041 }
29042
29043 /* execute property widget */
29044 old_state = *state;
29045 ctx->text_edit.clip = ctx->clip;
29046 in = ((s == NK_WIDGET_ROM && !win->property.active) ||
29047 layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED) ? 0 : &ctx->input;
29048 nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,
29049 variant, inc_per_pixel, buffer, len, state, cursor, select_begin,
29050 select_end, &style->property, filter, in, style->font, &ctx->text_edit,
29051 ctx->button_behavior);
29052
29053 if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) {
29054 /* current property is now hot */
29055 win->property.active = 1;
29056 NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);
29057 win->property.length = *len;
29058 win->property.cursor = *cursor;
29059 win->property.state = *state;
29060 win->property.name = hash;
29061 win->property.select_start = *select_begin;
29062 win->property.select_end = *select_end;
29063 if (*state == NK_PROPERTY_DRAG) {
29064 ctx->input.mouse.grab = nk_true;
29065 ctx->input.mouse.grabbed = nk_true;
29066 }
29067 }
29068 /* check if previously active property is now inactive */
29069 if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {
29070 if (old_state == NK_PROPERTY_DRAG) {
29071 ctx->input.mouse.grab = nk_false;
29072 ctx->input.mouse.grabbed = nk_false;
29073 ctx->input.mouse.ungrab = nk_true;
29074 }
29075 win->property.select_start = 0;
29076 win->property.select_end = 0;
29077 win->property.active = 0;
29078 }
29079}
29080NK_API void
29081nk_property_int(struct nk_context *ctx, const char *name,
29082 int min, int *val, int max, int step, float inc_per_pixel)
29083{
29084 struct nk_property_variant variant;
29085 NK_ASSERT(ctx);
29086 NK_ASSERT(name);
29087 NK_ASSERT(val);
29088
29089 if (!ctx || !ctx->current || !name || !val) return;
29090 variant = nk_property_variant_int(*val, min, max, step);
29091 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
29092 *val = variant.value.i;
29093}
29094NK_API void
29095nk_property_float(struct nk_context *ctx, const char *name,
29096 float min, float *val, float max, float step, float inc_per_pixel)
29097{
29098 struct nk_property_variant variant;
29099 NK_ASSERT(ctx);
29100 NK_ASSERT(name);
29101 NK_ASSERT(val);
29102
29103 if (!ctx || !ctx->current || !name || !val) return;
29104 variant = nk_property_variant_float(*val, min, max, step);
29105 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
29106 *val = variant.value.f;
29107}
29108NK_API void
29109nk_property_double(struct nk_context *ctx, const char *name,
29110 double min, double *val, double max, double step, float inc_per_pixel)
29111{
29112 struct nk_property_variant variant;
29113 NK_ASSERT(ctx);
29114 NK_ASSERT(name);
29115 NK_ASSERT(val);
29116
29117 if (!ctx || !ctx->current || !name || !val) return;
29118 variant = nk_property_variant_double(*val, min, max, step);
29119 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
29120 *val = variant.value.d;
29121}
29122NK_API int
29123nk_propertyi(struct nk_context *ctx, const char *name, int min, int val,
29124 int max, int step, float inc_per_pixel)
29125{
29126 struct nk_property_variant variant;
29127 NK_ASSERT(ctx);
29128 NK_ASSERT(name);
29129
29130 if (!ctx || !ctx->current || !name) return val;
29131 variant = nk_property_variant_int(val, min, max, step);
29132 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
29133 val = variant.value.i;
29134 return val;
29135}
29136NK_API float
29137nk_propertyf(struct nk_context *ctx, const char *name, float min,
29138 float val, float max, float step, float inc_per_pixel)
29139{
29140 struct nk_property_variant variant;
29141 NK_ASSERT(ctx);
29142 NK_ASSERT(name);
29143
29144 if (!ctx || !ctx->current || !name) return val;
29145 variant = nk_property_variant_float(val, min, max, step);
29146 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
29147 val = variant.value.f;
29148 return val;
29149}
29150NK_API double
29151nk_propertyd(struct nk_context *ctx, const char *name, double min,
29152 double val, double max, double step, float inc_per_pixel)
29153{
29154 struct nk_property_variant variant;
29155 NK_ASSERT(ctx);
29156 NK_ASSERT(name);
29157
29158 if (!ctx || !ctx->current || !name) return val;
29159 variant = nk_property_variant_double(val, min, max, step);
29160 nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
29161 val = variant.value.d;
29162 return val;
29163}
29164
29165
29166
29167
29168
29169/* ==============================================================
29170 *
29171 * CHART
29172 *
29173 * ===============================================================*/
29174NK_API nk_bool
29175nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
29176 struct nk_color color, struct nk_color highlight,
29177 int count, float min_value, float max_value)
29178{
29179 struct nk_window *win;
29180 struct nk_chart *chart;
29181 const struct nk_style *config;
29182 const struct nk_style_chart *style;
29183
29184 const struct nk_style_item *background;
29185 struct nk_rect bounds = {0, 0, 0, 0};
29186
29187 NK_ASSERT(ctx);
29188 NK_ASSERT(ctx->current);
29189 NK_ASSERT(ctx->current->layout);
29190
29191 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
29192 if (!nk_widget(&bounds, ctx)) {
29193 chart = &ctx->current->layout->chart;
29194 nk_zero(chart, sizeof(*chart));
29195 return 0;
29196 }
29197
29198 win = ctx->current;
29199 config = &ctx->style;
29200 chart = &win->layout->chart;
29201 style = &config->chart;
29202
29203 /* setup basic generic chart */
29204 nk_zero(chart, sizeof(*chart));
29205 chart->x = bounds.x + style->padding.x;
29206 chart->y = bounds.y + style->padding.y;
29207 chart->w = bounds.w - 2 * style->padding.x;
29208 chart->h = bounds.h - 2 * style->padding.y;
29209 chart->w = NK_MAX(chart->w, 2 * style->padding.x);
29210 chart->h = NK_MAX(chart->h, 2 * style->padding.y);
29211
29212 /* add first slot into chart */
29213 {struct nk_chart_slot *slot = &chart->slots[chart->slot++];
29214 slot->type = type;
29215 slot->count = count;
29216 slot->color = nk_rgb_factor(color, style->color_factor);
29217 slot->highlight = highlight;
29218 slot->min = NK_MIN(min_value, max_value);
29219 slot->max = NK_MAX(min_value, max_value);
29220 slot->range = slot->max - slot->min;
29221 slot->show_markers = style->show_markers;}
29222
29223 /* draw chart background */
29224 background = &style->background;
29225
29226 switch(background->type) {
29227 case NK_STYLE_ITEM_IMAGE:
29228 nk_draw_image(&win->buffer, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
29229 break;
29230 case NK_STYLE_ITEM_NINE_SLICE:
29231 nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
29232 break;
29233 case NK_STYLE_ITEM_COLOR:
29234 nk_fill_rect(&win->buffer, bounds, style->rounding, nk_rgb_factor(style->border_color, style->color_factor));
29235 nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
29236 style->rounding, nk_rgb_factor(style->background.data.color, style->color_factor));
29237 break;
29238 }
29239 return 1;
29240}
29241NK_API nk_bool
29242nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
29243 int count, float min_value, float max_value)
29244{
29245 return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,
29246 ctx->style.chart.selected_color, count, min_value, max_value);
29247}
29248NK_API void
29249nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
29250 struct nk_color color, struct nk_color highlight,
29251 int count, float min_value, float max_value)
29252{
29253 const struct nk_style_chart* style;
29254
29255 NK_ASSERT(ctx);
29256 NK_ASSERT(ctx->current);
29257 NK_ASSERT(ctx->current->layout);
29258 NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
29259 if (!ctx || !ctx->current || !ctx->current->layout) return;
29260 if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
29261
29262 style = &ctx->style.chart;
29263
29264 /* add another slot into the graph */
29265 {struct nk_chart *chart = &ctx->current->layout->chart;
29266 struct nk_chart_slot *slot = &chart->slots[chart->slot++];
29267 slot->type = type;
29268 slot->count = count;
29269 slot->color = nk_rgb_factor(color, style->color_factor);
29270 slot->highlight = highlight;
29271 slot->min = NK_MIN(min_value, max_value);
29272 slot->max = NK_MAX(min_value, max_value);
29273 slot->range = slot->max - slot->min;
29274 slot->show_markers = style->show_markers;}
29275}
29276NK_API void
29277nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
29278 int count, float min_value, float max_value)
29279{
29280 nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,
29281 ctx->style.chart.selected_color, count, min_value, max_value);
29282}
29283NK_INTERN nk_flags
29284nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
29285 struct nk_chart *g, float value, int slot)
29286{
29287 struct nk_panel *layout = win->layout;
29288 const struct nk_input *i = ctx->current->widgets_disabled ? 0 : &ctx->input;
29289 struct nk_command_buffer *out = &win->buffer;
29290
29291 nk_flags ret = 0;
29292 struct nk_vec2 cur;
29293 struct nk_rect bounds;
29294 struct nk_color color;
29295 float step;
29296 float range;
29297 float ratio;
29298
29299 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
29300 step = g->w / (float)g->slots[slot].count;
29301 range = g->slots[slot].max - g->slots[slot].min;
29302 ratio = (value - g->slots[slot].min) / range;
29303
29304 if (g->slots[slot].index == 0) {
29305 /* first data point does not have a connection */
29306 g->slots[slot].last.x = g->x;
29307 g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
29308
29309 bounds.x = g->slots[slot].last.x - 2;
29310 bounds.y = g->slots[slot].last.y - 2;
29311 bounds.w = bounds.h = 4;
29312
29313 color = g->slots[slot].color;
29314 if (!(layout->flags & NK_WINDOW_ROM) && i &&
29315 NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
29316 ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
29317 ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
29318 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
29319 color = g->slots[slot].highlight;
29320 }
29321 if (g->slots[slot].show_markers) {
29322 nk_fill_rect(out, bounds, 0, color);
29323 }
29324 g->slots[slot].index += 1;
29325 return ret;
29326 }
29327
29328 /* draw a line between the last data point and the new one */
29329 color = g->slots[slot].color;
29330 cur.x = g->x + (float)(step * (float)g->slots[slot].index);
29331 cur.y = (g->y + g->h) - (ratio * (float)g->h);
29332 nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
29333
29334 bounds.x = cur.x - 3;
29335 bounds.y = cur.y - 3;
29336 bounds.w = bounds.h = 6;
29337
29338 /* user selection of current data point */
29339 if (!(layout->flags & NK_WINDOW_ROM)) {
29340 if (nk_input_is_mouse_hovering_rect(i, bounds)) {
29341 ret = NK_CHART_HOVERING;
29342 ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
29343 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
29344 color = g->slots[slot].highlight;
29345 }
29346 }
29347 if (g->slots[slot].show_markers) {
29348 nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
29349 }
29350
29351 /* save current data point position */
29352 g->slots[slot].last.x = cur.x;
29353 g->slots[slot].last.y = cur.y;
29354 g->slots[slot].index += 1;
29355 return ret;
29356}
29357NK_INTERN nk_flags
29358nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
29359 struct nk_chart *chart, float value, int slot)
29360{
29361 struct nk_command_buffer *out = &win->buffer;
29362 const struct nk_input *in = ctx->current->widgets_disabled ? 0 : &ctx->input;
29363 struct nk_panel *layout = win->layout;
29364
29365 float ratio;
29366 nk_flags ret = 0;
29367 struct nk_color color;
29368 struct nk_rect item = {0,0,0,0};
29369
29370 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
29371 if (chart->slots[slot].index >= chart->slots[slot].count)
29372 return nk_false;
29373 if (chart->slots[slot].count) {
29374 float padding = (float)(chart->slots[slot].count-1);
29375 item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
29376 }
29377
29378 /* calculate bounds of current bar chart entry */
29379 color = chart->slots[slot].color;;
29380 item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
29381 if (value >= 0) {
29382 ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
29383 item.y = (chart->y + chart->h) - chart->h * ratio;
29384 } else {
29385 ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
29386 item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
29387 }
29388 item.x = chart->x + ((float)chart->slots[slot].index * item.w);
29389 item.x = item.x + ((float)chart->slots[slot].index);
29390
29391 /* user chart bar selection */
29392 if (!(layout->flags & NK_WINDOW_ROM) && in &&
29393 NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
29394 ret = NK_CHART_HOVERING;
29395 ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
29396 in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
29397 color = chart->slots[slot].highlight;
29398 }
29399 nk_fill_rect(out, item, 0, color);
29400 chart->slots[slot].index += 1;
29401 return ret;
29402}
29403NK_API nk_flags
29404nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
29405{
29406 nk_flags flags;
29407 struct nk_window *win;
29408
29409 NK_ASSERT(ctx);
29410 NK_ASSERT(ctx->current);
29411 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
29412 NK_ASSERT(slot < ctx->current->layout->chart.slot);
29413 if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
29414 if (slot >= ctx->current->layout->chart.slot) return nk_false;
29415
29416 win = ctx->current;
29417 if (win->layout->chart.slot < slot) return nk_false;
29418 switch (win->layout->chart.slots[slot].type) {
29419 case NK_CHART_LINES:
29420 flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
29421 case NK_CHART_COLUMN:
29422 flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
29423 default:
29424 case NK_CHART_MAX:
29425 flags = 0;
29426 }
29427 return flags;
29428}
29429NK_API nk_flags
29430nk_chart_push(struct nk_context *ctx, float value)
29431{
29432 return nk_chart_push_slot(ctx, value, 0);
29433}
29434NK_API void
29435nk_chart_end(struct nk_context *ctx)
29436{
29437 struct nk_window *win;
29438 struct nk_chart *chart;
29439
29440 NK_ASSERT(ctx);
29441 NK_ASSERT(ctx->current);
29442 if (!ctx || !ctx->current)
29443 return;
29444
29445 win = ctx->current;
29446 chart = &win->layout->chart;
29447 NK_MEMSET(chart, 0, sizeof(*chart));
29448 return;
29449}
29450NK_API void
29451nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
29452 int count, int offset)
29453{
29454 int i = 0;
29455 float min_value;
29456 float max_value;
29457
29458 NK_ASSERT(ctx);
29459 NK_ASSERT(values);
29460 if (!ctx || !values || !count) return;
29461
29462 min_value = values[offset];
29463 max_value = values[offset];
29464 for (i = 0; i < count; ++i) {
29465 min_value = NK_MIN(values[i + offset], min_value);
29466 max_value = NK_MAX(values[i + offset], max_value);
29467 }
29468
29469 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
29470 for (i = 0; i < count; ++i)
29471 nk_chart_push(ctx, values[i + offset]);
29472 nk_chart_end(ctx);
29473 }
29474}
29475NK_API void
29476nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
29477 float(*value_getter)(void* user, int index), int count, int offset)
29478{
29479 int i = 0;
29480 float min_value;
29481 float max_value;
29482
29483 NK_ASSERT(ctx);
29484 NK_ASSERT(value_getter);
29485 if (!ctx || !value_getter || !count) return;
29486
29487 max_value = min_value = value_getter(userdata, offset);
29488 for (i = 0; i < count; ++i) {
29489 float value = value_getter(userdata, i + offset);
29490 min_value = NK_MIN(value, min_value);
29491 max_value = NK_MAX(value, max_value);
29492 }
29493
29494 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
29495 for (i = 0; i < count; ++i)
29496 nk_chart_push(ctx, value_getter(userdata, i + offset));
29497 nk_chart_end(ctx);
29498 }
29499}
29500
29501
29502
29503
29504
29505/* ==============================================================
29506 *
29507 * COLOR PICKER
29508 *
29509 * ===============================================================*/
29510NK_LIB nk_bool
29511nk_color_picker_behavior(nk_flags *state,
29512 const struct nk_rect *bounds, const struct nk_rect *matrix,
29513 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
29514 struct nk_colorf *color, const struct nk_input *in)
29515{
29516 float hsva[4];
29517 nk_bool value_changed = 0;
29518 nk_bool hsv_changed = 0;
29519
29520 NK_ASSERT(state);
29521 NK_ASSERT(matrix);
29522 NK_ASSERT(hue_bar);
29523 NK_ASSERT(color);
29524
29525 /* color matrix */
29526 nk_colorf_hsva_fv(hsva, *color);
29527 if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {
29528 hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));
29529 hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));
29530 value_changed = hsv_changed = 1;
29531 }
29532 /* hue bar */
29533 if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {
29534 hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));
29535 value_changed = hsv_changed = 1;
29536 }
29537 /* alpha bar */
29538 if (alpha_bar) {
29539 if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {
29540 hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));
29541 value_changed = 1;
29542 }
29543 }
29544 nk_widget_state_reset(state);
29545 if (hsv_changed) {
29546 *color = nk_hsva_colorfv(hsva);
29547 *state = NK_WIDGET_STATE_ACTIVE;
29548 }
29549 if (value_changed) {
29550 color->a = hsva[3];
29551 *state = NK_WIDGET_STATE_ACTIVE;
29552 }
29553 /* set color picker widget state */
29554 if (nk_input_is_mouse_hovering_rect(in, *bounds))
29555 *state = NK_WIDGET_STATE_HOVERED;
29556 if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))
29557 *state |= NK_WIDGET_STATE_ENTERED;
29558 else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))
29559 *state |= NK_WIDGET_STATE_LEFT;
29560 return value_changed;
29561}
29562NK_LIB void
29563nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,
29564 const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,
29565 struct nk_colorf col)
29566{
29567 NK_STORAGE const struct nk_color black = {0,0,0,255};
29568 NK_STORAGE const struct nk_color white = {255, 255, 255, 255};
29569 NK_STORAGE const struct nk_color black_trans = {0,0,0,0};
29570
29571 const float crosshair_size = 7.0f;
29572 struct nk_color temp;
29573 float hsva[4];
29574 float line_y;
29575 int i;
29576
29577 NK_ASSERT(o);
29578 NK_ASSERT(matrix);
29579 NK_ASSERT(hue_bar);
29580
29581 /* draw hue bar */
29582 nk_colorf_hsva_fv(hsva, col);
29583 for (i = 0; i < 6; ++i) {
29584 NK_GLOBAL const struct nk_color hue_colors[] = {
29585 {255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255},
29586 {0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255}
29587 };
29588 nk_fill_rect_multi_color(o,
29589 nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,
29590 hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],
29591 hue_colors[i+1], hue_colors[i+1]);
29592 }
29593 line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);
29594 nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,
29595 line_y, 1, nk_rgb(255,255,255));
29596
29597 /* draw alpha bar */
29598 if (alpha_bar) {
29599 float alpha = NK_SATURATE(col.a);
29600 line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f);
29601
29602 nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);
29603 nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,
29604 line_y, 1, nk_rgb(255,255,255));
29605 }
29606
29607 /* draw color matrix */
29608 temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);
29609 nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);
29610 nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);
29611
29612 /* draw cross-hair */
29613 {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];
29614 p.x = (float)(int)(matrix->x + S * matrix->w);
29615 p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);
29616 nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);
29617 nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);
29618 nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);
29619 nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}
29620}
29621NK_LIB nk_bool
29622nk_do_color_picker(nk_flags *state,
29623 struct nk_command_buffer *out, struct nk_colorf *col,
29624 enum nk_color_format fmt, struct nk_rect bounds,
29625 struct nk_vec2 padding, const struct nk_input *in,
29626 const struct nk_user_font *font)
29627{
29628 int ret = 0;
29629 struct nk_rect matrix;
29630 struct nk_rect hue_bar;
29631 struct nk_rect alpha_bar;
29632 float bar_w;
29633
29634 NK_ASSERT(out);
29635 NK_ASSERT(col);
29636 NK_ASSERT(state);
29637 NK_ASSERT(font);
29638 if (!out || !col || !state || !font)
29639 return ret;
29640
29641 bar_w = font->height;
29642 bounds.x += padding.x;
29643 bounds.y += padding.x;
29644 bounds.w -= 2 * padding.x;
29645 bounds.h -= 2 * padding.y;
29646
29647 matrix.x = bounds.x;
29648 matrix.y = bounds.y;
29649 matrix.h = bounds.h;
29650 matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);
29651
29652 hue_bar.w = bar_w;
29653 hue_bar.y = bounds.y;
29654 hue_bar.h = matrix.h;
29655 hue_bar.x = matrix.x + matrix.w + padding.x;
29656
29657 alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;
29658 alpha_bar.y = bounds.y;
29659 alpha_bar.w = bar_w;
29660 alpha_bar.h = matrix.h;
29661
29662 ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,
29663 (fmt == NK_RGBA) ? &alpha_bar:0, col, in);
29664 nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col);
29665 return ret;
29666}
29667NK_API nk_bool
29668nk_color_pick(struct nk_context * ctx, struct nk_colorf *color,
29669 enum nk_color_format fmt)
29670{
29671 struct nk_window *win;
29672 struct nk_panel *layout;
29673 const struct nk_style *config;
29674 const struct nk_input *in;
29675
29676 enum nk_widget_layout_states state;
29677 struct nk_rect bounds;
29678
29679 NK_ASSERT(ctx);
29680 NK_ASSERT(color);
29681 NK_ASSERT(ctx->current);
29682 NK_ASSERT(ctx->current->layout);
29683 if (!ctx || !ctx->current || !ctx->current->layout || !color)
29684 return 0;
29685
29686 win = ctx->current;
29687 config = &ctx->style;
29688 layout = win->layout;
29689 state = nk_widget(&bounds, ctx);
29690 if (!state) return 0;
29691 in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
29692 return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,
29693 nk_vec2(0,0), in, config->font);
29694}
29695NK_API struct nk_colorf
29696nk_color_picker(struct nk_context *ctx, struct nk_colorf color,
29697 enum nk_color_format fmt)
29698{
29699 nk_color_pick(ctx, &color, fmt);
29700 return color;
29701}
29702
29703
29704
29705
29706
29707/* ==============================================================
29708 *
29709 * COMBO
29710 *
29711 * ===============================================================*/
29712NK_INTERN nk_bool
29713nk_combo_begin(struct nk_context *ctx, struct nk_window *win,
29714 struct nk_vec2 size, nk_bool is_clicked, struct nk_rect header)
29715{
29716 struct nk_window *popup;
29717 int is_open = 0;
29718 int is_active = 0;
29719 struct nk_rect body;
29720 nk_hash hash;
29721
29722 NK_ASSERT(ctx);
29723 NK_ASSERT(ctx->current);
29724 NK_ASSERT(ctx->current->layout);
29725 if (!ctx || !ctx->current || !ctx->current->layout)
29726 return 0;
29727
29728 popup = win->popup.win;
29729 body.x = header.x;
29730 body.w = size.x;
29731 body.y = header.y + header.h-ctx->style.window.combo_border;
29732 body.h = size.y;
29733
29734 hash = win->popup.combo_count++;
29735 is_open = (popup) ? nk_true:nk_false;
29736 is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);
29737 if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||
29738 (!is_open && !is_active && !is_clicked)) return 0;
29739 if (!nk_nonblock_begin(ctx, 0, body,
29740 (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;
29741
29742 win->popup.type = NK_PANEL_COMBO;
29743 win->popup.name = hash;
29744 return 1;
29745}
29746NK_API nk_bool
29747nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,
29748 struct nk_vec2 size)
29749{
29750 const struct nk_input *in;
29751 struct nk_window *win;
29752 struct nk_style *style;
29753
29755 int is_clicked = nk_false;
29756 struct nk_rect header;
29757 const struct nk_style_item *background;
29758 struct nk_text text;
29759
29760 NK_ASSERT(ctx);
29761 NK_ASSERT(selected);
29762 NK_ASSERT(ctx->current);
29763 NK_ASSERT(ctx->current->layout);
29764 if (!ctx || !ctx->current || !ctx->current->layout || !selected)
29765 return 0;
29766
29767 win = ctx->current;
29768 style = &ctx->style;
29769 s = nk_widget(&header, ctx);
29770 if (s == NK_WIDGET_INVALID)
29771 return 0;
29772
29773 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
29774 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
29775 is_clicked = nk_true;
29776
29777 /* draw combo box header background and border */
29778 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
29779 background = &style->combo.active;
29780 text.text = style->combo.label_active;
29781 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
29782 background = &style->combo.hover;
29783 text.text = style->combo.label_hover;
29784 } else {
29785 background = &style->combo.normal;
29786 text.text = style->combo.label_normal;
29787 }
29788
29789 text.text = nk_rgb_factor(text.text, style->combo.color_factor);
29790
29791 switch(background->type) {
29792 case NK_STYLE_ITEM_IMAGE:
29793 text.background = nk_rgba(0, 0, 0, 0);
29794 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
29795 break;
29796 case NK_STYLE_ITEM_NINE_SLICE:
29797 text.background = nk_rgba(0, 0, 0, 0);
29798 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
29799 break;
29800 case NK_STYLE_ITEM_COLOR:
29801 text.background = background->data.color;
29802 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
29803 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
29804 break;
29805 }
29806 {
29807 /* print currently selected text item */
29808 struct nk_rect label;
29809 struct nk_rect button;
29810 struct nk_rect content;
29811 int draw_button_symbol;
29812
29813 enum nk_symbol_type sym;
29814 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
29815 sym = style->combo.sym_hover;
29816 else if (is_clicked)
29817 sym = style->combo.sym_active;
29818 else
29819 sym = style->combo.sym_normal;
29820
29821 /* represents whether or not the combo's button symbol should be drawn */
29822 draw_button_symbol = sym != NK_SYMBOL_NONE;
29823
29824 /* calculate button */
29825 button.w = header.h - 2 * style->combo.button_padding.y;
29826 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
29827 button.y = header.y + style->combo.button_padding.y;
29828 button.h = button.w;
29829
29830 content.x = button.x + style->combo.button.padding.x;
29831 content.y = button.y + style->combo.button.padding.y;
29832 content.w = button.w - 2 * style->combo.button.padding.x;
29833 content.h = button.h - 2 * style->combo.button.padding.y;
29834
29835 /* draw selected label */
29836 text.padding = nk_vec2(0,0);
29837 label.x = header.x + style->combo.content_padding.x;
29838 label.y = header.y + style->combo.content_padding.y;
29839 label.h = header.h - 2 * style->combo.content_padding.y;
29840 if (draw_button_symbol)
29841 label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;
29842 else
29843 label.w = header.w - 2 * style->combo.content_padding.x;
29844 nk_widget_text(&win->buffer, label, selected, len, &text,
29845 NK_TEXT_LEFT, ctx->style.font);
29846
29847 /* draw open/close button */
29848 if (draw_button_symbol)
29849 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
29850 &ctx->style.combo.button, sym, style->font);
29851 }
29852 return nk_combo_begin(ctx, win, size, is_clicked, header);
29853}
29854NK_API nk_bool
29855nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)
29856{
29857 return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);
29858}
29859NK_API nk_bool
29860nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)
29861{
29862 struct nk_window *win;
29863 struct nk_style *style;
29864 const struct nk_input *in;
29865
29866 struct nk_rect header;
29867 int is_clicked = nk_false;
29869 const struct nk_style_item *background;
29870
29871 NK_ASSERT(ctx);
29872 NK_ASSERT(ctx->current);
29873 NK_ASSERT(ctx->current->layout);
29874 if (!ctx || !ctx->current || !ctx->current->layout)
29875 return 0;
29876
29877 win = ctx->current;
29878 style = &ctx->style;
29879 s = nk_widget(&header, ctx);
29880 if (s == NK_WIDGET_INVALID)
29881 return 0;
29882
29883 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
29884 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
29885 is_clicked = nk_true;
29886
29887 /* draw combo box header background and border */
29888 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
29889 background = &style->combo.active;
29890 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
29891 background = &style->combo.hover;
29892 else background = &style->combo.normal;
29893
29894 switch(background->type) {
29895 case NK_STYLE_ITEM_IMAGE:
29896 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
29897 break;
29898 case NK_STYLE_ITEM_NINE_SLICE:
29899 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
29900 break;
29901 case NK_STYLE_ITEM_COLOR:
29902 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
29903 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
29904 break;
29905 }
29906 {
29907 struct nk_rect content;
29908 struct nk_rect button;
29909 struct nk_rect bounds;
29910 int draw_button_symbol;
29911
29912 enum nk_symbol_type sym;
29913 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
29914 sym = style->combo.sym_hover;
29915 else if (is_clicked)
29916 sym = style->combo.sym_active;
29917 else sym = style->combo.sym_normal;
29918
29919 /* represents whether or not the combo's button symbol should be drawn */
29920 draw_button_symbol = sym != NK_SYMBOL_NONE;
29921
29922 /* calculate button */
29923 button.w = header.h - 2 * style->combo.button_padding.y;
29924 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
29925 button.y = header.y + style->combo.button_padding.y;
29926 button.h = button.w;
29927
29928 content.x = button.x + style->combo.button.padding.x;
29929 content.y = button.y + style->combo.button.padding.y;
29930 content.w = button.w - 2 * style->combo.button.padding.x;
29931 content.h = button.h - 2 * style->combo.button.padding.y;
29932
29933 /* draw color */
29934 bounds.h = header.h - 4 * style->combo.content_padding.y;
29935 bounds.y = header.y + 2 * style->combo.content_padding.y;
29936 bounds.x = header.x + 2 * style->combo.content_padding.x;
29937 if (draw_button_symbol)
29938 bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;
29939 else
29940 bounds.w = header.w - 4 * style->combo.content_padding.x;
29941 nk_fill_rect(&win->buffer, bounds, 0, nk_rgb_factor(color, style->combo.color_factor));
29942
29943 /* draw open/close button */
29944 if (draw_button_symbol)
29945 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
29946 &ctx->style.combo.button, sym, style->font);
29947 }
29948 return nk_combo_begin(ctx, win, size, is_clicked, header);
29949}
29950NK_API nk_bool
29951nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)
29952{
29953 struct nk_window *win;
29954 struct nk_style *style;
29955 const struct nk_input *in;
29956
29957 struct nk_rect header;
29958 int is_clicked = nk_false;
29960 const struct nk_style_item *background;
29961 struct nk_color sym_background;
29962 struct nk_color symbol_color;
29963
29964 NK_ASSERT(ctx);
29965 NK_ASSERT(ctx->current);
29966 NK_ASSERT(ctx->current->layout);
29967 if (!ctx || !ctx->current || !ctx->current->layout)
29968 return 0;
29969
29970 win = ctx->current;
29971 style = &ctx->style;
29972 s = nk_widget(&header, ctx);
29973 if (s == NK_WIDGET_INVALID)
29974 return 0;
29975
29976 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
29977 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
29978 is_clicked = nk_true;
29979
29980 /* draw combo box header background and border */
29981 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
29982 background = &style->combo.active;
29983 symbol_color = style->combo.symbol_active;
29984 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
29985 background = &style->combo.hover;
29986 symbol_color = style->combo.symbol_hover;
29987 } else {
29988 background = &style->combo.normal;
29989 symbol_color = style->combo.symbol_hover;
29990 }
29991
29992 symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);
29993
29994 switch(background->type) {
29995 case NK_STYLE_ITEM_IMAGE:
29996 sym_background = nk_rgba(0, 0, 0, 0);
29997 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
29998 break;
29999 case NK_STYLE_ITEM_NINE_SLICE:
30000 sym_background = nk_rgba(0, 0, 0, 0);
30001 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
30002 break;
30003 case NK_STYLE_ITEM_COLOR:
30004 sym_background = background->data.color;
30005 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
30006 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
30007 break;
30008 }
30009 {
30010 struct nk_rect bounds = {0,0,0,0};
30011 struct nk_rect content;
30012 struct nk_rect button;
30013
30014 enum nk_symbol_type sym;
30015 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
30016 sym = style->combo.sym_hover;
30017 else if (is_clicked)
30018 sym = style->combo.sym_active;
30019 else sym = style->combo.sym_normal;
30020
30021 /* calculate button */
30022 button.w = header.h - 2 * style->combo.button_padding.y;
30023 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
30024 button.y = header.y + style->combo.button_padding.y;
30025 button.h = button.w;
30026
30027 content.x = button.x + style->combo.button.padding.x;
30028 content.y = button.y + style->combo.button.padding.y;
30029 content.w = button.w - 2 * style->combo.button.padding.x;
30030 content.h = button.h - 2 * style->combo.button.padding.y;
30031
30032 /* draw symbol */
30033 bounds.h = header.h - 2 * style->combo.content_padding.y;
30034 bounds.y = header.y + style->combo.content_padding.y;
30035 bounds.x = header.x + style->combo.content_padding.x;
30036 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
30037 nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,
30038 1.0f, style->font);
30039
30040 /* draw open/close button */
30041 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
30042 &ctx->style.combo.button, sym, style->font);
30043 }
30044 return nk_combo_begin(ctx, win, size, is_clicked, header);
30045}
30046NK_API nk_bool
30047nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,
30048 enum nk_symbol_type symbol, struct nk_vec2 size)
30049{
30050 struct nk_window *win;
30051 struct nk_style *style;
30052 struct nk_input *in;
30053
30054 struct nk_rect header;
30055 int is_clicked = nk_false;
30057 const struct nk_style_item *background;
30058 struct nk_color symbol_color;
30059 struct nk_text text;
30060
30061 NK_ASSERT(ctx);
30062 NK_ASSERT(ctx->current);
30063 NK_ASSERT(ctx->current->layout);
30064 if (!ctx || !ctx->current || !ctx->current->layout)
30065 return 0;
30066
30067 win = ctx->current;
30068 style = &ctx->style;
30069 s = nk_widget(&header, ctx);
30070 if (!s) return 0;
30071
30072 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
30073 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
30074 is_clicked = nk_true;
30075
30076 /* draw combo box header background and border */
30077 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
30078 background = &style->combo.active;
30079 symbol_color = style->combo.symbol_active;
30080 text.text = style->combo.label_active;
30081 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
30082 background = &style->combo.hover;
30083 symbol_color = style->combo.symbol_hover;
30084 text.text = style->combo.label_hover;
30085 } else {
30086 background = &style->combo.normal;
30087 symbol_color = style->combo.symbol_normal;
30088 text.text = style->combo.label_normal;
30089 }
30090
30091 text.text = nk_rgb_factor(text.text, style->combo.color_factor);
30092 symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);
30093
30094 switch(background->type) {
30095 case NK_STYLE_ITEM_IMAGE:
30096 text.background = nk_rgba(0, 0, 0, 0);
30097 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
30098 break;
30099 case NK_STYLE_ITEM_NINE_SLICE:
30100 text.background = nk_rgba(0, 0, 0, 0);
30101 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
30102 break;
30103 case NK_STYLE_ITEM_COLOR:
30104 text.background = background->data.color;
30105 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
30106 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
30107 break;
30108 }
30109 {
30110 struct nk_rect content;
30111 struct nk_rect button;
30112 struct nk_rect label;
30113 struct nk_rect image;
30114
30115 enum nk_symbol_type sym;
30116 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
30117 sym = style->combo.sym_hover;
30118 else if (is_clicked)
30119 sym = style->combo.sym_active;
30120 else sym = style->combo.sym_normal;
30121
30122 /* calculate button */
30123 button.w = header.h - 2 * style->combo.button_padding.y;
30124 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
30125 button.y = header.y + style->combo.button_padding.y;
30126 button.h = button.w;
30127
30128 content.x = button.x + style->combo.button.padding.x;
30129 content.y = button.y + style->combo.button.padding.y;
30130 content.w = button.w - 2 * style->combo.button.padding.x;
30131 content.h = button.h - 2 * style->combo.button.padding.y;
30132 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
30133 &ctx->style.combo.button, sym, style->font);
30134
30135 /* draw symbol */
30136 image.x = header.x + style->combo.content_padding.x;
30137 image.y = header.y + style->combo.content_padding.y;
30138 image.h = header.h - 2 * style->combo.content_padding.y;
30139 image.w = image.h;
30140 nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,
30141 1.0f, style->font);
30142
30143 /* draw label */
30144 text.padding = nk_vec2(0,0);
30145 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
30146 label.y = header.y + style->combo.content_padding.y;
30147 label.w = (button.x - style->combo.content_padding.x) - label.x;
30148 label.h = header.h - 2 * style->combo.content_padding.y;
30149 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
30150 }
30151 return nk_combo_begin(ctx, win, size, is_clicked, header);
30152}
30153NK_API nk_bool
30154nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)
30155{
30156 struct nk_window *win;
30157 struct nk_style *style;
30158 const struct nk_input *in;
30159
30160 struct nk_rect header;
30161 int is_clicked = nk_false;
30163 const struct nk_style_item *background;
30164
30165 NK_ASSERT(ctx);
30166 NK_ASSERT(ctx->current);
30167 NK_ASSERT(ctx->current->layout);
30168 if (!ctx || !ctx->current || !ctx->current->layout)
30169 return 0;
30170
30171 win = ctx->current;
30172 style = &ctx->style;
30173 s = nk_widget(&header, ctx);
30174 if (s == NK_WIDGET_INVALID)
30175 return 0;
30176
30177 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
30178 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
30179 is_clicked = nk_true;
30180
30181 /* draw combo box header background and border */
30182 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)
30183 background = &style->combo.active;
30184 else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
30185 background = &style->combo.hover;
30186 else background = &style->combo.normal;
30187
30188 switch (background->type) {
30189 case NK_STYLE_ITEM_IMAGE:
30190 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
30191 break;
30192 case NK_STYLE_ITEM_NINE_SLICE:
30193 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
30194 break;
30195 case NK_STYLE_ITEM_COLOR:
30196 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
30197 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
30198 break;
30199 }
30200 {
30201 struct nk_rect bounds = {0,0,0,0};
30202 struct nk_rect content;
30203 struct nk_rect button;
30204 int draw_button_symbol;
30205
30206 enum nk_symbol_type sym;
30207 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
30208 sym = style->combo.sym_hover;
30209 else if (is_clicked)
30210 sym = style->combo.sym_active;
30211 else sym = style->combo.sym_normal;
30212
30213 /* represents whether or not the combo's button symbol should be drawn */
30214 draw_button_symbol = sym != NK_SYMBOL_NONE;
30215
30216 /* calculate button */
30217 button.w = header.h - 2 * style->combo.button_padding.y;
30218 button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;
30219 button.y = header.y + style->combo.button_padding.y;
30220 button.h = button.w;
30221
30222 content.x = button.x + style->combo.button.padding.x;
30223 content.y = button.y + style->combo.button.padding.y;
30224 content.w = button.w - 2 * style->combo.button.padding.x;
30225 content.h = button.h - 2 * style->combo.button.padding.y;
30226
30227 /* draw image */
30228 bounds.h = header.h - 2 * style->combo.content_padding.y;
30229 bounds.y = header.y + style->combo.content_padding.y;
30230 bounds.x = header.x + style->combo.content_padding.x;
30231 if (draw_button_symbol)
30232 bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
30233 else
30234 bounds.w = header.w - 2 * style->combo.content_padding.x;
30235 nk_draw_image(&win->buffer, bounds, &img, nk_rgb_factor(nk_white, style->combo.color_factor));
30236
30237 /* draw open/close button */
30238 if (draw_button_symbol)
30239 nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,
30240 &ctx->style.combo.button, sym, style->font);
30241 }
30242 return nk_combo_begin(ctx, win, size, is_clicked, header);
30243}
30244NK_API nk_bool
30245nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,
30246 struct nk_image img, struct nk_vec2 size)
30247{
30248 struct nk_window *win;
30249 struct nk_style *style;
30250 struct nk_input *in;
30251
30252 struct nk_rect header;
30253 int is_clicked = nk_false;
30255 const struct nk_style_item *background;
30256 struct nk_text text;
30257
30258 NK_ASSERT(ctx);
30259 NK_ASSERT(ctx->current);
30260 NK_ASSERT(ctx->current->layout);
30261 if (!ctx || !ctx->current || !ctx->current->layout)
30262 return 0;
30263
30264 win = ctx->current;
30265 style = &ctx->style;
30266 s = nk_widget(&header, ctx);
30267 if (!s) return 0;
30268
30269 in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;
30270 if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))
30271 is_clicked = nk_true;
30272
30273 /* draw combo box header background and border */
30274 if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {
30275 background = &style->combo.active;
30276 text.text = style->combo.label_active;
30277 } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {
30278 background = &style->combo.hover;
30279 text.text = style->combo.label_hover;
30280 } else {
30281 background = &style->combo.normal;
30282 text.text = style->combo.label_normal;
30283 }
30284
30285 text.text = nk_rgb_factor(text.text, style->combo.color_factor);
30286
30287 switch(background->type) {
30288 case NK_STYLE_ITEM_IMAGE:
30289 text.background = nk_rgba(0, 0, 0, 0);
30290 nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));
30291 break;
30292 case NK_STYLE_ITEM_NINE_SLICE:
30293 text.background = nk_rgba(0, 0, 0, 0);
30294 nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));
30295 break;
30296 case NK_STYLE_ITEM_COLOR:
30297 text.background = background->data.color;
30298 nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));
30299 nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));
30300 break;
30301 }
30302 {
30303 struct nk_rect content;
30304 struct nk_rect button;
30305 struct nk_rect label;
30306 struct nk_rect image;
30307 int draw_button_symbol;
30308
30309 enum nk_symbol_type sym;
30310 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
30311 sym = style->combo.sym_hover;
30312 else if (is_clicked)
30313 sym = style->combo.sym_active;
30314 else sym = style->combo.sym_normal;
30315
30316 /* represents whether or not the combo's button symbol should be drawn */
30317 draw_button_symbol = sym != NK_SYMBOL_NONE;
30318
30319 /* calculate button */
30320 button.w = header.h - 2 * style->combo.button_padding.y;
30321 button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;
30322 button.y = header.y + style->combo.button_padding.y;
30323 button.h = button.w;
30324
30325 content.x = button.x + style->combo.button.padding.x;
30326 content.y = button.y + style->combo.button.padding.y;
30327 content.w = button.w - 2 * style->combo.button.padding.x;
30328 content.h = button.h - 2 * style->combo.button.padding.y;
30329 if (draw_button_symbol)
30330 nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,
30331 &ctx->style.combo.button, sym, style->font);
30332
30333 /* draw image */
30334 image.x = header.x + style->combo.content_padding.x;
30335 image.y = header.y + style->combo.content_padding.y;
30336 image.h = header.h - 2 * style->combo.content_padding.y;
30337 image.w = image.h;
30338 nk_draw_image(&win->buffer, image, &img, nk_rgb_factor(nk_white, style->combo.color_factor));
30339
30340 /* draw label */
30341 text.padding = nk_vec2(0,0);
30342 label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;
30343 label.y = header.y + style->combo.content_padding.y;
30344 label.h = header.h - 2 * style->combo.content_padding.y;
30345 if (draw_button_symbol)
30346 label.w = (button.x - style->combo.content_padding.x) - label.x;
30347 else
30348 label.w = (header.x + header.w - style->combo.content_padding.x) - label.x;
30349 nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);
30350 }
30351 return nk_combo_begin(ctx, win, size, is_clicked, header);
30352}
30353NK_API nk_bool
30354nk_combo_begin_symbol_label(struct nk_context *ctx,
30355 const char *selected, enum nk_symbol_type type, struct nk_vec2 size)
30356{
30357 return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);
30358}
30359NK_API nk_bool
30360nk_combo_begin_image_label(struct nk_context *ctx,
30361 const char *selected, struct nk_image img, struct nk_vec2 size)
30362{
30363 return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);
30364}
30365NK_API nk_bool
30366nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)
30367{
30368 return nk_contextual_item_text(ctx, text, len, align);
30369}
30370NK_API nk_bool
30371nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)
30372{
30373 return nk_contextual_item_label(ctx, label, align);
30374}
30375NK_API nk_bool
30376nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,
30377 int len, nk_flags alignment)
30378{
30379 return nk_contextual_item_image_text(ctx, img, text, len, alignment);
30380}
30381NK_API nk_bool
30382nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,
30383 const char *text, nk_flags alignment)
30384{
30385 return nk_contextual_item_image_label(ctx, img, text, alignment);
30386}
30387NK_API nk_bool
30388nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
30389 const char *text, int len, nk_flags alignment)
30390{
30391 return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);
30392}
30393NK_API nk_bool
30394nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
30395 const char *label, nk_flags alignment)
30396{
30397 return nk_contextual_item_symbol_label(ctx, sym, label, alignment);
30398}
30399NK_API void nk_combo_end(struct nk_context *ctx)
30400{
30401 nk_contextual_end(ctx);
30402}
30403NK_API void nk_combo_close(struct nk_context *ctx)
30404{
30405 nk_contextual_close(ctx);
30406}
30407NK_API int
30408nk_combo(struct nk_context *ctx, const char *const *items, int count,
30409 int selected, int item_height, struct nk_vec2 size)
30410{
30411 int i = 0;
30412 int max_height;
30413 struct nk_vec2 item_spacing;
30414 struct nk_vec2 window_padding;
30415
30416 NK_ASSERT(ctx);
30417 NK_ASSERT(items);
30418 NK_ASSERT(ctx->current);
30419 if (!ctx || !items ||!count)
30420 return selected;
30421
30422 item_spacing = ctx->style.window.spacing;
30423 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
30424 max_height = count * item_height + count * (int)item_spacing.y;
30425 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
30426 size.y = NK_MIN(size.y, (float)max_height);
30427 if (nk_combo_begin_label(ctx, items[selected], size)) {
30428 nk_layout_row_dynamic(ctx, (float)item_height, 1);
30429 for (i = 0; i < count; ++i) {
30430 if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
30431 selected = i;
30432 }
30433 nk_combo_end(ctx);
30434 }
30435 return selected;
30436}
30437NK_API int
30438nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,
30439 int separator, int selected, int count, int item_height, struct nk_vec2 size)
30440{
30441 int i;
30442 int max_height;
30443 struct nk_vec2 item_spacing;
30444 struct nk_vec2 window_padding;
30445 const char *current_item;
30446 const char *iter;
30447 int length = 0;
30448
30449 NK_ASSERT(ctx);
30450 NK_ASSERT(items_separated_by_separator);
30451 if (!ctx || !items_separated_by_separator)
30452 return selected;
30453
30454 /* calculate popup window */
30455 item_spacing = ctx->style.window.spacing;
30456 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
30457 max_height = count * item_height + count * (int)item_spacing.y;
30458 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
30459 size.y = NK_MIN(size.y, (float)max_height);
30460
30461 /* find selected item */
30462 current_item = items_separated_by_separator;
30463 for (i = 0; i < count; ++i) {
30464 iter = current_item;
30465 while (*iter && *iter != separator) iter++;
30466 length = (int)(iter - current_item);
30467 if (i == selected) break;
30468 current_item = iter + 1;
30469 }
30470
30471 if (nk_combo_begin_text(ctx, current_item, length, size)) {
30472 current_item = items_separated_by_separator;
30473 nk_layout_row_dynamic(ctx, (float)item_height, 1);
30474 for (i = 0; i < count; ++i) {
30475 iter = current_item;
30476 while (*iter && *iter != separator) iter++;
30477 length = (int)(iter - current_item);
30478 if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))
30479 selected = i;
30480 current_item = current_item + length + 1;
30481 }
30482 nk_combo_end(ctx);
30483 }
30484 return selected;
30485}
30486NK_API int
30487nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,
30488 int selected, int count, int item_height, struct nk_vec2 size)
30489{
30490 return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);
30491}
30492NK_API int
30493nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),
30494 void *userdata, int selected, int count, int item_height, struct nk_vec2 size)
30495{
30496 int i;
30497 int max_height;
30498 struct nk_vec2 item_spacing;
30499 struct nk_vec2 window_padding;
30500 const char *item;
30501
30502 NK_ASSERT(ctx);
30503 NK_ASSERT(item_getter);
30504 if (!ctx || !item_getter)
30505 return selected;
30506
30507 /* calculate popup window */
30508 item_spacing = ctx->style.window.spacing;
30509 window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);
30510 max_height = count * item_height + count * (int)item_spacing.y;
30511 max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;
30512 size.y = NK_MIN(size.y, (float)max_height);
30513
30514 item_getter(userdata, selected, &item);
30515 if (nk_combo_begin_label(ctx, item, size)) {
30516 nk_layout_row_dynamic(ctx, (float)item_height, 1);
30517 for (i = 0; i < count; ++i) {
30518 item_getter(userdata, i, &item);
30519 if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))
30520 selected = i;
30521 }
30522 nk_combo_end(ctx);
30523 } return selected;
30524}
30525NK_API void
30526nk_combobox(struct nk_context *ctx, const char *const *items, int count,
30527 int *selected, int item_height, struct nk_vec2 size)
30528{
30529 *selected = nk_combo(ctx, items, count, *selected, item_height, size);
30530}
30531NK_API void
30532nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,
30533 int *selected, int count, int item_height, struct nk_vec2 size)
30534{
30535 *selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);
30536}
30537NK_API void
30538nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,
30539 int separator, int *selected, int count, int item_height, struct nk_vec2 size)
30540{
30541 *selected = nk_combo_separator(ctx, items_separated_by_separator, separator,
30542 *selected, count, item_height, size);
30543}
30544NK_API void
30545nk_combobox_callback(struct nk_context *ctx,
30546 void(*item_getter)(void* data, int id, const char **out_text),
30547 void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)
30548{
30549 *selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);
30550}
30551
30552
30553
30554
30555/* ===============================================================
30556 *
30557 * TOOLTIP
30558 *
30559 * ===============================================================*/
30560NK_API nk_bool
30561nk_tooltip_begin(struct nk_context *ctx, float width)
30562{
30563 int x,y,w,h;
30564 struct nk_window *win;
30565 const struct nk_input *in;
30566 struct nk_rect bounds;
30567 int ret;
30568
30569 NK_ASSERT(ctx);
30570 NK_ASSERT(ctx->current);
30571 NK_ASSERT(ctx->current->layout);
30572 if (!ctx || !ctx->current || !ctx->current->layout)
30573 return 0;
30574
30575 /* make sure that no nonblocking popup is currently active */
30576 win = ctx->current;
30577 in = &ctx->input;
30578 if (win->popup.win && ((int)win->popup.type & (int)NK_PANEL_SET_NONBLOCK))
30579 return 0;
30580
30581 w = nk_iceilf(width);
30582 h = nk_iceilf(nk_null_rect.h);
30583 x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x;
30584 y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y;
30585
30586 bounds.x = (float)x;
30587 bounds.y = (float)y;
30588 bounds.w = (float)w;
30589 bounds.h = (float)h;
30590
30591 ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,
30592 "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);
30593 if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;
30594 win->popup.type = NK_PANEL_TOOLTIP;
30595 ctx->current->layout->type = NK_PANEL_TOOLTIP;
30596 return ret;
30597}
30598
30599NK_API void
30600nk_tooltip_end(struct nk_context *ctx)
30601{
30602 NK_ASSERT(ctx);
30603 NK_ASSERT(ctx->current);
30604 if (!ctx || !ctx->current) return;
30605 ctx->current->seq--;
30606 nk_popup_close(ctx);
30607 nk_popup_end(ctx);
30608}
30609NK_API void
30610nk_tooltip(struct nk_context *ctx, const char *text)
30611{
30612 const struct nk_style *style;
30613 struct nk_vec2 padding;
30614
30615 int text_len;
30616 float text_width;
30617 float text_height;
30618
30619 NK_ASSERT(ctx);
30620 NK_ASSERT(ctx->current);
30621 NK_ASSERT(ctx->current->layout);
30622 NK_ASSERT(text);
30623 if (!ctx || !ctx->current || !ctx->current->layout || !text)
30624 return;
30625
30626 /* fetch configuration data */
30627 style = &ctx->style;
30628 padding = style->window.padding;
30629
30630 /* calculate size of the text and tooltip */
30631 text_len = nk_strlen(text);
30632 text_width = style->font->width(style->font->userdata,
30633 style->font->height, text, text_len);
30634 text_width += (4 * padding.x);
30635 text_height = (style->font->height + 2 * padding.y);
30636
30637 /* execute tooltip and fill with text */
30638 if (nk_tooltip_begin(ctx, (float)text_width)) {
30639 nk_layout_row_dynamic(ctx, (float)text_height, 1);
30640 nk_text(ctx, text, text_len, NK_TEXT_LEFT);
30641 nk_tooltip_end(ctx);
30642 }
30643}
30644#ifdef NK_INCLUDE_STANDARD_VARARGS
30645NK_API void
30646nk_tooltipf(struct nk_context *ctx, const char *fmt, ...)
30647{
30648 va_list args;
30649 va_start(args, fmt);
30650 nk_tooltipfv(ctx, fmt, args);
30651 va_end(args);
30652}
30653NK_API void
30654nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
30655{
30656 char buf[256];
30657 nk_strfmt(buf, NK_LEN(buf), fmt, args);
30658 nk_tooltip(ctx, buf);
30659}
30660#endif
30661
30662
30663
30664#endif /* NK_IMPLEMENTATION */
30665
30666/*
30709
31085*/
31086
float vec2[2]
2D vector of floats
Definition Structs.h:190
NK_API void nk_tree_pop(struct nk_context *)
NK_API void nk_free(struct nk_context *)
Frees all memory allocated by nuklear; Not needed if context was initialized with nk_init_fixed.
NK_API nk_bool nk_group_begin(struct nk_context *, const char *title, nk_flags)
Starts a new widget group. Requires a previous layouting function to specify a pos/size.
NK_API struct nk_vec2 nk_window_get_content_region_max(const struct nk_context *ctx)
NK_API void nk_layout_row_end(struct nk_context *)
Finished previously started row.
NK_API void nk_input_end(struct nk_context *)
End the input mirroring process by resetting mouse grabbing state to ensure the mouse cursor is not g...
NK_API void nk_window_close(struct nk_context *ctx, const char *name)
NK_API void nk_spacer(struct nk_context *ctx)
NK_API void nk_input_begin(struct nk_context *)
Begins the input mirroring process by resetting text, scroll mouse, previous mouse position and movem...
NK_API float nk_propertyf(struct nk_context *, const char *name, float min, float val, float max, float step, float inc_per_pixel)
NK_API void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)
NK_API void nk_layout_space_end(struct nk_context *)
NK_API nk_bool nk_init_fixed(struct nk_context *, void *memory, nk_size size, const struct nk_user_font *)
NK_API void nk_property_float(struct nk_context *, const char *name, float min, float *val, float max, float step, float inc_per_pixel)
nk_window_flags
Definition nuklear.h:5712
@ NK_WINDOW_CLOSED
Definition nuklear.h:5718
@ NK_WINDOW_MINIMIZED
Definition nuklear.h:5719
@ NK_WINDOW_HIDDEN
Definition nuklear.h:5717
@ NK_WINDOW_ROM
Definition nuklear.h:5715
@ NK_WINDOW_NOT_INTERACTIVE
Definition nuklear.h:5716
@ NK_WINDOW_DYNAMIC
Definition nuklear.h:5714
@ NK_WINDOW_REMOVE_ROM
Definition nuklear.h:5720
NK_API void nk_layout_row(struct nk_context *, enum nk_layout_format, float height, int cols, const float *ratio)
Specifies row columns in array as either window ratio or size.
NK_API void nk_draw_image(struct nk_command_buffer *, struct nk_rect, const struct nk_image *, struct nk_color)
NK_API nk_bool nk_window_is_hovered(const struct nk_context *ctx)
NK_API void nk_window_collapse_if(struct nk_context *ctx, const char *name, enum nk_collapse_states state, int cond)
NK_API struct nk_vec2 nk_layout_space_to_screen(const struct nk_context *ctx, struct nk_vec2 vec)
#define NK_UTF_INVALID
Definition nuklear.h:244
#define NK_BOOL
Definition nuklear.h:415
NK_API struct nk_command_buffer * nk_window_get_canvas(const struct nk_context *ctx)
NK_API nk_bool nk_init_custom(struct nk_context *, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *)
Initializes a nk_context struct from two different either fixed or growing buffers.
NK_API nk_bool 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)
NK_API void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)
NK_API void nk_group_scrolled_end(struct nk_context *)
NK_API struct nk_vec2 nk_window_get_size(const struct nk_context *ctx)
NK_API void nk_layout_row_template_push_dynamic(struct nk_context *)
NK_API const struct nk_command * nk__begin(struct nk_context *)
Returns a draw command list iterator to iterate all draw commands accumulated over one frame.
NK_API nk_bool nk_window_is_active(const struct nk_context *ctx, const char *name)
NK_API void nk_group_get_scroll(struct nk_context *, const char *id, nk_uint *x_offset, nk_uint *y_offset)
NK_API struct nk_vec2 nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 vec)
NK_API void nk_window_set_focus(struct nk_context *ctx, const char *name)
NK_API nk_bool nk_item_is_any_active(const struct nk_context *ctx)
#define NK_UTF_SIZE
Definition nuklear.h:245
NK_API void nk_input_unicode(struct nk_context *, nk_rune)
Converts a unicode rune into UTF-8 and copies the result into an internal text buffer.
NK_API nk_bool nk_window_is_any_hovered(const struct nk_context *ctx)
NK_API nk_bool nk_window_is_hidden(const struct nk_context *ctx, const char *name)
NK_API void nk_input_key(struct nk_context *, enum nk_keys, nk_bool down)
Mirrors the state of a specific key to nuklear.
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)
NK_API void nk_property_double(struct nk_context *, const char *name, double min, double *val, double max, double step, float inc_per_pixel)
NK_API void nk_fill_rect(struct nk_command_buffer *, struct nk_rect, float rounding, struct nk_color)
NK_API void nk_layout_row_template_push_static(struct nk_context *, float width)
NK_API struct nk_vec2 nk_window_get_content_region_size(const struct nk_context *ctx)
NK_API struct nk_panel * nk_window_get_panel(const struct nk_context *ctx)
NK_API void nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
NK_API nk_bool nk_group_scrolled_offset_begin(struct nk_context *, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)
NK_API nk_bool nk_tree_state_image_push(struct nk_context *, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state)
NK_API void nk_window_set_position(struct nk_context *ctx, const char *name, struct nk_vec2 pos)
NK_API void nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states state)
NK_API nk_bool nk_window_is_collapsed(const struct nk_context *ctx, const char *name)
NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
Sets current row layout to share horizontal space between @cols number of widgets evenly....
NK_API const struct nk_command * nk__next(struct nk_context *, const struct nk_command *)
Returns draw command pointer pointing to the next command inside the draw command list.
NK_API void nk_window_collapse(struct nk_context *ctx, const char *name, enum nk_collapse_states state)
NK_API nk_bool nk_filter_default(const struct nk_text_edit *, nk_rune unicode)
NK_API void nk_layout_row_template_end(struct nk_context *)
NK_API nk_bool nk_window_has_focus(const struct nk_context *ctx)
NK_API void nk_layout_reset_min_row_height(struct nk_context *)
nk_widget_states
Definition nuklear.h:3310
@ NK_WIDGET_STATE_LEFT
Definition nuklear.h:3316
@ NK_WIDGET_STATE_ACTIVED
Definition nuklear.h:3315
@ NK_WIDGET_STATE_ENTERED
Definition nuklear.h:3313
@ NK_WIDGET_STATE_HOVER
Definition nuklear.h:3314
@ NK_WIDGET_STATE_ACTIVE
Definition nuklear.h:3318
@ NK_WIDGET_STATE_HOVERED
Definition nuklear.h:3317
NK_API struct nk_window * nk_window_find(const struct nk_context *ctx, const char *name)
NK_API struct nk_rect nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect bounds)
NK_API void nk_window_set_bounds(struct nk_context *ctx, const char *name, struct nk_rect bounds)
NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx)
NK_API nk_bool nk_tree_state_push(struct nk_context *, enum nk_tree_type, const char *title, enum nk_collapse_states *state)
NK_API nk_bool 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)
NK_API void nk_layout_set_min_row_height(struct nk_context *, float height)
NK_API void nk_window_show_if(struct nk_context *ctx, const char *name, enum nk_show_states state, int cond)
NK_API float nk_window_get_height(const struct nk_context *ctx)
NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols)
Starts a new dynamic or fixed row with given height and columns.
NK_API nk_bool nk_group_begin_titled(struct nk_context *, const char *name, const char *title, nk_flags)
Starts a new widget group. Requires a previous layouting function to specify a pos/size.
NK_API nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags)
#define nk_foreach(c, ctx)
Iterates over each draw command inside the context draw command list.
Definition nuklear.h:1254
NK_API void nk_layout_space_push(struct nk_context *, struct nk_rect bounds)
NK_API nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags)
NK_API void nk_window_set_size(struct nk_context *ctx, const char *name, struct nk_vec2 size)
NK_API void nk_input_button(struct nk_context *, enum nk_buttons, int x, int y, nk_bool down)
Mirrors the state of a specific mouse button to nuklear.
NK_API void nk_group_set_scroll(struct nk_context *, const char *id, nk_uint x_offset, nk_uint y_offset)
NK_API void nk_layout_row_template_begin(struct nk_context *, float row_height)
NK_API nk_bool nk_init(struct nk_context *, const struct nk_allocator *, const struct nk_user_font *)
NK_API float nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width)
Utility functions to calculate window ratio from pixel size.
NK_API void nk_tree_state_pop(struct nk_context *)
NK_API void nk_layout_row_push(struct nk_context *, float value)
NK_API struct nk_rect nk_layout_widget_bounds(const struct nk_context *ctx)
Returns the width of the next row allocate by one of the layouting functions.
NK_API struct nk_rect nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect bounds)
NK_API struct nk_vec2 nk_window_get_content_region_min(const struct nk_context *ctx)
NK_API void nk_input_char(struct nk_context *, char)
Copies a single ASCII character into an internal text buffer.
NK_API float nk_window_get_width(const struct nk_context *ctx)
NK_API void nk_input_scroll(struct nk_context *, struct nk_vec2 val)
Copies the last mouse scroll value to nuklear.
nk_widget_layout_states
Definition nuklear.h:3304
@ NK_WIDGET_DISABLED
Definition nuklear.h:3308
@ NK_WIDGET_ROM
Definition nuklear.h:3307
@ NK_WIDGET_VALID
Definition nuklear.h:3306
@ NK_WIDGET_INVALID
Definition nuklear.h:3305
NK_API double nk_propertyd(struct nk_context *, const char *name, double min, double val, double max, double step, float inc_per_pixel)
NK_API void nk_input_motion(struct nk_context *, int x, int y)
Mirrors current mouse position to nuklear.
NK_API void nk_layout_space_begin(struct nk_context *, enum nk_layout_format, float height, int widget_count)
NK_API struct nk_rect nk_layout_space_bounds(const struct nk_context *ctx)
NK_API struct nk_rect nk_window_get_content_region(const struct nk_context *ctx)
NK_API nk_bool nk_window_is_closed(const struct nk_context *ctx, const char *name)
NK_API void nk_clear(struct nk_context *)
Resets the context state at the end of the frame.
NK_API void nk_end(struct nk_context *ctx)
NK_API void nk_group_end(struct nk_context *)
NK_API void nk_layout_row_template_push_variable(struct nk_context *, float min_width)
NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx)
nk_edit_events
Definition nuklear.h:3724
@ NK_EDIT_INACTIVE
Definition nuklear.h:3726
@ NK_EDIT_DEACTIVATED
Definition nuklear.h:3728
@ NK_EDIT_COMMITED
Definition nuklear.h:3729
@ NK_EDIT_ACTIVATED
Definition nuklear.h:3727
NK_API int nk_propertyi(struct nk_context *, const char *name, int min, int val, int max, int step, float inc_per_pixel)
NK_API nk_bool nk_group_scrolled_begin(struct nk_context *, struct nk_scroll *off, const char *title, nk_flags)
NK_API void nk_input_glyph(struct nk_context *, const nk_glyph)
Converts an encoded unicode rune into UTF-8 and copies the result into an internal text buffer.
NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
Sets current row layout to fill @cols number of widgets in row with same @item_width horizontal size....
NK_API void nk_textedit_init(struct nk_text_edit *, const struct nk_allocator *, nk_size size)
Definition nuklear.h:516
Definition nuklear.h:4406
Definition nuklear.h:4412
struct nk_allocator pool
Definition nuklear.h:4414
struct nk_memory memory
Definition nuklear.h:4416
enum nk_allocation_type type
Definition nuklear.h:4415
nk_size needed
Definition nuklear.h:4419
nk_size size
Definition nuklear.h:4421
nk_size allocated
Definition nuklear.h:4418
float grow_factor
Definition nuklear.h:4417
nk_size calls
Definition nuklear.h:4420
Definition nuklear.h:5627
Definition nuklear.h:5638
Definition nuklear.h:4535
Definition nuklear.h:484
Definition nuklear.h:485
Definition nuklear.h:4789
Definition nuklear.h:4780
Definition nuklear.h:4855
Definition nuklear.h:4773
Definition nuklear.h:4765
Definition nuklear.h:4712
Definition nuklear.h:4830
Definition nuklear.h:4820
Definition nuklear.h:4704
Definition nuklear.h:4805
Definition nuklear.h:4797
Definition nuklear.h:4812
Definition nuklear.h:4730
Definition nuklear.h:4738
Definition nuklear.h:4721
Definition nuklear.h:4698
Definition nuklear.h:4838
Definition nuklear.h:4757
Definition nuklear.h:4748
Definition nuklear.h:4690
Definition nuklear.h:5874
Definition nuklear.h:5927
int build
Definition nuklear.h:5956
struct nk_text_edit text_edit
Definition nuklear.h:5951
struct nk_command_buffer overlay
Definition nuklear.h:5953
Definition nuklear.h:1201
enum nk_anti_aliasing shape_AA
Definition nuklear.h:1204
enum nk_anti_aliasing line_AA
Definition nuklear.h:1203
nk_size vertex_alignment
Definition nuklear.h:1211
nk_size vertex_size
Definition nuklear.h:1210
const struct nk_draw_vertex_layout_element * vertex_layout
Definition nuklear.h:1209
unsigned arc_segment_count
Definition nuklear.h:1206
unsigned circle_segment_count
Definition nuklear.h:1205
unsigned curve_segment_count
Definition nuklear.h:1207
struct nk_draw_null_texture tex_null
Definition nuklear.h:1208
Definition nuklear.h:494
Definition nuklear.h:1197
struct nk_vec2 uv
Definition nuklear.h:1199
Definition nuklear.h:5735
Definition nuklear.h:492
Definition nuklear.h:4922
Definition nuklear.h:4912
Definition nuklear.h:4916
Definition nuklear.h:3288
Definition nuklear.h:4386
Definition nuklear.h:4411
Definition nuklear.h:5680
Definition nuklear.h:4893
Definition nuklear.h:4898
Definition nuklear.h:493
Definition nuklear.h:5904
Definition nuklear.h:5910
Definition nuklear.h:5685
Definition nuklear.h:5916
Definition nuklear.h:5672
Definition nuklear.h:5723
Definition nuklear.h:5748
Definition nuklear.h:488
Definition nuklear.h:489
Definition nuklear.h:5656
Definition nuklear.h:495
Definition nuklear.h:4449
Definition nuklear.h:5125
Definition nuklear.h:5430
Definition nuklear.h:5446
Definition nuklear.h:5361
Definition nuklear.h:5113
Definition nuklear.h:5265
Definition nuklear.h:5298
Definition nuklear.h:5397
Definition nuklear.h:5326
Definition nuklear.h:5187
Definition nuklear.h:5224
Definition nuklear.h:5479
Definition nuklear.h:5118
Definition nuklear.h:5155
Definition nuklear.h:5507
Definition nuklear.h:5532
Definition nuklear.h:5569
Definition nuklear.h:5890
Definition nuklear.h:4568
Definition nuklear.h:4541
Definition nuklear.h:4548
Definition nuklear.h:4229
nk_text_width_f width
Definition nuklear.h:4232
float height
Definition nuklear.h:4231
Definition nuklear.h:486
Definition nuklear.h:487
Definition nuklear.h:5761
Definition nuklear.h:491
Definition nuklear.h:5898
Definition nuklear.h:5107