WM: refactor gestures for use as tools
[blender.git] / source / blender / editors / space_view3d / view3d_edit.c
index df649a59f085a7d865d0096431cbf47fb51ac9b4..77a3556db0a7c34a4707876273753386d8a00d81 100644 (file)
@@ -85,6 +85,8 @@
 
 #include "view3d_intern.h"  /* own include */
 
+static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar);
+
 bool ED_view3d_offset_lock_check(const  View3D *v3d, const  RegionView3D *rv3d)
 {
        return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
@@ -697,16 +699,72 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
        return is_set;
 }
 
+enum eViewOpsOrbit {
+       VIEWOPS_ORBIT_SELECT = (1 << 0),
+       VIEWOPS_ORBIT_DEPTH = (1 << 1),
+};
+
+static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth)
+{
+       enum eViewOpsOrbit flag = 0;
+       if (use_select) {
+               flag |= VIEWOPS_ORBIT_SELECT;
+       }
+       if (use_depth) {
+               flag |= VIEWOPS_ORBIT_DEPTH;
+       }
+
+       return flag;
+}
+
+static enum eViewOpsOrbit viewops_orbit_mode(void)
+{
+       return viewops_orbit_mode_ex(
+               (U.uiflag & USER_ORBIT_SELECTION) != 0,
+               (U.uiflag & USER_ZBUF_ORBIT) != 0);
+}
+
 /**
  * Calculate the values for #ViewOpsData
+ *
+ * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of
+ * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled.
+ * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common
+ * so we don't want it to trigger auto-perspective).
  */
-static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *event,
-                                   const bool use_orbit_select,
-                                   const bool use_orbit_zbuf)
+static void viewops_data_create_ex(
+        bContext *C, wmOperator *op, const wmEvent *event,
+        bool use_ensure_persp, enum eViewOpsOrbit orbit_mode)
 {
        ViewOpsData *vod = op->customdata;
        RegionView3D *rv3d = vod->rv3d;
 
+       /* we need the depth info before changing any viewport options */
+       if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+               float fallback_depth_pt[3];
+
+               view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
+
+               negate_v3_v3(fallback_depth_pt, rv3d->ofs);
+
+               vod->use_dyn_ofs = ED_view3d_autodist(
+                       vod->scene, vod->ar, vod->v3d,
+                       event->mval, vod->dyn_ofs, true, fallback_depth_pt);
+       }
+       else {
+               vod->use_dyn_ofs = false;
+       }
+
+       if (use_ensure_persp) {
+               if (view3d_ensure_persp(vod->v3d, vod->ar)) {
+                       /* If we're switching from camera view to the perspective one,
+                        * need to tag viewport update, so camera vuew and borders
+                        * are properly updated.
+                        */
+                       ED_region_tag_redraw(vod->ar);
+               }
+       }
+
        /* set the view from the camera, if view locking is enabled.
         * we may want to make this optional but for now its needed always */
        ED_view3d_camera_lock_init(vod->v3d, vod->rv3d);
@@ -718,28 +776,19 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
        vod->origx = vod->oldx = event->x;
        vod->origy = vod->oldy = event->y;
        vod->origkey = event->type; /* the key that triggered the operator.  */
-       vod->use_dyn_ofs = false;
        copy_v3_v3(vod->ofs, rv3d->ofs);
 
-       if (use_orbit_select) {
-
-               vod->use_dyn_ofs = true;
-
-               view3d_orbit_calc_center(C, vod->dyn_ofs);
-
-               negate_v3(vod->dyn_ofs);
+       if (orbit_mode & VIEWOPS_ORBIT_SELECT) {
+               float ofs[3];
+               if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
+                       vod->use_dyn_ofs = true;
+                       negate_v3_v3(vod->dyn_ofs, ofs);
+                       orbit_mode &= ~VIEWOPS_ORBIT_DEPTH;
+               }
        }
-       else if (use_orbit_zbuf) {
-               Scene *scene = CTX_data_scene(C);
-               float fallback_depth_pt[3];
 
-               view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
-
-               negate_v3_v3(fallback_depth_pt, rv3d->ofs);
-
-               if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d,
-                                                          event->mval, vod->dyn_ofs, true, fallback_depth_pt)))
-               {
+       if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+               if (vod->use_dyn_ofs) {
                        if (rv3d->is_persp) {
                                float my_origin[3]; /* original G.vd->ofs */
                                float my_pivot[3]; /* view */
@@ -808,12 +857,10 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
        rv3d->rflag |= RV3D_NAVIGATING;
 }
 
-static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp)
 {
-       viewops_data_create_ex(
-               C, op, event,
-               (U.uiflag & USER_ORBIT_SELECTION) != 0,
-               (U.uiflag & USER_ZBUF_ORBIT) != 0);
+       enum eViewOpsOrbit orbit_mode = viewops_orbit_mode();
+       viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode);
 }
 
 static void viewops_data_free(bContext *C, wmOperator *op)
@@ -1219,16 +1266,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
        ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
 
-       /* switch from camera view when: */
-       if (view3d_ensure_persp(vod->v3d, vod->ar)) {
-               /* If we're switching from camera view to the perspective one,
-                * need to tag viewport update, so camera vuew and borders
-                * are properly updated.
-                */
-               ED_region_tag_redraw(vod->ar);
-       }
-
-       viewops_data_create(C, op, event);
+       viewops_data_create(C, op, event, true);
 
        if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
                /* Rotate direction we keep always same */
@@ -1637,8 +1675,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
                const wmNDOFMotionData *ndof = event->customdata;
 
                viewops_data_alloc(C, op);
-               viewops_data_create_ex(C, op, event,
-                                      (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+               viewops_data_create_ex(
+                       C, op, event,
+                       false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
                vod = op->customdata;
 
                ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -1705,8 +1744,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
                const wmNDOFMotionData *ndof = event->customdata;
 
                viewops_data_alloc(C, op);
-               viewops_data_create_ex(C, op, event,
-                                      (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+               viewops_data_create_ex(
+                       C, op, event,
+                       false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false));
 
                vod = op->customdata;
 
@@ -2020,7 +2060,7 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
        /* makes op->customdata */
        viewops_data_alloc(C, op);
-       viewops_data_create(C, op, event);
+       viewops_data_create(C, op, event, false);
        vod = op->customdata;
 
        ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2501,7 +2541,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
        /* makes op->customdata */
        viewops_data_alloc(C, op);
-       viewops_data_create(C, op, event);
+       viewops_data_create(C, op, event, false);
        vod = op->customdata;
 
        ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2774,7 +2814,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
                ED_region_tag_redraw(vod->ar);
        }
 
-       viewops_data_create(C, op, event);
+       viewops_data_create(C, op, event, false);
 
 
        /* if one or the other zoom position aren't set, set from event */
@@ -3467,10 +3507,10 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
        ot->idname = "VIEW3D_OT_render_border";
 
        /* api callbacks */
-       ot->invoke = WM_border_select_invoke;
+       ot->invoke = WM_gesture_border_invoke;
        ot->exec = render_border_exec;
-       ot->modal = WM_border_select_modal;
-       ot->cancel = WM_border_select_cancel;
+       ot->modal = WM_gesture_border_modal;
+       ot->cancel = WM_gesture_border_cancel;
 
        ot->poll = ED_operator_view3d_active;
 
@@ -3540,7 +3580,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
        View3D *v3d = CTX_wm_view3d(C);
        RegionView3D *rv3d = CTX_wm_region_view3d(C);
        Scene *scene = CTX_data_scene(C);
-       int gesture_mode;
        const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
 
        /* Zooms in on a border drawn by the user */
@@ -3564,7 +3603,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
        WM_operator_properties_border_to_rcti(op, &rect);
 
        /* check if zooming in/out view */
-       gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+       const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
 
        ED_view3d_dist_range_get(v3d, dist_range);
 
@@ -3662,7 +3701,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
                new_dist *= max_ff(xscale, yscale);
        }
 
-       if (gesture_mode == GESTURE_MODAL_OUT) {
+       if (!zoom_in) {
                sub_v3_v3v3(dvec, new_ofs, rv3d->ofs);
                new_dist = rv3d->dist * (rv3d->dist / new_dist);
                add_v3_v3v3(new_ofs, rv3d->ofs, dvec);
@@ -3688,7 +3727,7 @@ static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, const wmEvent
 
        /* if in camera view do not exec the operator so we do not conflict with set render border*/
        if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d))
-               return WM_border_select_invoke(C, op, event);
+               return WM_gesture_border_invoke(C, op, event);
        else
                return OPERATOR_PASS_THROUGH;
 }
@@ -3703,8 +3742,8 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke = view3d_zoom_border_invoke;
        ot->exec = view3d_zoom_border_exec;
-       ot->modal = WM_border_select_modal;
-       ot->cancel = WM_border_select_cancel;
+       ot->modal = WM_gesture_border_modal;
+       ot->cancel = WM_gesture_border_cancel;
 
        ot->poll = ED_operator_region_view3d_active;
 
@@ -3712,7 +3751,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
        ot->flag = 0;
 
        /* rna */
-       WM_operator_properties_gesture_border(ot, false);
+       WM_operator_properties_gesture_border_zoom(ot);
 }
 
 /* sets the view to 1:1 camera/render-pixel */
@@ -4298,7 +4337,7 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
        else {
                /* makes op->customdata */
                viewops_data_alloc(C, op);
-               viewops_data_create(C, op, event);
+               viewops_data_create(C, op, event, false);
                vod = op->customdata;
 
                ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -4375,7 +4414,7 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
        else if (pandir == V3D_VIEW_PANDOWN)   { y =  25; }
 
        viewops_data_alloc(C, op);
-       viewops_data_create(C, op, event);
+       viewops_data_create(C, op, event, false);
        ViewOpsData *vod = op->customdata;
 
        viewmove_apply(vod, vod->oldx + x, vod->oldy + y);
@@ -4632,7 +4671,7 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev
                return OPERATOR_FINISHED;
        }
        else {
-               return WM_border_select_invoke(C, op, event);
+               return WM_gesture_border_invoke(C, op, event);
        }
 }
 
@@ -4648,8 +4687,8 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke = view3d_clipping_invoke;
        ot->exec = view3d_clipping_exec;
-       ot->modal = WM_border_select_modal;
-       ot->cancel = WM_border_select_cancel;
+       ot->modal = WM_gesture_border_modal;
+       ot->cancel = WM_gesture_border_cancel;
 
        ot->poll = ED_operator_region_view3d_active;
 
@@ -4717,13 +4756,20 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
                ARegion *ar = CTX_wm_region(C);
                RegionView3D *rv3d = ar->regiondata;
 
-               float co_curr[2], co_prev[2];
+               if (U.uiflag & USER_LOCK_CURSOR_ADJUST) {
 
-               if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
-                   (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
-               {
-                       rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
-                       rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+                       float co_curr[2], co_prev[2];
+
+                       if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+                           (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+                       {
+                               rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
+                               rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+                       }
+               }
+               else {
+                       /* Cursor may be outside of the view, prevent it getting 'lost', see: T40353 & T45301 */
+                       zero_v2(rv3d->ofs_lock);
                }
        }
 
@@ -4798,7 +4844,7 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot)
 
        prop = RNA_def_boolean(ot->srna, "use_planar_constraint", false, "Planar Constraint", "Limit the transformation to the "
                               "two axes that have not been clicked (translate/scale only)");
-       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
 }
 
 static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -4887,11 +4933,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
                rect.ymax = mval[1] + 1;
        }
        else {
-               rect.xmax = mval[0] + margin;
-               rect.ymax = mval[1] + margin;
-
-               rect.xmin = mval[0] - margin;
-               rect.ymin = mval[1] - margin;
+               BLI_rcti_init_pt_radius(&rect, mval, margin);
        }
 
        view3d_update_depths_rect(ar, &depth_temp, &rect);