Immediate-Mode-UI / Nuklear

A single-header ANSI C immediate mode cross-platform GUI library
https://immediate-mode-ui.github.io/Nuklear/doc/index.html
8.86k stars 535 forks source link

No NK_EDIT_DEACTIVATED flag is returned when switching from one nk_edit_string to a previous one #656

Open Askyras opened 6 days ago

Askyras commented 6 days ago

When an nk_edit_string widget is active, the expected behaviour is that the return flags include NK_EDIT_DEACTIVATED whenever it becomes inactive. It works for most cases, but not if you switch straight to a different nk_edit_string, specifically one that was submitted earlier in the frame.

It is reproducible with the following code, notice that the deactivation message does not get triggered when clicking the first textbox while the second is active.

static char text[2][64];
static int text_len[2];
nk_flags return_flags[2];
nk_layout_row_dynamic(ctx, 30, 1);

for (int i = 0; i < 2; i++) {
  return_flags[i] = nk_edit_string(ctx, NK_EDIT_FIELD, text[i], &text_len[i], 64, nk_filter_default);

  if (return_flags[i] & NK_EDIT_ACTIVATED)
    std::cout << "activated " << i << std::endl;
  if (return_flags[i] & NK_EDIT_DEACTIVATED)
    std::cout << "deactivated " << i << std::endl;
}

The bug arises from the fact that when the earlier widget becomes active, it already overwrites the name of the current active edit field to its own id, so information on the previous frame's active edit field is lost too early.

  1. Widget A sees it became active and updates ctx->current.edit.name to its index/hash https://github.com/Immediate-Mode-UI/Nuklear/blob/0319c0ff3b36006a377cd30fa5eb39672ecb3c83/nuklear.h#L28071-L28074
  2. Widget B determines it is inactive because its index/hash no longer matches ctx->current.edit.name, and this falsely becomes prev_state https://github.com/Immediate-Mode-UI/Nuklear/blob/0319c0ff3b36006a377cd30fa5eb39672ecb3c83/nuklear.h#L27449
  3. Then when the mouse click is processed and it is found to be outside the bounding box, the widget doesn't register a change because prev_state is already 0. https://github.com/Immediate-Mode-UI/Nuklear/blob/0319c0ff3b36006a377cd30fa5eb39672ecb3c83/nuklear.h#L27477-L27478

(Tested on the most up-to-date version at the time of posting)