2.5
authorTon Roosendaal <ton@blender.org>
Tue, 2 Dec 2008 18:49:58 +0000 (18:49 +0000)
committerTon Roosendaal <ton@blender.org>
Tue, 2 Dec 2008 18:49:58 +0000 (18:49 +0000)
- 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

source/blender/editors/interface/interface_ops.c
source/blender/editors/screen/screen_ops.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c

index 2d515aafc13c88ea88821ff983e30132cf49c9f9..aa09a0a7ba799bd2e49faab7f70cd5d36c7b3753 100644 (file)
@@ -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) {
index 095f6e1a74bd6c8df784dfe2cf2d79643d625a30..ef8b47a368fb9138e21df39e0c3e48f71e5453e5 100644 (file)
@@ -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);
        }
index 4b9c01b3e333c7d334f0eb0b86d0b814971c0d24..509056bfe71405099ac1689bc7dfdafd38a6c32d 100644 (file)
@@ -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,
index 35dad1f0db2539cbc659b1ee16918ac396770a30..be0fbb4fca6be4802771bd03290eb5f5cff6a739 100644 (file)
@@ -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;              
index 9432036b4bc760e22dd4789e458edf312850872b..85cf07864038277eae99b6d1beabc9d86911d3fe 100644 (file)
@@ -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) 
index fb8101168e21aed4ec9235ad69bb553b965e40e0..3346f0607a90099d6767a1b406626dbbbd55334e 100644 (file)
@@ -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();