From ec12ed5393c8866afe44037fac1eadb19365dd26 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Thu, 29 Jan 2026 19:29:19 -0700 Subject: [PATCH 1/8] Add basic tooltip positioning --- demo/common/overview.c | 2 +- nuklear.h | 69 +++++++++++++++++++++++++++++++++++++++--- src/nuklear.h | 4 ++- src/nuklear_tooltip.c | 65 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/demo/common/overview.c b/demo/common/overview.c index 87d5f686f..b90d23548 100644 --- a/demo/common/overview.c +++ b/demo/common/overview.c @@ -844,7 +844,7 @@ overview(struct nk_context *ctx) bounds = nk_widget_bounds(ctx); nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) - nk_tooltip(ctx, "This is a tooltip"); + nk_tooltip_positioned(ctx, "This is a tooltip", NK_BOTTOM_LEFT); nk_tree_pop(ctx); } diff --git a/nuklear.h b/nuklear.h index aee190eb8..d20db0e82 100644 --- a/nuklear.h +++ b/nuklear.h @@ -515,6 +515,7 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; +enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -3827,11 +3828,12 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); +NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif -NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); +NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width, enum nk_tooltip_pos); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * @@ -30630,7 +30632,7 @@ nk_combobox_callback(struct nk_context *ctx, * * ===============================================================*/ NK_API nk_bool -nk_tooltip_begin(struct nk_context *ctx, float width) +nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos position) { int x,y,w,h; struct nk_window *win; @@ -30652,8 +30654,28 @@ nk_tooltip_begin(struct nk_context *ctx, float width) w = nk_iceilf(width); h = nk_iceilf(nk_null_rect.h); - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + switch (position) { + case NK_TOP_LEFT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + break; + case NK_BOTTOM_LEFT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; + break; + case NK_TOP_RIGHT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + break; + case NK_BOTTOM_RIGHT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; + break; + default: + /* NK_ASSERT(0 && "unknown tooltip position enum"); */ + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + } bounds.x = (float)x; bounds.y = (float)y; @@ -30678,6 +30700,43 @@ nk_tooltip_end(struct nk_context *ctx) nk_popup_close(ctx); nk_popup_end(ctx); } + +NK_API void +nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) +{ + const struct nk_style *style; + struct nk_vec2 padding; + + int text_len; + float text_width; + float text_height; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(text); + if (!ctx || !ctx->current || !ctx->current->layout || !text) + return; + + /* fetch configuration data */ + style = &ctx->style; + padding = style->window.padding; + + /* calculate size of the text and tooltip */ + text_len = nk_strlen(text); + text_width = style->font->width(style->font->userdata, + style->font->height, text, text_len); + text_width += (4 * padding.x); + text_height = (style->font->height + 2 * padding.y); + + /* execute tooltip and fill with text */ + if (nk_tooltip_begin(ctx, (float)text_width, position)) { + nk_layout_row_dynamic(ctx, (float)text_height, 1); + nk_text(ctx, text, text_len, NK_TEXT_LEFT); + nk_tooltip_end(ctx); + } +} + NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { @@ -30707,7 +30766,7 @@ nk_tooltip(struct nk_context *ctx, const char *text) text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { + if (nk_tooltip_begin(ctx, (float)text_width, NK_TOP_LEFT)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); diff --git a/src/nuklear.h b/src/nuklear.h index 6fa62204c..c8c27bfef 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -292,6 +292,7 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; +enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -3604,11 +3605,12 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); +NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif -NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); +NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width, enum nk_tooltip_pos); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index f4d78c692..be1d4dd40 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -7,7 +7,7 @@ * * ===============================================================*/ NK_API nk_bool -nk_tooltip_begin(struct nk_context *ctx, float width) +nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos position) { int x,y,w,h; struct nk_window *win; @@ -29,8 +29,28 @@ nk_tooltip_begin(struct nk_context *ctx, float width) w = nk_iceilf(width); h = nk_iceilf(nk_null_rect.h); - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + switch (position) { + case NK_TOP_LEFT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + break; + case NK_BOTTOM_LEFT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; + break; + case NK_TOP_RIGHT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + break; + case NK_BOTTOM_RIGHT: + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; + break; + default: + /* NK_ASSERT(0 && "unknown tooltip position enum"); */ + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; + } bounds.x = (float)x; bounds.y = (float)y; @@ -55,6 +75,43 @@ nk_tooltip_end(struct nk_context *ctx) nk_popup_close(ctx); nk_popup_end(ctx); } + +NK_API void +nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) +{ + const struct nk_style *style; + struct nk_vec2 padding; + + int text_len; + float text_width; + float text_height; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(text); + if (!ctx || !ctx->current || !ctx->current->layout || !text) + return; + + /* fetch configuration data */ + style = &ctx->style; + padding = style->window.padding; + + /* calculate size of the text and tooltip */ + text_len = nk_strlen(text); + text_width = style->font->width(style->font->userdata, + style->font->height, text, text_len); + text_width += (4 * padding.x); + text_height = (style->font->height + 2 * padding.y); + + /* execute tooltip and fill with text */ + if (nk_tooltip_begin(ctx, (float)text_width, position)) { + nk_layout_row_dynamic(ctx, (float)text_height, 1); + nk_text(ctx, text, text_len, NK_TEXT_LEFT); + nk_tooltip_end(ctx); + } +} + NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { @@ -84,7 +141,7 @@ nk_tooltip(struct nk_context *ctx, const char *text) text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { + if (nk_tooltip_begin(ctx, (float)text_width, NK_TOP_LEFT)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); From 7faad22a88ea2e3b378c93777bddc5e31d61aed9 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Fri, 30 Jan 2026 21:01:19 -0700 Subject: [PATCH 2/8] More flexible tooltip API, allow arbitrary offset --- nuklear.h | 116 ++++++++++++++++++++++++++++++++---------- src/nuklear.h | 6 ++- src/nuklear_tooltip.c | 110 ++++++++++++++++++++++++++++++--------- 3 files changed, 178 insertions(+), 54 deletions(-) diff --git a/nuklear.h b/nuklear.h index d20db0e82..fef9b1ea8 100644 --- a/nuklear.h +++ b/nuklear.h @@ -515,7 +515,7 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; -enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT}; +enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT, NK_TOP_MIDDLE, NK_BOTTOM_MIDDLE}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -3829,11 +3829,13 @@ NK_API void nk_contextual_end(struct nk_context*); * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); +NK_API void nk_tooltip_offset(struct nk_context*, const char*, struct nk_vec2); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif -NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width, enum nk_tooltip_pos); +NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); +NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * @@ -30632,7 +30634,14 @@ nk_combobox_callback(struct nk_context *ctx, * * ===============================================================*/ NK_API nk_bool -nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos position) +nk_tooltip_begin(struct nk_context *ctx, float width) +{ + struct nk_vec2 offset = {0}; + return nk_tooltip_begin_offset(ctx, width, offset); +} + +NK_API nk_bool +nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -30654,28 +30663,8 @@ nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos positi w = nk_iceilf(width); h = nk_iceilf(nk_null_rect.h); - switch (position) { - case NK_TOP_LEFT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - break; - case NK_BOTTOM_LEFT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; - break; - case NK_TOP_RIGHT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - break; - case NK_BOTTOM_RIGHT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; - break; - default: - /* NK_ASSERT(0 && "unknown tooltip position enum"); */ - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - } + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y; bounds.x = (float)x; bounds.y = (float)y; @@ -30701,6 +30690,42 @@ nk_tooltip_end(struct nk_context *ctx) nk_popup_end(ctx); } +NK_API void +nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offset) +{ + const struct nk_style *style; + struct nk_vec2 padding; + + int text_len; + float text_width; + float text_height; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(text); + if (!ctx || !ctx->current || !ctx->current->layout || !text) + return; + + /* fetch configuration data */ + style = &ctx->style; + padding = style->window.padding; + + /* calculate size of the text and tooltip */ + text_len = nk_strlen(text); + text_width = style->font->width(style->font->userdata, + style->font->height, text, text_len); + text_width += (4 * padding.x); + text_height = (style->font->height + 2 * padding.y); + + /* execute tooltip and fill with text */ + if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { + nk_layout_row_dynamic(ctx, (float)text_height, 1); + nk_text(ctx, text, text_len, NK_TEXT_LEFT); + nk_tooltip_end(ctx); + } +} + NK_API void nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) { @@ -30711,6 +30736,9 @@ nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_ float text_width; float text_height; + struct nk_vec2 offset = { 0 }; + int w,h; + NK_ASSERT(ctx); NK_ASSERT(ctx->current); NK_ASSERT(ctx->current->layout); @@ -30729,8 +30757,42 @@ nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_ text_width += (4 * padding.x); text_height = (style->font->height + 2 * padding.y); + /* Should I use text_height? Any difference? */ + h = ctx->current->layout->row.min_height; + w = nk_iceilf(text_width); + + switch (position) { + case NK_TOP_LEFT: + offset.x = 0; + offset.y = 0; + break; + case NK_BOTTOM_LEFT: + offset.x = 0; + offset.y = -h; + break; + case NK_TOP_RIGHT: + offset.x = -w; + offset.y = 0; + break; + case NK_BOTTOM_RIGHT: + offset.x = -w; + offset.y = -h; + break; + case NK_TOP_MIDDLE: + offset.x = -w/2; + offset.y = 0; + break; + case NK_BOTTOM_MIDDLE: + offset.x = -w/2; + offset.y = -h; + break; + default: + offset.x = 0; + offset.y = 0; + } + /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width, position)) { + if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); @@ -30766,7 +30828,7 @@ nk_tooltip(struct nk_context *ctx, const char *text) text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width, NK_TOP_LEFT)) { + if (nk_tooltip_begin(ctx, (float)text_width)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); diff --git a/src/nuklear.h b/src/nuklear.h index c8c27bfef..2b837c966 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -292,7 +292,7 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; -enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT}; +enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT, NK_TOP_MIDDLE, NK_BOTTOM_MIDDLE}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -3606,11 +3606,13 @@ NK_API void nk_contextual_end(struct nk_context*); * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); +NK_API void nk_tooltip_offset(struct nk_context*, const char*, struct nk_vec2); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif -NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width, enum nk_tooltip_pos); +NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); +NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index be1d4dd40..890b75e14 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -7,7 +7,14 @@ * * ===============================================================*/ NK_API nk_bool -nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos position) +nk_tooltip_begin(struct nk_context *ctx, float width) +{ + struct nk_vec2 offset = {0}; + return nk_tooltip_begin_offset(ctx, width, offset); +} + +NK_API nk_bool +nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -29,28 +36,8 @@ nk_tooltip_begin(struct nk_context *ctx, float width, enum nk_tooltip_pos positi w = nk_iceilf(width); h = nk_iceilf(nk_null_rect.h); - switch (position) { - case NK_TOP_LEFT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - break; - case NK_BOTTOM_LEFT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; - break; - case NK_TOP_RIGHT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - break; - case NK_BOTTOM_RIGHT: - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x - w; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y - win->layout->row.min_height; - break; - default: - /* NK_ASSERT(0 && "unknown tooltip position enum"); */ - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - } + x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x; + y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y; bounds.x = (float)x; bounds.y = (float)y; @@ -76,6 +63,42 @@ nk_tooltip_end(struct nk_context *ctx) nk_popup_end(ctx); } +NK_API void +nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offset) +{ + const struct nk_style *style; + struct nk_vec2 padding; + + int text_len; + float text_width; + float text_height; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + NK_ASSERT(text); + if (!ctx || !ctx->current || !ctx->current->layout || !text) + return; + + /* fetch configuration data */ + style = &ctx->style; + padding = style->window.padding; + + /* calculate size of the text and tooltip */ + text_len = nk_strlen(text); + text_width = style->font->width(style->font->userdata, + style->font->height, text, text_len); + text_width += (4 * padding.x); + text_height = (style->font->height + 2 * padding.y); + + /* execute tooltip and fill with text */ + if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { + nk_layout_row_dynamic(ctx, (float)text_height, 1); + nk_text(ctx, text, text_len, NK_TEXT_LEFT); + nk_tooltip_end(ctx); + } +} + NK_API void nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) { @@ -86,6 +109,9 @@ nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_ float text_width; float text_height; + struct nk_vec2 offset = { 0 }; + int w,h; + NK_ASSERT(ctx); NK_ASSERT(ctx->current); NK_ASSERT(ctx->current->layout); @@ -104,8 +130,42 @@ nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_ text_width += (4 * padding.x); text_height = (style->font->height + 2 * padding.y); + /* Should I use text_height? Any difference? */ + h = ctx->current->layout->row.min_height; + w = nk_iceilf(text_width); + + switch (position) { + case NK_TOP_LEFT: + offset.x = 0; + offset.y = 0; + break; + case NK_BOTTOM_LEFT: + offset.x = 0; + offset.y = -h; + break; + case NK_TOP_RIGHT: + offset.x = -w; + offset.y = 0; + break; + case NK_BOTTOM_RIGHT: + offset.x = -w; + offset.y = -h; + break; + case NK_TOP_MIDDLE: + offset.x = -w/2; + offset.y = 0; + break; + case NK_BOTTOM_MIDDLE: + offset.x = -w/2; + offset.y = -h; + break; + default: + offset.x = 0; + offset.y = 0; + } + /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width, position)) { + if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); @@ -141,7 +201,7 @@ nk_tooltip(struct nk_context *ctx, const char *text) text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width, NK_TOP_LEFT)) { + if (nk_tooltip_begin(ctx, (float)text_width)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); From 40ae32ec5ab9c9ebfbbc2b94e18c1fc35b123b71 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Mon, 2 Feb 2026 22:36:20 -0700 Subject: [PATCH 3/8] Simplify and combine functions as discussed... Combine position and offset parameters a single call using the latter as the origin. Credit to @sleeptightAnsiC for the obvious idea. --- nuklear.h | 119 +++++++++++++----------------------------- src/nuklear.h | 5 +- src/nuklear_tooltip.c | 114 +++++++++++++--------------------------- 3 files changed, 74 insertions(+), 164 deletions(-) diff --git a/nuklear.h b/nuklear.h index fef9b1ea8..b69121e6e 100644 --- a/nuklear.h +++ b/nuklear.h @@ -3828,14 +3828,13 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); -NK_API void nk_tooltip_offset(struct nk_context*, const char*, struct nk_vec2); +NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); -NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, struct nk_vec2); +NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * @@ -30637,11 +30636,11 @@ NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { struct nk_vec2 offset = {0}; - return nk_tooltip_begin_offset(ctx, width, offset); + return nk_tooltip_begin_pos_offset(ctx, width, NK_TOP_LEFT, offset); } NK_API nk_bool -nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offset) +nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -30662,14 +30661,43 @@ nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offs return 0; w = nk_iceilf(width); - h = nk_iceilf(nk_null_rect.h); + /* Should I use text_height? Any difference? */ + h = ctx->current->layout->row.min_height; + + /* Default origin is top left, plus user offset */ x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x; y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y; + /* Adjust origin based on enum */ + switch (position) { + case NK_TOP_LEFT: + /* no change */ + break; + case NK_BOTTOM_LEFT: + y -= h; + break; + case NK_TOP_RIGHT: + x -= w; + break; + case NK_BOTTOM_RIGHT: + x -= w; + y -= h; + break; + case NK_TOP_MIDDLE: + x -= w/2; + break; + case NK_BOTTOM_MIDDLE: + x -= w/2; + y -= h; + break; + default: + NK_ASSERT(0 && "Invalid tooltip position"); + } + bounds.x = (float)x; bounds.y = (float)y; bounds.w = (float)w; - bounds.h = (float)h; + bounds.h = (float)nk_iceilf(nk_null_rect.h); ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); @@ -30691,7 +30719,7 @@ nk_tooltip_end(struct nk_context *ctx) } NK_API void -nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offset) +nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) { const struct nk_style *style; struct nk_vec2 padding; @@ -30719,80 +30747,7 @@ nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offse text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } -} - -NK_API void -nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) -{ - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - struct nk_vec2 offset = { 0 }; - int w,h; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* Should I use text_height? Any difference? */ - h = ctx->current->layout->row.min_height; - w = nk_iceilf(text_width); - - switch (position) { - case NK_TOP_LEFT: - offset.x = 0; - offset.y = 0; - break; - case NK_BOTTOM_LEFT: - offset.x = 0; - offset.y = -h; - break; - case NK_TOP_RIGHT: - offset.x = -w; - offset.y = 0; - break; - case NK_BOTTOM_RIGHT: - offset.x = -w; - offset.y = -h; - break; - case NK_TOP_MIDDLE: - offset.x = -w/2; - offset.y = 0; - break; - case NK_BOTTOM_MIDDLE: - offset.x = -w/2; - offset.y = -h; - break; - default: - offset.x = 0; - offset.y = 0; - } - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { + if (nk_tooltip_begin_pos_offset(ctx, (float)text_width, position, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); diff --git a/src/nuklear.h b/src/nuklear.h index 2b837c966..9fd314807 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -3605,14 +3605,13 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API void nk_tooltip_positioned(struct nk_context*, const char*, enum nk_tooltip_pos); -NK_API void nk_tooltip_offset(struct nk_context*, const char*, struct nk_vec2); +NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); -NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, struct nk_vec2); +NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index 890b75e14..047f06927 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -10,11 +10,11 @@ NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { struct nk_vec2 offset = {0}; - return nk_tooltip_begin_offset(ctx, width, offset); + return nk_tooltip_begin_pos_offset(ctx, width, NK_TOP_LEFT, offset); } NK_API nk_bool -nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offset) +nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -35,14 +35,43 @@ nk_tooltip_begin_offset(struct nk_context *ctx, float width, struct nk_vec2 offs return 0; w = nk_iceilf(width); - h = nk_iceilf(nk_null_rect.h); + /* Should I use text_height? Any difference? */ + h = ctx->current->layout->row.min_height; + + /* Default origin is top left, plus user offset */ x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x; y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y; + /* Adjust origin based on enum */ + switch (position) { + case NK_TOP_LEFT: + /* no change */ + break; + case NK_BOTTOM_LEFT: + y -= h; + break; + case NK_TOP_RIGHT: + x -= w; + break; + case NK_BOTTOM_RIGHT: + x -= w; + y -= h; + break; + case NK_TOP_MIDDLE: + x -= w/2; + break; + case NK_BOTTOM_MIDDLE: + x -= w/2; + y -= h; + break; + default: + NK_ASSERT(0 && "Invalid tooltip position"); + } + bounds.x = (float)x; bounds.y = (float)y; bounds.w = (float)w; - bounds.h = (float)h; + bounds.h = (float)nk_iceilf(nk_null_rect.h); ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); @@ -64,7 +93,7 @@ nk_tooltip_end(struct nk_context *ctx) } NK_API void -nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offset) +nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) { const struct nk_style *style; struct nk_vec2 padding; @@ -92,80 +121,7 @@ nk_tooltip_offset(struct nk_context *ctx, const char *text, struct nk_vec2 offse text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } -} - -NK_API void -nk_tooltip_positioned(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position) -{ - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - struct nk_vec2 offset = { 0 }; - int w,h; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* Should I use text_height? Any difference? */ - h = ctx->current->layout->row.min_height; - w = nk_iceilf(text_width); - - switch (position) { - case NK_TOP_LEFT: - offset.x = 0; - offset.y = 0; - break; - case NK_BOTTOM_LEFT: - offset.x = 0; - offset.y = -h; - break; - case NK_TOP_RIGHT: - offset.x = -w; - offset.y = 0; - break; - case NK_BOTTOM_RIGHT: - offset.x = -w; - offset.y = -h; - break; - case NK_TOP_MIDDLE: - offset.x = -w/2; - offset.y = 0; - break; - case NK_BOTTOM_MIDDLE: - offset.x = -w/2; - offset.y = -h; - break; - default: - offset.x = 0; - offset.y = 0; - } - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin_offset(ctx, (float)text_width, offset)) { + if (nk_tooltip_begin_pos_offset(ctx, (float)text_width, position, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); From a18f55d14dadedae43d9031437637feb332fed2a Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Tue, 3 Feb 2026 09:42:55 -0700 Subject: [PATCH 4/8] Add examples to overview, fix vararg versions --- demo/common/overview.c | 25 ++++++++++++++++++++++--- nuklear.h | 17 +++++++++++++++++ src/nuklear.h | 2 ++ src/nuklear_tooltip.c | 15 +++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/demo/common/overview.c b/demo/common/overview.c index b90d23548..efe36b0bf 100644 --- a/demo/common/overview.c +++ b/demo/common/overview.c @@ -842,9 +842,28 @@ overview(struct nk_context *ctx) /* tooltip */ nk_layout_row_static(ctx, 30, 150, 1); bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT); - if (nk_input_is_mouse_hovering_rect(in, bounds)) - nk_tooltip_positioned(ctx, "This is a tooltip", NK_BOTTOM_LEFT); + nk_label(ctx, "Hover for tooltip", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + nk_tooltip(ctx, "This is a default tooltip"); + } + bounds = nk_widget_bounds(ctx); + nk_label(ctx, "Chrome-like tooltip", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + struct nk_vec2 offset = { 8, 8 }; + nk_tooltip_pos_offset(ctx, "Chrome offsets just a bit", NK_TOP_LEFT, offset); + } + bounds = nk_widget_bounds(ctx); + nk_label(ctx, "Gnome-like tooltip", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + struct nk_vec2 offset = { 0, -15 }; + nk_tooltip_pos_offset(ctx, "Gnome centers with greater y offset", NK_BOTTOM_MIDDLE, offset); + } + bounds = nk_widget_bounds(ctx); + nk_label(ctx, "Bottom left tooltip", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + struct nk_vec2 offset = { 0, 0 }; + nk_tooltip_pos_offset(ctx, "Bottom left positioning", NK_BOTTOM_LEFT, offset); + } nk_tree_pop(ctx); } diff --git a/nuklear.h b/nuklear.h index b69121e6e..0e99ef2d7 100644 --- a/nuklear.h +++ b/nuklear.h @@ -3832,6 +3832,8 @@ NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); +NK_API void nk_tooltipf_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); +NK_API void nk_tooltipfv_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); @@ -30791,6 +30793,14 @@ nk_tooltip(struct nk_context *ctx, const char *text) } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void +nk_tooltipf_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + nk_tooltipfv_pos_offset(ctx, position, offset, fmt, args); + va_end(args); +} +NK_API void nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) { va_list args; @@ -30799,6 +30809,13 @@ nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) va_end(args); } NK_API void +nk_tooltipfv_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) +{ + char buf[256]; + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_tooltip_pos_offset(ctx, buf, position, offset); +} +NK_API void nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) { char buf[256]; diff --git a/src/nuklear.h b/src/nuklear.h index 9fd314807..577fbb092 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -3609,6 +3609,8 @@ NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); +NK_API void nk_tooltipf_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); +NK_API void nk_tooltipfv_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index 047f06927..a5d55656d 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -165,6 +165,14 @@ nk_tooltip(struct nk_context *ctx, const char *text) } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void +nk_tooltipf_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + nk_tooltipfv_pos_offset(ctx, position, offset, fmt, args); + va_end(args); +} +NK_API void nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) { va_list args; @@ -173,6 +181,13 @@ nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) va_end(args); } NK_API void +nk_tooltipfv_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) +{ + char buf[256]; + nk_strfmt(buf, NK_LEN(buf), fmt, args); + nk_tooltip_pos_offset(ctx, buf, position, offset); +} +NK_API void nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) { char buf[256]; From f23c020fa8ac39efeb6b485d52024aad022016cf Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Sat, 21 Feb 2026 15:38:07 -0700 Subject: [PATCH 5/8] Add more options (vertially centered origins), and more demos --- demo/common/overview.c | 80 +++++++++++++++++++++++++++++++++++------- nuklear.h | 73 ++++++++++++++++++-------------------- src/nuklear.h | 15 +++++++- src/nuklear_tooltip.c | 58 +++++++++++------------------- 4 files changed, 138 insertions(+), 88 deletions(-) diff --git a/demo/common/overview.c b/demo/common/overview.c index efe36b0bf..73e60c25c 100644 --- a/demo/common/overview.c +++ b/demo/common/overview.c @@ -839,31 +839,87 @@ overview(struct nk_context *ctx) } else popup_active = nk_false; } - /* tooltip */ - nk_layout_row_static(ctx, 30, 150, 1); + /* tooltips */ + nk_layout_row_static(ctx, 30, 400, 1); bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Hover for tooltip", NK_TEXT_LEFT); + nk_label(ctx, "Hover for default tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { nk_tooltip(ctx, "This is a default tooltip"); } bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Chrome-like tooltip", NK_TEXT_LEFT); - if (nk_input_is_mouse_hovering_rect(in, bounds)) { - struct nk_vec2 offset = { 8, 8 }; - nk_tooltip_pos_offset(ctx, "Chrome offsets just a bit", NK_TOP_LEFT, offset); - } - bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Gnome-like tooltip", NK_TEXT_LEFT); + nk_label(ctx, "Hover for Gnome-like tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { struct nk_vec2 offset = { 0, -15 }; - nk_tooltip_pos_offset(ctx, "Gnome centers with greater y offset", NK_BOTTOM_MIDDLE, offset); + nk_tooltip_pos_offset(ctx, "Gnome bottom centers plus a -y offset", NK_BOTTOM_CENTER, offset); } bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Bottom left tooltip", NK_TEXT_LEFT); + nk_label(ctx, "Hover for a bottom left tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { struct nk_vec2 offset = { 0, 0 }; nk_tooltip_pos_offset(ctx, "Bottom left positioning", NK_BOTTOM_LEFT, offset); } + bounds = nk_widget_bounds(ctx); + nk_label(ctx, "Hover for MAGIC!", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + static double accum_time_seconds = 0.0; + const double speed = 3.0, radius = 50.0; + struct nk_vec2 offset; + offset.x = radius * cos(accum_time_seconds * speed); + offset.y = radius * sin(accum_time_seconds * speed); + nk_tooltip_pos_offset(ctx, "WOW!", NK_MIDDLE_CENTER, offset); + accum_time_seconds += (double)(ctx->delta_time_seconds); + } + + /* editor for custom tooltip */ + { + static char text_buf[64] = {0}; + static int text_len = 0; + static int text_initialized = 0; + static struct nk_vec2 offset = {0}; + static const char* tooltip_positions[] = + { + "TOP_LEFT", + "TOP_CENTER", + "TOP_RIGHT", + + "MIDDLE_LEFT", + "MIDDLE_CENTER", + "MIDDLE_RIGHT", + + "BOTTOM_LEFT", + "BOTTOM_CENTER", + "BOTTOM_RIGHT" + }; + static int cur_pos = NK_TOP_LEFT; + + if (!text_initialized) { + const char text_default[] = "you can customize this!"; + NK_ASSERT(sizeof(text_default) < sizeof(text_buf)); + memcpy(text_buf, text_default, sizeof(text_default)); + text_len = sizeof(text_default) - 1; + text_initialized = 1; + } + bounds = nk_widget_bounds(ctx); + nk_label(ctx, "Hover for custom tooltip (you can customize it below)", NK_TEXT_LEFT); + if (nk_input_is_mouse_hovering_rect(in, bounds)) { + nk_tooltip_pos_offset(ctx, text_buf, cur_pos, offset); + } + nk_layout_row_dynamic(ctx, 1, 1); + nk_rule_horizontal(ctx, nk_white, nk_true); + nk_layout_row_dynamic(ctx, 30, 2); + nk_label(ctx, "custom tooltip text:", NK_TEXT_LEFT); + nk_edit_string(ctx, NK_EDIT_FIELD, text_buf, &text_len, sizeof(text_buf), nk_filter_default); + text_buf[text_len] = '\0'; /* TODO: why nk_edit_string is NOT setting this on its own? */ + nk_layout_row_dynamic(ctx, 30, 1); + cur_pos = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), cur_pos, 25, nk_vec2(200, 200)); + + + nk_layout_row_dynamic(ctx, 30, 2); + nk_label(ctx, "custom tooltip offset", NK_TEXT_LEFT); + nk_property_float(ctx, "x", -100.0f, &offset.x, 100.0f, 5.0f, 0.5f); + nk_label(ctx, "custom tooltip offset", NK_TEXT_LEFT); + nk_property_float(ctx, "y", -100.0f, &offset.y, 100.0f, 5.0f, 0.5f); + } nk_tree_pop(ctx); } diff --git a/nuklear.h b/nuklear.h index 0e99ef2d7..2d17aa5f6 100644 --- a/nuklear.h +++ b/nuklear.h @@ -515,7 +515,20 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; -enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT, NK_TOP_MIDDLE, NK_BOTTOM_MIDDLE}; + +enum nk_tooltip_pos { + NK_TOP_LEFT, + NK_TOP_CENTER, + NK_TOP_RIGHT, + + NK_MIDDLE_LEFT, + NK_MIDDLE_CENTER, + NK_MIDDLE_RIGHT, + + NK_BOTTOM_LEFT, + NK_BOTTOM_CENTER, + NK_BOTTOM_RIGHT +}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); @@ -30675,21 +30688,34 @@ nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip case NK_TOP_LEFT: /* no change */ break; - case NK_BOTTOM_LEFT: - y -= h; + case NK_TOP_CENTER: + x -= w/2; break; case NK_TOP_RIGHT: x -= w; break; - case NK_BOTTOM_RIGHT: + + case NK_MIDDLE_LEFT: + y -= h/2; + break; + case NK_MIDDLE_CENTER: + x -= w/2; + y -= h/2; + break; + case NK_MIDDLE_RIGHT: x -= w; + y -= h/2; + break; + + case NK_BOTTOM_LEFT: y -= h; break; - case NK_TOP_MIDDLE: + case NK_BOTTOM_CENTER: x -= w/2; + y -= h; break; - case NK_BOTTOM_MIDDLE: - x -= w/2; + case NK_BOTTOM_RIGHT: + x -= w; y -= h; break; default: @@ -30759,37 +30785,8 @@ nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_ NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } + struct nk_vec2 offset = { 12, 12 }; + nk_tooltip_pos_offset(ctx, text, NK_TOP_LEFT, offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void diff --git a/src/nuklear.h b/src/nuklear.h index 577fbb092..86158b7dd 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -292,7 +292,20 @@ enum nk_color_format {NK_RGB, NK_RGBA}; enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; -enum nk_tooltip_pos {NK_TOP_LEFT, NK_BOTTOM_LEFT, NK_TOP_RIGHT, NK_BOTTOM_RIGHT, NK_TOP_MIDDLE, NK_BOTTOM_MIDDLE}; + +enum nk_tooltip_pos { + NK_TOP_LEFT, + NK_TOP_CENTER, + NK_TOP_RIGHT, + + NK_MIDDLE_LEFT, + NK_MIDDLE_CENTER, + NK_MIDDLE_RIGHT, + + NK_BOTTOM_LEFT, + NK_BOTTOM_CENTER, + NK_BOTTOM_RIGHT +}; typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); typedef void (*nk_plugin_free)(nk_handle, void *old); diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index a5d55656d..cad08bb04 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -47,21 +47,34 @@ nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip case NK_TOP_LEFT: /* no change */ break; - case NK_BOTTOM_LEFT: - y -= h; + case NK_TOP_CENTER: + x -= w/2; break; case NK_TOP_RIGHT: x -= w; break; - case NK_BOTTOM_RIGHT: + + case NK_MIDDLE_LEFT: + y -= h/2; + break; + case NK_MIDDLE_CENTER: + x -= w/2; + y -= h/2; + break; + case NK_MIDDLE_RIGHT: x -= w; + y -= h/2; + break; + + case NK_BOTTOM_LEFT: y -= h; break; - case NK_TOP_MIDDLE: + case NK_BOTTOM_CENTER: x -= w/2; + y -= h; break; - case NK_BOTTOM_MIDDLE: - x -= w/2; + case NK_BOTTOM_RIGHT: + x -= w; y -= h; break; default: @@ -131,37 +144,8 @@ nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_ NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } + struct nk_vec2 offset = { 12, 12 }; + nk_tooltip_pos_offset(ctx, text, NK_TOP_LEFT, offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void From 945e358bc62c805b7b33d497f8b9cf9b6f06eea2 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Fri, 27 Feb 2026 15:51:35 -0700 Subject: [PATCH 6/8] Simplify naming --- demo/common/overview.c | 8 ++++---- nuklear.h | 26 +++++++++++++------------- src/nuklear.h | 8 ++++---- src/nuklear_tooltip.c | 18 +++++++++--------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/demo/common/overview.c b/demo/common/overview.c index 73e60c25c..5e3077244 100644 --- a/demo/common/overview.c +++ b/demo/common/overview.c @@ -850,13 +850,13 @@ overview(struct nk_context *ctx) nk_label(ctx, "Hover for Gnome-like tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { struct nk_vec2 offset = { 0, -15 }; - nk_tooltip_pos_offset(ctx, "Gnome bottom centers plus a -y offset", NK_BOTTOM_CENTER, offset); + nk_tooltip_offset(ctx, "Gnome bottom centers plus a -y offset", NK_BOTTOM_CENTER, offset); } bounds = nk_widget_bounds(ctx); nk_label(ctx, "Hover for a bottom left tooltip", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { struct nk_vec2 offset = { 0, 0 }; - nk_tooltip_pos_offset(ctx, "Bottom left positioning", NK_BOTTOM_LEFT, offset); + nk_tooltip_offset(ctx, "Bottom left positioning", NK_BOTTOM_LEFT, offset); } bounds = nk_widget_bounds(ctx); nk_label(ctx, "Hover for MAGIC!", NK_TEXT_LEFT); @@ -866,7 +866,7 @@ overview(struct nk_context *ctx) struct nk_vec2 offset; offset.x = radius * cos(accum_time_seconds * speed); offset.y = radius * sin(accum_time_seconds * speed); - nk_tooltip_pos_offset(ctx, "WOW!", NK_MIDDLE_CENTER, offset); + nk_tooltip_offset(ctx, "WOW!", NK_MIDDLE_CENTER, offset); accum_time_seconds += (double)(ctx->delta_time_seconds); } @@ -902,7 +902,7 @@ overview(struct nk_context *ctx) bounds = nk_widget_bounds(ctx); nk_label(ctx, "Hover for custom tooltip (you can customize it below)", NK_TEXT_LEFT); if (nk_input_is_mouse_hovering_rect(in, bounds)) { - nk_tooltip_pos_offset(ctx, text_buf, cur_pos, offset); + nk_tooltip_offset(ctx, text_buf, cur_pos, offset); } nk_layout_row_dynamic(ctx, 1, 1); nk_rule_horizontal(ctx, nk_white, nk_true); diff --git a/nuklear.h b/nuklear.h index 2d17aa5f6..d14f6beca 100644 --- a/nuklear.h +++ b/nuklear.h @@ -3841,15 +3841,15 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); +NK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); -NK_API void nk_tooltipf_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); -NK_API void nk_tooltipfv_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); +NK_API void nk_tooltipf_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); +NK_API void nk_tooltipfv_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); -NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); +NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * @@ -30651,11 +30651,11 @@ NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { struct nk_vec2 offset = {0}; - return nk_tooltip_begin_pos_offset(ctx, width, NK_TOP_LEFT, offset); + return nk_tooltip_begin_offset(ctx, width, NK_TOP_LEFT, offset); } NK_API nk_bool -nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) +nk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -30747,7 +30747,7 @@ nk_tooltip_end(struct nk_context *ctx) } NK_API void -nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) +nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) { const struct nk_style *style; struct nk_vec2 padding; @@ -30775,7 +30775,7 @@ nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_ text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin_pos_offset(ctx, (float)text_width, position, offset)) { + if (nk_tooltip_begin_offset(ctx, (float)text_width, position, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); @@ -30786,15 +30786,15 @@ NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { struct nk_vec2 offset = { 12, 12 }; - nk_tooltip_pos_offset(ctx, text, NK_TOP_LEFT, offset); + nk_tooltip_offset(ctx, text, NK_TOP_LEFT, offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void -nk_tooltipf_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) +nk_tooltipf_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) { va_list args; va_start(args, fmt); - nk_tooltipfv_pos_offset(ctx, position, offset, fmt, args); + nk_tooltipfv_offset(ctx, position, offset, fmt, args); va_end(args); } NK_API void @@ -30806,11 +30806,11 @@ nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) va_end(args); } NK_API void -nk_tooltipfv_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) +nk_tooltipfv_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) { char buf[256]; nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_tooltip_pos_offset(ctx, buf, position, offset); + nk_tooltip_offset(ctx, buf, position, offset); } NK_API void nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) diff --git a/src/nuklear.h b/src/nuklear.h index 86158b7dd..f85d8a073 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -3618,15 +3618,15 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); -NK_API void nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); +NK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset); #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2); NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2); -NK_API void nk_tooltipf_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); -NK_API void nk_tooltipfv_pos_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); +NK_API void nk_tooltipf_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4); +NK_API void nk_tooltipfv_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4); #endif NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width); -NK_API nk_bool nk_tooltip_begin_pos_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); +NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= * diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index cad08bb04..d226ceb1e 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -10,11 +10,11 @@ NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { struct nk_vec2 offset = {0}; - return nk_tooltip_begin_pos_offset(ctx, width, NK_TOP_LEFT, offset); + return nk_tooltip_begin_offset(ctx, width, NK_TOP_LEFT, offset); } NK_API nk_bool -nk_tooltip_begin_pos_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) +nk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset) { int x,y,w,h; struct nk_window *win; @@ -106,7 +106,7 @@ nk_tooltip_end(struct nk_context *ctx) } NK_API void -nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) +nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset) { const struct nk_style *style; struct nk_vec2 padding; @@ -134,7 +134,7 @@ nk_tooltip_pos_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_ text_height = (style->font->height + 2 * padding.y); /* execute tooltip and fill with text */ - if (nk_tooltip_begin_pos_offset(ctx, (float)text_width, position, offset)) { + if (nk_tooltip_begin_offset(ctx, (float)text_width, position, offset)) { nk_layout_row_dynamic(ctx, (float)text_height, 1); nk_text(ctx, text, text_len, NK_TEXT_LEFT); nk_tooltip_end(ctx); @@ -145,15 +145,15 @@ NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { struct nk_vec2 offset = { 12, 12 }; - nk_tooltip_pos_offset(ctx, text, NK_TOP_LEFT, offset); + nk_tooltip_offset(ctx, text, NK_TOP_LEFT, offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void -nk_tooltipf_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) +nk_tooltipf_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...) { va_list args; va_start(args, fmt); - nk_tooltipfv_pos_offset(ctx, position, offset, fmt, args); + nk_tooltipfv_offset(ctx, position, offset, fmt, args); va_end(args); } NK_API void @@ -165,11 +165,11 @@ nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) va_end(args); } NK_API void -nk_tooltipfv_pos_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) +nk_tooltipfv_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args) { char buf[256]; nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_tooltip_pos_offset(ctx, buf, position, offset); + nk_tooltip_offset(ctx, buf, position, offset); } NK_API void nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) From 844f8c7cd1f8e365840c57c4cb5998ef901ba669 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Sat, 7 Mar 2026 23:08:49 -0700 Subject: [PATCH 7/8] tooltip offsets with a default style --- nuklear.h | 20 ++++++++++++++++---- src/nuklear.h | 3 +++ src/nuklear_style.c | 9 +++++++++ src/nuklear_tooltip.c | 8 ++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/nuklear.h b/nuklear.h index d14f6beca..9140300d6 100644 --- a/nuklear.h +++ b/nuklear.h @@ -5599,6 +5599,9 @@ struct nk_style_window { struct nk_vec2 contextual_padding; struct nk_vec2 menu_padding; struct nk_vec2 tooltip_padding; + + enum nk_tooltip_pos tooltip_origin; + struct nk_vec2 tooltip_offset; }; struct nk_style { @@ -19246,6 +19249,15 @@ nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) win->contextual_padding = nk_vec2(4,4); win->menu_padding = nk_vec2(4,4); win->tooltip_padding = nk_vec2(4,4); + + /* default tooltip just down and to the right of the cursor + * so it doesn't cover the text + * + * TODO might be worth consolidating tooltip styling + * into its own style structure, though it is a + * type of window...*/ + win->tooltip_origin = NK_TOP_LEFT; + win->tooltip_offset = nk_vec2(12, 12); } NK_API void nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) @@ -30650,8 +30662,8 @@ nk_combobox_callback(struct nk_context *ctx, NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { - struct nk_vec2 offset = {0}; - return nk_tooltip_begin_offset(ctx, width, NK_TOP_LEFT, offset); + NK_ASSERT(ctx); + return nk_tooltip_begin_offset(ctx, width, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset); } NK_API nk_bool @@ -30785,8 +30797,8 @@ nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { - struct nk_vec2 offset = { 12, 12 }; - nk_tooltip_offset(ctx, text, NK_TOP_LEFT, offset); + NK_ASSERT(ctx); + nk_tooltip_offset(ctx, text, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void diff --git a/src/nuklear.h b/src/nuklear.h index f85d8a073..ca497872e 100644 --- a/src/nuklear.h +++ b/src/nuklear.h @@ -5376,6 +5376,9 @@ struct nk_style_window { struct nk_vec2 contextual_padding; struct nk_vec2 menu_padding; struct nk_vec2 tooltip_padding; + + enum nk_tooltip_pos tooltip_origin; + struct nk_vec2 tooltip_offset; }; struct nk_style { diff --git a/src/nuklear_style.c b/src/nuklear_style.c index 377836a4a..b241e7757 100644 --- a/src/nuklear_style.c +++ b/src/nuklear_style.c @@ -720,6 +720,15 @@ nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) win->contextual_padding = nk_vec2(4,4); win->menu_padding = nk_vec2(4,4); win->tooltip_padding = nk_vec2(4,4); + + /* default tooltip just down and to the right of the cursor + * so it doesn't cover the text + * + * TODO might be worth consolidating tooltip styling + * into its own style structure, though it is a + * type of window...*/ + win->tooltip_origin = NK_TOP_LEFT; + win->tooltip_offset = nk_vec2(12, 12); } NK_API void nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index d226ceb1e..78a956664 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -9,8 +9,8 @@ NK_API nk_bool nk_tooltip_begin(struct nk_context *ctx, float width) { - struct nk_vec2 offset = {0}; - return nk_tooltip_begin_offset(ctx, width, NK_TOP_LEFT, offset); + NK_ASSERT(ctx); + return nk_tooltip_begin_offset(ctx, width, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset); } NK_API nk_bool @@ -144,8 +144,8 @@ nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos NK_API void nk_tooltip(struct nk_context *ctx, const char *text) { - struct nk_vec2 offset = { 12, 12 }; - nk_tooltip_offset(ctx, text, NK_TOP_LEFT, offset); + NK_ASSERT(ctx); + nk_tooltip_offset(ctx, text, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset); } #ifdef NK_INCLUDE_STANDARD_VARARGS NK_API void From 748d86d79f0c193227f9f63676925aa93e64b918 Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Sun, 8 Mar 2026 12:55:14 -0700 Subject: [PATCH 8/8] Minor fixes, update style_configurator with new tooltip styling --- demo/common/overview.c | 4 ++-- demo/common/style_configurator.c | 20 ++++++++++++++++++++ nuklear.h | 3 +-- src/nuklear_tooltip.c | 3 +-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/demo/common/overview.c b/demo/common/overview.c index 5e3077244..bd73116a3 100644 --- a/demo/common/overview.c +++ b/demo/common/overview.c @@ -864,8 +864,8 @@ overview(struct nk_context *ctx) static double accum_time_seconds = 0.0; const double speed = 3.0, radius = 50.0; struct nk_vec2 offset; - offset.x = radius * cos(accum_time_seconds * speed); - offset.y = radius * sin(accum_time_seconds * speed); + offset.x = radius * NK_COS(accum_time_seconds * speed); + offset.y = radius * NK_SIN(accum_time_seconds * speed); nk_tooltip_offset(ctx, "WOW!", NK_MIDDLE_CENTER, offset); accum_time_seconds += (double)(ctx->delta_time_seconds); } diff --git a/demo/common/style_configurator.c b/demo/common/style_configurator.c index ba87740e2..ad7de96f0 100644 --- a/demo/common/style_configurator.c +++ b/demo/common/style_configurator.c @@ -632,6 +632,22 @@ style_window_header(struct nk_context* ctx, struct nk_style_window_header* out_s static void style_window(struct nk_context* ctx, struct nk_style_window* out_style) { + static const char* tooltip_positions[] = + { + "TOP_LEFT", + "TOP_CENTER", + "TOP_RIGHT", + + "MIDDLE_LEFT", + "MIDDLE_CENTER", + "MIDDLE_RIGHT", + + "BOTTOM_LEFT", + "BOTTOM_CENTER", + "BOTTOM_RIGHT" + }; + /*static int cur_tooltip_pos = NK_TOP_LEFT;*/ + struct nk_style_window win = *out_style; nk_layout_row_dynamic(ctx, 30, 2); @@ -661,6 +677,10 @@ style_window(struct nk_context* ctx, struct nk_style_window* out_style) style_vec2(ctx, "Menu Padding:", &win.menu_padding); style_vec2(ctx, "Tooltip Padding:", &win.tooltip_padding); + nk_label(ctx, "Tooltip Origin", NK_TEXT_LEFT); + win.tooltip_origin = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), win.tooltip_origin, 25, nk_vec2(200, 200)); + style_vec2(ctx, "Tooltip offset:", &win.tooltip_offset); + nk_property_float(ctx, "#Rounding:", -100.0f, &win.rounding, 100.0f, 1,0.5f); nk_property_float(ctx, "#Combo Border:", -100.0f, &win.combo_border, 100.0f, 1,0.5f); nk_property_float(ctx, "#Contextual Border:", -100.0f, &win.contextual_border, 100.0f, 1,0.5f); diff --git a/nuklear.h b/nuklear.h index 9140300d6..73afb7258 100644 --- a/nuklear.h +++ b/nuklear.h @@ -30688,8 +30688,7 @@ nk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos return 0; w = nk_iceilf(width); - /* Should I use text_height? Any difference? */ - h = ctx->current->layout->row.min_height; + h = NK_MAX(win->layout->row.min_height, ctx->style.font->height+2*ctx->style.window.padding.y); /* Default origin is top left, plus user offset */ x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x; diff --git a/src/nuklear_tooltip.c b/src/nuklear_tooltip.c index 78a956664..3729a0f52 100644 --- a/src/nuklear_tooltip.c +++ b/src/nuklear_tooltip.c @@ -35,8 +35,7 @@ nk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos return 0; w = nk_iceilf(width); - /* Should I use text_height? Any difference? */ - h = ctx->current->layout->row.min_height; + h = NK_MAX(win->layout->row.min_height, ctx->style.font->height+2*ctx->style.window.padding.y); /* Default origin is top left, plus user offset */ x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x;