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