e12f1b4286a4095a2c4b89c4919d1001d1e34363
[blender.git] / source / blender / editors / transform / transform_manipulator.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) 2005 Blender Foundation
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_manipulator.c
29  *  \ingroup edtransform
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "DNA_armature_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_gpencil_types.h"
41 #include "DNA_lattice_types.h"
42 #include "DNA_manipulator_types.h"
43 #include "DNA_meta_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_view3d_types.h"
47
48 #include "BLI_listbase.h"
49 #include "BLI_math.h"
50 #include "BLI_utildefines.h"
51
52 #include "RNA_access.h"
53
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_curve.h"
57 #include "BKE_global.h"
58 #include "BKE_particle.h"
59 #include "BKE_pointcache.h"
60 #include "BKE_editmesh.h"
61 #include "BKE_lattice.h"
62 #include "BKE_gpencil.h"
63
64 #include "BIF_gl.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "ED_armature.h"
70 #include "ED_curve.h"
71 #include "ED_object.h"
72 #include "ED_particle.h"
73 #include "ED_view3d.h"
74 #include "ED_gpencil.h"
75 #include "ED_screen.h"
76
77 #include "UI_resources.h"
78
79 /* local module include */
80 #include "transform.h"
81
82 #include "MEM_guardedalloc.h"
83
84 #include "GPU_select.h"
85 #include "GPU_immediate.h"
86 #include "GPU_matrix.h"
87
88 /* return codes for select, and drawing flags */
89
90 #define MAN_TRANS_X             (1 << 0)
91 #define MAN_TRANS_Y             (1 << 1)
92 #define MAN_TRANS_Z             (1 << 2)
93 #define MAN_TRANS_C             (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
94
95 #define MAN_ROT_X               (1 << 3)
96 #define MAN_ROT_Y               (1 << 4)
97 #define MAN_ROT_Z               (1 << 5)
98 #define MAN_ROT_C               (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)
99
100 #define MAN_SCALE_X             (1 << 8)
101 #define MAN_SCALE_Y             (1 << 9)
102 #define MAN_SCALE_Z             (1 << 10)
103 #define MAN_SCALE_C             (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
104
105 /* threshold for testing view aligned manipulator axis */
106 #define TW_AXIS_DOT_MIN 0.02f
107 #define TW_AXIS_DOT_MAX 0.1f
108
109 /* axes as index */
110 enum {
111         MAN_AXIS_TRANS_X = 0,
112         MAN_AXIS_TRANS_Y,
113         MAN_AXIS_TRANS_Z,
114         MAN_AXIS_TRANS_C,
115
116         MAN_AXIS_ROT_X,
117         MAN_AXIS_ROT_Y,
118         MAN_AXIS_ROT_Z,
119         MAN_AXIS_ROT_C,
120         MAN_AXIS_ROT_T, /* trackball rotation */
121
122         MAN_AXIS_SCALE_X,
123         MAN_AXIS_SCALE_Y,
124         MAN_AXIS_SCALE_Z,
125         MAN_AXIS_SCALE_C,
126
127         /* special */
128         MAN_AXIS_TRANS_XY,
129         MAN_AXIS_TRANS_YZ,
130         MAN_AXIS_TRANS_ZX,
131
132         MAN_AXIS_SCALE_XY,
133         MAN_AXIS_SCALE_YZ,
134         MAN_AXIS_SCALE_ZX,
135
136         MAN_AXIS_LAST,
137 };
138
139 /* axis types */
140 enum {
141         MAN_AXES_ALL = 0,
142         MAN_AXES_TRANSLATE,
143         MAN_AXES_ROTATE,
144         MAN_AXES_SCALE,
145 };
146
147 typedef struct ManipulatorGroup {
148         bool all_hidden;
149
150         struct wmManipulator *translate_x,
151                         *translate_y,
152                         *translate_z,
153                         *translate_xy,
154                         *translate_yz,
155                         *translate_zx,
156                         *translate_c,
157
158                         *rotate_x,
159                         *rotate_y,
160                         *rotate_z,
161                         *rotate_c,
162                         *rotate_t, /* trackball rotation */
163
164                         *scale_x,
165                         *scale_y,
166                         *scale_z,
167                         *scale_xy,
168                         *scale_yz,
169                         *scale_zx,
170                         *scale_c;
171 } ManipulatorGroup;
172
173
174 /* **************** Utilities **************** */
175
176 /* loop over axes */
177 #define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
178         { \
179                 wmManipulator *axis; \
180                 int axis_idx; \
181                 for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
182                         axis = manipulator_get_axis_from_index(man, axis_idx);
183
184 #define MAN_ITER_AXES_END \
185                 } \
186         } ((void)0)
187
188 static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx)
189 {
190         BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
191
192         switch (axis_idx) {
193                 case MAN_AXIS_TRANS_X:
194                         return man->translate_x;
195                 case MAN_AXIS_TRANS_Y:
196                         return man->translate_y;
197                 case MAN_AXIS_TRANS_Z:
198                         return man->translate_z;
199                 case MAN_AXIS_TRANS_XY:
200                         return man->translate_xy;
201                 case MAN_AXIS_TRANS_YZ:
202                         return man->translate_yz;
203                 case MAN_AXIS_TRANS_ZX:
204                         return man->translate_zx;
205                 case MAN_AXIS_TRANS_C:
206                         return man->translate_c;
207                 case MAN_AXIS_ROT_X:
208                         return man->rotate_x;
209                 case MAN_AXIS_ROT_Y:
210                         return man->rotate_y;
211                 case MAN_AXIS_ROT_Z:
212                         return man->rotate_z;
213                 case MAN_AXIS_ROT_C:
214                         return man->rotate_c;
215                 case MAN_AXIS_ROT_T:
216                         return man->rotate_t;
217                 case MAN_AXIS_SCALE_X:
218                         return man->scale_x;
219                 case MAN_AXIS_SCALE_Y:
220                         return man->scale_y;
221                 case MAN_AXIS_SCALE_Z:
222                         return man->scale_z;
223                 case MAN_AXIS_SCALE_XY:
224                         return man->scale_xy;
225                 case MAN_AXIS_SCALE_YZ:
226                         return man->scale_yz;
227                 case MAN_AXIS_SCALE_ZX:
228                         return man->scale_zx;
229                 case MAN_AXIS_SCALE_C:
230                         return man->scale_c;
231         }
232
233         return NULL;
234 }
235
236 static short manipulator_get_axis_type(const ManipulatorGroup *man, const wmManipulator *axis)
237 {
238         if (ELEM(axis, man->translate_x, man->translate_y, man->translate_z, man->translate_c,
239                  man->translate_xy, man->translate_yz, man->translate_zx))
240         {
241                 return MAN_AXES_TRANSLATE;
242         }
243         else if (ELEM(axis, man->rotate_x, man->rotate_y, man->rotate_z, man->rotate_c, man->rotate_t)) {
244                 return MAN_AXES_ROTATE;
245         }
246         else {
247                 return MAN_AXES_SCALE;
248         }
249 }
250
251 /* get index within axis type, so that x == 0, y == 1 and z == 2, no matter which axis type */
252 static unsigned int manipulator_index_normalize(const int axis_idx)
253 {
254         if (axis_idx > MAN_AXIS_TRANS_ZX) {
255                 return axis_idx - 16;
256         }
257         else if (axis_idx > MAN_AXIS_SCALE_C) {
258                 return axis_idx - 13;
259         }
260         else if (axis_idx > MAN_AXIS_ROT_T) {
261                 return axis_idx - 9;
262         }
263         else if (axis_idx > MAN_AXIS_TRANS_C) {
264                 return axis_idx - 4;
265         }
266
267         return axis_idx;
268 }
269
270 static bool manipulator_is_axis_visible(
271         const View3D *v3d, const RegionView3D *rv3d,
272         const float idot[3], const int axis_type, const int axis_idx)
273 {
274         const unsigned int aidx_norm = manipulator_index_normalize(axis_idx);
275         /* don't draw axis perpendicular to the view */
276         if (aidx_norm < 3 && idot[aidx_norm] < TW_AXIS_DOT_MIN) {
277                 return false;
278         }
279
280         if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) ||
281             (axis_type == MAN_AXES_ROTATE && !(v3d->twtype & V3D_MANIP_ROTATE)) ||
282             (axis_type == MAN_AXES_SCALE && !(v3d->twtype & V3D_MANIP_SCALE)))
283         {
284                 return false;
285         }
286
287         switch (axis_idx) {
288                 case MAN_AXIS_TRANS_X:
289                         return (rv3d->twdrawflag & MAN_TRANS_X);
290                 case MAN_AXIS_TRANS_Y:
291                         return (rv3d->twdrawflag & MAN_TRANS_Y);
292                 case MAN_AXIS_TRANS_Z:
293                         return (rv3d->twdrawflag & MAN_TRANS_Z);
294                 case MAN_AXIS_TRANS_C:
295                         return (rv3d->twdrawflag & MAN_TRANS_C);
296                 case MAN_AXIS_ROT_X:
297                         return (rv3d->twdrawflag & MAN_ROT_X);
298                 case MAN_AXIS_ROT_Y:
299                         return (rv3d->twdrawflag & MAN_ROT_Y);
300                 case MAN_AXIS_ROT_Z:
301                         return (rv3d->twdrawflag & MAN_ROT_Z);
302                 case MAN_AXIS_ROT_C:
303                 case MAN_AXIS_ROT_T:
304                         return (rv3d->twdrawflag & MAN_ROT_C);
305                 case MAN_AXIS_SCALE_X:
306                         return (rv3d->twdrawflag & MAN_SCALE_X);
307                 case MAN_AXIS_SCALE_Y:
308                         return (rv3d->twdrawflag & MAN_SCALE_Y);
309                 case MAN_AXIS_SCALE_Z:
310                         return (rv3d->twdrawflag & MAN_SCALE_Z);
311                 case MAN_AXIS_SCALE_C:
312                         return (rv3d->twdrawflag & MAN_SCALE_C && (v3d->twtype & V3D_MANIP_TRANSLATE) == 0);
313                 case MAN_AXIS_TRANS_XY:
314                         return (rv3d->twdrawflag & MAN_TRANS_X &&
315                                 rv3d->twdrawflag & MAN_TRANS_Y &&
316                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
317                 case MAN_AXIS_TRANS_YZ:
318                         return (rv3d->twdrawflag & MAN_TRANS_Y &&
319                                 rv3d->twdrawflag & MAN_TRANS_Z &&
320                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
321                 case MAN_AXIS_TRANS_ZX:
322                         return (rv3d->twdrawflag & MAN_TRANS_Z &&
323                                 rv3d->twdrawflag & MAN_TRANS_X &&
324                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
325                 case MAN_AXIS_SCALE_XY:
326                         return (rv3d->twdrawflag & MAN_SCALE_X &&
327                                 rv3d->twdrawflag & MAN_SCALE_Y &&
328                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
329                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
330                 case MAN_AXIS_SCALE_YZ:
331                         return (rv3d->twdrawflag & MAN_SCALE_Y &&
332                                 rv3d->twdrawflag & MAN_SCALE_Z &&
333                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
334                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
335                 case MAN_AXIS_SCALE_ZX:
336                         return (rv3d->twdrawflag & MAN_SCALE_Z &&
337                                 rv3d->twdrawflag & MAN_SCALE_X &&
338                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
339                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
340         }
341         return false;
342 }
343
344 static void manipulator_get_axis_color(
345         const int axis_idx, const float idot[3],
346         float r_col[4], float r_col_hi[4])
347 {
348         /* alpha values for normal/highlighted states */
349         const float alpha = 0.6f;
350         const float alpha_hi = 1.0f;
351         float alpha_fac;
352
353         const int axis_idx_norm = manipulator_index_normalize(axis_idx);
354         /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */
355         if (axis_idx_norm < 3) {
356                 const float idot_axis = idot[axis_idx_norm];
357                 alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ?
358                         1.0f : (idot_axis < TW_AXIS_DOT_MIN) ?
359                         0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
360         }
361         else {
362                 /* trackball rotation axis is a special case, we only draw a slight overlay */
363                 alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
364         }
365
366         switch (axis_idx) {
367                 case MAN_AXIS_TRANS_X:
368                 case MAN_AXIS_ROT_X:
369                 case MAN_AXIS_SCALE_X:
370                 case MAN_AXIS_TRANS_XY:
371                 case MAN_AXIS_SCALE_XY:
372                         UI_GetThemeColor4fv(TH_AXIS_X, r_col);
373                         break;
374                 case MAN_AXIS_TRANS_Y:
375                 case MAN_AXIS_ROT_Y:
376                 case MAN_AXIS_SCALE_Y:
377                 case MAN_AXIS_TRANS_YZ:
378                 case MAN_AXIS_SCALE_YZ:
379                         UI_GetThemeColor4fv(TH_AXIS_Y, r_col);
380                         break;
381                 case MAN_AXIS_TRANS_Z:
382                 case MAN_AXIS_ROT_Z:
383                 case MAN_AXIS_SCALE_Z:
384                 case MAN_AXIS_TRANS_ZX:
385                 case MAN_AXIS_SCALE_ZX:
386                         UI_GetThemeColor4fv(TH_AXIS_Z, r_col);
387                         break;
388                 case MAN_AXIS_TRANS_C:
389                 case MAN_AXIS_ROT_C:
390                 case MAN_AXIS_SCALE_C:
391                 case MAN_AXIS_ROT_T:
392                         copy_v4_fl(r_col, 1.0f);
393                         break;
394         }
395
396         copy_v4_v4(r_col_hi, r_col);
397
398         r_col[3] = alpha * alpha_fac;
399         r_col_hi[3] = alpha_hi * alpha_fac;
400 }
401
402 static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3])
403 {
404         zero_v3_int(r_axis);
405
406         switch (axis_idx) {
407                 case MAN_AXIS_TRANS_X:
408                 case MAN_AXIS_ROT_X:
409                 case MAN_AXIS_SCALE_X:
410                         r_axis[0] = 1;
411                         break;
412                 case MAN_AXIS_TRANS_Y:
413                 case MAN_AXIS_ROT_Y:
414                 case MAN_AXIS_SCALE_Y:
415                         r_axis[1] = 1;
416                         break;
417                 case MAN_AXIS_TRANS_Z:
418                 case MAN_AXIS_ROT_Z:
419                 case MAN_AXIS_SCALE_Z:
420                         r_axis[2] = 1;
421                         break;
422                 case MAN_AXIS_TRANS_XY:
423                 case MAN_AXIS_SCALE_XY:
424                         r_axis[0] = r_axis[1] = 1;
425                         break;
426                 case MAN_AXIS_TRANS_YZ:
427                 case MAN_AXIS_SCALE_YZ:
428                         r_axis[1] = r_axis[2] = 1;
429                         break;
430                 case MAN_AXIS_TRANS_ZX:
431                 case MAN_AXIS_SCALE_ZX:
432                         r_axis[2] = r_axis[0] = 1;
433                         break;
434                 default:
435                         break;
436         }
437 }
438
439
440 /* **************** Preparation Stuff **************** */
441
442 /* transform widget center calc helper for below */
443 static void calc_tw_center(Scene *scene, const float co[3])
444 {
445         float *twcent = scene->twcent;
446         float *min = scene->twmin;
447         float *max = scene->twmax;
448
449         minmax_v3v3_v3(min, max, co);
450         add_v3_v3(twcent, co);
451 }
452
453 static void protectflag_to_drawflags(short protectflag, short *drawflags)
454 {
455         if (protectflag & OB_LOCK_LOCX)
456                 *drawflags &= ~MAN_TRANS_X;
457         if (protectflag & OB_LOCK_LOCY)
458                 *drawflags &= ~MAN_TRANS_Y;
459         if (protectflag & OB_LOCK_LOCZ)
460                 *drawflags &= ~MAN_TRANS_Z;
461
462         if (protectflag & OB_LOCK_ROTX)
463                 *drawflags &= ~MAN_ROT_X;
464         if (protectflag & OB_LOCK_ROTY)
465                 *drawflags &= ~MAN_ROT_Y;
466         if (protectflag & OB_LOCK_ROTZ)
467                 *drawflags &= ~MAN_ROT_Z;
468
469         if (protectflag & OB_LOCK_SCALEX)
470                 *drawflags &= ~MAN_SCALE_X;
471         if (protectflag & OB_LOCK_SCALEY)
472                 *drawflags &= ~MAN_SCALE_Y;
473         if (protectflag & OB_LOCK_SCALEZ)
474                 *drawflags &= ~MAN_SCALE_Z;
475 }
476
477 /* for pose mode */
478 static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
479 {
480         protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
481 }
482
483 /* for editmode*/
484 static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
485 {
486         if (ebo->flag & BONE_EDITMODE_LOCKED) {
487                 protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
488         }
489 }
490
491 /* could move into BLI_math however this is only useful for display/editing purposes */
492 static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
493 {
494         /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
495
496         float cross_vec[3];
497         float quat[4];
498
499         /* this is an un-scientific method to get a vector to cross with
500          * XYZ intentionally YZX */
501         cross_vec[0] = axis[1];
502         cross_vec[1] = axis[2];
503         cross_vec[2] = axis[0];
504
505         /* X-axis */
506         cross_v3_v3v3(gmat[0], cross_vec, axis);
507         normalize_v3(gmat[0]);
508         axis_angle_to_quat(quat, axis, angle);
509         mul_qt_v3(quat, gmat[0]);
510
511         /* Y-axis */
512         axis_angle_to_quat(quat, axis, M_PI_2);
513         copy_v3_v3(gmat[1], gmat[0]);
514         mul_qt_v3(quat, gmat[1]);
515
516         /* Z-axis */
517         copy_v3_v3(gmat[2], axis);
518
519         normalize_m3(gmat);
520 }
521
522
523 static bool test_rotmode_euler(short rotmode)
524 {
525         return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
526 }
527
528 bool gimbal_axis(Object *ob, float gmat[3][3])
529 {
530         if (ob->mode & OB_MODE_POSE) {
531                 bPoseChannel *pchan = BKE_pose_channel_active(ob);
532
533                 if (pchan) {
534                         float mat[3][3], tmat[3][3], obmat[3][3];
535                         if (test_rotmode_euler(pchan->rotmode)) {
536                                 eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
537                         }
538                         else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
539                                 axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
540                         }
541                         else { /* quat */
542                                 return 0;
543                         }
544
545
546                         /* apply bone transformation */
547                         mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
548
549                         if (pchan->parent) {
550                                 float parent_mat[3][3];
551
552                                 copy_m3_m4(parent_mat, pchan->parent->pose_mat);
553                                 mul_m3_m3m3(mat, parent_mat, tmat);
554
555                                 /* needed if object transformation isn't identity */
556                                 copy_m3_m4(obmat, ob->obmat);
557                                 mul_m3_m3m3(gmat, obmat, mat);
558                         }
559                         else {
560                                 /* needed if object transformation isn't identity */
561                                 copy_m3_m4(obmat, ob->obmat);
562                                 mul_m3_m3m3(gmat, obmat, tmat);
563                         }
564
565                         normalize_m3(gmat);
566                         return 1;
567                 }
568         }
569         else {
570                 if (test_rotmode_euler(ob->rotmode)) {
571                         eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
572                 }
573                 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
574                         axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
575                 }
576                 else { /* quat */
577                         return 0;
578                 }
579
580                 if (ob->parent) {
581                         float parent_mat[3][3];
582                         copy_m3_m4(parent_mat, ob->parent->obmat);
583                         normalize_m3(parent_mat);
584                         mul_m3_m3m3(gmat, parent_mat, gmat);
585                 }
586                 return 1;
587         }
588
589         return 0;
590 }
591
592
593 /* centroid, boundbox, of selection */
594 /* returns total items selected */
595 static int calc_manipulator_stats(const bContext *C)
596 {
597         ScrArea *sa = CTX_wm_area(C);
598         ARegion *ar = CTX_wm_region(C);
599         Scene *scene = CTX_data_scene(C);
600         SceneLayer *sl = CTX_data_scene_layer(C);
601         Object *obedit = CTX_data_edit_object(C);
602         View3D *v3d = sa->spacedata.first;
603         RegionView3D *rv3d = ar->regiondata;
604         Base *base;
605         Object *ob = OBACT_NEW;
606         bGPdata *gpd = CTX_data_gpencil_data(C);
607         const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
608         int a, totsel = 0;
609
610         /* transform widget matrix */
611         unit_m4(rv3d->twmat);
612
613         rv3d->twdrawflag = 0xFFFF;
614
615         /* transform widget centroid/center */
616         INIT_MINMAX(scene->twmin, scene->twmax);
617         zero_v3(scene->twcent);
618         
619         if (is_gp_edit) {
620                 float diff_mat[4][4];
621                 float fpt[3];
622
623                 for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
624                         /* only editable and visible layers are considered */
625                         if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
626
627                                 /* calculate difference matrix if parent object */
628                                 if (gpl->parent != NULL) {
629                                         ED_gpencil_parent_location(gpl, diff_mat);
630                                 }
631
632                                 for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
633                                         /* skip strokes that are invalid for current view */
634                                         if (ED_gpencil_stroke_can_use(C, gps) == false) {
635                                                 continue;
636                                         }
637
638                                         /* we're only interested in selected points here... */
639                                         if (gps->flag & GP_STROKE_SELECT) {
640                                                 bGPDspoint *pt;
641                                                 int i;
642
643                                                 /* Change selection status of all points, then make the stroke match */
644                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
645                                                         if (pt->flag & GP_SPOINT_SELECT) {
646                                                                 if (gpl->parent == NULL) {
647                                                                         calc_tw_center(scene, &pt->x);
648                                                                         totsel++;
649                                                                 }
650                                                                 else {
651                                                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
652                                                                         calc_tw_center(scene, fpt);
653                                                                         totsel++;
654                                                                 }
655                                                         }
656                                                 }
657                                         }
658                                 }
659                         }
660                 }
661
662
663                 /* selection center */
664                 if (totsel) {
665                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   /* centroid! */
666                 }
667         }
668         else if (obedit) {
669                 ob = obedit;
670                 if (obedit->type == OB_MESH) {
671                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
672                         BMEditSelection ese;
673                         float vec[3] = {0, 0, 0};
674
675                         /* USE LAST SELECTE WITH ACTIVE */
676                         if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
677                                 BM_editselection_center(&ese, vec);
678                                 calc_tw_center(scene, vec);
679                                 totsel = 1;
680                         }
681                         else {
682                                 BMesh *bm = em->bm;
683                                 BMVert *eve;
684
685                                 BMIter iter;
686
687                                 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
688                                         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
689                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
690                                                         totsel++;
691                                                         calc_tw_center(scene, eve->co);
692                                                 }
693                                         }
694                                 }
695                         }
696                 } /* end editmesh */
697                 else if (obedit->type == OB_ARMATURE) {
698                         bArmature *arm = obedit->data;
699                         EditBone *ebo;
700
701                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
702                                 /* doesn't check selection or visibility intentionally */
703                                 if (ebo->flag & BONE_TIPSEL) {
704                                         calc_tw_center(scene, ebo->tail);
705                                         totsel++;
706                                 }
707                                 if ((ebo->flag & BONE_ROOTSEL) ||
708                                     ((ebo->flag & BONE_TIPSEL) == false))  /* ensure we get at least one point */
709                                 {
710                                         calc_tw_center(scene, ebo->head);
711                                         totsel++;
712                                 }
713                                 protectflag_to_drawflags_ebone(rv3d, ebo);
714                         }
715                         else {
716                                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
717                                         if (EBONE_VISIBLE(arm, ebo)) {
718                                                 if (ebo->flag & BONE_TIPSEL) {
719                                                         calc_tw_center(scene, ebo->tail);
720                                                         totsel++;
721                                                 }
722                                                 if ((ebo->flag & BONE_ROOTSEL) &&
723                                                     /* don't include same point multiple times */
724                                                     ((ebo->flag & BONE_CONNECTED) &&
725                                                      (ebo->parent != NULL) &&
726                                                      (ebo->parent->flag & BONE_TIPSEL) &&
727                                                      EBONE_VISIBLE(arm, ebo->parent)) == 0)
728                                                 {
729                                                         calc_tw_center(scene, ebo->head);
730                                                         totsel++;
731                                                 }
732                                                 if (ebo->flag & BONE_SELECTED) {
733                                                         protectflag_to_drawflags_ebone(rv3d, ebo);
734                                                 }
735                                         }
736                                 }
737                         }
738                 }
739                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
740                         Curve *cu = obedit->data;
741                         float center[3];
742
743                         if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
744                                 calc_tw_center(scene, center);
745                                 totsel++;
746                         }
747                         else {
748                                 Nurb *nu;
749                                 BezTriple *bezt;
750                                 BPoint *bp;
751                                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
752
753                                 nu = nurbs->first;
754                                 while (nu) {
755                                         if (nu->type == CU_BEZIER) {
756                                                 bezt = nu->bezt;
757                                                 a = nu->pntsu;
758                                                 while (a--) {
759                                                         /* exceptions
760                                                          * if handles are hidden then only check the center points.
761                                                          * If the center knot is selected then only use this as the center point.
762                                                          */
763                                                         if (cu->drawflag & CU_HIDE_HANDLES) {
764                                                                 if (bezt->f2 & SELECT) {
765                                                                         calc_tw_center(scene, bezt->vec[1]);
766                                                                         totsel++;
767                                                                 }
768                                                         }
769                                                         else if (bezt->f2 & SELECT) {
770                                                                 calc_tw_center(scene, bezt->vec[1]);
771                                                                 totsel++;
772                                                         }
773                                                         else {
774                                                                 if (bezt->f1 & SELECT) {
775                                                                         calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
776                                                                         totsel++;
777                                                                 }
778                                                                 if (bezt->f3 & SELECT) {
779                                                                         calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
780                                                                         totsel++;
781                                                                 }
782                                                         }
783                                                         bezt++;
784                                                 }
785                                         }
786                                         else {
787                                                 bp = nu->bp;
788                                                 a = nu->pntsu * nu->pntsv;
789                                                 while (a--) {
790                                                         if (bp->f1 & SELECT) {
791                                                                 calc_tw_center(scene, bp->vec);
792                                                                 totsel++;
793                                                         }
794                                                         bp++;
795                                                 }
796                                         }
797                                         nu = nu->next;
798                                 }
799                         }
800                 }
801                 else if (obedit->type == OB_MBALL) {
802                         MetaBall *mb = (MetaBall *)obedit->data;
803                         MetaElem *ml;
804
805                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
806                                 calc_tw_center(scene, &ml->x);
807                                 totsel++;
808                         }
809                         else {
810                                 for (ml = mb->editelems->first; ml; ml = ml->next) {
811                                         if (ml->flag & SELECT) {
812                                                 calc_tw_center(scene, &ml->x);
813                                                 totsel++;
814                                         }
815                                 }
816                         }
817                 }
818                 else if (obedit->type == OB_LATTICE) {
819                         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
820                         BPoint *bp;
821
822                         if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
823                                 calc_tw_center(scene, bp->vec);
824                                 totsel++;
825                         }
826                         else {
827                                 bp = lt->def;
828                                 a = lt->pntsu * lt->pntsv * lt->pntsw;
829                                 while (a--) {
830                                         if (bp->f1 & SELECT) {
831                                                 calc_tw_center(scene, bp->vec);
832                                                 totsel++;
833                                         }
834                                         bp++;
835                                 }
836                         }
837                 }
838
839                 /* selection center */
840                 if (totsel) {
841                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
842                         mul_m4_v3(obedit->obmat, scene->twcent);
843                         mul_m4_v3(obedit->obmat, scene->twmin);
844                         mul_m4_v3(obedit->obmat, scene->twmax);
845                 }
846         }
847         else if (ob && (ob->mode & OB_MODE_POSE)) {
848                 bPoseChannel *pchan;
849                 int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
850                 bool ok = false;
851
852                 if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
853                         /* doesn't check selection or visibility intentionally */
854                         Bone *bone = pchan->bone;
855                         if (bone) {
856                                 calc_tw_center(scene, pchan->pose_head);
857                                 protectflag_to_drawflags_pchan(rv3d, pchan);
858                                 totsel = 1;
859                                 ok = true;
860                         }
861                 }
862                 else {
863                         totsel = count_set_pose_transflags(&mode, 0, ob);
864
865                         if (totsel) {
866                                 /* use channels to get stats */
867                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
868                                         Bone *bone = pchan->bone;
869                                         if (bone && (bone->flag & BONE_TRANSFORM)) {
870                                                 calc_tw_center(scene, pchan->pose_head);
871                                                 protectflag_to_drawflags_pchan(rv3d, pchan);
872                                         }
873                                 }
874                                 ok = true;
875                         }
876                 }
877
878                 if (ok) {
879                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
880                         mul_m4_v3(ob->obmat, scene->twcent);
881                         mul_m4_v3(ob->obmat, scene->twmin);
882                         mul_m4_v3(ob->obmat, scene->twmax);
883                 }
884         }
885         else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
886                 /* pass */
887         }
888         else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
889                 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
890                 PTCacheEditPoint *point;
891                 PTCacheEditKey *ek;
892                 int k;
893
894                 if (edit) {
895                         point = edit->points;
896                         for (a = 0; a < edit->totpoint; a++, point++) {
897                                 if (point->flag & PEP_HIDE) continue;
898
899                                 for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
900                                         if (ek->flag & PEK_SELECT) {
901                                                 calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
902                                                 totsel++;
903                                         }
904                                 }
905                         }
906
907                         /* selection center */
908                         if (totsel)
909                                 mul_v3_fl(scene->twcent, 1.0f / (float)totsel);  // centroid!
910                 }
911         }
912         else {
913
914                 /* we need the one selected object, if its not active */
915                 base = BASACT_NEW;
916                 ob = OBACT_NEW;
917                 if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
918
919                 for (base = sl->object_bases.first; base; base = base->next) {
920                         if (TESTBASELIB_NEW(base)) {
921                                 if (ob == NULL)
922                                         ob = base->object;
923                                 calc_tw_center(scene, base->object->obmat[3]);
924                                 protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
925                                 totsel++;
926                         }
927                 }
928
929                 /* selection center */
930                 if (totsel) {
931                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
932                 }
933         }
934
935         /* global, local or normal orientation? */
936         if (ob && totsel && !is_gp_edit) {
937
938                 switch (v3d->twmode) {
939                 
940                         case V3D_MANIP_GLOBAL:
941                         {
942                                 break; /* nothing to do */
943                         }
944                         case V3D_MANIP_GIMBAL:
945                         {
946                                 float mat[3][3];
947                                 if (gimbal_axis(ob, mat)) {
948                                         copy_m4_m3(rv3d->twmat, mat);
949                                         break;
950                                 }
951                                 /* if not gimbal, fall through to normal */
952                                 /* fall-through */
953                         }
954                         case V3D_MANIP_NORMAL:
955                         {
956                                 if (obedit || ob->mode & OB_MODE_POSE) {
957                                         float mat[3][3];
958                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
959                                         copy_m4_m3(rv3d->twmat, mat);
960                                         break;
961                                 }
962                                 /* no break we define 'normal' as 'local' in Object mode */
963                                 /* fall-through */
964                         }
965                         case V3D_MANIP_LOCAL:
966                         {
967                                 if (ob->mode & OB_MODE_POSE) {
968                                         /* each bone moves on its own local axis, but  to avoid confusion,
969                                          * use the active pones axis for display [#33575], this works as expected on a single bone
970                                          * and users who select many bones will understand whats going on and what local means
971                                          * when they start transforming */
972                                         float mat[3][3];
973                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
974                                         copy_m4_m3(rv3d->twmat, mat);
975                                         break;
976                                 }
977                                 copy_m4_m4(rv3d->twmat, ob->obmat);
978                                 normalize_m4(rv3d->twmat);
979                                 break;
980                         }
981                         case V3D_MANIP_VIEW:
982                         {
983                                 float mat[3][3];
984                                 copy_m3_m4(mat, rv3d->viewinv);
985                                 normalize_m3(mat);
986                                 copy_m4_m3(rv3d->twmat, mat);
987                                 break;
988                         }
989                         default: /* V3D_MANIP_CUSTOM */
990                         {
991                                 float mat[3][3];
992                                 if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) {
993                                         copy_m4_m3(rv3d->twmat, mat);
994                                 }
995                                 break;
996                         }
997                 }
998
999         }
1000
1001         return totsel;
1002 }
1003
1004 static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3])
1005 {
1006         float view_vec[3], axis_vec[3];
1007         ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
1008         for (int i = 0; i < 3; i++) {
1009                 normalize_v3_v3(axis_vec, rv3d->twmat[i]);
1010                 r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
1011         }
1012 }
1013
1014 static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D *rv3d)
1015 {
1016         Scene *scene = CTX_data_scene(C);
1017         SceneLayer *sl = CTX_data_scene_layer(C);
1018
1019         switch (v3d->around) {
1020                 case V3D_AROUND_CENTER_BOUNDS:
1021                 case V3D_AROUND_ACTIVE:
1022                 {
1023                                 bGPdata *gpd = CTX_data_gpencil_data(C);
1024                                 Object *ob = OBACT_NEW;
1025
1026                                 if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
1027                                     ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
1028                                     (!(ob->mode & OB_MODE_POSE)))
1029                                 {
1030                                         copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
1031                                 }
1032                                 else {
1033                                         mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
1034                                 }
1035                                 break;
1036                 }
1037                 case V3D_AROUND_LOCAL_ORIGINS:
1038                 case V3D_AROUND_CENTER_MEAN:
1039                         copy_v3_v3(rv3d->twmat[3], scene->twcent);
1040                         break;
1041                 case V3D_AROUND_CURSOR:
1042                         copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
1043                         break;
1044         }
1045 }
1046
1047 /**
1048  * Sets up \a r_start and \a r_len to define arrow line range.
1049  * Needed to adjust line drawing for combined manipulator axis types.
1050  */
1051 static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len)
1052 {
1053         const float ofs = 0.2f;
1054
1055         *r_start = 0.2f;
1056         *r_len = 1.0f;
1057
1058         switch (axis_type) {
1059                 case MAN_AXES_TRANSLATE:
1060                         if (v3d->twtype & V3D_MANIP_SCALE) {
1061                                 *r_start = *r_len - ofs + 0.075f;
1062                         }
1063                         if (v3d->twtype & V3D_MANIP_ROTATE) {
1064                                 *r_len += ofs;
1065                         }
1066                         break;
1067                 case MAN_AXES_SCALE:
1068                         if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) {
1069                                 *r_len -= ofs + 0.025f;
1070                         }
1071                         break;
1072         }
1073
1074         *r_len -= *r_start;
1075 }
1076
1077 /* **************** Actual Widget Stuff **************** */
1078
1079 static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *wgroup)
1080 {
1081         ManipulatorGroup *man;
1082
1083         man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data");
1084
1085         /* add/init widgets - order matters! */
1086         man->rotate_t = MANIPULATOR_dial_new(wgroup, "rotate_t", MANIPULATOR_DIAL_STYLE_RING_FILLED);
1087
1088         man->scale_c = MANIPULATOR_dial_new(wgroup, "scale_c", MANIPULATOR_DIAL_STYLE_RING);
1089         man->scale_x = MANIPULATOR_arrow_new(wgroup, "scale_x", MANIPULATOR_ARROW_STYLE_BOX);
1090         man->scale_y = MANIPULATOR_arrow_new(wgroup, "scale_y", MANIPULATOR_ARROW_STYLE_BOX);
1091         man->scale_z = MANIPULATOR_arrow_new(wgroup, "scale_z", MANIPULATOR_ARROW_STYLE_BOX);
1092         man->scale_xy = MANIPULATOR_primitive_new(wgroup, "scale_xy", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1093         man->scale_yz = MANIPULATOR_primitive_new(wgroup, "scale_yz", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1094         man->scale_zx = MANIPULATOR_primitive_new(wgroup, "scale_zx", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1095
1096         man->rotate_x = MANIPULATOR_dial_new(wgroup, "rotate_x", MANIPULATOR_DIAL_STYLE_RING_CLIPPED);
1097         man->rotate_y = MANIPULATOR_dial_new(wgroup, "rotate_y", MANIPULATOR_DIAL_STYLE_RING_CLIPPED);
1098         man->rotate_z = MANIPULATOR_dial_new(wgroup, "rotate_z", MANIPULATOR_DIAL_STYLE_RING_CLIPPED);
1099         /* init screen aligned widget last here, looks better, behaves better */
1100         man->rotate_c = MANIPULATOR_dial_new(wgroup, "rotate_c", MANIPULATOR_DIAL_STYLE_RING);
1101
1102         man->translate_c = MANIPULATOR_dial_new(wgroup, "translate_c", MANIPULATOR_DIAL_STYLE_RING);
1103         man->translate_x = MANIPULATOR_arrow_new(wgroup, "translate_x", MANIPULATOR_ARROW_STYLE_NORMAL);
1104         man->translate_y = MANIPULATOR_arrow_new(wgroup, "translate_y", MANIPULATOR_ARROW_STYLE_NORMAL);
1105         man->translate_z = MANIPULATOR_arrow_new(wgroup, "translate_z", MANIPULATOR_ARROW_STYLE_NORMAL);
1106         man->translate_xy = MANIPULATOR_primitive_new(wgroup, "translate_xy", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1107         man->translate_yz = MANIPULATOR_primitive_new(wgroup, "translate_yz", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1108         man->translate_zx = MANIPULATOR_primitive_new(wgroup, "translate_zx", MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1109
1110         return man;
1111 }
1112
1113 /**
1114  * Custom handler for manipulator widgets
1115  */
1116 static int manipulator_handler(bContext *C, const wmEvent *UNUSED(event), wmManipulator *widget, const int UNUSED(flag))
1117 {
1118         const ScrArea *sa = CTX_wm_area(C);
1119         ARegion *ar = CTX_wm_region(C);
1120         View3D *v3d = sa->spacedata.first;
1121         RegionView3D *rv3d = ar->regiondata;
1122
1123         if (calc_manipulator_stats(C)) {
1124                 manipulator_prepare_mat(C, v3d, rv3d);
1125                 WM_manipulator_set_origin(widget, rv3d->twmat[3]);
1126         }
1127
1128         ED_region_tag_redraw(ar);
1129
1130         return OPERATOR_PASS_THROUGH;
1131 }
1132
1133 static void WIDGETGROUP_manipulator_init(const bContext *UNUSED(C), wmManipulatorGroup *wgroup)
1134 {
1135         ManipulatorGroup *man = manipulatorgroup_init(wgroup);
1136         wgroup->customdata = man;
1137
1138         /* *** set properties for axes *** */
1139
1140         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1141         {
1142                 const short axis_type = manipulator_get_axis_type(man, axis);
1143                 int constraint_axis[3] = {1, 0, 0};
1144                 PointerRNA *ptr;
1145
1146                 manipulator_get_axis_constraint(axis_idx, constraint_axis);
1147
1148                 /* custom handler! */
1149                 WM_manipulator_set_custom_handler(axis, manipulator_handler);
1150
1151                 switch(axis_idx) {
1152                         case MAN_AXIS_TRANS_X:
1153                         case MAN_AXIS_TRANS_Y:
1154                         case MAN_AXIS_TRANS_Z:
1155                         case MAN_AXIS_SCALE_X:
1156                         case MAN_AXIS_SCALE_Y:
1157                         case MAN_AXIS_SCALE_Z:
1158                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
1159                                 break;
1160                         case MAN_AXIS_ROT_X:
1161                         case MAN_AXIS_ROT_Y:
1162                         case MAN_AXIS_ROT_Z:
1163                                 /* increased line width for better display */
1164                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f);
1165                                 WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
1166                                 break;
1167                         case MAN_AXIS_TRANS_XY:
1168                         case MAN_AXIS_TRANS_YZ:
1169                         case MAN_AXIS_TRANS_ZX:
1170                         case MAN_AXIS_SCALE_XY:
1171                         case MAN_AXIS_SCALE_YZ:
1172                         case MAN_AXIS_SCALE_ZX:
1173                         {
1174                                 const float ofs_ax = 11.0f;
1175                                 const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
1176                                 WM_manipulator_set_scale(axis, 0.07f);
1177                                 WM_manipulator_set_offset(axis, ofs);
1178                                 break;
1179                         }
1180                         case MAN_AXIS_TRANS_C:
1181                         case MAN_AXIS_ROT_C:
1182                         case MAN_AXIS_SCALE_C:
1183                         case MAN_AXIS_ROT_T:
1184                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
1185                                 if (axis_idx == MAN_AXIS_ROT_T) {
1186                                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true);
1187                                 }
1188                                 else if (axis_idx == MAN_AXIS_ROT_C) {
1189                                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
1190                                 }
1191                                 else {
1192                                         WM_manipulator_set_scale(axis, 0.2f);
1193                                 }
1194                                 break;
1195                 }
1196
1197                 switch (axis_type) {
1198                         case MAN_AXES_TRANSLATE:
1199                                 ptr = WM_manipulator_set_operator(axis, "TRANSFORM_OT_translate");
1200                                 break;
1201                         case MAN_AXES_ROTATE:
1202                                 ptr = WM_manipulator_set_operator(
1203                                           axis, (axis_idx == MAN_AXIS_ROT_T) ?
1204                                           "TRANSFORM_OT_trackball" : "TRANSFORM_OT_rotate");
1205                                 break;
1206                         case MAN_AXES_SCALE:
1207                                 ptr = WM_manipulator_set_operator(axis, "TRANSFORM_OT_resize");
1208                                 break;
1209                 }
1210                 if (RNA_struct_find_property(ptr, "constraint_axis"))
1211                         RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
1212                 RNA_boolean_set(ptr, "release_confirm", 1);
1213         }
1214         MAN_ITER_AXES_END;
1215 }
1216
1217 static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *wgroup)
1218 {
1219         ManipulatorGroup *man = wgroup->customdata;
1220         ScrArea *sa = CTX_wm_area(C);
1221         ARegion *ar = CTX_wm_region(C);
1222         View3D *v3d = sa->spacedata.first;
1223         RegionView3D *rv3d = ar->regiondata;
1224
1225         /* skip, we don't draw anything anyway */
1226         if ((man->all_hidden = (calc_manipulator_stats(C) == 0)))
1227                 return;
1228
1229         manipulator_prepare_mat(C, v3d, rv3d);
1230
1231         /* *** set properties for axes *** */
1232
1233         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1234         {
1235                 const short axis_type = manipulator_get_axis_type(man, axis);
1236                 const int aidx_norm = manipulator_index_normalize(axis_idx);
1237
1238                 WM_manipulator_set_origin(axis, rv3d->twmat[3]);
1239
1240                 switch (axis_idx) {
1241                         case MAN_AXIS_TRANS_X:
1242                         case MAN_AXIS_TRANS_Y:
1243                         case MAN_AXIS_TRANS_Z:
1244                         case MAN_AXIS_SCALE_X:
1245                         case MAN_AXIS_SCALE_Y:
1246                         case MAN_AXIS_SCALE_Z:
1247                         {
1248                                 float start_co[3] = {0.0f, 0.0f, 0.0f};
1249                                 float len;
1250
1251                                 manipulator_line_range(v3d, axis_type, &start_co[2], &len);
1252
1253                                 MANIPULATOR_arrow_set_direction(axis, rv3d->twmat[aidx_norm]);
1254                                 MANIPULATOR_arrow_set_line_len(axis, len);
1255                                 WM_manipulator_set_offset(axis, start_co);
1256                                 break;
1257                         }
1258                         case MAN_AXIS_ROT_X:
1259                         case MAN_AXIS_ROT_Y:
1260                         case MAN_AXIS_ROT_Z:
1261                                 MANIPULATOR_dial_set_up_vector(axis, rv3d->twmat[aidx_norm]);
1262                                 break;
1263                         case MAN_AXIS_TRANS_XY:
1264                         case MAN_AXIS_TRANS_YZ:
1265                         case MAN_AXIS_TRANS_ZX:
1266                         case MAN_AXIS_SCALE_XY:
1267                         case MAN_AXIS_SCALE_YZ:
1268                         case MAN_AXIS_SCALE_ZX:
1269                                 MANIPULATOR_primitive_set_direction(axis, rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]);
1270                                 MANIPULATOR_primitive_set_up_vector(axis, rv3d->twmat[aidx_norm + 1 > 2 ? 0 : aidx_norm + 1]);
1271                                 break;
1272                 }
1273         }
1274         MAN_ITER_AXES_END;
1275 }
1276
1277 static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *wgroup)
1278 {
1279         ManipulatorGroup *man = wgroup->customdata;
1280         ScrArea *sa = CTX_wm_area(C);
1281         ARegion *ar = CTX_wm_region(C);
1282         View3D *v3d = sa->spacedata.first;
1283         RegionView3D *rv3d = ar->regiondata;
1284         float idot[3];
1285
1286         /* when looking through a selected camera, the manipulator can be at the
1287          * exact same position as the view, skip so we don't break selection */
1288         if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
1289                 MAN_ITER_AXES_BEGIN(axis, axis_idx)
1290                 {
1291                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
1292                 }
1293                 MAN_ITER_AXES_END;
1294                 return;
1295         }
1296         manipulator_get_idot(rv3d, idot);
1297
1298         /* *** set properties for axes *** */
1299
1300         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1301         {
1302                 const short axis_type = manipulator_get_axis_type(man, axis);
1303                 /* XXX maybe unset _HIDDEN flag on redraw? */
1304                 if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) {
1305                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false);
1306                 }
1307                 else {
1308                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
1309                         continue;
1310                 }
1311
1312                 float col[4], col_hi[4];
1313                 manipulator_get_axis_color(axis_idx, idot, col, col_hi);
1314                 WM_manipulator_set_colors(axis, col, col_hi);
1315
1316                 switch (axis_idx) {
1317                         case MAN_AXIS_TRANS_C:
1318                         case MAN_AXIS_ROT_C:
1319                         case MAN_AXIS_SCALE_C:
1320                         case MAN_AXIS_ROT_T:
1321                                 MANIPULATOR_dial_set_up_vector(axis, rv3d->viewinv[2]);
1322                                 break;
1323                 }
1324         }
1325         MAN_ITER_AXES_END;
1326 }
1327
1328 static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *UNUSED(wgrouptype))
1329 {
1330         /* it's a given we only use this in 3D view */
1331         const ScrArea *sa = CTX_wm_area(C);
1332         const View3D *v3d = sa->spacedata.first;
1333
1334         return (((v3d->twflag & V3D_USE_MANIPULATOR) != 0) &&
1335                 ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) != 0));
1336 }
1337
1338 void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt)
1339 {
1340         wgt->name = "Transform Manipulator";
1341
1342         wgt->poll = WIDGETGROUP_manipulator_poll;
1343         wgt->init = WIDGETGROUP_manipulator_init;
1344         wgt->refresh = WIDGETGROUP_manipulator_refresh;
1345         wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
1346
1347         wgt->flag |= (WM_MANIPULATORGROUPTYPE_IS_3D | WM_MANIPULATORGROUPTYPE_SCALE_3D);
1348 }
1349
1350
1351 /* -------------------------------------------------------------------- */
1352 /* Custom Object Manipulator (unfinished - unsure if this will stay) */
1353 #if 0
1354 static void WIDGETGROUP_object_manipulator_init(const bContext *C, wmManipulatorGroup *wgroup)
1355 {
1356         Object *ob = ED_object_active_context((bContext *)C);
1357
1358         if (ob->wgroup == NULL) {
1359                 ob->wgroup = wgroup;
1360         }
1361
1362         WIDGETGROUP_manipulator_init(C, wgroup);
1363 }
1364
1365 static bool WIDGETGROUP_object_manipulator_poll(const bContext *C, wmManipulatorGroupType *wgrouptype)
1366 {
1367         Object *ob = ED_object_active_context((bContext *)C);
1368
1369         if (ED_operator_object_active((bContext *)C)) {
1370                 if (STREQ(wgrouptype->idname, ob->id.name)) {
1371                         return true;
1372                 }
1373         }
1374         return false;
1375 }
1376
1377 /* XXX should this really be in transform_manipulator.c? */
1378 void TRANSFORM_WGT_object(wmManipulatorGroupType *wgt)
1379 {
1380         wgt->name = "Object Widgets";
1381
1382         wgt->poll = WIDGETGROUP_object_manipulator_poll;
1383         wgt->init = WIDGETGROUP_object_manipulator_init;
1384         wgt->refresh = WIDGETGROUP_manipulator_refresh;
1385         wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
1386
1387         wgt->flag |= (WM_MANIPULATORGROUPTYPE_IS_3D | WM_MANIPULATORGROUPTYPE_SCALE_3D);
1388 }
1389 #endif