b493bbe886788b00f10bc60d2a73703d58e7cd61
[blender.git] / source / blender / editors / transform / transform.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edtransform
22  */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <math.h>
28 #include <float.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_anim_types.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_constraint_types.h"
35 #include "DNA_mask_types.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_movieclip_types.h"
38 #include "DNA_scene_types.h" /* PET modes */
39 #include "DNA_workspace_types.h"
40 #include "DNA_gpencil_types.h"
41
42 #include "BLI_alloca.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_math.h"
45 #include "BLI_rect.h"
46 #include "BLI_listbase.h"
47 #include "BLI_string.h"
48 #include "BLI_ghash.h"
49 #include "BLI_utildefines_stack.h"
50 #include "BLI_memarena.h"
51
52 #include "BKE_nla.h"
53 #include "BKE_editmesh.h"
54 #include "BKE_editmesh_bvh.h"
55 #include "BKE_context.h"
56 #include "BKE_constraint.h"
57 #include "BKE_particle.h"
58 #include "BKE_unit.h"
59 #include "BKE_scene.h"
60 #include "BKE_mask.h"
61 #include "BKE_mesh.h"
62 #include "BKE_report.h"
63 #include "BKE_workspace.h"
64
65 #include "DEG_depsgraph.h"
66
67 #include "GPU_immediate.h"
68 #include "GPU_matrix.h"
69 #include "GPU_state.h"
70
71 #include "ED_image.h"
72 #include "ED_keyframing.h"
73 #include "ED_screen.h"
74 #include "ED_space_api.h"
75 #include "ED_view3d.h"
76 #include "ED_mesh.h"
77 #include "ED_clip.h"
78 #include "ED_node.h"
79 #include "ED_gpencil.h"
80 #include "ED_sculpt.h"
81
82 #include "WM_types.h"
83 #include "WM_api.h"
84
85 #include "UI_view2d.h"
86 #include "UI_interface.h"
87 #include "UI_interface_icons.h"
88 #include "UI_resources.h"
89
90 #include "RNA_access.h"
91 #include "RNA_define.h"
92
93 #include "BLF_api.h"
94 #include "BLT_translation.h"
95
96 #include "transform.h"
97 #include "transform_convert.h"
98 #include "transform_snap.h"
99
100 /* Disabling, since when you type you know what you are doing,
101  * and being able to set it to zero is handy. */
102 // #define USE_NUM_NO_ZERO
103
104 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
105 static void doEdgeSlide(TransInfo *t, float perc);
106 static void doVertSlide(TransInfo *t, float perc);
107
108 static void drawEdgeSlide(TransInfo *t);
109 static void drawVertSlide(TransInfo *t);
110 static void postInputRotation(TransInfo *t, float values[3]);
111
112 static void ElementRotation(
113     TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
114 static void initSnapSpatial(TransInfo *t, float r_snap[3]);
115
116 static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm);
117
118 /* Transform Callbacks */
119 static void initBend(TransInfo *t);
120 static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event);
121 static void Bend(TransInfo *t, const int mval[2]);
122
123 static void initShear(TransInfo *t);
124 static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event);
125 static void applyShear(TransInfo *t, const int mval[2]);
126
127 static void initResize(TransInfo *t);
128 static void applyResize(TransInfo *t, const int mval[2]);
129
130 static void initSkinResize(TransInfo *t);
131 static void applySkinResize(TransInfo *t, const int mval[2]);
132
133 static void initTranslation(TransInfo *t);
134 static void applyTranslation(TransInfo *t, const int mval[2]);
135
136 static void initToSphere(TransInfo *t);
137 static void applyToSphere(TransInfo *t, const int mval[2]);
138
139 static void initRotation(TransInfo *t);
140 static void applyRotation(TransInfo *t, const int mval[2]);
141
142 static void initNormalRotation(TransInfo *t);
143 static void applyNormalRotation(TransInfo *t, const int mval[2]);
144
145 static void initShrinkFatten(TransInfo *t);
146 static void applyShrinkFatten(TransInfo *t, const int mval[2]);
147
148 static void initTilt(TransInfo *t);
149 static void applyTilt(TransInfo *t, const int mval[2]);
150
151 static void initCurveShrinkFatten(TransInfo *t);
152 static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]);
153
154 static void initMaskShrinkFatten(TransInfo *t);
155 static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]);
156
157 static void initGPShrinkFatten(TransInfo *t);
158 static void applyGPShrinkFatten(TransInfo *t, const int mval[2]);
159
160 static void initTrackball(TransInfo *t);
161 static void applyTrackball(TransInfo *t, const int mval[2]);
162
163 static void initPushPull(TransInfo *t);
164 static void applyPushPull(TransInfo *t, const int mval[2]);
165
166 static void initBevelWeight(TransInfo *t);
167 static void applyBevelWeight(TransInfo *t, const int mval[2]);
168
169 static void initCrease(TransInfo *t);
170 static void applyCrease(TransInfo *t, const int mval[2]);
171
172 static void initBoneSize(TransInfo *t);
173 static void applyBoneSize(TransInfo *t, const int mval[2]);
174
175 static void initBoneEnvelope(TransInfo *t);
176 static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
177
178 static void initBoneRoll(TransInfo *t);
179 static void applyBoneRoll(TransInfo *t, const int mval[2]);
180
181 static void initEdgeSlide_ex(
182     TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
183 static void initEdgeSlide(TransInfo *t);
184 static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
185 static void applyEdgeSlide(TransInfo *t, const int mval[2]);
186
187 static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
188 static void initVertSlide(TransInfo *t);
189 static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
190 static void applyVertSlide(TransInfo *t, const int mval[2]);
191
192 static void initTimeTranslate(TransInfo *t);
193 static void applyTimeTranslate(TransInfo *t, const int mval[2]);
194
195 static void initTimeSlide(TransInfo *t);
196 static void applyTimeSlide(TransInfo *t, const int mval[2]);
197
198 static void initTimeScale(TransInfo *t);
199 static void applyTimeScale(TransInfo *t, const int mval[2]);
200
201 static void initBakeTime(TransInfo *t);
202 static void applyBakeTime(TransInfo *t, const int mval[2]);
203
204 static void initMirror(TransInfo *t);
205 static void applyMirror(TransInfo *t, const int mval[2]);
206
207 static void initAlign(TransInfo *t);
208 static void applyAlign(TransInfo *t, const int mval[2]);
209
210 static void initSeqSlide(TransInfo *t);
211 static void applySeqSlide(TransInfo *t, const int mval[2]);
212
213 static void initGPOpacity(TransInfo *t);
214 static void applyGPOpacity(TransInfo *t, const int mval[2]);
215 /* end transform callbacks */
216
217 static bool transdata_check_local_center(TransInfo *t, short around)
218 {
219   return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
220           ((t->flag & (T_OBJECT | T_POSE)) ||
221            /* implicit: (t->flag & T_EDIT) */
222            (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) ||
223            (t->spacetype == SPACE_GRAPH) ||
224            (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
225 }
226
227 bool transdata_check_local_islands(TransInfo *t, short around)
228 {
229   return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH))));
230 }
231
232 /* ************************** SPACE DEPENDENT CODE **************************** */
233
234 void setTransformViewMatrices(TransInfo *t)
235 {
236   if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
237     RegionView3D *rv3d = t->ar->regiondata;
238
239     copy_m4_m4(t->viewmat, rv3d->viewmat);
240     copy_m4_m4(t->viewinv, rv3d->viewinv);
241     copy_m4_m4(t->persmat, rv3d->persmat);
242     copy_m4_m4(t->persinv, rv3d->persinv);
243     t->persp = rv3d->persp;
244   }
245   else {
246     unit_m4(t->viewmat);
247     unit_m4(t->viewinv);
248     unit_m4(t->persmat);
249     unit_m4(t->persinv);
250     t->persp = RV3D_ORTHO;
251   }
252
253   calculateCenter2D(t);
254   calculateCenterLocal(t, t->center_global);
255 }
256
257 void setTransformViewAspect(TransInfo *t, float r_aspect[3])
258 {
259   copy_v3_fl(r_aspect, 1.0f);
260
261   if (t->spacetype == SPACE_IMAGE) {
262     SpaceImage *sima = t->sa->spacedata.first;
263
264     if (t->options & CTX_MASK) {
265       ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
266     }
267     else if (t->options & CTX_PAINT_CURVE) {
268       /* pass */
269     }
270     else {
271       ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
272     }
273   }
274   else if (t->spacetype == SPACE_CLIP) {
275     SpaceClip *sclip = t->sa->spacedata.first;
276
277     if (t->options & CTX_MOVIECLIP) {
278       ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
279     }
280     else {
281       ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]);
282     }
283   }
284   else if (t->spacetype == SPACE_GRAPH) {
285     /* depemds on context of usage */
286   }
287 }
288
289 static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
290 {
291   float divx = BLI_rcti_size_x(&v2d->mask);
292   float divy = BLI_rcti_size_y(&v2d->mask);
293
294   r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
295   r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
296   r_vec[2] = 0.0f;
297 }
298
299 static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
300 {
301   float divx = BLI_rcti_size_x(&v2d->mask);
302   float divy = BLI_rcti_size_y(&v2d->mask);
303
304   float mulx = BLI_rctf_size_x(&v2d->cur);
305   float muly = BLI_rctf_size_y(&v2d->cur);
306
307   /* difference with convertViewVec2D */
308   /* clamp w/h, mask only */
309   if (mulx / divx < muly / divy) {
310     divy = divx;
311     muly = mulx;
312   }
313   else {
314     divx = divy;
315     mulx = muly;
316   }
317   /* end difference */
318
319   r_vec[0] = mulx * dx / divx;
320   r_vec[1] = muly * dy / divy;
321   r_vec[2] = 0.0f;
322 }
323
324 void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
325 {
326   if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
327     if (t->options & CTX_PAINT_CURVE) {
328       r_vec[0] = dx;
329       r_vec[1] = dy;
330     }
331     else {
332       const float mval_f[2] = {(float)dx, (float)dy};
333       ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
334     }
335   }
336   else if (t->spacetype == SPACE_IMAGE) {
337     if (t->options & CTX_MASK) {
338       convertViewVec2D_mask(t->view, r_vec, dx, dy);
339     }
340     else if (t->options & CTX_PAINT_CURVE) {
341       r_vec[0] = dx;
342       r_vec[1] = dy;
343     }
344     else {
345       convertViewVec2D(t->view, r_vec, dx, dy);
346     }
347
348     r_vec[0] *= t->aspect[0];
349     r_vec[1] *= t->aspect[1];
350   }
351   else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
352     convertViewVec2D(t->view, r_vec, dx, dy);
353   }
354   else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
355     convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
356   }
357   else if (t->spacetype == SPACE_CLIP) {
358     if (t->options & CTX_MASK) {
359       convertViewVec2D_mask(t->view, r_vec, dx, dy);
360     }
361     else {
362       convertViewVec2D(t->view, r_vec, dx, dy);
363     }
364
365     r_vec[0] *= t->aspect[0];
366     r_vec[1] *= t->aspect[1];
367   }
368   else {
369     printf("%s: called in an invalid context\n", __func__);
370     zero_v3(r_vec);
371   }
372 }
373
374 void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
375 {
376   if (t->spacetype == SPACE_VIEW3D) {
377     if (t->ar->regiontype == RGN_TYPE_WINDOW) {
378       if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
379         /* this is what was done in 2.64, perhaps we can be smarter? */
380         adr[0] = (int)2140000000.0f;
381         adr[1] = (int)2140000000.0f;
382       }
383     }
384   }
385   else if (t->spacetype == SPACE_IMAGE) {
386     SpaceImage *sima = t->sa->spacedata.first;
387
388     if (t->options & CTX_MASK) {
389       float v[2];
390
391       v[0] = vec[0] / t->aspect[0];
392       v[1] = vec[1] / t->aspect[1];
393
394       BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
395
396       ED_image_point_pos__reverse(sima, t->ar, v, v);
397
398       adr[0] = v[0];
399       adr[1] = v[1];
400     }
401     else if (t->options & CTX_PAINT_CURVE) {
402       adr[0] = vec[0];
403       adr[1] = vec[1];
404     }
405     else {
406       float v[2];
407
408       v[0] = vec[0] / t->aspect[0];
409       v[1] = vec[1] / t->aspect[1];
410
411       UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
412     }
413   }
414   else if (t->spacetype == SPACE_ACTION) {
415     int out[2] = {0, 0};
416 #if 0
417     SpaceAction *sact = t->sa->spacedata.first;
418
419     if (sact->flag & SACTION_DRAWTIME) {
420       //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
421       /* same as below */
422       UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
423     }
424     else
425 #endif
426     {
427       UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
428     }
429
430     adr[0] = out[0];
431     adr[1] = out[1];
432   }
433   else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
434     int out[2] = {0, 0};
435
436     UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
437     adr[0] = out[0];
438     adr[1] = out[1];
439   }
440   else if (t->spacetype == SPACE_SEQ) { /* XXX not tested yet, but should work */
441     int out[2] = {0, 0};
442
443     UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &out[0], &out[1]);
444     adr[0] = out[0];
445     adr[1] = out[1];
446   }
447   else if (t->spacetype == SPACE_CLIP) {
448     SpaceClip *sc = t->sa->spacedata.first;
449
450     if (t->options & CTX_MASK) {
451       MovieClip *clip = ED_space_clip_get_clip(sc);
452
453       if (clip) {
454         float v[2];
455
456         v[0] = vec[0] / t->aspect[0];
457         v[1] = vec[1] / t->aspect[1];
458
459         BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
460
461         ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
462
463         adr[0] = v[0];
464         adr[1] = v[1];
465       }
466       else {
467         adr[0] = 0;
468         adr[1] = 0;
469       }
470     }
471     else if (t->options & CTX_MOVIECLIP) {
472       float v[2];
473
474       v[0] = vec[0] / t->aspect[0];
475       v[1] = vec[1] / t->aspect[1];
476
477       UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
478     }
479     else {
480       BLI_assert(0);
481     }
482   }
483   else if (t->spacetype == SPACE_NODE) {
484     UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], &adr[0], &adr[1]);
485   }
486 }
487 void projectIntView(TransInfo *t, const float vec[3], int adr[2])
488 {
489   projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
490 }
491
492 void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
493 {
494   switch (t->spacetype) {
495     case SPACE_VIEW3D: {
496       if (t->options & CTX_PAINT_CURVE) {
497         adr[0] = vec[0];
498         adr[1] = vec[1];
499       }
500       else if (t->ar->regiontype == RGN_TYPE_WINDOW) {
501         /* allow points behind the view [#33643] */
502         if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
503           /* XXX, 2.64 and prior did this, weak! */
504           adr[0] = t->ar->winx / 2.0f;
505           adr[1] = t->ar->winy / 2.0f;
506         }
507         return;
508       }
509       break;
510     }
511     default: {
512       int a[2] = {0, 0};
513       projectIntView(t, vec, a);
514       adr[0] = a[0];
515       adr[1] = a[1];
516       break;
517     }
518   }
519 }
520 void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
521 {
522   projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
523 }
524
525 void applyAspectRatio(TransInfo *t, float vec[2])
526 {
527   if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) &&
528       !(t->options & CTX_PAINT_CURVE)) {
529     SpaceImage *sima = t->sa->spacedata.first;
530
531     if ((sima->flag & SI_COORDFLOATS) == 0) {
532       int width, height;
533       ED_space_image_get_size(sima, &width, &height);
534
535       vec[0] *= width;
536       vec[1] *= height;
537     }
538
539     vec[0] /= t->aspect[0];
540     vec[1] /= t->aspect[1];
541   }
542   else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
543     if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
544       vec[0] /= t->aspect[0];
545       vec[1] /= t->aspect[1];
546     }
547   }
548 }
549
550 void removeAspectRatio(TransInfo *t, float vec[2])
551 {
552   if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
553     SpaceImage *sima = t->sa->spacedata.first;
554
555     if ((sima->flag & SI_COORDFLOATS) == 0) {
556       int width, height;
557       ED_space_image_get_size(sima, &width, &height);
558
559       vec[0] /= width;
560       vec[1] /= height;
561     }
562
563     vec[0] *= t->aspect[0];
564     vec[1] *= t->aspect[1];
565   }
566   else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
567     if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
568       vec[0] *= t->aspect[0];
569       vec[1] *= t->aspect[1];
570     }
571   }
572 }
573
574 static void viewRedrawForce(const bContext *C, TransInfo *t)
575 {
576   if (t->options & CTX_GPENCIL_STROKES) {
577     bGPdata *gpd = ED_gpencil_data_get_active(C);
578     if (gpd) {
579       DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
580     }
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       }
593       else {
594         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
595       }
596
597       /* For real-time animation record - send notifiers recognized by animation editors */
598       // XXX: is this notifier a lame duck?
599       if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
600         WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
601       }
602     }
603   }
604   else if (t->spacetype == SPACE_ACTION) {
605     // SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
606     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
607   }
608   else if (t->spacetype == SPACE_GRAPH) {
609     // SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
610     WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
611   }
612   else if (t->spacetype == SPACE_NLA) {
613     WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
614   }
615   else if (t->spacetype == SPACE_NODE) {
616     // ED_area_tag_redraw(t->sa);
617     WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
618   }
619   else if (t->spacetype == SPACE_SEQ) {
620     WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
621     /* Keyframes on strips has been moved, so make sure related editos are informed. */
622     WM_event_add_notifier(C, NC_ANIMATION, NULL);
623   }
624   else if (t->spacetype == SPACE_IMAGE) {
625     if (t->options & CTX_MASK) {
626       Mask *mask = CTX_data_edit_mask(C);
627
628       WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
629     }
630     else if (t->options & CTX_PAINT_CURVE) {
631       wmWindow *window = CTX_wm_window(C);
632       WM_paint_cursor_tag_redraw(window, t->ar);
633     }
634     else if (t->flag & T_CURSOR) {
635       ED_area_tag_redraw(t->sa);
636     }
637     else {
638       // XXX how to deal with lock?
639       SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
640       if (sima->lock) {
641         WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
642       }
643       else {
644         ED_area_tag_redraw(t->sa);
645       }
646     }
647   }
648   else if (t->spacetype == SPACE_CLIP) {
649     SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
650
651     if (ED_space_clip_check_show_trackedit(sc)) {
652       MovieClip *clip = ED_space_clip_get_clip(sc);
653
654       /* objects could be parented to tracking data, so send this for viewport refresh */
655       WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
656
657       WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
658     }
659     else if (ED_space_clip_check_show_maskedit(sc)) {
660       Mask *mask = CTX_data_edit_mask(C);
661
662       WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
663     }
664   }
665 }
666
667 static void viewRedrawPost(bContext *C, TransInfo *t)
668 {
669   ED_area_status_text(t->sa, NULL);
670
671   if (t->spacetype == SPACE_VIEW3D) {
672     /* if autokeying is enabled, send notifiers that keyframes were added */
673     if (IS_AUTOKEY_ON(t->scene)) {
674       WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
675     }
676
677     /* redraw UV editor */
678     if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) &&
679         (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
680       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
681     }
682
683     /* XXX temp, first hack to get auto-render in compositor work (ton) */
684     WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
685   }
686
687 #if 0  // TRANSFORM_FIX_ME
688   if (t->spacetype == SPACE_VIEW3D) {
689     allqueue(REDRAWBUTSOBJECT, 0);
690     allqueue(REDRAWVIEW3D, 0);
691   }
692   else if (t->spacetype == SPACE_IMAGE) {
693     allqueue(REDRAWIMAGE, 0);
694     allqueue(REDRAWVIEW3D, 0);
695   }
696   else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_GRAPH)) {
697     allqueue(REDRAWVIEW3D, 0);
698     allqueue(REDRAWACTION, 0);
699     allqueue(REDRAWNLA, 0);
700     allqueue(REDRAWIPO, 0);
701     allqueue(REDRAWTIME, 0);
702     allqueue(REDRAWBUTSOBJECT, 0);
703   }
704
705   scrarea_queue_headredraw(curarea);
706 #endif
707 }
708
709 /* ************************** TRANSFORMATIONS **************************** */
710
711 static void view_editmove(unsigned short UNUSED(event))
712 {
713 #if 0  // TRANSFORM_FIX_ME
714   int refresh = 0;
715   /* Regular:   Zoom in */
716   /* Shift:     Scroll up */
717   /* Ctrl:      Scroll right */
718   /* Alt-Shift: Rotate up */
719   /* Alt-Ctrl:  Rotate right */
720
721   /* only work in 3D window for now
722    * In the end, will have to send to event to a 2D window handler instead
723    */
724   if (Trans.flag & T_2D_EDIT) {
725     return;
726   }
727
728   switch (event) {
729     case WHEELUPMOUSE:
730       if (G.qual & LR_SHIFTKEY) {
731         if (G.qual & LR_ALTKEY) {
732           G.qual &= ~LR_SHIFTKEY;
733           persptoetsen(PAD2);
734           G.qual |= LR_SHIFTKEY;
735         }
736         else {
737           persptoetsen(PAD2);
738         }
739       }
740       else if (G.qual & LR_CTRLKEY) {
741         if (G.qual & LR_ALTKEY) {
742           G.qual &= ~LR_CTRLKEY;
743           persptoetsen(PAD4);
744           G.qual |= LR_CTRLKEY;
745         }
746         else {
747           persptoetsen(PAD4);
748         }
749       }
750       else if (U.uiflag & USER_WHEELZOOMDIR) {
751         persptoetsen(PADMINUS);
752       }
753       else {
754         persptoetsen(PADPLUSKEY);
755       }
756
757       refresh = 1;
758       break;
759     case WHEELDOWNMOUSE:
760       if (G.qual & LR_SHIFTKEY) {
761         if (G.qual & LR_ALTKEY) {
762           G.qual &= ~LR_SHIFTKEY;
763           persptoetsen(PAD8);
764           G.qual |= LR_SHIFTKEY;
765         }
766         else {
767           persptoetsen(PAD8);
768         }
769       }
770       else if (G.qual & LR_CTRLKEY) {
771         if (G.qual & LR_ALTKEY) {
772           G.qual &= ~LR_CTRLKEY;
773           persptoetsen(PAD6);
774           G.qual |= LR_CTRLKEY;
775         }
776         else {
777           persptoetsen(PAD6);
778         }
779       }
780       else if (U.uiflag & USER_WHEELZOOMDIR) {
781         persptoetsen(PADPLUSKEY);
782       }
783       else {
784         persptoetsen(PADMINUS);
785       }
786
787       refresh = 1;
788       break;
789   }
790
791   if (refresh) {
792     setTransformViewMatrices(&Trans);
793   }
794 #endif
795 }
796
797 /* ************************************************* */
798
799 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
800 enum {
801   TFM_MODAL_CANCEL = 1,
802   TFM_MODAL_CONFIRM = 2,
803   TFM_MODAL_TRANSLATE = 3,
804   TFM_MODAL_ROTATE = 4,
805   TFM_MODAL_RESIZE = 5,
806   TFM_MODAL_SNAP_INV_ON = 6,
807   TFM_MODAL_SNAP_INV_OFF = 7,
808   TFM_MODAL_SNAP_TOGGLE = 8,
809   TFM_MODAL_AXIS_X = 9,
810   TFM_MODAL_AXIS_Y = 10,
811   TFM_MODAL_AXIS_Z = 11,
812   TFM_MODAL_PLANE_X = 12,
813   TFM_MODAL_PLANE_Y = 13,
814   TFM_MODAL_PLANE_Z = 14,
815   TFM_MODAL_CONS_OFF = 15,
816   TFM_MODAL_ADD_SNAP = 16,
817   TFM_MODAL_REMOVE_SNAP = 17,
818
819   /* 18 and 19 used by numinput, defined in transform.h */
820
821   TFM_MODAL_PROPSIZE_UP = 20,
822   TFM_MODAL_PROPSIZE_DOWN = 21,
823   TFM_MODAL_AUTOIK_LEN_INC = 22,
824   TFM_MODAL_AUTOIK_LEN_DEC = 23,
825
826   TFM_MODAL_EDGESLIDE_UP = 24,
827   TFM_MODAL_EDGESLIDE_DOWN = 25,
828
829   /* for analog input, like trackpad */
830   TFM_MODAL_PROPSIZE = 26,
831   /* node editor insert offset (aka auto-offset) direction toggle */
832   TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27,
833 };
834
835 static bool transform_modal_item_poll(const wmOperator *op, int value)
836 {
837   const TransInfo *t = op->customdata;
838   switch (value) {
839     case TFM_MODAL_CANCEL: {
840       if ((t->flag & T_RELEASE_CONFIRM) && ISMOUSE(t->launch_event)) {
841         return false;
842       }
843       break;
844     }
845     case TFM_MODAL_PROPSIZE:
846     case TFM_MODAL_PROPSIZE_UP:
847     case TFM_MODAL_PROPSIZE_DOWN: {
848       if ((t->flag & T_PROP_EDIT) == 0) {
849         return false;
850       }
851       break;
852     }
853     case TFM_MODAL_ADD_SNAP:
854     case TFM_MODAL_REMOVE_SNAP: {
855       if (t->spacetype != SPACE_VIEW3D) {
856         return false;
857       }
858       else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
859         return false;
860       }
861       else if (!validSnap(t)) {
862         return false;
863       }
864       break;
865     }
866     case TFM_MODAL_AXIS_X:
867     case TFM_MODAL_AXIS_Y:
868     case TFM_MODAL_AXIS_Z:
869     case TFM_MODAL_PLANE_X:
870     case TFM_MODAL_PLANE_Y:
871     case TFM_MODAL_PLANE_Z: {
872       if (t->flag & T_NO_CONSTRAINT) {
873         return false;
874       }
875       if (!ELEM(value, TFM_MODAL_AXIS_X, TFM_MODAL_AXIS_Y)) {
876         if (t->flag & T_2D_EDIT) {
877           return false;
878         }
879       }
880       break;
881     }
882     case TFM_MODAL_CONS_OFF: {
883       if ((t->con.mode & CON_APPLY) == 0) {
884         return false;
885       }
886       break;
887     }
888     case TFM_MODAL_EDGESLIDE_UP:
889     case TFM_MODAL_EDGESLIDE_DOWN: {
890       if (t->mode != TFM_EDGE_SLIDE) {
891         return false;
892       }
893       break;
894     }
895     case TFM_MODAL_INSERTOFS_TOGGLE_DIR: {
896       if (t->spacetype != SPACE_NODE) {
897         return false;
898       }
899       break;
900     }
901     case TFM_MODAL_AUTOIK_LEN_INC:
902     case TFM_MODAL_AUTOIK_LEN_DEC: {
903       if ((t->flag & T_AUTOIK) == 0) {
904         return false;
905       }
906       break;
907     }
908   }
909   return true;
910 }
911
912 /* called in transform_ops.c, on each regeneration of keymaps */
913 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
914 {
915   static const EnumPropertyItem modal_items[] = {
916       {TFM_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
917       {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
918       {TFM_MODAL_AXIS_X, "AXIS_X", 0, "X axis", ""},
919       {TFM_MODAL_AXIS_Y, "AXIS_Y", 0, "Y axis", ""},
920       {TFM_MODAL_AXIS_Z, "AXIS_Z", 0, "Z axis", ""},
921       {TFM_MODAL_PLANE_X, "PLANE_X", 0, "X plane", ""},
922       {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Y plane", ""},
923       {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Z plane", ""},
924       {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Clear Constraints", ""},
925       {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Snap Invert", ""},
926       {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Snap Invert (Off)", ""},
927       {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""},
928       {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""},
929       {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""},
930       {NUM_MODAL_INCREMENT_UP, "INCREMENT_UP", 0, "Numinput Increment Up", ""},
931       {NUM_MODAL_INCREMENT_DOWN, "INCREMENT_DOWN", 0, "Numinput Increment Down", ""},
932       {TFM_MODAL_PROPSIZE_UP, "PROPORTIONAL_SIZE_UP", 0, "Increase Proportional Influence", ""},
933       {TFM_MODAL_PROPSIZE_DOWN,
934        "PROPORTIONAL_SIZE_DOWN",
935        0,
936        "Decrease Proportional Influence",
937        ""},
938       {TFM_MODAL_AUTOIK_LEN_INC, "AUTOIK_CHAIN_LEN_UP", 0, "Increase Max AutoIK Chain Length", ""},
939       {TFM_MODAL_AUTOIK_LEN_DEC,
940        "AUTOIK_CHAIN_LEN_DOWN",
941        0,
942        "Decrease Max AutoIK Chain Length",
943        ""},
944       {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
945       {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
946       {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
947       {TFM_MODAL_INSERTOFS_TOGGLE_DIR,
948        "INSERTOFS_TOGGLE_DIR",
949        0,
950        "Toggle Direction for Node Auto-offset",
951        ""},
952       {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Move", ""},
953       {TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""},
954       {TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""},
955       {0, NULL, 0, NULL, NULL},
956   };
957
958   wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
959
960   keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
961   keymap->poll_modal_item = transform_modal_item_poll;
962
963   return keymap;
964 }
965
966 static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
967 {
968   if (!(t->flag & T_NO_CONSTRAINT)) {
969     int constraint_axis, constraint_plane;
970     const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
971     const char *msg1 = "", *msg2 = "", *msg3 = "";
972     char axis;
973
974     /* Initialize */
975     switch (key_type) {
976       case XKEY:
977         msg1 = TIP_("along X");
978         msg2 = TIP_("along %s X");
979         msg3 = TIP_("locking %s X");
980         axis = 'X';
981         constraint_axis = CON_AXIS0;
982         break;
983       case YKEY:
984         msg1 = TIP_("along Y");
985         msg2 = TIP_("along %s Y");
986         msg3 = TIP_("locking %s Y");
987         axis = 'Y';
988         constraint_axis = CON_AXIS1;
989         break;
990       case ZKEY:
991         msg1 = TIP_("along Z");
992         msg2 = TIP_("along %s Z");
993         msg3 = TIP_("locking %s Z");
994         axis = 'Z';
995         constraint_axis = CON_AXIS2;
996         break;
997       default:
998         /* Invalid key */
999         return;
1000     }
1001     constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis));
1002
1003     if (edit_2d && (key_type != ZKEY)) {
1004       if (cmode == axis) {
1005         stopConstraint(t);
1006       }
1007       else {
1008         setUserConstraint(t, V3D_ORIENT_GLOBAL, constraint_axis, msg1);
1009       }
1010     }
1011     else if (!edit_2d) {
1012       if (cmode != axis) {
1013         /* First press, constraint to an axis. */
1014         t->orientation.index = 0;
1015         const short *orientation_ptr = t->orientation.types[t->orientation.index];
1016         const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
1017         if (is_plane == false) {
1018           setUserConstraint(t, orientation, constraint_axis, msg2);
1019         }
1020         else {
1021           setUserConstraint(t, orientation, constraint_plane, msg3);
1022         }
1023       }
1024       else {
1025         /* Successive presses on existing axis, cycle orientation modes. */
1026         t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
1027
1028         if (t->orientation.index == 0) {
1029           stopConstraint(t);
1030         }
1031         else {
1032           const short *orientation_ptr = t->orientation.types[t->orientation.index];
1033           const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
1034           if (is_plane == false) {
1035             setUserConstraint(t, orientation, constraint_axis, msg2);
1036           }
1037           else {
1038             setUserConstraint(t, orientation, constraint_plane, msg3);
1039           }
1040         }
1041       }
1042     }
1043     t->redraw |= TREDRAW_HARD;
1044   }
1045 }
1046
1047 int transformEvent(TransInfo *t, const wmEvent *event)
1048 {
1049   char cmode = constraintModeToChar(t);
1050   bool handled = false;
1051   const int modifiers_prev = t->modifiers;
1052   const int mode_prev = t->mode;
1053
1054   t->redraw |= handleMouseInput(t, &t->mouse, event);
1055
1056   /* Handle modal numinput events first, if already activated. */
1057   if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) && hasNumInput(&t->num) &&
1058       handleNumInput(t->context, &(t->num), event)) {
1059     t->redraw |= TREDRAW_HARD;
1060     handled = true;
1061   }
1062   else if (event->type == MOUSEMOVE) {
1063     if (t->modifiers & MOD_CONSTRAINT_SELECT) {
1064       t->con.mode |= CON_SELECT;
1065     }
1066
1067     copy_v2_v2_int(t->mval, event->mval);
1068
1069     /* Use this for soft redraw. Might cause flicker in object mode */
1070     // t->redraw |= TREDRAW_SOFT;
1071     t->redraw |= TREDRAW_HARD;
1072
1073     if (t->state == TRANS_STARTING) {
1074       t->state = TRANS_RUNNING;
1075     }
1076
1077     applyMouseInput(t, &t->mouse, t->mval, t->values);
1078
1079     // Snapping mouse move events
1080     t->redraw |= handleSnapping(t, event);
1081     handled = true;
1082   }
1083   /* handle modal keymap first */
1084   else if (event->type == EVT_MODAL_MAP) {
1085     switch (event->val) {
1086       case TFM_MODAL_CANCEL:
1087         t->state = TRANS_CANCEL;
1088         handled = true;
1089         break;
1090       case TFM_MODAL_CONFIRM:
1091         t->state = TRANS_CONFIRM;
1092         handled = true;
1093         break;
1094       case TFM_MODAL_TRANSLATE:
1095         /* only switch when... */
1096         if (ELEM(t->mode,
1097                  TFM_ROTATION,
1098                  TFM_RESIZE,
1099                  TFM_TRACKBALL,
1100                  TFM_EDGE_SLIDE,
1101                  TFM_VERT_SLIDE)) {
1102           restoreTransObjects(t);
1103           resetTransModal(t);
1104           resetTransRestrictions(t);
1105           initTranslation(t);
1106           initSnapping(t, NULL);  // need to reinit after mode change
1107           t->redraw |= TREDRAW_HARD;
1108           handled = true;
1109         }
1110         else if (t->mode == TFM_SEQ_SLIDE) {
1111           t->flag ^= T_ALT_TRANSFORM;
1112           t->redraw |= TREDRAW_HARD;
1113           handled = true;
1114         }
1115         else {
1116           if (t->obedit_type == OB_MESH) {
1117             if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
1118               restoreTransObjects(t);
1119               resetTransModal(t);
1120               resetTransRestrictions(t);
1121
1122               /* first try edge slide */
1123               initEdgeSlide(t);
1124               /* if that fails, do vertex slide */
1125               if (t->state == TRANS_CANCEL) {
1126                 resetTransModal(t);
1127                 t->state = TRANS_STARTING;
1128                 initVertSlide(t);
1129               }
1130               /* vert slide can fail on unconnected vertices (rare but possible) */
1131               if (t->state == TRANS_CANCEL) {
1132                 resetTransModal(t);
1133                 t->mode = TFM_TRANSLATION;
1134                 t->state = TRANS_STARTING;
1135                 restoreTransObjects(t);
1136                 resetTransRestrictions(t);
1137                 initTranslation(t);
1138               }
1139               initSnapping(t, NULL);  // need to reinit after mode change
1140               t->redraw |= TREDRAW_HARD;
1141               handled = true;
1142             }
1143           }
1144           else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
1145             if (t->mode == TFM_TRANSLATION) {
1146               restoreTransObjects(t);
1147
1148               t->flag ^= T_ALT_TRANSFORM;
1149               t->redraw |= TREDRAW_HARD;
1150               handled = true;
1151             }
1152           }
1153         }
1154         break;
1155       case TFM_MODAL_ROTATE:
1156         /* only switch when... */
1157         if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
1158           if (ELEM(t->mode,
1159                    TFM_ROTATION,
1160                    TFM_RESIZE,
1161                    TFM_TRACKBALL,
1162                    TFM_TRANSLATION,
1163                    TFM_EDGE_SLIDE,
1164                    TFM_VERT_SLIDE)) {
1165             restoreTransObjects(t);
1166             resetTransModal(t);
1167             resetTransRestrictions(t);
1168
1169             if (t->mode == TFM_ROTATION) {
1170               initTrackball(t);
1171             }
1172             else {
1173               initRotation(t);
1174             }
1175             initSnapping(t, NULL);  // need to reinit after mode change
1176             t->redraw |= TREDRAW_HARD;
1177             handled = true;
1178           }
1179         }
1180         break;
1181       case TFM_MODAL_RESIZE:
1182         /* only switch when... */
1183         if (ELEM(t->mode,
1184                  TFM_ROTATION,
1185                  TFM_TRANSLATION,
1186                  TFM_TRACKBALL,
1187                  TFM_EDGE_SLIDE,
1188                  TFM_VERT_SLIDE)) {
1189
1190           /* Scale isn't normally very useful after extrude along normals, see T39756 */
1191           if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) {
1192             stopConstraint(t);
1193           }
1194
1195           restoreTransObjects(t);
1196           resetTransModal(t);
1197           resetTransRestrictions(t);
1198           initResize(t);
1199           initSnapping(t, NULL);  // need to reinit after mode change
1200           t->redraw |= TREDRAW_HARD;
1201           handled = true;
1202         }
1203         else if (t->mode == TFM_SHRINKFATTEN) {
1204           t->flag ^= T_ALT_TRANSFORM;
1205           t->redraw |= TREDRAW_HARD;
1206           handled = true;
1207         }
1208         else if (t->mode == TFM_RESIZE) {
1209           if (t->options & CTX_MOVIECLIP) {
1210             restoreTransObjects(t);
1211
1212             t->flag ^= T_ALT_TRANSFORM;
1213             t->redraw |= TREDRAW_HARD;
1214             handled = true;
1215           }
1216         }
1217         break;
1218
1219       case TFM_MODAL_SNAP_INV_ON:
1220         t->modifiers |= MOD_SNAP_INVERT;
1221         t->redraw |= TREDRAW_HARD;
1222         handled = true;
1223         break;
1224       case TFM_MODAL_SNAP_INV_OFF:
1225         t->modifiers &= ~MOD_SNAP_INVERT;
1226         t->redraw |= TREDRAW_HARD;
1227         handled = true;
1228         break;
1229       case TFM_MODAL_SNAP_TOGGLE:
1230         t->modifiers ^= MOD_SNAP;
1231         t->redraw |= TREDRAW_HARD;
1232         handled = true;
1233         break;
1234       case TFM_MODAL_AXIS_X:
1235         if (!(t->flag & T_NO_CONSTRAINT)) {
1236           transform_event_xyz_constraint(t, XKEY, cmode, false);
1237           t->redraw |= TREDRAW_HARD;
1238           handled = true;
1239         }
1240         break;
1241       case TFM_MODAL_AXIS_Y:
1242         if ((t->flag & T_NO_CONSTRAINT) == 0) {
1243           transform_event_xyz_constraint(t, YKEY, cmode, false);
1244           t->redraw |= TREDRAW_HARD;
1245           handled = true;
1246         }
1247         break;
1248       case TFM_MODAL_AXIS_Z:
1249         if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
1250           transform_event_xyz_constraint(t, ZKEY, cmode, false);
1251           t->redraw |= TREDRAW_HARD;
1252           handled = true;
1253         }
1254         break;
1255       case TFM_MODAL_PLANE_X:
1256         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1257           transform_event_xyz_constraint(t, XKEY, cmode, true);
1258           t->redraw |= TREDRAW_HARD;
1259           handled = true;
1260         }
1261         break;
1262       case TFM_MODAL_PLANE_Y:
1263         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1264           transform_event_xyz_constraint(t, YKEY, cmode, true);
1265           t->redraw |= TREDRAW_HARD;
1266           handled = true;
1267         }
1268         break;
1269       case TFM_MODAL_PLANE_Z:
1270         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1271           transform_event_xyz_constraint(t, ZKEY, cmode, true);
1272           t->redraw |= TREDRAW_HARD;
1273           handled = true;
1274         }
1275         break;
1276       case TFM_MODAL_CONS_OFF:
1277         if ((t->flag & T_NO_CONSTRAINT) == 0) {
1278           stopConstraint(t);
1279           t->redraw |= TREDRAW_HARD;
1280           handled = true;
1281         }
1282         break;
1283       case TFM_MODAL_ADD_SNAP:
1284         addSnapPoint(t);
1285         t->redraw |= TREDRAW_HARD;
1286         handled = true;
1287         break;
1288       case TFM_MODAL_REMOVE_SNAP:
1289         removeSnapPoint(t);
1290         t->redraw |= TREDRAW_HARD;
1291         handled = true;
1292         break;
1293       case TFM_MODAL_PROPSIZE:
1294         /* MOUSEPAN usage... */
1295         if (t->flag & T_PROP_EDIT) {
1296           float fac = 1.0f + 0.005f * (event->y - event->prevy);
1297           t->prop_size *= fac;
1298           if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1299             t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->clip_end),
1300                                   T_PROP_SIZE_MIN);
1301           }
1302           else {
1303             t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
1304           }
1305           calculatePropRatio(t);
1306           t->redraw |= TREDRAW_HARD;
1307           handled = true;
1308         }
1309         break;
1310       case TFM_MODAL_PROPSIZE_UP:
1311         if (t->flag & T_PROP_EDIT) {
1312           t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1313           if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1314             t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->clip_end);
1315           }
1316           else {
1317             t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
1318           }
1319           calculatePropRatio(t);
1320           t->redraw |= TREDRAW_HARD;
1321           handled = true;
1322         }
1323         break;
1324       case TFM_MODAL_PROPSIZE_DOWN:
1325         if (t->flag & T_PROP_EDIT) {
1326           t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1327           t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
1328           calculatePropRatio(t);
1329           t->redraw |= TREDRAW_HARD;
1330           handled = true;
1331         }
1332         break;
1333       case TFM_MODAL_AUTOIK_LEN_INC:
1334         if (t->flag & T_AUTOIK) {
1335           transform_autoik_update(t, 1);
1336           t->redraw |= TREDRAW_HARD;
1337           handled = true;
1338         }
1339         break;
1340       case TFM_MODAL_AUTOIK_LEN_DEC:
1341         if (t->flag & T_AUTOIK) {
1342           transform_autoik_update(t, -1);
1343           t->redraw |= TREDRAW_HARD;
1344           handled = true;
1345         }
1346         break;
1347       case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
1348         if (t->spacetype == SPACE_NODE) {
1349           SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
1350
1351           BLI_assert(t->sa->spacetype == t->spacetype);
1352
1353           if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
1354             snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
1355           }
1356           else if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_LEFT) {
1357             snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_RIGHT;
1358           }
1359           else {
1360             BLI_assert(0);
1361           }
1362
1363           t->redraw |= TREDRAW_SOFT;
1364         }
1365         break;
1366       /* Those two are only handled in transform's own handler, see T44634! */
1367       case TFM_MODAL_EDGESLIDE_UP:
1368       case TFM_MODAL_EDGESLIDE_DOWN:
1369       default:
1370         break;
1371     }
1372   }
1373   /* else do non-mapped events */
1374   else if (event->val == KM_PRESS) {
1375     switch (event->type) {
1376       case RIGHTMOUSE:
1377         t->state = TRANS_CANCEL;
1378         handled = true;
1379         break;
1380       /* enforce redraw of transform when modifiers are used */
1381       case LEFTSHIFTKEY:
1382       case RIGHTSHIFTKEY:
1383         t->modifiers |= MOD_CONSTRAINT_PLANE;
1384         t->redraw |= TREDRAW_HARD;
1385         handled = true;
1386         break;
1387
1388       case SPACEKEY:
1389         t->state = TRANS_CONFIRM;
1390         handled = true;
1391         break;
1392
1393       case MIDDLEMOUSE:
1394         if ((t->flag & T_NO_CONSTRAINT) == 0) {
1395           /* exception for switching to dolly, or trackball, in camera view */
1396           if (t->flag & T_CAMERA) {
1397             if (t->mode == TFM_TRANSLATION) {
1398               setLocalConstraint(t, (CON_AXIS2), TIP_("along local Z"));
1399             }
1400             else if (t->mode == TFM_ROTATION) {
1401               restoreTransObjects(t);
1402               initTrackball(t);
1403             }
1404           }
1405           else {
1406             t->modifiers |= MOD_CONSTRAINT_SELECT;
1407             if (t->con.mode & CON_APPLY) {
1408               stopConstraint(t);
1409             }
1410             else {
1411               if (event->shift) {
1412                 /* bit hackish... but it prevents mmb select to print the
1413                  * orientation from menu */
1414                 float mati[3][3];
1415                 strcpy(t->spacename, "global");
1416                 unit_m3(mati);
1417                 initSelectConstraint(t, mati);
1418               }
1419               else {
1420                 initSelectConstraint(t, t->spacemtx);
1421               }
1422               postSelectConstraint(t);
1423             }
1424           }
1425           t->redraw |= TREDRAW_HARD;
1426           handled = true;
1427         }
1428         break;
1429       case ESCKEY:
1430         t->state = TRANS_CANCEL;
1431         handled = true;
1432         break;
1433       case PADENTER:
1434       case RETKEY:
1435         t->state = TRANS_CONFIRM;
1436         handled = true;
1437         break;
1438       case GKEY:
1439         /* only switch when... */
1440         if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
1441           restoreTransObjects(t);
1442           resetTransModal(t);
1443           resetTransRestrictions(t);
1444           initTranslation(t);
1445           initSnapping(t, NULL);  // need to reinit after mode change
1446           t->redraw |= TREDRAW_HARD;
1447           handled = true;
1448         }
1449         break;
1450       case SKEY:
1451         /* only switch when... */
1452         if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
1453           restoreTransObjects(t);
1454           resetTransModal(t);
1455           resetTransRestrictions(t);
1456           initResize(t);
1457           initSnapping(t, NULL);  // need to reinit after mode change
1458           t->redraw |= TREDRAW_HARD;
1459           handled = true;
1460         }
1461         break;
1462       case RKEY:
1463         /* only switch when... */
1464         if (!(t->options & CTX_TEXTURE)) {
1465           if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
1466             restoreTransObjects(t);
1467             resetTransModal(t);
1468             resetTransRestrictions(t);
1469
1470             if (t->mode == TFM_ROTATION) {
1471               initTrackball(t);
1472             }
1473             else {
1474               initRotation(t);
1475             }
1476             initSnapping(t, NULL);  // need to reinit after mode change
1477             t->redraw |= TREDRAW_HARD;
1478             handled = true;
1479           }
1480         }
1481         break;
1482       case CKEY:
1483         if (event->alt) {
1484           if (!(t->options & CTX_NO_PET)) {
1485             t->flag ^= T_PROP_CONNECTED;
1486             sort_trans_data_dist(t);
1487             calculatePropRatio(t);
1488             t->redraw = TREDRAW_HARD;
1489             handled = true;
1490           }
1491         }
1492         break;
1493       case OKEY:
1494         if (t->flag & T_PROP_EDIT && event->shift) {
1495           t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
1496           calculatePropRatio(t);
1497           t->redraw |= TREDRAW_HARD;
1498           handled = true;
1499         }
1500         break;
1501       case PADPLUSKEY:
1502         if (event->alt && t->flag & T_PROP_EDIT) {
1503           t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1504           if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
1505             t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->clip_end);
1506           }
1507           calculatePropRatio(t);
1508           t->redraw = TREDRAW_HARD;
1509           handled = true;
1510         }
1511         break;
1512       case PAGEUPKEY:
1513       case WHEELDOWNMOUSE:
1514         if (t->flag & T_AUTOIK) {
1515           transform_autoik_update(t, 1);
1516         }
1517         else {
1518           view_editmove(event->type);
1519         }
1520         t->redraw = TREDRAW_HARD;
1521         handled = true;
1522         break;
1523       case PADMINUS:
1524         if (event->alt && t->flag & T_PROP_EDIT) {
1525           t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
1526           calculatePropRatio(t);
1527           t->redraw = TREDRAW_HARD;
1528           handled = true;
1529         }
1530         break;
1531       case PAGEDOWNKEY:
1532       case WHEELUPMOUSE:
1533         if (t->flag & T_AUTOIK) {
1534           transform_autoik_update(t, -1);
1535         }
1536         else {
1537           view_editmove(event->type);
1538         }
1539         t->redraw = TREDRAW_HARD;
1540         handled = true;
1541         break;
1542       case LEFTALTKEY:
1543       case RIGHTALTKEY:
1544         if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1545           t->flag |= T_ALT_TRANSFORM;
1546           t->redraw |= TREDRAW_HARD;
1547           handled = true;
1548         }
1549         break;
1550       case NKEY:
1551         if (ELEM(t->mode, TFM_ROTATION)) {
1552           if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
1553             restoreTransObjects(t);
1554             resetTransModal(t);
1555             resetTransRestrictions(t);
1556             initNormalRotation(t);
1557             t->redraw = TREDRAW_HARD;
1558             handled = true;
1559           }
1560         }
1561         break;
1562       default:
1563         break;
1564     }
1565
1566     /* Snapping key events */
1567     t->redraw |= handleSnapping(t, event);
1568   }
1569   else if (event->val == KM_RELEASE) {
1570     switch (event->type) {
1571       case LEFTSHIFTKEY:
1572       case RIGHTSHIFTKEY:
1573         t->modifiers &= ~MOD_CONSTRAINT_PLANE;
1574         t->redraw |= TREDRAW_HARD;
1575         handled = true;
1576         break;
1577
1578       case MIDDLEMOUSE:
1579         if ((t->flag & T_NO_CONSTRAINT) == 0) {
1580           t->modifiers &= ~MOD_CONSTRAINT_SELECT;
1581           postSelectConstraint(t);
1582           t->redraw |= TREDRAW_HARD;
1583           handled = true;
1584         }
1585         break;
1586       case LEFTALTKEY:
1587       case RIGHTALTKEY:
1588         if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1589           t->flag &= ~T_ALT_TRANSFORM;
1590           t->redraw |= TREDRAW_HARD;
1591           handled = true;
1592         }
1593         break;
1594       default:
1595         break;
1596     }
1597
1598     /* confirm transform if launch key is released after mouse move */
1599     if ((t->flag & T_RELEASE_CONFIRM) && event->type == t->launch_event) {
1600       t->state = TRANS_CONFIRM;
1601     }
1602   }
1603
1604   /* if we change snap options, get the unsnapped values back */
1605   if ((mode_prev != t->mode) || ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) !=
1606                                  (modifiers_prev & (MOD_SNAP | MOD_SNAP_INVERT)))) {
1607     applyMouseInput(t, &t->mouse, t->mval, t->values);
1608   }
1609
1610   /* Per transform event, if present */
1611   if (t->handleEvent && (!handled ||
1612                          /* Needed for vertex slide, see [#38756] */
1613                          (event->type == MOUSEMOVE))) {
1614     t->redraw |= t->handleEvent(t, event);
1615   }
1616
1617   /* Try to init modal numinput now, if possible. */
1618   if (!(handled || t->redraw) && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
1619       handleNumInput(t->context, &(t->num), event)) {
1620     t->redraw |= TREDRAW_HARD;
1621     handled = true;
1622   }
1623
1624   if (t->redraw && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
1625     WM_window_status_area_tag_redraw(CTX_wm_window(t->context));
1626   }
1627
1628   if (handled || t->redraw) {
1629     return 0;
1630   }
1631   else {
1632     return OPERATOR_PASS_THROUGH;
1633   }
1634 }
1635
1636 bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], float cent2d[2])
1637 {
1638   TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
1639   bool success;
1640
1641   t->context = C;
1642
1643   t->state = TRANS_RUNNING;
1644
1645   /* avoid calculating PET */
1646   t->options = CTX_NO_PET;
1647
1648   t->mode = TFM_DUMMY;
1649
1650   initTransInfo(C, t, NULL, NULL);
1651
1652   /* avoid doing connectivity lookups (when V3D_AROUND_LOCAL_ORIGINS is set) */
1653   t->around = V3D_AROUND_CENTER_BOUNDS;
1654
1655   createTransData(C, t);  // make TransData structs from selection
1656
1657   t->around = centerMode;  // override userdefined mode
1658
1659   if (t->data_len_all == 0) {
1660     success = false;
1661   }
1662   else {
1663     success = true;
1664
1665     calculateCenter(t);
1666
1667     if (cent2d) {
1668       copy_v2_v2(cent2d, t->center2d);
1669     }
1670
1671     if (cent3d) {
1672       // Copy center from constraint center. Transform center can be local
1673       copy_v3_v3(cent3d, t->center_global);
1674     }
1675   }
1676
1677   /* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
1678   special_aftertrans_update(C, t);
1679
1680   postTrans(C, t);
1681
1682   MEM_freeN(t);
1683
1684   return success;
1685 }
1686
1687 typedef enum {
1688   UP,
1689   DOWN,
1690   LEFT,
1691   RIGHT,
1692 } ArrowDirection;
1693
1694 #define POS_INDEX 0
1695 /* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
1696  * private to this file  - merwin
1697  */
1698
1699 static void drawArrow(ArrowDirection d, short offset, short length, short size)
1700 {
1701   immBegin(GPU_PRIM_LINES, 6);
1702
1703   switch (d) {
1704     case LEFT:
1705       offset = -offset;
1706       length = -length;
1707       size = -size;
1708       ATTR_FALLTHROUGH;
1709     case RIGHT:
1710       immVertex2f(POS_INDEX, offset, 0);
1711       immVertex2f(POS_INDEX, offset + length, 0);
1712       immVertex2f(POS_INDEX, offset + length, 0);
1713       immVertex2f(POS_INDEX, offset + length - size, -size);
1714       immVertex2f(POS_INDEX, offset + length, 0);
1715       immVertex2f(POS_INDEX, offset + length - size, size);
1716       break;
1717
1718     case DOWN:
1719       offset = -offset;
1720       length = -length;
1721       size = -size;
1722       ATTR_FALLTHROUGH;
1723     case UP:
1724       immVertex2f(POS_INDEX, 0, offset);
1725       immVertex2f(POS_INDEX, 0, offset + length);
1726       immVertex2f(POS_INDEX, 0, offset + length);
1727       immVertex2f(POS_INDEX, -size, offset + length - size);
1728       immVertex2f(POS_INDEX, 0, offset + length);
1729       immVertex2f(POS_INDEX, size, offset + length - size);
1730       break;
1731   }
1732
1733   immEnd();
1734 }
1735
1736 static void drawArrowHead(ArrowDirection d, short size)
1737 {
1738   immBegin(GPU_PRIM_LINES, 4);
1739
1740   switch (d) {
1741     case LEFT:
1742       size = -size;
1743       ATTR_FALLTHROUGH;
1744     case RIGHT:
1745       immVertex2f(POS_INDEX, 0, 0);
1746       immVertex2f(POS_INDEX, -size, -size);
1747       immVertex2f(POS_INDEX, 0, 0);
1748       immVertex2f(POS_INDEX, -size, size);
1749       break;
1750
1751     case DOWN:
1752       size = -size;
1753       ATTR_FALLTHROUGH;
1754     case UP:
1755       immVertex2f(POS_INDEX, 0, 0);
1756       immVertex2f(POS_INDEX, -size, -size);
1757       immVertex2f(POS_INDEX, 0, 0);
1758       immVertex2f(POS_INDEX, size, -size);
1759       break;
1760   }
1761
1762   immEnd();
1763 }
1764
1765 static void drawArc(float size, float angle_start, float angle_end, int segments)
1766 {
1767   float delta = (angle_end - angle_start) / segments;
1768   float angle;
1769   int a;
1770
1771   immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
1772
1773   for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
1774     immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
1775   }
1776   immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
1777
1778   immEnd();
1779 }
1780
1781 static bool helpline_poll(bContext *C)
1782 {
1783   ARegion *ar = CTX_wm_region(C);
1784
1785   if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
1786     return 1;
1787   }
1788   return 0;
1789 }
1790
1791 static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
1792 {
1793   TransInfo *t = (TransInfo *)customdata;
1794
1795   if (t->helpline != HLP_NONE) {
1796     float cent[2];
1797     const float mval[3] = {
1798         x,
1799         y,
1800         0.0f,
1801     };
1802     float tmval[2] = {
1803         (float)t->mval[0],
1804         (float)t->mval[1],
1805     };
1806
1807     projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
1808     /* Offset the values for the area region. */
1809     const float offset[2] = {
1810         t->ar->winrct.xmin,
1811         t->ar->winrct.ymin,
1812     };
1813
1814     for (int i = 0; i < 2; i++) {
1815       cent[i] += offset[i];
1816       tmval[i] += offset[i];
1817     }
1818
1819     GPU_matrix_push();
1820
1821     /* Dashed lines first. */
1822     if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
1823       const uint shdr_pos = GPU_vertformat_attr_add(
1824           immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1825
1826       UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
1827       BLI_assert(shdr_pos == POS_INDEX);
1828
1829       GPU_line_width(1.0f);
1830
1831       immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
1832
1833       float viewport_size[4];
1834       GPU_viewport_size_get_f(viewport_size);
1835       immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1836
1837       immUniform1i("colors_len", 0); /* "simple" mode */
1838       immUniformThemeColor(TH_VIEW_OVERLAY);
1839       immUniform1f("dash_width", 6.0f);
1840       immUniform1f("dash_factor", 0.5f);
1841
1842       immBegin(GPU_PRIM_LINES, 2);
1843       immVertex2fv(POS_INDEX, cent);
1844       immVertex2f(POS_INDEX, tmval[0], tmval[1]);
1845       immEnd();
1846
1847       immUnbindProgram();
1848     }
1849
1850     /* And now, solid lines. */
1851     uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1852     UNUSED_VARS_NDEBUG(pos); /* silence warning */
1853     BLI_assert(pos == POS_INDEX);
1854     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1855
1856     switch (t->helpline) {
1857       case HLP_SPRING:
1858         immUniformThemeColor(TH_VIEW_OVERLAY);
1859
1860         GPU_matrix_translate_3fv(mval);
1861         GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
1862
1863         GPU_line_width(3.0f);
1864         drawArrow(UP, 5, 10, 5);
1865         drawArrow(DOWN, 5, 10, 5);
1866         break;
1867       case HLP_HARROW:
1868         immUniformThemeColor(TH_VIEW_OVERLAY);
1869         GPU_matrix_translate_3fv(mval);
1870
1871         GPU_line_width(3.0f);
1872         drawArrow(RIGHT, 5, 10, 5);
1873         drawArrow(LEFT, 5, 10, 5);
1874         break;
1875       case HLP_VARROW:
1876         immUniformThemeColor(TH_VIEW_OVERLAY);
1877
1878         GPU_matrix_translate_3fv(mval);
1879
1880         GPU_line_width(3.0f);
1881         drawArrow(UP, 5, 10, 5);
1882         drawArrow(DOWN, 5, 10, 5);
1883         break;
1884       case HLP_CARROW: {
1885         /* Draw arrow based on direction defined by custom-points. */
1886         immUniformThemeColor(TH_VIEW_OVERLAY);
1887
1888         GPU_matrix_translate_3fv(mval);
1889
1890         GPU_line_width(3.0f);
1891
1892         const int *data = t->mouse.data;
1893         const float dx = data[2] - data[0], dy = data[3] - data[1];
1894         const float angle = -atan2f(dx, dy);
1895
1896         GPU_matrix_push();
1897
1898         GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
1899
1900         drawArrow(UP, 5, 10, 5);
1901         drawArrow(DOWN, 5, 10, 5);
1902
1903         GPU_matrix_pop();
1904         break;
1905       }
1906       case HLP_ANGLE: {
1907         float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
1908         float angle = atan2f(dy, dx);
1909         float dist = hypotf(dx, dy);
1910         float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
1911         float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
1912
1913         immUniformThemeColor(TH_VIEW_OVERLAY);
1914
1915         GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
1916
1917         GPU_line_width(3.0f);
1918         drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
1919         drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
1920
1921         GPU_matrix_push();
1922
1923         GPU_matrix_translate_3f(
1924             cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
1925         GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
1926
1927         drawArrowHead(DOWN, 5);
1928
1929         GPU_matrix_pop();
1930
1931         GPU_matrix_translate_3f(
1932             cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
1933         GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
1934
1935         drawArrowHead(UP, 5);
1936         break;
1937       }
1938       case HLP_TRACKBALL: {
1939         unsigned char col[3], col2[3];
1940         UI_GetThemeColor3ubv(TH_GRID, col);
1941
1942         GPU_matrix_translate_3fv(mval);
1943
1944         GPU_line_width(3.0f);
1945
1946         UI_make_axis_color(col, col2, 'X');
1947         immUniformColor3ubv(col2);
1948
1949         drawArrow(RIGHT, 5, 10, 5);
1950         drawArrow(LEFT, 5, 10, 5);
1951
1952         UI_make_axis_color(col, col2, 'Y');
1953         immUniformColor3ubv(col2);
1954
1955         drawArrow(UP, 5, 10, 5);
1956         drawArrow(DOWN, 5, 10, 5);
1957         break;
1958       }
1959     }
1960
1961     immUnbindProgram();
1962     GPU_matrix_pop();
1963   }
1964 }
1965
1966 static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *ar)
1967 {
1968   /* Don't show overlays when not the active view and when overlay is disabled: T57139 */
1969   bool ok = false;
1970   if (ar == t->ar) {
1971     ok = true;
1972   }
1973   else {
1974     ScrArea *sa = CTX_wm_area(C);
1975     if (sa->spacetype == SPACE_VIEW3D) {
1976       View3D *v3d = sa->spacedata.first;
1977       if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
1978         ok = true;
1979       }
1980     }
1981   }
1982   return ok;
1983 }
1984
1985 static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg)
1986 {
1987   TransInfo *t = arg;
1988
1989   if (!transinfo_show_overlay(C, t, ar)) {
1990     return;
1991   }
1992
1993   GPU_line_width(1.0f);
1994
1995   drawConstraint(t);
1996   drawPropCircle(C, t);
1997   drawSnapping(C, t);
1998
1999   if (ar == t->ar) {
2000     /* edge slide, vert slide */
2001     drawEdgeSlide(t);
2002     drawVertSlide(t);
2003
2004     /* Rotation */
2005     drawDial3d(t);
2006   }
2007 }
2008
2009 /* just draw a little warning message in the top-right corner of the viewport
2010  * to warn that autokeying is enabled */
2011 static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
2012 {
2013   const char *printable = IFACE_("Auto Keying On");
2014   float printable_size[2];
2015   int xco, yco;
2016
2017   const rcti *rect = ED_region_visible_rect(ar);
2018
2019   const int font_id = BLF_default();
2020   BLF_width_and_height(
2021       font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
2022
2023   xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
2024   yco = (rect->ymax - U.widget_unit);
2025
2026   /* warning text (to clarify meaning of overlays)
2027    * - original color was red to match the icon, but that clashes badly with a less nasty border
2028    */
2029   unsigned char color[3];
2030   UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
2031   BLF_color3ubv(font_id, color);
2032 #ifdef WITH_INTERNATIONAL
2033   BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
2034 #else
2035   BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
2036 #endif
2037
2038   /* autokey recording icon... */
2039   GPU_blend_set_func_separate(
2040       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
2041   GPU_blend(true);
2042
2043   xco -= U.widget_unit;
2044   yco -= (int)printable_size[1] / 2;
2045
2046   UI_icon_draw(xco, yco, ICON_REC);
2047
2048   GPU_blend(false);
2049 }
2050
2051 static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg)
2052 {
2053   TransInfo *t = arg;
2054
2055   if (!transinfo_show_overlay(C, t, ar)) {
2056     return;
2057   }
2058
2059   if (ar == t->ar) {
2060     Scene *scene = t->scene;
2061     ViewLayer *view_layer = t->view_layer;
2062     Object *ob = OBACT(view_layer);
2063
2064     /* draw auto-key-framing hint in the corner
2065      * - only draw if enabled (advanced users may be distracted/annoyed),
2066      *   for objects that will be autokeyframed (no point otherwise),
2067      *   AND only for the active region (as showing all is too overwhelming)
2068      */
2069     if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
2070       if (ar == t->ar) {
2071         if (t->flag & (T_OBJECT | T_POSE)) {
2072           if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
2073             drawAutoKeyWarning(t, ar);
2074           }
2075         }
2076       }
2077     }
2078   }
2079 }
2080
2081 /**
2082  * \see #initTransform which reads values from the operator.
2083  */
2084 void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
2085 {
2086   ToolSettings *ts = CTX_data_tool_settings(C);
2087   int proportional = 0;
2088   PropertyRNA *prop;
2089
2090   // Save back mode in case we're in the generic operator
2091   if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
2092     RNA_property_enum_set(op->ptr, prop, t->mode);
2093   }
2094
2095   if ((prop = RNA_struct_find_property(op->ptr, "value"))) {
2096     if (RNA_property_array_check(prop)) {
2097       RNA_property_float_set_array(op->ptr, prop, t->values_final);
2098     }
2099     else {
2100       RNA_property_float_set(op->ptr, prop, t->values_final[0]);
2101     }
2102   }
2103
2104   if (t->flag & T_PROP_EDIT_ALL) {
2105     if (t->flag & T_PROP_EDIT) {
2106       proportional |= PROP_EDIT_USE;
2107     }
2108     if (t->flag & T_PROP_CONNECTED) {
2109       proportional |= PROP_EDIT_CONNECTED;
2110     }
2111     if (t->flag & T_PROP_PROJECTED) {
2112       proportional |= PROP_EDIT_PROJECTED;
2113     }
2114   }
2115
2116   // If modal, save settings back in scene if not set as operator argument
2117   if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) {
2118     /* save settings if not set in operator */
2119
2120     /* skip saving proportional edit if it was not actually used */
2121     if (!(t->options & CTX_NO_PET)) {
2122       if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) &&
2123           !RNA_property_is_set(op->ptr, prop)) {
2124         if (t->spacetype == SPACE_GRAPH) {
2125           ts->proportional_fcurve = proportional;
2126         }
2127         else if (t->spacetype == SPACE_ACTION) {
2128           ts->proportional_action = proportional;
2129         }
2130         else if (t->obedit_type != -1) {
2131           ts->proportional_edit = proportional;
2132         }
2133         else if (t->options & CTX_MASK) {
2134           ts->proportional_mask = proportional != 0;
2135         }
2136         else if ((t->options & CTX_CURSOR) == 0) {
2137           ts->proportional_objects = proportional != 0;
2138         }
2139       }
2140
2141       if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) {
2142         ts->proportional_size = RNA_property_is_set(op->ptr, prop) ?
2143                                     RNA_property_float_get(op->ptr, prop) :
2144                                     t->prop_size;
2145       }
2146
2147       if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
2148           !RNA_property_is_set(op->ptr, prop)) {
2149         ts->prop_mode = t->prop_mode;
2150       }
2151     }
2152
2153     if (t->spacetype == SPACE_VIEW3D) {
2154       if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
2155           !RNA_property_is_set(op->ptr, prop) &&
2156           (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
2157         TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
2158         orient_slot->type = t->orientation.user;
2159         BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
2160                    (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
2161                     orient_slot->index_custom));
2162       }
2163     }
2164   }
2165
2166   if (t->flag & T_MODAL) {
2167     /* do we check for parameter? */
2168     if (transformModeUseSnap(t)) {
2169       if (t->modifiers & MOD_SNAP) {
2170         ts->snap_flag |= SCE_SNAP;
2171       }
2172       else {
2173         ts->snap_flag &= ~SCE_SNAP;
2174       }
2175     }
2176   }
2177
2178   if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
2179     RNA_property_boolean_set(op->ptr, prop, proportional & PROP_EDIT_USE);
2180     RNA_boolean_set(op->ptr, "use_proportional_connected", proportional & PROP_EDIT_CONNECTED);
2181     RNA_boolean_set(op->ptr, "use_proportional_projected", proportional & PROP_EDIT_PROJECTED);
2182     RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
2183     RNA_float_set(op->ptr, "proportional_size", t->prop_size);
2184   }
2185
2186   if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
2187     RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
2188   }
2189
2190   /* Orientation used for redo. */
2191   const bool use_orient_axis = (t->orient_matrix_is_set &&
2192                                 (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
2193   short orientation;
2194   if (t->con.mode & CON_APPLY) {
2195     orientation = t->con.orientation;
2196     if (orientation == V3D_ORIENT_CUSTOM) {
2197       const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
2198           t->scene, t->orientation.custom);
2199       /* Maybe we need a t->con.custom_orientation?
2200        * Seems like it would always match t->orientation.custom. */
2201       orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
2202       BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
2203     }
2204   }
2205   else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
2206            (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
2207     orientation = RNA_property_enum_get(op->ptr, prop);
2208   }
2209   else if (use_orient_axis) {
2210     /* We're not using an orientation, use the fallback. */
2211     orientation = t->orientation.unset;
2212   }
2213   else {
2214     orientation = V3D_ORIENT_GLOBAL;
2215   }
2216
2217   if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
2218     if (t->flag & T_MODAL) {
2219       if (t->con.mode & CON_APPLY) {
2220         int orient_axis = constraintModeToIndex(t);
2221         if (orient_axis != -1) {
2222           RNA_property_enum_set(op->ptr, prop, orient_axis);
2223         }
2224       }
2225       else {
2226         RNA_property_enum_set(op->ptr, prop, t->orient_axis);
2227       }
2228     }
2229   }
2230   if ((prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
2231     if (t->flag & T_MODAL) {
2232       RNA_property_enum_set(op->ptr, prop, t->orient_axis_ortho);
2233     }
2234   }
2235
2236   if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
2237     if (t->flag & T_MODAL) {
2238       if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
2239         if (t->flag & T_MODAL) {
2240           RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
2241         }
2242       }
2243       if (t->con.mode & CON_APPLY) {
2244         RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]);
2245       }
2246       else if (use_orient_axis) {
2247         RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]);
2248       }
2249       else {
2250         RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
2251       }
2252     }
2253   }
2254
2255   if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
2256     /* constraint orientation can be global, even if user selects something else
2257      * so use the orientation in the constraint if set */
2258
2259     /* Use 'orient_matrix' instead. */
2260     if (t->flag & T_MODAL) {
2261       if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
2262         RNA_property_enum_set(op->ptr, prop, orientation);
2263       }
2264     }
2265   }
2266
2267   if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
2268     bool constraint_axis[3] = {false, false, false};
2269     if (t->flag & T_MODAL) {
2270       /* Only set if needed, so we can hide in the UI when nothing is set.
2271        * See 'transform_poll_property'. */
2272       if (t->con.mode & CON_APPLY) {
2273         if (t->con.mode & CON_AXIS0) {
2274           constraint_axis[0] = true;
2275         }
2276         if (t->con.mode & CON_AXIS1) {
2277           constraint_axis[1] = true;
2278         }
2279         if (t->con.mode & CON_AXIS2) {
2280           constraint_axis[2] = true;
2281         }
2282       }
2283       if (ELEM(true, UNPACK3(constraint_axis))) {
2284         RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
2285       }
2286     }
2287   }
2288
2289   {
2290     const char *prop_id = NULL;
2291     bool prop_state = true;
2292     if (t->mode == TFM_SHRINKFATTEN) {
2293       prop_id = "use_even_offset";
2294       prop_state = false;
2295     }
2296
2297     if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
2298       RNA_property_boolean_set(op->ptr, prop, ((t->flag & T_ALT_TRANSFORM) == 0) == prop_state);
2299     }
2300   }
2301
2302   if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
2303     ED_sculpt_end_transform(C);
2304   }
2305
2306   if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
2307     RNA_property_boolean_set(
2308         op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
2309   }
2310 }
2311
2312 /**
2313  * \note  caller needs to free 't' on a 0 return
2314  * \warning  \a event might be NULL (when tweaking from redo panel)
2315  * \see #saveTransform which writes these values back.
2316  */
2317 bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
2318 {
2319   int options = 0;
2320   PropertyRNA *prop;
2321
2322   t->context = C;
2323
2324   /* added initialize, for external calls to set stuff in TransInfo, like undo string */
2325
2326   t->state = TRANS_STARTING;
2327
2328   if ((prop = RNA_struct_find_property(op->ptr, "cursor_transform")) &&
2329       RNA_property_is_set(op->ptr, prop)) {
2330     if (RNA_property_boolean_get(op->ptr, prop)) {
2331       options |= CTX_CURSOR;
2332     }
2333   }
2334
2335   if ((prop = RNA_struct_find_property(op->ptr, "texture_space")) &&
2336       RNA_property_is_set(op->ptr, prop)) {
2337     if (RNA_property_boolean_get(op->ptr, prop)) {
2338       options |= CTX_TEXTURE;
2339     }
2340   }
2341
2342   if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) &&
2343       RNA_property_is_set(op->ptr, prop)) {
2344     if (RNA_property_boolean_get(op->ptr, prop)) {
2345       options |= CTX_GPENCIL_STROKES;
2346     }
2347   }
2348
2349   if (CTX_wm_view3d(C) != NULL) {
2350     Object *ob = CTX_data_active_object(C);
2351     if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
2352       options |= CTX_SCULPT;
2353     }
2354   }
2355
2356   t->options = options;
2357
2358   t->mode = mode;
2359
2360   /* Needed to translate tweak events to mouse buttons. */
2361   t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
2362
2363   /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate
2364    * (which can have type = 0) */
2365   /* For gizmo only, so assume LEFTMOUSE. */
2366   if (t->launch_event == 0) {
2367     t->launch_event = LEFTMOUSE;
2368   }
2369
2370   unit_m3(t->spacemtx);
2371
2372   initTransInfo(C, t, op, event);
2373   initTransformOrientation(C, t);
2374
2375   if (t->spacetype == SPACE_VIEW3D) {
2376     t->draw_handle_apply = ED_region_draw_cb_activate(
2377         t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
2378     t->draw_handle_view = ED_region_draw_cb_activate(
2379         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2380     t->draw_handle_pixel = ED_region_draw_cb_activate(
2381         t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
2382     t->draw_handle_cursor = WM_paint_cursor_activate(
2383         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2384   }
2385   else if (t->spacetype == SPACE_IMAGE) {
2386     t->draw_handle_view = ED_region_draw_cb_activate(
2387         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2388     t->draw_handle_cursor = WM_paint_cursor_activate(
2389         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2390   }
2391   else if (t->spacetype == SPACE_CLIP) {
2392     t->draw_handle_view = ED_region_draw_cb_activate(
2393         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2394     t->draw_handle_cursor = WM_paint_cursor_activate(
2395         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2396   }
2397   else if (t->spacetype == SPACE_NODE) {
2398     t->draw_handle_view = ED_region_draw_cb_activate(
2399         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2400     t->draw_handle_cursor = WM_paint_cursor_activate(
2401         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2402   }
2403   else if (t->spacetype == SPACE_GRAPH) {
2404     t->draw_handle_view = ED_region_draw_cb_activate(
2405         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2406     t->draw_handle_cursor = WM_paint_cursor_activate(
2407         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2408   }
2409   else if (t->spacetype == SPACE_ACTION) {
2410     t->draw_handle_view = ED_region_draw_cb_activate(
2411         t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
2412     t->draw_handle_cursor = WM_paint_cursor_activate(
2413         CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
2414   }
2415
2416   createTransData(C, t);  // make TransData structs from selection
2417
2418   if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
2419     ED_sculpt_init_transform(C);
2420   }
2421
2422   if (t->data_len_all == 0) {
2423     postTrans(C, t);
2424     return 0;
2425   }
2426
2427   if (event) {
2428     /* keymap for shortcut header prints */
2429     t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
2430
2431     /* Stupid code to have Ctrl-Click on gizmo work ok.
2432      *
2433      * Do this only for translation/rotation/resize because only these
2434      * modes are available from gizmo and doing such check could
2435      * lead to keymap conflicts for other modes (see #31584)
2436      */
2437     if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
2438       wmKeyMapItem *kmi;
2439
2440       for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
2441         if (kmi->flag & KMI_INACTIVE) {
2442           continue;
2443         }
2444
2445         if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
2446           if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) && event->ctrl) ||
2447               (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) ||
2448               (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) && event->alt) ||
2449               ((kmi->type == OSKEY) && event->oskey)) {
2450             t->modifiers |= MOD_SNAP_INVERT;
2451           }
2452           break;
2453         }
2454       }
2455     }
2456   }
2457
2458   initSnapping(t, op);  // Initialize snapping data AFTER mode flags
2459
2460   initSnapSpatial(t, t->snap_spatial);
2461
2462   /* EVIL! posemode code can switch translation to rotate when 1 bone is selected.
2463    * will be removed (ton) */
2464
2465   /* EVIL2: we gave as argument also texture space context bit... was cleared */
2466
2467   /* EVIL3: extend mode for animation editors also switches modes...
2468    * but is best way to avoid duplicate code */
2469   mode = t->mode;
2470
2471   calculatePropRatio(t);
2472   calculateCenter(t);
2473
2474   /* Overwrite initial values if operator supplied a non-null vector.
2475    *
2476    * Run before init functions so 'values_modal_offset' can be applied on mouse input.
2477    */
2478   BLI_assert(is_zero_v4(t->values_modal_offset));
2479   if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
2480     float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
2481
2482     if (RNA_property_array_check(prop)) {
2483       RNA_float_get_array(op->ptr, "value", values);
2484     }
2485     else {
2486       values[0] = RNA_float_get(op->ptr, "value");
2487     }
2488
2489     copy_v4_v4(t->values, values);
2490
2491     if (t->flag & T_MODAL) {
2492       copy_v4_v4(t->values_modal_offset, values);
2493       t->redraw = TREDRAW_HARD;
2494     }
2495     else {
2496       copy_v4_v4(t->values, values);
2497       t->flag |= T_INPUT_IS_VALUES_FINAL;
2498     }
2499   }
2500
2501   if (event) {
2502     /* Initialize accurate transform to settings requested by keymap. */
2503     bool use_accurate = false;
2504     if ((prop = RNA_struct_find_property(op->ptr, "use_accurate")) &&
2505         RNA_property_is_set(op->ptr, prop)) {
2506       if (RNA_property_boolean_get(op->ptr, prop)) {
2507         use_accurate = true;
2508       }
2509     }
2510     initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
2511   }
2512
2513   switch (mode) {
2514     case TFM_TRANSLATION:
2515       initTranslation(t);
2516       break;
2517     case TFM_ROTATION:
2518       initRotation(t);
2519       break;
2520     case TFM_RESIZE:
2521       initResize(t);
2522       break;
2523     case TFM_SKIN_RESIZE:
2524       initSkinResize(t);
2525       break;
2526     case TFM_TOSPHERE:
2527       initToSphere(t);
2528       break;
2529     case TFM_SHEAR:
2530       initShear(t);
2531       break;
2532     case TFM_BEND:
2533       initBend(t);
2534       break;
2535     case TFM_SHRINKFATTEN:
2536       initShrinkFatten(t);
2537       break;
2538     case TFM_TILT:
2539       initTilt(t);
2540       break;
2541     case TFM_CURVE_SHRINKFATTEN:
2542       initCurveShrinkFatten(t);
2543       break;
2544     case TFM_MASK_SHRINKFATTEN:
2545       initMaskShrinkFatten(t);
2546       break;
2547     case TFM_GPENCIL_SHRINKFATTEN:
2548       initGPShrinkFatten(t);
2549       break;
2550     case TFM_TRACKBALL:
2551       initTrackball(t);
2552       break;
2553     case TFM_PUSHPULL:
2554       initPushPull(t);
2555       break;
2556     case TFM_CREASE:
2557       initCrease(t);
2558       break;
2559     case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
2560       /* Note: we have to pick one, use the active object. */
2561       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
2562       bArmature *arm = tc->poseobj->data;
2563       if (arm->drawtype == ARM_ENVELOPE) {
2564         initBoneEnvelope(t);
2565         t->mode = TFM_BONE_ENVELOPE_DIST;
2566       }
2567       else {
2568         initBoneSize(t);
2569       }
2570       break;
2571     }
2572     case TFM_BONE_ENVELOPE:
2573       initBoneEnvelope(t);
2574       break;
2575     case TFM_BONE_ENVELOPE_DIST:
2576       initBoneEnvelope(t);
2577       t->mode = TFM_BONE_ENVELOPE_DIST;
2578       break;
2579     case TFM_EDGE_SLIDE:
2580     case TFM_VERT_SLIDE: {
2581       const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
2582       const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
2583       const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
2584       if (mode == TFM_EDGE_SLIDE) {
2585         const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
2586         initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
2587       }
2588       else {
2589         initVertSlide_ex(t, use_even, flipped, use_clamp);
2590       }
2591       break;
2592     }
2593     case TFM_BONE_ROLL:
2594       initBoneRoll(t);
2595       break;
2596     case TFM_TIME_TRANSLATE:
2597       initTimeTranslate(t);
2598       break;
2599     case TFM_TIME_SLIDE:
2600       initTimeSlide(t);
2601       break;
2602     case TFM_TIME_SCALE:
2603       initTimeScale(t);
2604       break;
2605     case TFM_TIME_DUPLICATE:
2606       /* same as TFM_TIME_EXTEND, but we need the mode info for later
2607        * so that duplicate-culling will work properly
2608        */
2609       if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
2610         initTranslation(t);
2611       }
2612       else {
2613         initTimeTranslate(t);
2614       }
2615       t->mode = mode;
2616       break;
2617     case TFM_TIME_EXTEND:
2618       /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
2619        * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
2620        * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
2621        * depending on which editor this was called from
2622        */
2623       if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
2624         initTranslation(t);
2625       }
2626       else {
2627         initTimeTranslate(t);
2628       }
2629       break;
2630     case TFM_BAKE_TIME:
2631       initBakeTime(t);
2632       break;
2633     case TFM_MIRROR:
2634       initMirror(t);
2635       break;
2636     case TFM_BWEIGHT:
2637       initBevelWeight(t);
2638       break;
2639     case TFM_ALIGN:
2640       initAlign(t);
2641       break;
2642     case TFM_SEQ_SLIDE:
2643       initSeqSlide(t);
2644       break;
2645     case TFM_NORMAL_ROTATION:
2646       initNormalRotation(t);
2647       break;
2648     case TFM_GPENCIL_OPACITY:
2649       initGPOpacity(t);
2650       break;
2651   }
2652
2653   if (t->state == TRANS_CANCEL) {
2654     postTrans(C, t);
2655     return 0;
2656   }
2657
2658   /* Transformation axis from operator */
2659   if ((prop = RNA_struct_find_property(op->ptr, "orient_axis")) &&
2660       RNA_property_is_set(op->ptr, prop)) {
2661     t->orient_axis = RNA_property_enum_get(op->ptr, prop);
2662   }
2663   if ((prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho")) &&
2664       RNA_property_is_set(op->ptr, prop)) {
2665     t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
2666   }
2667
2668   /* Constraint init from operator */
2669   if ((t->flag & T_MODAL) ||
2670       /* For mirror operator the constraint axes are effectively the values. */
2671       (RNA_struct_find_property(op->ptr, "value") == NULL)) {
2672     if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
2673         RNA_property_is_set(op->ptr, prop)) {
2674       bool constraint_axis[3];
2675
2676       RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
2677
2678       if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
2679         t->con.mode |= CON_APPLY;
2680
2681         if (constraint_axis[0]) {
2682           t->con.mode |= CON_AXIS0;
2683         }
2684         if (constraint_axis[1]) {
2685           t->con.mode |= CON_AXIS1;
2686         }
2687         if (constraint_axis[2]) {
2688           t->con.mode |= CON_AXIS2;
2689         }
2690
2691         setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
2692       }
2693     }
2694   }
2695   else {
2696     /* So we can adjust in non global orientation. */
2697     if (t->orientation.user != V3D_ORIENT_GLOBAL) {
2698       t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
2699       setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
2700     }
2701   }
2702
2703   /* Don't write into the values when non-modal because they are already set from operator redo
2704    * values. */
2705   if (t->flag & T_MODAL) {
2706     /* Setup the mouse input with initial values. */
2707     applyMouseInput(t, &t->mouse, t->mouse.imval, t->values);
2708   }
2709
2710   if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) {
2711     if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
2712
2713       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
2714         if ((((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH)) {
2715           BMEditMesh *em = NULL;  // BKE_editmesh_from_object(t->obedit);
2716           bool do_skip = false;
2717
2718           /* Currently only used for two of three most frequent transform ops,
2719            * can include more ops.
2720            * Note that scaling cannot be included here,
2721            * non-uniform scaling will affect normals. */
2722           if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
2723             if (em->bm->totvertsel == em->bm->totvert) {
2724               /* No need to invalidate if whole mesh is selected. */
2725               do_skip = true;
2726             }
2727           }
2728
2729           if (t->flag & T_MODAL) {
2730             RNA_property_boolean_set(op->ptr, prop, false);
2731           }
2732           else if (!do_skip) {
2733             const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
2734             if (preserve_clnor) {
2735               BKE_editmesh_lnorspace_update(em);
2736               t->flag |= T_CLNOR_REBUILD;
2737             }
2738             BM_lnorspace_invalidate(em->bm, true);
2739           }
2740         }
2741       }
2742     }
2743   }
2744
2745   t->context = NULL;
2746
2747   return 1;
2748 }
2749
2750 void transformApply(bContext *C, TransInfo *t)
2751 {
2752   t->context = C;
2753
2754   if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
2755     selectConstraint(t);
2756     if (t->transform) {
2757       t->transform(t, t->mval);  // calls recalcData()
2758       viewRedrawForce(C, t);
2759     }
2760     t->redraw = TREDRAW_NOTHING;
2761   }
2762   else if (t->redraw & TREDRAW_SOFT) {
2763     viewRedrawForce(C, t);
2764   }
2765
2766   /* If auto confirm is on, break after one pass */
2767   if (t->options & CTX_AUTOCONFIRM) {
2768     t->state = TRANS_CONFIRM;
2769   }
2770
2771   t->context = NULL;
2772 }
2773
2774 static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg)
2775 {
2776   TransInfo *t = arg;
2777
2778   if (t->redraw & TREDRAW_SOFT) {
2779     t->redraw |= TREDRAW_HARD;
2780     transformApply((bContext *)C, t);
2781   }
2782 }
2783
2784 int transformEnd(bContext *C, TransInfo *t)
2785 {
2786   int exit_code = OPERATOR_RUNNING_MODAL;
2787
2788   t->context = C;
2789
2790   if (t->state != TRANS_STARTING && t->state != TRANS_RUNNING) {
2791     /* handle restoring objects */
2792     if (t->state == TRANS_CANCEL) {
2793       /* exception, edge slide transformed UVs too */
2794       if (t->mode == TFM_EDGE_SLIDE) {
2795         doEdgeSlide(t, 0.0f);
2796       }
2797       else if (t->mode == TFM_VERT_SLIDE) {
2798         doVertSlide(t, 0.0f);
2799       }
2800
2801       exit_code = OPERATOR_CANCELLED;
2802       restoreTransObjects(t);  // calls recalcData()
2803     }
2804     else {
2805       if (t->flag & T_CLNOR_REBUILD) {
2806         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
2807           BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
2808           BM_lnorspace_rebuild(em->bm, true);
2809         }
2810       }
2811       exit_code = OPERATOR_FINISHED;
2812     }
2813
2814     /* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
2815     special_aftertrans_update(C, t);
2816
2817     /* free data */
2818     postTrans(C, t);
2819
2820     /* send events out for redraws */
2821     viewRedrawPost(C, t);
2822
2823     viewRedrawForce(C, t);
2824   }
2825
2826   t->context = NULL;
2827
2828   return exit_code;
2829 }
2830
2831 /* ************************** TRANSFORM LOCKS **************************** */
2832
2833 static void protectedTransBits(short protectflag, float vec[3])
2834 {
2835   if (protectflag & OB_LOCK_LOCX) {
2836     vec[0] = 0.0f;
2837   }
2838   if (protectflag & OB_LOCK_LOCY) {
2839     vec[1] = 0.0f;
2840   }
2841   if (protectflag & OB_LOCK_LOCZ) {
2842     vec[2] = 0.0f;
2843   }
2844 }
2845
2846 static void protectedSizeBits(short protectflag, float size[3])
2847 {
2848   if (protectflag & OB_LOCK_SCALEX) {
2849     size[0] = 1.0f;
2850   }
2851   if (protectflag & OB_LOCK_SCALEY) {
2852     size[1] = 1.0f;
2853   }
2854   if (protectflag & OB_LOCK_SCALEZ) {
2855     size[2] = 1.0f;
2856   }
2857 }
2858
2859 static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
2860 {
2861   if (protectflag & OB_LOCK_ROTX) {
2862     eul[0] = oldeul[0];
2863   }
2864   if (protectflag & OB_LOCK_ROTY) {
2865     eul[1] = oldeul[1];
2866   }
2867   if (protectflag & OB_LOCK_ROTZ) {
2868     eul[2] = oldeul[2];
2869   }
2870 }
2871
2872 /* this function only does the delta rotation */
2873 /* axis-angle is usually internally stored as quats... */
2874 static void protectedAxisAngleBits(
2875     short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle)
2876 {
2877   /* check that protection flags are set */
2878   if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
2879     return;
2880   }
2881
2882   if (protectflag & OB_LOCK_ROT4D) {
2883     /* axis-angle getting limited as 4D entities that they are... */
2884     if (protectflag & OB_LOCK_ROTW) {
2885       *angle = oldAngle;
2886     }
2887     if (protectflag & OB_LOCK_ROTX) {
2888       axis[0] = oldAxis[0];
2889     }
2890     if (protectflag & OB_LOCK_ROTY) {
2891       axis[1] = oldAxis[1];
2892     }
2893     if (protectflag & OB_LOCK_ROTZ) {
2894       axis[2] = oldAxis[2];
2895     }
2896   }
2897   else {
2898     /* axis-angle get limited with euler... */
2899     float eul[3], oldeul[3];
2900
2901     axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
2902     axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
2903
2904     if (protectflag & OB_LOCK_ROTX) {
2905       eul[0] = oldeul[0];
2906     }
2907     if (protectflag & OB_LOCK_ROTY) {
2908       eul[1] = oldeul[1];
2909     }
2910     if (protectflag & OB_LOCK_ROTZ) {
2911       eul[2] = oldeul[2];
2912     }
2913
2914     eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
2915
2916     /* When converting to axis-angle,
2917      * we need a special exception for the case when there is no axis. */
2918     if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
2919       /* for now, rotate around y-axis then (so that it simply becomes the roll) */
2920       axis[1] = 1.0f;
2921     }
2922   }
2923 }
2924
2925 /* this function only does the delta rotation */
2926 static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
2927 {
2928   /* check that protection flags are set */
2929   if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
2930     return;
2931   }
2932
2933   if (protectflag & OB_LOCK_ROT4D) {
2934     /* quaternions getting limited as 4D entities that they are... */
2935     if (protectflag & OB_LOCK_ROTW) {
2936       quat[0] = oldquat[0];
2937     }
2938     if (protectflag & OB_LOCK_ROTX) {
2939       quat[1] = oldquat[1];
2940     }
2941     if (protectflag & OB_LOCK_ROTY) {
2942       quat[2] = oldquat[2];
2943     }
2944     if (protectflag & OB_LOCK_ROTZ) {
2945       quat[3] = oldquat[3];
2946     }
2947   }
2948   else {
2949     /* quaternions get limited with euler... (compatibility mode) */
2950     float eul[3], oldeul[3], nquat[4], noldquat[4];
2951     float qlen;
2952
2953     qlen = normalize_qt_qt(nquat, quat);
2954     normalize_qt_qt(noldquat, oldquat);
2955
2956     quat_to_eul(eul, nquat);
2957     quat_to_eul(oldeul, noldquat);
2958
2959     if (protectflag & OB_LOCK_ROTX) {
2960       eul[0] = oldeul[0];
2961     }
2962     if (protectflag & OB_LOCK_ROTY) {
2963       eul[1] = oldeul[1];
2964     }
2965     if (protectflag & OB_LOCK_ROTZ) {
2966       eul[2] = oldeul[2];
2967     }
2968
2969     eul_to_quat(quat, eul);
2970
2971     /* restore original quat size */
2972     mul_qt_fl(quat, qlen);
2973
2974     /* quaternions flip w sign to accumulate rotations correctly */
2975     if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) {
2976       mul_qt_fl(quat, -1.0f);
2977     }
2978   }
2979 }
2980
2981 /* ******************* TRANSFORM LIMITS ********************** */
2982
2983 static void constraintTransLim(TransInfo *t, TransData *td)
2984 {
2985   if (td->con) {
2986     const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(
2987         CONSTRAINT_TYPE_LOCLIMIT);
2988     const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(
2989         CONSTRAINT_TYPE_DISTLIMIT);
2990
2991     bConstraintOb cob = {NULL};
2992     bConstraint *con;
2993     float ctime = (float)(t->scene->r.cfra);
2994
2995     /* Make a temporary bConstraintOb for using these limit constraints
2996      * - they only care that cob->matrix is correctly set ;-)
2997      * - current space should be local
2998      */
2999     unit_m4(cob.matrix);
3000     copy_v3_v3(cob.matrix[3], td->loc);
3001
3002     /* Evaluate valid constraints */
3003     for (con = td->con; con; con = con->next) {
3004       const bConstraintTypeInfo *cti = NULL;
3005       ListBase targets = {NULL, NULL};
3006
3007       /* only consider constraint if enabled */
3008       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
3009         continue;
3010       }
3011       if (con->enforce == 0.0f) {
3012         continue;
3013       }
3014
3015       /* only use it if it's tagged for this purpose (and the right type) */
3016       if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
3017         bLocLimitConstraint *data = con->data;
3018
3019         if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
3020           continue;
3021         }
3022         cti = ctiLoc;
3023       }
3024       else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
3025         bDistLimitConstraint *data = con->data;
3026
3027         if ((data->flag & LIMITDIST_TRANSFORM) == 0) {
3028           continue;
3029         }
3030         cti = ctiDist;
3031       }
3032
3033       if (cti) {
3034         /* do space conversions */
3035         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3036           /* just multiply by td->mtx (this should be ok) */
3037           mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
3038         }
3039         else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
3040           /* skip... incompatible spacetype */
3041           continue;
3042         }
3043
3044         /* get constraint targets if needed */
3045         BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
3046
3047         /* do constraint */
3048         cti->evaluate_constraint(con, &cob, &targets);
3049
3050         /* convert spaces again */
3051         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3052           /* just multiply by td->smtx (this should be ok) */
3053           mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
3054         }
3055
3056         /* free targets list */
3057         BLI_freelistN(&targets);
3058       }
3059     }
3060
3061     /* copy results from cob->matrix */
3062     copy_v3_v3(td->loc, cob.matrix[3]);
3063   }
3064 }
3065
3066 static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
3067 {
3068   /* Make a temporary bConstraintOb for use by limit constraints
3069    * - they only care that cob->matrix is correctly set ;-)
3070    * - current space should be local
3071    */
3072   memset(cob, 0, sizeof(bConstraintOb));
3073   if (td->ext) {
3074     if (td->ext->rotOrder == ROT_MODE_QUAT) {
3075       /* quats */
3076       /* objects and bones do normalization first too, otherwise
3077        * we don't necessarily end up with a rotation matrix, and
3078        * then conversion back to quat gives a different result */
3079       float quat[4];
3080       normalize_qt_qt(quat, td->ext->quat);
3081       quat_to_mat4(cob->matrix, quat);
3082     }
3083     else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
3084       /* axis angle */
3085       axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
3086     }
3087     else {
3088       /* eulers */
3089       eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
3090     }
3091   }
3092 }
3093
3094 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
3095 {
3096   if (td->con) {
3097     const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
3098     bConstraintOb cob;
3099     bConstraint *con;
3100     bool do_limit = false;
3101
3102     /* Evaluate valid constraints */
3103     for (con = td->con; con; con = con->next) {
3104       /* only consider constraint if enabled */
3105       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
3106         continue;
3107       }
3108       if (con->enforce == 0.0f) {
3109         continue;
3110       }
3111
3112       /* we're only interested in Limit-Rotation constraints */
3113       if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
3114         bRotLimitConstraint *data = con->data;
3115
3116         /* only use it if it's tagged for this purpose */
3117         if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
3118           continue;
3119         }
3120
3121         /* skip incompatible spacetypes */
3122         if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
3123           continue;
3124         }
3125
3126         /* only do conversion if necessary, to preserve quats and eulers */
3127         if (do_limit == false) {
3128           constraintob_from_transdata(&cob, td);
3129           do_limit = true;
3130         }
3131
3132         /* do space conversions */
3133         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3134           /* just multiply by td->mtx (this should be ok) */
3135           mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
3136         }
3137
3138         /* do constraint */
3139         cti->evaluate_constraint(con, &cob, NULL);
3140
3141         /* convert spaces again */
3142         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3143           /* just multiply by td->smtx (this should be ok) */
3144           mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
3145         }
3146       }
3147     }
3148
3149     if (do_limit) {
3150       /* copy results from cob->matrix */
3151       if (td->ext->rotOrder == ROT_MODE_QUAT) {
3152         /* quats */
3153         mat4_to_quat(td->ext->quat, cob.matrix);
3154       }
3155       else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
3156         /* axis angle */
3157         mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix);
3158       }
3159       else {
3160         /* eulers */
3161         mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
3162       }
3163     }
3164   }
3165 }
3166
3167 static void constraintSizeLim(TransInfo *t, TransData *td)
3168 {
3169   if (td->con && td->ext) {
3170     const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
3171     bConstraintOb cob = {NULL};
3172     bConstraint *con;
3173     float size_sign[3], size_abs[3];
3174     int i;
3175
3176     /* Make a temporary bConstraintOb for using these limit constraints
3177      * - they only care that cob->matrix is correctly set ;-)
3178      * - current space should be local
3179      */
3180     if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
3181       /* scale val and reset size */
3182       return;  // TODO: fix this case
3183     }
3184     else {
3185       /* Reset val if SINGLESIZE but using a constraint */
3186       if (td->flag & TD_SINGLESIZE) {
3187         return;
3188       }
3189
3190       /* separate out sign to apply back later */
3191       for (i = 0; i < 3; i++) {
3192         size_sign[i] = signf(td->ext->size[i]);
3193         size_abs[i] = fabsf(td->ext->size[i]);
3194       }
3195
3196       size_to_mat4(cob.matrix, size_abs);
3197     }
3198
3199     /* Evaluate valid constraints */
3200     for (con = td->con; con; con = con->next) {
3201       /* only consider constraint if enabled */
3202       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
3203         continue;
3204       }
3205       if (con->enforce == 0.0f) {
3206         continue;
3207       }
3208
3209       /* we're only interested in Limit-Scale constraints */
3210       if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
3211         bSizeLimitConstraint *data = con->data;
3212
3213         /* only use it if it's tagged for this purpose */
3214         if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
3215           continue;
3216         }
3217
3218         /* do space conversions */
3219         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3220           /* just multiply by td->mtx (this should be ok) */
3221           mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
3222         }
3223         else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
3224           /* skip... incompatible spacetype */
3225           continue;
3226         }
3227
3228         /* do constraint */
3229         cti->evaluate_constraint(con, &cob, NULL);
3230
3231         /* convert spaces again */
3232         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
3233           /* just multiply by td->smtx (this should be ok) */
3234           mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
3235         }
3236       }
3237     }
3238
3239     /* copy results from cob->matrix */
3240     if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
3241       /* scale val and reset size */
3242       return;  // TODO: fix this case
3243     }
3244     else {
3245       /* Reset val if SINGLESIZE but using a constraint */
3246       if (td->flag & TD_SINGLESIZE) {
3247         return;
3248       }
3249
3250       /* extrace scale from matrix and apply back sign */
3251       mat4_to_size(td->ext->size, cob.matrix);
3252       mul_v3_v3(td->ext->size, size_sign);
3253     }
3254   }
3255 }
3256
3257 /* -------------------------------------------------------------------- */
3258 /* Transform (Bend) */
3259
3260 /** \name Transform Bend
3261  * \{ */
3262
3263 struct BendCustomData {
3264   /* All values are in global space. */
3265   float warp_sta[3];
3266   float warp_end[3];
3267
3268   float warp_nor[3];
3269   float warp_tan[3];
3270
3271   /* for applying the mouse distance */
3272   float warp_init_dist;
3273 };
3274
3275 static void initBend(TransInfo *t)
3276 {
3277   const float mval_fl[2] = {UNPACK2(t->mval)};
3278   const float *curs;
3279   float tvec[3];
3280   struct BendCustomData *data;
3281
3282   t->mode = TFM_BEND;
3283   t->transform = Bend;
3284   t->handleEvent = handleEventBend;
3285
3286   setInputPostFct(&t->mouse, postInputRotation);
3287   initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING);
3288
3289   t->idx_max = 1;
3290   t->num.idx_max = 1;
3291   t->snap[0] = 0.0f;
3292   t->snap[1] = SNAP_INCREMENTAL_ANGLE;
3293   t->snap[2] = t->snap[1] * 0.2;
3294
3295   copy_v3_fl(t->num.val_inc, t->snap[1]);
3296   t->num.unit_sys = t->scene->unit.system;
3297   t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
3298   t->num.unit_type[0] = B_UNIT_ROTATION;
3299   t->num.unit_type[1] = B_UNIT_LENGTH;
3300
3301   t->flag |= T_NO_CONSTRAINT;
3302
3303   // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
3304   if ((t->flag & T_OVERRIDE_CENTER) == 0) {
3305     calculateCenterCursor(t, t->center_global);
3306   }
3307   calculateCenterLocal(t, t->center_global);
3308
3309   t->val = 0.0f;
3310
3311   data = MEM_callocN(sizeof(*data), __func__);
3312
3313   curs = t->scene->cursor.location;
3314   copy_v3_v3(data->warp_sta, curs);
3315   ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
3316
3317   copy_v3_v3(data->warp_nor, t->viewinv[2]);
3318   normalize_v3(data->warp_nor);
3319
3320   /* tangent */
3321   sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
3322   cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
3323   normalize_v3(data->warp_tan);
3324
3325   data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
3326
3327   t->custom.mode.data = data;
3328   t->custom.mode.use_free = true;
3329 }
3330
3331 static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
3332 {
3333   eRedrawFlag status = TREDRAW_NOTHING;
3334
3335   if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
3336     status = TREDRAW_HARD;
3337   }
3338
3339   return status;
3340 }
3341
3342 static void Bend(TransInfo *t, const int UNUSED(mval[2]))
3343 {
3344   float vec[3];
3345   float pivot_global[3];
3346   float warp_end_radius_global[3];
3347   int i;
3348   char str[UI_MAX_DRAW_STR];
3349   const struct BendCustomData *data = t->custom.mode.data;
3350   const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
3351
3352   union {
3353     struct {
3354       float angle, scale;
3355     };
3356     float vector[2];
3357   } values;
3358
3359   /* amount of radians for bend */
3360   copy_v2_v2(values.vector, t->values);
3361
3362 #if 0
3363   snapGrid(t, angle_rad);
3364 #else
3365   /* hrmf, snapping radius is using 'angle' steps, need to convert to something else
3366    * this isnt essential but nicer to give reasonable snapping values for radius */
3367   if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) {
3368     const float radius_snap = 0.1f;
3369     const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
3370     values.scale *= snap_hack;
3371     snapGridIncrement(t, values.vector);
3372     values.scale /= snap_hack;
3373   }
3374 #endif
3375
3376   if (applyNumInput(&t->num, values.vector)) {
3377     values.scale = values.scale / data->warp_init_dist;
3378   }
3379
3380   copy_v2_v2(t->values_final, values.vector);
3381
3382   /* header print for NumInput */
3383   if (hasNumInput(&t->num)) {
3384     char c[NUM_STR_REP_LEN * 2];
3385
3386     outputNumInput(&(t->num), c, &t->scene->unit);
3387
3388     BLI_snprintf(str,
3389                  sizeof(str),
3390                  TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
3391                  &c[0],
3392                  &c[NUM_STR_REP_LEN],
3393                  WM_bool_as_string(is_clamp));
3394   }
3395   else {
3396     /* default header print */
3397     BLI_snprintf(str,
3398                  sizeof(str),
3399                  TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
3400                  RAD2DEGF(values.angle),
3401                  values.scale * data->warp_init_dist,
3402                  WM_bool_as_string(is_clamp));
3403   }
3404
3405   values.angle *= -1.0f;
3406   values.scale *= data->warp_init_dist;
3407
3408   /* calc 'data->warp_end' from 'data->warp_end_init' */
3409   copy_v3_v3(warp_end_radius_global, data->warp_end);
3410   dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
3411   /* done */
3412
3413   /* calculate pivot */
3414   copy_v3_v3(pivot_global, data->warp_sta);
3415   if (values.angle > 0.0f) {
3416     madd_v3_v3fl(pivot_global,
3417                  data->warp_tan,
3418                  -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
3419   }
3420   else {
3421     madd_v3_v3fl(pivot_global,
3422                  data->warp_tan,
3423                  +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
3424   }
3425
3426   /* TODO(campbell): xform, compensate object center. */
3427   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
3428     TransData *td = tc->data;
3429
3430     float warp_sta_local[3];
3431     float warp_end_local[3];
3432     float warp_end_radius_local[3];
3433     float pivot_local[3];
3434
3435     if (tc->use_local_mat) {
3436       sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]);
3437       sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]);
3438       sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
3439       sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
3440     }
3441     else {
3442       copy_v3_v3(warp_sta_local, data->warp_sta);
3443       copy_v3_v3(warp_end_local, data->warp_end);
3444       copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
3445       copy_v3_v3(pivot_local, pivot_global);
3446     }
3447
3448     for (i = 0; i < tc->data_len; i++, td++) {
3449       float mat[3][3];
3450       float delta[3];
3451       float fac, fac_scaled;
3452
3453       if (td->flag & TD_NOACTION) {
3454         break;
3455       }
3456
3457       if (td->flag & TD_SKIP) {
3458         continue;
3459       }
3460
3461       if (UNLIKELY(values.angle == 0.0f)) {
3462         copy_v3_v3(td->loc, td->iloc);
3463         continue;
3464       }
3465
3466       copy_v3_v3(vec, td->iloc);
3467       mul_m3_v3(td->mtx, vec);
3468
3469       fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
3470       if (is_clamp) {
3471         CLAMP(fac, 0.0f, 1.0f);
3472       }
3473
3474       if (t->options & CTX_GPENCIL_STROKES) {
3475         /* grease pencil multiframe falloff */
3476         bGPDstroke *gps = (bGPDstroke *)td->extra;
3477         if (gps != NULL) {
3478           fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff;
3479         }
3480         else {
3481           fac_scaled = fac * td->factor;
3482         }
3483       }
3484       else {
3485         fac_scaled = fac * td->factor;
3486       }
3487
3488       axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
3489       interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
3490       sub_v3_v3(delta, warp_sta_local);
3491
3492       /* delta is subtracted, rotation adds back this offset */
3493       sub_v3_v3(vec, delta);
3494
3495       sub_v3_v3(vec, pivot_local);
3496       mul_m3_v3(mat, vec);
3497       add_v3_v3(vec, pivot_local);
3498
3499       mul_m3_v3(td->smtx, vec);
3500
3501       /* rotation */
3502       if ((t->flag & T_POINTS) == 0) {
3503         ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
3504       }
3505
3506       /* location */
3507       copy_v3_v3(td->loc, vec);
3508     }
3509   }
3510
3511   recalcData(t);
3512
3513   ED_area_status_text(t->sa, str);
3514 }
3515 /** \} */
3516
3517 /* -------------------------------------------------------------------- */
3518 /* Transform (Shear) */
3519
3520 /** \name Transform Shear
3521  * \{ */
3522
3523 static void initShear_mouseInputMode(TransInfo *t)
3524 {
3525   float dir[3];
3526   copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
3527
3528   /* Without this, half the gizmo handles move in the opposite direction. */
3529   if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
3530     negate_v3(dir);
3531   }
3532
3533   mul_mat3_m4_v3(t->viewmat, dir);
3534   if (normalize_v2(dir) == 0.0f) {
3535     dir[0] = 1.0f;
3536   }
3537   setCustomPointsFromDirection(t, &t->mouse, dir);
3538
3539   initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
3540 }
3541
3542 static void initShear(TransInfo *t)
3543 {
3544   t->mode = TFM_SHEAR;
3545   t->transform = applyShear;
3546   t->handleEvent = handleEventShear;
3547
3548   if (t->orient_axis == t->orient_axis_ortho) {
3549     t->orient_axis = 2;
3550     t->orient_axis_ortho = 1;
3551   }
3552
3553   initShear_mouseInputMode(t);
3554
3555   t->idx_max = 0;
3556   t->num.idx_max = 0;
3557   t->snap[0] = 0.0f;
3558   t->snap[1] = 0.1f;
3559   t->snap[2] = t->snap[1] * 0.1f;
3560
3561   copy_v3_fl(t->num.val_inc, t->snap[1]);
3562   t->num.unit_sys = t->scene->unit.system;
3563   t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */
3564
3565   t->flag |= T_NO_CONSTRAINT;
3566 }
3567
3568 static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
3569 {
3570   eRedrawFlag status = TREDRAW_NOTHING;
3571
3572   if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
3573     /* Use custom.mode.data pointer to signal Shear direction */
3574     do {
3575       t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3;
3576     } while (t->orient_axis_ortho == t->orient_axis);
3577
3578     initShear_mouseInputMode(t);
3579
3580     status = TREDRAW_HARD;
3581   }
3582   else if (event->type == XKEY && event->val == KM_PRESS) {
3583     t->orient_axis_ortho = (t->orient_axis + 1) % 3;
3584     initShear_mouseInputMode(t);
3585
3586     status = TREDRAW_HARD;
3587   }
3588   else if (event->type == YKEY && event->val == KM_PRESS) {
3589     t->orient_axis_ortho = (t->orient_axis + 2) % 3;
3590     initShear_mouseInputMode(t);
3591
3592     status = TREDRAW_HARD;
3593   }
3594
3595   return status;
3596 }
3597
3598 static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
3599 {
3600   float vec[3];
3601   float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
3602   float value;
3603   int i;
3604   char str[UI_MAX_DRAW_STR];
3605   const bool is_local_center = transdata_check_local_center(t, t->around);
3606
3607   value = t->values[0];
3608
3609   snapGridIncrement(t, &value);
3610
3611   applyNumInput(&t->num, &value);
3612
3613   t->values_final[0] = value;
3614
3615   /* header print for NumInput */
3616   if (hasNumInput(&t->num)) {
3617     char c[NUM_STR_REP_LEN];
3618
3619     outputNumInput(&(t->num), c, &t->scene->unit);
3620
3621     BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext);
3622   }
3623   else {
3624     /* default header print */
3625     BLI_snprintf(str,
3626                  sizeof(str),
3627                  TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"),
3628                  value,
3629                  t->proptext);
3630   }
3631
3632   unit_m3(smat);
3633   smat[1][0] = value;
3634
3635   copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
3636   copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
3637   cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
3638   invert_m3_m3(axismat, axismat_inv);
3639
3640   mul_m3_series(totmat, axismat_inv, smat, axismat);
3641
3642   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
3643     TransData *td = tc->data;
3644     for (i = 0; i < tc->data_len; i++, td++) {
3645       const float *center, *co;
3646
3647       if (td->flag & TD_NOACTION) {
3648         break;
3649       }
3650
3651       if (td->flag & TD_SKIP) {
3652         continue;
3653       }
3654
3655       if (t->flag & T_EDIT) {
3656         mul_m3_series(tmat, td->smtx, totmat, td->mtx);
3657       }
3658       else {
3659         copy_m3_m3(tmat, totmat);
3660       }
3661
3662       if (is_local_center) {
3663         center = td->center;
3664         co = td->loc;