WM: refactor gestures for use as tools
[blender.git] / source / blender / editors / space_view3d / view3d_edit.c
index 349f606b912b1a3febf92aadc471a2f198a2bd88..77a3556db0a7c34a4707876273753386d8a00d81 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BLI_bitmap_draw_2d.h"
 #include "BLI_blenlib.h"
 #include "BLI_kdopbvh.h"
 #include "BLI_math.h"
 
 #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);
 }
 
-static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
-{
-       View3D *v3d = CTX_wm_view3d(C);
-       RegionView3D *rv3d = CTX_wm_region_view3d(C);
-       if (ED_view3d_offset_lock_check(v3d, rv3d)) {
-               BKE_report(op->reports, RPT_WARNING, "View offset is locked");
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
 /* ********************** view3d_edit: view manipulations ********************* */
 
 /**
@@ -565,22 +555,20 @@ typedef struct ViewOpsData {
 
 static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
 {
-       float x, y, radius, d, z, t;
-
-       radius = TRACKBALLSIZE;
+       const float radius = TRACKBALLSIZE;
+       const float t = radius / (float)M_SQRT2;
+       float x, y, z, d;
 
        /* normalize x and y */
        x = BLI_rcti_cent_x(rect) - mx;
        x /= (float)(BLI_rcti_size_x(rect) / 4);
        y = BLI_rcti_cent_y(rect) - my;
        y /= (float)(BLI_rcti_size_y(rect) / 2);
-
        d = sqrtf(x * x + y * y);
-       if (d < radius * (float)M_SQRT1_2) { /* Inside sphere */
+       if (d < t) { /* Inside sphere */
                z = sqrtf(radius * radius - d * d);
        }
        else { /* On hyperbola */
-               t = radius / (float)M_SQRT2;
                z = t * t / d;
        }
 
@@ -711,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);
@@ -732,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 */
@@ -788,7 +823,7 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
                                    (float)vod->ar->winx / 2.0f,
                                    (float)vod->ar->winy / 2.0f};
 
-                               ED_view3d_win_to_3d(vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
+                               ED_view3d_win_to_3d(vod->v3d, vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
                                negate_v3(rv3d->ofs);
                        }
                        negate_v3(vod->dyn_ofs);
@@ -822,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)
@@ -1233,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 */
@@ -1329,6 +1353,8 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
        ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
 }
 
+#ifdef WITH_INPUT_NDOF
+
 /** \name NDOF Utility Functions
  * \{ */
 
@@ -1649,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);
@@ -1717,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;
 
@@ -1894,6 +1922,8 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
        ot->flag = 0;
 }
 
+#endif /* WITH_INPUT_NDOF */
+
 /* ************************ viewmove ******************************** */
 
 
@@ -2030,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);
@@ -2511,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);
@@ -2593,6 +2623,19 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
 
 
 /* ************************ viewdolly ******************************** */
+static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
+{
+       View3D *v3d = CTX_wm_view3d(C);
+       RegionView3D *rv3d = CTX_wm_region_view3d(C);
+       if (ED_view3d_offset_lock_check(v3d, rv3d)) {
+               BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked");
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
 static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
 {
        RegionView3D *rv3d = ar->regiondata;
@@ -2743,7 +2786,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
        ViewOpsData *vod;
 
-       if (view3d_operator_offset_lock_check(C, op))
+       if (viewdolly_offset_lock_check(C, op))
                return OPERATOR_CANCELLED;
 
        /* makes op->customdata */
@@ -2771,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 */
@@ -3284,7 +3327,7 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
                else {
                        /* fallback to simple pan */
                        negate_v3_v3(new_ofs, rv3d->ofs);
-                       ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs);
+                       ED_view3d_win_to_3d_int(v3d, ar, new_ofs, event->mval, new_ofs);
                }
                negate_v3(new_ofs);
                ED_view3d_smooth_view(
@@ -3464,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;
 
@@ -3537,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 */
@@ -3561,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);
 
@@ -3659,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);
@@ -3685,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;
 }
@@ -3700,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;
 
@@ -3709,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 */
@@ -4061,6 +4103,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
 
                        mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
 
+                       /* avoid precision loss over time */
+                       normalize_qt(quat_new);
+
                        if (view_opposite != RV3D_VIEW_USER) {
                                rv3d->view = view_opposite;
                                /* avoid float in-precision, just get a new orientation */
@@ -4127,6 +4172,10 @@ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4]
        axis_angle_normalized_to_quat(quat_mul, dvec, angle);
 
        mul_qt_qtqt(quat, orig_quat, quat_mul);
+
+       /* avoid precision loss over time */
+       normalize_qt(quat);
+
        rv3d->view = RV3D_VIEW_USER;
 }
 
@@ -4288,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);
@@ -4354,41 +4403,24 @@ static EnumPropertyItem prop_view_pan_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
-static int viewpan_exec(bContext *C, wmOperator *op)
+static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       ScrArea *sa = CTX_wm_area(C);
-       ARegion *ar = CTX_wm_region(C);
-       View3D *v3d = CTX_wm_view3d(C);
-       RegionView3D *rv3d = CTX_wm_region_view3d(C);
-       float vec[3];
-       const float co_zero[3] = {0.0f};
-       float mval_f[2] = {0.0f, 0.0f};
-       float zfac;
-       int pandir;
-
-       if (view3d_operator_offset_lock_check(C, op))
-               return OPERATOR_CANCELLED;
-
-       pandir = RNA_enum_get(op->ptr, "type");
-
-       ED_view3d_camera_lock_init(v3d, rv3d);
+       int x = 0, y = 0;
+       int pandir = RNA_enum_get(op->ptr, "type");
 
-       zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
-       if      (pandir == V3D_VIEW_PANRIGHT)  { mval_f[0] = -32.0f; }
-       else if (pandir == V3D_VIEW_PANLEFT)   { mval_f[0] =  32.0f; }
-       else if (pandir == V3D_VIEW_PANUP)     { mval_f[1] = -25.0f; }
-       else if (pandir == V3D_VIEW_PANDOWN)   { mval_f[1] =  25.0f; }
-       ED_view3d_win_to_delta(ar, mval_f, vec, zfac);
-       add_v3_v3(rv3d->ofs, vec);
+       if      (pandir == V3D_VIEW_PANRIGHT)  { x = -32; }
+       else if (pandir == V3D_VIEW_PANLEFT)   { x =  32; }
+       else if (pandir == V3D_VIEW_PANUP)     { y = -25; }
+       else if (pandir == V3D_VIEW_PANDOWN)   { y =  25; }
 
-       if (rv3d->viewlock & RV3D_BOXVIEW)
-               view3d_boxview_sync(sa, ar);
-
-       ED_view3d_depth_tag_update(rv3d);
+       viewops_data_alloc(C, op);
+       viewops_data_create(C, op, event, false);
+       ViewOpsData *vod = op->customdata;
 
-       ED_view3d_camera_lock_sync(v3d, rv3d);
+       viewmove_apply(vod, vod->oldx + x, vod->oldy + y);
 
-       ED_region_tag_redraw(ar);
+       ED_view3d_depth_tag_update(vod->rv3d);
+       viewops_data_free(C, op);
 
        return OPERATOR_FINISHED;
 }
@@ -4401,7 +4433,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
        ot->idname = "VIEW3D_OT_view_pan";
 
        /* api callbacks */
-       ot->exec = viewpan_exec;
+       ot->invoke = viewpan_invoke;
        ot->poll = ED_operator_region_view3d_active;
 
        /* flags */
@@ -4517,7 +4549,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
        /* identifiers */
        /* note: having key shortcut here is bad practice,
         * but for now keep because this displays when dragging an image over the 3D viewport */
-       ot->name   = "Add Background Image";
+       ot->name   = "Add Background Image (Ctrl for Empty Object)";
        ot->description = "Add a new background image (Ctrl for Empty Object)";
        ot->idname = "VIEW3D_OT_background_image_add";
 
@@ -4639,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);
        }
 }
 
@@ -4655,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;
 
@@ -4703,7 +4735,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
        if (depth_used == false) {
                float depth_pt[3];
                copy_v3_v3(depth_pt, fp);
-               ED_view3d_win_to_3d_int(ar, depth_pt, mval, fp);
+               ED_view3d_win_to_3d_int(v3d, ar, depth_pt, mval, fp);
        }
 }
 
@@ -4724,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);
                }
        }
 
@@ -4777,13 +4816,10 @@ static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
        if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
        if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
 
-       /* only no modifier or shift */
-       if (event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
-
        /* note; otherwise opengl won't work */
        view3d_operator_needs_opengl(C);
 
-       if (0 == BIF_do_manipulator(C, event, op))
+       if (BIF_do_manipulator(C, event, op) == 0)
                return OPERATOR_PASS_THROUGH;
 
        return OPERATOR_FINISHED;
@@ -4791,6 +4827,7 @@ static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
 void VIEW3D_OT_manipulator(wmOperatorType *ot)
 {
+       PropertyRNA *prop;
 
        /* identifiers */
        ot->name = "3D Manipulator";
@@ -4804,6 +4841,10 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot)
 
        /* properties to pass to transform */
        Transform_Properties(ot, P_CONSTRAINT);
+
+       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 | PROP_HIDDEN);
 }
 
 static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -4892,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);
@@ -4952,7 +4989,7 @@ bool ED_view3d_autodist(
        }
 
        if (fallback_depth_pt) {
-               ED_view3d_win_to_3d_int(ar, fallback_depth_pt, mval, mouse_worldloc);
+               ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
                return true;
        }
        else {
@@ -5048,7 +5085,7 @@ bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int
        copy_v2_v2_int(p1, mval_sta);
        copy_v2_v2_int(p2, mval_end);
 
-       plot_line_v2v2i(p1, p2, depth_segment_cb, &data);
+       BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
 
        *depth = data.depth;