Immediate-Mode-UI / Immediate-Mode-UI/Nuklear

[BUG] `nk_label_wrap` eats the last character at line breaks (`nk_text_clamp` is not completely correct)

Open
#828 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
11.4k
Forks
686
Avg merge
4d 1h
Merged PRs (30d)
3

Description

Hello, I’ve found a bug in Nuklear related to `nk_label_wrap` (and other wrapped text widgets).
When rendering wrapped text, the last character of a line is incorrectly dropped due to an off-by-one logic issue in `nk_text_clamp`.

**Expected behavior**
All characters in the input string should be visible, with line breaks applied when the text exceeds the available width.

**Actual behavior**
The last character on each wrapped line is missing (see figure).
Image

**Minimal Reproducible Example**
The following standalone code (C99 + GLFW3 + GLAD + Nuklear) demonstrates the issue:

Source code

```C
//2025.09.10
//BUG: Last character of each wrapped line disappears (issue in nk_text_clamp)
#include
#include
#include
#include
#include

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#include "nuklear/nuklear.h"
#include "nuklear/nuklear_glfw_gl3.h"

#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024

typedef struct {
GLFWwindow* window;
struct nk_context* nk_ctx;
struct nk_glfw nk_glfw;
} app_state;

static void app_init_glfw_window(app_state* st, int w, int h) {
assert(glfwInit());

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

st->window = glfwCreateWindow(w, h, "Test App", NULL, NULL);
assert(st->window);

glfwSetWindowPos(st->window, 100, 100);
glfwMakeContextCurrent(st->window);

assert(gladLoadGL(glfwGetProcAddress));
}

static void app_nuklear_init(app_state* st) {
st->nk_ctx = nk_glfw3_init(&st->nk_glfw, st->window, NK_GLFW3_INSTALL_CALLBACKS);

struct nk_font_atlas* atlas;
nk_glfw3_font_stash_begin(&st->nk_glfw, &atlas);
nk_glfw3_font_stash_end(&st->nk_glfw);
}

static void app_init(app_state* st) {
app_init_glfw_window(st, 800, 600);
app_nuklear_init(st);
}

static inline int app_window_open(app_state* st) {
return !glfwWindowShouldClose(st->window);
}

static void app_ui_frame(app_state* st) {
struct nk_context* ctx = st->nk_ctx;

nk_glfw3_new_frame(&st->nk_glfw);

nk_begin(ctx, "ABC", nk_rect(10, 10, 100, 200), NK_WINDOW_NOT_INTERACTIVE | NK_WINDOW_NO_SCROLLBAR);
{
nk_layout_row_dynamic(ctx, 100, 1);
struct nk_rect r = nk_widget_bounds(ctx);
nk_fill_rect(&ctx->current->buffer, r, 0, nk_rgb(110,70,70));
nk_label_wrap(ctx, "0123456789_0123456789_0123456789_0123456789_0123456789_0123456789");
}
nk_end(ctx);

nk_glfw3_render(&st->nk_glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}

static void app_frame(app_state* st) {
glfwPollEvents();
int width, height;
glfwGetFramebufferSize(st->window, &width, &height);

glViewport(0, 0, width, height);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

app_ui_frame(st);
glfwSwapBuffers(st->window);
}

static void app_free(app_state* st) {
nk_glfw3_shutdown(&st->nk_glfw);
glfwDestroyWindow(st->window);
glfwTerminate();
}

int main(void) {
static app_state st = { 0 };
app_init(&st);
while (app_window_open(&st)) {
app_frame(&st);
}
app_free(&st);
return 0;
}

```

Contributor guide

Open the contributing guide

Research direction

Start in nuklear/nuklear.h at nk_text_clamp and reproduce the issue with the standalone C99, GLFW3, and GLAD example provided. Confirm that wrapped labels retain every character at line breaks and verify the behavior with the nk_label_wrap example.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
desktop
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.