Multitouch trackpad 2 fingers gestures implementation
[blender-staging.git] / source / blender / editors / space_view3d / view3d_edit.c
index f53f7fdba9ce2fddad98e41732176fa6d3b3e2d4..288918c3c1e9f0a39c2c2afe4597a6b5b7b4c8f2 100644 (file)
@@ -234,13 +234,20 @@ typedef struct ViewOpsData {
        ARegion *ar;
        RegionView3D *rv3d;
 
+       /* needed for continuous zoom */
+       wmTimer *timer;
+       double timer_lastdraw;
+
        float oldquat[4];
        float trackvec[3];
-       float ofs[3], obofs[3];
        float reverse, dist0;
        float grid, far;
        short axis_snap; /* view rotate only */
 
+       /* use for orbit selection and auto-dist */
+       float ofs[3], dyn_ofs[3];
+       short use_dyn_ofs;
+
        int origx, origy, oldx, oldy;
        int origkey; /* the key that triggered the operator */
 
@@ -275,7 +282,7 @@ static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
 }
 
 
-static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
 {
        static float lastofs[3] = {0,0,0};
        View3D *v3d = CTX_wm_view3d(C);
@@ -292,14 +299,56 @@ static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
        vod->origx= vod->oldx= event->x;
        vod->origy= vod->oldy= event->y;
        vod->origkey= event->type; /* the key that triggered the operator.  */
-       
-       if (U.uiflag & USER_ORBIT_SELECTION)
-       {
+       vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
+
+       if (vod->use_dyn_ofs) {
                VECCOPY(vod->ofs, rv3d->ofs);
                /* If there's no selection, lastofs is unmodified and last value since static */
-               calculateTransformCenter(C, event, V3D_CENTROID, lastofs);
-               VECCOPY(vod->obofs, lastofs);
-               mul_v3_fl(vod->obofs, -1.0f);
+               calculateTransformCenter(C, V3D_CENTROID, lastofs);
+               VECCOPY(vod->dyn_ofs, lastofs);
+               mul_v3_fl(vod->dyn_ofs, -1.0f);
+       }
+       else if (U.uiflag & USER_ORBIT_ZBUF) {
+
+               view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
+
+               if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, v3d, event->mval, vod->dyn_ofs))) {
+                       if (rv3d->persp==RV3D_PERSP) {
+                               float my_origin[3]; /* original G.vd->ofs */
+                               float my_pivot[3]; /* view */
+                               float dvec[3];
+
+                               // locals for dist correction
+                               float mat[3][3];
+                               float upvec[3];
+
+                               VECCOPY(my_origin, rv3d->ofs);
+                               negate_v3(my_origin);                           /* ofs is flipped */
+
+                               /* Set the dist value to be the distance from this 3d point */
+                               /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
+
+                               /* remove dist value */
+                               upvec[0] = upvec[1] = 0;
+                               upvec[2] = rv3d->dist;
+                               copy_m3_m4(mat, rv3d->viewinv);
+
+                               mul_m3_v3(mat, upvec);
+                               sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
+                               negate_v3(my_pivot);                            /* ofs is flipped */
+
+                               /* find a new ofs value that is allong the view axis (rather then the mouse location) */
+                               closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
+                               vod->dist0 = rv3d->dist = len_v3v3(my_pivot, dvec);
+
+                               negate_v3(dvec);
+                               VECCOPY(rv3d->ofs, dvec);
+                       }
+                       negate_v3(vod->dyn_ofs);
+                       VECCOPY(vod->ofs, rv3d->ofs);
+               } else {
+                       vod->ofs[0] = vod->ofs[1] = vod->ofs[2] = 0.0f;
+               }
        }
 
        /* lookup, we dont pass on v3d to prevent confusement */
@@ -314,6 +363,24 @@ static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
        if (rv3d->persmat[2][1] < 0.0f)
                vod->reverse= -1.0f;
 
+       rv3d->rflag |= RV3D_NAVIGATING;
+}
+
+static void viewops_data_free(bContext *C, wmOperator *op)
+{
+       Paint *p = paint_get_active(CTX_data_scene(C));
+       ViewOpsData *vod= op->customdata;
+
+       vod->rv3d->rflag &= ~RV3D_NAVIGATING;
+
+       if(p && (p->flags & PAINT_FAST_NAVIGATE))
+               ED_region_tag_redraw(vod->ar);
+
+       if(vod->timer)
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), vod->timer);
+
+       MEM_freeN(vod);
+       op->customdata= NULL;
 }
 
 /* ************************** viewrotate **********************************/
@@ -378,7 +445,9 @@ enum {
 #define VIEW_MODAL_CONFIRM                             1 /* used for all view operations */
 #define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2
 #define VIEWROT_MODAL_AXIS_SNAP_DISABLE        3
-
+#define VIEWROT_MODAL_SWITCH_ZOOM              4
+#define VIEWROT_MODAL_SWITCH_MOVE              5
+#define VIEWROT_MODAL_SWITCH_ROTATE            6
 
 /* called in transform_ops.c, on each regeneration of keymaps  */
 void viewrotate_modal_keymap(wmKeyConfig *keyconf)
@@ -387,7 +456,10 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
        {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Cancel", ""},
 
        {VIEWROT_MODAL_AXIS_SNAP_ENABLE,        "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
-       {VIEWROT_MODAL_AXIS_SNAP_DISABLE,       "AXIS_SNAP_DISABLE", 0, "Enable Axis Snap", ""},
+       {VIEWROT_MODAL_AXIS_SNAP_DISABLE,       "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""},
+               
+       {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
+       {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
 
        {0, NULL, 0, NULL, NULL}};
 
@@ -402,9 +474,13 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
        WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
 
-       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
-       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
+       WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
+       WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
 
+       WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
+       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
+       WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
+       
        /* assign map to operators */
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
 
@@ -413,7 +489,6 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
 static void viewrotate_apply(ViewOpsData *vod, int x, int y)
 {
        RegionView3D *rv3d= vod->rv3d;
-       int use_sel= U.uiflag & USER_ORBIT_SELECTION;
 
        rv3d->view= 0; /* need to reset everytime because of view snapping */
 
@@ -449,7 +524,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
                q1[3]*= si;
                mul_qt_qtqt(rv3d->viewquat, q1, vod->oldquat);
 
-               if (use_sel) {
+               if (vod->use_dyn_ofs) {
                        /* compute the post multiplication quat, to rotate the offset correctly */
                        QUATCOPY(q1, vod->oldquat);
                        conjugate_qt(q1);
@@ -457,9 +532,9 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
 
                        conjugate_qt(q1); /* conj == inv for unit quat */
                        VECCOPY(rv3d->ofs, vod->ofs);
-                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                        mul_qt_v3(q1, rv3d->ofs);
-                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                }
        }
        else {
@@ -479,7 +554,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
                invert_m3_m3(m_inv,m);
 
                /* Determine the direction of the x vector (for rotating up and down) */
-               /* This can likely be compuated directly from the quaternion. */
+               /* This can likely be computed directly from the quaternion. */
                mul_m3_v3(m_inv,xvec);
 
                /* Perform the up/down rotation */
@@ -491,11 +566,11 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
                q1[3] = si * xvec[2];
                mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
 
-               if (use_sel) {
+               if (vod->use_dyn_ofs) {
                        conjugate_qt(q1); /* conj == inv for unit quat */
-                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                        mul_qt_v3(q1, rv3d->ofs);
-                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                }
 
                /* Perform the orbital rotation */
@@ -505,11 +580,11 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
                q1[3] = sin(phi);
                mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
 
-               if (use_sel) {
+               if (vod->use_dyn_ofs) {
                        conjugate_qt(q1);
-                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                        mul_qt_v3(q1, rv3d->ofs);
-                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
+                       add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
                }
        }
 
@@ -567,6 +642,14 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
                                vod->axis_snap= FALSE;
                                event_code= VIEW_APPLY;
                                break;
+                       case VIEWROT_MODAL_SWITCH_ZOOM:
+                               WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
+                       case VIEWROT_MODAL_SWITCH_MOVE:
+                               WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
                }
        }
        else if(event->type==vod->origkey && event->val==KM_RELEASE) {
@@ -578,9 +661,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
        }
        else if (event_code==VIEW_CONFIRM) {
                request_depth_update(CTX_wm_region_view3d(C));
-
-               MEM_freeN(vod);
-               op->customdata= NULL;
+               viewops_data_free(C, op);
 
                return OPERATOR_FINISHED;
        }
@@ -597,7 +678,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
                return OPERATOR_CANCELLED;
 
        /* makes op->customdata */
-       viewops_data(C, op, event);
+       viewops_data_create(C, op, event);
        vod= op->customdata;
 
        /* switch from camera view when: */
@@ -609,13 +690,46 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
                        vod->rv3d->persp= RV3D_PERSP;
                ED_region_tag_redraw(vod->ar);
        }
+       
+       if (event->type == MOUSEPAN) {
+               viewrotate_apply(vod, event->prevx, event->prevy);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);
+               
+               return OPERATOR_FINISHED;
+       }
+       else if (event->type == MOUSEROTATE) {
+               /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
+               viewrotate_apply(vod, event->prevx, event->y);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);
+               
+               return OPERATOR_FINISHED;
+       }
+       else {          
+               /* add temp handler */
+               WM_event_add_modal_handler(C, op);
 
-       /* add temp handler */
-       WM_event_add_modal_handler(C, op);
-
-       return OPERATOR_RUNNING_MODAL;
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
+static int ED_operator_view3d_rotate(bContext *C)
+{
+       if (!ED_operator_view3d_active(C)) {
+               return 0;
+       } else {
+               RegionView3D *rv3d= CTX_wm_region_view3d(C);
+               /* rv3d is null in menus, but it's ok when the menu is clicked on */
+               /* XXX of course, this doesn't work with quadview
+                * Maybe having exec return PASSTHROUGH would be better than polling here
+                * Poll functions are full of problems anyway.
+                * */
+               return rv3d == NULL || rv3d->viewlock == 0;
+       }
+}
 
 void VIEW3D_OT_rotate(wmOperatorType *ot)
 {
@@ -628,7 +742,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke= viewrotate_invoke;
        ot->modal= viewrotate_modal;
-       ot->poll= ED_operator_view3d_active;
+       ot->poll= ED_operator_view3d_rotate;
 
        /* flags */
        ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
@@ -658,6 +772,10 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
        WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
 
+       WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
+       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
+       WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
+       
        /* assign map to operators */
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
 }
@@ -706,6 +824,14 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
                        case VIEW_MODAL_CONFIRM:
                                event_code= VIEW_CONFIRM;
                                break;
+                       case VIEWROT_MODAL_SWITCH_ZOOM:
+                               WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
+                       case VIEWROT_MODAL_SWITCH_ROTATE:
+                               WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
                }
        }
        else if(event->type==vod->origkey && event->val==KM_RELEASE) {
@@ -718,8 +844,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
        else if (event_code==VIEW_CONFIRM) {
                request_depth_update(CTX_wm_region_view3d(C));
 
-               MEM_freeN(vod);
-               op->customdata= NULL;
+               viewops_data_free(C, op);
 
                return OPERATOR_FINISHED;
        }
@@ -730,15 +855,25 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        /* makes op->customdata */
-       viewops_data(C, op, event);
+       viewops_data_create(C, op, event);
 
-       /* add temp handler */
-       WM_event_add_modal_handler(C, op);
+       if (event->type == MOUSEPAN) {
+               ViewOpsData *vod= op->customdata;
+               viewmove_apply(vod, event->prevx, event->prevy);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);               
+               
+               return OPERATOR_FINISHED;
+       }
+       else {
+               /* add temp handler */
+               WM_event_add_modal_handler(C, op);
 
-       return OPERATOR_RUNNING_MODAL;
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
-
 void VIEW3D_OT_move(wmOperatorType *ot)
 {
 
@@ -777,6 +912,10 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
        WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
 
+       WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
+       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
+       WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
+       
        /* assign map to operators */
        WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
 }
@@ -830,15 +969,19 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
 }
 
 
-static void viewzoom_apply(ViewOpsData *vod, int x, int y)
+static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
 {
        float zfac=1.0;
 
-       if(U.viewzoom==USER_ZOOM_CONT) {
+       if(viewzoom==USER_ZOOM_CONT) {
+               double time= PIL_check_seconds_timer();
+               float time_step= (float)(time - vod->timer_lastdraw);
+
                // oldstyle zoom
-               zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
+               zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y)/20.0) * time_step);
+               vod->timer_lastdraw= time;
        }
-       else if(U.viewzoom==USER_ZOOM_SCALE) {
+       else if(viewzoom==USER_ZOOM_SCALE) {
                int ctr[2], len1, len2;
                // method which zooms based on how far you move the mouse
 
@@ -851,8 +994,19 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y)
                zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
        }
        else {  /* USER_ZOOM_DOLLY */
-               float len1 = (vod->ar->winrct.ymax - y) + 5;
-               float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
+               float len1, len2;
+               
+               if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
+                       len1 = (vod->ar->winrct.xmax - x) + 5;
+                       len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+               }
+               else {
+                       len1 = (vod->ar->winrct.ymax - y) + 5;
+                       len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
+               }
+               if (U.uiflag & USER_ZOOM_INVERT)
+                       SWAP(float, len1, len2);
+               
                zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
        }
 
@@ -861,7 +1015,7 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y)
                view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
 
 
-       if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
+       if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
                float upvec[3], mat[3][3];
 
                /* Secret apricot feature, translate the view when in continues mode */
@@ -892,7 +1046,10 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
        short event_code= VIEW_PASS;
 
        /* execute the events */
-       if(event->type==MOUSEMOVE) {
+       if (event->type == TIMER && event->customdata == vod->timer) {
+               event_code= VIEW_APPLY;
+       }
+       else if(event->type==MOUSEMOVE) {
                event_code= VIEW_APPLY;
        }
        else if(event->type==EVT_MODAL_MAP) {
@@ -900,6 +1057,14 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
                        case VIEW_MODAL_CONFIRM:
                                event_code= VIEW_CONFIRM;
                                break;
+                       case VIEWROT_MODAL_SWITCH_MOVE:
+                               WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
+                       case VIEWROT_MODAL_SWITCH_ROTATE:
+                               WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
+                               event_code= VIEW_CONFIRM;
+                               break;
                }
        }
        else if(event->type==vod->origkey && event->val==KM_RELEASE) {
@@ -907,13 +1072,11 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
        }
 
        if(event_code==VIEW_APPLY) {
-               viewzoom_apply(vod, event->x, event->y);
+               viewzoom_apply(vod, event->x, event->y, U.viewzoom);
        }
        else if (event_code==VIEW_CONFIRM) {
                request_depth_update(CTX_wm_region_view3d(C));
-
-               MEM_freeN(vod);
-               op->customdata= NULL;
+               viewops_data_free(C, op);
 
                return OPERATOR_FINISHED;
        }
@@ -973,13 +1136,41 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
                viewzoom_exec(C, op);
        }
        else {
+               ViewOpsData *vod;
+
                /* makes op->customdata */
-               viewops_data(C, op, event);
+               viewops_data_create(C, op, event);
 
-               /* add temp handler */
-               WM_event_add_modal_handler(C, op);
+               vod= op->customdata;
 
-               return OPERATOR_RUNNING_MODAL;
+               if (event->type == MOUSEZOOM) {
+                       if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
+                               SWAP(int, event->x, event->prevx);
+
+                       if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
+                               vod->origx = vod->oldx = event->x;
+                               viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
+                       }
+                       else {
+                               
+                               /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
+                               vod->origy = vod->oldy = event->x;
+                               viewzoom_apply(vod, event->x, event->prevx, USER_ZOOM_DOLLY);
+                       }
+                       request_depth_update(CTX_wm_region_view3d(C));
+                       
+                       viewops_data_free(C, op);
+                       return OPERATOR_FINISHED;
+               }
+               else {
+                       vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+                       vod->timer_lastdraw= PIL_check_seconds_timer();
+
+                       /* add temp handler */
+                       WM_event_add_modal_handler(C, op);
+
+                       return OPERATOR_RUNNING_MODAL;
+               }
        }
        return OPERATOR_FINISHED;
 }
@@ -1001,7 +1192,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
        /* flags */
        ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
 
-       RNA_def_int(ot->srna, "delta", 0, 0, INT_MAX, "Delta", "", 0, INT_MAX);
+       RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
        RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
        RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
 }
@@ -1197,10 +1388,6 @@ static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview with
                new_dist*= size;
        }
 
-       v3d->cursor[0]= -new_ofs[0];
-       v3d->cursor[1]= -new_ofs[1];
-       v3d->cursor[2]= -new_ofs[2];
-
        if (rv3d->persp==RV3D_CAMOB) {
                rv3d->persp= RV3D_PERSP;
                smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
@@ -1319,6 +1506,8 @@ static int render_border_exec(bContext *C, wmOperator *op)
        } else {
                scene->r.mode |= R_BORDER;
        }
+       
+       WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
 
        return OPERATOR_FINISHED;
 
@@ -1376,7 +1565,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
 
        /* ZBuffer depth vars */
        bglMats mats;
-       float depth, depth_close= MAXFLOAT;
+       float depth, depth_close= FLT_MAX;
        int had_depth = 0;
        double cent[2],  p[3];
        int xs, ys;
@@ -1433,7 +1622,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
                double p_corner[3];
 
                /* no depths to use, we cant do anything! */
-               if (depth_close==MAXFLOAT){
+               if (depth_close==FLT_MAX){
                        BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
                        return OPERATOR_CANCELLED;
                }
@@ -1461,7 +1650,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
                new_dist = rv3d->dist;
 
                /* convert the drawn rectangle into 3d space */
-               if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
+               if (depth_close!=FLT_MAX && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
                        new_ofs[0] = -p[0];
                        new_ofs[1] = -p[1];
                        new_ofs[2] = -p[2];
@@ -1621,36 +1810,43 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
        RegionView3D *rv3d= CTX_wm_region_view3d(C);
        Scene *scene= CTX_data_scene(C);
        static int perspo=RV3D_PERSP;
-       int viewnum, align_active;
+       int viewnum, align_active, nextperspo;
 
        viewnum = RNA_enum_get(op->ptr, "type");
        align_active = RNA_boolean_get(op->ptr, "align_active");
 
+
        /* Use this to test if we started out with a camera */
 
+       if (rv3d->persp == RV3D_CAMOB) {
+               nextperspo= rv3d->lpersp;
+       } else {
+               nextperspo= perspo;
+       }
+
        switch (viewnum) {
                case RV3D_VIEW_BOTTOM :
-                       axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, perspo, align_active);
+                       axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_BACK:
-                       axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, perspo, align_active);
+                       axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_LEFT:
-                       axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, perspo, align_active);
+                       axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_TOP:
-                       axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, perspo, align_active);
+                       axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_FRONT:
-                       axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, perspo, align_active);
+                       axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_RIGHT:
-                       axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, perspo, align_active);
+                       axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
                        break;
 
                case RV3D_VIEW_CAMERA:
@@ -1731,9 +1927,8 @@ static EnumPropertyItem prop_view_orbit_items[] = {
 
 static int vieworbit_exec(bContext *C, wmOperator *op)
 {
-       ARegion *ar= CTX_wm_region(C);
        RegionView3D *rv3d= CTX_wm_region_view3d(C);
-       float phi, si, q1[4];
+       float phi, si, q1[4], new_quat[4];
        int orbitdir;
 
        orbitdir = RNA_enum_get(op->ptr, "type");
@@ -1749,10 +1944,10 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
                                q1[0]= (float)cos(phi);
                                q1[1]= q1[2]= 0.0;
                                q1[3]= si;
-                               mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+                               mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
                                rv3d->view= 0;
                        }
-                       if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
+                       else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
                                /* horizontal axis */
                                VECCOPY(q1+1, rv3d->viewinv[0]);
 
@@ -1764,10 +1959,11 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
                                q1[1]*= si;
                                q1[2]*= si;
                                q1[3]*= si;
-                               mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+                               mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
                                rv3d->view= 0;
                        }
-                       ED_region_tag_redraw(ar);
+
+                       smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
                }
        }
 
@@ -1783,7 +1979,7 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= vieworbit_exec;
-       ot->poll= ED_operator_view3d_active;
+       ot->poll= ED_operator_view3d_rotate;
 
        /* flags */
        ot->flag= 0;
@@ -1913,12 +2109,9 @@ void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
 static int view3d_clipping_exec(bContext *C, wmOperator *op)
 {
        RegionView3D *rv3d= CTX_wm_region_view3d(C);
+       ViewContext vc;
+       bglMats mats;
        rcti rect;
-       double mvmatrix[16];
-       double projmatrix[16];
-       double xs, ys, p[3];
-       GLint viewport[4];
-       short val;
 
        rect.xmin= RNA_int_get(op->ptr, "xmin");
        rect.ymin= RNA_int_get(op->ptr, "ymin");
@@ -1931,36 +2124,9 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op)
        /* note; otherwise opengl won't work */
        view3d_operator_needs_opengl(C);
 
-       /* Get the matrices needed for gluUnProject */
-       glGetIntegerv(GL_VIEWPORT, viewport);
-       glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
-       glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
-
-       /* near zero floating point values can give issues with gluUnProject
-               in side view on some implementations */
-       if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
-       if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
-
-       /* Set up viewport so that gluUnProject will give correct values */
-       viewport[0] = 0;
-       viewport[1] = 0;
-
-       /* four clipping planes and bounding volume */
-       /* first do the bounding volume */
-       for(val=0; val<4; val++) {
-
-               xs= (val==0||val==3)?rect.xmin:rect.xmax;
-               ys= (val==0||val==1)?rect.ymin:rect.ymax;
-
-               gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
-               VECCOPY(rv3d->clipbb->vec[val], p);
-
-               gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
-               VECCOPY(rv3d->clipbb->vec[4+val], p);
-       }
-
-       /* then plane equations */
-       calc_clipping_plane(rv3d->clip, rv3d->clipbb);
+       view3d_set_viewcontext(C, &vc);
+       view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
+       view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
 
        return OPERATOR_FINISHED;
 }
@@ -2050,14 +2216,10 @@ static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
                fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
        }
 
-//     if(lr_click) {
-               // XXX          if(obedit->type==OB_MESH) add_click_mesh();
-               //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
-               //              else if (obedit->type==OB_ARMATURE) addvert_armature();
-//             VECCOPY(fp, oldcurs);
-//     }
-       // XXX notifier for scene */
-       ED_area_tag_redraw(CTX_wm_area(C));
+       if(v3d && v3d->localvd)
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
+       else
+               WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
 
        return OPERATOR_FINISHED;
 }
@@ -2076,7 +2238,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
     
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+//     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
     
        /* rna later */
 
@@ -2126,22 +2288,66 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot)
 /* ************************* below the line! *********************** */
 
 
+static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
+{
+       RegionView3D *rv3d= ar->regiondata;
+       float depth= FLT_MAX;
+
+       if(margin==0) {
+               if (mval[0] < 0) return 0;
+               if (mval[1] < 0) return 0;
+               if (mval[0] >= rv3d->depths->w) return 0;
+               if (mval[1] >= rv3d->depths->h) return 0;
+
+               /* Get Z Depths, needed for perspective, nice for ortho */
+               depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
+               if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
+                       depth= FLT_MAX;
+               }
+       }
+       else {
+               rcti rect;
+               float depth_close= FLT_MAX;
+               int xs, ys;
+
+               rect.xmax = mval[0] + margin;
+               rect.ymax = mval[1] + margin;
+
+               rect.xmin = mval[0] - margin;
+               rect.ymin = mval[1] - margin;
+
+               /* Constrain rect to depth bounds */
+               if (rect.xmin < 0) rect.xmin = 0;
+               if (rect.ymin < 0) rect.ymin = 0;
+               if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
+               if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
+
+               /* Find the closest Z pixel */
+               for (xs=rect.xmin; xs < rect.xmax; xs++) {
+                       for (ys=rect.ymin; ys < rect.ymax; ys++) {
+                               depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
+                               if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
+                                       if (depth_close > depth) {
+                                               depth_close = depth;
+                                       }
+                               }
+                       }
+               }
+
+               depth= depth_close;
+       }
+
+       return depth;
+}
+
 /* XXX todo Zooms in on a border drawn by the user */
 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
 {
        RegionView3D *rv3d= ar->regiondata;
        bglMats mats; /* ZBuffer depth vars */
-       rcti rect;
-       float depth, depth_close= MAXFLOAT;
+       float depth_close= FLT_MAX;
        int had_depth = 0;
        double cent[2],  p[3];
-       int xs, ys;
-
-       rect.xmax = mval[0] + 4;
-       rect.ymax = mval[1] + 4;
-
-       rect.xmin = mval[0] - 4;
-       rect.ymin = mval[1] - 4;
 
        /* Get Z Depths, needed for perspective, nice for ortho */
        bgl_get_mats(&mats);
@@ -2155,25 +2361,9 @@ int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mou
 
        view3d_update_depths(ar, v3d);
 
-       /* Constrain rect to depth bounds */
-       if (rect.xmin < 0) rect.xmin = 0;
-       if (rect.ymin < 0) rect.ymin = 0;
-       if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
-       if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
+       depth_close= view_autodist_depth_margin(ar, mval, 4);
 
-       /* Find the closest Z pixel */
-       for (xs=rect.xmin; xs < rect.xmax; xs++) {
-               for (ys=rect.ymin; ys < rect.ymax; ys++) {
-                       depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
-                       if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
-                               if (depth_close > depth) {
-                                       depth_close = depth;
-                               }
-                       }
-               }
-       }
-
-       if (depth_close==MAXFLOAT)
+       if (depth_close==FLT_MAX)
                return 0;
 
        if (had_depth==0) {
@@ -2194,7 +2384,65 @@ int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mou
        return 1;
 }
 
+int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
+{
+       RegionView3D *rv3d= ar->regiondata;
+
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       switch(mode) {
+       case 0:
+               draw_depth(scene, ar, v3d, NULL);
+               break;
+       case 1:
+               draw_depth_gpencil(scene, ar, v3d);
+               break;
+       }
+
+       /* force updating */
+       if (rv3d->depths) {
+               rv3d->depths->damaged = 1;
+       }
+
+       view3d_update_depths(ar, v3d);
+       return 1;
+}
 
+// no 4x4 sampling, run view_autodist_init first
+int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
+{
+       bglMats mats; /* ZBuffer depth vars, could cache? */
+       float depth;
+       double cent[2],  p[3];
+
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       if(force_depth)
+               depth= *force_depth;
+       else
+               depth= view_autodist_depth_margin(ar, mval, margin);
+
+       if (depth==FLT_MAX)
+               return 0;
+
+       cent[0] = (double)mval[0];
+       cent[1] = (double)mval[1];
+
+       bgl_get_mats(&mats);
+       if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
+               return 0;
+
+       mouse_worldloc[0] = (float)p[0];
+       mouse_worldloc[1] = (float)p[1];
+       mouse_worldloc[2] = (float)p[2];
+       return 1;
+}
+
+int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
+{
+       *depth= view_autodist_depth_margin(ar, mval, margin);
+
+       return (*depth==FLT_MAX) ? 0:1;
+               return 0;
+}
 
 /* ********************* NDOF ************************ */
 /* note: this code is confusing and unclear... (ton) */