From d27c9f9d76752bffdcdf60812ee05f48482bccfc Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Tue, 2 Dec 2008 18:49:58 +0000 Subject: [PATCH] 2.5 - after closing button (having used it), it sends empty mousemove for invoking new modal handler on same button. Don't know better solution for now, at least this way WM handles everything. :) - experiment: moved button handlers to area level, that way it respects handlers on higher hierarchical level, like moving area edges. Als interesting is that you can have a button active (texteditor) and use a similar button in other area. This can also be done on region level even. On todo: proper notifier events for redraw! Don't want all areas to draw on simple refreshes --- .../blender/editors/interface/interface_ops.c | 23 +++++---- source/blender/editors/screen/screen_ops.c | 6 ++- source/blender/windowmanager/WM_api.h | 1 + source/blender/windowmanager/WM_types.h | 3 +- .../windowmanager/intern/wm_event_system.c | 51 ++++++++++++++----- .../windowmanager/intern/wm_init_exit.c | 7 +++ 6 files changed, 64 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 2d515aafc13..aa09a0a7ba7 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -2676,8 +2676,11 @@ static void button_activate_init(bContext *C, ARegion *ar, wmOperator *op, uiBut if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer()) but->block->auto_open= 0; - /* modal handler */ - WM_event_add_modal_handler(C, &C->window->handlers, op); + if(but->block->flag & UI_BLOCK_LOOP) + WM_event_add_modal_handler(C, &C->window->handlers, op); + else + /* regular button handler on area, handles mouse-exit in WM */ + WM_event_add_modal_handler(C, &C->area->handlers, op); button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); @@ -2791,19 +2794,19 @@ static int button_activate_try_exit(bContext *C, wmOperator *op, wmEvent *event) ARegion *ar; uiActivateBut *data; uiBut *but; - int state= OPERATOR_FINISHED; data= op->customdata; ar= data->region; but= ui_but_find_activated(data->region, data, NULL); - /* exit the current button, but try to re-init as well */ + /* exit the current button */ button_activate_exit(C, op->customdata, op); - /* XXX re-init has to be done differently... */ - /* XXX state= button_activate_try_init(C, ar, op, event, but); */ + + /* adds empty mousemove in queue for re-init operator (if mouse is still over button) */ + WM_event_add_mousemove(C); - return (state != OPERATOR_RUNNING_MODAL); + return 1; } static int button_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -2837,10 +2840,8 @@ static int button_activate_modal(bContext *C, wmOperator *op, wmEvent *event) /* check if the button dissappeared somehow */ if(!(but= ui_but_find_activated(data->region, data, &block))) { data->cancel= 1; - if(button_activate_try_exit(C, op, event)) - return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; - else - return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH; + button_activate_try_exit(C, op, event); + return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; } if(data->state == BUTTON_STATE_HIGHLIGHT) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 095f6e1a74b..ef8b47a368f 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -278,13 +278,17 @@ static int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event) } else { WM_set_cursor(C, CURSOR_X_MOVE); } - } else { + return OPERATOR_FINISHED; + } + else { ScrArea *sa= NULL; AZone *az= NULL; + for(sa= C->screen->areabase.first; sa; sa= sa->next) { az= is_in_area_actionzone(sa, event->x, event->y); if(az!=NULL) break; } + if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT); else WM_set_cursor(C, CURSOR_STD); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 4b9c01b3e33..509056bfe71 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -75,6 +75,7 @@ void WM_event_remove_handlers (bContext *C, ListBase *handlers); void WM_event_add_message(wmWindowManager *wm, void *customdata, short customdatafree); +void WM_event_add_mousemove(bContext *C); void WM_event_add_notifier(wmWindowManager *wm, wmWindow *window, int swinid, int type, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 35dad1f0db2..be0fbb4fca6 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -47,7 +47,8 @@ typedef struct wmEvent { short type; /* event code itself (short, is also in keymap) */ short val; /* press, release, scrollvalue */ - short x, y; /* mouse pointer position */ + short x, y; /* mouse pointer position */ + short prevx, prevy; /* previous mouse pointer position */ short unicode; /* future, ghost? */ char ascii; /* from ghost */ char pad1; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9432036b4bc..85cf0786403 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -326,7 +326,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) /* C is zero on freeing database, modal handlers then already were freed */ while((handler=handlers->first)) { - /* we have to remove the handler first, to prevent op->type->cancel() to remove modal handler too */ BLI_remlink(handlers, handler); if(C && handler->op) { @@ -473,18 +472,30 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect) return BLI_in_rcti(rect, event->x, event->y); } +static int wm_event_prev_inside_i(wmEvent *event, rcti *rect) +{ + if(BLI_in_rcti(rect, event->x, event->y)) + return 1; + if(event->type==MOUSEMOVE) { + if( BLI_in_rcti(rect, event->prevx, event->prevy)) { + return 1; + } + return 0; + } + return 0; +} + static ScrArea *area_event_inside(bContext *C, wmEvent *event) { ScrArea *sa; if(C->screen) for(sa= C->screen->areabase.first; sa; sa= sa->next) - if(wm_event_inside_i(event, &sa->totrct)) + if(BLI_in_rcti(&sa->totrct, event->x, event->y)) return sa; return NULL; } - /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -503,10 +514,10 @@ void wm_event_do_handlers(bContext *C) C->window= win; C->screen= win->screen; C->area= area_event_inside(C, event); - + /* MVC demands to not draw in event handlers... for now we leave it */ wm_window_make_drawable(C, win); - + action= wm_handlers_do(C, event, &win->handlers); /* modal menus in Blender use (own) regions linked to screen */ @@ -532,9 +543,11 @@ void wm_event_do_handlers(bContext *C) if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; + int doit= 0; for(sa= win->screen->areabase.first; sa; sa= sa->next) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) { + if(wm_event_always_pass(event) || wm_event_prev_inside_i(event, &sa->totrct)) { + doit= 1; C->area= sa; action= wm_handlers_do(C, event, &sa->handlers); @@ -546,24 +559,26 @@ void wm_event_do_handlers(bContext *C) C->region= NULL; if(!wm_event_always_pass(event)) { - action= WM_HANDLER_BREAK; - break; + if(action==WM_HANDLER_BREAK) + break; } } } } C->area= NULL; - - if(!wm_event_always_pass(event)) { - action= WM_HANDLER_BREAK; - break; - } + /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */ } } + /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? + doing it on ghost queue gives errors when mousemoves go over area borders */ + if(doit) { + C->window->eventstate->prevx= event->x; + C->window->eventstate->prevy= event->y; + } } wm_event_free(event); - + C->window= NULL; C->screen= NULL; } @@ -643,6 +658,14 @@ void WM_event_add_message(wmWindowManager *wm, void *customdata, short customdat } } +void WM_event_add_mousemove(bContext *C) +{ + wmEvent event= *(C->window->eventstate); + event.type= MOUSEMOVE; + wm_event_add(C->window, &event); + +} + /* ********************* ghost stuff *************** */ static int convert_key(GHOST_TKey key) diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fb8101168e2..3346f0607a9 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -164,6 +164,7 @@ void WM_exit(bContext *C) /* modal handlers are on window level freed, others too? */ if(C && C->wm) { for(win= C->wm->windows.first; win; win= win->next) { + ScrArea *sa; ARegion *ar; C->window= win; /* needed by operator close callbacks */ @@ -171,6 +172,12 @@ void WM_exit(bContext *C) for(ar= win->screen->regionbase.first; ar; ar= ar->next) WM_event_remove_handlers(C, &ar->handlers); + + for(sa= win->screen->areabase.first; sa; sa= sa->next) { + WM_event_remove_handlers(C, &sa->handlers); + for(ar= sa->regionbase.first; ar; ar= ar->next) + WM_event_remove_handlers(C, &ar->handlers); + } } } wm_operatortype_free();