Skip to content

handle nk_command_text::background where it's possible to do so - #1006

Draft
sleeptightAnsiC wants to merge 5 commits into
Immediate-Mode-UI:masterfrom
sleeptightAnsiC:fix_command_text_background
Draft

sleeptightAnsiC wants to merge 5 commits into
Immediate-Mode-UI:masterfrom
sleeptightAnsiC:fix_command_text_background

Conversation

@sleeptightAnsiC

@sleeptightAnsiC sleeptightAnsiC commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

This fixes the issue that caused the backends to read garbage values from nk_command_text::background, brings back the handling of that value to demo/x11, fixes the handling in demo/gdi, and implements similar handling for vertex buffer API, and few other goodies... Split to multiple commits because it was easier to deal with for me. Each commit explains exactly what I did and why.

Refs: #235

this appears to be regression caused by
Immediate-Mode-UI@6322f53
which could cause bugs such as
Immediate-Mode-UI#502
@sleeptightAnsiC

This comment was marked as resolved.

@TomJGooding

TomJGooding commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for looking into this @sleeptightAnsiC. I understand now what you meant by results depending on the render backend, but X11 not supporting transparency isn't surprising (and presumably GDI too).

Honestly I have no idea what 9-slice is, but I wonder why this removed the text background handling?

I haven't complied or run anything yet and honestly don't really feel qualified to review this PR, but even if the results aren't perfect, I think this is better than the background argument to nk_draw_text just doing nothing!

@sleeptightAnsiC

sleeptightAnsiC commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Honestly I have no idea what 9-slice is, but I wonder why this removed the text background handling?

It didn't really remove anything, but rather broke it on backends that had this implemented. Back then only demo/x11 was handling that value, so the issue was manifesting only there. See #502, it correctly identified what was wrong, but then (probably due to miscommunication) they removed the x11 handling instead of fixing the regression.

@sleeptightAnsiC

This comment was marked as resolved.

@sleeptightAnsiC

This comment was marked as resolved.

@sleeptightAnsiC
sleeptightAnsiC marked this pull request as draft November 6, 2026 00:49
@TomJGooding

TomJGooding commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

I'd like to investigate XDrawImageString, which seems to act just like XDrawString except first will "fill a destination rectangle with the background pixel". Is that just the background behind the actual glyphs?

@sleeptightAnsiC

sleeptightAnsiC commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor Author

@TomJGooding Yes. I gave it a quick try, and this works like GDI:

XSetForeground(surf->dpy, surf->gc, fg);
XSetBackground(surf->dpy, surf->gc, bg);
XDrawImageString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
image

The only problem is that x11 demo have alternative paths for text rendering with Xft and Xmb. There is XmbDrawImageString but I don't see the equivalent for Xft (but maybe there is a different way to supply background color to XftDrawStringUtf8 somehow). I'll revisit this PR soon and figure something out.

@TomJGooding

TomJGooding commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for checking @sleeptightAnsiC. Sorry I hope you didn't think I was expecting you to do all the work, my post was really more a 'note to self'! I will try to do some investigation into X11 myself when I have more time.


EDIT: From a quick search, I found this section from an Xft Tutorial:

5.3 Text Drawing

Xft doesn't support "image text" at all; rather the application must
explicitly fill the background rectangle before drawing the string. With AA
text, there's no other way to make it work.

XDrawString -> XftDrawString8
XDrawImageString -> XftDrawRect + XftDrawString8

Unfortunately it doesn't detail exactly how to replicate this background in terms of the rectangle position/size. Based on the filled rectangle explanation from the XDrawImageString docs, I suppose this would need to be calculated based on the font 'ascent' and 'descent'?

sleeptightAnsiC added a commit to sleeptightAnsiC/Nuklear that referenced this pull request Nov 10, 2026
…lib.h

this reverts old change which was attemting to workaround the bug
were Nuklear was passing garbage to nk_command_text::background
(said problem was fixed in prior commit 7ac558d and should not happen)
also added Tom's sugestion about using DrawImageString here

Refs: Immediate-Mode-UI@0eb3361
Refs: Immediate-Mode-UI#502
Refs: Immediate-Mode-UI#1006 (comment)
Co-authored-by: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
@sleeptightAnsiC
sleeptightAnsiC force-pushed the fix_command_text_background branch from c3d4a53 to bb0e4d7 Compare November 10, 2026 18:27
@sleeptightAnsiC

sleeptightAnsiC commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

@TomJGooding Nah, no worries, I wouldn't touch this thing if I wasn't interested myself.

Anyway, I went with #235 (comment) approach for vertex buffer, and with DrawImageString for x11. I honestly don't want to mess with Xft path so I just left a FIXME there. Now this is how the results look like:

demo/sdl3_renderer (and any other demo using vertex buffer):
image

demo/gdi
image

demo/x11
image

demo/x11 with Xft (and any other demo with custom draw loop that did not implement it yet)
image

EDIT: I hid few of my previous comments as they were pretty much resolved with latest push
EDIT: did one more push with example saying that red should be half-transparent

@sleeptightAnsiC
sleeptightAnsiC marked this pull request as ready for review November 10, 2026 18:51
@sleeptightAnsiC
sleeptightAnsiC force-pushed the fix_command_text_background branch from bb0e4d7 to 36806df Compare November 10, 2026 19:05
@TomJGooding

TomJGooding commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Sorry you might still regret touching this...! I haven't checked every example from the demo, but just skimming the overview I spotted this difference in the inactive button:

Before After
Before screenshot After screenshot

The screenshots are from the SDL3 renderer but checking X11 also showed similar results. I'm afraid I'm not familiar enough with the Nuklear codebase to understand why this would have changed just yet.

TomJGooding

This comment was marked as resolved.

sleeptightAnsiC and others added 4 commits November 10, 2026 22:35
…lib.h

this handling was removed in the past as a workaround to bug
were Nuklear was passing garbage to nk_command_text::background
(said problem was fixed in prior commit 7ac558d and should not happen)
also added Tom's sugestion about using DrawImageString here

Refs: Immediate-Mode-UI@0eb3361
Refs: Immediate-Mode-UI#502
Refs: Immediate-Mode-UI#1006 (comment)
Co-authored-by: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
this test text drawing with forground and background colors
it's the same code but collapsed to a single line:
Immediate-Mode-UI#235 (comment)

Co-authored-by: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Even thought the backend was reading the text background color
it was not drawing it in any way. I fixed it by using SetBkMode(,OPAQUE)
which I'm not sure is 100% correct but... it works...

Refs: Immediate-Mode-UI#235 (comment)
inspider by ronaaron's patch linked down below but implemented inside of
nk_covert() instead (because emiting two commands from nk_draw_text()
could confuse backends with custom drawing loop and just isn't correct)

Refs: Immediate-Mode-UI#235 (comment)
Co-authored-by: ronaaron <ron@aaron-tech.com>
@sleeptightAnsiC
sleeptightAnsiC force-pushed the fix_command_text_background branch from 36806df to 958f412 Compare November 10, 2026 21:39
@sleeptightAnsiC

sleeptightAnsiC commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Fixed those unused args. There should be no warnings now.

Not sure what to do about that inactive button tbh. Styling structs have 3 values for text foreground (text_normal/hover/active) but only one for background (text_background) which is weird. Pattern searching for /text.background/ shows that only few widgets read those styling values and the rest either sets the background to zero or to the color of the widget itself. This is really bad... Nuklear's styling is a can of worms.

you might still regret touching this

🫠

@sleeptightAnsiC
sleeptightAnsiC marked this pull request as draft November 10, 2026 22:13
@TomJGooding

Copy link
Copy Markdown
Contributor

Honesty no idea if this is the correct fix, but copying the code from the background of the button itself seems to work?

diff --git a/nuklear.h b/nuklear.h
index 9ad31b7..83bd4c4 100644
--- a/nuklear.h
+++ b/nuklear.h
@@ -25095,7 +25095,7 @@ nk_draw_button_text(struct nk_command_buffer *out,
 
     /* select correct colors/images */
     if (background->type == NK_STYLE_ITEM_COLOR)
-        text.background = background->data.color;
+        text.background = nk_rgb_factor(background->data.color, style->color_factor_background);
     else text.background = style->text_background;
     if (state & NK_WIDGET_STATE_HOVER)
         text.text = style->text_hover;

@sleeptightAnsiC

sleeptightAnsiC commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor Author

@TomJGooding It should do the trick for the button but I'm afraid other widgets may have similar problem. Might be a good idea to add more code to Overview>Widgets>Inactive in order to test this thing.

Also, in situations where Nuklear sets text background to the same color as the widget, and we know for sure the glyps are inside of the widget, it makes more sense to use nk_rgba(0,0,0,0) instead IMO. That's because setting alpha to zero may avoid producing unnecessary vertex (and maybe help with batching on some backends) and it looks the same anyway.

(To be fair, I have some ideas on how to fix it, I'm just concerned that a dead code that was harmless before and that no one really cared about, may start producing bugs now. That's what I meant by "not being sure what to do")

@TomJGooding

Copy link
Copy Markdown
Contributor

I might have something working for Xft in the meantime:

diff --git a/demo/x11/nuklear_xlib.h b/demo/x11/nuklear_xlib.h
index f204c0b..f7143da 100644
--- a/demo/x11/nuklear_xlib.h
+++ b/demo/x11/nuklear_xlib.h
@@ -448,8 +448,14 @@ nk_xsurf_draw_text(XSurface *surf, short x, short y,
 {
     int tx, ty;
 #ifdef NK_XLIB_USE_XFT
-    XRenderColor xrc;
-    XftColor color;
+    XRenderColor fg_xrc;
+    XftColor fg;
+
+    XRenderColor bg_xrc;
+    XftColor bg;
+    XGlyphInfo bg_ext;
+    int bg_x, bg_y;
+    unsigned int bg_w, bg_h;
 #else
     unsigned long fg = nk_color_from_byte(&cfg.r);
     unsigned long bg = nk_color_from_byte(&cbg.r);
@@ -460,14 +466,28 @@ nk_xsurf_draw_text(XSurface *surf, short x, short y,
     tx = (int)x;
     ty = (int)y + font->ascent;
 #ifdef NK_XLIB_USE_XFT
-    xrc.red = cfg.r * 257;
-    xrc.green = cfg.g * 257;
-    xrc.blue = cfg.b * 257;
-    xrc.alpha = cfg.a * 257;
-    XftColorAllocValue(surf->dpy, xlib.vis, xlib.cmap, &xrc, &color);
-    (void)cbg; /* FIXME: Xft does not have DrawImageString so 'cbg' needs to be handled in a different way */
-    XftDrawStringUtf8(surf->ftdraw, &color, font->ft, tx, ty, (FcChar8*)text, len);
-    XftColorFree(surf->dpy, xlib.vis, xlib.cmap, &color);
+    fg_xrc.red = cfg.r * 257;
+    fg_xrc.green = cfg.g * 257;
+    fg_xrc.blue = cfg.b * 257;
+    fg_xrc.alpha = cfg.a * 257;
+    XftColorAllocValue(surf->dpy, xlib.vis, xlib.cmap, &fg_xrc, &fg);
+
+    XftTextExtentsUtf8(surf->dpy, font->ft, (FcChar8*)text, len, &bg_ext);
+    bg_xrc.red = cbg.r * 257;
+    bg_xrc.green = cbg.g * 257;
+    bg_xrc.blue = cbg.b * 257;
+    bg_xrc.alpha = cbg.a * 257;
+    XftColorAllocValue(surf->dpy, xlib.vis, xlib.cmap, &bg_xrc, &bg);
+    bg_x = tx;
+    bg_y = ty - font->ascent;
+    bg_w = (unsigned int)bg_ext.xOff;
+    bg_h = (unsigned int)(font->ascent + font->descent);
+
+    XftDrawRect(surf->ftdraw, &bg, bg_x, bg_y, bg_w, bg_h);
+    XftDrawStringUtf8(surf->ftdraw, &fg, font->ft, tx, ty, (FcChar8*)text, len);
+
+    XftColorFree(surf->dpy, xlib.vis, xlib.cmap, &fg);
+    XftColorFree(surf->dpy, xlib.vis, xlib.cmap, &bg);
 #else
     XSetBackground(surf->dpy, surf->gc, bg);
     XSetForeground(surf->dpy, surf->gc, fg);

Xft demo screenshot

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants