Made 2D zoom consistent with 3D zoom for touchpads #110375

Open
Stefan Schumann wants to merge 23 commits from StefanS/blender:2dzoomfix into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
16 changed files with 2583 additions and 504 deletions

View File

@ -559,7 +559,7 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
static int lastdy = 0;
const int dy = WM_event_absolute_delta_y(event);
/* This event should be originally from event->type,
/* This event should originally be from event->type,
* converting wrong event into wheel is bad, see #33803. */
BLI_assert(*type == MOUSEPAN);
@ -6286,7 +6286,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
hsv[2] = clamp_f(hsv[2] + 0.05f, 0.0f, 1.0f);
}
else {
const float fac = 0.005 * (event->xy[1] - event->prev_xy[1]);
const float fac = 0.005 / UI_SCALE_FAC * WM_event_absolute_delta_y(event);
hsv[2] = clamp_f(hsv[2] + fac, 0.0f, 1.0f);
}

View File

@ -1317,7 +1317,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
dx *= -1.0f;
dy *= -1.0f;
}
/* set transform amount, and add current deltas to stored total delta (for redo) */
RNA_float_set(op->ptr, "deltax", dx);
RNA_float_set(op->ptr, "deltay", dy);

View File

@ -695,7 +695,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (etype == MOUSEPAN) {
float delta = 0.02f * (event->xy[1] - event->prev_xy[1]);
float delta = 0.02f / UI_SCALE_FAC * WM_event_absolute_delta_y(event);
if (opdata->segments >= 1 && opdata->segments + delta < 1) {
opdata->segments = 1;
}

View File

@ -595,13 +595,13 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
case MOUSEPAN:
if ((event->modifier & KM_ALT) == 0) {
cuts += 0.02f * (event->xy[1] - event->prev_xy[1]);
cuts += 0.02f / UI_SCALE_FAC * WM_event_absolute_delta_y(event);
if (cuts < 1 && lcd->cuts >= 1) {
cuts = 1;
}
}
else {
smoothness += 0.002f * (event->xy[1] - event->prev_xy[1]);
smoothness += 0.002f / UI_SCALE_FAC * WM_event_absolute_delta_y(event);
}
handled = true;
break;

View File

@ -605,13 +605,23 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
float delta, factor;
delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
if (event->type == MOUSEPAN) {
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = WM_event_absolute_delta_x(event);
}
else {
delta = WM_event_absolute_delta_y(event);
}
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
}
}
else { /* MOUSEZOOM */
delta = WM_event_absolute_delta_x(event);
}
factor = 1.0f + delta / 300.0f;
factor = 1.0f + delta / UI_SCALE_FAC / 300.0f;
RNA_float_set(op->ptr, "factor", factor);
sclip_zoom_set_factor_exec(C, event, factor);
@ -642,7 +652,7 @@ static void view_zoom_apply(
delta = event->xy[0] - vpd->x + event->xy[1] - vpd->y;
}
delta /= U.pixelsize;
delta /= U.pixelsize * UI_SCALE_FAC;
if (U.uiflag & USER_ZOOM_INVERT) {
delta = -delta;

View File

@ -597,14 +597,24 @@ static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
if (event->type == MOUSEPAN) {
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = WM_event_absolute_delta_x(event);
}
else {
delta = WM_event_absolute_delta_y(event);
}
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
}
}
else { /* MOUSEZOOM */
delta = WM_event_absolute_delta_x(event);
}
factor = 1.0f + delta / 300.0f;
factor = 1.0f + delta / UI_SCALE_FAC / 300.0f;
RNA_float_set(op->ptr, "factor", factor);
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
sima_zoom_set(sima,
@ -644,7 +654,7 @@ static void image_zoom_apply(ViewZoomData *vpd,
delta = x - vpd->origx + y - vpd->origy;
}
delta /= U.pixelsize;
delta /= U.pixelsize * UI_SCALE_FAC;
if (zoom_invert) {
delta = -delta;

View File

@ -335,8 +335,16 @@ void ViewOpsData::init_navigation(bContext *C,
}
/* For dolly */
const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
ED_view3d_win_to_vector(region, mval, this->init.mousevec);
{
float mval[2];
if (viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) {
copy_v2fl_v2i(mval, event->mval);
}
else {
copy_v2_fl2(mval, (float)(region->winx / 2), (float)(region->winy / 2));
}
ED_view3d_win_to_vector(region, mval, this->init.mousevec);
}
{
int event_xy_offset[2];

File diff suppressed because it is too large Load Diff

View File

@ -155,10 +155,14 @@ struct ViewOpsData {
/** Current state. */
struct {
/** Working copy of #RegionView3D.viewquat, needed for rotation calculation
* so we can apply snap to the 3D Viewport while keeping the unsnapped rotation
* here to use when snap is disabled and for continued calculation. */
float viewquat[4];
union {
/** Working copy of #RegionView3D.viewquat, needed for rotation calculation
* so we can apply snap to the 3D Viewport while keeping the unsnapped rotation
* here to use when snap is disabled and for continued calculation. */
float viewquat[4];
/** Total distance for continuous zoom */
float total_dist;
};
} curr;
const ViewOpsType *nav_type;

View File

@ -472,6 +472,20 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event)
else if (event->type == MOUSEMOVE) {
copy_v2_v2_int(fly->mval, event->mval);
}
else if (event->type == MOUSEPAN) {
float fac = -0.03f * WM_event_absolute_delta_y(event) / UI_SCALE_FAC;
/* allow to brake immediately */
if (fac > 0.0f && fly->speed < 0.0f) {
fly->speed = 0.0f;
}
else if (fac < 0.0f && fly->speed > 0.0f) {
fly->speed = 0.0f;
}
else {
fly->speed += fly->grid * fac;
}
}
#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
/* do these automagically get delivered? yes. */
@ -529,28 +543,9 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event)
case FLY_MODAL_CONFIRM:
fly->state = FLY_CONFIRM;
break;
/* Speed adjusting with mouse-pan (track-pad). */
case FLY_MODAL_SPEED: {
float fac = 0.02f * (event->prev_xy[1] - event->xy[1]);
/* allowing to brake immediate */
if (fac > 0.0f && fly->speed < 0.0f) {
fly->speed = 0.0f;
}
else if (fac < 0.0f && fly->speed > 0.0f) {
fly->speed = 0.0f;
}
else {
fly->speed += fly->grid * fac;
}
break;
}
case FLY_MODAL_ACCELERATE: {
double time_currwheel;
float time_wheel;
/* not quite correct but avoids confusion WASD/arrow keys 'locking up' */
if (fly->axis == -1) {
fly->axis = 2;

View File

@ -72,35 +72,24 @@ static void view_dolly_to_vector_3d(ARegion *region,
float dfac)
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac));
madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -dfac);
}
static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert)
static void viewdolly_apply(ViewOpsData *vod, const int move_xy[2], const bool delta_invert)
{
float zfac = 1.0;
float delta;
const int sgn = 1 - 2 * delta_invert;
{
float len1, len2;
if (U.uiflag & USER_ZOOM_HORIZ) {
len1 = (vod->region->winrct.xmax - xy[0]) + 5;
len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5;
}
else {
len1 = (vod->region->winrct.ymax - xy[1]) + 5;
len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5;
}
if (zoom_invert) {
SWAP(float, len1, len2);
}
zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist);
}
if (zfac != 1.0f) {
view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac);
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = float(sgn * move_xy[0]) / UI_SCALE_FAC * vod->init.dist / 130.0f;
}
else {
delta = float(sgn * move_xy[1]) / UI_SCALE_FAC * vod->init.dist / 130.0f;
}
view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, delta);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->area, vod->region);
}
@ -116,10 +105,14 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
short event_code = VIEW_PASS;
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
int move_xy[2];
/* Execute the events. */
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CANCEL:
event_code = VIEW_CANCEL;
break;
case VIEW_MODAL_CONFIRM:
event_code = VIEW_CONFIRM;
break;
@ -151,7 +144,9 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event_code) {
case VIEW_APPLY: {
viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
sub_v2_v2v2_int(move_xy, event->xy, vod->init.event_xy);
viewdolly_apply(vod, move_xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@ -192,7 +187,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
ARegion *region;
float mousevec[3];
const int delta = RNA_int_get(op->ptr, "delta");
float delta = float(RNA_int_get(op->ptr, "delta"));
if (op->customdata) {
ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
@ -200,32 +195,37 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
area = vod->area;
region = vod->region;
copy_v3_v3(mousevec, vod->init.mousevec);
delta *= vod->init.dist / 5.0f;
}
else {
area = CTX_wm_area(C);
region = CTX_wm_region(C);
negate_v3_v3(mousevec, static_cast<RegionView3D *>(region->regiondata)->viewinv[2]);
normalize_v3(mousevec);
float reg_xy[2];
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
if (use_cursor_init) {
reg_xy[0] = float(RNA_int_get(op->ptr, "mx"));
reg_xy[1] = float(RNA_int_get(op->ptr, "my"));
}
else {
reg_xy[0] = float(region->winx / 2);
reg_xy[1] = float(region->winy / 2);
}
ED_view3d_win_to_vector(region, reg_xy, mousevec);
}
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
/* overwrite the mouse vector with the view direction (zoom into the center) */
if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
negate_v3(mousevec);
}
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 1.8f : 0.2f);
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
ED_region_tag_redraw(region);
@ -239,19 +239,17 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
if (viewdolly_offset_lock_check(C, op)) {
return OPERATOR_CANCELLED;
}
/* use_cursor_init is true by default */
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
vod = viewops_data_create(C, event, &ViewOpsType_dolly, use_cursor_init);
op->customdata = vod;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
/* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */
/* switch from camera view when: */
if (vod->rv3d->persp != RV3D_PERSP) {
if (vod->rv3d->persp == RV3D_CAMOB) {
@ -265,45 +263,56 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->region);
}
/* if one or the other zoom position aren't set, set from event */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
RNA_int_set(op->ptr, "mx", event->xy[0]);
RNA_int_set(op->ptr, "my", event->xy[1]);
if (!use_cursor_init) {
RNA_int_set(op->ptr, "mx", vod->region->winx / 2);
RNA_int_set(op->ptr, "my", vod->region->winy / 2);
}
else {
/* if one or the other zoom direction is not set */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
RNA_int_set(op->ptr, "mx", event->mval[0]);
RNA_int_set(op->ptr, "my", event->mval[1]);
}
else {
const float reg_xy[2] = {float(RNA_int_get(op->ptr, "mx")), float(RNA_int_get(op->ptr, "my"))};
/* recompute movement direction for dolly */
ED_view3d_win_to_vector(vod->region, reg_xy, vod->init.mousevec);
}
}
if (RNA_struct_property_is_set(op->ptr, "delta")) {
viewdolly_exec(C, op);
return viewdolly_exec(C, op);
}
else {
/* overwrite the mouse vector with the view direction (zoom into the center) */
if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
normalize_v3(vod->init.mousevec);
/* do not set the delta property, as an integer it would be 0 here */
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
int move_xy[2];
bool zoominv;
if (event->type == MOUSEPAN) {
move_xy[0] = WM_event_absolute_delta_x(event);
move_xy[1] = WM_event_absolute_delta_y(event);
zoominv = (U.uiflag & USER_ZOOM_INVERT) != 0;
}
if (event->type == MOUSEZOOM) {
/* Bypass Zoom invert flag for track pads (pass false always) */
if (U.uiflag & USER_ZOOM_HORIZ) {
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
event->prev_xy[0];
}
viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0);
viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
op->customdata = nullptr;
return OPERATOR_FINISHED;
else { /* MOUSEZOOM */
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
move_xy[1] = move_xy[0] = WM_event_absolute_delta_x(event);
zoominv = false;
}
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
viewdolly_apply(vod, move_xy, zoominv);
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
op->customdata = nullptr;
return OPERATOR_FINISHED;
}
return OPERATOR_FINISHED;
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
void VIEW3D_OT_dolly(wmOperatorType *ot)
@ -317,11 +326,11 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
ot->invoke = viewdolly_invoke;
ot->exec = viewdolly_exec;
ot->modal = viewdolly_modal;
ot->poll = view3d_rotation_poll;
ot->poll = view3d_zoom_or_dolly_poll;
ot->cancel = view3d_navigate_cancel_fn;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_DEPENDS_ON_CURSOR;
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
/* properties */
view3d_operator_properties_common(

View File

@ -0,0 +1,359 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spview3d
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "WM_api.hh"
#include "RNA_access.h"
#include "ED_screen.hh"
#include "view3d_intern.h"
#include "view3d_navigate.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name View Dolly Operator
*
* Like zoom but translates the view offset along the view direction
* which avoids #RegionView3D.dist approaching zero.
* \{ */
/* This is an exact copy of #viewzoom_modal_keymap. */
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{VIEW_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
{0, nullptr, 0, nullptr, nullptr},
};
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal");
/* This function is called for each space-type, only needs to add map once. */
if (keymap && keymap->modal_items) {
return;
}
keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly");
}
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;
}
return false;
}
static void view_dolly_to_vector_3d(ARegion *region,
const float orig_ofs[3],
const float dvec[3],
float dfac)
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -dfac);
}
static void viewdolly_apply(ViewOpsData *vod, const int move_xy[2], const bool delta_invert)
{
float delta;
const int sgn = 1 - 2 * delta_invert;
/* the factor 1.2 adjusts the input sensitivity */
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = 1.2f * (float)(sgn * move_xy[0]) / vod->region->winx * vod->rv3d->dist;
}
else {
delta = 1.2f * (float)(sgn * move_xy[1]) / vod->region->winy * vod->rv3d->dist;
}
view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, delta);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->region);
}
static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
short event_code = VIEW_PASS;
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
int move_xy[2];
/* Execute the events. */
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CANCEL:
event_code = VIEW_CANCEL;
break;
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, nullptr, event);
event_code = VIEW_CONFIRM;
break;
case VIEWROT_MODAL_SWITCH_ROTATE:
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, nullptr, event);
event_code = VIEW_CONFIRM;
break;
}
}
else {
if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
else if (event->type == vod->init.event_type) {
if (event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
}
else if (event->type == EVT_ESCKEY) {
if (event->val == KM_PRESS) {
event_code = VIEW_CANCEL;
}
}
}
switch (event_code) {
case VIEW_APPLY: {
sub_v2_v2v2_int(move_xy, event->xy, vod->init.event_xy);
viewdolly_apply(vod, move_xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
break;
}
case VIEW_CONFIRM: {
use_autokey = true;
ret = OPERATOR_FINISHED;
break;
}
case VIEW_CANCEL: {
vod->state_restore();
ret = OPERATOR_CANCELLED;
break;
}
}
if (use_autokey) {
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
}
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
if (ret & OPERATOR_FINISHED) {
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
}
viewops_data_free(C, vod);
op->customdata = nullptr;
}
return ret;
}
static int viewdolly_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
float mousevec[3];
const int delta = RNA_int_get(op->ptr, "delta");
if (op->customdata) {
ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
area = vod->area;
region = vod->region;
copy_v3_v3(mousevec, vod->init.mousevec);
}
else {
area = CTX_wm_area(C);
region = CTX_wm_region(C);
float xy[2];
/* compute direction vector for given zoom direction */
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
if (use_cursor_init) {
xy[0] = (float)RNA_int_get(op->ptr, "mx");
xy[1] = (float)RNA_int_get(op->ptr, "my");
}
else {
xy[0] = (float)region->winx / 2.0f;
xy[1] = (float)region->winy / 2.0f;
}
ED_view3d_win_to_vector(region, xy, mousevec);
}
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
ED_region_tag_redraw(region);
viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
op->customdata = nullptr;
return OPERATOR_FINISHED;
}
/* copied from viewzoom_invoke(), changes here may apply there */
static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
if (viewdolly_offset_lock_check(C, op)) {
return OPERATOR_CANCELLED;
}
/* use_cursor_init is true by default */
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
<<<<<<< HEAD:source/blender/editors/space_view3d/view3d_navigate_dolly.cc
vod = viewops_data_create(C, event, V3D_OP_MODE_DOLLY, use_cursor_init);
=======
vod = viewops_data_create(C, event, &ViewOpsType_dolly, use_cursor_init);
>>>>>>> main:source/blender/editors/space_view3d/view3d_navigate_view_dolly.cc
op->customdata = vod;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
/* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */
/* switch from camera view when: */
if (vod->rv3d->persp != RV3D_PERSP) {
if (vod->rv3d->persp == RV3D_CAMOB) {
/* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP);
}
else {
vod->rv3d->persp = RV3D_PERSP;
}
ED_region_tag_redraw(vod->region);
}
/* if one or the other zoom direction is not set */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
/* set xy to region local coordinates */
int xy[2];
if (use_cursor_init) {
xy[0] = event->mval[0];
xy[1] = event->mval[1];
}
else {
xy[0] = vod->region->winx / 2;
xy[1] = vod->region->winy / 2;
}
RNA_int_set(op->ptr, "mx", xy[0]);
RNA_int_set(op->ptr, "my", xy[1]);
}
else {
/* recompute direction vector for given zoom direction */
const float xy[2] = {(float)RNA_int_get(op->ptr, "mx"),
(float)RNA_int_get(op->ptr, "my")};
ED_view3d_win_to_vector(vod->region, xy, vod->init.mousevec);
}
if (RNA_struct_property_is_set(op->ptr, "delta")) {
return viewdolly_exec(C, op);
}
else {
/* we do not set the delta property. It is an int, so usually would be
* 0 if rounded from a float */
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
int move_xy[2];
sub_v2_v2v2_int(move_xy, event->prev_xy, event->xy);
if (event->type == MOUSEZOOM) {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
move_xy[1] = move_xy[0];
}
viewdolly_apply(vod, move_xy, ((U.uiflag & USER_ZOOM_INVERT) != 0)
^ ((event->flag & WM_EVENT_SCROLL_INVERT) !=0));
viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
op->customdata = nullptr;
return OPERATOR_FINISHED;
}
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
}
void VIEW3D_OT_dolly(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Dolly View";
ot->description = "Dolly in/out in the view";
ot->idname = ViewOpsType_dolly.idname;
/* api callbacks */
ot->invoke = viewdolly_invoke;
ot->exec = viewdolly_exec;
ot->modal = viewdolly_modal;
ot->poll = view3d_zoom_or_dolly_poll;
ot->cancel = view3d_navigate_cancel_fn;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
/* properties */
view3d_operator_properties_common(
ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
}
/** \} */
ViewOpsType ViewOpsType_dolly = {
/*flag*/ (VIEWOPS_FLAG_DEPTH_NAVIGATE | VIEWOPS_FLAG_ZOOM_TO_MOUSE),
/*idname*/ "VIEW3D_OT_dolly",
/*poll_fn*/ nullptr,
/*init_fn*/ nullptr,
/*apply_fn*/ nullptr,
};

View File

@ -344,19 +344,18 @@ static int viewrotate_invoke_impl(bContext * /*C*/,
eV3D_OpEvent event_code = ELEM(event->type, MOUSEROTATE, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
if (event_code == VIEW_CONFIRM) {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
const bool is_inverted = (event->flag & WM_EVENT_SCROLL_INVERT) &&
(event->type != MOUSEROTATE);
int m_xy[2];
if (is_inverted) {
m_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
m_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
if (event->type == MOUSEPAN) {
m_xy[0] = event->xy[0] + WM_event_absolute_delta_x(event);
m_xy[1] = event->xy[1] + WM_event_absolute_delta_y(event);
}
else {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
copy_v2_v2_int(m_xy, event->prev_xy);
}
viewrotate_apply(vod, m_xy);
return OPERATOR_FINISHED;
}

View File

@ -57,296 +57,112 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
/**
* \param zoom_xy: Optionally zoom to window location
* (coords compatible w/ #wmEvent.xy). Use when not nullptr.
* (coords compatible w/ #wmEvent.mval).
*/
static void view_zoom_to_window_xy_camera(Scene *scene,
Depsgraph *depsgraph,
View3D *v3d,
ARegion *region,
float dfac,
const int zoom_xy[2])
static void view_zoom_to_vector_3d(const View3D *v3d,
ARegion *region,
const float orig_ofs[3],
const float orig_dist,
const float orig_mval[2],
float delta)
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
const float zoomfac_new = clamp_f(
zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
if (zoom_xy != nullptr) {
float zoomfac_px;
rctf camera_frame_old;
rctf camera_frame_new;
const float pt_src[2] = {float(zoom_xy[0]), float(zoom_xy[1])};
float pt_dst[2];
float delta_px[2];
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_old, false);
BLI_rctf_translate(&camera_frame_old, region->winrct.xmin, region->winrct.ymin);
rv3d->camzoom = camzoom_new;
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_new, false);
BLI_rctf_translate(&camera_frame_new, region->winrct.xmin, region->winrct.ymin);
BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
sub_v2_v2v2(delta_px, pt_dst, pt_src);
/* translate the camera offset using pixel space delta
* mapped back to the camera (same logic as panning in camera view) */
zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
rv3d->camdx += delta_px[0] / (region->winx * zoomfac_px);
rv3d->camdy += delta_px[1] / (region->winy * zoomfac_px);
CLAMP(rv3d->camdx, -1.0f, 1.0f);
CLAMP(rv3d->camdy, -1.0f, 1.0f);
}
else {
rv3d->camzoom = camzoom_new;
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
}
}
/**
* \param zoom_xy: Optionally zoom to window location
* (coords compatible w/ #wmEvent.xy). Use when not nullptr.
*/
static void view_zoom_to_window_xy_3d(ARegion *region, float dfac, const int zoom_xy[2])
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
const float dist_new = rv3d->dist * dfac;
if (zoom_xy != nullptr) {
float dvec[3];
float tvec[3];
float tpos[3];
float xy_delta[2];
float zfac;
negate_v3_v3(tpos, rv3d->ofs);
xy_delta[0] = float(((zoom_xy[0] - region->winrct.xmin) * 2) - region->winx) / 2.0f;
xy_delta[1] = float(((zoom_xy[1] - region->winrct.ymin) * 2) - region->winy) / 2.0f;
/* Project cursor position into 3D space */
zfac = ED_view3d_calc_zfac(rv3d, tpos);
ED_view3d_win_to_delta(region, xy_delta, zfac, dvec);
/* Calculate view target position for dolly */
add_v3_v3v3(tvec, tpos, dvec);
negate_v3(tvec);
/* Offset to target position and dolly */
copy_v3_v3(rv3d->ofs, tvec);
rv3d->dist = dist_new;
/* Calculate final offset */
madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
}
else {
rv3d->dist = dist_new;
}
}
static float viewzoom_scale_value(const rcti *winrct,
const eViewZoom_Style viewzoom,
const bool zoom_invert,
const bool zoom_invert_force,
const int xy_curr[2],
const int xy_init[2],
const float val,
const float val_orig,
double *r_timer_lastdraw)
{
float zfac;
if (viewzoom == USER_ZOOM_CONTINUE) {
double time = PIL_check_seconds_timer();
float time_step = float(time - *r_timer_lastdraw);
float fac;
if (U.uiflag & USER_ZOOM_HORIZ) {
fac = float(xy_init[0] - xy_curr[0]);
}
else {
fac = float(xy_init[1] - xy_curr[1]);
}
fac /= UI_SCALE_FAC;
if (zoom_invert != zoom_invert_force) {
fac = -fac;
}
zfac = 1.0f + ((fac / 20.0f) * time_step);
*r_timer_lastdraw = time;
}
else if (viewzoom == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
const int ctr[2] = {
BLI_rcti_cent_x(winrct),
BLI_rcti_cent_y(winrct),
};
float len_new = (5 * UI_SCALE_FAC) + (float(len_v2v2_int(ctr, xy_curr)) / UI_SCALE_FAC);
float len_old = (5 * UI_SCALE_FAC) + (float(len_v2v2_int(ctr, xy_init)) / UI_SCALE_FAC);
/* intentionally ignore 'zoom_invert' for scale */
if (zoom_invert_force) {
SWAP(float, len_new, len_old);
}
zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val;
}
else { /* USER_ZOOM_DOLLY */
float len_new = 5 * UI_SCALE_FAC;
float len_old = 5 * UI_SCALE_FAC;
if (U.uiflag & USER_ZOOM_HORIZ) {
len_new += (winrct->xmax - (xy_curr[0])) / UI_SCALE_FAC;
len_old += (winrct->xmax - (xy_init[0])) / UI_SCALE_FAC;
}
else {
len_new += (winrct->ymax - (xy_curr[1])) / UI_SCALE_FAC;
len_old += (winrct->ymax - (xy_init[1])) / UI_SCALE_FAC;
}
if (zoom_invert != zoom_invert_force) {
SWAP(float, len_new, len_old);
}
zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val;
}
return zfac;
}
static float viewzoom_scale_value_offset(const rcti *winrct,
const eViewZoom_Style viewzoom,
const bool zoom_invert,
const bool zoom_invert_force,
const int xy_curr[2],
const int xy_init[2],
const int xy_offset[2],
const float val,
const float val_orig,
double *r_timer_lastdraw)
{
const int xy_curr_offset[2] = {
xy_curr[0] + xy_offset[0],
xy_curr[1] + xy_offset[1],
};
const int xy_init_offset[2] = {
xy_init[0] + xy_offset[0],
xy_init[1] + xy_offset[1],
};
return viewzoom_scale_value(winrct,
viewzoom,
zoom_invert,
zoom_invert_force,
xy_curr_offset,
xy_init_offset,
val,
val_orig,
r_timer_lastdraw);
}
static void viewzoom_apply_camera(ViewOpsData *vod,
const int xy[2],
const eViewZoom_Style viewzoom,
const bool zoom_invert,
const bool zoom_to_pos)
{
float zfac;
float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f;
float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
zfac = viewzoom_scale_value_offset(&vod->region->winrct,
viewzoom,
zoom_invert,
true,
xy,
vod->init.event_xy,
vod->init.event_xy_offset,
zoomfac,
zoomfac_prev,
&vod->prev.time);
if (!ELEM(zfac, 1.0f, 0.0f)) {
/* calculate inverted, then invert again (needed because of camera zoom scaling) */
zfac = 1.0f / zfac;
view_zoom_to_window_xy_camera(vod->scene,
vod->depsgraph,
vod->v3d,
vod->region,
zfac,
zoom_to_pos ? vod->prev.event_xy : nullptr);
}
ED_region_tag_redraw(vod->region);
}
static void viewzoom_apply_3d(ViewOpsData *vod,
const int xy[2],
const eViewZoom_Style viewzoom,
const bool zoom_invert,
const bool zoom_to_pos)
{
float zfac;
float dist_range[2];
ED_view3d_dist_range_get(vod->v3d, dist_range);
zfac = viewzoom_scale_value_offset(&vod->region->winrct,
viewzoom,
zoom_invert,
false,
xy,
vod->init.event_xy,
vod->init.event_xy_offset,
vod->rv3d->dist,
vod->init.dist,
&vod->prev.time);
if (zfac != 1.0f) {
const float zfac_min = dist_range[0] / vod->rv3d->dist;
const float zfac_max = dist_range[1] / vod->rv3d->dist;
CLAMP(zfac, zfac_min, zfac_max);
view_zoom_to_window_xy_3d(vod->region, zfac, zoom_to_pos ? vod->prev.event_xy : nullptr);
float ctr_xy[2];
float v[3];
ED_view3d_dist_range_get(v3d, dist_range);
rv3d->dist = orig_dist - delta;
CLAMP(rv3d->dist, dist_range[0], dist_range[1]);
ctr_xy[0] = orig_mval[0] - region->winx / 2;
ctr_xy[1] = orig_mval[1] - region->winy / 2;
if (rv3d->persp != RV3D_ORTHO) {
ED_view3d_win_to_delta(region, ctr_xy, -delta, v);
}
/* these limits were in old code too */
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->area, vod->region);
else {
ED_view3d_win_to_delta(region, ctr_xy, -delta/rv3d->dist, v);
}
add_v3_v3v3(rv3d->ofs, orig_ofs, v);
}
static void viewzoom_apply(ViewOpsData *vod, const int move_xy[2],
const eViewZoom_Style zoomstyle, const bool delta_invert, const int zoomctr_xy[2])
{
const int sgn = 1 - 2 * delta_invert;
if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
float scale;
if (U.uiflag & USER_ZOOM_HORIZ) {
scale = 1.0f + float(sgn * move_xy[0]) / UI_SCALE_FAC / 300.0f;
}
else {
scale = 1.0f + float(sgn * move_xy[1]) / UI_SCALE_FAC / 300.0f;
}
ED_view3d_camera_view_zoom_scale(vod->rv3d, scale);
}
else {
float delta;
if (zoomstyle == USER_ZOOM_CONTINUE) {
double time = PIL_check_seconds_timer();
float move_t = float(time - vod->prev.time);
vod->prev.time = time;
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = float(sgn * move_xy[0]) / UI_SCALE_FAC / 130.0f;
}
else {
delta = float(sgn * move_xy[1]) / UI_SCALE_FAC / 130.0f;
}
delta *= move_t * vod->init.dist;
delta = vod->curr.total_dist += delta;
}
else if (zoomstyle == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
float delta_xy[2];
float radii[2];
int ctr_xy[2];
ctr_xy[0] = BLI_rcti_cent_x(&vod->region->winrct);
ctr_xy[1] = BLI_rcti_cent_y(&vod->region->winrct);
/* initial radius */
radii[0] = max_ff(len_v2v2_int(vod->init.event_xy, ctr_xy), 1.0f);
delta_xy[0] = float(vod->init.event_xy[0] - ctr_xy[0] + move_xy[0]);
delta_xy[1] = float(vod->init.event_xy[1] - ctr_xy[1] + move_xy[1]);
/* current radius */
radii[1] = max_ff(len_v2(delta_xy), 1.0f);
delta = (radii[1] / radii[0] - 1.0f) * vod->init.dist * 2.0f;
}
else { /* USER_ZOOM_DOLLY */
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = float(sgn * move_xy[0]) / UI_SCALE_FAC * vod->init.dist / 130.0f;
}
else {
delta = float(sgn * move_xy[1]) / UI_SCALE_FAC * vod->init.dist / 130.0f;
}
}
{
const float zoomctr_f_xy[2] = {float(zoomctr_xy[0]), float(zoomctr_xy[1])};
view_zoom_to_vector_3d(vod->v3d, vod->region, vod->init.ofs, vod->init.dist, zoomctr_f_xy, delta);
}
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->area, vod->region);
}
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->region);
}
static void viewzoom_apply(ViewOpsData *vod,
const int xy[2],
const eViewZoom_Style viewzoom,
const bool zoom_invert)
{
const bool zoom_to_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
if ((vod->rv3d->persp == RV3D_CAMOB) &&
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
{
viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
else {
viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
}
static int viewzoom_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
@ -354,10 +170,22 @@ static int viewzoom_modal_impl(bContext *C,
{
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
int move_xy[2];
int zoomctr_xy[2];
switch (event_code) {
case VIEW_APPLY: {
viewzoom_apply(vod, xy, (eViewZoom_Style)U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
sub_v2_v2v2_int(move_xy, xy, vod->prev.event_xy);
copy_v2_v2_int(vod->prev.event_xy, xy);
}
else {
sub_v2_v2v2_int(move_xy, xy, vod->init.event_xy);
copy_v2_v2_int(zoomctr_xy, vod->init.event_xy_offset);
}
viewzoom_apply(vod, move_xy, (eViewZoom_Style)U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0, zoomctr_xy);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@ -384,84 +212,78 @@ static int viewzoom_modal_impl(bContext *C,
return ret;
}
static void view_zoom_apply_step(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
ScrArea *area,
ARegion *region,
const int delta,
const int zoom_xy[2])
static int viewzoom_apply_step(bContext *C, PointerRNA *ptr, ViewOpsData *vod, const int zoomctr_xy[2])
{
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
bool use_cam_zoom;
float dist_range[2];
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
!(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
const int delta = RNA_int_get(ptr, "delta");
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
const float step = 1.2f;
if (use_cam_zoom) {
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
}
else {
if (rv3d->dist < dist_range[1]) {
view_zoom_to_window_xy_3d(region, step, zoom_xy);
}
}
/* execution is always based on input device event */
area = vod->area;
region = vod->region;
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
if ((rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(v3d, rv3d)) {
const float scale = 1.0f + 0.1f * delta;
ED_view3d_camera_view_zoom_scale(rv3d, scale);
}
else {
const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
}
else {
if (rv3d->dist > dist_range[0]) {
view_zoom_to_window_xy_3d(region, step, zoom_xy);
}
const float zoomctr_f_xy[2] = {float(zoomctr_xy[0]), float(zoomctr_xy[1])};
view_zoom_to_vector_3d(v3d, region, rv3d->ofs, rv3d->dist, zoomctr_f_xy, delta * vod->init.dist / 5.0f);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
}
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
static int viewzoom_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
const int delta = RNA_int_get(op->ptr, "delta");
area = CTX_wm_area(C);
region = CTX_wm_region(C);
float zoomctr_f_xy[2];
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
if (use_cursor_init) {
zoomctr_f_xy[0] = float(RNA_int_get(op->ptr, "mx"));
zoomctr_f_xy[1] = float(RNA_int_get(op->ptr, "my"));
}
else {
zoomctr_f_xy[0] = float(region->winx / 2);
zoomctr_f_xy[1] = float(region->winy / 2);
}
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
view_zoom_to_vector_3d(v3d, region, rv3d->ofs, rv3d->dist, zoomctr_f_xy, delta);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
ED_region_tag_redraw(region);
}
static int viewzoom_exec(bContext *C, wmOperator *op)
{
BLI_assert(op->customdata == nullptr);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
const int delta = RNA_int_get(op->ptr, "delta");
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
int zoom_xy_buf[2];
const int *zoom_xy = nullptr;
const bool do_zoom_to_mouse_pos = (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS));
if (do_zoom_to_mouse_pos) {
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
region->winx / 2;
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
region->winy / 2;
zoom_xy = zoom_xy_buf;
}
view_zoom_apply_step(C, depsgraph, scene, area, region, delta, zoom_xy);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
return OPERATOR_FINISHED;
}
@ -471,53 +293,71 @@ static int viewzoom_invoke_impl(bContext *C,
const wmEvent *event,
PointerRNA *ptr)
{
int xy[2];
PropertyRNA *prop;
prop = RNA_struct_find_property(ptr, "mx");
xy[0] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[0];
prop = RNA_struct_find_property(ptr, "my");
xy[1] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[1];
prop = RNA_struct_find_property(ptr, "delta");
const int delta = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : 0;
if (delta) {
const bool do_zoom_to_mouse_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
view_zoom_apply_step(C,
vod->depsgraph,
vod->scene,
vod->area,
vod->region,
delta,
do_zoom_to_mouse_pos ? xy : nullptr);
return OPERATOR_FINISHED;
int zoomctr_xy[2];
/* use_cursor_init is true by default */
const bool use_cursor_init = RNA_boolean_get(ptr, "use_cursor_init");
if (!use_cursor_init) {
RNA_int_set(ptr, "mx", zoomctr_xy[0] = vod->region->winx / 2);
RNA_int_set(ptr, "my", zoomctr_xy[1] = vod->region->winy / 2);
}
else {
eV3D_OpEvent event_code = ELEM(event->type, MOUSEZOOM, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
if (event_code == VIEW_CONFIRM) {
if (U.uiflag & USER_ZOOM_HORIZ) {
vod->init.event_xy[0] = vod->prev.event_xy[0] = xy[0];
/* if one or the other zoom direction is not set */
if (!RNA_struct_property_is_set(ptr, "mx") || !RNA_struct_property_is_set(ptr, "my")) {
if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
copy_v2_v2_int(zoomctr_xy, event->mval);
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + xy[0] -
event->prev_xy[0];
zoomctr_xy[0] = vod->region->winx / 2;
zoomctr_xy[1] = vod->region->winy / 2;
}
viewzoom_apply(vod, event->prev_xy, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
RNA_int_set(ptr, "mx", zoomctr_xy[0]);
RNA_int_set(ptr, "my", zoomctr_xy[1]);
}
else {
zoomctr_xy[0] = RNA_int_get(ptr, "mx");
zoomctr_xy[1] = RNA_int_get(ptr, "my");
}
}
if (RNA_struct_property_is_set(ptr, "delta")) {
return viewzoom_apply_step(C, ptr, vod, zoomctr_xy);
}
else {
/* do not set the delta property, as an integer it would be 0 here */
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
int move_xy[2];
bool zoominv;
if (event->type == MOUSEPAN) {
move_xy[0] = WM_event_absolute_delta_x(event);
move_xy[1] = WM_event_absolute_delta_y(event);
zoominv = (U.uiflag & USER_ZOOM_INVERT) != 0;
}
else { /* MOUSEZOOM */
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
move_xy[1] = move_xy[0] = WM_event_absolute_delta_x(event);
zoominv = false;
}
viewzoom_apply(vod, move_xy, USER_ZOOM_DOLLY, zoominv, zoomctr_xy);
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
return OPERATOR_FINISHED;
}
}
if (U.viewzoom == USER_ZOOM_CONTINUE) {
/* needs a timer to continue redrawing */
vod->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
vod->prev.time = PIL_check_seconds_timer();
vod->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
}
copy_v2_v2_int(vod->init.event_xy_offset, zoomctr_xy);
copy_v2_v2_int(vod->prev.event_xy, event->xy);
vod->curr.total_dist = 0.0f;
return OPERATOR_RUNNING_MODAL;
}

View File

@ -0,0 +1,414 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spview3d
*/
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "DEG_depsgraph_query.h"
#include "WM_api.hh"
#include "RNA_access.h"
#include "ED_screen.hh"
#include "PIL_time.h"
#include "view3d_intern.h"
#include "view3d_navigate.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name View Zoom Operator
* \{ */
/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */
void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{VIEW_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
{VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
{VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
{0, nullptr, 0, nullptr, nullptr},
};
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal");
/* This function is called for each space-type, only needs to add map once. */
if (keymap && keymap->modal_items) {
return;
}
keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
}
/**
* \param zoom_xy: Optionally zoom to window location
* (coords compatible w/ #wmEvent.mval).
*/
static void view_zoom_to_window_xy_3d(const View3D *v3d,
ARegion *region,
const float orig_ofs[3],
const float orig_dist,
const float orig_mval[2],
float delta)
{
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
float dist_range[2];
float cent_xy[2];
float v[3];
ED_view3d_dist_range_get(v3d, dist_range);
rv3d->dist = orig_dist - delta;
CLAMP(rv3d->dist, dist_range[0], dist_range[1]);
cent_xy[0] = orig_mval[0] - region->winx / 2;
cent_xy[1] = orig_mval[1] - region->winy / 2;
if (rv3d->persp != RV3D_ORTHO) {
ED_view3d_win_to_delta(region, cent_xy, -delta, v);
}
else {
ED_view3d_win_to_delta(region, cent_xy, -delta/rv3d->dist, v);
}
add_v3_v3v3(rv3d->ofs, orig_ofs, v);
}
static void viewzoom_apply(ViewOpsData *vod, const int move_xy[2],
const eViewZoom_Style zoomstyle, const bool delta_invert, const float mval[2])
{
const int sgn = 1 - 2 * delta_invert;
if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
float scale;
if (U.uiflag & USER_ZOOM_HORIZ) {
scale = 1.0f + (float)(sgn * move_xy[0]) / vod->region->winx;
}
else {
scale = 1.0f + (float)(sgn * move_xy[1]) / vod->region->winy;
}
ED_view3d_camera_view_zoom_scale(vod->rv3d, scale);
}
else {
float delta;
if (zoomstyle == USER_ZOOM_CONTINUE) {
double time = PIL_check_seconds_timer();
float move_t = (float)(time - vod->prev.time);
vod->prev.time = time;
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = 1.2f * (float)(sgn * move_xy[0]) / vod->region->winx;
}
else {
delta = 1.2f * (float)(sgn * move_xy[1]) / vod->region->winy;
}
delta *= move_t * vod->rv3d->dist;
delta = vod->init.zfac += delta;
}
else if (zoomstyle == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
float delta_xy[2];
float radii[2];
int c_xy[2];
c_xy[0] = BLI_rcti_cent_x(&vod->region->winrct);
c_xy[1] = BLI_rcti_cent_y(&vod->region->winrct);
/* initial radius */
radii[0] = max_ff(len_v2v2_int(vod->init.event_xy, c_xy) / vod->region->winx, 0.05f);
delta_xy[0] = (float)(vod->init.event_xy[0] + move_xy[0] - c_xy[0]);
delta_xy[1] = (float)(vod->init.event_xy[1] + move_xy[1] - c_xy[1]);
/* current radius */
radii[1] = max_ff(len_v2(delta_xy) / vod->region->winx, 0.05f);
delta = 1.2f * (radii[1] / radii[0] - 1.0f) * vod->rv3d->dist;
}
else { /* USER_ZOOM_DOLLY */
/* the factor 1.2 adjusts the input sensitivity */
if (U.uiflag & USER_ZOOM_HORIZ) {
delta = 1.2f * (float)(sgn * move_xy[0]) / vod->region->winx * vod->rv3d->dist;
}
else {
delta = 1.2f * (float)(sgn * move_xy[1]) / vod->region->winy * vod->rv3d->dist;
}
}
view_zoom_to_window_xy_3d(vod->v3d, vod->region, vod->init.ofs, vod->init.dist, mval, delta);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(vod->area, vod->region);
}
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->region);
}
<<<<<<< HEAD:source/blender/editors/space_view3d/view3d_navigate_zoom.cc
int viewzoom_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
=======
static void viewzoom_apply(ViewOpsData *vod,
const int xy[2],
const eViewZoom_Style viewzoom,
const bool zoom_invert)
{
const bool zoom_to_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
if ((vod->rv3d->persp == RV3D_CAMOB) &&
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
{
viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
else {
viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
}
}
static int viewzoom_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
>>>>>>> main:source/blender/editors/space_view3d/view3d_navigate_view_zoom.cc
{
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
int move_xy[2];
float mval[2];
switch (event_code) {
case VIEW_APPLY: {
if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
sub_v2_v2v2_int(move_xy, xy, vod->prev.event_xy);
copy_v2_v2_int(vod->prev.event_xy, xy);
}
else {
sub_v2_v2v2_int(move_xy, xy, vod->init.event_xy);
mval[0] = vod->region->winx / 2.0f + vod->init.event_xy_offset[0];
mval[1] = vod->region->winy / 2.0f + vod->init.event_xy_offset[1];
}
viewzoom_apply(vod, move_xy, (eViewZoom_Style)U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0, mval);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
break;
}
case VIEW_CONFIRM: {
use_autokey = true;
ret = OPERATOR_FINISHED;
break;
}
case VIEW_CANCEL: {
vod->state_restore();
ret = OPERATOR_CANCELLED;
break;
}
case VIEW_PASS:
break;
}
if (use_autokey) {
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
}
return ret;
}
static int viewzoom_apply_step(bContext *C, PointerRNA *ptr, ViewOpsData *vod, const float mval[2])
{
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
const int delta = RNA_int_get(ptr, "delta");
/* based on input device event */
area = vod->area;
region = vod->region;
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
if ((rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(v3d, rv3d)) {
float scale;
scale = 1.0f + 0.1f * delta;
ED_view3d_camera_view_zoom_scale(rv3d, scale);
}
else {
view_zoom_to_window_xy_3d(v3d, region, rv3d->ofs, rv3d->dist, mval, delta);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
}
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
static int viewzoom_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
const int delta = RNA_int_get(op->ptr, "delta");
area = CTX_wm_area(C);
region = CTX_wm_region(C);
float xy[2];
/* compute direction vector for given zoom direction */
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
if (use_cursor_init) {
xy[0] = (float)RNA_int_get(op->ptr, "mx");
xy[1] = (float)RNA_int_get(op->ptr, "my");
}
else {
xy[0] = (float)region->winx / 2.0f;
xy[1] = (float)region->winy / 2.0f;
}
v3d = static_cast<View3D *>(area->spacedata.first);
rv3d = static_cast<RegionView3D *>(region->regiondata);
view_zoom_to_window_xy_3d(v3d, region, rv3d->ofs, rv3d->dist, xy, delta);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
view3d_boxview_sync(area, region);
}
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
static int viewzoom_invoke_impl(bContext *C,
ViewOpsData *vod,
const wmEvent *event,
PointerRNA *ptr)
{
float xy[2];
/* Set to false to avoid contradiction with VIEWOPS_FLAG_ZOOM_TO_MOUSE */
RNA_boolean_set(ptr, "use_cursor_init", false);
/* if one or the other zoom direction is not set */
if (!RNA_struct_property_is_set(ptr, "mx") || !RNA_struct_property_is_set(ptr, "my")) {
/* set xy to region local coordinates */
if (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) {
xy[0] = (float)event->mval[0];
xy[1] = (float)event->mval[1];
}
else {
xy[0] = (float)vod->region->winx / 2.0f;
xy[1] = (float)vod->region->winy / 2.0f;
}
RNA_int_set(ptr, "mx", (int)xy[0]);
RNA_int_set(ptr, "my", (int)xy[1]);
}
else {
copy_v2_fl2(xy, (float)RNA_int_get(ptr, "mx"), (float)RNA_int_get(ptr, "my"));
}
if (RNA_struct_property_is_set(ptr, "delta")) {
return viewzoom_apply_step(C, ptr, vod, xy);
}
else {
/* we do not set the delta property. It is an int, so usually would be
* 0 if rounded from a float */
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
int move_xy[2];
sub_v2_v2v2_int(move_xy, event->prev_xy, event->xy);
if (event->type == MOUSEZOOM) {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
move_xy[1] = move_xy[0];
}
viewzoom_apply(vod, move_xy, USER_ZOOM_DOLLY,((U.uiflag & USER_ZOOM_INVERT) != 0)
^ ((event->flag & WM_EVENT_SCROLL_INVERT) !=0), xy);
return OPERATOR_FINISHED;
}
}
if (U.viewzoom == USER_ZOOM_CONTINUE) {
/* needs a timer to continue redrawing */
vod->prev.time = PIL_check_seconds_timer();
vod->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
}
vod->init.event_xy_offset[0] = xy[0] - (float)vod->region->winx / 2.0f;
vod->init.event_xy_offset[1] = xy[1] - (float)vod->region->winy / 2.0f;
vod->init.zfac = 0.0f;
copy_v2_v2_int(vod->prev.event_xy, event->xy);
return OPERATOR_RUNNING_MODAL;
}
/* viewdolly_invoke() copied this function, changes here may apply there */
static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return view3d_navigate_invoke_impl(C, op, event, &ViewOpsType_zoom);
}
void VIEW3D_OT_zoom(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Zoom View";
ot->description = "Zoom in/out in the view";
ot->idname = ViewOpsType_zoom.idname;
/* api callbacks */
ot->invoke = viewzoom_invoke;
ot->exec = viewzoom_exec;
ot->modal = view3d_navigate_modal_fn;
ot->poll = view3d_zoom_or_dolly_poll;
ot->cancel = view3d_navigate_cancel_fn;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
/* properties */
view3d_operator_properties_common(
ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
}
/** \} */
const ViewOpsType ViewOpsType_zoom = {
/*flag*/ (VIEWOPS_FLAG_DEPTH_NAVIGATE | VIEWOPS_FLAG_ZOOM_TO_MOUSE),
/*idname*/ "VIEW3D_OT_zoom",
/*poll_fn*/ view3d_zoom_or_dolly_poll,
/*init_fn*/ viewzoom_invoke_impl,
/*apply_fn*/ viewzoom_modal_impl,
};

View File

@ -1136,7 +1136,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE:
/* MOUSEPAN usage... */
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f * (event->xy[1] - event->prev_xy[1]);
float fac = 1.0f + 0.005f / UI_SCALE_FAC * WM_event_absolute_delta_y(event);
t->prop_size *= fac;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->clip_end),