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