Fix T44011: Ruler/Knife/Loop-cut fail in quad-view
authorCampbell Barton <ideasman42@gmail.com>
Mon, 27 Apr 2015 08:53:45 +0000 (18:53 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 27 Apr 2015 09:17:07 +0000 (19:17 +1000)
This is a kind of sloppy-focus,
resolving long standing bug with loop-cut/knife/ruler /w quad-view.

Where activating a tool would lock onto one of quad-views,
especially problematic when activating from the toolbar or menus.

source/blender/blenkernel/BKE_screen.h
source/blender/blenkernel/intern/screen.c
source/blender/editors/mesh/editmesh_knife.c
source/blender/editors/mesh/editmesh_loopcut.c
source/blender/editors/space_view3d/view3d_ruler.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_wm.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/wm_event_system.h

index 43499933d16437fd61f248ca3a38537a2c422d63..bb764540da9ba2b9667df4f2929e3b02092fb594 100644 (file)
@@ -280,6 +280,7 @@ void            BKE_screen_area_free(struct ScrArea *sa);
 
 struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
 struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
 struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
 struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
 struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
index 3c43bfa2920434f67b5a1ba78eea1b2a694885ad..36fd598cc7067fd656bbc990e35f7dbf60162312 100644 (file)
@@ -405,6 +405,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa)
        return NULL;
 }
 
+ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+{
+       ARegion *ar_found = NULL;
+       if (sa) {
+               ARegion *ar;
+               for (ar = sa->regionbase.first; ar; ar = ar->next) {
+                       if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
+                               if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+                                       ar_found = ar;
+                                       break;
+                               }
+                       }
+               }
+       }
+       return ar_found;
+}
+
 /**
  * \note, ideally we can get the area from the context,
  * there are a few places however where this isn't practical.
index df91679b5f001b5f9fc0e7127b45daedc03239a2..4f8839005c9b9f59723eb56d6310e4261066807d 100644 (file)
@@ -3051,6 +3051,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
        knifetool_init(C, kcd, only_select, cut_through, true);
 
+       op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
        /* add a modal handler for this operator - handles loop selection */
        WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
        WM_event_add_modal_handler(C, op);
@@ -3143,6 +3145,9 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
                return OPERATOR_FINISHED;
        }
 
+       em_setup_viewcontext(C, &kcd->vc);
+       kcd->ar = kcd->vc.ar;
+
        view3d_operator_needs_opengl(C);
        ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d);  /* needed to initialize clipping */
 
@@ -3302,6 +3307,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
                }
        }
 
+       if (kcd->mode == MODE_DRAGGING) {
+               op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+       }
+       else {
+               op->flag |= OP_IS_MODAL_CURSOR_REGION;
+       }
+
        if (do_refresh) {
                /* we don't really need to update mval,
                 * but this happens to be the best way to refresh at the moment */
index a4ea2ab39213298e2593be27275af5ca4dc67420..c7f9522ab3f58b8f945492e86571efd99d801a7f 100644 (file)
@@ -553,6 +553,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
 
        /* add a modal handler for this operator - handles loop selection */
        if (is_interactive) {
+               op->flag |= OP_IS_MODAL_CURSOR_REGION;
                WM_event_add_modal_handler(C, op);
        }
 
@@ -639,6 +640,9 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
        bool show_cuts = false;
        const bool has_numinput = hasNumInput(&lcd->num);
 
+       em_setup_viewcontext(C, &lcd->vc);
+       lcd->ar = lcd->vc.ar;
+
        view3d_operator_needs_opengl(C);
 
        /* using the keyboard to input the number of cuts */
index eba31866f54ede51874f19f332a5540aba138977..addda0a8b6642b09d4fe829af7003f3b7de757d7 100644 (file)
@@ -187,6 +187,7 @@ typedef struct RulerInfo {
 
        /* wm state */
        wmWindow *win;
+       ScrArea *sa;
        ARegion *ar;
        void *draw_handle_pixel;
 } RulerInfo;
@@ -435,7 +436,7 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
        UnitSettings *unit = &scene->unit;
        RulerItem *ruler_item;
        RulerInfo *ruler_info = arg;
-       RegionView3D *rv3d = ruler_info->ar->regiondata;
+       RegionView3D *rv3d = ar->regiondata;
 //     ARegion *ar = ruler_info->ar;
        const float cap_size = 4.0f;
        const float bg_margin = 4.0f * U.pixelsize;
@@ -798,12 +799,14 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
        op->customdata = ruler_info;
 
        ruler_info->win = win;
-       ruler_info->ar = ar;
+       ruler_info->sa = sa;
        ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
                                                                   ruler_info, REGION_DRAW_POST_PIXEL);
 
        view3d_ruler_header_update(sa);
 
+       op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
        WM_cursor_modal_set(win, BC_CROSSCURSOR);
        WM_event_add_modal_handler(C, op);
 
@@ -829,11 +832,13 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
        RegionView3D *rv3d = ar->regiondata;
 
        /* its possible to change spaces while running the operator [#34894] */
-       if (UNLIKELY(ar != CTX_wm_region(C))) {
+       if (UNLIKELY(sa != ruler_info->sa)) {
                exit_code = OPERATOR_FINISHED;
                goto exit;
        }
 
+       ruler_info->ar = ar;
+
        switch (event->type) {
                case LEFTMOUSE:
                        if (event->val == KM_RELEASE) {
@@ -1019,6 +1024,13 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
 
        }
 
+       if (ruler_info->state == RULER_STATE_DRAG) {
+               op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+       }
+       else {
+               op->flag |= OP_IS_MODAL_CURSOR_REGION;
+       }
+
        if (do_draw) {
                view3d_ruler_header_update(sa);
 
index 13365adeb58e04e0ebb6a2dbdff1471721cb88b5..eb76c90c0fc4e173a5ffe79402225c25a0ee6681 100644 (file)
@@ -374,6 +374,8 @@ enum {
        RGN_TYPE_TOOL_PROPS = 6,
        RGN_TYPE_PREVIEW = 7
 };
+/* use for function args */
+#define RGN_TYPE_ANY -1
 
 /* region alignment */
 #define RGN_ALIGN_NONE         0
index 4aa49eea2e837d6e2053e01315837a3b7343a46f..51ed8bb6c0d0a36411dd7bf5298a34a3d5fb8c4e 100644 (file)
@@ -390,10 +390,16 @@ enum {
 
 /* wmOperator flag */
 enum {
-       OP_IS_MODAL_GRAB_CURSOR    = (1 << 0),
        /* low level flag so exec() operators can tell if they were invoked, use with care.
         * typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */
-       OP_IS_INVOKE       = (1 << 1),
+       OP_IS_INVOKE = (1 << 0),
+
+       /* When the cursor is grabbed */
+       OP_IS_MODAL_GRAB_CURSOR    = (1 << 1),
+
+       /* allow modal operators to have the region under the cursor for their context
+        * (the regiontype is maintained to prevent errors) */
+       OP_IS_MODAL_CURSOR_REGION = (1 << 2),
 };
 
 #endif /* __DNA_WINDOWMANAGER_TYPES_H__ */
index ded4ea02a9bef723ef2523d23d7f3fc701e49bde..3b8ddd011c0614356885cb666e4a24451565fb7c 100644 (file)
@@ -1416,6 +1416,10 @@ static void rna_def_operator_options_runtime(BlenderRNA *brna)
        RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_INVOKE);
        RNA_def_property_ui_text(prop, "Invoke", "True when invoked (even if only the execute callbacks available)");
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+       prop = RNA_def_property(srna, "use_cursor_region", PROP_BOOLEAN, PROP_BOOLEAN);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_CURSOR_REGION);
+       RNA_def_property_ui_text(prop, "Focus Region", "Enable to use the region under the cursor for modal execution");
 }
 
 static void rna_def_operator(BlenderRNA *brna)
index 8c97d399385a0de0c418e8d85e6770e4c6d8c345..830feed2fc7c8caac50752063d402dcfa8b5d831 100644 (file)
@@ -1337,7 +1337,7 @@ void wm_event_free_handler(wmEventHandler *handler)
 }
 
 /* only set context when area/region is part of screen */
-static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
+static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
 {
        bScreen *screen = CTX_wm_screen(C);
        
@@ -1358,10 +1358,27 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
                        }
                        else {
                                ARegion *ar;
+                               wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
                                CTX_wm_area_set(C, sa);
-                               for (ar = sa->regionbase.first; ar; ar = ar->next)
-                                       if (ar == handler->op_region)
-                                               break;
+
+                               if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
+                                       ar = BKE_area_find_region_xy(sa, handler->op_region_type, event->x, event->y);
+                                       if (ar) {
+                                               handler->op_region = ar;
+                                       }
+                               }
+                               else {
+                                       ar = NULL;
+                               }
+
+                               if (ar == NULL) {
+                                       for (ar = sa->regionbase.first; ar; ar = ar->next) {
+                                               if (ar == handler->op_region) {
+                                                       break;
+                                               }
+                                       }
+                               }
+
                                /* XXX no warning print here, after full-area and back regions are remade */
                                if (ar)
                                        CTX_wm_region_set(C, ar);
@@ -1379,11 +1396,12 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
        /* C is zero on freeing database, modal handlers then already were freed */
        while ((handler = BLI_pophead(handlers))) {
                if (handler->op) {
+                       wmWindow *win = CTX_wm_window(C);
                        if (handler->op->type->cancel) {
                                ScrArea *area = CTX_wm_area(C);
                                ARegion *region = CTX_wm_region(C);
                                
-                               wm_handler_op_context(C, handler);
+                               wm_handler_op_context(C, handler, win->eventstate);
 
                                if (handler->op->type->flag & OPTYPE_UNDO)
                                        wm->op_undo_depth++;
@@ -1397,7 +1415,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                                CTX_wm_region_set(C, region);
                        }
 
-                       WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+                       WM_cursor_grab_disable(win, NULL);
                        WM_operator_free(handler->op);
                }
                else if (handler->ui_remove) {
@@ -1569,7 +1587,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        ARegion *region = CTX_wm_region(C);
                        bool dbl_click_disabled = false;
 
-                       wm_handler_op_context(C, handler);
+                       wm_handler_op_context(C, handler, event);
                        wm_region_mouse_co(C, event);
                        wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
                        
@@ -1717,7 +1735,7 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
                                ED_screen_full_prevspace(C, CTX_wm_area(C));
                        }
 
-                       wm_handler_op_context(C, handler);
+                       wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
 
                        /* needed for UI_popup_menu_reports */
 
@@ -2534,6 +2552,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
        
        handler->op_area = CTX_wm_area(C);       /* means frozen screen context for modal handlers! */
        handler->op_region = CTX_wm_region(C);
+       handler->op_region_type = handler->op_region ? handler->op_region->regiontype : -1;
        
        BLI_addhead(&win->modalhandlers, handler);
 
index f89177a82ea1dc3af92a395fbfa295c9fb19d071..a097343d037a0cef490ca38915d174e51cb77431 100644 (file)
@@ -56,6 +56,7 @@ typedef struct wmEventHandler {
        wmOperator *op;                     /* for derived/modal handlers */
        struct ScrArea *op_area;            /* for derived/modal handlers */
        struct ARegion *op_region;          /* for derived/modal handlers */
+       short           op_region_type;     /* for derived/modal handlers */
 
        /* ui handler */
        wmUIHandlerFunc ui_handle;          /* callback receiving events */