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