2#include "nuklear_internal.h"
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;}
17#define NK_MEMCPY nk_memcopy
19nk_memcopy(
void *dst0,
const void *src0, nk_size length)
22 char *dst = (
char*)dst0;
23 const char *src = (
const char*)src0;
24 if (length == 0 || dst == src)
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)
35 if ((t | (nk_ptr)dst) & nk_wmask) {
36 if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)
39 t = nk_wsize - (t & nk_wmask);
41 NK_TLOOP1(*dst++ = *src++);
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++);
52 if ((t | (nk_ptr)dst) & nk_wmask) {
53 if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)
58 NK_TLOOP1(*--dst = *--src);
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);
76#define NK_MEMSET nk_memset
78nk_memset(
void *ptr,
int c0, nk_size size)
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;
87 if ((c = (nk_byte)c0) != 0) {
89 if (
sizeof(
unsigned int) > 2)
95 if (size < 3 * nk_wsize) {
96 while (size--) *dst++ = (nk_byte)c0;
101 if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {
105 *dst++ = (nk_byte)c0;
112 *(nk_word*)((
void*)dst) = c;
117 t = (size & nk_wmask);
120 *dst++ = (nk_byte)c0;
130nk_zero(
void *ptr, nk_size size)
133 NK_MEMSET(ptr, 0, size);
136nk_strlen(
const char *str)
140 while (str && *str++ !=
'\0') siz++;
144nk_strtoi(
const char *str,
char **endptr)
154 while (*p ==
' ') p++;
159 while (*p && *p >=
'0' && *p <=
'9') {
160 value = value * 10 + (int) (*p -
'0');
168nk_strtod(
const char *str,
char **endptr)
172 char *p = (
char *)str;
180 while (*p ==
' ') p++;
186 while (*p && *p !=
'.' && *p !=
'e') {
187 value = value * 10.0 + (double) (*p -
'0');
193 for(m = 0.1; *p && *p !=
'e'; p++ ) {
194 value = value + (double) (*p -
'0') * m;
204 }
else if (*p ==
'+') {
207 }
else div = nk_false;
209 for (pow = 0; *p; p++)
210 pow = pow * 10 + (
int) (*p -
'0');
212 for (m = 1.0, i = 0; i < pow; i++)
219 number = value * neg;
225nk_strtof(
const char *str,
char **endptr)
229 double_value = NK_STRTOD(str, endptr);
230 float_value = (float)double_value;
234nk_stricmp(
const char *s1,
const char *s2)
242 if (c1 <=
'Z' && c1 >=
'A') {
246 if (c2 <=
'Z' && c2 >=
'A') {
250 return ((d >= 0) << 1) - 1;
256nk_stricmpn(
const char *s1,
const char *s2,
int n)
267 if (c1 <=
'Z' && c1 >=
'A') {
271 if (c2 <=
'Z' && c2 >=
'A') {
275 return ((d >= 0) << 1) - 1;
281nk_str_match_here(
const char *regexp,
const char *text)
283 if (regexp[0] ==
'\0')
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);
294nk_str_match_star(
int c,
const char *regexp,
const char *text)
297 if (nk_str_match_here(regexp, text))
299 }
while (*text !=
'\0' && (*text++ == c || c ==
'.'));
303nk_strfilter(
const char *text,
const char *regexp)
311 if (regexp[0] ==
'^')
312 return nk_str_match_here(regexp+1, text);
314 if (nk_str_match_here(regexp, text))
316 }
while (*text++ !=
'\0');
320nk_strmatch_fuzzy_text(
const char *str,
int str_len,
321 const char *pattern,
int *out_score)
328 #define NK_ADJACENCY_BONUS 5
330 #define NK_SEPARATOR_BONUS 10
332 #define NK_CAMEL_BONUS 10
334 #define NK_LEADING_LETTER_PENALTY (-3)
336 #define NK_MAX_LEADING_LETTER_PENALTY (-9)
338 #define NK_UNMATCHED_LETTER_PENALTY (-1)
342 char const * pattern_iter = pattern;
344 int prev_matched = nk_false;
345 int prev_lower = nk_false;
347 int prev_separator = nk_true;
350 char const * best_letter = 0;
351 int best_letter_score = 0;
356 if (!str || !str_len || !pattern)
return 0;
357 while (str_iter < str_len)
359 const char pattern_letter = *pattern_iter;
360 const char str_letter = str[str_iter];
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);
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);
371 if (advanced || pattern_repeat) {
372 score += best_letter_score;
374 best_letter_score = 0;
377 if (next_match || rematch)
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;
392 new_score += NK_ADJACENCY_BONUS;
396 new_score += NK_SEPARATOR_BONUS;
399 if (prev_lower && nk_is_upper(str_letter))
400 new_score += NK_CAMEL_BONUS;
407 if (new_score >= best_letter_score) {
409 if (best_letter != 0)
410 score += NK_UNMATCHED_LETTER_PENALTY;
412 best_letter = &str[str_iter];
413 best_letter_score = new_score;
415 prev_matched = nk_true;
417 score += NK_UNMATCHED_LETTER_PENALTY;
418 prev_matched = nk_false;
422 prev_lower = nk_is_lower(str_letter) != 0;
423 prev_separator = str_letter ==
'_' || str_letter ==
' ';
430 score += best_letter_score;
433 if (*pattern_iter !=
'\0')
441nk_strmatch_fuzzy_string(
char const *str,
char const *pattern,
int *out_score)
443 return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);
446nk_string_float_limit(
char *
string,
int prec)
456 if (dot == (prec+1)) {
463 return (
int)(c - string);
466nk_strrev_ascii(
char *s)
468 int len = nk_strlen(s);
472 for (; i < end; ++i) {
474 s[i] = s[len - 1 - i];
479nk_itoa(
char *s,
long n)
492 s[i++] = (char)(
'0' + (n % 10));
503#define NK_DTOA nk_dtoa
505nk_dtoa(
char *s,
double n)
508 int digit = 0, m = 0, m1 = 0;
516 s[0] =
'0'; s[1] =
'\0';
525 useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
526 if (neg) *(c++) =
'-';
532 n = n / (double)nk_pow(10.0, m);
541 while (n > NK_FLOAT_PRECISION || m >= 0) {
542 double weight = nk_pow(10.0, m);
544 double t = (double)n / weight;
545 digit = nk_ifloord(t);
546 n -= ((double)digit * weight);
547 *(c++) = (
char)(
'0' + (char)digit);
566 *(c++) = (
char)(
'0' + (char)(m1 % 10));
571 for (i = 0, j = m-1; i<j; i++, j--) {
583#ifdef NK_INCLUDE_STANDARD_VARARGS
584#ifndef NK_INCLUDE_STANDARD_IO
586nk_vsnprintf(
char *buf,
int buf_size,
const char *fmt, va_list args)
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
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;
610 const char *iter = fmt;
614 if (!buf || !buf_size || !fmt)
return 0;
615 for (iter = fmt; *iter && len < buf_size; iter++) {
617 while (*iter && (*iter !=
'%') && (len < buf_size))
618 buf[len++] = *iter++;
619 if (!(*iter) || len >= buf_size)
break;
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;
635 if (*iter >=
'1' && *iter <=
'9') {
637 width = nk_strtoi(iter, &end);
641 }
else if (*iter ==
'*') {
642 width = va_arg(args,
int);
647 precision = NK_DEFAULT;
651 precision = va_arg(args,
int);
655 precision = nk_strtoi(iter, &end);
664 if (*(iter+1) ==
'h') {
665 arg_type = NK_ARG_TYPE_CHAR;
667 }
else arg_type = NK_ARG_TYPE_SHORT;
669 }
else if (*iter ==
'l') {
670 arg_type = NK_ARG_TYPE_LONG;
672 }
else arg_type = NK_ARG_TYPE_DEFAULT;
676 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
677 NK_ASSERT(precision == NK_DEFAULT);
678 NK_ASSERT(width == NK_DEFAULT);
681 }
else if (*iter ==
's') {
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)
691 }
else if (*iter ==
'n') {
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);
698 }
else if (*iter ==
'c' || *iter ==
'i' || *iter ==
'd') {
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);
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);
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);
725 if (!(flag & NK_ARG_FLAG_LEFT)) {
726 while (padding-- > 0 && (len < buf_size)) {
727 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
729 else buf[len++] =
' ';
734 if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)
736 else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)
740 num_print = NK_MAX(cur_precision, num_len);
741 while (precision && (num_print > num_len) && (len < buf_size)) {
747 num_iter = number_buffer;
748 while (precision && *num_iter && len < buf_size)
749 buf[len++] = *num_iter++;
752 if (flag & NK_ARG_FLAG_LEFT) {
753 while ((padding-- > 0) && (len < buf_size))
756 }
else if (*iter ==
'o' || *iter ==
'x' || *iter ==
'X' || *iter ==
'u') {
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;
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;
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);
781 int digit = output_format[value % base];
782 if (num_len < NK_MAX_NUMBER_BUFFER)
783 number_buffer[num_len++] = (char)digit;
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);
793 if (!(flag & NK_ARG_FLAG_LEFT)) {
794 while ((padding-- > 0) && (len < buf_size)) {
795 if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))
797 else buf[len++] =
' ';
802 if (num_print && (flag & NK_ARG_FLAG_NUM)) {
803 if ((*iter ==
'o') && (len < buf_size)) {
805 }
else if ((*iter ==
'x') && ((len+1) < buf_size)) {
808 }
else if ((*iter ==
'X') && ((len+1) < buf_size)) {
813 while (precision && (num_print > num_len) && (len < buf_size)) {
819 while (num_len > 0) {
820 if (precision && (len < buf_size))
821 buf[len++] = number_buffer[num_len-1];
826 if (flag & NK_ARG_FLAG_LEFT) {
827 while ((padding-- > 0) && (len < buf_size))
830 }
else if (*iter ==
'f') {
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;
839 NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);
840 NK_DTOA(number_buffer, value);
841 num_len = nk_strlen(number_buffer);
844 num_iter = number_buffer;
845 while (*num_iter && *num_iter !=
'.')
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);
854 if (!(flag & NK_ARG_FLAG_LEFT)) {
855 while (padding-- > 0 && (len < buf_size)) {
856 if (flag & NK_ARG_FLAG_ZERO)
858 else buf[len++] =
' ';
863 num_iter = number_buffer;
864 if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))
866 else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))
871 buf[len++] = *num_iter;
872 if (*num_iter ==
'.') dot = 1;
873 if (frac_len >= cur_precision)
break;
878 while (frac_len < cur_precision) {
879 if (!dot && len < buf_size) {
889 if (flag & NK_ARG_FLAG_LEFT) {
890 while ((padding-- > 0) && (len < buf_size))
895 NK_ASSERT(0 &&
"specifier is not supported!");
899 buf[(len >= buf_size)?(buf_size-1):len] = 0;
900 result = (len >= buf_size)?-1:len;
905nk_strfmt(
char *buf,
int buf_size,
const char *fmt, va_list args)
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;
916 result = nk_vsnprintf(buf, buf_size, fmt, args);
922nk_murmur_hash(
const void * key,
int len, nk_hash seed)
925 #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))
929 const nk_byte *data = (
const nk_byte*)key;
930 const nk_byte *keyptr = data;
932 const int bsize =
sizeof(k1);
933 const int nblocks = len/4;
935 const nk_uint c1 = 0xcc9e2d51;
936 const nk_uint c2 = 0x1b873593;
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];
955 h1 = h1*5+0xe6546b64;
959 tail = (
const nk_byte*)(data + nblocks*4);
962 case 3: k1 ^= (nk_uint)(tail[2] << 16);
963 case 2: k1 ^= (nk_uint)(tail[1] << 8u);
964 case 1: k1 ^= tail[0];
985#ifdef NK_INCLUDE_STANDARD_IO
987nk_file_load(
const char* path, nk_size* siz,
const struct nk_allocator *alloc)
996 if (!path || !siz || !alloc)
999 fd = fopen(path,
"rb");
1001 fseek(fd, 0, SEEK_END);
1007 *siz = (nk_size)ret;
1008 fseek(fd, 0, SEEK_SET);
1009 buf = (
char*)alloc->alloc(alloc->userdata,0, *siz);
1015 *siz = (nk_size)fread(buf, 1,*siz, fd);
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)
1027 float last_width = 0;
1028 nk_rune unicode = 0;
1036 float sep_width = 0;
1037 sep_count = NK_MAX(sep_count,0);
1039 glyph_len = nk_utf_decode(text, &unicode, text_len);
1040 while (glyph_len && (width < space) && (len < text_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;
1050 if (i == sep_count){
1051 last_width = sep_width = width;
1055 glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);
1058 if (len >= text_len) {
1060 *text_width = last_width;
1064 *text_width = sep_width;
1065 return (!sep_len) ? len: sep_len;
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)
1073 float line_height = row_height;
1075 float line_width = 0.0f;
1079 nk_rune unicode = 0;
1081 if (!begin || byte_len <= 0 || !font)
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);
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;
1095 if (op == NK_STOP_ON_NEW_LINE)
1099 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
1103 if (unicode ==
'\r') {
1106 glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);
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);
1118 if (text_size.x < line_width)
1119 text_size.x = line_width;
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;
1125 *remaining = begin+text_len;
main API and documentation file
nk_text_width_f width
!< max height of the font
float height
!< user provided font handle