Blender V5.0
editors/transform/transform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_listbase.h"
10#include "BLI_math_matrix.h"
11#include "BLI_math_vector.h"
12#include "BLI_rect.h"
13
14#include "BKE_context.hh"
15#include "BKE_editmesh.hh"
16#include "BKE_global.hh"
17#include "BKE_layer.hh"
18#include "BKE_mask.h"
19#include "BKE_screen.hh"
20#include "BKE_workspace.hh"
21
22#include "GPU_state.hh"
23
24#include "ED_clip.hh"
25#include "ED_gpencil_legacy.hh"
26#include "ED_image.hh"
27#include "ED_screen.hh"
28#include "ED_space_api.hh"
29#include "ED_uvedit.hh"
30
31#include "ANIM_keyframing.hh"
32
33#include "SEQ_transform.hh"
34
35#include "WM_api.hh"
36#include "WM_message.hh"
37
38#include "UI_interface_icons.hh"
39#include "UI_resources.hh"
40#include "UI_view2d.hh"
41
42#include "RNA_access.hh"
43
44#include "BLF_api.hh"
45#include "BLT_translation.hh"
46
47#include "transform.hh"
49#include "transform_convert.hh"
51#include "transform_gizmo.hh"
52#include "transform_mode.hh"
54#include "transform_snap.hh"
55
56/* Disabling, since when you type you know what you are doing,
57 * and being able to set it to zero is handy. */
58// #define USE_NUM_NO_ZERO.
59
60namespace blender::ed::transform {
61
62/* -------------------------------------------------------------------- */
65
66void transform_view_vector_calc(const TransInfo *t, const float focus[3], float r_vec[3])
67{
68 if (t->persp != RV3D_ORTHO) {
69 sub_v3_v3v3(r_vec, t->viewinv[3], focus);
70 }
71 else {
72 copy_v3_v3(r_vec, t->viewinv[2]);
73 }
74 normalize_v3(r_vec);
75}
76
78{
80 return false;
81 }
82 return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
84}
85
87
88/* ************************** SPACE DEPENDENT CODE **************************** */
89
91{
92 if (!(t->options & CTX_PAINT_CURVE) && (t->spacetype == SPACE_VIEW3D) && t->region &&
94 {
95 RegionView3D *rv3d = static_cast<RegionView3D *>(t->region->regiondata);
96
97 copy_m4_m4(t->viewmat, rv3d->viewmat);
98 copy_m4_m4(t->viewinv, rv3d->viewinv);
99 copy_m4_m4(t->persmat, rv3d->persmat);
100 copy_m4_m4(t->persinv, rv3d->persinv);
101 t->persp = rv3d->persp;
102 }
103 else {
104 unit_m4(t->viewmat);
105 unit_m4(t->viewinv);
106 unit_m4(t->persmat);
107 unit_m4(t->persinv);
108 t->persp = RV3D_ORTHO;
109 }
110}
111
112void setTransformViewAspect(TransInfo *t, float r_aspect[3])
113{
114 copy_v3_fl(r_aspect, 1.0f);
115
116 if (t->spacetype == SPACE_IMAGE) {
117 SpaceImage *sima = static_cast<SpaceImage *>(t->area->spacedata.first);
118
119 if (t->options & CTX_MASK) {
120 ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
121 }
122 else if (t->options & CTX_PAINT_CURVE) {
123 /* Pass. */
124 }
125 else {
126 ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
127 }
128 }
129 else if (t->spacetype == SPACE_SEQ) {
130 if (t->options & CTX_CURSOR) {
132 const float2 aspect = seq::image_preview_unit_to_px(scene, r_aspect);
133 copy_v2_v2(r_aspect, aspect);
134 }
135 }
136 else if (t->spacetype == SPACE_CLIP) {
137 SpaceClip *sclip = static_cast<SpaceClip *>(t->area->spacedata.first);
138
139 if (t->options & CTX_MOVIECLIP) {
140 ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
141 }
142 else {
143 ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]);
144 }
145 }
146 else if (t->spacetype == SPACE_GRAPH) {
147 /* Depends on context of usage. */
148 }
149}
150
151static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
152{
153 float divx = BLI_rcti_size_x(&v2d->mask);
154 float divy = BLI_rcti_size_y(&v2d->mask);
155
156 r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
157 r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
158 r_vec[2] = 0.0f;
159}
160
161static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
162{
163 float divx = BLI_rcti_size_x(&v2d->mask);
164 float divy = BLI_rcti_size_y(&v2d->mask);
165
166 float mulx = BLI_rctf_size_x(&v2d->cur);
167 float muly = BLI_rctf_size_y(&v2d->cur);
168
169 /* Difference with #convertViewVec2D. */
170 /* Clamp w/h, mask only. */
171 if (mulx / divx < muly / divy) {
172 divy = divx;
173 muly = mulx;
174 }
175 else {
176 divx = divy;
177 mulx = muly;
178 }
179 /* End difference. */
180
181 r_vec[0] = mulx * dx / divx;
182 r_vec[1] = muly * dy / divy;
183 r_vec[2] = 0.0f;
184}
185
186void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
187{
188 if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
189 if (t->options & CTX_PAINT_CURVE) {
190 r_vec[0] = dx;
191 r_vec[1] = dy;
192 }
193 else {
194 const float xy_delta[2] = {float(dx), float(dy)};
195 ED_view3d_win_to_delta(t->region, xy_delta, t->zfac, r_vec);
196 }
197 }
198 else if (t->spacetype == SPACE_IMAGE) {
199 if (t->options & CTX_MASK) {
200 convertViewVec2D_mask(static_cast<View2D *>(t->view), r_vec, dx, dy);
201 }
202 else if (t->options & CTX_PAINT_CURVE) {
203 r_vec[0] = dx;
204 r_vec[1] = dy;
205 }
206 else {
207 convertViewVec2D(static_cast<View2D *>(t->view), r_vec, dx, dy);
208 }
209
210 r_vec[0] *= t->aspect[0];
211 r_vec[1] *= t->aspect[1];
212 }
213 else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
214 convertViewVec2D(static_cast<View2D *>(t->view), r_vec, dx, dy);
215 }
216 else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
217 convertViewVec2D(&t->region->v2d, r_vec, dx, dy);
218 }
219 else if (t->spacetype == SPACE_CLIP) {
220 if (t->options & CTX_MASK) {
221 convertViewVec2D_mask(static_cast<View2D *>(t->view), r_vec, dx, dy);
222 }
223 else {
224 convertViewVec2D(static_cast<View2D *>(t->view), r_vec, dx, dy);
225 }
226
227 r_vec[0] *= t->aspect[0];
228 r_vec[1] *= t->aspect[1];
229 }
230 else {
231 printf("%s: called in an invalid context\n", __func__);
232 zero_v3(r_vec);
233 }
234}
235
237{
238 const ARegion *region = t->region;
239
240 if (UNLIKELY(region == nullptr)) {
241 /* While this function probably wont be calved without a region.
242 * Doing so shouldn't cause errors. */
243 adr[0] = 0.0f;
244 adr[1] = 0.0f;
245 return;
246 }
247
248 bool changed = false;
249 switch (t->spacetype) {
250 case SPACE_VIEW3D: {
251 if (region->regiontype == RGN_TYPE_WINDOW) {
252 /* NOTE(@ideasman42): When picking a fallback there isn't a "correct" location.
253 * By default the region center is the fallback, use this unless there is a reason not to.
254 *
255 * One exception is when transforming the camera from the camera viewpoint.
256 * In this case it's logical to use the camera frames center, see: #141663. */
257 if (t->options & CTX_CAMERA) {
258 const View3D *v3d = static_cast<View3D *>(t->view);
259 const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
260 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
261 /* Exclude any camera "shift" because the un-shifted point is the pivot.
262 *
263 * This may not be the case when transforming a cameras parent however
264 * in these situations it's not practical to find a screen space location
265 * for a 3D point that couldn't be projected. */
266 const bool no_shift = true;
267 rctf viewborder = {0};
269 t->scene, t->depsgraph, region, v3d, rv3d, no_shift, &viewborder);
270 adr[0] = BLI_rctf_cent_x(&viewborder);
271 adr[1] = BLI_rctf_cent_y(&viewborder);
272 changed = true;
273 }
274 }
275 }
276 break;
277 }
278 }
279
280 if (changed == false) {
281 adr[0] = region->winx / 2.0f;
282 adr[1] = region->winy / 2.0f;
283 }
284}
285
286void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
287{
288 if (t->spacetype == SPACE_VIEW3D) {
289 if (t->region->regiontype == RGN_TYPE_WINDOW) {
291 /* This is what was done in 2.64, perhaps we can be smarter? */
292 adr[0] = int(2140000000.0f);
293 adr[1] = int(2140000000.0f);
294 }
295 }
296 }
297 else if (t->spacetype == SPACE_IMAGE) {
298 SpaceImage *sima = static_cast<SpaceImage *>(t->area->spacedata.first);
299
300 if (t->options & CTX_MASK) {
301 float v[2];
302
303 v[0] = vec[0] / t->aspect[0];
304 v[1] = vec[1] / t->aspect[1];
305
306 BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
307
309
310 adr[0] = v[0];
311 adr[1] = v[1];
312 }
313 else if (t->options & CTX_PAINT_CURVE) {
314 adr[0] = vec[0];
315 adr[1] = vec[1];
316 }
317 else {
318 float v[2];
319
320 v[0] = vec[0] / t->aspect[0];
321 v[1] = vec[1] / t->aspect[1];
322
323 UI_view2d_view_to_region(static_cast<const View2D *>(t->view), v[0], v[1], &adr[0], &adr[1]);
324 }
325 }
326 else if (t->spacetype == SPACE_ACTION) {
327 int out[2] = {0, 0};
328#if 0
329 SpaceAction *sact = t->area->spacedata.first;
330
331 if (sact->flag & SACTION_DRAWTIME) {
332 // vec[0] = vec[0] / ((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
333 /* Same as below. */
334 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
335 }
336 else
337#endif
338 {
339 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
340 }
341
342 adr[0] = out[0];
343 adr[1] = out[1];
344 }
345 else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
346 int out[2] = {0, 0};
347
348 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
349 adr[0] = out[0];
350 adr[1] = out[1];
351 }
352 else if (t->spacetype == SPACE_SEQ) { /* XXX not tested yet, but should work. */
353 int out[2] = {0, 0};
354
355 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
356 adr[0] = out[0];
357 adr[1] = out[1];
358 }
359 else if (t->spacetype == SPACE_CLIP) {
360 SpaceClip *sc = static_cast<SpaceClip *>(t->area->spacedata.first);
361
362 if (t->options & CTX_MASK) {
364
365 if (clip) {
366 float v[2];
367
368 v[0] = vec[0] / t->aspect[0];
369 v[1] = vec[1] / t->aspect[1];
370
372
374
375 adr[0] = v[0];
376 adr[1] = v[1];
377 }
378 else {
379 adr[0] = 0;
380 adr[1] = 0;
381 }
382 }
383 else if (t->options & CTX_MOVIECLIP) {
384 float v[2];
385
386 v[0] = vec[0] / t->aspect[0];
387 v[1] = vec[1] / t->aspect[1];
388
389 UI_view2d_view_to_region(static_cast<const View2D *>(t->view), v[0], v[1], &adr[0], &adr[1]);
390 }
391 else {
392 BLI_assert(0);
393 }
394 }
395 else if (t->spacetype == SPACE_NODE) {
396 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &adr[0], &adr[1]);
397 }
398}
399void projectIntView(TransInfo *t, const float vec[3], int adr[2])
400{
402}
403
404void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
405{
406 switch (t->spacetype) {
407 case SPACE_VIEW3D: {
408 if (t->options & CTX_PAINT_CURVE) {
409 adr[0] = vec[0];
410 adr[1] = vec[1];
411 }
412 else if (t->region->regiontype == RGN_TYPE_WINDOW) {
413 /* Allow points behind the view #33643. */
415 /* XXX, 2.64 and prior did this, weak! */
417 }
418 return;
419 }
420 break;
421 }
422 default: {
423 int a[2] = {0, 0};
424 projectIntView(t, vec, a);
425 adr[0] = a[0];
426 adr[1] = a[1];
427 break;
428 }
429 }
430}
431void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
432{
434}
435
436void applyAspectRatio(TransInfo *t, float vec[2])
437{
438 if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) &&
439 !(t->options & CTX_PAINT_CURVE))
440 {
441 SpaceImage *sima = static_cast<SpaceImage *>(t->area->spacedata.first);
442
443 if ((sima->flag & SI_COORDFLOATS) == 0) {
444 int width, height;
445 ED_space_image_get_size(sima, &width, &height);
446
447 vec[0] *= width;
448 vec[1] *= height;
449 }
450
451 vec[0] /= t->aspect[0];
452 vec[1] /= t->aspect[1];
453 }
454 else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
455 if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
456 vec[0] /= t->aspect[0];
457 vec[1] /= t->aspect[1];
458 }
459 }
460}
461
462void removeAspectRatio(TransInfo *t, float vec[2])
463{
464 if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
465 SpaceImage *sima = static_cast<SpaceImage *>(t->area->spacedata.first);
466
467 if ((sima->flag & SI_COORDFLOATS) == 0) {
468 int width, height;
469 ED_space_image_get_size(sima, &width, &height);
470
471 vec[0] /= width;
472 vec[1] /= height;
473 }
474
475 vec[0] *= t->aspect[0];
476 vec[1] *= t->aspect[1];
477 }
478 else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
479 if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
480 vec[0] *= t->aspect[0];
481 vec[1] *= t->aspect[1];
482 }
483 }
484}
485
486static void viewRedrawForce(const bContext *C, TransInfo *t)
487{
488 if (t->options & CTX_GPENCIL_STROKES) {
489 if (t->obedit_type == OB_GREASE_PENCIL) {
491 }
492 }
493 else if (t->spacetype == SPACE_VIEW3D) {
494 if (t->options & CTX_PAINT_CURVE) {
495 wmWindow *window = CTX_wm_window(C);
497 }
498 else {
499 /* Do we need more refined tags? */
500 if (t->options & CTX_POSE_BONE) {
502 }
503 else {
505 }
506
507 /* For real-time animation record - send notifiers recognized by animation editors. */
508 /* XXX: is this notifier a lame duck? */
509 if ((t->animtimer) && animrig::is_autokey_on(t->scene)) {
511 }
512 }
513 }
514 else if (t->spacetype == SPACE_ACTION) {
515 // SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
517 }
518 else if (t->spacetype == SPACE_GRAPH) {
519 // SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
521 }
522 else if (t->spacetype == SPACE_NLA) {
524 }
525 else if (t->spacetype == SPACE_NODE) {
526 // ED_area_tag_redraw(t->area);
528 }
529 else if (t->spacetype == SPACE_SEQ) {
531 /* Key-frames on strips has been moved, so make sure related editors are informed. */
533 }
534 else if (t->spacetype == SPACE_IMAGE) {
535 if (t->options & CTX_MASK) {
537
539 }
540 else if (t->options & CTX_PAINT_CURVE) {
541 wmWindow *window = CTX_wm_window(C);
543 }
544 else if (t->options & CTX_CURSOR) {
546 }
547 else {
548 /* XXX how to deal with lock? */
550 if (sima->lock) {
554 }
555 else {
557 }
558 }
559 }
560 else if (t->spacetype == SPACE_CLIP) {
562
565
566 /* Objects could be parented to tracking data, so send this for viewport refresh. */
568
570 }
573
575 }
576 }
577}
578
580{
581 ED_area_status_text(t->area, nullptr);
582 WorkSpace *workspace = CTX_wm_workspace(C);
583 if (workspace) {
585 }
586
587 if (t->spacetype == SPACE_VIEW3D) {
588 /* If auto-keying is enabled, send notifiers that keyframes were added. */
591 }
592
593 /* Redraw UV editor. */
594 const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ?
597
598 if ((t->data_type == &TransConvertType_Mesh) &&
599 (t->settings->uvcalc_flag & uvcalc_correct_flag))
600 {
602 }
603 }
604}
605
606/* ************************************************* */
607
608static bool transform_modal_item_poll(const wmOperator *op, int value)
609{
610 const TransInfo *t = static_cast<const TransInfo *>(op->customdata);
612 if (value == TFM_MODAL_EDIT_SNAP_SOURCE_OFF) {
613 return true;
614 }
615 if (!ELEM(
617 {
618 return false;
619 }
620 }
621
622 switch (value) {
623 case TFM_MODAL_CANCEL: {
624 /* TODO: Canceling with LMB is not possible when the operator is activated
625 * through tweak and the LMB is pressed.
626 * Therefore, this item should not appear in the status bar. */
627 break;
628 }
632 if ((t->flag & T_PROP_EDIT) == 0) {
633 return false;
634 }
635 break;
636 }
639 if (t->spacetype != SPACE_VIEW3D) {
640 return false;
641 }
642 if (value == TFM_MODAL_ADD_SNAP) {
643 if (!(t->tsnap.status & SNAP_TARGET_FOUND)) {
644 return false;
645 }
646 }
647 else {
648 if (!t->tsnap.selectedPoint) {
649 return false;
650 }
651 }
652 break;
653 }
654 case TFM_MODAL_AXIS_Z:
659 if (t->flag & T_2D_EDIT) {
660 return false;
661 }
662 [[fallthrough]];
663 case TFM_MODAL_AXIS_X:
664 case TFM_MODAL_AXIS_Y:
666 if (t->flag & T_NO_CONSTRAINT) {
667 return false;
668 }
669 break;
670 case TFM_MODAL_CONS_OFF: {
671 if ((t->con.mode & CON_APPLY) == 0) {
672 return false;
673 }
674 break;
675 }
680 if (t->spacetype != SPACE_NODE) {
681 return false;
682 }
683 break;
684 }
687 if ((t->flag & T_AUTOIK) == 0) {
688 return false;
689 }
690 break;
691 }
693 case TFM_MODAL_ROTATE:
694 case TFM_MODAL_RESIZE:
699 return false;
700 }
701 if (value == TFM_MODAL_TRANSLATE && t->mode == TFM_TRANSLATION) {
702 /* The tracking transform in MovieClip has an alternate translate that modifies the offset
703 * of the tracks. */
705 }
706 if (value == TFM_MODAL_ROTATE && t->mode == TFM_ROTATION) {
707 return false;
708 }
709 if (value == TFM_MODAL_RESIZE && t->mode == TFM_RESIZE) {
710 /* The tracking transform in MovieClip has an alternate resize that only affects the
711 * tracker size and not the search area. */
713 }
714 if (value == TFM_MODAL_VERT_EDGE_SLIDE &&
716 /* WORKAROUND: Avoid repeated keys in status bar.
717 *
718 * Previously, `Vert/Edge Slide` and `Move` were triggered by the same modal key.
719 * But now, to fix #100129 (Status bar incorrectly shows "[G] Move"), `Vert/Edge Slide`
720 * has its own modal key. However by default it uses the same key as `Move` (G). So, to
721 * avoid displaying the same key twice (G and G), only display this modal key during the
722 * `Move` operation.
723 *
724 * Ideally we should check if it really uses the same key. */
725 t->mode != TFM_TRANSLATION))
726 {
727 return false;
728 }
729 if (value == TFM_MODAL_TRACKBALL &&
730 /* WORKAROUND: Avoid repeated keys in status bar.
731 *
732 * Previously, `Trackball` and `Rotate` were triggered by the same modal key.
733 * But to fix the status bar incorrectly showing "[R] Rotate", `Trackball` has now its
734 * own modal key. However by default it uses the same key as `Rotate` (R). So, to avoid
735 * displaying the same key twice (R and R), only display this modal key during the
736 * `Rotate` operation.
737 *
738 * Ideally we should check if it really uses the same key. */
739 t->mode != TFM_ROTATION)
740 {
741 return false;
742 }
743 if (value == TFM_MODAL_ROTATE_NORMALS) {
744 return t->mode == TFM_ROTATION && t->data_type == &TransConvertType_Mesh;
745 }
746 break;
747 }
749 return false;
752 return false;
753 }
754 if (!ELEM(
756 {
757 /* More modes can be added over time if this feature proves useful for them. */
758 return false;
759 }
760 if (t->options & CTX_CAMERA) {
761 /* Not supported. */
762 return false;
763 }
764 break;
765 }
768 /* Returning `false` will not prevent the navigation from working, it will just not display
769 * the shortcut in the header.
770 * Return `false` here to prevent this modal item from affecting the state with
771 * #T_ALT_TRANSFORM is used by the operator. */
772 return false;
773 }
774 return t->vod != nullptr;
776 if (t->spacetype != SPACE_SEQ) {
777 return false;
778 }
779 break;
780 }
781 return true;
782}
783
785{
786 static const EnumPropertyItem modal_items[] = {
787 {TFM_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
788 {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
789 {TFM_MODAL_AXIS_X, "AXIS_X", 0, "X Axis", ""},
790 {TFM_MODAL_AXIS_Y, "AXIS_Y", 0, "Y Axis", ""},
791 {TFM_MODAL_AXIS_Z, "AXIS_Z", 0, "Z Axis", ""},
792 {TFM_MODAL_PLANE_X, "PLANE_X", 0, "X Plane", ""},
793 {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Y Plane", ""},
794 {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Z Plane", ""},
795 {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Clear Constraints", ""},
796 {TFM_MODAL_EDIT_SNAP_SOURCE_ON, "EDIT_SNAP_SOURCE_ON", 0, "Set Snap Base", ""},
797 {TFM_MODAL_EDIT_SNAP_SOURCE_OFF, "EDIT_SNAP_SOURCE_OFF", 0, "Set Snap Base (Off)", ""},
798 {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Snap Invert", ""},
799 {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Snap Invert (Off)", ""},
800 {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""},
801 {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""},
802 {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""},
803 {NUM_MODAL_INCREMENT_UP, "INCREMENT_UP", 0, "Numinput Increment Up", ""},
804 {NUM_MODAL_INCREMENT_DOWN, "INCREMENT_DOWN", 0, "Numinput Increment Down", ""},
805 {TFM_MODAL_PROPSIZE_UP, "PROPORTIONAL_SIZE_UP", 0, "Increase Proportional Influence", ""},
807 "PROPORTIONAL_SIZE_DOWN",
808 0,
809 "Decrease Proportional Influence",
810 ""},
811 {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
812 {TFM_MODAL_AUTOIK_LEN_INC, "AUTOIK_CHAIN_LEN_UP", 0, "Increase Max AutoIK Chain Length", ""},
814 "AUTOIK_CHAIN_LEN_DOWN",
815 0,
816 "Decrease Max AutoIK Chain Length",
817 ""},
819 "INSERTOFS_TOGGLE_DIR",
820 0,
821 "Toggle Direction for Node Auto-Offset",
822 ""},
823 {TFM_MODAL_NODE_ATTACH_ON, "NODE_ATTACH_ON", 0, "Node Attachment", ""},
824 {TFM_MODAL_NODE_ATTACH_OFF, "NODE_ATTACH_OFF", 0, "Node Attachment (Off)", ""},
825 {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Move", ""},
826 {TFM_MODAL_VERT_EDGE_SLIDE, "VERT_EDGE_SLIDE", 0, "Vert/Edge Slide", ""},
827 {TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""},
828 {TFM_MODAL_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
829 {TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""},
830 {TFM_MODAL_ROTATE_NORMALS, "ROTATE_NORMALS", 0, "Rotate Normals", ""},
831 {TFM_MODAL_AUTOCONSTRAINT, "AUTOCONSTRAIN", 0, "Automatic Constraint", ""},
832 {TFM_MODAL_AUTOCONSTRAINTPLANE, "AUTOCONSTRAINPLANE", 0, "Automatic Constraint Plane", ""},
833 {TFM_MODAL_PRECISION, "PRECISION", 0, "Precision Mode", ""},
834 {TFM_MODAL_PASSTHROUGH_NAVIGATE, "PASSTHROUGH_NAVIGATE", 0, "Navigate", ""},
835 {TFM_MODAL_NODE_FRAME, "NODE_FRAME", 0, "Attach/Detach Frame", ""},
836 {TFM_MODAL_STRIP_CLAMP, "STRIP_CLAMP_TOGGLE", 0, "Clamp Strips", ""},
837 {0, nullptr, 0, nullptr, nullptr},
838 };
839
840 wmKeyMap *keymap = WM_modalkeymap_ensure(keyconf, "Transform Modal Map", modal_items);
842
843 /* Default modal map values:
844 *
845 * \code{.c}
846 * WM_modalkeymap_add_item(keymap,
847 * &(const KeyMapItem_Params){
848 * .type = EVT_RETKEY,
849 * .value = KM_PRESS,
850 * .modifier = KM_ANY,
851 * .direction = KM_ANY,
852 * },
853 * TFM_MODAL_CONFIRM);
854 * WM_modalkeymap_add_item(keymap,
855 * &(const KeyMapItem_Params){
856 * .type = EVT_ESCKEY,
857 * .value = KM_PRESS,
858 * .modifier = KM_ANY,
859 * .direction = KM_ANY,
860 * },
861 * TFM_MODAL_CANCEL);
862 * WM_modalkeymap_add_item(keymap,
863 * &(const KeyMapItem_Params){
864 * .type = EVT_PAGEUPKEY,
865 * .value = KM_PRESS,
866 * .modifier = KM_ANY,
867 * .direction = KM_ANY,
868 * },
869 * TFM_MODAL_AUTOIK_LEN_INC);
870 * WM_modalkeymap_add_item(keymap,
871 * &(const KeyMapItem_Params){
872 * .type = EVT_PAGEDOWNKEY,
873 * .value = KM_PRESS,
874 * .modifier = KM_ANY,
875 * .direction = KM_ANY,
876 * },
877 * TFM_MODAL_AUTOIK_LEN_DEC);
878 * WM_modalkeymap_add_item(keymap,
879 * &(const KeyMapItem_Params){
880 * .type = EVT_GKEY,
881 * .value = KM_PRESS,
882 * .modifier = KM_ANY,
883 * .direction = KM_ANY,
884 * },
885 * TFM_MODAL_TRANSLATE);
886 * WM_modalkeymap_add_item(keymap,
887 * &(const KeyMapItem_Params){
888 * .type = EVT_RKEY,
889 * .value = KM_PRESS,
890 * .modifier = KM_ANY,
891 * .direction = KM_ANY,
892 * },
893 * TFM_MODAL_ROTATE);
894 * WM_modalkeymap_add_item(keymap,
895 * &(const KeyMapItem_Params){
896 * .type = EVT_SKEY,
897 * .value = KM_PRESS,
898 * .modifier = KM_ANY,
899 * .direction = KM_ANY,
900 * },
901 * TFM_MODAL_RESIZE);
902 * WM_modalkeymap_add_item(keymap,
903 * &(const KeyMapItem_Params){
904 * .type = MIDDLEMOUSE,
905 * .value = KM_PRESS,
906 * .modifier = KM_ANY,
907 * .direction = KM_ANY,
908 * },
909 * TFM_MODAL_AUTOCONSTRAINT);
910 * WM_modalkeymap_add_item(keymap,
911 * &(const KeyMapItem_Params){
912 * .type = MIDDLEMOUSE,
913 * .value = KM_PRESS,
914 * .modifier = KM_SHIFT,
915 * .direction = KM_ANY,
916 * },
917 * TFM_MODAL_AUTOCONSTRAINTPLANE);
918 * \endcode
919 */
920
921 return keymap;
922}
923
924static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
925{
926 if (t->flag & T_NO_CONSTRAINT) {
927 return false;
928 }
929
930 if (t->flag & T_2D_EDIT && ELEM(modal_type, TFM_MODAL_AXIS_Z, TFM_MODAL_PLANE_Z)) {
931 return false;
932 }
933
934 int constraint_curr = -1;
935
938
939 /* Avoid changing orientation in this case. */
940 constraint_curr = -2;
941 }
942 else if (t->con.mode & CON_APPLY) {
943 constraint_curr = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
944 }
945
946 int constraint_new;
947 const char *msg_2d = "", *msg_3d = "";
948
949 /* Initialize. */
950 switch (modal_type) {
951 case TFM_MODAL_AXIS_X:
952 msg_2d = IFACE_("along X");
953 msg_3d = IFACE_("along %s X");
954 constraint_new = CON_AXIS0;
955 break;
956 case TFM_MODAL_AXIS_Y:
957 msg_2d = IFACE_("along Y");
958 msg_3d = IFACE_("along %s Y");
959 constraint_new = CON_AXIS1;
960 break;
961 case TFM_MODAL_AXIS_Z:
962 msg_2d = IFACE_("along Z");
963 msg_3d = IFACE_("along %s Z");
964 constraint_new = CON_AXIS2;
965 break;
967 msg_3d = IFACE_("locking %s X");
968 constraint_new = CON_AXIS1 | CON_AXIS2;
969 break;
971 msg_3d = IFACE_("locking %s Y");
972 constraint_new = CON_AXIS0 | CON_AXIS2;
973 break;
975 msg_3d = IFACE_("locking %s Z");
976 constraint_new = CON_AXIS0 | CON_AXIS1;
977 break;
978 default:
979 /* Invalid key. */
980 return false;
981 }
982
983 if (t->flag & T_2D_EDIT) {
984 BLI_assert(modal_type < TFM_MODAL_PLANE_X);
985 if (constraint_new == CON_AXIS2) {
986 return false;
987 }
988
990 /* Setup the 2d msg string so it writes out the transform space. */
991 msg_2d = msg_3d;
992
993 short orient_index = 1;
994 if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) {
995 /* Successive presses on existing axis, cycle orientation modes. */
996 orient_index = short((t->orient_curr + 1) % int(ARRAY_SIZE(t->orient)));
997 }
998
999 transform_orientations_current_set(t, orient_index);
1000 if (orient_index != 0) {
1001 /* Make sure that we don't stop the constraint unless we are looped back around to
1002 * "no constraint". */
1003 constraint_curr = -1;
1004 }
1005 }
1006
1007 if (constraint_curr == constraint_new) {
1008 stopConstraint(t);
1009 }
1010 else {
1011 setUserConstraint(t, constraint_new, msg_2d);
1012 }
1013 }
1014 else {
1015 short orient_index = 1;
1016 if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) {
1017 /* Successive presses on existing axis, cycle orientation modes. */
1018 orient_index = short((t->orient_curr + 1) % int(ARRAY_SIZE(t->orient)));
1019 }
1020
1021 transform_orientations_current_set(t, orient_index);
1022 if (orient_index == 0) {
1023 stopConstraint(t);
1024 }
1025 else {
1026 setUserConstraint(t, constraint_new, msg_3d);
1027 }
1028
1029 /* Take the opportunity to update the gizmo. */
1031 }
1032 return true;
1033}
1034
1036{
1037 bool is_snap_enabled = (t->modifiers & MOD_SNAP) != 0;
1038
1039 /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */
1040 short *snap_flag_ptr;
1041
1042 wmMsgParams_RNA msg_key_params = {{}};
1043 msg_key_params.ptr = RNA_pointer_create_discrete(&t->scene->id, &RNA_ToolSettings, t->settings);
1044 if ((snap_flag_ptr = transform_snap_flag_from_spacetype_ptr(t, &msg_key_params.prop)) &&
1045 (is_snap_enabled != bool(*snap_flag_ptr & SCE_SNAP)))
1046 {
1047 SET_FLAG_FROM_TEST(*snap_flag_ptr, is_snap_enabled, SCE_SNAP);
1048 WM_msg_publish_rna_params(t->mbus, &msg_key_params);
1049 }
1050}
1051
1053{
1054 bool is_navigating = t->vod ? ((RegionView3D *)t->region->regiondata)->rflag & RV3D_NAVIGATING :
1055 false;
1056
1057 /* Handle modal numinput events first, if already activated. */
1058 if (!is_navigating && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
1059 hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
1060 {
1061 t->redraw |= TREDRAW_HARD;
1062 }
1063 else if (event->type == TIMER) {
1064 if (ED_uvedit_live_unwrap_timer_check(static_cast<const wmTimer *>(event->customdata))) {
1065 t->redraw |= TREDRAW_HARD;
1066 }
1067 }
1068 else if (!is_navigating && event->type == MOUSEMOVE) {
1069 t->mval = float2(event->mval);
1070
1071 /* Use this for soft redraw. Might cause flicker in object mode. */
1072 // t->redraw |= TREDRAW_SOFT;
1073 t->redraw |= TREDRAW_HARD;
1074
1075 if (t->state == TRANS_STARTING) {
1076 t->state = TRANS_RUNNING;
1077 }
1078
1079 applyMouseInput(t, &t->mouse, t->mval, t->values);
1080
1081 /* Snapping mouse move events. */
1082 t->redraw |= handleSnapping(t, event);
1083 }
1084 /* Handle modal keymap first. */
1085 /* Enforce redraw of transform when modifiers are used. */
1086 else if (event->type == EVT_MODAL_MAP) {
1087 switch (event->val) {
1088 case TFM_MODAL_CANCEL:
1089 if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
1090 t->state = TRANS_CANCEL;
1091 }
1092 break;
1093 case TFM_MODAL_CONFIRM:
1094 if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
1095 t->state = TRANS_CONFIRM;
1096 }
1097 break;
1099 case TFM_MODAL_ROTATE:
1100 case TFM_MODAL_RESIZE:
1104 /* Only switch when supported. */
1106 break;
1107 }
1108
1109 if ((event->val == TFM_MODAL_TRANSLATE && t->mode == TFM_TRANSLATION) ||
1110 (event->val == TFM_MODAL_RESIZE && t->mode == TFM_RESIZE))
1111 {
1114
1115 t->flag ^= T_ALT_TRANSFORM;
1116 t->redraw |= TREDRAW_HARD;
1117 }
1118 break;
1119 }
1120
1121 if ((event->val == TFM_MODAL_ROTATE && t->mode == TFM_ROTATION) ||
1122 (event->val == TFM_MODAL_TRACKBALL && t->mode == TFM_TRACKBALL) ||
1124 (event->val == TFM_MODAL_VERT_EDGE_SLIDE &&
1126 {
1127 break;
1128 }
1129
1131 break;
1132 }
1133
1135 resetTransModal(t);
1137
1138 if (event->val == TFM_MODAL_TRANSLATE) {
1140 }
1141 else if (event->val == TFM_MODAL_ROTATE) {
1142 transform_mode_init(t, nullptr, TFM_ROTATION);
1143 }
1144 else if (event->val == TFM_MODAL_TRACKBALL) {
1146 }
1147 else if (event->val == TFM_MODAL_ROTATE_NORMALS) {
1149 }
1150 else if (event->val == TFM_MODAL_RESIZE) {
1151 /* Scale isn't normally very useful after extrude along normals, see #39756 */
1152 if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) {
1153 stopConstraint(t);
1154 }
1155 transform_mode_init(t, nullptr, TFM_RESIZE);
1156 }
1157 else {
1158 /* First try Edge Slide. */
1160 /* If that fails, try Vertex Slide. */
1161 if (t->state == TRANS_CANCEL) {
1162 resetTransModal(t);
1163 t->state = TRANS_STARTING;
1165 }
1166 /* Vert Slide can fail on unconnected vertices (rare but possible). */
1167 if (t->state == TRANS_CANCEL) {
1168 resetTransModal(t);
1169 t->state = TRANS_STARTING;
1172 }
1173 }
1174
1175 /* Need to reinitialize after mode change. */
1177 applyMouseInput(t, &t->mouse, t->mval, t->values);
1178 t->redraw |= TREDRAW_HARD;
1179 break;
1180
1182 if (!(t->modifiers & MOD_SNAP_INVERT)) {
1185 t->redraw |= TREDRAW_HARD;
1186 }
1187 break;
1189 if (t->modifiers & MOD_SNAP_INVERT) {
1192 t->redraw |= TREDRAW_HARD;
1193 }
1194 break;
1196 t->modifiers ^= MOD_SNAP;
1199 t->redraw |= TREDRAW_HARD;
1200 break;
1201 case TFM_MODAL_AXIS_X:
1202 case TFM_MODAL_AXIS_Y:
1203 case TFM_MODAL_AXIS_Z:
1204 case TFM_MODAL_PLANE_X:
1205 case TFM_MODAL_PLANE_Y:
1206 case TFM_MODAL_PLANE_Z:
1207 if (transform_event_modal_constraint(t, event->val)) {
1208 t->redraw |= TREDRAW_HARD;
1209 }
1210 break;
1211 case TFM_MODAL_CONS_OFF:
1212 if ((t->flag & T_NO_CONSTRAINT) == 0) {
1213 stopConstraint(t);
1214 t->redraw |= TREDRAW_HARD;
1215 }
1216 break;
1217 case TFM_MODAL_ADD_SNAP:
1218 addSnapPoint(t);
1219 t->redraw |= TREDRAW_HARD;
1220 break;
1222 removeSnapPoint(t);
1223 t->redraw |= TREDRAW_HARD;
1224 break;
1225 case TFM_MODAL_PROPSIZE:
1226 /* MOUSEPAN usage... */
1227 if (t->flag & T_PROP_EDIT) {
1228 float fac = 1.0f + 0.005f * (event->xy[1] - event->prev_xy[1]);
1229 t->prop_size *= fac;
1230 if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1231 t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->clip_end),
1233 }
1234 else {
1236 }
1238 t->redraw |= TREDRAW_HARD;
1239 }
1240 break;
1242 if (t->flag & T_PROP_EDIT) {
1243 t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1244 if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1245 t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->clip_end);
1246 }
1247 else {
1249 }
1251 t->redraw |= TREDRAW_HARD;
1252 }
1253 break;
1255 if (t->flag & T_PROP_EDIT) {
1256 t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1259 t->redraw |= TREDRAW_HARD;
1260 }
1261 break;
1263 if (t->flag & T_AUTOIK) {
1265 t->redraw |= TREDRAW_HARD;
1266 }
1267 break;
1269 if (t->flag & T_AUTOIK) {
1271 t->redraw |= TREDRAW_HARD;
1272 }
1273 break;
1275 if (t->spacetype == SPACE_NODE) {
1276 SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
1277
1279
1282 }
1283 else if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_LEFT) {
1285 }
1286 else {
1287 BLI_assert(0);
1288 }
1289
1290 t->redraw |= TREDRAW_SOFT;
1291 }
1292 break;
1295 t->redraw |= TREDRAW_HARD;
1296 break;
1299 t->redraw |= TREDRAW_HARD;
1300 break;
1303 t->redraw |= TREDRAW_HARD;
1304 break;
1305
1308 if ((t->flag & T_RELEASE_CONFIRM) && (event->prev_val == KM_RELEASE) &&
1309 event->prev_type == t->launch_event)
1310 {
1311 /* Confirm transform if launch key is released after mouse move. */
1312 t->state = TRANS_CONFIRM;
1313 }
1314 else if ((t->flag & T_NO_CONSTRAINT) == 0) {
1316 /* Confirm. */
1319 t->redraw = TREDRAW_HARD;
1320 }
1321 else {
1322 if (t->options & CTX_CAMERA) {
1323 /* Exception for switching to dolly, or trackball, in camera view. */
1324 if (t->mode == TFM_TRANSLATION) {
1325 setLocalConstraint(t, (CON_AXIS2), IFACE_("along local Z"));
1326 }
1327 else if (t->mode == TFM_ROTATION) {
1330 }
1331 t->redraw = TREDRAW_HARD;
1332 }
1333 else {
1334 t->modifiers |= (event->val == TFM_MODAL_AUTOCONSTRAINT) ?
1337 if (t->con.mode & CON_APPLY) {
1338 stopConstraint(t);
1340
1341 /* In this case we might just want to remove the constraint,
1342 * so set #TREDRAW_SOFT to only select the constraint on the next mouse move event.
1343 * This way we can kind of "cancel" due to confirmation without constraint. */
1344 t->redraw = TREDRAW_SOFT;
1345 }
1346 else {
1348
1349 /* When first called, set #TREDRAW_HARD to select constraint immediately in
1350 * #selectConstraint. */
1352 }
1353 }
1354 }
1355 }
1356 break;
1358 if (is_navigating) {
1359 /* WORKAROUND: During navigation, due to key conflicts, precision may be unintentionally
1360 * enabled. */
1361 }
1362 else if (event->prev_val == KM_PRESS) {
1364 /* Mouse position during Snap to Grid is not affected by precision. */
1365 if (!(validSnap(t) && t->tsnap.target_type == SCE_SNAP_TO_GRID)) {
1366 t->mouse.precision = true;
1367 }
1368
1369 t->redraw |= TREDRAW_HARD;
1370 }
1371 else if (event->prev_val == KM_RELEASE) {
1373 t->mouse.precision = false;
1374 t->redraw |= TREDRAW_HARD;
1375 }
1376 break;
1378 if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
1380 t->redraw |= TREDRAW_HARD;
1381 }
1382 break;
1385 t->redraw |= TREDRAW_HARD;
1386 break;
1387 default:
1388 break;
1389 }
1390 }
1391 /* Else do non-mapped events. */
1392 else if (event->val == KM_PRESS) {
1393 switch (event->type) {
1394 case EVT_CKEY:
1395 if (event->flag & WM_EVENT_IS_REPEAT) {
1396 break;
1397 }
1398 if (event->modifier & KM_ALT) {
1399 if (!(t->options & CTX_NO_PET)) {
1400 t->flag ^= T_PROP_CONNECTED;
1403 t->redraw = TREDRAW_HARD;
1404 }
1405 }
1406 break;
1407 case EVT_OKEY:
1408 if (event->flag & WM_EVENT_IS_REPEAT) {
1409 break;
1410 }
1411 if ((t->flag & T_PROP_EDIT) && (event->modifier & KM_SHIFT)) {
1412 t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
1414 t->redraw |= TREDRAW_HARD;
1415 }
1416 break;
1417 case EVT_PADPLUSKEY:
1418 if ((event->modifier & KM_ALT) && (t->flag & T_PROP_EDIT)) {
1419 t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1420 if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1421 t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->clip_end);
1422 }
1424 t->redraw = TREDRAW_HARD;
1425 }
1426 break;
1427 case EVT_PADMINUS:
1428 if ((event->modifier & KM_ALT) && (t->flag & T_PROP_EDIT)) {
1429 t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1431 t->redraw = TREDRAW_HARD;
1432 }
1433 break;
1434 case EVT_LEFTALTKEY:
1435 case EVT_RIGHTALTKEY:
1437 t->flag |= T_ALT_TRANSFORM;
1438 t->redraw |= TREDRAW_HARD;
1439 }
1440 break;
1441 default:
1442 break;
1443 }
1444 }
1445 else if (event->val == KM_RELEASE) {
1446 switch (event->type) {
1447 case EVT_LEFTALTKEY:
1448 case EVT_RIGHTALTKEY:
1449 /* TODO: Modal Map */
1451 t->flag &= ~T_ALT_TRANSFORM;
1452 t->redraw |= TREDRAW_HARD;
1453 }
1454 break;
1455 default: {
1456 break;
1457 }
1458 }
1459
1460 /* Confirm transform if launch key is released after mouse move. */
1461 if ((t->flag & T_RELEASE_CONFIRM) && event->type == t->launch_event) {
1462 t->state = TRANS_CONFIRM;
1463 }
1464 }
1465
1466 /* Per transform event, if present. */
1467 if (t->mode_info && t->mode_info->handle_event_fn) {
1468 t->redraw |= t->mode_info->handle_event_fn(t, event);
1469 }
1470
1471 /* Try to init modal numinput now, if possible. */
1472 if (!t->redraw && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
1473 handleNumInput(t->context, &(t->num), event))
1474 {
1475 t->redraw |= TREDRAW_HARD;
1476 }
1477
1478 if (t->redraw && !ISMOUSE_MOTION(event->type)) {
1479 /* The status area is currently also tagged to update by the notifiers in
1480 * `viewRedrawForce`. However, this may change in the future, and tagging
1481 * the region twice doesn't add any overhead. */
1483
1485 ED_workspace_status_text(t->context, nullptr);
1486 }
1487 }
1488
1489 if (!is_navigating && t->redraw) {
1490 return wmOperatorStatus(0);
1491 }
1492 return OPERATOR_PASS_THROUGH;
1493}
1494
1495bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], float cent2d[2])
1496{
1497 TransInfo *t = MEM_callocN<TransInfo>("TransInfo data");
1498 bool success;
1499
1500 t->context = C;
1501
1502 t->state = TRANS_RUNNING;
1503
1504 /* Avoid calculating proportional editing. */
1505 t->options = CTX_NO_PET;
1506
1507 t->mode = TFM_DUMMY;
1508
1509 initTransInfo(C, t, nullptr, nullptr);
1510
1511 /* Avoid doing connectivity lookups (when V3D_AROUND_LOCAL_ORIGINS is set). */
1513
1514 create_trans_data(C, t); /* Make TransData structs from selection. */
1515
1516 t->around = centerMode; /* Override user-defined mode. */
1517
1518 if (t->data_len_all == 0) {
1519 success = false;
1520 }
1521 else {
1522 success = true;
1523
1524 calculateCenter(t);
1525
1526 if (cent2d) {
1527 copy_v2_v2(cent2d, t->center2d);
1528 }
1529
1530 if (cent3d) {
1531 /* Copy center from constraint center. Transform center can be local. */
1532 copy_v3_v3(cent3d, t->center_global);
1533 }
1534 }
1535
1536 /* Does insert keyframes, and clears base flags; doesn't read `transdata`. */
1538
1539 postTrans(C, t);
1540
1541 MEM_freeN(t);
1542
1543 return success;
1544}
1545
1547{
1548 /* Don't show overlays when not the active view and when overlay is disabled: #57139 */
1549 if (region != t->region) {
1550 return false;
1551 }
1552
1553 switch (t->spacetype) {
1554 case SPACE_VIEW3D: {
1555 const View3D *v3d = static_cast<const View3D *>(t->view);
1556 return (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
1557 }
1558 case SPACE_IMAGE: {
1559 const SpaceImage *sima = static_cast<const SpaceImage *>(t->area->spacedata.first);
1560 return (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) != 0;
1561 }
1562 case SPACE_SEQ: {
1563 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(t->area->spacedata.first);
1564 return (sseq->flag & SEQ_SHOW_OVERLAY) != 0;
1565 }
1566 case SPACE_ACTION: {
1567 const SpaceAction *sact = static_cast<const SpaceAction *>(t->area->spacedata.first);
1568 return (sact->overlays.flag & ADS_OVERLAY_SHOW_OVERLAYS) != 0;
1569 }
1570
1571 case SPACE_GRAPH: {
1572 /* There is no overlay flag defined yet for the Graph Editor. But there is the proportional
1573 * editing drawing that will not happen if we return false here. */
1574 return true;
1575 }
1576 }
1577 return false;
1578}
1579
1580static void drawTransformView(const bContext * /*C*/, ARegion *region, void *arg)
1581{
1582 TransInfo *t = static_cast<TransInfo *>(arg);
1583
1584 if (!transinfo_show_overlay(t, region)) {
1585 return;
1586 }
1587
1588 GPU_line_width(1.0f);
1589
1590 drawConstraint(t);
1591
1592 switch (t->spacetype) {
1593 case SPACE_GRAPH:
1594 case SPACE_ACTION:
1595 /* Different visualization because the proportional editing in these editors only looks at
1596 * the x-axis. */
1597 drawPropRange(t);
1598 break;
1599
1600 default:
1601 drawPropCircle(t);
1602 break;
1603 }
1604
1605 drawSnapping(t);
1606
1607 if (region == t->region && t->mode_info && t->mode_info->draw_fn) {
1608 t->mode_info->draw_fn(t);
1609 }
1610}
1611
1616static void drawAutoKeyWarning(TransInfo *t, ARegion *region)
1617{
1618 const char *printable = IFACE_("Auto Keying On");
1619 float printable_size[2];
1620 int xco, yco;
1621 int offset = 0;
1622
1623 const rcti *rect = ED_region_visible_rect(region);
1624
1625 View3D *v3d = nullptr;
1626 Scene *scene = nullptr;
1627 if (t->spacetype == SPACE_VIEW3D) {
1628 v3d = static_cast<View3D *>(t->view);
1629 scene = t->scene;
1630 }
1631
1632 const int font_id = BLF_set_default();
1634 font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
1635
1636 /* Check to see if the Navigation Gizmo is enabled. */
1637 if ((t->spacetype != SPACE_VIEW3D) || (v3d == nullptr) ||
1639 {
1640 offset = 10;
1641 }
1642 else {
1643 /* Depending on user MINI_AXIS preference, pad accordingly. */
1644 switch ((eUserpref_MiniAxisType)U.mini_axis_type) {
1646 offset = U.gizmo_size_navigate_v3d;
1647 break;
1649 offset = U.rvisize * std::min((U.pixelsize / U.scale_factor), 1.0f) * 2.5f;
1650 break;
1652 offset = U.rvisize;
1653 break;
1654 }
1655 }
1656
1657 offset *= U.scale_factor;
1658
1659 xco = (rect->xmax - U.widget_unit) - int(printable_size[0]) - offset;
1660 yco = (rect->ymax - U.widget_unit);
1661
1662 /* Warning text (to clarify meaning of overlays)
1663 * - Original color was red to match the icon, but that clashes badly with a less nasty border.
1664 */
1665
1666 float text_color[4], shadow_color[4];
1667 if (v3d && scene) {
1668 ED_view3d_text_colors_get(scene, v3d, text_color, shadow_color);
1669 }
1670 else {
1671 UI_GetThemeColor4fv(TH_TEXT_HI, text_color);
1672 UI_GetThemeColor4fv(TH_BACK, text_color);
1673 }
1674 BLF_color4fv(BLF_default(), text_color);
1676 BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1677
1678 /* Auto-key recording icon. */
1680
1681 xco -= U.widget_unit;
1682 yco -= int(printable_size[1]) / 2;
1683
1684 UI_icon_draw(xco, yco, ICON_REC);
1685
1687}
1688
1689static void drawTransformPixel(const bContext * /*C*/, ARegion *region, void *arg)
1690{
1691 TransInfo *t = static_cast<TransInfo *>(arg);
1692
1693 if (!transinfo_show_overlay(t, region)) {
1694 return;
1695 }
1696
1697 if (region != t->region) {
1698 return;
1699 }
1700
1701 /* Draw auto-key-framing hint in the corner
1702 * - only draw if enabled (advanced users may be distracted/annoyed),
1703 * for objects that will be auto-keyframed (no point otherwise),
1704 * AND only for the active region (as showing all is too overwhelming)
1705 */
1706 if ((U.keying_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
1707 if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
1708 Scene *scene = t->scene;
1709 ViewLayer *view_layer = t->view_layer;
1710 BKE_view_layer_synced_ensure(scene, view_layer);
1711 Object *ob = BKE_view_layer_active_object_get(view_layer);
1712
1713 if (ob && animrig::autokeyframe_cfra_can_key(scene, &ob->id)) {
1714 drawAutoKeyWarning(t, region);
1715 }
1716 }
1717 }
1718}
1719
1721{
1723 PropertyRNA *prop;
1724
1725 bool use_prop_edit = false;
1726 int prop_edit_flag = 0;
1727
1728 /* Save proportional edit settings.
1729 * Skip saving proportional edit if it was not actually used.
1730 * Note that this value is being saved even if the operation is canceled. This is to maintain a
1731 * behavior already used by users. */
1732 if (!(t->options & CTX_NO_PET)) {
1733 if (t->flag & T_PROP_EDIT_ALL) {
1734 if (t->flag & T_PROP_EDIT) {
1735 use_prop_edit = true;
1736 }
1737 if (t->flag & T_PROP_CONNECTED) {
1738 prop_edit_flag |= PROP_EDIT_CONNECTED;
1739 }
1740 if (t->flag & T_PROP_PROJECTED) {
1741 prop_edit_flag |= PROP_EDIT_PROJECTED;
1742 }
1743 }
1744
1745 /* If modal, save settings back in scene if not set as operator argument. */
1746 if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
1747 /* Save settings if not set in operator. */
1748 if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) &&
1749 !RNA_property_is_set(op->ptr, prop))
1750 {
1753 const eObjectMode object_mode = eObjectMode(obact ? obact->mode : OB_MODE_OBJECT);
1754
1755 if (t->spacetype == SPACE_GRAPH) {
1756 ts->proportional_fcurve = use_prop_edit;
1757 }
1758 else if (t->spacetype == SPACE_ACTION) {
1759 ts->proportional_action = use_prop_edit;
1760 }
1761 else if (t->options & CTX_MASK) {
1762 ts->proportional_mask = use_prop_edit;
1763 }
1764 else if (object_mode == OB_MODE_OBJECT) {
1765 /* No active object means #TransConvertType_Object [see #convert_type_get()], so use
1766 * toolsetting for *object*. */
1767 ts->proportional_objects = use_prop_edit;
1768 }
1769 else {
1770 if (use_prop_edit) {
1772 }
1773 else {
1775 }
1776 }
1777 }
1778
1779 if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) {
1780 ts->proportional_size = RNA_property_is_set(op->ptr, prop) ?
1781 RNA_property_float_get(op->ptr, prop) :
1782 t->prop_size;
1783 }
1784
1785 if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
1786 !RNA_property_is_set(op->ptr, prop))
1787 {
1788 ts->prop_mode = t->prop_mode;
1789 }
1790 }
1791 }
1792
1793 if (t->state == TRANS_CANCEL) {
1794 /* No need to edit operator properties or tool settings if we are canceling the operation.
1795 * These properties must match the original ones. */
1796 return;
1797 }
1798
1799 if (!(t->options & CTX_NO_PET)) {
1800 if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
1801 RNA_property_boolean_set(op->ptr, prop, use_prop_edit);
1802 RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED);
1803 RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED);
1804 RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
1805 RNA_float_set(op->ptr, "proportional_size", t->prop_size);
1806 }
1807 }
1808
1809 /* Save back mode in case we're in the generic operator. */
1810 if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
1811 RNA_property_enum_set(op->ptr, prop, t->mode);
1812 }
1813
1814 if ((prop = RNA_struct_find_property(op->ptr, "value"))) {
1815 if (RNA_property_array_check(prop)) {
1817 }
1818 else {
1819 RNA_property_float_set(op->ptr, prop, t->values_final[0]);
1820 }
1821 }
1822
1823 /* Save snapping settings. */
1824 if ((prop = RNA_struct_find_property(op->ptr, "snap"))) {
1825
1826 /* Update the snap toggle in `ToolSettings`. */
1827 if (
1828 /* Update only if snapping has changed during a modal operation. */
1829 (t->flag & T_MODAL) &&
1830 /* Skip updating if the snapping mode does not match the snap types. */
1832 /* Skip updating the snap toggle if it was not explicitly set by the user. */
1833 !(t->modifiers & MOD_SNAP_FORCED) &&
1834 /* Skip updating the snap toggle if snapping was enabled via operator properties. */
1835 !RNA_property_is_set(op->ptr, prop))
1836 {
1838 }
1839
1840 bool is_snap_enabled = (t->modifiers & MOD_SNAP) != 0;
1841 RNA_property_boolean_set(op->ptr, prop, is_snap_enabled);
1842
1843 if ((prop = RNA_struct_find_property(op->ptr, "snap_elements"))) {
1844 RNA_property_enum_set(op->ptr, prop, t->tsnap.mode);
1846 op->ptr, "use_snap_project", (t->tsnap.mode & SCE_SNAP_INDIVIDUAL_PROJECT) != 0);
1847 RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_operation);
1848
1850 RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0);
1851 RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0);
1852 RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0);
1854 op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0);
1855 }
1856 }
1857
1858 if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
1859 RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
1860 }
1861
1862 if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
1863 if (t->flag & T_MODAL) {
1864 if (t->con.mode & CON_APPLY) {
1865 int orient_axis = constraintModeToIndex(t);
1866 if (orient_axis != -1) {
1867 RNA_property_enum_set(op->ptr, prop, orient_axis);
1868 t->con.mode &= ~CON_APPLY;
1869 }
1870 }
1871 else {
1872 RNA_property_enum_set(op->ptr, prop, t->orient_axis);
1873 }
1874 }
1875 }
1876 if ((prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
1877 if (t->flag & T_MODAL) {
1879 }
1880 }
1881
1882 if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
1883 short orient_type_set, orient_type_curr;
1884 orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) :
1885 -1;
1886 orient_type_curr = t->orient[t->orient_curr].type;
1887
1888 if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) {
1889 RNA_property_enum_set(op->ptr, prop, orient_type_curr);
1890 orient_type_set = orient_type_curr;
1891 }
1892
1893 if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
1894 !RNA_property_is_set(op->ptr, prop))
1895 {
1896 /* Set the first time to register on redo. */
1897 RNA_property_enum_set(op->ptr, prop, orient_type_set);
1898 RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
1899 }
1900 }
1901
1902 if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
1903 bool constraint_axis[3] = {false, false, false};
1904 if (t->con.mode & CON_APPLY) {
1905 if (t->con.mode & CON_AXIS0) {
1906 constraint_axis[0] = true;
1907 }
1908 if (t->con.mode & CON_AXIS1) {
1909 constraint_axis[1] = true;
1910 }
1911 if (t->con.mode & CON_AXIS2) {
1912 constraint_axis[2] = true;
1913 }
1914 RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
1915 }
1916 else {
1917 RNA_property_unset(op->ptr, prop);
1918 }
1919 }
1920
1921 {
1922 const char *prop_id = nullptr;
1923 bool prop_state = true;
1924 if (t->mode == TFM_SHRINKFATTEN) {
1925 prop_id = "use_even_offset";
1926 prop_state = false;
1927 }
1928
1929 if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
1930 RNA_property_boolean_set(op->ptr, prop, ((t->flag & T_ALT_TRANSFORM) == 0) == prop_state);
1931 }
1932 }
1933
1934 if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
1936 op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0);
1937 }
1938}
1939
1940bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
1941{
1942 int options = 0;
1943 PropertyRNA *prop;
1944
1945 mode = transform_mode_really_used(C, eTfmMode(mode));
1946
1947 t->context = C;
1948
1949 /* Added initialize, for external calls to set stuff in TransInfo, like undo string. */
1950
1951 t->state = TRANS_STARTING;
1952
1953 if ((prop = RNA_struct_find_property(op->ptr, "cursor_transform")) &&
1954 RNA_property_is_set(op->ptr, prop))
1955 {
1956 if (RNA_property_boolean_get(op->ptr, prop)) {
1958 }
1959 }
1960
1961 if ((prop = RNA_struct_find_property(op->ptr, "texture_space")) &&
1962 RNA_property_is_set(op->ptr, prop))
1963 {
1964 if (RNA_property_boolean_get(op->ptr, prop)) {
1966 }
1967 }
1968
1969 if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) &&
1970 RNA_property_is_set(op->ptr, prop))
1971 {
1972 if (RNA_property_boolean_get(op->ptr, prop)) {
1974 }
1975 }
1976
1977 if ((prop = RNA_struct_find_property(op->ptr, "view2d_edge_pan")) &&
1978 RNA_property_is_set(op->ptr, prop))
1979 {
1980 if (RNA_property_boolean_get(op->ptr, prop)) {
1982 }
1983 }
1984
1986
1987 t->mode = eTfmMode(mode);
1988
1989 /* Needed to translate tweak events to mouse buttons. */
1991 t->is_launch_event_drag = event ? (event->val == KM_PRESS_DRAG) : false;
1992
1993 unit_m3(t->spacemtx);
1994
1995 initTransInfo(C, t, op, event);
1996
1997 if (!G.background) {
1998 if (t->spacetype == SPACE_VIEW3D) {
2005 }
2006 else if (ELEM(t->spacetype,
2008 SPACE_CLIP,
2009 SPACE_NODE,
2012 SPACE_SEQ))
2013 {
2018 }
2019 }
2020
2021 create_trans_data(C, t); /* Make #TransData structs from selection. */
2022
2023 if (t->data_len_all == 0) {
2024 postTrans(C, t);
2025 return false;
2026 }
2027
2028 /* When proportional editing is enabled, data_len_all can be non zero when
2029 * nothing is selected, if this is the case we can end the transform early.
2030 *
2031 * By definition transform-data has selected items in beginning,
2032 * so only the first item in each container needs to be checked
2033 * when looking for the presence of selected data. */
2034 if (t->flag & T_PROP_EDIT) {
2035 bool has_selected_any = false;
2037 if (tc->data_len == 0) {
2038 continue;
2039 }
2040
2041 if (!tc->sorted_index_map) {
2042 BLI_assert_msg(tc->data[0].flag & TD_SELECTED,
2043 "Without sorted_index_map, all items are expected to be selected");
2044 has_selected_any = true;
2045 break;
2046 }
2047
2048 const int first_selected_index = tc->sorted_index_map[0];
2049 TransData *td = &tc->data[first_selected_index];
2050 if (td->flag & TD_SELECTED) {
2051 has_selected_any = true;
2052 break;
2053 }
2054 }
2055
2056 if (!has_selected_any) {
2057 postTrans(C, t);
2058 return false;
2059 }
2060 }
2061
2062 if (event) {
2063 /* Keymap for shortcut header prints. */
2065
2066 /* Stupid code to have Ctrl-Click on gizmo work ok.
2067 *
2068 * Do this only for translation/rotation/resize because only these
2069 * modes are available from gizmo and doing such check could
2070 * lead to keymap conflicts for other modes (see #31584)
2071 */
2073 LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &t->keymap->items) {
2074 if (kmi->flag & KMI_INACTIVE) {
2075 continue;
2076 }
2077
2078 if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
2079 if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) &&
2080 (event->modifier & KM_CTRL)) ||
2081 (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) &&
2082 (event->modifier & KM_SHIFT)) ||
2083 (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && (event->modifier & KM_ALT)) ||
2084 ((kmi->type == EVT_OSKEY) && (event->modifier & KM_OSKEY)))
2085 {
2087 }
2088 break;
2089 }
2090 }
2091 }
2092 if (t->data_type == &TransConvertType_Node) {
2093 /* Set the initial auto-attach flag based on whether the chosen keymap key is pressed at the
2094 * start of the operator. */
2096 LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &t->keymap->items) {
2097 if (kmi->flag & KMI_INACTIVE) {
2098 continue;
2099 }
2100
2101 if (kmi->propvalue == TFM_MODAL_NODE_ATTACH_OFF && kmi->val == KM_PRESS) {
2102 if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) &&
2103 (event->modifier & KM_CTRL)) ||
2104 (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) &&
2105 (event->modifier & KM_SHIFT)) ||
2106 (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && (event->modifier & KM_ALT)) ||
2107 ((kmi->type == EVT_OSKEY) && (event->modifier & KM_OSKEY)) ||
2108 ((kmi->type == EVT_HYPER) && (event->modifier & KM_HYPER)))
2109 {
2111 }
2112 break;
2113 }
2114 }
2115 }
2116 }
2117
2118 initSnapping(t, op); /* Initialize snapping data AFTER mode flags. */
2119
2120 /* EVIL! pose-mode code can switch translation to rotate when 1 bone is selected.
2121 * will be removed (ton). */
2122
2123 /* EVIL2: we gave as argument also texture space context bit... was cleared. */
2124
2125 /* EVIL3: extend mode for animation editors also switches modes...
2126 * but is best way to avoid duplicate code. */
2127 mode = t->mode;
2128
2130 calculateCenter(t);
2131
2132 if (event) {
2133 /* Initialize accurate transform to settings requested by keymap. */
2134 bool use_accurate = false;
2135 if ((prop = RNA_struct_find_property(op->ptr, "use_accurate")) &&
2136 RNA_property_is_set(op->ptr, prop))
2137 {
2138 if (RNA_property_boolean_get(op->ptr, prop)) {
2139 use_accurate = true;
2140 }
2141 }
2142
2143 initMouseInput(t, &t->mouse, t->center2d, t->mval, use_accurate);
2144 }
2145
2146 transform_mode_init(t, op, mode);
2147
2148 if (t->state == TRANS_CANCEL) {
2149 postTrans(C, t);
2150 return false;
2151 }
2152
2153 /* Transformation axis from operator. */
2154 if ((prop = RNA_struct_find_property(op->ptr, "orient_axis")) &&
2155 RNA_property_is_set(op->ptr, prop))
2156 {
2157 t->orient_axis = RNA_property_enum_get(op->ptr, prop);
2158 }
2159 if ((prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho")) &&
2160 RNA_property_is_set(op->ptr, prop))
2161 {
2163 }
2164
2165 /* Constraint init from operator. */
2166 if (t->con.mode & CON_APPLY) {
2167 setUserConstraint(t, t->con.mode, "%s");
2168 }
2169
2170 /* Don't write into the values when non-modal because they are already set from operator redo
2171 * values. */
2172 if (t->flag & T_MODAL) {
2173 /* Setup the mouse input with initial values. */
2174 applyMouseInput(t, &t->mouse, t->mouse.imval, t->values);
2175 }
2176
2177 if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) {
2178 if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
2179
2181 BMEditMesh *em = nullptr; /* BKE_editmesh_from_object(t->obedit); */
2182 bool do_skip = false;
2183
2184 /* Currently only used for two of three most frequent transform ops,
2185 * can include more ops.
2186 * Note that scaling cannot be included here,
2187 * non-uniform scaling will affect normals. */
2189 if (em->bm->totvertsel == em->bm->totvert) {
2190 /* No need to invalidate if whole mesh is selected. */
2191 do_skip = true;
2192 }
2193 }
2194
2195 if (t->flag & T_MODAL) {
2196 RNA_property_boolean_set(op->ptr, prop, false);
2197 }
2198 else if (!do_skip) {
2199 const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
2200 if (preserve_clnor) {
2202 t->flag |= T_CLNOR_REBUILD;
2203 }
2204 BM_lnorspace_invalidate(em->bm, true);
2205 }
2206 }
2207 }
2208 }
2209
2210 t->context = nullptr;
2211
2212 return true;
2213}
2214
2216{
2217 t->context = C;
2218
2219 if (t->redraw == TREDRAW_HARD) {
2221 if (t->mode_info) {
2222 t->mode_info->transform_fn(t); /* Calls #recalc_data(). */
2223 }
2224 }
2225
2226 if (t->redraw & TREDRAW_SOFT) {
2227 viewRedrawForce(C, t);
2228 }
2229
2231
2232 /* If auto confirm is on, break after one pass. */
2233 if (t->options & CTX_AUTOCONFIRM) {
2234 t->state = TRANS_CONFIRM;
2235 }
2236
2237 t->context = nullptr;
2238}
2239
2241{
2243
2244 t->context = C;
2245
2247 /* Handle restoring objects. */
2248 if (t->state == TRANS_CANCEL) {
2249 exit_code = OPERATOR_CANCELLED;
2250 restoreTransObjects(t); /* Calls #recalc_data(). */
2251 }
2252 else {
2253 if (t->flag & T_CLNOR_REBUILD) {
2255 BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
2256 BM_lnorspace_rebuild(em->bm, true);
2257 }
2258 }
2259 exit_code = OPERATOR_FINISHED;
2260 }
2261
2262 /* Does insert keyframes, and clears base flags; doesn't read `transdata`. */
2264
2265 /* Free data, also handles overlap [in freeTransCustomData()]. */
2266 postTrans(C, t);
2267
2268 /* Send events out for redraws. */
2269 viewRedrawPost(C, t);
2270
2271 viewRedrawForce(C, t);
2272
2274 }
2275
2276 t->context = nullptr;
2277
2278 return exit_code;
2279}
2280
2282{
2283 /* Currently only checks for editmode. */
2284 if (t->flag & T_EDIT) {
2285 if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
2287 {
2288 /* Not all editmode supports axis-matrix. */
2289 return true;
2290 }
2291 }
2292
2293 return false;
2294}
2295
2296bool transform_apply_matrix(TransInfo *t, float mat[4][4])
2297{
2298 if (t->mode_info && t->mode_info->transform_matrix_fn) {
2299 t->mode_info->transform_matrix_fn(t, mat);
2300 return true;
2301 }
2302 return false;
2303}
2304
2305void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
2306{
2307 memcpy(value, t->values_final, sizeof(float) * value_num);
2308}
2309
2310void view_vector_calc(const TransInfo *t, const float focus[3], float r_vec[3])
2311{
2312 if (t->persp != RV3D_ORTHO) {
2313 sub_v3_v3v3(r_vec, t->viewinv[3], focus);
2314 }
2315 else {
2316 copy_v3_v3(r_vec, t->viewinv[2]);
2317 }
2318 normalize_v3(r_vec);
2319}
2320
2321} // namespace blender::ed::transform
Functions to insert, delete or modify keyframes.
WorkSpace * CTX_wm_workspace(const bContext *C)
Mask * CTX_data_edit_mask(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
Definition editmesh.cc:220
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
void BKE_mask_coord_to_image(struct Image *image, struct ImageUser *iuser, float r_co[2], const float co[2])
void BKE_mask_coord_to_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2])
void BKE_workspace_status_clear(WorkSpace *workspace)
Definition workspace.cc:650
int BLF_set_default()
void BLF_shadow(int fontid, FontShadowType type, const float rgba[4]=nullptr)
Definition blf.cc:934
void BLF_width_and_height(int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL()
Definition blf.cc:789
void BLF_color4fv(int fontid, const float rgba[4])
Definition blf.cc:505
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:440
int BLF_default()
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL()
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
void unit_m3(float m[3][3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void unit_m4(float m[4][4])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v3(float n[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:185
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define ARRAY_SIZE(arr)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define IFACE_(msgid)
@ ADS_OVERLAY_SHOW_OVERLAYS
@ SACTION_DRAWTIME
eObjectMode
@ OB_MODE_OBJECT
@ OB_MBALL
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES_LEGACY
@ OB_CURVES
@ PROP_EDIT_PROJECTED
@ PROP_EDIT_USE
@ PROP_EDIT_CONNECTED
@ UVCALC_TRANSFORM_CORRECT_SLIDE
@ UVCALC_TRANSFORM_CORRECT
@ PROP_MODE_MAX
@ SCE_SNAP
eSnapTargetOP
@ SCE_SNAP_TARGET_NOT_ACTIVE
@ SCE_SNAP_TARGET_NOT_NONEDITED
@ SCE_SNAP_TARGET_ONLY_SELECTABLE
@ SCE_SNAP_TARGET_NOT_EDITED
@ SCE_SNAP_INDIVIDUAL_PROJECT
@ SCE_SNAP_TO_GRID
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SI_COORDFLOATS
@ SI_OVERLAY_SHOW_OVERLAYS
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_NODE
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SNODE_INSERTOFS_DIR_RIGHT
@ SNODE_INSERTOFS_DIR_LEFT
@ SEQ_SHOW_OVERLAY
#define SPACE_TYPE_ANY
@ AUTOKEY_FLAG_NOWARNING
eUserpref_MiniAxisType
@ USER_MINI_AXIS_TYPE_GIZMO
@ USER_MINI_AXIS_TYPE_MINIMAL
@ USER_MINI_AXIS_TYPE_NONE
@ V3D_HIDE_OVERLAYS
@ V3D_GIZMO_HIDE
@ V3D_GIZMO_HIDE_NAVIGATE
@ RV3D_NAVIGATING
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_LOCAL_ORIGINS
@ V3D_ORIENT_NORMAL
@ V3D_ORIENT_CUSTOM_MATRIX
@ RV3D_CAMOB
@ RV3D_ORTHO
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
MovieClip * ED_space_clip_get_clip(const SpaceClip *sc)
bool ED_space_clip_check_show_trackedit(const SpaceClip *sc)
bool ED_space_clip_check_show_maskedit(const SpaceClip *sc)
void ED_space_clip_get_aspect(const SpaceClip *sc, float *r_aspx, float *r_aspy)
void ED_clip_point_stable_pos__reverse(const SpaceClip *sc, const ARegion *region, const float co[2], float r_co[2])
the reverse of ED_clip_point_stable_pos(), gets the marker region coords. better name here?...
void ED_space_clip_get_aspect_dimension_aware(const SpaceClip *sc, float *r_aspx, float *r_aspy)
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
void ED_space_image_get_uv_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
void ED_image_point_pos__reverse(SpaceImage *sima, const ARegion *region, const float co[2], float r_co[2])
#define NUM_MODAL_INCREMENT_DOWN
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:312
#define NUM_MODAL_INCREMENT_UP
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
const rcti * ED_region_visible_rect(ARegion *region)
Definition area.cc:4301
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
#define REGION_DRAW_POST_PIXEL
bool ED_uvedit_live_unwrap_timer_check(const wmTimer *timer)
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
eV3DProjTest
Definition ED_view3d.hh:278
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
void ED_view3d_calc_camera_border(const Scene *scene, const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const RegionView3D *rv3d, bool no_shift, rctf *r_viewborder)
void ED_view3d_text_colors_get(const Scene *scene, const View3D *v3d, float r_text_color[4], float r_shadow_color[4])
eV3DProjStatus ED_view3d_project_int_global(const ARegion *region, const float co[3], int r_co[2], eV3DProjTest flag)
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void GPU_line_width(float width)
Definition gpu_state.cc:166
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
#define C
Definition RandGen.cpp:29
void UI_icon_draw(float x, float y, int icon_id)
@ TH_BACK
@ TH_TEXT_HI
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_view2d_view_to_region(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1723
#define ND_SEQUENCER
Definition WM_types.hh:437
#define NC_GEOM
Definition WM_types.hh:393
@ KM_CTRL
Definition WM_types.hh:279
@ KM_ALT
Definition WM_types.hh:280
@ KM_HYPER
Definition WM_types.hh:292
@ KM_OSKEY
Definition WM_types.hh:282
@ KM_SHIFT
Definition WM_types.hh:278
@ WM_EVENT_IS_REPEAT
Definition WM_types.hh:684
#define ND_DATA
Definition WM_types.hh:509
@ KM_PRESS
Definition WM_types.hh:311
@ KM_PRESS_DRAG
Definition WM_types.hh:319
@ KM_RELEASE
Definition WM_types.hh:312
#define NC_ANIMATION
Definition WM_types.hh:388
#define NC_MOVIECLIP
Definition WM_types.hh:397
#define NC_SCENE
Definition WM_types.hh:378
#define ND_SPACE_NODE_VIEW
Definition WM_types.hh:536
#define ND_POSE
Definition WM_types.hh:458
#define NA_EDITED
Definition WM_types.hh:584
#define ND_NLA
Definition WM_types.hh:497
#define ND_TRANSFORM
Definition WM_types.hh:456
#define NC_MASK
Definition WM_types.hh:398
#define ND_KEYS
Definition WM_types.hh:463
#define ND_KEYFRAME
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:379
#define NC_SPACE
Definition WM_types.hh:392
#define U
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
ATTR_WARN_UNUSED_RESULT const BMVert * v
nullptr float
CCL_NAMESPACE_BEGIN struct Options options
#define out
#define printf(...)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define G(x, y, z)
bool is_autokey_on(const Scene *scene)
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
static void viewRedrawPost(bContext *C, TransInfo *t)
void calculateCenter(TransInfo *t)
void transformApply(bContext *C, TransInfo *t)
TransConvertTypeInfo TransConvertType_Mesh
void setTransformViewMatrices(TransInfo *t)
void resetTransRestrictions(TransInfo *t)
wmKeyMap * transform_modal_keymap(wmKeyConfig *keyconf)
void transform_snap_reset_from_mode(TransInfo *t, wmOperator *op)
void special_aftertrans_update(bContext *C, TransInfo *t)
void postSelectConstraint(TransInfo *t)
void transform_snap_flag_from_modifiers_set(TransInfo *t)
TransConvertTypeInfo TransConvertType_Node
bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], float cent2d[2])
bool transform_mode_is_changeable(const int mode)
void setUserConstraint(TransInfo *t, int mode, const char text_[])
static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
void removeSnapPoint(TransInfo *t)
bool transformModeUseSnap(const TransInfo *t)
void initSnapping(TransInfo *t, wmOperator *op)
bool validSnap(const TransInfo *t)
void setLocalConstraint(TransInfo *t, int mode, const char text[])
static bool transform_modal_item_poll(const wmOperator *op, int value)
void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
static void drawTransformPixel(const bContext *, ARegion *region, void *arg)
void view_vector_calc(const TransInfo *t, const float focus[3], float r_vec[3])
void initMouseInput(TransInfo *t, MouseInput *mi, const float2 &center, const float2 &mval, bool precision)
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
void restoreTransObjects(TransInfo *t)
eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
void resetTransModal(TransInfo *t)
eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode)
void transform_view_vector_calc(const TransInfo *t, const float focus[3], float r_vec[3])
void transform_draw_cursor_draw(bContext *C, const blender::int2 &xy, const blender::float2 &, void *customdata)
static bool transinfo_show_overlay(TransInfo *t, ARegion *region)
void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
static void drawAutoKeyWarning(TransInfo *t, ARegion *region)
static void viewRedrawForce(const bContext *C, TransInfo *t)
void addSnapPoint(TransInfo *t)
void applyMouseInput(TransInfo *t, MouseInput *mi, const float2 &mval, float output[3])
void transform_autoik_update(TransInfo *t, short mode)
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t)
static void drawTransformView(const bContext *, ARegion *region, void *arg)
void projectIntView(TransInfo *t, const float vec[3], int adr[2])
void transform_mode_snap_source_init(TransInfo *t, wmOperator *op)
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
void projectFloatViewCenterFallback(TransInfo *t, float adr[2])
void drawSnapping(TransInfo *t)
wmOperatorStatus transformEvent(TransInfo *t, wmOperator *op, const wmEvent *event)
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
void sort_trans_data_dist(TransInfo *t)
bool transform_draw_cursor_poll(bContext *C)
static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
void removeAspectRatio(TransInfo *t, float vec[2])
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
void initSelectConstraint(TransInfo *t)
short * transform_snap_flag_from_spacetype_ptr(TransInfo *t, const PropertyRNA **r_prop=nullptr)
void selectConstraint(TransInfo *t)
void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
wmOperatorStatus transformEnd(bContext *C, TransInfo *t)
void calculatePropRatio(TransInfo *t)
static void tool_settings_update_snap_toggle(TransInfo *t)
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
void postTrans(bContext *C, TransInfo *t)
TransConvertTypeInfo TransConvertType_MeshUV
TransConvertTypeInfo TransConvertType_Tracking
void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
bool transform_apply_matrix(TransInfo *t, float mat[4][4])
void applyAspectRatio(TransInfo *t, float vec[2])
void drawConstraint(TransInfo *t)
int constraintModeToIndex(const TransInfo *t)
void drawPropCircle(TransInfo *t)
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t)
void create_trans_data(bContext *C, TransInfo *t)
bool transdata_check_local_islands(TransInfo *t, short around)
void transform_orientations_current_set(TransInfo *t, const short orient_index)
float2 image_preview_unit_to_px(const Scene *scene, const float2 co_src)
VecBase< float, 2 > float2
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
void * regiondata
ARegionRuntimeHandle * runtime
int totvert
int totvertsel
void * first
float persmat[4][4]
float persinv[4][4]
float viewmat[4][4]
float viewinv[4][4]
ListBase spacedata
SpaceActionOverlays overlays
struct MovieClipUser user
struct MovieClip * clip
SpaceImageOverlay overlay
struct ImageUser iuser
struct Image * image
struct Object * camera
TransConvertTypeInfo * data_type
Definition transform.hh:810
struct blender::ed::transform::TransInfo::@342160341045112220003361360177273117120157367076 orient[3]
enum eRedrawFlag(* handle_event_fn)(TransInfo *, const wmEvent *)
void(* transform_matrix_fn)(TransInfo *, float[4][4])
int ymax
int xmax
wmEventType prev_type
Definition WM_types.hh:812
wmEventModifierFlag modifier
Definition WM_types.hh:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
eWM_EventFlag flag
Definition WM_types.hh:788
short prev_val
Definition WM_types.hh:814
void * customdata
Definition WM_types.hh:807
bool(* poll_modal_item)(const struct wmOperator *op, int value)
const PropertyRNA * prop
wmKeyMap * modalkeymap
Definition WM_types.hh:1145
struct wmOperatorType * type
struct PointerRNA * ptr
#define T_PROP_SIZE_MIN
Definition transform.hh:31
#define T_PROP_EDIT_ALL
Definition transform.hh:28
#define T_PROP_SIZE_MAX
Definition transform.hh:32
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:42
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *)
Definition wm_draw.cc:1606
int WM_userdef_event_type_from_keymap_type(int kmitype)
void WM_window_status_area_tag_redraw(wmWindow *win)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
#define ISMOUSE_MOTION(event_type)
@ EVT_OKEY
@ TIMER
@ EVT_MODAL_MAP
@ EVT_RIGHTCTRLKEY
@ EVT_CKEY
@ EVT_OSKEY
@ EVT_LEFTCTRLKEY
@ MOUSEMOVE
@ EVT_RIGHTALTKEY
@ EVT_PADMINUS
@ EVT_LEFTALTKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
@ EVT_PADPLUSKEY
@ EVT_HYPER
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:932
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
void WM_msg_publish_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
uint8_t flag
Definition wm_window.cc:145