Skip to content

Commit 1fb5865

Browse files
authored
Add Tooltip Positioning (#911)
* Add basic tooltip positioning * More flexible tooltip API, allow arbitrary offset * 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. * Add examples to overview, fix vararg versions * Add more options (vertially centered origins), and more demos * Simplify naming * tooltip offsets with a default style * Minor fixes, update style_configurator with new tooltip styling
1 parent 4aff9c7 commit 1fb5865

6 files changed

Lines changed: 314 additions & 17 deletions

File tree

demo/common/overview.c

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -839,12 +839,87 @@ overview(struct nk_context *ctx)
839839
} else popup_active = nk_false;
840840
}
841841

842-
/* tooltip */
843-
nk_layout_row_static(ctx, 30, 150, 1);
842+
/* tooltips */
843+
nk_layout_row_static(ctx, 30, 400, 1);
844844
bounds = nk_widget_bounds(ctx);
845-
nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT);
846-
if (nk_input_is_mouse_hovering_rect(in, bounds))
847-
nk_tooltip(ctx, "This is a tooltip");
845+
nk_label(ctx, "Hover for default tooltip", NK_TEXT_LEFT);
846+
if (nk_input_is_mouse_hovering_rect(in, bounds)) {
847+
nk_tooltip(ctx, "This is a default tooltip");
848+
}
849+
bounds = nk_widget_bounds(ctx);
850+
nk_label(ctx, "Hover for Gnome-like tooltip", NK_TEXT_LEFT);
851+
if (nk_input_is_mouse_hovering_rect(in, bounds)) {
852+
struct nk_vec2 offset = { 0, -15 };
853+
nk_tooltip_offset(ctx, "Gnome bottom centers plus a -y offset", NK_BOTTOM_CENTER, offset);
854+
}
855+
bounds = nk_widget_bounds(ctx);
856+
nk_label(ctx, "Hover for a bottom left tooltip", NK_TEXT_LEFT);
857+
if (nk_input_is_mouse_hovering_rect(in, bounds)) {
858+
struct nk_vec2 offset = { 0, 0 };
859+
nk_tooltip_offset(ctx, "Bottom left positioning", NK_BOTTOM_LEFT, offset);
860+
}
861+
bounds = nk_widget_bounds(ctx);
862+
nk_label(ctx, "Hover for MAGIC!", NK_TEXT_LEFT);
863+
if (nk_input_is_mouse_hovering_rect(in, bounds)) {
864+
static double accum_time_seconds = 0.0;
865+
const double speed = 3.0, radius = 50.0;
866+
struct nk_vec2 offset;
867+
offset.x = radius * NK_COS(accum_time_seconds * speed);
868+
offset.y = radius * NK_SIN(accum_time_seconds * speed);
869+
nk_tooltip_offset(ctx, "WOW!", NK_MIDDLE_CENTER, offset);
870+
accum_time_seconds += (double)(ctx->delta_time_seconds);
871+
}
872+
873+
/* editor for custom tooltip */
874+
{
875+
static char text_buf[64] = {0};
876+
static int text_len = 0;
877+
static int text_initialized = 0;
878+
static struct nk_vec2 offset = {0};
879+
static const char* tooltip_positions[] =
880+
{
881+
"TOP_LEFT",
882+
"TOP_CENTER",
883+
"TOP_RIGHT",
884+
885+
"MIDDLE_LEFT",
886+
"MIDDLE_CENTER",
887+
"MIDDLE_RIGHT",
888+
889+
"BOTTOM_LEFT",
890+
"BOTTOM_CENTER",
891+
"BOTTOM_RIGHT"
892+
};
893+
static int cur_pos = NK_TOP_LEFT;
894+
895+
if (!text_initialized) {
896+
const char text_default[] = "you can customize this!";
897+
NK_ASSERT(sizeof(text_default) < sizeof(text_buf));
898+
memcpy(text_buf, text_default, sizeof(text_default));
899+
text_len = sizeof(text_default) - 1;
900+
text_initialized = 1;
901+
}
902+
bounds = nk_widget_bounds(ctx);
903+
nk_label(ctx, "Hover for custom tooltip (you can customize it below)", NK_TEXT_LEFT);
904+
if (nk_input_is_mouse_hovering_rect(in, bounds)) {
905+
nk_tooltip_offset(ctx, text_buf, cur_pos, offset);
906+
}
907+
nk_layout_row_dynamic(ctx, 1, 1);
908+
nk_rule_horizontal(ctx, nk_white, nk_true);
909+
nk_layout_row_dynamic(ctx, 30, 2);
910+
nk_label(ctx, "custom tooltip text:", NK_TEXT_LEFT);
911+
nk_edit_string(ctx, NK_EDIT_FIELD, text_buf, &text_len, sizeof(text_buf), nk_filter_default);
912+
text_buf[text_len] = '\0'; /* TODO: why nk_edit_string is NOT setting this on its own? */
913+
nk_layout_row_dynamic(ctx, 30, 1);
914+
cur_pos = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), cur_pos, 25, nk_vec2(200, 200));
915+
916+
917+
nk_layout_row_dynamic(ctx, 30, 2);
918+
nk_label(ctx, "custom tooltip offset", NK_TEXT_LEFT);
919+
nk_property_float(ctx, "x", -100.0f, &offset.x, 100.0f, 5.0f, 0.5f);
920+
nk_label(ctx, "custom tooltip offset", NK_TEXT_LEFT);
921+
nk_property_float(ctx, "y", -100.0f, &offset.y, 100.0f, 5.0f, 0.5f);
922+
}
848923

849924
nk_tree_pop(ctx);
850925
}

demo/common/style_configurator.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,22 @@ style_window_header(struct nk_context* ctx, struct nk_style_window_header* out_s
632632
static void
633633
style_window(struct nk_context* ctx, struct nk_style_window* out_style)
634634
{
635+
static const char* tooltip_positions[] =
636+
{
637+
"TOP_LEFT",
638+
"TOP_CENTER",
639+
"TOP_RIGHT",
640+
641+
"MIDDLE_LEFT",
642+
"MIDDLE_CENTER",
643+
"MIDDLE_RIGHT",
644+
645+
"BOTTOM_LEFT",
646+
"BOTTOM_CENTER",
647+
"BOTTOM_RIGHT"
648+
};
649+
/*static int cur_tooltip_pos = NK_TOP_LEFT;*/
650+
635651
struct nk_style_window win = *out_style;
636652

637653
nk_layout_row_dynamic(ctx, 30, 2);
@@ -661,6 +677,10 @@ style_window(struct nk_context* ctx, struct nk_style_window* out_style)
661677
style_vec2(ctx, "Menu Padding:", &win.menu_padding);
662678
style_vec2(ctx, "Tooltip Padding:", &win.tooltip_padding);
663679

680+
nk_label(ctx, "Tooltip Origin", NK_TEXT_LEFT);
681+
win.tooltip_origin = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), win.tooltip_origin, 25, nk_vec2(200, 200));
682+
style_vec2(ctx, "Tooltip offset:", &win.tooltip_offset);
683+
664684
nk_property_float(ctx, "#Rounding:", -100.0f, &win.rounding, 100.0f, 1,0.5f);
665685
nk_property_float(ctx, "#Combo Border:", -100.0f, &win.combo_border, 100.0f, 1,0.5f);
666686
nk_property_float(ctx, "#Contextual Border:", -100.0f, &win.contextual_border, 100.0f, 1,0.5f);

nuklear.h

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,20 @@ enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};
516516
enum nk_layout_format {NK_DYNAMIC, NK_STATIC};
517517
enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB};
518518

519+
enum nk_tooltip_pos {
520+
NK_TOP_LEFT,
521+
NK_TOP_CENTER,
522+
NK_TOP_RIGHT,
523+
524+
NK_MIDDLE_LEFT,
525+
NK_MIDDLE_CENTER,
526+
NK_MIDDLE_RIGHT,
527+
528+
NK_BOTTOM_LEFT,
529+
NK_BOTTOM_CENTER,
530+
NK_BOTTOM_RIGHT
531+
};
532+
519533
typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);
520534
typedef void (*nk_plugin_free)(nk_handle, void *old);
521535
typedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);
@@ -3827,11 +3841,15 @@ NK_API void nk_contextual_end(struct nk_context*);
38273841
*
38283842
* ============================================================================= */
38293843
NK_API void nk_tooltip(struct nk_context*, const char*);
3844+
NK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset);
38303845
#ifdef NK_INCLUDE_STANDARD_VARARGS
38313846
NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2);
38323847
NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);
3848+
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);
3849+
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);
38333850
#endif
38343851
NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width);
3852+
NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2);
38353853
NK_API void nk_tooltip_end(struct nk_context*);
38363854
/* =============================================================================
38373855
*
@@ -5581,6 +5599,9 @@ struct nk_style_window {
55815599
struct nk_vec2 contextual_padding;
55825600
struct nk_vec2 menu_padding;
55835601
struct nk_vec2 tooltip_padding;
5602+
5603+
enum nk_tooltip_pos tooltip_origin;
5604+
struct nk_vec2 tooltip_offset;
55845605
};
55855606

55865607
struct nk_style {
@@ -19228,6 +19249,15 @@ nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
1922819249
win->contextual_padding = nk_vec2(4,4);
1922919250
win->menu_padding = nk_vec2(4,4);
1923019251
win->tooltip_padding = nk_vec2(4,4);
19252+
19253+
/* default tooltip just down and to the right of the cursor
19254+
* so it doesn't cover the text
19255+
*
19256+
* TODO might be worth consolidating tooltip styling
19257+
* into its own style structure, though it is a
19258+
* type of window...*/
19259+
win->tooltip_origin = NK_TOP_LEFT;
19260+
win->tooltip_offset = nk_vec2(12, 12);
1923119261
}
1923219262
NK_API void
1923319263
nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)
@@ -30631,6 +30661,13 @@ nk_combobox_callback(struct nk_context *ctx,
3063130661
* ===============================================================*/
3063230662
NK_API nk_bool
3063330663
nk_tooltip_begin(struct nk_context *ctx, float width)
30664+
{
30665+
NK_ASSERT(ctx);
30666+
return nk_tooltip_begin_offset(ctx, width, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);
30667+
}
30668+
30669+
NK_API nk_bool
30670+
nk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset)
3063430671
{
3063530672
int x,y,w,h;
3063630673
struct nk_window *win;
@@ -30651,14 +30688,55 @@ nk_tooltip_begin(struct nk_context *ctx, float width)
3065130688
return 0;
3065230689

3065330690
w = nk_iceilf(width);
30654-
h = nk_iceilf(nk_null_rect.h);
30655-
x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x;
30656-
y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y;
30691+
h = NK_MAX(win->layout->row.min_height, ctx->style.font->height+2*ctx->style.window.padding.y);
30692+
30693+
/* Default origin is top left, plus user offset */
30694+
x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x;
30695+
y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y;
30696+
30697+
/* Adjust origin based on enum */
30698+
switch (position) {
30699+
case NK_TOP_LEFT:
30700+
/* no change */
30701+
break;
30702+
case NK_TOP_CENTER:
30703+
x -= w/2;
30704+
break;
30705+
case NK_TOP_RIGHT:
30706+
x -= w;
30707+
break;
30708+
30709+
case NK_MIDDLE_LEFT:
30710+
y -= h/2;
30711+
break;
30712+
case NK_MIDDLE_CENTER:
30713+
x -= w/2;
30714+
y -= h/2;
30715+
break;
30716+
case NK_MIDDLE_RIGHT:
30717+
x -= w;
30718+
y -= h/2;
30719+
break;
30720+
30721+
case NK_BOTTOM_LEFT:
30722+
y -= h;
30723+
break;
30724+
case NK_BOTTOM_CENTER:
30725+
x -= w/2;
30726+
y -= h;
30727+
break;
30728+
case NK_BOTTOM_RIGHT:
30729+
x -= w;
30730+
y -= h;
30731+
break;
30732+
default:
30733+
NK_ASSERT(0 && "Invalid tooltip position");
30734+
}
3065730735

3065830736
bounds.x = (float)x;
3065930737
bounds.y = (float)y;
3066030738
bounds.w = (float)w;
30661-
bounds.h = (float)h;
30739+
bounds.h = (float)nk_iceilf(nk_null_rect.h);
3066230740

3066330741
ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,
3066430742
"__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);
@@ -30678,8 +30756,9 @@ nk_tooltip_end(struct nk_context *ctx)
3067830756
nk_popup_close(ctx);
3067930757
nk_popup_end(ctx);
3068030758
}
30759+
3068130760
NK_API void
30682-
nk_tooltip(struct nk_context *ctx, const char *text)
30761+
nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset)
3068330762
{
3068430763
const struct nk_style *style;
3068530764
struct nk_vec2 padding;
@@ -30707,14 +30786,29 @@ nk_tooltip(struct nk_context *ctx, const char *text)
3070730786
text_height = (style->font->height + 2 * padding.y);
3070830787

3070930788
/* execute tooltip and fill with text */
30710-
if (nk_tooltip_begin(ctx, (float)text_width)) {
30789+
if (nk_tooltip_begin_offset(ctx, (float)text_width, position, offset)) {
3071130790
nk_layout_row_dynamic(ctx, (float)text_height, 1);
3071230791
nk_text(ctx, text, text_len, NK_TEXT_LEFT);
3071330792
nk_tooltip_end(ctx);
3071430793
}
3071530794
}
30795+
30796+
NK_API void
30797+
nk_tooltip(struct nk_context *ctx, const char *text)
30798+
{
30799+
NK_ASSERT(ctx);
30800+
nk_tooltip_offset(ctx, text, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);
30801+
}
3071630802
#ifdef NK_INCLUDE_STANDARD_VARARGS
3071730803
NK_API void
30804+
nk_tooltipf_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...)
30805+
{
30806+
va_list args;
30807+
va_start(args, fmt);
30808+
nk_tooltipfv_offset(ctx, position, offset, fmt, args);
30809+
va_end(args);
30810+
}
30811+
NK_API void
3071830812
nk_tooltipf(struct nk_context *ctx, const char *fmt, ...)
3071930813
{
3072030814
va_list args;
@@ -30723,6 +30817,13 @@ nk_tooltipf(struct nk_context *ctx, const char *fmt, ...)
3072330817
va_end(args);
3072430818
}
3072530819
NK_API void
30820+
nk_tooltipfv_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args)
30821+
{
30822+
char buf[256];
30823+
nk_strfmt(buf, NK_LEN(buf), fmt, args);
30824+
nk_tooltip_offset(ctx, buf, position, offset);
30825+
}
30826+
NK_API void
3072630827
nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
3072730828
{
3072830829
char buf[256];

src/nuklear.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,20 @@ enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};
293293
enum nk_layout_format {NK_DYNAMIC, NK_STATIC};
294294
enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB};
295295

296+
enum nk_tooltip_pos {
297+
NK_TOP_LEFT,
298+
NK_TOP_CENTER,
299+
NK_TOP_RIGHT,
300+
301+
NK_MIDDLE_LEFT,
302+
NK_MIDDLE_CENTER,
303+
NK_MIDDLE_RIGHT,
304+
305+
NK_BOTTOM_LEFT,
306+
NK_BOTTOM_CENTER,
307+
NK_BOTTOM_RIGHT
308+
};
309+
296310
typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);
297311
typedef void (*nk_plugin_free)(nk_handle, void *old);
298312
typedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);
@@ -3604,11 +3618,15 @@ NK_API void nk_contextual_end(struct nk_context*);
36043618
*
36053619
* ============================================================================= */
36063620
NK_API void nk_tooltip(struct nk_context*, const char*);
3621+
NK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset);
36073622
#ifdef NK_INCLUDE_STANDARD_VARARGS
36083623
NK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2);
36093624
NK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);
3625+
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);
3626+
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);
36103627
#endif
36113628
NK_API nk_bool nk_tooltip_begin(struct nk_context*, float width);
3629+
NK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2);
36123630
NK_API void nk_tooltip_end(struct nk_context*);
36133631
/* =============================================================================
36143632
*
@@ -5358,6 +5376,9 @@ struct nk_style_window {
53585376
struct nk_vec2 contextual_padding;
53595377
struct nk_vec2 menu_padding;
53605378
struct nk_vec2 tooltip_padding;
5379+
5380+
enum nk_tooltip_pos tooltip_origin;
5381+
struct nk_vec2 tooltip_offset;
53615382
};
53625383

53635384
struct nk_style {

src/nuklear_style.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,15 @@ nk_style_from_table(struct nk_context *ctx, const struct nk_color *table)
720720
win->contextual_padding = nk_vec2(4,4);
721721
win->menu_padding = nk_vec2(4,4);
722722
win->tooltip_padding = nk_vec2(4,4);
723+
724+
/* default tooltip just down and to the right of the cursor
725+
* so it doesn't cover the text
726+
*
727+
* TODO might be worth consolidating tooltip styling
728+
* into its own style structure, though it is a
729+
* type of window...*/
730+
win->tooltip_origin = NK_TOP_LEFT;
731+
win->tooltip_offset = nk_vec2(12, 12);
723732
}
724733
NK_API void
725734
nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)

0 commit comments

Comments
 (0)