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