From 7a8e8aa3fc6afc49c279ecfdf932e91bbddb66b8 Mon Sep 17 00:00:00 2001 From: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> Date: Tue, 18 Nov 2025 20:34:29 +0100 Subject: [PATCH 1/4] fix(nk_property): nk_do_property now uses NK_STRTOD via macro nk_do_property was using 'nk_strtod' instead of 'NK_STRTOD' which was not picking the user-provided implementation of NK_STRTOD Fixes: https://github.com/Immediate-Mode-UI/Nuklear/issues/851 --- nuklear.h | 3 ++- src/CHANGELOG | 1 + src/nuklear_property.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nuklear.h b/nuklear.h index 1b13281f..52aba17a 100644 --- a/nuklear.h +++ b/nuklear.h @@ -28950,7 +28950,7 @@ nk_do_property(nk_flags *ws, break; case NK_PROPERTY_DOUBLE: nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.d = nk_strtod(buffer, 0); + variant->value.d = NK_STRTOD(buffer, 0); variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); break; } @@ -30731,6 +30731,7 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) /// - [y]: Minor version with non-breaking API and library changes /// - [z]: Patch version with no direct changes to the API /// +/// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/CHANGELOG b/src/CHANGELOG index 8de53d80..242f8f4e 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -7,6 +7,7 @@ /// - [y]: Minor version with non-breaking API and library changes /// - [z]: Patch version with no direct changes to the API /// +/// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/nuklear_property.c b/src/nuklear_property.c index 668b78c8..6f9eff69 100644 --- a/src/nuklear_property.c +++ b/src/nuklear_property.c @@ -282,7 +282,7 @@ nk_do_property(nk_flags *ws, break; case NK_PROPERTY_DOUBLE: nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.d = nk_strtod(buffer, 0); + variant->value.d = NK_STRTOD(buffer, 0); variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); break; } From 52e75563406e78d5ef93ebd11dfcceebac77906f Mon Sep 17 00:00:00 2001 From: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:03:17 +0100 Subject: [PATCH 2/4] fix(build): failure do build from nuklear/src/* sources This fixes an issue, where you would not be able to build Nuklear from sources (without amalgamated header), caused by nuklear_math/util.c not declaring some function definitions, due to wrong preprocessor logic. This fix is an "Option 3" mentioned in following comment... https://github.com/Immediate-Mode-UI/Nuklear/issues/256#issuecomment-2949725477 ... where we define additional macro at definition (e.g. FOO_IMPLEMENTATION) so the preprocessor will be able to correctly detect it in all cases. Fixes: https://github.com/Immediate-Mode-UI/Nuklear/issues/256 --- nuklear.h | 40 ++++++++++++++++++++++++---------------- src/CHANGELOG | 2 ++ src/nuklear_internal.h | 16 ++++++++++++++++ src/nuklear_math.c | 15 +++++---------- src/nuklear_util.c | 9 +++------ 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/nuklear.h b/nuklear.h index 52aba17a..ae33bd98 100644 --- a/nuklear.h +++ b/nuklear.h @@ -6146,18 +6146,28 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; /* math */ #ifndef NK_INV_SQRT +#define NK_INV_SQRT nk_inv_sqrt +#define NK_INV_SQRT_IMPLEMENTATION NK_LIB float nk_inv_sqrt(float n); #endif #ifndef NK_SIN +#define NK_SIN nk_sin +#define NK_SIN_IMPLEMENTATION NK_LIB float nk_sin(float x); #endif #ifndef NK_COS +#define NK_COS nk_cos +#define NK_COS_IMPLEMENTATION NK_LIB float nk_cos(float x); #endif #ifndef NK_ATAN +#define NK_ATAN nk_atan +#define NK_ATAN_IMPLEMENTATION NK_LIB float nk_atan(float x); #endif #ifndef NK_ATAN2 +#define NK_ATAN2 nk_atan2 +#define NK_ATAN2_IMPLEMENTATION NK_LIB float nk_atan2(float y, float x); #endif NK_LIB nk_uint nk_round_up_pow2(nk_uint v); @@ -6179,15 +6189,21 @@ NK_LIB int nk_to_upper(int c); NK_LIB int nk_to_lower(int c); #ifndef NK_MEMCPY +#define NK_MEMCPY nk_memcopy +#define NK_MEMCPY_IMPLEMENTATION NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n); #endif #ifndef NK_MEMSET +#define NK_MEMSET nk_memset +#define NK_MEMSET_IMPLEMENTATION NK_LIB void nk_memset(void *ptr, int c0, nk_size size); #endif NK_LIB void nk_zero(void *ptr, nk_size size); NK_LIB char *nk_itoa(char *s, long n); NK_LIB int nk_string_float_limit(char *string, int prec); #ifndef NK_DTOA +#define NK_DTOA nk_dtoa +#define NK_DTOA_IMPLEMENTATION NK_LIB char *nk_dtoa(char *s, double n); #endif NK_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); @@ -6463,8 +6479,7 @@ nk_stbtt_free(void *ptr, void *user_data) { /// (it can actually approximate a lot more functions) can be /// found here: www.lolengine.net/wiki/oss/lolremez */ -#ifndef NK_INV_SQRT -#define NK_INV_SQRT nk_inv_sqrt +#ifdef NK_INV_SQRT_IMPLEMENTATION NK_LIB float nk_inv_sqrt(float n) { @@ -6478,8 +6493,7 @@ nk_inv_sqrt(float n) return conv.f; } #endif -#ifndef NK_SIN -#define NK_SIN nk_sin +#ifdef NK_SIN_IMPLEMENTATION NK_LIB float nk_sin(float x) { @@ -6494,8 +6508,7 @@ nk_sin(float x) return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); } #endif -#ifndef NK_COS -#define NK_COS nk_cos +#ifdef NK_COS_IMPLEMENTATION NK_LIB float nk_cos(float x) { @@ -6513,8 +6526,7 @@ nk_cos(float x) return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8))))))); } #endif -#ifndef NK_ATAN -#define NK_ATAN nk_atan +#ifdef NK_ATAN_IMPLEMENTATION NK_LIB float nk_atan(float x) { @@ -6533,8 +6545,7 @@ nk_atan(float x) return u; } #endif -#ifndef NK_ATAN2 -#define NK_ATAN2 nk_atan2 +#ifdef NK_ATAN2_IMPLEMENTATION NK_LIB float nk_atan2(float y, float x) { @@ -6797,8 +6808,7 @@ NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} -#ifndef NK_MEMCPY -#define NK_MEMCPY nk_memcopy +#ifdef NK_MEMCPY_IMPLEMENTATION NK_LIB void* nk_memcopy(void *dst0, const void *src0, nk_size length) { @@ -6856,8 +6866,7 @@ nk_memcopy(void *dst0, const void *src0, nk_size length) return (dst0); } #endif -#ifndef NK_MEMSET -#define NK_MEMSET nk_memset +#ifdef NK_MEMSET_IMPLEMENTATION NK_LIB void nk_memset(void *ptr, int c0, nk_size size) { @@ -7283,8 +7292,7 @@ nk_itoa(char *s, long n) nk_strrev_ascii(s); return s; } -#ifndef NK_DTOA -#define NK_DTOA nk_dtoa +#ifdef NK_DTOA_IMPLEMENTATION NK_LIB char* nk_dtoa(char *s, double n) { diff --git a/src/CHANGELOG b/src/CHANGELOG index 242f8f4e..17507f8e 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -8,6 +8,8 @@ /// - [z]: Patch version with no direct changes to the API /// /// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro +/// - Fix: failure to build from source, due to +/// nuklear_math/util.c not declaring some functions /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/nuklear_internal.h b/src/nuklear_internal.h index a1523e8e..c6e5a579 100644 --- a/src/nuklear_internal.h +++ b/src/nuklear_internal.h @@ -95,18 +95,28 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; /* math */ #ifndef NK_INV_SQRT +#define NK_INV_SQRT nk_inv_sqrt +#define NK_INV_SQRT_IMPLEMENTATION NK_LIB float nk_inv_sqrt(float n); #endif #ifndef NK_SIN +#define NK_SIN nk_sin +#define NK_SIN_IMPLEMENTATION NK_LIB float nk_sin(float x); #endif #ifndef NK_COS +#define NK_COS nk_cos +#define NK_COS_IMPLEMENTATION NK_LIB float nk_cos(float x); #endif #ifndef NK_ATAN +#define NK_ATAN nk_atan +#define NK_ATAN_IMPLEMENTATION NK_LIB float nk_atan(float x); #endif #ifndef NK_ATAN2 +#define NK_ATAN2 nk_atan2 +#define NK_ATAN2_IMPLEMENTATION NK_LIB float nk_atan2(float y, float x); #endif NK_LIB nk_uint nk_round_up_pow2(nk_uint v); @@ -128,15 +138,21 @@ NK_LIB int nk_to_upper(int c); NK_LIB int nk_to_lower(int c); #ifndef NK_MEMCPY +#define NK_MEMCPY nk_memcopy +#define NK_MEMCPY_IMPLEMENTATION NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n); #endif #ifndef NK_MEMSET +#define NK_MEMSET nk_memset +#define NK_MEMSET_IMPLEMENTATION NK_LIB void nk_memset(void *ptr, int c0, nk_size size); #endif NK_LIB void nk_zero(void *ptr, nk_size size); NK_LIB char *nk_itoa(char *s, long n); NK_LIB int nk_string_float_limit(char *string, int prec); #ifndef NK_DTOA +#define NK_DTOA nk_dtoa +#define NK_DTOA_IMPLEMENTATION NK_LIB char *nk_dtoa(char *s, double n); #endif NK_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); diff --git a/src/nuklear_math.c b/src/nuklear_math.c index c24512c2..55e078e9 100644 --- a/src/nuklear_math.c +++ b/src/nuklear_math.c @@ -34,8 +34,7 @@ /// (it can actually approximate a lot more functions) can be /// found here: www.lolengine.net/wiki/oss/lolremez */ -#ifndef NK_INV_SQRT -#define NK_INV_SQRT nk_inv_sqrt +#ifdef NK_INV_SQRT_IMPLEMENTATION NK_LIB float nk_inv_sqrt(float n) { @@ -49,8 +48,7 @@ nk_inv_sqrt(float n) return conv.f; } #endif -#ifndef NK_SIN -#define NK_SIN nk_sin +#ifdef NK_SIN_IMPLEMENTATION NK_LIB float nk_sin(float x) { @@ -65,8 +63,7 @@ nk_sin(float x) return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); } #endif -#ifndef NK_COS -#define NK_COS nk_cos +#ifdef NK_COS_IMPLEMENTATION NK_LIB float nk_cos(float x) { @@ -84,8 +81,7 @@ nk_cos(float x) return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8))))))); } #endif -#ifndef NK_ATAN -#define NK_ATAN nk_atan +#ifdef NK_ATAN_IMPLEMENTATION NK_LIB float nk_atan(float x) { @@ -104,8 +100,7 @@ nk_atan(float x) return u; } #endif -#ifndef NK_ATAN2 -#define NK_ATAN2 nk_atan2 +#ifdef NK_ATAN2_IMPLEMENTATION NK_LIB float nk_atan2(float y, float x) { diff --git a/src/nuklear_util.c b/src/nuklear_util.c index b55602b1..92aafe0f 100644 --- a/src/nuklear_util.c +++ b/src/nuklear_util.c @@ -13,8 +13,7 @@ NK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && NK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} NK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} -#ifndef NK_MEMCPY -#define NK_MEMCPY nk_memcopy +#ifdef NK_MEMCPY_IMPLEMENTATION NK_LIB void* nk_memcopy(void *dst0, const void *src0, nk_size length) { @@ -72,8 +71,7 @@ nk_memcopy(void *dst0, const void *src0, nk_size length) return (dst0); } #endif -#ifndef NK_MEMSET -#define NK_MEMSET nk_memset +#ifdef NK_MEMSET_IMPLEMENTATION NK_LIB void nk_memset(void *ptr, int c0, nk_size size) { @@ -499,8 +497,7 @@ nk_itoa(char *s, long n) nk_strrev_ascii(s); return s; } -#ifndef NK_DTOA -#define NK_DTOA nk_dtoa +#ifdef NK_DTOA_IMPLEMENTATION NK_LIB char* nk_dtoa(char *s, double n) { From 180f167c04746af4610384c4624d2cdd8f8983b2 Mon Sep 17 00:00:00 2001 From: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:25:48 +0100 Subject: [PATCH 3/4] fix(util): guard nk_strtod implementation with preprocessor nk_strtod implementation was never guarder by the preprocessor, so if you ever provided your own NK_STRTOD, the default one would still be compiled. This fix was INTENTIONALLY split into another commit, because the lack of the guard was very suspicious to me... Fixes: https://github.com/Immediate-Mode-UI/Nuklear/issues/851#issuecomment-3503880414 --- nuklear.h | 6 ++++++ src/CHANGELOG | 1 + src/nuklear.h | 1 + src/nuklear_util.c | 2 ++ 4 files changed, 10 insertions(+) diff --git a/nuklear.h b/nuklear.h index ae33bd98..999be5f0 100644 --- a/nuklear.h +++ b/nuklear.h @@ -4040,6 +4040,7 @@ NK_API int nk_strtoi(const char *str, char **endptr); NK_API float nk_strtof(const char *str, char **endptr); #ifndef NK_STRTOD #define NK_STRTOD nk_strtod +#define NK_STRTOD_IMPLEMENTATION NK_API double nk_strtod(const char *str, char **endptr); #endif NK_API int nk_strfilter(const char *text, const char *regexp); @@ -6957,6 +6958,7 @@ nk_strtoi(const char *str, char **endptr) *endptr = (char *)p; return neg*value; } +#ifdef NK_STRTOD_IMPLEMENTATION NK_API double nk_strtod(const char *str, char **endptr) { @@ -7014,6 +7016,7 @@ nk_strtod(const char *str, char **endptr) *endptr = p; return number; } +#endif NK_API float nk_strtof(const char *str, char **endptr) { @@ -30740,6 +30743,9 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) /// - [z]: Patch version with no direct changes to the API /// /// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro +/// - Fix: failure to build from source, due to +/// nuklear_math/util.c not declaring some functions +/// - Fix: guard nk_strtod implementation with preprocessor /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/CHANGELOG b/src/CHANGELOG index 17507f8e..f1e8d0a4 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -10,6 +10,7 @@ /// - 2025/11/18 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro /// - Fix: failure to build from source, due to /// nuklear_math/util.c not declaring some functions +/// - Fix: guard nk_strtod implementation with preprocessor /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/nuklear.h b/src/nuklear.h index 9362e816..c14eca3c 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -3817,6 +3817,7 @@ NK_API int nk_strtoi(const char *str, char **endptr); NK_API float nk_strtof(const char *str, char **endptr); #ifndef NK_STRTOD #define NK_STRTOD nk_strtod +#define NK_STRTOD_IMPLEMENTATION NK_API double nk_strtod(const char *str, char **endptr); #endif NK_API int nk_strfilter(const char *text, const char *regexp); diff --git a/src/nuklear_util.c b/src/nuklear_util.c index 92aafe0f..16e2b649 100644 --- a/src/nuklear_util.c +++ b/src/nuklear_util.c @@ -162,6 +162,7 @@ nk_strtoi(const char *str, char **endptr) *endptr = (char *)p; return neg*value; } +#ifdef NK_STRTOD_IMPLEMENTATION NK_API double nk_strtod(const char *str, char **endptr) { @@ -219,6 +220,7 @@ nk_strtod(const char *str, char **endptr) *endptr = p; return number; } +#endif NK_API float nk_strtof(const char *str, char **endptr) { From 2b27828cf4a478f6e14fe5339e673ae314a29d5c Mon Sep 17 00:00:00 2001 From: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:49:21 +0100 Subject: [PATCH 4/4] fix(demo): nuklear_sdl3_renderer now provides NK_DTOA There was a note inside nuklear_sdl3_renderer saying that SDL3 does not have "dtoa", so I simulated it's behavior with printf. This helps us test the actual NK_DTOA preprocessor path. This neat trick is not mine. I discovered it here [link below] and tweaked a bit to make it work. https://github.com/Immediate-Mode-UI/Nuklear/issues/699#issuecomment-2519530861 --- demo/sdl3_renderer/main.c | 5 +++-- nuklear.h | 1 + src/CHANGELOG | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/demo/sdl3_renderer/main.c b/demo/sdl3_renderer/main.c index 1d8cdce7..661331a1 100644 --- a/demo/sdl3_renderer/main.c +++ b/demo/sdl3_renderer/main.c @@ -75,8 +75,9 @@ #define NK_VSNPRINTF(s, n, f, a) SDL_vsnprintf(s, n, f, a) #define NK_STRTOD(str, endptr) SDL_strtod(str, endptr) -/* sadly, SDL3 does not provide "dtoa" (only integer version) */ -/*#define NK_DTOA (str, d)*/ +/* HACK: SDL3 does not provide "dtoa" (only integer version) + * so we use sprintf with %g formatting to get almost the same result */ +#define NK_DTOA(str, d) (SDL_snprintf(str, 999, "%g", d), str) /* SDL can also provide us with math functions, but beware that Nuklear's own * implementation can be slightly faster at the cost of some precision */ diff --git a/nuklear.h b/nuklear.h index 999be5f0..1b2b9103 100644 --- a/nuklear.h +++ b/nuklear.h @@ -30746,6 +30746,7 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) /// - Fix: failure to build from source, due to /// nuklear_math/util.c not declaring some functions /// - Fix: guard nk_strtod implementation with preprocessor +/// - Fix: nuklear_sdl3_renderer now provides NK_DTOA /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/CHANGELOG b/src/CHANGELOG index f1e8d0a4..05034f90 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -11,6 +11,7 @@ /// - Fix: failure to build from source, due to /// nuklear_math/util.c not declaring some functions /// - Fix: guard nk_strtod implementation with preprocessor +/// - Fix: nuklear_sdl3_renderer now provides NK_DTOA /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,