Nuklear
This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.
 
Loading...
Searching...
No Matches
nuklear_util.c
1#include "nuklear.h"
2#include "nuklear_internal.h"
3
4/* ===============================================================
5 *
6 * UTIL
7 *
8 * ===============================================================*/
9NK_INTERN int nk_str_match_here(const char *regexp, const char *text);
10NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);
11NK_LIB nk_bool nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}
12NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}
13NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}
14NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}
15
16#ifndef NK_MEMCPY
17#define NK_MEMCPY nk_memcopy
18NK_LIB void*
19nk_memcopy(void *dst0, const void *src0, nk_size length)
20{
21 nk_ptr t;
22 char *dst = (char*)dst0;
23 const char *src = (const char*)src0;
24 if (length == 0 || dst == src)
25 goto done;
26
27 #define nk_word int
28 #define nk_wsize sizeof(nk_word)
29 #define nk_wmask (nk_wsize-1)
30 #define NK_TLOOP(s) if (t) NK_TLOOP1(s)
31 #define NK_TLOOP1(s) do { s; } while (--t)
32
33 if (dst < src) {
34 t = (nk_ptr)src; /* only need low bits */
35 if ((t | (nk_ptr)dst) & nk_wmask) {
36 if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)
37 t = length;
38 else
39 t = nk_wsize - (t & nk_wmask);
40 length -= t;
41 NK_TLOOP1(*dst++ = *src++);
42 }
43 t = length / nk_wsize;
44 NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;
45 src += nk_wsize; dst += nk_wsize);
46 t = length & nk_wmask;
47 NK_TLOOP(*dst++ = *src++);
48 } else {
49 src += length;
50 dst += length;
51 t = (nk_ptr)src;
52 if ((t | (nk_ptr)dst) & nk_wmask) {
53 if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)
54 t = length;
55 else
56 t &= nk_wmask;
57 length -= t;
58 NK_TLOOP1(*--dst = *--src);
59 }
60 t = length / nk_wsize;
61 NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;
62 *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);
63 t = length & nk_wmask;
64 NK_TLOOP(*--dst = *--src);
65 }
66 #undef nk_word
67 #undef nk_wsize
68 #undef nk_wmask
69 #undef NK_TLOOP
70 #undef NK_TLOOP1
71done:
72 return (dst0);
73}
74#endif
75#ifndef NK_MEMSET
76#define NK_MEMSET nk_memset
77NK_LIB void
78nk_memset(void *ptr, int c0, nk_size size)
79{
80 #define nk_word unsigned
81 #define nk_wsize sizeof(nk_word)
82 #define nk_wmask (nk_wsize - 1)
83 nk_byte *dst = (nk_byte*)ptr;
84 unsigned c = 0;
85 nk_size t = 0;
86
87 if ((c = (nk_byte)c0) != 0) {
88 c = (c << 8) | c; /* at least 16-bits */
89 if (sizeof(unsigned int) > 2)
90 c = (c << 16) | c; /* at least 32-bits*/
91 }
92
93 /* too small of a word count */
94 dst = (nk_byte*)ptr;
95 if (size < 3 * nk_wsize) {
96 while (size--) *dst++ = (nk_byte)c0;
97 return;
98 }
99
100 /* align destination */
101 if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {
102 t = nk_wsize -t;
103 size -= t;
104 do {
105 *dst++ = (nk_byte)c0;
106 } while (--t != 0);
107 }
108
109 /* fill word */
110 t = size / nk_wsize;
111 do {
112 *(nk_word*)((void*)dst) = c;
113 dst += nk_wsize;
114 } while (--t != 0);
115
116 /* fill trailing bytes */
117 t = (size & nk_wmask);
118 if (t != 0) {
119 do {
120 *dst++ = (nk_byte)c0;
121 } while (--t != 0);
122 }
123
124 #undef nk_word
125 #undef nk_wsize
126 #undef nk_wmask
127}
128#endif
129NK_LIB void
130nk_zero(void *ptr, nk_size size)
131{
132 NK_ASSERT(ptr);
133 NK_MEMSET(ptr, 0, size);
134}
135NK_API int
136nk_strlen(const char *str)
137{
138 int siz = 0;
139 NK_ASSERT(str);
140 while (str && *str++ != '\0') siz++;
141 return siz;
142}
143NK_API int
144nk_strtoi(const char *str, char **endptr)
145{
146 int neg = 1;
147 const char *p = str;
148 int value = 0;
149
150 NK_ASSERT(str);
151 if (!str) return 0;
152
153 /* skip whitespace */
154 while (*p == ' ') p++;
155 if (*p == '-') {
156 neg = -1;
157 p++;
158 }
159 while (*p && *p >= '0' && *p <= '9') {
160 value = value * 10 + (int) (*p - '0');
161 p++;
162 }
163 if (endptr)
164 *endptr = (char *)p;
165 return neg*value;
166}
167NK_API double
168nk_strtod(const char *str, char **endptr)
169{
170 double m;
171 double neg = 1.0;
172 char *p = (char *)str;
173 double value = 0;
174 double number = 0;
175
176 NK_ASSERT(str);
177 if (!str) return 0;
178
179 /* skip whitespace */
180 while (*p == ' ') p++;
181 if (*p == '-') {
182 neg = -1.0;
183 p++;
184 }
185
186 while (*p && *p != '.' && *p != 'e') {
187 value = value * 10.0 + (double) (*p - '0');
188 p++;
189 }
190
191 if (*p == '.') {
192 p++;
193 for(m = 0.1; *p && *p != 'e'; p++ ) {
194 value = value + (double) (*p - '0') * m;
195 m *= 0.1;
196 }
197 }
198 if (*p == 'e') {
199 int i, pow, div;
200 p++;
201 if (*p == '-') {
202 div = nk_true;
203 p++;
204 } else if (*p == '+') {
205 div = nk_false;
206 p++;
207 } else div = nk_false;
208
209 for (pow = 0; *p; p++)
210 pow = pow * 10 + (int) (*p - '0');
211
212 for (m = 1.0, i = 0; i < pow; i++)
213 m *= 10.0;
214
215 if (div)
216 value /= m;
217 else value *= m;
218 }
219 number = value * neg;
220 if (endptr)
221 *endptr = p;
222 return number;
223}
224NK_API float
225nk_strtof(const char *str, char **endptr)
226{
227 float float_value;
228 double double_value;
229 double_value = NK_STRTOD(str, endptr);
230 float_value = (float)double_value;
231 return float_value;
232}
233NK_API int
234nk_stricmp(const char *s1, const char *s2)
235{
236 nk_int c1,c2,d;
237 do {
238 c1 = *s1++;
239 c2 = *s2++;
240 d = c1 - c2;
241 while (d) {
242 if (c1 <= 'Z' && c1 >= 'A') {
243 d += ('a' - 'A');
244 if (!d) break;
245 }
246 if (c2 <= 'Z' && c2 >= 'A') {
247 d -= ('a' - 'A');
248 if (!d) break;
249 }
250 return ((d >= 0) << 1) - 1;
251 }
252 } while (c1);
253 return 0;
254}
255NK_API int
256nk_stricmpn(const char *s1, const char *s2, int n)
257{
258 int c1,c2,d;
259 NK_ASSERT(n >= 0);
260 do {
261 c1 = *s1++;
262 c2 = *s2++;
263 if (!n--) return 0;
264
265 d = c1 - c2;
266 while (d) {
267 if (c1 <= 'Z' && c1 >= 'A') {
268 d += ('a' - 'A');
269 if (!d) break;
270 }
271 if (c2 <= 'Z' && c2 >= 'A') {
272 d -= ('a' - 'A');
273 if (!d) break;
274 }
275 return ((d >= 0) << 1) - 1;
276 }
277 } while (c1);
278 return 0;
279}
280NK_INTERN int
281nk_str_match_here(const char *regexp, const char *text)
282{
283 if (regexp[0] == '\0')
284 return 1;
285 if (regexp[1] == '*')
286 return nk_str_match_star(regexp[0], regexp+2, text);
287 if (regexp[0] == '$' && regexp[1] == '\0')
288 return *text == '\0';
289 if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
290 return nk_str_match_here(regexp+1, text+1);
291 return 0;
292}
293NK_INTERN int
294nk_str_match_star(int c, const char *regexp, const char *text)
295{
296 do {/* a '* matches zero or more instances */
297 if (nk_str_match_here(regexp, text))
298 return 1;
299 } while (*text != '\0' && (*text++ == c || c == '.'));
300 return 0;
301}
302NK_API int
303nk_strfilter(const char *text, const char *regexp)
304{
305 /*
306 c matches any literal character c
307 . matches any single character
308 ^ matches the beginning of the input string
309 $ matches the end of the input string
310 * matches zero or more occurrences of the previous character*/
311 if (regexp[0] == '^')
312 return nk_str_match_here(regexp+1, text);
313 do { /* must look even if string is empty */
314 if (nk_str_match_here(regexp, text))
315 return 1;
316 } while (*text++ != '\0');
317 return 0;
318}
319NK_API int
320nk_strmatch_fuzzy_text(const char *str, int str_len,
321 const char *pattern, int *out_score)
322{
323 /* Returns true if each character in pattern is found sequentially within str
324 * if found then out_score is also set. Score value has no intrinsic meaning.
325 * Range varies with pattern. Can only compare scores with same search pattern. */
326
327 /* bonus for adjacent matches */
328 #define NK_ADJACENCY_BONUS 5
329 /* bonus if match occurs after a separator */
330 #define NK_SEPARATOR_BONUS 10
331 /* bonus if match is uppercase and prev is lower */
332 #define NK_CAMEL_BONUS 10
333 /* penalty applied for every letter in str before the first match */
334 #define NK_LEADING_LETTER_PENALTY (-3)
335 /* maximum penalty for leading letters */
336 #define NK_MAX_LEADING_LETTER_PENALTY (-9)
337 /* penalty for every letter that doesn't matter */
338 #define NK_UNMATCHED_LETTER_PENALTY (-1)
339
340 /* loop variables */
341 int score = 0;
342 char const * pattern_iter = pattern;
343 int str_iter = 0;
344 int prev_matched = nk_false;
345 int prev_lower = nk_false;
346 /* true so if first letter match gets separator bonus*/
347 int prev_separator = nk_true;
348
349 /* use "best" matched letter if multiple string letters match the pattern */
350 char const * best_letter = 0;
351 int best_letter_score = 0;
352
353 /* loop over strings */
354 NK_ASSERT(str);
355 NK_ASSERT(pattern);
356 if (!str || !str_len || !pattern) return 0;
357 while (str_iter < str_len)
358 {
359 const char pattern_letter = *pattern_iter;
360 const char str_letter = str[str_iter];
361
362 int next_match = *pattern_iter != '\0' &&
363 nk_to_lower(pattern_letter) == nk_to_lower(str_letter);
364 int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);
365
366 int advanced = next_match && best_letter;
367 int pattern_repeat = best_letter && *pattern_iter != '\0';
368 pattern_repeat = pattern_repeat &&
369 nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);
370
371 if (advanced || pattern_repeat) {
372 score += best_letter_score;
373 best_letter = 0;
374 best_letter_score = 0;
375 }
376
377 if (next_match || rematch)
378 {
379 int new_score = 0;
380 /* Apply penalty for each letter before the first pattern match */
381 if (pattern_iter == pattern) {
382 int count = (int)(&str[str_iter] - str);
383 int penalty = NK_LEADING_LETTER_PENALTY * count;
384 if (penalty < NK_MAX_LEADING_LETTER_PENALTY)
385 penalty = NK_MAX_LEADING_LETTER_PENALTY;
386
387 score += penalty;
388 }
389
390 /* apply bonus for consecutive bonuses */
391 if (prev_matched)
392 new_score += NK_ADJACENCY_BONUS;
393
394 /* apply bonus for matches after a separator */
395 if (prev_separator)
396 new_score += NK_SEPARATOR_BONUS;
397
398 /* apply bonus across camel case boundaries */
399 if (prev_lower && nk_is_upper(str_letter))
400 new_score += NK_CAMEL_BONUS;
401
402 /* update pattern iter IFF the next pattern letter was matched */
403 if (next_match)
404 ++pattern_iter;
405
406 /* update best letter in str which may be for a "next" letter or a rematch */
407 if (new_score >= best_letter_score) {
408 /* apply penalty for now skipped letter */
409 if (best_letter != 0)
410 score += NK_UNMATCHED_LETTER_PENALTY;
411
412 best_letter = &str[str_iter];
413 best_letter_score = new_score;
414 }
415 prev_matched = nk_true;
416 } else {
417 score += NK_UNMATCHED_LETTER_PENALTY;
418 prev_matched = nk_false;
419 }
420
421 /* separators should be more easily defined */
422 prev_lower = nk_is_lower(str_letter) != 0;
423 prev_separator = str_letter == '_' || str_letter == ' ';
424
425 ++str_iter;
426 }
427
428 /* apply score for last match */
429 if (best_letter)
430 score += best_letter_score;
431
432 /* did not match full pattern */
433 if (*pattern_iter != '\0')
434 return nk_false;
435
436 if (out_score)
437 *out_score = score;
438 return nk_true;
439}
440NK_API int
441nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)
442{
443 return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);
444}
445NK_LIB int
446nk_string_float_limit(char *string, int prec)
447{
448 int dot = 0;
449 char *c = string;
450 while (*c) {
451 if (*c == '.') {
452 dot = 1;
453 c++;
454 continue;
455 }
456 if (dot == (prec+1)) {
457 *c = 0;
458 break;
459 }
460 if (dot > 0) dot++;
461 c++;
462 }
463 return (int)(c - string);
464}
465NK_INTERN void
466nk_strrev_ascii(char *s)
467{
468 int len = nk_strlen(s);
469 int end = len / 2;
470 int i = 0;
471 char t;
472 for (; i < end; ++i) {
473 t = s[i];
474 s[i] = s[len - 1 - i];
475 s[len -1 - i] = t;
476 }
477}
478NK_LIB char*
479nk_itoa(char *s, long n)
480{
481 long i = 0;
482 if (n == 0) {
483 s[i++] = '0';
484 s[i] = 0;
485 return s;
486 }
487 if (n < 0) {
488 s[i++] = '-';
489 n = -n;
490 }
491 while (n > 0) {
492 s[i++] = (char)('0' + (n % 10));
493 n /= 10;
494 }
495 s[i] = 0;
496 if (s[0] == '-')
497 ++s;
498
499 nk_strrev_ascii(s);
500 return s;
501}
502#ifndef NK_DTOA
503#define NK_DTOA nk_dtoa
504NK_LIB char*
505nk_dtoa(char *s, double n)
506{
507 int useExp = 0;
508 int digit = 0, m = 0, m1 = 0;
509 char *c = s;
510 int neg = 0;
511
512 NK_ASSERT(s);
513 if (!s) return 0;
514
515 if (n == 0.0) {
516 s[0] = '0'; s[1] = '\0';
517 return s;
518 }
519
520 neg = (n < 0);
521 if (neg) n = -n;
522
523 /* calculate magnitude */
524 m = nk_log10(n);
525 useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
526 if (neg) *(c++) = '-';
527
528 /* set up for scientific notation */
529 if (useExp) {
530 if (m < 0)
531 m -= 1;
532 n = n / (double)nk_pow(10.0, m);
533 m1 = m;
534 m = 0;
535 }
536 if (m < 1.0) {
537 m = 0;
538 }
539
540 /* convert the number */
541 while (n > NK_FLOAT_PRECISION || m >= 0) {
542 double weight = nk_pow(10.0, m);
543 if (weight > 0) {
544 double t = (double)n / weight;
545 digit = nk_ifloord(t);
546 n -= ((double)digit * weight);
547 *(c++) = (char)('0' + (char)digit);
548 }
549 if (m == 0 && n > 0)
550 *(c++) = '.';
551 m--;
552 }
553
554 if (useExp) {
555 /* convert the exponent */
556 int i, j;
557 *(c++) = 'e';
558 if (m1 > 0) {
559 *(c++) = '+';
560 } else {
561 *(c++) = '-';
562 m1 = -m1;
563 }
564 m = 0;
565 while (m1 > 0) {
566 *(c++) = (char)('0' + (char)(m1 % 10));
567 m1 /= 10;
568 m++;
569 }
570 c -= m;
571 for (i = 0, j = m-1; i<j; i++, j--) {
572 /* swap without temporary */
573 c[i] ^= c[j];
574 c[j] ^= c[i];
575 c[i] ^= c[j];
576 }
577 c += m;
578 }
579 *(c) = '\0';
580 return s;
581}
582#endif
583#ifdef NK_INCLUDE_STANDARD_VARARGS
584#ifndef NK_INCLUDE_STANDARD_IO
585NK_INTERN int
586nk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)
587{
588 enum nk_arg_type {
589 NK_ARG_TYPE_CHAR,
590 NK_ARG_TYPE_SHORT,
591 NK_ARG_TYPE_DEFAULT,
592 NK_ARG_TYPE_LONG
593 };
594 enum nk_arg_flags {
595 NK_ARG_FLAG_LEFT = 0x01,
596 NK_ARG_FLAG_PLUS = 0x02,
597 NK_ARG_FLAG_SPACE = 0x04,
598 NK_ARG_FLAG_NUM = 0x10,
599 NK_ARG_FLAG_ZERO = 0x20
600 };
601
602 char number_buffer[NK_MAX_NUMBER_BUFFER];
603 enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;
604 int precision = NK_DEFAULT;
605 int width = NK_DEFAULT;
606 nk_flags flag = 0;
607
608 int len = 0;
609 int result = -1;
610 const char *iter = fmt;
611
612 NK_ASSERT(buf);
613 NK_ASSERT(buf_size);
614 if (!buf || !buf_size || !fmt) return 0;
615 for (iter = fmt; *iter && len < buf_size; iter++) {
616 /* copy all non-format characters */
617 while (*iter && (*iter != '%') && (len < buf_size))
618 buf[len++] = *iter++;
619 if (!(*iter) || len >= buf_size) break;
620 iter++;
621
622 /* flag arguments */
623 while (*iter) {
624 if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;
625 else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;
626 else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;
627 else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;
628 else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;
629 else break;
630 iter++;
631 }
632
633 /* width argument */
634 width = NK_DEFAULT;
635 if (*iter >= '1' && *iter <= '9') {
636 char *end;
637 width = nk_strtoi(iter, &end);
638 if (end == iter)
639 width = -1;
640 else iter = end;
641 } else if (*iter == '*') {
642 width = va_arg(args, int);
643 iter++;
644 }
645
646 /* precision argument */
647 precision = NK_DEFAULT;
648 if (*iter == '.') {
649 iter++;
650 if (*iter == '*') {
651 precision = va_arg(args, int);
652 iter++;
653 } else {
654 char *end;
655 precision = nk_strtoi(iter, &end);
656 if (end == iter)
657 precision = -1;
658 else iter = end;
659 }
660 }
661
662 /* length modifier */
663 if (*iter == 'h') {
664 if (*(iter+1) == 'h') {
665 arg_type = NK_ARG_TYPE_CHAR;
666 iter++;
667 } else arg_type = NK_ARG_TYPE_SHORT;
668 iter++;
669 } else if (*iter == 'l') {
670 arg_type = NK_ARG_TYPE_LONG;
671 iter++;
672 } else arg_type = NK_ARG_TYPE_DEFAULT;
673
674 /* specifier */
675 if (*iter == '%') {
676 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
677 NK_ASSERT(precision == NK_DEFAULT);
678 NK_ASSERT(width == NK_DEFAULT);
679 if (len < buf_size)
680 buf[len++] = '%';
681 } else if (*iter == 's') {
682 /* string */
683 const char *str = va_arg(args, const char*);
684 NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!");
685 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
686 NK_ASSERT(precision == NK_DEFAULT);
687 NK_ASSERT(width == NK_DEFAULT);
688 if (str == buf) return -1;
689 while (str && *str && len < buf_size)
690 buf[len++] = *str++;
691 } else if (*iter == 'n') {
692 /* current length callback */
693 signed int *n = va_arg(args, int*);
694 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
695 NK_ASSERT(precision == NK_DEFAULT);
696 NK_ASSERT(width == NK_DEFAULT);
697 if (n) *n = len;
698 } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {
699 /* signed integer */
700 long value = 0;
701 const char *num_iter;
702 int num_len, num_print, padding;
703 int cur_precision = NK_MAX(precision, 1);
704 int cur_width = NK_MAX(width, 0);
705
706 /* retrieve correct value type */
707 if (arg_type == NK_ARG_TYPE_CHAR)
708 value = (signed char)va_arg(args, int);
709 else if (arg_type == NK_ARG_TYPE_SHORT)
710 value = (signed short)va_arg(args, int);
711 else if (arg_type == NK_ARG_TYPE_LONG)
712 value = va_arg(args, signed long);
713 else if (*iter == 'c')
714 value = (unsigned char)va_arg(args, int);
715 else value = va_arg(args, signed int);
716
717 /* convert number to string */
718 nk_itoa(number_buffer, value);
719 num_len = nk_strlen(number_buffer);
720 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
721 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
722 padding = NK_MAX(padding-1, 0);
723
724 /* fill left padding up to a total of `width` characters */
725 if (!(flag & NK_ARG_FLAG_LEFT)) {
726 while (padding-- > 0 && (len < buf_size)) {
727 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
728 buf[len++] = '0';
729 else buf[len++] = ' ';
730 }
731 }
732
733 /* copy string value representation into buffer */
734 if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)
735 buf[len++] = '+';
736 else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)
737 buf[len++] = ' ';
738
739 /* fill up to precision number of digits with '0' */
740 num_print = NK_MAX(cur_precision, num_len);
741 while (precision && (num_print > num_len) && (len < buf_size)) {
742 buf[len++] = '0';
743 num_print--;
744 }
745
746 /* copy string value representation into buffer */
747 num_iter = number_buffer;
748 while (precision && *num_iter && len < buf_size)
749 buf[len++] = *num_iter++;
750
751 /* fill right padding up to width characters */
752 if (flag & NK_ARG_FLAG_LEFT) {
753 while ((padding-- > 0) && (len < buf_size))
754 buf[len++] = ' ';
755 }
756 } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {
757 /* unsigned integer */
758 unsigned long value = 0;
759 int num_len = 0, num_print, padding = 0;
760 int cur_precision = NK_MAX(precision, 1);
761 int cur_width = NK_MAX(width, 0);
762 unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;
763
764 /* print oct/hex/dec value */
765 const char *upper_output_format = "0123456789ABCDEF";
766 const char *lower_output_format = "0123456789abcdef";
767 const char *output_format = (*iter == 'x') ?
768 lower_output_format: upper_output_format;
769
770 /* retrieve correct value type */
771 if (arg_type == NK_ARG_TYPE_CHAR)
772 value = (unsigned char)va_arg(args, int);
773 else if (arg_type == NK_ARG_TYPE_SHORT)
774 value = (unsigned short)va_arg(args, int);
775 else if (arg_type == NK_ARG_TYPE_LONG)
776 value = va_arg(args, unsigned long);
777 else value = va_arg(args, unsigned int);
778
779 do {
780 /* convert decimal number into hex/oct number */
781 int digit = output_format[value % base];
782 if (num_len < NK_MAX_NUMBER_BUFFER)
783 number_buffer[num_len++] = (char)digit;
784 value /= base;
785 } while (value > 0);
786
787 num_print = NK_MAX(cur_precision, num_len);
788 padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);
789 if (flag & NK_ARG_FLAG_NUM)
790 padding = NK_MAX(padding-1, 0);
791
792 /* fill left padding up to a total of `width` characters */
793 if (!(flag & NK_ARG_FLAG_LEFT)) {
794 while ((padding-- > 0) && (len < buf_size)) {
795 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
796 buf[len++] = '0';
797 else buf[len++] = ' ';
798 }
799 }
800
801 /* fill up to precision number of digits */
802 if (num_print && (flag & NK_ARG_FLAG_NUM)) {
803 if ((*iter == 'o') && (len < buf_size)) {
804 buf[len++] = '0';
805 } else if ((*iter == 'x') && ((len+1) < buf_size)) {
806 buf[len++] = '0';
807 buf[len++] = 'x';
808 } else if ((*iter == 'X') && ((len+1) < buf_size)) {
809 buf[len++] = '0';
810 buf[len++] = 'X';
811 }
812 }
813 while (precision && (num_print > num_len) && (len < buf_size)) {
814 buf[len++] = '0';
815 num_print--;
816 }
817
818 /* reverse number direction */
819 while (num_len > 0) {
820 if (precision && (len < buf_size))
821 buf[len++] = number_buffer[num_len-1];
822 num_len--;
823 }
824
825 /* fill right padding up to width characters */
826 if (flag & NK_ARG_FLAG_LEFT) {
827 while ((padding-- > 0) && (len < buf_size))
828 buf[len++] = ' ';
829 }
830 } else if (*iter == 'f') {
831 /* floating point */
832 const char *num_iter;
833 int cur_precision = (precision < 0) ? 6: precision;
834 int prefix, cur_width = NK_MAX(width, 0);
835 double value = va_arg(args, double);
836 int num_len = 0, frac_len = 0, dot = 0;
837 int padding = 0;
838
839 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
840 NK_DTOA(number_buffer, value);
841 num_len = nk_strlen(number_buffer);
842
843 /* calculate padding */
844 num_iter = number_buffer;
845 while (*num_iter && *num_iter != '.')
846 num_iter++;
847
848 prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;
849 padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);
850 if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))
851 padding = NK_MAX(padding-1, 0);
852
853 /* fill left padding up to a total of `width` characters */
854 if (!(flag & NK_ARG_FLAG_LEFT)) {
855 while (padding-- > 0 && (len < buf_size)) {
856 if (flag & NK_ARG_FLAG_ZERO)
857 buf[len++] = '0';
858 else buf[len++] = ' ';
859 }
860 }
861
862 /* copy string value representation into buffer */
863 num_iter = number_buffer;
864 if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))
865 buf[len++] = '+';
866 else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))
867 buf[len++] = ' ';
868 while (*num_iter) {
869 if (dot) frac_len++;
870 if (len < buf_size)
871 buf[len++] = *num_iter;
872 if (*num_iter == '.') dot = 1;
873 if (frac_len >= cur_precision) break;
874 num_iter++;
875 }
876
877 /* fill number up to precision */
878 while (frac_len < cur_precision) {
879 if (!dot && len < buf_size) {
880 buf[len++] = '.';
881 dot = 1;
882 }
883 if (len < buf_size)
884 buf[len++] = '0';
885 frac_len++;
886 }
887
888 /* fill right padding up to width characters */
889 if (flag & NK_ARG_FLAG_LEFT) {
890 while ((padding-- > 0) && (len < buf_size))
891 buf[len++] = ' ';
892 }
893 } else {
894 /* Specifier not supported: g,G,e,E,p,z */
895 NK_ASSERT(0 && "specifier is not supported!");
896 return result;
897 }
898 }
899 buf[(len >= buf_size)?(buf_size-1):len] = 0;
900 result = (len >= buf_size)?-1:len;
901 return result;
902}
903#endif
904NK_LIB int
905nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)
906{
907 int result = -1;
908 NK_ASSERT(buf);
909 NK_ASSERT(buf_size);
910 if (!buf || !buf_size || !fmt) return 0;
911#ifdef NK_INCLUDE_STANDARD_IO
912 result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);
913 result = (result >= buf_size) ? -1: result;
914 buf[buf_size-1] = 0;
915#else
916 result = nk_vsnprintf(buf, buf_size, fmt, args);
917#endif
918 return result;
919}
920#endif
921NK_API nk_hash
922nk_murmur_hash(const void * key, int len, nk_hash seed)
923{
924 /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/
925 #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))
926
927 nk_uint h1 = seed;
928 nk_uint k1;
929 const nk_byte *data = (const nk_byte*)key;
930 const nk_byte *keyptr = data;
931 nk_byte *k1ptr;
932 const int bsize = sizeof(k1);
933 const int nblocks = len/4;
934
935 const nk_uint c1 = 0xcc9e2d51;
936 const nk_uint c2 = 0x1b873593;
937 const nk_byte *tail;
938 int i;
939
940 /* body */
941 if (!key) return 0;
942 for (i = 0; i < nblocks; ++i, keyptr += bsize) {
943 k1ptr = (nk_byte*)&k1;
944 k1ptr[0] = keyptr[0];
945 k1ptr[1] = keyptr[1];
946 k1ptr[2] = keyptr[2];
947 k1ptr[3] = keyptr[3];
948
949 k1 *= c1;
950 k1 = NK_ROTL(k1,15);
951 k1 *= c2;
952
953 h1 ^= k1;
954 h1 = NK_ROTL(h1,13);
955 h1 = h1*5+0xe6546b64;
956 }
957
958 /* tail */
959 tail = (const nk_byte*)(data + nblocks*4);
960 k1 = 0;
961 switch (len & 3) {
962 case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */
963 case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */
964 case 1: k1 ^= tail[0];
965 k1 *= c1;
966 k1 = NK_ROTL(k1,15);
967 k1 *= c2;
968 h1 ^= k1;
969 break;
970 default: break;
971 }
972
973 /* finalization */
974 h1 ^= (nk_uint)len;
975 /* fmix32 */
976 h1 ^= h1 >> 16;
977 h1 *= 0x85ebca6b;
978 h1 ^= h1 >> 13;
979 h1 *= 0xc2b2ae35;
980 h1 ^= h1 >> 16;
981
982 #undef NK_ROTL
983 return h1;
984}
985#ifdef NK_INCLUDE_STANDARD_IO
986NK_LIB char*
987nk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc)
988{
989 char *buf;
990 FILE *fd;
991 long ret;
992
993 NK_ASSERT(path);
994 NK_ASSERT(siz);
995 NK_ASSERT(alloc);
996 if (!path || !siz || !alloc)
997 return 0;
998
999 fd = fopen(path, "rb");
1000 if (!fd) return 0;
1001 fseek(fd, 0, SEEK_END);
1002 ret = ftell(fd);
1003 if (ret < 0) {
1004 fclose(fd);
1005 return 0;
1006 }
1007 *siz = (nk_size)ret;
1008 fseek(fd, 0, SEEK_SET);
1009 buf = (char*)alloc->alloc(alloc->userdata,0, *siz);
1010 NK_ASSERT(buf);
1011 if (!buf) {
1012 fclose(fd);
1013 return 0;
1014 }
1015 *siz = (nk_size)fread(buf, 1,*siz, fd);
1016 fclose(fd);
1017 return buf;
1018}
1019#endif
1020NK_LIB int
1021nk_text_clamp(const struct nk_user_font *font, const char *text,
1022 int text_len, float space, int *glyphs, float *text_width,
1023 nk_rune *sep_list, int sep_count)
1024{
1025 int i = 0;
1026 int glyph_len = 0;
1027 float last_width = 0;
1028 nk_rune unicode = 0;
1029 float width = 0;
1030 int len = 0;
1031 int g = 0;
1032 float s;
1033
1034 int sep_len = 0;
1035 int sep_g = 0;
1036 float sep_width = 0;
1037 sep_count = NK_MAX(sep_count,0);
1038
1039 glyph_len = nk_utf_decode(text, &unicode, text_len);
1040 while (glyph_len && (width < space) && (len < text_len)) {
1041 len += glyph_len;
1042 s = font->width(font->userdata, font->height, text, len);
1043 for (i = 0; i < sep_count; ++i) {
1044 if (unicode != sep_list[i]) continue;
1045 sep_width = last_width = width;
1046 sep_g = g+1;
1047 sep_len = len;
1048 break;
1049 }
1050 if (i == sep_count){
1051 last_width = sep_width = width;
1052 sep_g = g+1;
1053 }
1054 width = s;
1055 glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);
1056 g++;
1057 }
1058 if (len >= text_len) {
1059 *glyphs = g;
1060 *text_width = last_width;
1061 return len;
1062 } else {
1063 *glyphs = sep_g;
1064 *text_width = sep_width;
1065 return (!sep_len) ? len: sep_len;
1066 }
1067}
1068NK_LIB struct nk_vec2
1069nk_text_calculate_text_bounds(const struct nk_user_font *font,
1070 const char *begin, int byte_len, float row_height, const char **remaining,
1071 struct nk_vec2 *out_offset, int *glyphs, int op)
1072{
1073 float line_height = row_height;
1074 struct nk_vec2 text_size = nk_vec2(0,0);
1075 float line_width = 0.0f;
1076
1077 float glyph_width;
1078 int glyph_len = 0;
1079 nk_rune unicode = 0;
1080 int text_len = 0;
1081 if (!begin || byte_len <= 0 || !font)
1082 return nk_vec2(0,row_height);
1083
1084 glyph_len = nk_utf_decode(begin, &unicode, byte_len);
1085 if (!glyph_len) return text_size;
1086 glyph_width = font->width(font->userdata, font->height, begin, glyph_len);
1087
1088 *glyphs = 0;
1089 while ((text_len < byte_len) && glyph_len) {
1090 if (unicode == '\n') {
1091 text_size.x = NK_MAX(text_size.x, line_width);
1092 text_size.y += line_height;
1093 line_width = 0;
1094 *glyphs+=1;
1095 if (op == NK_STOP_ON_NEW_LINE)
1096 break;
1097
1098 text_len++;
1099 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
1100 continue;
1101 }
1102
1103 if (unicode == '\r') {
1104 text_len++;
1105 *glyphs+=1;
1106 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
1107 continue;
1108 }
1109
1110 *glyphs = *glyphs + 1;
1111 text_len += glyph_len;
1112 line_width += (float)glyph_width;
1113 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
1114 glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);
1115 continue;
1116 }
1117
1118 if (text_size.x < line_width)
1119 text_size.x = line_width;
1120 if (out_offset)
1121 *out_offset = nk_vec2(line_width, text_size.y + line_height);
1122 if (line_width > 0 || text_size.y == 0.0f)
1123 text_size.y += line_height;
1124 if (remaining)
1125 *remaining = begin+text_len;
1126 return text_size;
1127}
1128
main API and documentation file
nk_text_width_f width
!< max height of the font
Definition nuklear.h:4009
float height
!< user provided font handle
Definition nuklear.h:4008