Merge branch 'blender2.8' into soc-2018-bevel
[blender.git] / source / blender / editors / transform / transform.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/transform/transform.c
29  *  \ingroup edtransform
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_anim_types.h"
41 #include "DNA_armature_types.h"
42 #include "DNA_constraint_types.h"
43 #include "DNA_mask_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_movieclip_types.h"
46 #include "DNA_scene_types.h"  /* PET modes */
47 #include "DNA_workspace_types.h"
48
49 #include "BLI_alloca.h"
50 #include "BLI_utildefines.h"
51 #include "BLI_math.h"
52 #include "BLI_rect.h"
53 #include "BLI_listbase.h"
54 #include "BLI_string.h"
55 #include "BLI_ghash.h"
56 #include "BLI_utildefines_stack.h"
57 #include "BLI_memarena.h"
58
59 #include "BKE_nla.h"
60 #include "BKE_editmesh.h"
61 #include "BKE_editmesh_bvh.h"
62 #include "BKE_context.h"
63 #include "BKE_constraint.h"
64 #include "BKE_particle.h"
65 #include "BKE_unit.h"
66 #include "BKE_scene.h"
67 #include "BKE_mask.h"
68 #include "BKE_mesh.h"
69 #include "BKE_report.h"
70 #include "BKE_workspace.h"
71
72 #include "DEG_depsgraph.h"
73
74 #include "BIF_glutil.h"
75
76 #include "GPU_immediate.h"
77 #include "GPU_immediate_util.h"
78 #include "GPU_matrix.h"
79 #include "GPU_state.h"
80
81 #include "ED_image.h"
82 #include "ED_keyframing.h"
83 #include "ED_screen.h"
84 #include "ED_space_api.h"
85 #include "ED_markers.h"
86 #include "ED_view3d.h"
87 #include "ED_mesh.h"
88 #include "ED_clip.h"
89 #include "ED_node.h"
90
91 #include "WM_types.h"
92 #include "WM_api.h"
93
94 #include "UI_view2d.h"
95 #include "UI_interface.h"
96 #include "UI_interface_icons.h"
97 #include "UI_resources.h"
98
99 #include "RNA_access.h"
100 #include "RNA_define.h"
101
102 #include "BLF_api.h"
103 #include "BLT_translation.h"
104
105 #include "transform.h"
106
107 /* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
108 // #define USE_NUM_NO_ZERO
109
110 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
111 static void doEdgeSlide(TransInfo *t, float perc);
112 static void doVertSlide(TransInfo *t, float perc);
113
114 static void drawEdgeSlide(TransInfo *t);
115 static void drawVertSlide(TransInfo *t);
116 static void postInputRotation(TransInfo *t, float values[3]);
117
118 static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
119 static void initSnapSpatial(TransInfo *t, float r_snap[3]);
120
121 static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm);
122
123 /* Transform Callbacks */
124 static void initBend(TransInfo *t);
125 static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event);
126 static void Bend(TransInfo *t, const int mval[2]);
127
128 static void initShear(TransInfo *t);
129 static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event);
130 static void applyShear(TransInfo *t, const int mval[2]);
131
132 static void initResize(TransInfo *t);
133 static void applyResize(TransInfo *t, const int mval[2]);
134
135 static void initSkinResize(TransInfo *t);
136 static void applySkinResize(TransInfo *t, const int mval[2]);
137
138 static void initTranslation(TransInfo *t);
139 static void applyTranslation(TransInfo *t, const int mval[2]);
140
141 static void initToSphere(TransInfo *t);
142 static void applyToSphere(TransInfo *t, const int mval[2]);
143
144 static void initRotation(TransInfo *t);
145 static void applyRotation(TransInfo *t, const int mval[2]);
146
147 static void initNormalRotation(TransInfo *t);
148 static void applyNormalRotation(TransInfo *t, const int mval[2]);
149
150 static void initShrinkFatten(TransInfo *t);
151 static void applyShrinkFatten(TransInfo *t, const int mval[2]);
152
153 static void initTilt(TransInfo *t);
154 static void applyTilt(TransInfo *t, const int mval[2]);
155
156 static void initCurveShrinkFatten(TransInfo *t);
157 static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]);
158
159 static void initMaskShrinkFatten(TransInfo *t);
160 static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]);
161
162 static void initGPShrinkFatten(TransInfo *t);
163 static void applyGPShrinkFatten(TransInfo *t, const int mval[2]);
164
165 static void initTrackball(TransInfo *t);
166 static void applyTrackball(TransInfo *t, const int mval[2]);
167
168 static void initPushPull(TransInfo *t);
169 static void applyPushPull(TransInfo *t, const int mval[2]);
170
171 static void initBevelWeight(TransInfo *t);
172 static void applyBevelWeight(TransInfo *t, const int mval[2]);
173
174 static void initCrease(TransInfo *t);
175 static void applyCrease(TransInfo *t, const int mval[2]);
176
177 static void initBoneSize(TransInfo *t);
178 static void applyBoneSize(TransInfo *t, const int mval[2]);
179
180 static void initBoneEnvelope(TransInfo *t);
181 static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
182
183 static void initBoneRoll(TransInfo *t);
184 static void applyBoneRoll(TransInfo *t, const int mval[2]);
185
186 static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
187 static void initEdgeSlide(TransInfo *t);
188 static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
189 static void applyEdgeSlide(TransInfo *t, const int mval[2]);
190
191 static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
192 static void initVertSlide(TransInfo *t);
193 static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
194 static void applyVertSlide(TransInfo *t, const int mval[2]);
195
196 static void initTimeTranslate(TransInfo *t);
197 static void applyTimeTranslate(TransInfo *t, const int mval[2]);
198
199 static void initTimeSlide(TransInfo *t);
200 static void applyTimeSlide(TransInfo *t, const int mval[2]);
201
202 static void initTimeScale(TransInfo *t);
203 static void applyTimeScale(TransInfo *t, const int mval[2]);
204
205 static void initBakeTime(TransInfo *t);
206 static void applyBakeTime(TransInfo *t, const int mval[2]);
207
208 static void initMirror(TransInfo *t);
209 static void applyMirror(TransInfo *t, const int mval[2]);
210
211 static void initAlign(TransInfo *t);
212 static void applyAlign(TransInfo *t, const int mval[2]);
213
214 static void initSeqSlide(TransInfo *t);
215 static void applySeqSlide(TransInfo *t, const int mval[2]);
216 /* end transform callbacks */
217
218
219 static bool transdata_check_local_center(TransInfo *t, short around)
220 {
221         return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
222                     (t->flag & (T_OBJECT | T_POSE)) ||
223                     /* implicit: (t->flag & T_EDIT) */
224                     (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
225                     (t->spacetype == SPACE_IPO) ||
226                     (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
227                 );
228 }
229
230 bool transdata_check_local_islands(TransInfo *t, short around)
231 {
232         return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
233                 (ELEM(t->obedit_type, OB_MESH))));
234 }
235
236 /* ************************** SPACE DEPENDANT CODE **************************** */
237
238 void setTransformViewMatrices(TransInfo *t)
239 {
240         if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
241                 RegionView3D *rv3d = t->ar->regiondata;
242
243                 copy_m4_m4(t->viewmat, rv3d->viewmat);
244                 copy_m4_m4(t->viewinv, rv3d->viewinv);
245                 copy_m4_m4(t->persmat, rv3d->persmat);
246                 copy_m4_m4(t->persinv, rv3d->persinv);
247                 t->persp = rv3d->persp;
248         }
249         else {
250                 unit_m4(t->viewmat);
251                 unit_m4(t->viewinv);
252                 unit_m4(t->persmat);
253                 unit_m4(t->persinv);
254                 t->persp = RV3D_ORTHO;
255         }
256
257         calculateCenter2D(t);
258         calculateCenterLocal(t, t->center_global);
259 }
260
261 void setTransformViewAspect(TransInfo *t, float r_aspect[3])
262 {
263         copy_v3_fl(r_aspect, 1.0f);
264
265         if (t->spacetype == SPACE_IMAGE) {
266                 SpaceImage *sima = t->sa->spacedata.first;
267
268                 if (t->options & CTX_MASK) {
269                         ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
270                 }
271                 else if (t->options & CTX_PAINT_CURVE) {
272                         /* pass */
273                 }
274                 else {
275                         ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
276                 }
277         }
278         else if (t->spacetype == SPACE_CLIP) {
279                 SpaceClip *sclip = t->sa->spacedata.first;
280
281                 if (t->options & CTX_MOVIECLIP) {
282                         ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
283                 }
284                 else {
285                         ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]);
286                 }
287         }
288         else if (t->spacetype == SPACE_IPO) {
289                 /* depemds on context of usage */
290         }
291 }
292
293 static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
294 {
295         float divx = BLI_rcti_size_x(&v2d->mask);
296         float divy = BLI_rcti_size_y(&v2d->mask);
297
298         r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
299         r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
300         r_vec[2] = 0.0f;
301 }
302
303 static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
304 {
305         float divx = BLI_rcti_size_x(&v2d->mask);
306         float divy = BLI_rcti_size_y(&v2d->mask);
307
308         float mulx = BLI_rctf_size_x(&v2d->cur);
309         float muly = BLI_rctf_size_y(&v2d->cur);
310
311         /* difference with convertViewVec2D */
312         /* clamp w/h, mask only */
313         if (mulx / divx < muly / divy) {
314                 divy = divx;
315                 muly = mulx;
316         }
317         else {
318                 divx = divy;
319                 mulx = muly;
320         }
321         /* end difference */
322
323         r_vec[0] = mulx * dx / divx;
324         r_vec[1] = muly * dy / divy;
325         r_vec[2] = 0.0f;
326 }
327
328 void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
329 {
330         if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
331                 if (t->options & CTX_PAINT_CURVE) {
332                         r_vec[0] = dx;
333                         r_vec[1] = dy;
334                 }
335                 else {
336                         const float mval_f[2] = {(float)dx, (float)dy};
337                         ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
338                 }
339         }
340         else if (t->spacetype == SPACE_IMAGE) {
341                 if (t->options & CTX_MASK) {
342                         convertViewVec2D_mask(t->view, r_vec, dx, dy);
343                 }
344                 else if (t->options & CTX_PAINT_CURVE) {
345                         r_vec[0] = dx;
346                         r_vec[1] = dy;
347                 }
348                 else {
349                         convertViewVec2D(t->view, r_vec, dx, dy);
350                 }
351
352                 r_vec[0] *= t->aspect[0];
353                 r_vec[1] *= t->aspect[1];
354         }
355         else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
356                 convertViewVec2D(t->view, r_vec, dx, dy);
357         }
358         else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
359                 convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
360         }
361         else if (t->spacetype == SPACE_CLIP) {
362                 if (t->options & CTX_MASK) {
363                         convertViewVec2D_mask(t->view, r_vec, dx, dy);
364                 }
365                 else {
366                         convertViewVec2D(t->view, r_vec, dx, dy);
367                 }
368
369                 r_vec[0] *= t->aspect[0];
370                 r_vec[1] *= t->aspect[1];
371         }
372         else {
373                 printf("%s: called in an invalid context\n", __func__);
374                 zero_v3(r_vec);
375         }
376 }
377
378 void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
379 {
380         if (t->spacetype == SPACE_VIEW3D) {
381                 if (t->ar->regiontype == RGN_TYPE_WINDOW) {
382                         if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
383                                 adr[0] = (int)2140000000.0f;  /* this is what was done in 2.64, perhaps we can be smarter? */
384                                 adr[1] = (int)2140000000.0f;
385                         }
386                 }
387         }
388         else if (t->spacetype == SPACE_IMAGE) {
389                 SpaceImage *sima = t->sa->spacedata.first;
390
391                 if (t->options & CTX_MASK) {
392                         float v[2];
393
394                         v[0] = vec[0] / t->aspect[0];
395                         v[1] = vec[1] / t->aspect[1];
396
397                         BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
398
399                         ED_image_point_pos__reverse(sima, t->ar, v, v);
400
401                         adr[0] = v[0];
402                         adr[1] = v[1];
403                 }
404                 else if (t->options & CTX_PAINT_CURVE) {
405                         adr[0] = vec[0];
406                         adr[1] = vec[1];
407                 }
408                 else {
409                         float v[2];
410
411                         v[0] = vec[0] / t->aspect[0];
412                         v[1] = vec[1] / t->aspect[1];
413
414                         UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
415                 }
416         }
417         else if (t->spacetype == SPACE_ACTION) {
418                 int out[2] = {0, 0};
419 #if 0
420                 SpaceAction *sact = t->sa->spacedata.first;
421
422                 if (sact->flag & SACTION_DRAWTIME) {
423                         //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
424                         /* same as below */
425                         UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
426                 }
427                 else
428 #endif
429                 {
430                         UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
431                 }
432
433                 adr[0] = out[0];
434                 adr[1] = out[1];
435         }
436         else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
437                 int out[2] = {0, 0};
438
439                 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
440                 adr[0] = out[0];
441                 adr[1] = out[1];
442         }
443         else if (t->spacetype == SPACE_SEQ) { /* XXX not tested yet, but should work */
444                 int out[2] = {0, 0};
445
446                 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
447                 adr[0] = out[0];
448                 adr[1] = out[1];
449         }
450         else if (t->spacetype == SPACE_CLIP) {
451                 SpaceClip *sc = t->sa->spacedata.first;
452
453                 if (t->options & CTX_MASK) {
454                         MovieClip *clip = ED_space_clip_get_clip(sc);
455
456                         if (clip) {
457                                 float v[2];
458
459                                 v[0] = vec[0] / t->aspect[0];
460                                 v[1] = vec[1] / t->aspect[1];
461
462                                 BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
463
464                                 ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
465
466                                 adr[0] = v[0];
467                                 adr[1] = v[1];
468                         }
469                         else {
470                                 adr[0] = 0;
471                                 adr[1] = 0;
472                         }
473                 }
474                 else if (t->options & CTX_MOVIECLIP) {
475                         float v[2];
476
477                         v[0] = vec[0] / t->aspect[0];
478                         v[1] = vec[1] / t->aspect[1];
479
480                         UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
481                 }
482                 else {
483                         BLI_assert(0);
484                 }
485         }
486         else if (t->spacetype == SPACE_NODE) {
487                 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &adr[0], &adr[1]);
488         }
489 }
490 void projectIntView(TransInfo *t, const float vec[3], int adr[2])
491 {
492         projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
493 }
494
495 void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
496 {
497         switch (t->spacetype) {
498                 case SPACE_VIEW3D:
499                 {
500                         if (t->options & CTX_PAINT_CURVE) {
501                                 adr[0] = vec[0];
502                                 adr[1] = vec[1];
503                         }
504                         else if (t->ar->regiontype == RGN_TYPE_WINDOW) {
505                                 /* allow points behind the view [#33643] */
506                                 if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
507                                         /* XXX, 2.64 and prior did this, weak! */
508                                         adr[0] = t->ar->winx / 2.0f;
509                                         adr[1] = t->ar->winy / 2.0f;
510                                 }
511                                 return;
512                         }
513                         break;
514                 }
515                 default:
516                 {
517                         int a[2] = {0, 0};
518                         projectIntView(t, vec, a);
519                         adr[0] = a[0];
520                         adr[1] = a[1];
521                         break;
522                 }
523         }
524 }
525 void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
526 {
527         projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
528 }
529
530 void applyAspectRatio(TransInfo *t, float vec[2])
531 {
532         if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) {
533                 SpaceImage *sima = t->sa->spacedata.first;
534
535                 if ((sima->flag & SI_COORDFLOATS) == 0) {
536                         int width, height;
537                         ED_space_image_get_size(sima, &width, &height);
538
539                         vec[0] *= width;
540                         vec[1] *= height;
541                 }
542
543                 vec[0] /= t->aspect[0];
544                 vec[1] /= t->aspect[1];
545         }
546         else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
547                 if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
548                         vec[0] /= t->aspect[0];
549                         vec[1] /= t->aspect[1];
550                 }
551         }
552 }
553
554 void removeAspectRatio(TransInfo *t, float vec[2])
555 {
556         if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
557                 SpaceImage *sima = t->sa->spacedata.first;
558
559                 if ((sima->flag & SI_COORDFLOATS) == 0) {
560                         int width, height;
561                         ED_space_image_get_size(sima, &width, &height);
562
563                         vec[0] /= width;
564                         vec[1] /= height;
565                 }
566
567                 vec[0] *= t->aspect[0];
568                 vec[1] *= t->aspect[1];
569         }
570         else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
571                 if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
572                         vec[0] *= t->aspect[0];
573                         vec[1] *= t->aspect[1];
574                 }
575         }
576 }
577
578 static void viewRedrawForce(const bContext *C, TransInfo *t)
579 {
580         if (t->options & CTX_GPENCIL_STROKES) {
581                 WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
582         }
583         else if (t->spacetype == SPACE_VIEW3D) {
584                 if (t->options & CTX_PAINT_CURVE) {
585                         wmWindow *window = CTX_wm_window(C);
586                         WM_paint_cursor_tag_redraw(window, t->ar);
587                 }
588                 else {
589                         /* Do we need more refined tags? */
590                         if (t->flag & T_POSE)
591                                 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
592                         else
593                                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
594
595                         /* for realtime animation record - send notifiers recognised by animation editors */
596                         // XXX: is this notifier a lame duck?
597                         if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
598                                 WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
599
600                 }
601         }
602         else if (t->spacetype == SPACE_ACTION) {
603                 //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
604                 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
605         }
606         else if (t->spacetype == SPACE_IPO) {
607                 //SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
608                 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
609         }
610         else if (t->spacetype == SPACE_NLA) {
611                 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
612         }
613         else if (t->spacetype == SPACE_NODE) {
614                 //ED_area_tag_redraw(t->sa);
615                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
616         }
617         else if (t->spacetype == SPACE_SEQ) {
618                 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
619         }
620         else if (t->spacetype == SPACE_IMAGE) {
621                 if (t->options & CTX_MASK) {
622                         Mask *mask = CTX_data_edit_mask(C);
623
624                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
625                 }
626                 else if (t->options & CTX_PAINT_CURVE) {
627                         wmWindow *window = CTX_wm_window(C);
628                         WM_paint_cursor_tag_redraw(window, t->ar);
629                 }
630                 else {
631                         // XXX how to deal with lock?
632                         SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
633                         if (sima->lock) {
634                                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
635                         }
636                         else {
637                                 ED_area_tag_redraw(t->sa);
638                         }
639                 }
640         }
641         else if (t->spacetype == SPACE_CLIP) {
642                 SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
643
644                 if (ED_space_clip_check_show_trackedit(sc)) {
645                         MovieClip *clip = ED_space_clip_get_clip(sc);
646
647                         /* objects could be parented to tracking data, so send this for viewport refresh */
648                         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
649
650                         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
651                 }
652                 else if (ED_space_clip_check_show_maskedit(sc)) {
653                         Mask *mask = CTX_data_edit_mask(C);
654
655                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
656                 }
657         }
658 }
659
660 static void viewRedrawPost(bContext *C, TransInfo *t)
661 {
662         ED_area_status_text(t->sa, NULL);
663
664         if (t->spacetype == SPACE_VIEW3D) {
665                 /* if autokeying is enabled, send notifiers that keyframes were added */
666                 if (IS_AUTOKEY_ON(t->scene))
667                         WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
668
669                 /* redraw UV editor */
670                 if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) &&
671                     (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
672                 {
673                         WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
674                 }
675
676                 /* XXX temp, first hack to get auto-render in compositor work (ton) */
677                 WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
678
679         }
680
681 #if 0 // TRANSFORM_FIX_ME
682         if (t->spacetype == SPACE_VIEW3D) {
683                 allqueue(REDRAWBUTSOBJECT, 0);
684                 allqueue(REDRAWVIEW3D, 0);
685         }
686         else if (t->spacetype == SPACE_IMAGE) {
687                 allqueue(REDRAWIMAGE, 0);
688                 allqueue(REDRAWVIEW3D, 0);
689         }
690         else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
691                 allqueue(REDRAWVIEW3D, 0);
692                 allqueue(REDRAWACTION, 0);
693                 allqueue(REDRAWNLA, 0);
694                 allqueue(REDRAWIPO, 0);
695                 allqueue(REDRAWTIME, 0);
696                 allqueue(REDRAWBUTSOBJECT, 0);
697         }
698
699         scrarea_queue_headredraw(curarea);
700 #endif
701 }
702
703 /* ************************** TRANSFORMATIONS **************************** */
704
705 static void view_editmove(unsigned short UNUSED(event))
706 {
707 #if 0 // TRANSFORM_FIX_ME
708         int refresh = 0;
709         /* Regular:   Zoom in */
710         /* Shift:     Scroll up */
711         /* Ctrl:      Scroll right */
712         /* Alt-Shift: Rotate up */
713         /* Alt-Ctrl:  Rotate right */
714
715         /* only work in 3D window for now
716          * In the end, will have to send to event to a 2D window handler instead
717          */
718         if (Trans.flag & T_2D_EDIT)
719                 return;
720
721         switch (event) {
722                 case WHEELUPMOUSE:
723                         if (G.qual & LR_SHIFTKEY) {
724                                 if (G.qual & LR_ALTKEY) {
725                                         G.qual &= ~LR_SHIFTKEY;
726                                         persptoetsen(PAD2);
727                                         G.qual |= LR_SHIFTKEY;
728                                 }
729                                 else {
730                                         persptoetsen(PAD2);
731                                 }
732                         }
733                         else if (G.qual & LR_CTRLKEY) {
734                                 if (G.qual & LR_ALTKEY) {
735                                         G.qual &= ~LR_CTRLKEY;
736                                         persptoetsen(PAD4);
737                                         G.qual |= LR_CTRLKEY;
738                                 }
739                                 else {
740                                         persptoetsen(PAD4);
741                                 }
742                         }
743                         else if (U.uiflag & USER_WHEELZOOMDIR)
744                                 persptoetsen(PADMINUS);
745                         else
746                                 persptoetsen(PADPLUSKEY);
747
748                         refresh = 1;
749                         break;
750                 case WHEELDOWNMOUSE:
751                         if (G.qual & LR_SHIFTKEY) {
752                                 if (G.qual & LR_ALTKEY) {
753                                         G.qual &= ~LR_SHIFTKEY;
754                                         persptoetsen(PAD8);
755                                         G.qual |= LR_SHIFTKEY;
756                                 }
757                                 else {
758                                         persptoetsen(PAD8);
759                                 }
760                         }
761                         else if (G.qual & LR_CTRLKEY) {
762                                 if (G.qual & LR_ALTKEY) {
763                                         G.qual &= ~LR_CTRLKEY;
764                                         persptoetsen(PAD6);
765                                         G.qual |= LR_CTRLKEY;
766                                 }
767                                 else {
768                                         persptoetsen(PAD6);
769                                 }
770                         }
771                         else if (U.uiflag & USER_WHEELZOOMDIR)
772                                 persptoetsen(PADPLUSKEY);
773                         else
774                                 persptoetsen(PADMINUS);
775
776                         refresh = 1;
777                         break;
778         }
779
780         if (refresh)
781                 setTransformViewMatrices(&Trans);
782 #endif
783 }
784
785 /* ************************************************* */
786
787 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
788 enum {
789         TFM_MODAL_CANCEL         = 1,
790         TFM_MODAL_CONFIRM        = 2,
791         TFM_MODAL_TRANSLATE      = 3,
792         TFM_MODAL_ROTATE         = 4,
793         TFM_MODAL_RESIZE         = 5,
794         TFM_MODAL_SNAP_INV_ON    = 6,
795         TFM_MODAL_SNAP_INV_OFF   = 7,
796         TFM_MODAL_SNAP_TOGGLE    = 8,
797         TFM_MODAL_AXIS_X         = 9,
798         TFM_MODAL_AXIS_Y         = 10,
799         TFM_MODAL_AXIS_Z         = 11,
800         TFM_MODAL_PLANE_X        = 12,
801         TFM_MODAL_PLANE_Y        = 13,
802         TFM_MODAL_PLANE_Z        = 14,
803         TFM_MODAL_CONS_OFF       = 15,
804         TFM_MODAL_ADD_SNAP       = 16,
805         TFM_MODAL_REMOVE_SNAP    = 17,
806
807 /*      18 and 19 used by numinput, defined in transform.h */
808
809         TFM_MODAL_PROPSIZE_UP    = 20,
810         TFM_MODAL_PROPSIZE_DOWN  = 21,
811         TFM_MODAL_AUTOIK_LEN_INC = 22,
812         TFM_MODAL_AUTOIK_LEN_DEC = 23,
813
814         TFM_MODAL_EDGESLIDE_UP   = 24,
815         TFM_MODAL_EDGESLIDE_DOWN = 25,
816
817 /* for analog input, like trackpad */
818         TFM_MODAL_PROPSIZE       = 26,
819 /* node editor insert offset (aka auto-offset) direction toggle */
820         TFM_MODAL_INSERTOFS_TOGGLE_DIR         = 27,
821 };
822
823 static bool transform_modal_item_poll(const wmOperator *op, int value)
824 {
825         const TransInfo *t = op->customdata;
826         switch (value) {
827                 case TFM_MODAL_PROPSIZE:
828                 case TFM_MODAL_PROPSIZE_UP:
829                 case TFM_MODAL_PROPSIZE_DOWN:
830                 {
831                         if ((t->flag & T_PROP_EDIT) == 0) {
832                                 return false;
833                         }
834                         break;
835                 }
836                 case TFM_MODAL_ADD_SNAP:
837                 case TFM_MODAL_REMOVE_SNAP:
838                 {
839                         if (t->spacetype != SPACE_VIEW3D) {
840                                 return false;
841                         }
842                         else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
843                                 return false;
844                         }
845                         else if (!validSnap(t)) {
846                                 return false;
847                         }
848                         break;
849                 }
850                 case TFM_MODAL_AXIS_X:
851                 case TFM_MODAL_AXIS_Y:
852                 case TFM_MODAL_AXIS_Z:
853                 case TFM_MODAL_PLANE_X:
854                 case TFM_MODAL_PLANE_Y:
855                 case TFM_MODAL_PLANE_Z:
856                 {
857                         if (t->flag & T_NO_CONSTRAINT) {
858                                 return false;
859                         }
860                         if (!ELEM(value, TFM_MODAL_AXIS_X, TFM_MODAL_AXIS_Y)) {
861                                 if (t->flag & T_2D_EDIT) {
862                                         return false;
863                                 }
864                         }
865                         break;
866                 }
867                 case TFM_MODAL_CONS_OFF:
868                 {
869                         if ((t->con.mode & CON_APPLY) == 0) {
870                                 return false;
871                         }
872                         break;
873                 }
874                 case TFM_MODAL_EDGESLIDE_UP:
875                 case TFM_MODAL_EDGESLIDE_DOWN:
876                 {
877                         if (t->mode != TFM_EDGE_SLIDE) {
878                                 return false;
879                         }
880                         break;
881                 }
882                 case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
883                 {
884                         if (t->spacetype != SPACE_NODE) {
885                                 return false;
886                         }
887                         break;
888                 }
889                 case TFM_MODAL_AUTOIK_LEN_INC:
890                 case TFM_MODAL_AUTOIK_LEN_DEC:
891                 {
892                         if ((t->flag & T_AUTOIK) == 0) {
893                                 return false;
894                         }
895                         break;
896                 }
897         }
898         return true;
899 }
900
901 /* called in transform_ops.c, on each regeneration of keymaps */
902 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
903 {
904         static const EnumPropertyItem modal_items[] = {
905                 {TFM_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
906                 {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
907                 {TFM_MODAL_AXIS_X, "AXIS_X", 0, "X axis", ""},
908                 {TFM_MODAL_AXIS_Y, "AXIS_Y", 0, "Y axis", ""},
909                 {TFM_MODAL_AXIS_Z, "AXIS_Z", 0, "Z axis", ""},
910                 {TFM_MODAL_PLANE_X, "PLANE_X", 0, "X plane", ""},
911                 {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Y plane", ""},
912                 {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Z plane", ""},
913                 {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Clear Constraints", ""},
914                 {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Snap Invert", ""},
915                 {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Snap Invert (Off)", ""},
916                 {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""},
917                 {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""},
918                 {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""},
919                 {NUM_MODAL_INCREMENT_UP, "INCREMENT_UP", 0, "Numinput Increment Up", ""},
920                 {NUM_MODAL_INCREMENT_DOWN, "INCREMENT_DOWN", 0, "Numinput Increment Down", ""},
921                 {TFM_MODAL_PROPSIZE_UP, "PROPORTIONAL_SIZE_UP", 0, "Increase Proportional Influence", ""},
922                 {TFM_MODAL_PROPSIZE_DOWN, "PROPORTIONAL_SIZE_DOWN", 0, "Decrease Proportional Influence", ""},
923                 {TFM_MODAL_AUTOIK_LEN_INC, "AUTOIK_CHAIN_LEN_UP", 0, "Increase Max AutoIK Chain Length", ""},
924                 {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
925                 {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
926                 {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
927                 {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
928                 {TFM_MODAL_INSERTOFS_TOGGLE_DIR, "INSERTOFS_TOGGLE_DIR", 0, "Toggle Direction for Node Auto-offset", ""},
929                 {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
930                 {TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""},
931                 {TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""},
932                 {0, NULL, 0, NULL, NULL}
933         };
934
935         wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
936
937         /* this function is called for each spacetype, only needs to add map once */
938         if (keymap && keymap->modal_items) return NULL;
939
940         keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
941         keymap->poll_modal_item = transform_modal_item_poll;
942
943         /* items for modal map */
944         WM_modalkeymap_add_item(keymap, LEFTMOUSE,  KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
945         WM_modalkeymap_add_item(keymap, RETKEY,     KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
946         WM_modalkeymap_add_item(keymap, PADENTER,   KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
947         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
948         WM_modalkeymap_add_item(keymap, ESCKEY,     KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
949
950         WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_X);
951         WM_modalkeymap_add_item(keymap, YKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_Y);
952         WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_Z);
953
954         WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_X);
955         WM_modalkeymap_add_item(keymap, YKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_Y);
956         WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_Z);
957
958         WM_modalkeymap_add_item(keymap, CKEY, KM_PRESS, 0, 0, TFM_MODAL_CONS_OFF);
959
960         WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
961         WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
962         WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE);
963
964         WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE);
965
966         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
967         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
968
969         WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
970         WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
971
972         WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, TFM_MODAL_ADD_SNAP);
973         WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ALT, 0, TFM_MODAL_REMOVE_SNAP);
974
975         WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
976         WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
977         WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
978         WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
979         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
980         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
981         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
982         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
983         WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
984
985         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
986         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
987
988         WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
989         WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
990         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
991         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
992
993         /* node editor only */
994         WM_modalkeymap_add_item(keymap, TKEY, KM_PRESS, 0, 0, TFM_MODAL_INSERTOFS_TOGGLE_DIR);
995
996         return keymap;
997 }
998
999 static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
1000 {
1001         if (!(t->flag & T_NO_CONSTRAINT)) {
1002                 int constraint_axis, constraint_plane;
1003                 const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
1004                 const char *msg1 = "", *msg2 = "", *msg3 = "";
1005                 char axis;
1006
1007                 /* Initialize */
1008                 switch (key_type) {
1009                         case XKEY:
1010                                 msg1 = IFACE_("along X");
1011                                 msg2 = IFACE_("along %s X");
1012                                 msg3 = IFACE_("locking %s X");
1013                                 axis = 'X';
1014                                 constraint_axis = CON_AXIS0;
1015                                 break;
1016                         case YKEY:
1017                                 msg1 = IFACE_("along Y");
1018                                 msg2 = IFACE_("along %s Y");
1019                                 msg3 = IFACE_("locking %s Y");
1020                                 axis = 'Y';
1021                                 constraint_axis = CON_AXIS1;
1022                                 break;
1023                         case ZKEY:
1024                                 msg1 = IFACE_("along Z");
1025                                 msg2 = IFACE_("along %s Z");
1026                                 msg3 = IFACE_("locking %s Z");
1027                                 axis = 'Z';
1028                                 constraint_axis = CON_AXIS2;
1029                                 break;
1030                         default:
1031                                 /* Invalid key */
1032                                 return;
1033                 }
1034                 constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis));
1035
1036                 if (edit_2d && (key_type != ZKEY)) {
1037                         if (cmode == axis) {
1038                                 stopConstraint(t);
1039                         }
1040                         else {
1041                                 setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_axis, msg1);
1042                         }
1043                 }
1044                 else if (!edit_2d) {
1045                         if (cmode == axis) {
1046                                 if (t->con.orientation != V3D_MANIP_GLOBAL) {
1047                                         stopConstraint(t);
1048                                 }
1049                                 else {
1050                                         short orientation = (t->current_orientation != V3D_MANIP_GLOBAL ?
1051                                                              t->current_orientation : V3D_MANIP_LOCAL);
1052                                         if (is_plane == false) {
1053                                                 setUserConstraint(t, orientation, constraint_axis, msg2);
1054                                         }
1055                                         else {
1056                                                 setUserConstraint(t, orientation, constraint_plane, msg3);
1057                                         }
1058                                 }
1059                         }
1060                         else {
1061                                 if (is_plane == false) {
1062                                         setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_axis, msg2);
1063                                 }
1064                                 else {
1065                                         setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_plane, msg3);
1066                                 }
1067                         }
1068                 }
1069                 t->redraw |= TREDRAW_HARD;
1070         }
1071 }
1072
1073 int transformEvent(TransInfo *t, const wmEvent *event)
1074 {
1075         char cmode = constraintModeToChar(t);
1076         bool handled = false;
1077         const int modifiers_prev = t->modifiers;
1078
1079         t->redraw |= handleMouseInput(t, &t->mouse, event);
1080
1081         /* Handle modal numinput events first, if already activated. */
1082         if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
1083             hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
1084         {
1085                 t->redraw |= TREDRAW_HARD;
1086                 handled = true;
1087         }
1088         else if (event->type == MOUSEMOVE) {
1089                 if (t->modifiers & MOD_CONSTRAINT_SELECT)
1090                         t->con.mode |= CON_SELECT;
1091
1092                 copy_v2_v2_int(t->mval, event->mval);
1093
1094                 // t->redraw |= TREDRAW_SOFT; /* Use this for soft redraw. Might cause flicker in object mode */
1095                 t->redraw |= TREDRAW_HARD;
1096
1097                 if (t->state == TRANS_STARTING) {
1098                         t->state = TRANS_RUNNING;
1099                 }
1100
1101                 applyMouseInput(t, &t->mouse, t->mval, t->values);
1102
1103                 // Snapping mouse move events
1104                 t->redraw |= handleSnapping(t, event);
1105                 handled = true;
1106         }
1107         /* handle modal keymap first */
1108         else if (event->type == EVT_MODAL_MAP) {
1109                 switch (event->val) {
1110                         case TFM_MODAL_CANCEL:
1111                                 t->state = TRANS_CANCEL;
1112                                 handled = true;
1113                                 break;
1114                         case TFM_MODAL_CONFIRM:
1115                                 t->state = TRANS_CONFIRM;
1116                                 handled = true;
1117                                 break;
1118                         case TFM_MODAL_TRANSLATE:
1119                                 /* only switch when... */
1120                                 if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
1121                                         restoreTransObjects(t);
1122                                         resetTransModal(t);
1123                                         resetTransRestrictions(t);
1124                                         initTranslation(t);
1125                                         initSnapping(t, NULL); // need to reinit after mode change
1126                                         t->redraw |= TREDRAW_HARD;
1127                                         WM_event_add_mousemove(t->context);
1128                                         handled = true;
1129                                 }
1130                                 else if (t->mode == TFM_SEQ_SLIDE) {
1131                                         t->flag ^= T_ALT_TRANSFORM;
1132                                         t->redraw |= TREDRAW_HARD;
1133                                         handled = true;
1134                                 }
1135                                 else {
1136                                         if (t->obedit_type == OB_MESH) {
1137                                                 if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
1138                                                         restoreTransObjects(t);
1139                                                         resetTransModal(t);
1140                                                         resetTransRestrictions(t);
1141
1142                                                         /* first try edge slide */
1143                                                         initEdgeSlide(t);
1144                                                         /* if that fails, do vertex slide */
1145                                                         if (t->state == TRANS_CANCEL) {
1146                                                                 resetTransModal(t);
1147                                                                 t->state = TRANS_STARTING;
1148                                                                 initVertSlide(t);
1149                                                         }
1150                                                         /* vert slide can fail on unconnected vertices (rare but possible) */
1151                                                         if (t->state == TRANS_CANCEL) {
1152                                                                 resetTransModal(t);
1153                                                                 t->mode = TFM_TRANSLATION;
1154                                                                 t->state = TRANS_STARTING;
1155                                                                 restoreTransObjects(t);
1156                                                                 resetTransRestrictions(t);
1157                                                                 initTranslation(t);
1158                                                         }
1159                                                         initSnapping(t, NULL); // need to reinit after mode change
1160                                                         t->redraw |= TREDRAW_HARD;
1161                                                         handled = true;
1162                                                         WM_event_add_mousemove(t->context);
1163                                                 }
1164                                         }
1165                                         else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
1166                                                 if (t->mode == TFM_TRANSLATION) {
1167                                                         restoreTransObjects(t);
1168
1169                                                         t->flag ^= T_ALT_TRANSFORM;
1170                                                         t->redraw |= TREDRAW_HARD;
1171                                                         handled = true;
1172                                                 }
1173                                         }
1174                                 }
1175                                 break;
1176                         case TFM_MODAL_ROTATE:
1177                                 /* only switch when... */
1178                                 if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
1179                                         if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
1180                                                 restoreTransObjects(t);
1181                                                 resetTransModal(t);
1182                                                 resetTransRestrictions(t);
1183
1184                                                 if (t->mode == TFM_ROTATION) {
1185                                                         initTrackball(t);
1186                                                 }
1187                                                 else {
1188                                                         initRotation(t);
1189                                                 }
1190                                                 initSnapping(t, NULL); // need to reinit after mode change
1191                                                 t->redraw |= TREDRAW_HARD;
1192                                                 handled = true;
1193                                         }
1194                                 }
1195                                 break;
1196                         case TFM_MODAL_RESIZE:
1197                                 /* only switch when... */
1198                                 if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
1199
1200                                         /* Scale isn't normally very useful after extrude along normals, see T39756 */
1201                                         if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_MANIP_NORMAL)) {
1202                                                 stopConstraint(t);
1203                                         }
1204
1205                                         restoreTransObjects(t);
1206                                         resetTransModal(t);
1207                                         resetTransRestrictions(t);
1208                                         initResize(t);
1209                                         initSnapping(t, NULL); // need to reinit after mode change
1210                                         t->redraw |= TREDRAW_HARD;
1211                                         handled = true;
1212                                 }
1213                                 else if (t->mode == TFM_SHRINKFATTEN) {
1214                                         t->flag ^= T_ALT_TRANSFORM;
1215                                         t->redraw |= TREDRAW_HARD;
1216                                         handled = true;
1217                                 }
1218                                 else if (t->mode == TFM_RESIZE) {
1219                                         if (t->options & CTX_MOVIECLIP) {
1220                                                 restoreTransObjects(t);
1221
1222                                                 t->flag ^= T_ALT_TRANSFORM;
1223                                                 t->redraw |= TREDRAW_HARD;
1224                                                 handled = true;
1225                                         }
1226                                 }
1227                                 break;
1228
1229                         case TFM_MODAL_SNAP_INV_ON:
1230                                 t->modifiers |= MOD_SNAP_INVERT;
1231                                 t->redraw |= TREDRAW_HARD;
1232                                 handled = true;
1233                                 break;
1234                         case TFM_MODAL_SNAP_INV_OFF:
1235                                 t->modifiers &= ~MOD_SNAP_INVERT;
1236                                 t->redraw |= TREDRAW_HARD;
1237                                 handled = true;
1238                                 break;
1239                         case TFM_MODAL_SNAP_TOGGLE:
1240                                 t->modifiers ^= MOD_SNAP;
1241                                 t->redraw |= TREDRAW_HARD;
1242                                 handled = true;
1243                                 break;
1244                         case TFM_MODAL_AXIS_X:
1245                                 if (!(t->flag & T_NO_CONSTRAINT)) {
1246                                         transform_event_xyz_constraint(t, XKEY, cmode, false);
1247                                         t->redraw |= TREDRAW_HARD;
1248                                         handled = true;
1249                                 }
1250                                 break;
1251                         case TFM_MODAL_AXIS_Y:
1252                                 if ((t->flag & T_NO_CONSTRAINT) == 0) {
1253                                         transform_event_xyz_constraint(t, YKEY, cmode, false);
1254                                         t->redraw |= TREDRAW_HARD;
1255                                         handled = true;
1256                                 }
1257                                 break;
1258                         case TFM_MODAL_AXIS_Z:
1259                                 if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
1260                                         transform_event_xyz_constraint(t, ZKEY, cmode, false);
1261                                         t->redraw |= TREDRAW_HARD;
1262                                         handled = true;
1263                                 }
1264                                 break;
1265                         case TFM_MODAL_PLANE_X:
1266                                 if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1267                                         transform_event_xyz_constraint(t, XKEY, cmode, true);
1268                                         t->redraw |= TREDRAW_HARD;
1269                                         handled = true;
1270                                 }
1271                                 break;
1272                         case TFM_MODAL_PLANE_Y:
1273                                 if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1274                                         transform_event_xyz_constraint(t, YKEY, cmode, true);
1275                                         t->redraw |= TREDRAW_HARD;
1276                                         handled = true;
1277                                 }
1278                                 break;
1279                         case TFM_MODAL_PLANE_Z:
1280                                 if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1281                                         transform_event_xyz_constraint(t, ZKEY, cmode, true);
1282                                         t->redraw |= TREDRAW_HARD;
1283                                         handled = true;
1284                                 }
1285                                 break;
1286                         case TFM_MODAL_CONS_OFF:
1287                                 if ((t->flag & T_NO_CONSTRAINT) == 0) {
1288                                         stopConstraint(t);
1289                                         t->redraw |= TREDRAW_HARD;
1290                                         handled = true;
1291                                 }
1292                                 break;
1293                         case TFM_MODAL_ADD_SNAP:
1294                                 addSnapPoint(t);
1295                                 t->redraw |= TREDRAW_HARD;
1296                                 handled = true;
1297                                 break;
1298                         case TFM_MODAL_REMOVE_SNAP:
1299                                 removeSnapPoint(t);
1300                                 t->redraw |= TREDRAW_HARD;
1301                                 handled = true;
1302                                 break;
1303                         case TFM_MODAL_PROPSIZE:
1304                                 /* MOUSEPAN usage... */
1305                                 if (t->flag & T_PROP_EDIT) {
1306                                         float fac = 1.0f + 0.005f *(event->y - event->prevy);
1307                                         t->prop_size *= fac;
1308                                         if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1309                                                 t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
1310                                         }
1311                                         else {
1312                                                 t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
1313                                         }
1314                                         calculatePropRatio(t);
1315                                         t->redraw |= TREDRAW_HARD;
1316                                         handled = true;
1317                                 }
1318                                 break;
1319                         case TFM_MODAL_PROPSIZE_UP:
1320                                 if (t->flag & T_PROP_EDIT) {
1321                                         t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1322                                         if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1323                                                 t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
1324                                         }
1325                                         else {
1326                                                 t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
1327                                         }
1328                                         calculatePropRatio(t);
1329                                         t->redraw |= TREDRAW_HARD;
1330                                         handled = true;
1331                                 }
1332                                 break;
1333                         case TFM_MODAL_PROPSIZE_DOWN:
1334                                 if (t->flag & T_PROP_EDIT) {
1335                                         t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1336                                         t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
1337                                         calculatePropRatio(t);
1338                                         t->redraw |= TREDRAW_HARD;
1339                                         handled = true;
1340                                 }
1341                                 break;
1342                         case TFM_MODAL_AUTOIK_LEN_INC:
1343                                 if (t->flag & T_AUTOIK) {
1344                                         transform_autoik_update(t, 1);
1345                                         t->redraw |= TREDRAW_HARD;
1346                                         handled = true;
1347                                 }
1348                                 break;
1349                         case TFM_MODAL_AUTOIK_LEN_DEC:
1350                                 if (t->flag & T_AUTOIK) {
1351                                         transform_autoik_update(t, -1);
1352                                         t->redraw |= TREDRAW_HARD;
1353                                         handled = true;
1354                                 }
1355                                 break;
1356                         case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
1357                                 if (t->spacetype == SPACE_NODE) {
1358                                         SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
1359
1360                                         BLI_assert(t->sa->spacetype == t->spacetype);
1361
1362                                         if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
1363                                                 snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
1364                                         }
1365                                         else if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_LEFT) {
1366                                                 snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_RIGHT;
1367                                         }
1368                                         else {
1369                                                 BLI_assert(0);
1370                                         }
1371
1372                                         t->redraw |= TREDRAW_SOFT;
1373                                 }
1374                                 break;
1375                         /* Those two are only handled in transform's own handler, see T44634! */
1376                         case TFM_MODAL_EDGESLIDE_UP:
1377                         case TFM_MODAL_EDGESLIDE_DOWN:
1378                         default:
1379                                 break;
1380                 }
1381         }
1382         /* else do non-mapped events */
1383         else if (event->val == KM_PRESS) {
1384                 switch (event->type) {
1385                         case RIGHTMOUSE:
1386                                 t->state = TRANS_CANCEL;
1387                                 handled = true;
1388                                 break;
1389                         /* enforce redraw of transform when modifiers are used */
1390                         case LEFTSHIFTKEY:
1391                         case RIGHTSHIFTKEY:
1392                                 t->modifiers |= MOD_CONSTRAINT_PLANE;
1393                                 t->redraw |= TREDRAW_HARD;
1394                                 handled = true;
1395                                 break;
1396
1397                         case SPACEKEY:
1398                                 t->state = TRANS_CONFIRM;
1399                                 handled = true;
1400                                 break;
1401
1402                         case MIDDLEMOUSE:
1403                                 if ((t->flag & T_NO_CONSTRAINT) == 0) {
1404                                         /* exception for switching to dolly, or trackball, in camera view */
1405                                         if (t->flag & T_CAMERA) {
1406                                                 if (t->mode == TFM_TRANSLATION)
1407                                                         setLocalConstraint(t, (CON_AXIS2), IFACE_("along local Z"));
1408                                                 else if (t->mode == TFM_ROTATION) {
1409                                                         restoreTransObjects(t);
1410                                                         initTrackball(t);
1411                                                 }
1412                                         }
1413                                         else {
1414                                                 t->modifiers |= MOD_CONSTRAINT_SELECT;
1415                                                 if (t->con.mode & CON_APPLY) {
1416                                                         stopConstraint(t);
1417                                                 }
1418                                                 else {
1419                                                         if (event->shift) {
1420                                                                 initSelectConstraint(t, t->spacemtx);
1421                                                         }
1422                                                         else {
1423                                                                 /* bit hackish... but it prevents mmb select to print the orientation from menu */
1424                                                                 float mati[3][3];
1425                                                                 strcpy(t->spacename, "global");
1426                                                                 unit_m3(mati);
1427                                                                 initSelectConstraint(t, mati);
1428                                                         }
1429                                                         postSelectConstraint(t);
1430                                                 }
1431                                         }
1432                                         t->redraw |= TREDRAW_HARD;
1433                                         handled = true;
1434                                 }
1435                                 break;
1436                         case ESCKEY:
1437                                 t->state = TRANS_CANCEL;
1438                                 handled = true;
1439                                 break;
1440                         case PADENTER:
1441                         case RETKEY:
1442                                 t->state = TRANS_CONFIRM;
1443                                 handled = true;
1444                                 break;
1445                         case GKEY:
1446                                 /* only switch when... */
1447                                 if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
1448                                         restoreTransObjects(t);
1449                                         resetTransModal(t);
1450                                         resetTransRestrictions(t);
1451                                         initTranslation(t);
1452                                         initSnapping(t, NULL); // need to reinit after mode change
1453                                         t->redraw |= TREDRAW_HARD;
1454                                         handled = true;
1455                                 }
1456                                 break;
1457                         case SKEY:
1458                                 /* only switch when... */
1459                                 if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
1460                                         restoreTransObjects(t);
1461                                         resetTransModal(t);
1462                                         resetTransRestrictions(t);
1463                                         initResize(t);
1464                                         initSnapping(t, NULL); // need to reinit after mode change
1465                                         t->redraw |= TREDRAW_HARD;
1466                                         handled = true;
1467                                 }
1468                                 break;
1469                         case RKEY:
1470                                 /* only switch when... */
1471                                 if (!(t->options & CTX_TEXTURE)) {
1472                                         if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
1473                                                 restoreTransObjects(t);
1474                                                 resetTransModal(t);
1475                                                 resetTransRestrictions(t);
1476
1477                                                 if (t->mode == TFM_ROTATION) {
1478                                                         initTrackball(t);
1479                                                 }
1480                                                 else {
1481                                                         initRotation(t);
1482                                                 }
1483                                                 initSnapping(t, NULL); // need to reinit after mode change
1484                                                 t->redraw |= TREDRAW_HARD;
1485                                                 handled = true;
1486                                         }
1487                                 }
1488                                 break;
1489                         case CKEY:
1490                                 if (event->alt) {
1491                                         if (!(t->options & CTX_NO_PET)) {
1492                                                 t->flag ^= T_PROP_CONNECTED;
1493                                                 sort_trans_data_dist(t);
1494                                                 calculatePropRatio(t);
1495                                                 t->redraw = TREDRAW_HARD;
1496                                                 handled = true;
1497                                         }
1498                                 }
1499                                 break;
1500                         case OKEY:
1501                                 if (t->flag & T_PROP_EDIT && event->shift) {
1502                                         t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
1503                                         calculatePropRatio(t);
1504                                         t->redraw |= TREDRAW_HARD;
1505                                         handled = true;
1506                                 }
1507                                 break;
1508                         case PADPLUSKEY:
1509                                 if (event->alt && t->flag & T_PROP_EDIT) {
1510                                         t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1511                                         if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
1512                                                 t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
1513                                         calculatePropRatio(t);
1514                                         t->redraw = TREDRAW_HARD;
1515                                         handled = true;
1516                                 }
1517                                 break;
1518                         case PAGEUPKEY:
1519                         case WHEELDOWNMOUSE:
1520                                 if (t->flag & T_AUTOIK) {
1521                                         transform_autoik_update(t, 1);
1522                                 }
1523                                 else {
1524                                         view_editmove(event->type);
1525                                 }
1526                                 t->redraw = TREDRAW_HARD;
1527                                 handled = true;
1528                                 break;
1529                         case PADMINUS:
1530                                 if (event->alt && t->flag & T_PROP_EDIT) {
1531                                         t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1532                                         calculatePropRatio(t);
1533                                         t->redraw = TREDRAW_HARD;
1534                                         handled = true;
1535                                 }
1536                                 break;
1537                         case PAGEDOWNKEY:
1538                         case WHEELUPMOUSE:
1539                                 if (t->flag & T_AUTOIK) {
1540                                         transform_autoik_update(t, -1);
1541                                 }
1542                                 else {
1543                                         view_editmove(event->type);
1544                                 }
1545                                 t->redraw = TREDRAW_HARD;
1546                                 handled = true;
1547                                 break;
1548                         case LEFTALTKEY:
1549                         case RIGHTALTKEY:
1550                                 if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1551                                         t->flag |= T_ALT_TRANSFORM;
1552                                         t->redraw |= TREDRAW_HARD;
1553                                         handled = true;
1554                                 }
1555                                 break;
1556                         case NKEY:
1557                                 if (ELEM(t->mode, TFM_ROTATION)) {
1558                                         if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
1559                                                 restoreTransObjects(t);
1560                                                 resetTransModal(t);
1561                                                 resetTransRestrictions(t);
1562                                                 initNormalRotation(t);
1563                                                 t->redraw = TREDRAW_HARD;
1564                                                 handled = true;
1565                                         }
1566                                 }
1567                                 break;
1568                         default:
1569                                 break;
1570                 }
1571
1572                 /* Snapping key events */
1573                 t->redraw |= handleSnapping(t, event);
1574         }
1575         else if (event->val == KM_RELEASE) {
1576                 switch (event->type) {
1577                         case LEFTSHIFTKEY:
1578                         case RIGHTSHIFTKEY:
1579                                 t->modifiers &= ~MOD_CONSTRAINT_PLANE;
1580                                 t->redraw |= TREDRAW_HARD;
1581                                 handled = true;
1582                                 break;
1583
1584                         case MIDDLEMOUSE:
1585                                 if ((t->flag & T_NO_CONSTRAINT) == 0) {
1586                                         t->modifiers &= ~MOD_CONSTRAINT_SELECT;
1587                                         postSelectConstraint(t);
1588                                         t->redraw |= TREDRAW_HARD;
1589                                         handled = true;
1590                                 }
1591                                 break;
1592                         case LEFTALTKEY:
1593                         case RIGHTALTKEY:
1594                                 if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1595                                         t->flag &= ~T_ALT_TRANSFORM;
1596                                         t->redraw |= TREDRAW_HARD;
1597                                         handled = true;
1598                                 }
1599                                 break;
1600                         default:
1601                                 break;
1602                 }
1603
1604                 /* confirm transform if launch key is released after mouse move */
1605                 if (t->flag & T_RELEASE_CONFIRM) {
1606                         /* XXX Keyrepeat bug in Xorg messes this up, will test when fixed */
1607                         if ((event->type == t->launch_event) && ISMOUSE(t->launch_event)) {
1608                                 t->state = TRANS_CONFIRM;
1609                         }
1610                 }
1611         }
1612
1613         /* if we change snap options, get the unsnapped values back */
1614         if ((t->modifiers   & (MOD_SNAP | MOD_SNAP_INVERT)) !=
1615             (modifiers_prev & (MOD_SNAP | MOD_SNAP_INVERT)))
1616         {
1617                 applyMouseInput(t, &t->mouse, t->mval, t->values);
1618         }
1619
1620         /* Per transform event, if present */
1621         if (t->handleEvent &&
1622             (!handled ||
1623              /* Needed for vertex slide, see [#38756] */
1624              (event->type == MOUSEMOVE)))
1625         {
1626                 t->redraw |= t->handleEvent(t, event);
1627         }
1628
1629         /* Try to init modal numinput now, if possible. */
1630         if (!(handled || t->redraw) && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
1631             handleNumInput(t->context, &(t->num), event))
1632         {
1633                 t->redraw |= TREDRAW_HARD;
1634                 handled = true;
1635         }
1636
1637         if (t->redraw &&
1638             !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
1639         {
1640                 WM_window_status_area_tag_redraw(CTX_wm_window(t->context));
1641         }
1642
1643         if (handled || t->redraw) {
1644                 return 0;
1645         }
1646         else {
1647                 return OPERATOR_PASS_THROUGH;
1648         }
1649 }
1650
1651 bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], float cent2d[2])
1652 {
1653         TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
1654         bool success;
1655
1656         t->context = C;
1657
1658         t->state = TRANS_RUNNING;
1659
1660         /* avoid calculating PET */
1661         t->options = CTX_NO_PET;
1662
1663         t->mode = TFM_DUMMY;
1664
1665         initTransInfo(C, t, NULL, NULL);
1666
1667         /* avoid doing connectivity lookups (when V3D_AROUND_LOCAL_ORIGINS is set) */
1668         t->around = V3D_AROUND_CENTER_BOUNDS;
1669
1670         createTransData(C, t);              // make TransData structs from selection
1671
1672         t->around = centerMode;             // override userdefined mode
1673
1674         if (t->data_len_all == 0) {
1675                 success = false;
1676         }
1677         else {
1678                 success = true;
1679
1680                 calculateCenter(t);
1681
1682                 if (cent2d) {
1683                         copy_v2_v2(cent2d, t->center2d);
1684                 }
1685
1686                 if (cent3d) {
1687                         // Copy center from constraint center. Transform center can be local
1688                         copy_v3_v3(cent3d, t->center_global);
1689                 }
1690         }
1691
1692
1693         /* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
1694         special_aftertrans_update(C, t);
1695
1696         postTrans(C, t);
1697
1698         MEM_freeN(t);
1699
1700         return success;
1701 }
1702
1703 typedef enum {
1704         UP,
1705         DOWN,
1706         LEFT,
1707         RIGHT
1708 } ArrowDirection;
1709
1710 #define POS_INDEX 0
1711 /* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
1712  * private to this file  - merwin
1713  */
1714
1715 static void drawArrow(ArrowDirection d, short offset, short length, short size)
1716 {
1717         immBegin(GPU_PRIM_LINES, 6);
1718
1719         switch (d) {
1720                 case LEFT:
1721                         offset = -offset;
1722                         length = -length;
1723                         size = -size;
1724                         ATTR_FALLTHROUGH;
1725                 case RIGHT:
1726                         immVertex2f(POS_INDEX, offset, 0);
1727                         immVertex2f(POS_INDEX, offset + length, 0);
1728                         immVertex2f(POS_INDEX, offset + length, 0);
1729                         immVertex2f(POS_INDEX, offset + length - size, -size);
1730                         immVertex2f(POS_INDEX, offset + length, 0);
1731                         immVertex2f(POS_INDEX, offset + length - size,  size);
1732                         break;
1733
1734                 case DOWN:
1735                         offset = -offset;
1736                         length = -length;
1737                         size = -size;
1738                         ATTR_FALLTHROUGH;
1739                 case UP:
1740                         immVertex2f(POS_INDEX, 0, offset);
1741                         immVertex2f(POS_INDEX, 0, offset + length);
1742                         immVertex2f(POS_INDEX, 0, offset + length);
1743                         immVertex2f(POS_INDEX, -size, offset + length - size);
1744                         immVertex2f(POS_INDEX, 0, offset + length);
1745                         immVertex2f(POS_INDEX, size, offset + length - size);
1746                         break;
1747         }
1748
1749         immEnd();
1750 }
1751
1752 static void drawArrowHead(ArrowDirection d, short size)
1753 {
1754         immBegin(GPU_PRIM_LINES, 4);
1755
1756         switch (d) {
1757                 case LEFT:
1758                         size = -size;
1759                         ATTR_FALLTHROUGH;
1760                 case RIGHT:
1761                         immVertex2f(POS_INDEX, 0, 0);
1762                         immVertex2f(POS_INDEX, -size, -size);
1763                         immVertex2f(POS_INDEX, 0, 0);
1764                         immVertex2f(POS_INDEX, -size,  size);
1765                         break;
1766
1767                 case DOWN:
1768                         size = -size;
1769                         ATTR_FALLTHROUGH;
1770                 case UP:
1771                         immVertex2f(POS_INDEX, 0, 0);
1772                         immVertex2f(POS_INDEX, -size, -size);
1773                         immVertex2f(POS_INDEX, 0, 0);
1774                         immVertex2f(POS_INDEX, size, -size);
1775                         break;
1776         }
1777
1778         immEnd();
1779 }
1780
1781 static void drawArc(float size, float angle_start, float angle_end, int segments)
1782 {
1783         float delta = (angle_end - angle_start) / segments;
1784         float angle;
1785         int a;
1786
1787         immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
1788
1789         for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
1790                 immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
1791         }
1792         immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
1793
1794         immEnd();
1795 }
1796
1797 static bool helpline_poll(bContext *C)
1798 {
1799         ARegion *ar = CTX_wm_region(C);
1800
1801         if (ar && ar->regiontype == RGN_TYPE_WINDOW)
1802                 return 1;
1803         return 0;
1804 }
1805
1806 static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
1807 {
1808         TransInfo *t = (TransInfo *)customdata;
1809
1810         if (t->helpline != HLP_NONE) {
1811                 float cent[2];
1812                 float mval[3] = {
1813                     x,
1814                     y,
1815                     0.0f,
1816                 };
1817                 float tmval[2] = {
1818                     (float)t->mval[0],
1819                     (float)t->mval[1],
1820                 };
1821
1822                 projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
1823
1824                 /* Offset the values for the area region. */
1825                 const float offset[2] = {
1826                     t->ar->winrct.xmin,
1827                     t->ar->winrct.ymin,
1828                 };
1829
1830                 for (int i = 0; i < 2; i++) {
1831                         cent[i] += offset[i];
1832                         tmval[i] += offset[i];
1833                 }
1834
1835                 GPU_matrix_push();
1836
1837                 /* Dashed lines first. */
1838                 if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
1839                         const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1840
1841                         UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
1842                         BLI_assert(shdr_pos == POS_INDEX);
1843
1844                         GPU_line_width(1.0f);
1845
1846                         immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
1847
1848                         float viewport_size[4];
1849                         GPU_viewport_size_get_f(viewport_size);
1850                         immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1851
1852                         immUniform1i("colors_len", 0);  /* "simple" mode */
1853                         immUniformThemeColor(TH_VIEW_OVERLAY);
1854                         immUniform1f("dash_width", 6.0f);
1855                         immUniform1f("dash_factor", 0.5f);
1856
1857                         immBegin(GPU_PRIM_LINES, 2);
1858                         immVertex2fv(POS_INDEX, cent);
1859                         immVertex2f(POS_INDEX, tmval[0], tmval[1]);
1860                         immEnd();
1861
1862                         immUnbindProgram();
1863                 }
1864
1865                 /* And now, solid lines. */
1866                 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1867                 UNUSED_VARS_NDEBUG(pos); /* silence warning */
1868                 BLI_assert(pos == POS_INDEX);
1869                 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1870
1871                 switch (t->helpline) {
1872                         case HLP_SPRING:
1873                                 immUniformThemeColor(TH_VIEW_OVERLAY);
1874
1875                                 GPU_matrix_translate_3fv(mval);
1876                                 GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
1877
1878                                 GPU_line_width(3.0f);
1879                                 drawArrow(UP, 5, 10, 5);
1880                                 drawArrow(DOWN, 5, 10, 5);
1881                                 break;
1882                         case HLP_HARROW:
1883                                 immUniformThemeColor(TH_VIEW_OVERLAY);
1884                                 GPU_matrix_translate_3fv(mval);
1885
1886                                 GPU_line_width(3.0f);
1887                                 drawArrow(RIGHT, 5, 10, 5);
1888                                 drawArrow(LEFT, 5, 10, 5);
1889                                 break;
1890                         case HLP_VARROW:
1891                                 immUniformThemeColor(TH_VIEW_OVERLAY);
1892
1893                                 GPU_matrix_translate_3fv(mval);
1894
1895                                 GPU_line_width(3.0f);
1896                                 drawArrow(UP, 5, 10, 5);
1897                                 drawArrow(DOWN, 5, 10, 5);
1898                                 break;
1899                         case HLP_ANGLE:
1900                         {
1901                                 float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
1902                                 float angle = atan2f(dy, dx);
1903                                 float dist = hypotf(dx, dy);
1904                                 float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
1905                                 float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
1906
1907                                 immUniformThemeColor(TH_VIEW_OVERLAY);
1908
1909                                 GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
1910
1911                                 GPU_line_width(3.0f);
1912                                 drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
1913                                 drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
1914
1915                                 GPU_matrix_push();
1916
1917                                 GPU_matrix_translate_3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
1918                                 GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
1919
1920                                 drawArrowHead(DOWN, 5);
1921
1922                                 GPU_matrix_pop();
1923
1924                                 GPU_matrix_translate_3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
1925                                 GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
1926
1927                                 drawArrowHead(UP, 5);
1928                                 break;
1929                         }
1930                         case HLP_TRACKBALL:
1931                         {
1932                                 unsigned char col[3], col2[3];
1933                                 UI_GetThemeColor3ubv(TH_GRID, col);
1934
1935                                 GPU_matrix_translate_3fv(mval);
1936
1937                                 GPU_line_width(3.0f);
1938
1939                                 UI_make_axis_color(col, col2, 'X');
1940                                 immUniformColor3ubv(col2);
1941
1942                                 drawArrow(RIGHT, 5, 10, 5);
1943                                 drawArrow(LEFT, 5, 10, 5);
1944
1945                                 UI_make_axis_color(col, col2, 'Y');
1946                                 immUniformColor3ubv(col2);
1947
1948                                 drawArrow(UP, 5, 10, 5);
1949                                 drawArrow(DOWN, 5, 10, 5);
1950                                 break;
1951                         }
1952                 }
1953
1954                 immUnbindProgram();
1955                 GPU_matrix_pop();
1956         }
1957 }
1958
1959 static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
1960 {
1961         TransInfo *t = arg;
1962
1963         GPU_line_width(1.0f);
1964
1965         drawConstraint(t);
1966         drawPropCircle(C, t);
1967         drawSnapping(C, t);
1968
1969         /* edge slide, vert slide */
1970         drawEdgeSlide(t);
1971         drawVertSlide(t);
1972 }
1973
1974 /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
1975 static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
1976 {
1977         rcti rect;
1978         const char *printable = IFACE_("Auto Keying On");
1979         float      printable_size[2];
1980         int xco, yco;
1981
1982         ED_region_visible_rect(ar, &rect);
1983
1984         const int font_id = BLF_default();
1985         BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
1986
1987         xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
1988         yco = (rect.ymax - U.widget_unit);
1989
1990         /* warning text (to clarify meaning of overlays)
1991          * - original color was red to match the icon, but that clashes badly with a less nasty border
1992          */
1993         unsigned char color[3];
1994         UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
1995         BLF_color3ubv(font_id, color);
1996 #ifdef WITH_INTERNATIONAL
1997         BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
1998 #else
1999         BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
2000 #endif
2001
2002         /* autokey recording icon... */
2003         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
2004         GPU_blend(true);
2005
2006         xco -= U.widget_unit;
2007         yco -= (int)printable_size[1] / 2;
2008
2009         UI_icon_draw(xco, yco, ICON_REC);
2010
2011         GPU_blend(false);
2012 }
2013
2014 static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg)
2015 {
2016         TransInfo *t = arg;
2017         Scene *scene = t->scene;
2018         ViewLayer *view_layer = t->view_layer;
2019         Object *ob = OBACT(view_layer);
2020
2021         /* draw autokeyframing hint in the corner
2022          * - only draw if enabled (advanced users may be distracted/annoyed),
2023          *   for objects that will be autokeyframed (no point ohterwise),
2024          *   AND only for the active region (as showing all is too overwhelming)
2025          */
2026         if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
2027                 if (ar == t->ar) {
2028                         if (t->flag & (T_OBJECT | T_POSE)) {
2029                                 if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
2030                                         drawAutoKeyWarning(t, ar);
2031                                 }
2032                         }
2033                 }
2034         }
2035 }
2036
2037 /**
2038  * \see #initTransform which reads values from the operator.
2039  */
2040 void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
2041 {
2042         ToolSettings *ts = CTX_data_tool_settings(C);
2043         bool constraint_axis[3] = {false, false, false};
2044         int proportional = 0;
2045         PropertyRNA *prop;
2046
2047         // Save back mode in case we're in the generic operator
2048         if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
2049                 RNA_property_enum_set(op->ptr, prop, t->mode);
2050         }
2051
2052         if ((prop = RNA_struct_find_property(op->ptr, "value"))) {
2053                 float values[4];
2054
2055                 copy_v4_v4(values, (t->flag & T_AUTOVALUES) ? t->auto_values : t->values);
2056
2057                 if (RNA_property_array_check(prop)) {
2058                         RNA_property_float_set_array(op->ptr, prop, values);
2059                 }
2060                 else {
2061                         RNA_property_float_set(op->ptr, prop, values[0]);
2062                 }
2063         }
2064
2065         /* convert flag to enum */
2066         switch (t->flag & T_PROP_EDIT_ALL) {
2067                 case T_PROP_EDIT:
2068                         proportional = PROP_EDIT_ON;
2069                         break;
2070                 case (T_PROP_EDIT | T_PROP_CONNECTED):
2071                         proportional = PROP_EDIT_CONNECTED;
2072                         break;
2073                 case (T_PROP_EDIT | T_PROP_PROJECTED):
2074                         proportional = PROP_EDIT_PROJECTED;
2075                         break;
2076                 default:
2077                         proportional = PROP_EDIT_OFF;
2078                         break;
2079         }
2080
2081         // If modal, save settings back in scene if not set as operator argument
2082         if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
2083                 /* save settings if not set in operator */
2084
2085                 /* skip saving proportional edit if it was not actually used */
2086                 if (!(t->options & CTX_NO_PET)) {
2087                         if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
2088                             !RNA_property_is_set(op->ptr, prop))
2089                         {
2090                                 if (t->spacetype == SPACE_IPO)
2091                                         ts->proportional_fcurve = proportional;
2092                                 else if (t->spacetype == SPACE_ACTION)
2093                                         ts->proportional_action = proportional;
2094                                 else if (t->obedit_type != -1)
2095                                         ts->proportional = proportional;
2096                                 else if (t->options & CTX_MASK)
2097                                         ts->proportional_mask = (proportional != PROP_EDIT_OFF);
2098                                 else
2099                                         ts->proportional_objects = (proportional != PROP_EDIT_OFF);
2100                         }
2101
2102                         if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) {
2103                                 ts->proportional_size =
2104                                         RNA_property_is_set(op->ptr, prop) ? RNA_property_float_get(op->ptr, prop) : t->prop_size;
2105                         }
2106
2107                         if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
2108                             !RNA_property_is_set(op->ptr, prop))
2109                         {
2110                                 ts->prop_mode = t->prop_mode;
2111                         }
2112                 }
2113
2114                 /* do we check for parameter? */
2115                 if (t->modifiers & MOD_SNAP) {
2116                         ts->snap_flag |= SCE_SNAP;
2117                 }
2118                 else {
2119                         ts->snap_flag &= ~SCE_SNAP;
2120                 }
2121
2122                 if (t->spacetype == SPACE_VIEW3D) {
2123                         if ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
2124                             !RNA_property_is_set(op->ptr, prop))
2125                         {
2126                                 t->scene->orientation_type = t->current_orientation;
2127                                 BLI_assert(((t->scene->orientation_index_custom == -1) && (t->custom_orientation == NULL)) ||
2128                                            (BKE_scene_transform_orientation_get_index(
2129                                                     t->scene, t->custom_orientation) == t->scene->orientation_index_custom));
2130                         }
2131                 }
2132         }
2133
2134         if ((prop = RNA_struct_find_property(op->ptr, "proportional"))) {
2135                 RNA_property_enum_set(op->ptr, prop, proportional);
2136                 RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
2137                 RNA_float_set(op->ptr, "proportional_size", t->prop_size);
2138         }
2139
2140         if ((prop = RNA_struct_find_property(op->ptr, "axis"))) {
2141                 RNA_property_float_set_array(op->ptr, prop, t->axis);
2142         }
2143
2144         if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
2145                 RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0);
2146         }
2147
2148         if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
2149                 /* constraint orientation can be global, even if user selects something else
2150                  * so use the orientation in the constraint if set */
2151                 short orientation = (t->con.mode & CON_APPLY) ? t->con.orientation : t->current_orientation;
2152
2153                 if (orientation == V3D_MANIP_CUSTOM) {
2154                         const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
2155                                 t->scene, t->custom_orientation);
2156
2157                         /* Maybe we need a t->con.custom_orientation? Seems like it would always match t->custom_orientation. */
2158                         orientation = V3D_MANIP_CUSTOM + orientation_index_custom;
2159                         BLI_assert(orientation >= V3D_MANIP_CUSTOM);
2160                 }
2161                 RNA_enum_set(op->ptr, "constraint_orientation", orientation);
2162
2163                 if (t->con.mode & CON_APPLY) {
2164                         if (t->con.mode & CON_AXIS0) {
2165                                 constraint_axis[0] = true;
2166                         }
2167                         if (t->con.mode & CON_AXIS1) {
2168                                 constraint_axis[1] = true;
2169                         }
2170                         if (t->con.mode & CON_AXIS2) {
2171                                 constraint_axis[2] = true;
2172                         }
2173                 }
2174
2175                 RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
2176         }
2177
2178         {
2179                 const char *prop_id = NULL;
2180                 if (t->mode == TFM_SHRINKFATTEN) {
2181                         prop_id = "use_even_offset";
2182                 }
2183
2184                 if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
2185
2186                         RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
2187                 }
2188         }
2189
2190         if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
2191                 RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
2192         }
2193 }
2194
2195 /**
2196  * \note  caller needs to free 't' on a 0 return
2197  * \warning  \a event might be NULL (when tweaking from redo panel)
2198  * \see #saveTransform which writes these values back.
2199  */
2200 bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
2201 {
2202         int options = 0;
2203         PropertyRNA *prop;
2204
2205         t->context = C;
2206
2207         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
2208
2209         t->state = TRANS_STARTING;
2210
2211         if ((prop = RNA_struct_find_property(op->ptr, "cursor_transform")) && RNA_property_is_set(op->ptr, prop)) {
2212                 if (RNA_property_boolean_get(op->ptr, prop)) {
2213                         options |= CTX_CURSOR;
2214                 }
2215         }
2216
2217         if ((prop = RNA_struct_find_property(op->ptr, "texture_space")) && RNA_property_is_set(op->ptr, prop)) {
2218                 if (RNA_property_boolean_get(op->ptr, prop)) {
2219                         options |= CTX_TEXTURE;
2220                 }
2221         }
2222
2223         if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) && RNA_property_is_set(op->ptr, prop)) {
2224                 if (RNA_property_boolean_get(op->ptr, prop)) {
2225                         options |= CTX_GPENCIL_STROKES;
2226                 }
2227         }
2228
2229         t->options = options;
2230
2231         t->mode = mode;
2232
2233         /* Needed to translate tweak events to mouse buttons. */
2234         t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
2235
2236         // XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0)
2237         // For gizmo only, so assume LEFTMOUSE
2238         if (t->launch_event == 0) {
2239                 t->launch_event = LEFTMOUSE;
2240         }
2241
2242         unit_m3(t->spacemtx);
2243
2244         initTransInfo(C, t, op, event);
2245         initTransformOrientation(C, t);
2246
2247         if (t->spacetype == SPACE_VIEW3D) {
2248                 t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
2249                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2250                 t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
2251                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2252         }
2253         else if (t->spacetype == SPACE_IMAGE) {
2254                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2255                 //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
2256                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2257         }
2258         else if (t->spacetype == SPACE_CLIP) {
2259                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2260                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2261         }
2262         else if (t->spacetype == SPACE_NODE) {
2263                 /*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
2264                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2265                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2266         }
2267         else if (t->spacetype == SPACE_IPO) {
2268                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2269                 //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
2270                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2271         }
2272         else if (t->spacetype == SPACE_ACTION) {
2273                 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2274                 //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
2275                 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
2276         }
2277
2278         createTransData(C, t);          // make TransData structs from selection
2279
2280         if (t->data_len_all == 0) {
2281                 postTrans(C, t);
2282                 return 0;
2283         }
2284
2285         if (event) {
2286                 /* keymap for shortcut header prints */
2287                 t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
2288
2289                 /* Stupid code to have Ctrl-Click on gizmo work ok
2290                  *
2291                  * do this only for translation/rotation/resize due to only this
2292                  * moded are available from gizmo and doing such check could
2293                  * lead to keymap conflicts for other modes (see #31584)
2294                  */
2295                 if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
2296                         wmKeyMapItem *kmi;
2297
2298                         for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
2299                                 if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
2300                                         if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) &&   event->ctrl)  ||
2301                                             (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) ||
2302                                             (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) &&     event->alt)   ||
2303                                             ((kmi->type == OSKEY) &&                         event->oskey) )
2304                                         {
2305                                                 t->modifiers |= MOD_SNAP_INVERT;
2306                                         }
2307                                         break;
2308                                 }
2309                         }
2310                 }
2311         }
2312
2313         initSnapping(t, op); // Initialize snapping data AFTER mode flags
2314
2315         initSnapSpatial(t, t->snap_spatial);
2316
2317         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
2318         /* EVIL2: we gave as argument also texture space context bit... was cleared */
2319         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
2320         mode = t->mode;
2321
2322         calculatePropRatio(t);
2323         calculateCenter(t);
2324
2325         /* Overwrite initial values if operator supplied a non-null vector.
2326          *
2327          * Run before init functions so 'values_modal_offset' can be applied on mouse input.
2328          */
2329         BLI_assert(is_zero_v4(t->values_modal_offset));
2330         if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
2331                 float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
2332
2333                 if (RNA_property_array_check(prop)) {
2334                         RNA_float_get_array(op->ptr, "value", values);
2335                 }
2336                 else {
2337                         values[0] = RNA_float_get(op->ptr, "value");
2338                 }
2339
2340                 copy_v4_v4(t->values, values);
2341
2342                 if (t->flag & T_MODAL) {
2343                         copy_v4_v4(t->values_modal_offset, values);
2344                         t->redraw = TREDRAW_HARD;
2345                 }
2346                 else {
2347                         copy_v4_v4(t->auto_values, values);
2348                         t->flag |= T_AUTOVALUES;
2349                 }
2350         }
2351
2352         /* Transformation axis from operator */
2353         if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
2354                 RNA_property_float_get_array(op->ptr, prop, t->axis);
2355                 normalize_v3(t->axis);
2356                 copy_v3_v3(t->axis_orig, t->axis);
2357         }
2358
2359         /* Constraint init from operator */
2360         if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
2361                 bool constraint_axis[3];
2362
2363                 RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
2364
2365                 if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
2366                         t->con.mode |= CON_APPLY;
2367
2368                         if (constraint_axis[0]) {
2369                                 t->con.mode |= CON_AXIS0;
2370                         }
2371                         if (constraint_axis[1]) {
2372                                 t->con.mode |= CON_AXIS1;
2373                         }
2374                         if (constraint_axis[2]) {
2375                                 t->con.mode |= CON_AXIS2;
2376                         }
2377
2378                         setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
2379                 }
2380         }
2381
2382         if (event) {
2383                 /* Initialize accurate transform to settings requested by keymap. */
2384                 bool use_accurate = false;
2385                 if ((prop = RNA_struct_find_property(op->ptr, "use_accurate")) && RNA_property_is_set(op->ptr, prop)) {
2386                         if (RNA_property_boolean_get(op->ptr, prop)) {
2387                                 use_accurate = true;
2388                         }
2389                 }
2390                 initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
2391         }
2392
2393         switch (mode) {
2394                 case TFM_TRANSLATION:
2395                         initTranslation(t);
2396                         break;
2397                 case TFM_ROTATION:
2398                         initRotation(t);
2399                         break;
2400                 case TFM_RESIZE:
2401                         initResize(t);
2402                         break;
2403                 case TFM_SKIN_RESIZE:
2404                         initSkinResize(t);
2405                         break;
2406                 case TFM_TOSPHERE:
2407                         initToSphere(t);
2408                         break;
2409                 case TFM_SHEAR:
2410                         initShear(t);
2411                         break;
2412                 case TFM_BEND:
2413                         initBend(t);
2414                         break;
2415                 case TFM_SHRINKFATTEN:
2416                         initShrinkFatten(t);
2417                         break;
2418                 case TFM_TILT:
2419                         initTilt(t);
2420                         break;
2421                 case TFM_CURVE_SHRINKFATTEN:
2422                         initCurveShrinkFatten(t);
2423                         break;
2424                 case TFM_MASK_SHRINKFATTEN:
2425                         initMaskShrinkFatten(t);
2426                         break;
2427                 case TFM_GPENCIL_SHRINKFATTEN:
2428                         initGPShrinkFatten(t);
2429                         break;
2430                 case TFM_TRACKBALL:
2431                         initTrackball(t);
2432                         break;
2433                 case TFM_PUSHPULL:
2434                         initPushPull(t);
2435                         break;
2436                 case TFM_CREASE:
2437                         initCrease(t);
2438                         break;
2439                 case TFM_BONESIZE:
2440                 {   /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
2441                         /* Note: we have to pick one, use the active object. */
2442                         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
2443                         bArmature *arm = tc->poseobj->data;
2444                         if (arm->drawtype == ARM_ENVELOPE) {
2445                                 initBoneEnvelope(t);
2446                                 t->mode = TFM_BONE_ENVELOPE_DIST;
2447                         }
2448                         else {
2449                                 initBoneSize(t);
2450                         }
2451                         break;
2452                 }
2453                 case TFM_BONE_ENVELOPE:
2454                         initBoneEnvelope(t);
2455                         break;
2456                 case TFM_BONE_ENVELOPE_DIST:
2457                         initBoneEnvelope(t);
2458                         t->mode = TFM_BONE_ENVELOPE_DIST;
2459                         break;
2460                 case TFM_EDGE_SLIDE:
2461                 case TFM_VERT_SLIDE:
2462                 {
2463                         const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
2464                         const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
2465                         const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
2466                         if (mode == TFM_EDGE_SLIDE) {
2467                                 const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
2468                                 initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
2469                         }
2470                         else {
2471                                 initVertSlide_ex(t, use_even, flipped, use_clamp);
2472                         }
2473                         break;
2474                 }
2475                 case TFM_BONE_ROLL:
2476                         initBoneRoll(t);
2477                         break;
2478                 case TFM_TIME_TRANSLATE:
2479                         initTimeTranslate(t);
2480                         break;
2481                 case TFM_TIME_SLIDE:
2482                         initTimeSlide(t);
2483                         break;
2484                 case TFM_TIME_SCALE:
2485                         initTimeScale(t);
2486                         break;
2487                 case TFM_TIME_DUPLICATE:
2488                         /* same as TFM_TIME_EXTEND, but we need the mode info for later
2489                          * so that duplicate-culling will work properly
2490                          */
2491                         if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA))
2492                                 initTranslation(t);
2493                         else
2494                                 initTimeTranslate(t);
2495                         t->mode = mode;
2496                         break;
2497                 case TFM_TIME_EXTEND:
2498                         /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
2499                          * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
2500                          * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
2501                          * depending on which editor this was called from
2502                          */
2503                         if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA))
2504                                 initTranslation(t);
2505                         else
2506                                 initTimeTranslate(t);
2507                         break;
2508                 case TFM_BAKE_TIME:
2509                         initBakeTime(t);
2510                         break;
2511                 case TFM_MIRROR:
2512                         initMirror(t);
2513                         break;
2514                 case TFM_BWEIGHT:
2515                         initBevelWeight(t);
2516                         break;
2517                 case TFM_ALIGN:
2518                         initAlign(t);
2519                         break;
2520                 case TFM_SEQ_SLIDE:
2521                         initSeqSlide(t);
2522                         break;
2523                 case TFM_NORMAL_ROTATION:
2524                         initNormalRotation(t);
2525                         break;
2526         }
2527
2528         if (t->state == TRANS_CANCEL) {
2529                 postTrans(C, t);
2530                 return 0;
2531         }
2532
2533         if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) {
2534                 if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
2535
2536                         FOREACH_TRANS_DATA_CONTAINER(t, tc) {
2537                                 if ((((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH)) {
2538                                         BMEditMesh *em = NULL;// BKE_editmesh_from_object(t->obedit);
2539                                         bool do_skip = false;
2540
2541                                         /* Currently only used for two of three most frequent transform ops, can include more ops.
2542                                         * Note that scaling cannot be included here, non-uniform scaling will affect normals. */
2543                                         if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
2544                                                 if (em->bm->totvertsel == em->bm->totvert) {
2545                                                         /* No need to invalidate if whole mesh is selected. */
2546                                                         do_skip = true;
2547                                                 }
2548                                         }
2549
2550                                         if (t->flag & T_MODAL) {
2551                                                 RNA_property_boolean_set(op->ptr, prop, false);
2552                                         }
2553                                         else if (!do_skip) {
2554                                                 const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
2555                                                 if (preserve_clnor) {
2556                                                         BKE_editmesh_lnorspace_update(em);
2557                                                         t->flag |= T_CLNOR_REBUILD;
2558                                                 }
2559                                                 BM_lnorspace_invalidate(em->bm, true);
2560                                         }
2561                                 }
2562                         }
2563                 }
2564         }
2565
2566         t->context = NULL;
2567
2568         return 1;
2569 }
2570
2571 void transformApply(bContext *C, TransInfo *t)
2572 {
2573         t->context = C;
2574
2575         if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
2576                 selectConstraint(t);
2577                 if (t->transform) {
2578                         t->transform(t, t->mval);  // calls recalcData()
2579                         viewRedrawForce(C, t);
2580                 }
2581                 t->redraw = TREDRAW_NOTHING;
2582         }
2583         else if (t->redraw & TREDRAW_SOFT) {
2584                 viewRedrawForce(C, t);
2585         }
2586
2587         /* If auto confirm is on, break after one pass */
2588         if (t->options & CTX_AUTOCONFIRM) {
2589                 t->state = TRANS_CONFIRM;
2590         }
2591
2592         t->context = NULL;
2593 }
2594
2595 static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg)
2596 {
2597         TransInfo *t = arg;
2598
2599         if (t->redraw & TREDRAW_SOFT) {
2600                 t->redraw |= TREDRAW_HARD;
2601                 transformApply((bContext *)C, t);
2602         }
2603 }
2604
2605 int transformEnd(bContext *C, TransInfo *t)
2606 {
2607         int exit_code = OPERATOR_RUNNING_MODAL;
2608
2609         t->context = C;
2610
2611         if (t->state != TRANS_STARTING && t->state != TRANS_RUNNING) {
2612                 /* handle restoring objects */
2613                 if (t->state == TRANS_CANCEL) {
2614                         /* exception, edge slide transformed UVs too */
2615                         if (t->mode == TFM_EDGE_SLIDE) {
2616                                 doEdgeSlide(t, 0.0f);
2617                         }
2618                         else if (t->mode == TFM_VERT_SLIDE) {
2619                                 doVertSlide(t, 0.0f);
2620                         }
2621
2622                         exit_code = OPERATOR_CANCELLED;
2623                         restoreTransObjects(t); // calls recalcData()
2624                 }
2625                 else {
2626                         if (t->flag & T_CLNOR_REBUILD) {
2627                                 FOREACH_TRANS_DATA_CONTAINER(t, tc) {
2628                                         BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
2629                                         BM_lnorspace_rebuild(em->bm, true);
2630                                 }
2631                         }
2632                         exit_code = OPERATOR_FINISHED;
2633                 }
2634
2635                 /* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
2636                 special_aftertrans_update(C, t);
2637
2638                 /* free data */
2639                 postTrans(C, t);
2640
2641                 /* send events out for redraws */
2642                 viewRedrawPost(C, t);
2643
2644                 viewRedrawForce(C, t);
2645         }
2646
2647         t->context = NULL;
2648
2649         return exit_code;
2650 }
2651
2652 /* ************************** TRANSFORM LOCKS **************************** */
2653
2654 static void protectedTransBits(short protectflag, float vec[3])
2655 {
2656         if (protectflag & OB_LOCK_LOCX)
2657                 vec[0] = 0.0f;
2658         if (protectflag & OB_LOCK_LOCY)
2659                 vec[1] = 0.0f;
2660         if (protectflag & OB_LOCK_LOCZ)
2661                 vec[2] = 0.0f;
2662 }
2663
2664 static void protectedSizeBits(short protectflag, float size[3])
2665 {
2666         if (protectflag & OB_LOCK_SCALEX)
2667                 size[0] = 1.0f;
2668         if (protectflag & OB_LOCK_SCALEY)
2669                 size[1] = 1.0f;
2670         if (protectflag & OB_LOCK_SCALEZ)
2671                 size[2] = 1.0f;
2672 }
2673
2674 static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
2675 {
2676         if (protectflag & OB_LOCK_ROTX)
2677                 eul[0] = oldeul[0];
2678         if (protectflag & OB_LOCK_ROTY)
2679                 eul[1] = oldeul[1];
2680         if (protectflag & OB_LOCK_ROTZ)
2681                 eul[2] = oldeul[2];
2682 }
2683
2684
2685 /* this function only does the delta rotation */
2686 /* axis-angle is usually internally stored as quats... */
2687 static void protectedAxisAngleBits(short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle)
2688 {
2689         /* check that protection flags are set */
2690         if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0)
2691                 return;
2692
2693         if (protectflag & OB_LOCK_ROT4D) {
2694                 /* axis-angle getting limited as 4D entities that they are... */
2695                 if (protectflag & OB_LOCK_ROTW)
2696                         *angle = oldAngle;
2697                 if (protectflag & OB_LOCK_ROTX)
2698                         axis[0] = oldAxis[0];
2699                 if (protectflag & OB_LOCK_ROTY)
2700                         axis[1] = oldAxis[1];
2701                 if (protectflag & OB_LOCK_ROTZ)
2702                         axis[2] = oldAxis[2];
2703         }
2704         else {
2705                 /* axis-angle get limited with euler... */
2706                 float eul[3], oldeul[3];
2707
2708                 axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
2709                 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
2710
2711                 if (protectflag & OB_LOCK_ROTX)
2712                         eul[0] = oldeul[0];
2713                 if (protectflag & OB_LOCK_ROTY)
2714                         eul[1] = oldeul[1];
2715                 if (protectflag & OB_LOCK_ROTZ)
2716                         eul[2] = oldeul[2];
2717
2718                 eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
2719
2720                 /* when converting to axis-angle, we need a special exception for the case when there is no axis */
2721                 if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
2722                         /* for now, rotate around y-axis then (so that it simply becomes the roll) */
2723                         axis[1] = 1.0f;
2724                 }
2725         }
2726 }
2727
2728 /* this function only does the delta rotation */
2729 static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
2730 {
2731         /* check that protection flags are set */
2732         if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0)
2733                 return;
2734
2735         if (protectflag & OB_LOCK_ROT4D) {
2736                 /* quaternions getting limited as 4D entities that they are... */
2737                 if (protectflag & OB_LOCK_ROTW)
2738                         quat[0] = oldquat[0];
2739                 if (protectflag & OB_LOCK_ROTX)
2740                         quat[1] = oldquat[1];
2741                 if (protectflag & OB_LOCK_ROTY)
2742                         quat[2] = oldquat[2];
2743                 if (protectflag & OB_LOCK_ROTZ)
2744                         quat[3] = oldquat[3];
2745         }
2746         else {
2747                 /* quaternions get limited with euler... (compatibility mode) */
2748                 float eul[3], oldeul[3], nquat[4], noldquat[4];
2749                 float qlen;
2750
2751                 qlen = normalize_qt_qt(nquat, quat);
2752                 normalize_qt_qt(noldquat, oldquat);
2753
2754                 quat_to_eul(eul, nquat);
2755                 quat_to_eul(oldeul, noldquat);
2756
2757                 if (protectflag & OB_LOCK_ROTX)
2758                         eul[0] = oldeul[0];
2759                 if (protectflag & OB_LOCK_ROTY)
2760                         eul[1] = oldeul[1];
2761                 if (protectflag & OB_LOCK_ROTZ)
2762                         eul[2] = oldeul[2];
2763
2764                 eul_to_quat(quat, eul);
2765
2766                 /* restore original quat size */
2767                 mul_qt_fl(quat, qlen);
2768
2769                 /* quaternions flip w sign to accumulate rotations correctly */
2770                 if ((nquat[0] < 0.0f && quat[0] > 0.0f) ||
2771                     (nquat[0] > 0.0f && quat[0] < 0.0f))
2772                 {
2773                         mul_qt_fl(quat, -1.0f);
2774                 }
2775         }
2776 }
2777
2778 /* ******************* TRANSFORM LIMITS ********************** */
2779
2780 static void constraintTransLim(TransInfo *t, TransData *td)
2781 {
2782         if (td->con) {
2783                 const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
2784                 const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
2785
2786                 bConstraintOb cob = {NULL};
2787                 bConstraint *con;
2788                 float ctime = (float)(t->scene->r.cfra);
2789
2790                 /* Make a temporary bConstraintOb for using these limit constraints
2791                  *  - they only care that cob->matrix is correctly set ;-)
2792                  *      - current space should be local
2793                  */
2794                 unit_m4(cob.matrix);
2795                 copy_v3_v3(cob.matrix[3], td->loc);
2796
2797                 /* Evaluate valid constraints */
2798                 for (con = td->con; con; con = con->next) {
2799                         const bConstraintTypeInfo *cti = NULL;
2800                         ListBase targets = {NULL, NULL};
2801
2802                         /* only consider constraint if enabled */
2803                         if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
2804                         if (con->enforce == 0.0f) continue;
2805
2806                         /* only use it if it's tagged for this purpose (and the right type) */
2807                         if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
2808                                 bLocLimitConstraint *data = con->data;
2809
2810                                 if ((data->flag2 & LIMIT_TRANSFORM) == 0)
2811                                         continue;
2812                                 cti = ctiLoc;
2813                         }
2814                         else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
2815                                 bDistLimitConstraint *data = con->data;
2816
2817                                 if ((data->flag & LIMITDIST_TRANSFORM) == 0)
2818                                         continue;
2819                                 cti = ctiDist;
2820                         }
2821
2822                         if (cti) {
2823                                 /* do space conversions */
2824                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2825                                         /* just multiply by td->mtx (this should be ok) */
2826                                         mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
2827                                 }
2828                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
2829                                         /* skip... incompatable spacetype */
2830                                         continue;
2831                                 }
2832
2833                                 /* get constraint targets if needed */
2834                                 BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
2835
2836                                 /* do constraint */
2837                                 cti->evaluate_constraint(con, &cob, &targets);
2838
2839                                 /* convert spaces again */
2840                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2841                                         /* just multiply by td->smtx (this should be ok) */
2842                                         mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
2843                                 }
2844
2845                                 /* free targets list */
2846                                 BLI_freelistN(&targets);
2847                         }
2848                 }
2849
2850                 /* copy results from cob->matrix */
2851                 copy_v3_v3(td->loc, cob.matrix[3]);
2852         }
2853 }
2854
2855 static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
2856 {
2857         /* Make a temporary bConstraintOb for use by limit constraints
2858          *  - they only care that cob->matrix is correctly set ;-)
2859          *      - current space should be local
2860          */
2861         memset(cob, 0, sizeof(bConstraintOb));
2862         if (td->ext) {
2863                 if (td->ext->rotOrder == ROT_MODE_QUAT) {
2864                         /* quats */
2865                         /* objects and bones do normalization first too, otherwise
2866                          * we don't necessarily end up with a rotation matrix, and
2867                          * then conversion back to quat gives a different result */
2868                         float quat[4];
2869                         normalize_qt_qt(quat, td->ext->quat);
2870                         quat_to_mat4(cob->matrix, quat);
2871                 }
2872                 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2873        &