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