Fix T44011: Ruler/Knife/Loop-cut fail in quad-view

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.
This commit is contained in:
Campbell Barton 2015-04-27 18:53:45 +10:00
parent 5df939fd15
commit 3f80accfb3
Notes: blender-bot 2023-10-12 12:49:04 +02:00
Referenced by issue #44582, Using Ruler on Recent builds cause crash
Referenced by issue #44011, Ruler/Protractor not working in Quad view
10 changed files with 91 additions and 13 deletions

View 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);

View 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.

View 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 */

View 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 */

View 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);

View 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

View 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__ */

View 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)

View 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);

View 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 */