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