- 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
This commit is contained in:
Ton Roosendaal 2008-12-02 18:49:58 +00:00
parent 6a6b386832
commit d27c9f9d76
6 changed files with 64 additions and 27 deletions

@ -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()) if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer())
but->block->auto_open= 0; but->block->auto_open= 0;
/* modal handler */ if(but->block->flag & UI_BLOCK_LOOP)
WM_event_add_modal_handler(C, &C->window->handlers, op); 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); 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; ARegion *ar;
uiActivateBut *data; uiActivateBut *data;
uiBut *but; uiBut *but;
int state= OPERATOR_FINISHED;
data= op->customdata; data= op->customdata;
ar= data->region; ar= data->region;
but= ui_but_find_activated(data->region, data, NULL); 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); 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) 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 */ /* check if the button dissappeared somehow */
if(!(but= ui_but_find_activated(data->region, data, &block))) { if(!(but= ui_but_find_activated(data->region, data, &block))) {
data->cancel= 1; data->cancel= 1;
if(button_activate_try_exit(C, op, event)) button_activate_try_exit(C, op, event);
return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
else
return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH;
} }
if(data->state == BUTTON_STATE_HIGHLIGHT) { if(data->state == BUTTON_STATE_HIGHLIGHT) {

@ -278,13 +278,17 @@ static int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event)
} else { } else {
WM_set_cursor(C, CURSOR_X_MOVE); WM_set_cursor(C, CURSOR_X_MOVE);
} }
} else { return OPERATOR_FINISHED;
}
else {
ScrArea *sa= NULL; ScrArea *sa= NULL;
AZone *az= NULL; AZone *az= NULL;
for(sa= C->screen->areabase.first; sa; sa= sa->next) { for(sa= C->screen->areabase.first; sa; sa= sa->next) {
az= is_in_area_actionzone(sa, event->x, event->y); az= is_in_area_actionzone(sa, event->x, event->y);
if(az!=NULL) break; if(az!=NULL) break;
} }
if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT); if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT);
else WM_set_cursor(C, CURSOR_STD); else WM_set_cursor(C, CURSOR_STD);
} }

@ -75,6 +75,7 @@ void WM_event_remove_handlers (bContext *C, ListBase *handlers);
void WM_event_add_message(wmWindowManager *wm, void *customdata, void WM_event_add_message(wmWindowManager *wm, void *customdata,
short customdatafree); short customdatafree);
void WM_event_add_mousemove(bContext *C);
void WM_event_add_notifier(wmWindowManager *wm, wmWindow *window, void WM_event_add_notifier(wmWindowManager *wm, wmWindow *window,
int swinid, int type, int swinid, int type,

@ -47,7 +47,8 @@ typedef struct wmEvent {
short type; /* event code itself (short, is also in keymap) */ short type; /* event code itself (short, is also in keymap) */
short val; /* press, release, scrollvalue */ 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? */ short unicode; /* future, ghost? */
char ascii; /* from ghost */ char ascii; /* from ghost */
char pad1; char pad1;

@ -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 */ /* C is zero on freeing database, modal handlers then already were freed */
while((handler=handlers->first)) { 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); BLI_remlink(handlers, handler);
if(C && handler->op) { 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); 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) static ScrArea *area_event_inside(bContext *C, wmEvent *event)
{ {
ScrArea *sa; ScrArea *sa;
if(C->screen) if(C->screen)
for(sa= C->screen->areabase.first; sa; sa= sa->next) 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 sa;
return NULL; return NULL;
} }
/* called in main loop */ /* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C) void wm_event_do_handlers(bContext *C)
@ -503,10 +514,10 @@ void wm_event_do_handlers(bContext *C)
C->window= win; C->window= win;
C->screen= win->screen; C->screen= win->screen;
C->area= area_event_inside(C, event); C->area= area_event_inside(C, event);
/* MVC demands to not draw in event handlers... for now we leave it */ /* MVC demands to not draw in event handlers... for now we leave it */
wm_window_make_drawable(C, win); wm_window_make_drawable(C, win);
action= wm_handlers_do(C, event, &win->handlers); action= wm_handlers_do(C, event, &win->handlers);
/* modal menus in Blender use (own) regions linked to screen */ /* 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) { if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) {
ScrArea *sa; ScrArea *sa;
ARegion *ar; ARegion *ar;
int doit= 0;
for(sa= win->screen->areabase.first; sa; sa= sa->next) { 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; C->area= sa;
action= wm_handlers_do(C, event, &sa->handlers); action= wm_handlers_do(C, event, &sa->handlers);
@ -546,24 +559,26 @@ void wm_event_do_handlers(bContext *C)
C->region= NULL; C->region= NULL;
if(!wm_event_always_pass(event)) { if(!wm_event_always_pass(event)) {
action= WM_HANDLER_BREAK; if(action==WM_HANDLER_BREAK)
break; break;
} }
} }
} }
} }
C->area= NULL; C->area= NULL;
/* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
if(!wm_event_always_pass(event)) {
action= WM_HANDLER_BREAK;
break;
}
} }
} }
/* 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); wm_event_free(event);
C->window= NULL; C->window= NULL;
C->screen= 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 *************** */ /* ********************* ghost stuff *************** */
static int convert_key(GHOST_TKey key) static int convert_key(GHOST_TKey key)

@ -164,6 +164,7 @@ void WM_exit(bContext *C)
/* modal handlers are on window level freed, others too? */ /* modal handlers are on window level freed, others too? */
if(C && C->wm) { if(C && C->wm) {
for(win= C->wm->windows.first; win; win= win->next) { for(win= C->wm->windows.first; win; win= win->next) {
ScrArea *sa;
ARegion *ar; ARegion *ar;
C->window= win; /* needed by operator close callbacks */ 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) for(ar= win->screen->regionbase.first; ar; ar= ar->next)
WM_event_remove_handlers(C, &ar->handlers); 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(); wm_operatortype_free();