Blender V4.3
view3d_navigate_view_dolly.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BKE_context.hh"
10#include "BKE_report.hh"
11
12#include "BLI_math_vector.h"
13
14#include "WM_api.hh"
15
16#include "RNA_access.hh"
17
18#include "ED_screen.hh"
19
20#include "view3d_intern.hh"
21#include "view3d_navigate.hh" /* own include */
22
23/* -------------------------------------------------------------------- */
31{
32 /* NOTE: This is an exact copy of #viewzoom_modal_keymap. */
33
34 static const EnumPropertyItem modal_items[] = {
35 {VIEW_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
36 {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
37
38 {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
39 {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
40
41 {0, nullptr, 0, nullptr, nullptr},
42 };
43
44 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal");
45
46 /* This function is called for each space-type, only needs to add map once. */
47 if (keymap && keymap->modal_items) {
48 return;
49 }
50
51 keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items);
52
53 /* assign map to operators */
54 WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly");
55}
56
58{
59 View3D *v3d = CTX_wm_view3d(C);
61 if (ED_view3d_offset_lock_check(v3d, rv3d)) {
62 BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked");
63 return true;
64 }
65 return false;
66}
67
68static void view_dolly_to_vector_3d(ARegion *region,
69 const float orig_ofs[3],
70 const float dvec[3],
71 float dfac)
72{
73 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
74 madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac));
75}
76
77static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert)
78{
79 float zfac = 1.0;
80
81 {
82 float len1, len2;
83
84 if (U.uiflag & USER_ZOOM_HORIZ) {
85 len1 = (vod->region->winrct.xmax - xy[0]) + 5;
86 len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5;
87 }
88 else {
89 len1 = (vod->region->winrct.ymax - xy[1]) + 5;
90 len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5;
91 }
92 if (zoom_invert) {
93 std::swap(len1, len2);
94 }
95
96 zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist);
97 }
98
99 if (zfac != 1.0f) {
100 view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac);
101 }
102
103 if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
104 view3d_boxview_sync(vod->area, vod->region);
105 }
106
108
110}
111
112static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
113{
114 ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
115 short event_code = VIEW_PASS;
116 bool use_autokey = false;
118
119 /* Execute the events. */
120 if (event->type == EVT_MODAL_MAP) {
121 switch (event->val) {
123 event_code = VIEW_CONFIRM;
124 break;
126 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, nullptr, event);
127 event_code = VIEW_CONFIRM;
128 break;
130 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, nullptr, event);
131 event_code = VIEW_CONFIRM;
132 break;
133 }
134 }
135 else {
136 if (event->type == MOUSEMOVE) {
137 event_code = VIEW_APPLY;
138 }
139 else if (event->type == vod->init.event_type) {
140 if (event->val == KM_RELEASE) {
141 event_code = VIEW_CONFIRM;
142 }
143 }
144 else if (event->type == EVT_ESCKEY) {
145 if (event->val == KM_PRESS) {
146 event_code = VIEW_CANCEL;
147 }
148 }
149 }
150
151 switch (event_code) {
152 case VIEW_APPLY: {
153 viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
155 use_autokey = true;
156 }
157 break;
158 }
159 case VIEW_CONFIRM: {
160 use_autokey = true;
162 break;
163 }
164 case VIEW_CANCEL: {
165 vod->state_restore();
167 break;
168 }
169 }
170
171 if (use_autokey) {
172 ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
173 }
174
175 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
176 if (ret & OPERATOR_FINISHED) {
177 ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
178 }
179 viewops_data_free(C, vod);
180 op->customdata = nullptr;
181 }
182
183 return ret;
184}
185
187{
188 View3D *v3d;
189 RegionView3D *rv3d;
190 ScrArea *area;
191 ARegion *region;
192 float mousevec[3];
193
194 const int delta = RNA_int_get(op->ptr, "delta");
195
196 if (op->customdata) {
197 ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
198
199 area = vod->area;
200 region = vod->region;
201 copy_v3_v3(mousevec, vod->init.mousevec);
202 }
203 else {
204 area = CTX_wm_area(C);
205 region = CTX_wm_region(C);
206 negate_v3_v3(mousevec, static_cast<RegionView3D *>(region->regiondata)->viewinv[2]);
207 normalize_v3(mousevec);
208 }
209
210 v3d = static_cast<View3D *>(area->spacedata.first);
211 rv3d = static_cast<RegionView3D *>(region->regiondata);
212
213 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
214
215 /* overwrite the mouse vector with the view direction (zoom into the center) */
216 if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
217 normalize_v3_v3(mousevec, rv3d->viewinv[2]);
218 negate_v3(mousevec);
219 }
220
221 view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 1.8f : 0.2f);
222
223 if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
224 view3d_boxview_sync(area, region);
225 }
226
228
229 ED_region_tag_redraw(region);
230
231 viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
232 op->customdata = nullptr;
233
234 return OPERATOR_FINISHED;
235}
236
237/* copied from viewzoom_invoke(), changes here may apply there */
238static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
239{
240 ViewOpsData *vod;
241
242 if (viewdolly_offset_lock_check(C, op)) {
243 return OPERATOR_CANCELLED;
244 }
245
246 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
247
248 vod = viewops_data_create(C, event, &ViewOpsType_dolly, use_cursor_init);
249 op->customdata = vod;
250
252
253 /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */
254 /* switch from camera view when: */
255 if (vod->rv3d->persp != RV3D_PERSP) {
256 if (vod->rv3d->persp == RV3D_CAMOB) {
257 /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
260 }
261 else {
262 vod->rv3d->persp = RV3D_PERSP;
263 }
265 }
266
267 /* if one or the other zoom position aren't set, set from event */
268 if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
269 RNA_int_set(op->ptr, "mx", event->xy[0]);
270 RNA_int_set(op->ptr, "my", event->xy[1]);
271 }
272
273 if (RNA_struct_property_is_set(op->ptr, "delta")) {
274 viewdolly_exec(C, op);
275 }
276 else {
277 /* overwrite the mouse vector with the view direction (zoom into the center) */
278 if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) {
279 negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]);
281 }
282
283 if (event->type == MOUSEZOOM) {
284 /* Bypass Zoom invert flag for track pads (pass false always) */
285
286 if (U.uiflag & USER_ZOOM_HORIZ) {
287 vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
288 }
289 else {
290 /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
291 vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
292 event->prev_xy[0];
293 }
294 viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0);
295
296 viewops_data_free(C, static_cast<ViewOpsData *>(op->customdata));
297 op->customdata = nullptr;
298 return OPERATOR_FINISHED;
299 }
300
301 /* add temp handler */
304 }
305 return OPERATOR_FINISHED;
306}
307
309{
310 /* identifiers */
311 ot->name = "Dolly View";
312 ot->description = "Dolly in/out in the view";
314
315 /* api callbacks */
321
322 /* flags */
324
325 /* properties */
328}
329
334 /*idname*/ "VIEW3D_OT_dolly",
335 /*poll_fn*/ nullptr,
336 /*init_fn*/ nullptr,
337 /*apply_fn*/ nullptr,
338};
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE float normalize_v3(float n[3])
@ USER_ZOOM_INVERT
@ USER_ZOOM_TO_MOUSEPOS
@ USER_ZOOM_HORIZ
#define RV3D_LOCK_FLAGS(rv3d)
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_BOXVIEW
@ OPERATOR_RUNNING_MODAL
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, char persp)
bool ED_view3d_camera_lock_undo_push(const char *str, const View3D *v3d, const RegionView3D *rv3d, bContext *C)
bool ED_view3d_camera_lock_autokey(View3D *v3d, RegionView3D *rv3d, bContext *C, bool do_rotate, bool do_translate)
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_GRAB_CURSOR_XY
Definition WM_types.hh:168
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
unsigned int U
Definition btGjkEpa3.h:78
const Depsgraph * depsgraph
@ VIEW_CONFIRM
Definition image_ops.cc:587
@ VIEW_PASS
Definition image_ops.cc:585
@ VIEW_APPLY
Definition image_ops.cc:586
return ret
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
float viewinv[4][4]
struct ViewOpsData::@543 init
Depsgraph * depsgraph
ARegion * region
struct ViewOpsData::@544 prev
RegionView3D * rv3d
const char * idname
int ymax
int xmax
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
int prev_xy[2]
Definition WM_types.hh:785
short type
Definition WM_types.hh:722
const void * modal_items
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void view3d_boxview_sync(ScrArea *area, ARegion *region)
void view3d_navigate_cancel_fn(bContext *C, wmOperator *op)
void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag)
void viewops_data_free(bContext *C, ViewOpsData *vod)
ViewOpsData * viewops_data_create(bContext *C, const wmEvent *event, const ViewOpsType *nav_type, const bool use_cursor_init)
bool view3d_rotation_poll(bContext *C)
@ VIEWOPS_FLAG_DEPTH_NAVIGATE
@ VIEWOPS_FLAG_ZOOM_TO_MOUSE
@ VIEW_CANCEL
@ VIEWROT_MODAL_SWITCH_ROTATE
@ VIEW_MODAL_CANCEL
@ VIEWROT_MODAL_SWITCH_MOVE
@ VIEW_MODAL_CONFIRM
@ V3D_OP_PROP_USE_MOUSE_INIT
@ V3D_OP_PROP_DELTA
@ V3D_OP_PROP_MOUSE_CO
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void view_dolly_to_vector_3d(ARegion *region, const float orig_ofs[3], const float dvec[3], float dfac)
ViewOpsType ViewOpsType_dolly
static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert)
static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int viewdolly_exec(bContext *C, wmOperator *op)
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
void VIEW3D_OT_dolly(wmOperatorType *ot)
int xy[2]
Definition wm_draw.cc:170
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ EVT_MODAL_MAP
@ MOUSEZOOM
@ MOUSEMOVE
@ EVT_ESCKEY
wmOperatorType * ot
Definition wm_files.cc:4125
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960