Double clicks were never working reliably in Blender - this mostly because
it wasn't a real event, but something generated in the handler code.

Now it is an actual event - meaning it always gets handled (if you have
a keymap item for it of course), but if there's no doubleclick handling
it treats the doubleclick as a normal click.

Also cleaned code. No recursion anymore.
This commit is contained in:
Ton Roosendaal
2012-10-26 15:21:31 +00:00
parent d24aaf5958
commit 37bf6ef044
2 changed files with 77 additions and 77 deletions

View File

@@ -1672,7 +1672,7 @@ static int wm_action_not_handled(int action)
return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
}
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
#ifndef NDEBUG
const int do_debug_handler = (G.debug & G_DEBUG_EVENTS)
@@ -1849,49 +1849,44 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
/* test for CLICK event */
if (wm_action_not_handled(action) && event->val == KM_RELEASE) {
if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL))
wm_cursor_arrow_move(CTX_wm_window(C), event);
return action;
}
/* this calls handlers twice - to solve (double-)click events */
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, event, handlers);
/* test for CLICK events */
if (wm_action_not_handled(action)) {
wmWindow *win = CTX_wm_window(C);
if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) {
/* test for double click first,
* note1: this can be problematic because single click operators can get the
* double click event but then with old mouse coords which is highly confusing,
* so check for mouse moves too.
* note2: the first click event will be handled but still used to create a
* double click event if clicking again quickly.
* If no double click events are found it will fallback to a single click.
* So a double click event can result in 2 successive single click calls
* if its not handled by the keymap - campbell */
if ((ABS(event->x - win->eventstate->prevclickx)) <= 2 &&
(ABS(event->y - win->eventstate->prevclicky)) <= 2 &&
((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time))
{
event->val = KM_DBL_CLICK;
/* removed this because in cases where we're this is used as a single click
* event, this will give old coords,
* since the distance is checked above, using new coords should be ok. */
// event->x = win->eventstate->prevclickx;
// event->y = win->eventstate->prevclicky;
action |= wm_handlers_do(C, event, handlers);
}
if (wm_action_not_handled(action)) {
if (win && win->eventstate->prevtype == event->type) {
if(event->val == KM_RELEASE && win->eventstate->prevval == KM_PRESS) {
event->val = KM_CLICK;
action |= wm_handlers_do(C, event, handlers);
action |= wm_handlers_do_intern(C, event, handlers);
/* revert value if not handled */
if (wm_action_not_handled(action)) {
event->val = KM_RELEASE;
}
}
/* revert value if not handled */
if (wm_action_not_handled(action)) {
event->val = KM_RELEASE;
else if(event->val == KM_DBL_CLICK) {
event->val = KM_PRESS;
action |= wm_handlers_do_intern(C, event, handlers);
/* revert value if not handled */
if (wm_action_not_handled(action)) {
event->val = KM_DBL_CLICK;
}
}
}
}
if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL))
wm_cursor_arrow_move(CTX_wm_window(C), event);
return action;
}
@@ -2185,40 +2180,6 @@ void wm_event_do_handlers(bContext *C)
}
}
/* store last event for this window */
/* mousemove and timer events don't overwrite last type */
if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) && !ISTIMER(event->type)) {
if (wm_action_not_handled(action)) {
if (win->eventstate->prevtype == event->type) {
/* set click time on first click (press -> release) */
if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) {
win->eventstate->prevclicktime = PIL_check_seconds_timer();
win->eventstate->prevclickx = event->x;
win->eventstate->prevclicky = event->y;
}
}
else {
/* reset click time if event type not the same */
win->eventstate->prevclicktime = 0;
}
win->eventstate->prevval = event->val;
win->eventstate->prevtype = event->type;
}
else if (event->val == KM_CLICK) { /* keep click for double click later */
win->eventstate->prevtype = event->type;
win->eventstate->prevval = event->val;
win->eventstate->prevclicktime = PIL_check_seconds_timer();
win->eventstate->prevclickx = event->x;
win->eventstate->prevclicky = event->y;
}
else { /* reset if not */
win->eventstate->prevtype = -1;
win->eventstate->prevval = 0;
win->eventstate->prevclicktime = 0;
}
}
/* unlink and free here, blender-quit then frees all */
BLI_remlink(&win->queue, event);
wm_event_free(event);
@@ -2724,6 +2685,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* initialize and copy state (only mouse x y and modifiers) */
event = *evt;
/* copy prev state to event state */
evt->prevval = evt->val;
evt->prevtype = evt->type;
switch (type) {
/* mouse move */
case GHOST_kEventCursorMove:
@@ -2806,7 +2771,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventButtonUp:
{
GHOST_TEventButtonData *bd = customdata;
/* get value and type from ghost */
event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
if (bd->button == GHOST_kButtonMaskLeft)
@@ -2820,6 +2786,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
else
event.type = MIDDLEMOUSE;
/* copy to event state */
evt->val= event.val;
evt->type= event.type;
if (win->active == 0) {
int cx, cy;
@@ -2830,6 +2800,21 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.y = evt->y = cy;
}
/* double click test */
if (event.type == evt->prevtype && event.val == KM_PRESS) {
if ((ABS(event.x - evt->prevclickx)) <= 2 &&
(ABS(event.y - evt->prevclicky)) <= 2 &&
((PIL_check_seconds_timer() - evt->prevclicktime) * 1000 < U.dbl_click_time))
{
event.val = KM_DBL_CLICK;
}
}
if (event.val == KM_RELEASE) {
evt->prevclicktime = PIL_check_seconds_timer();
evt->prevclickx = event.x;
evt->prevclicky = event.y;
}
/* add to other window if event is there (not to both!) */
owin = wm_event_cursor_other_windows(wm, win, &event);
if (owin) {
@@ -2860,6 +2845,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/
event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE;
/* copy to event state */
evt->val= event.val;
evt->type= event.type;
/* exclude arrow keys, esc, etc from text input */
if (type == GHOST_kEventKeyUp) {
event.ascii = '\0';
@@ -2932,6 +2921,22 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
if (event.type == ESCKEY && event.val == KM_PRESS)
G.is_break = TRUE;
/* double click test */
if (event.type == evt->prevtype && event.val == KM_PRESS) {
if ((ABS(event.x - evt->prevclickx)) <= 2 &&
(ABS(event.y - evt->prevclicky)) <= 2 &&
((PIL_check_seconds_timer() - evt->prevclicktime) * 1000 < U.dbl_click_time))
{
printf("double key click\n");
event.val = KM_DBL_CLICK;
}
}
if (event.val == KM_RELEASE) {
evt->prevclicktime = PIL_check_seconds_timer();
evt->prevclickx = event.x;
evt->prevclicky = event.y;
}
wm_event_add(win, &event);
break;

View File

@@ -957,11 +957,6 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
return 0;
if (k1->val != KM_ANY && k2->val != KM_ANY) {
/* take click, press, release conflict into account */
if (k1->val == KM_CLICK && ELEM3(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
return 0;
if (k2->val == KM_CLICK && ELEM3(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
return 0;
if (k1->val != k2->val)
return 0;
}