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