Skip to content
This repository has been archived by the owner on Dec 2, 2019. It is now read-only.

Prevent clicking more than one (overlapping) button per frame #803

Closed
wants to merge 4 commits into from
Closed

Prevent clicking more than one (overlapping) button per frame #803

wants to merge 4 commits into from

Conversation

keharriso
Copy link
Contributor

@keharriso keharriso commented Feb 18, 2019

This hopefully prevents a single click from activating multiple, overlapping buttons. This is a problem when you click in one place on one window that opens a new window with a button in the same place.

See below for the C code to reproduce the problem.

@dumblob dumblob requested a review from vurtun February 18, 2019 18:02
@keharriso
Copy link
Contributor Author

I just want to give a high-level overview of the changes here:
I added a field clicked to struct nk_mouse. It's reset to 0 at the beginning of every frame and set to 1 when a button is clicked (in nk_button_behavior). If mouse.clicked is true, then nk_input_has_mouse_click_in_rect returns false.

These simple changes unfortunately mean that the struct nk_input parameters need to be non-const, propagating throughout all of the higher-level API.

@keharriso
Copy link
Contributor Author

keharriso commented Feb 20, 2019

Here is the example code demonstrating the problem:

static int showB = 0;
if (nk_begin(ctx, "Window A", nk_rect(100, 100, 100, 100), NK_WINDOW_TITLE))
{
  nk_layout_row_dynamic(ctx, 50, 1);
  if (nk_button_label(ctx, "Button A")) {
    puts("Button A");
    showB = 1;
  }
}
nk_end(ctx);
if (showB) {
  if (nk_begin(ctx, "Window B", nk_rect(100, 100, 100, 100), NK_WINDOW_TITLE))
  {
    nk_layout_row_dynamic(ctx, 50, 1);
    if (nk_button_label(ctx, "Button B")) {
      puts("Button B");
      showB = 0;
    }
  }
  nk_end(ctx);
}

@keharriso
Copy link
Contributor Author

Is anyone able to reproduce this problem? Do I need to bump the version myself before being accepted?

@keharriso keharriso mentioned this pull request Oct 25, 2019
@revolucas
Copy link

revolucas commented Nov 25, 2019

Great find. A real shame all these fix-related pull requests aren't being implemented in some way. But probably the better way of implementing the fix would have been to add a new nk_flag to nk_widget_states enum, like NK_WIDGET_STATE_CLICKED. Then the only changes need to be made to function nk_button_behavior rather than changing all the const, which has consequences on version backwards compatibility.

Something like:

nk_button_behavior(nk_flags *state, struct nk_rect r,
	const struct nk_input *i, enum nk_button_behavior behavior)
{
	int ret = 0;
	nk_widget_state_reset(state);
	if (!i) return 0;
	if (nk_input_is_mouse_hovering_rect(i, r)) {
		*state = NK_WIDGET_STATE_HOVERED;
		if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))
			*state = NK_WIDGET_STATE_ACTIVE;
		if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r) && !(*state & NK_WIDGET_STATE_CLICKED)) {
			ret = (behavior != NK_BUTTON_DEFAULT) ?
				nk_input_is_mouse_down(i, NK_BUTTON_LEFT):
#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
				nk_input_is_mouse_released(i, NK_BUTTON_LEFT);
#else
				nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);
#endif
		}
	}
	if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))
		*state |= NK_WIDGET_STATE_ENTERED;
	else if (nk_input_is_mouse_prev_hovering_rect(i, r))
		*state |= NK_WIDGET_STATE_LEFT;

	if (!ret)
		*state &= ~(nk_flags)NK_WIDGET_STATE_CLICKED;
	else
		*state |= NK_WIDGET_STATE_CLICKED;
	return ret;
}

@dumblob
Copy link
Contributor

dumblob commented Nov 26, 2019

@revolucas I hope I can come back to Nuklear maintenance next year (currently it's kind of difficult for me - see #913 (comment) ).

This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants