277d0f6a2a082b141b9071e34158b66257b14faa
[blender.git] / source / blender / editors / space_view3d / view3d_buttons.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) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_buttons.c
28  *  \ingroup spview3d
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <math.h>
35 #include <float.h>
36
37 #include "DNA_armature_types.h"
38 #include "DNA_curve_types.h"
39 #include "DNA_lattice_types.h"
40 #include "DNA_meta_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLT_translation.h"
49
50 #include "BLI_math.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_curve.h"
57 #include "BKE_customdata.h"
58 #include "BKE_screen.h"
59 #include "BKE_editmesh.h"
60 #include "BKE_deform.h"
61 #include "BKE_object.h"
62 #include "BKE_object_deform.h"
63 #include "BKE_report.h"
64
65 #include "DEG_depsgraph.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "RNA_access.h"
71
72 #include "ED_armature.h"
73 #include "ED_object.h"
74 #include "ED_mesh.h"
75 #include "ED_screen.h"
76
77 #include "UI_interface.h"
78 #include "UI_resources.h"
79
80 #include "view3d_intern.h"  /* own include */
81
82
83 /* ******************* view3d space & buttons ************** */
84 #define B_REDR              2
85 #define B_OBJECTPANELMEDIAN 1008
86
87 #define NBR_TRANSFORM_PROPERTIES 8
88
89 /* temporary struct for storing transform properties */
90 typedef struct {
91         float ob_eul[4];   /* used for quat too... */
92         float ob_scale[3]; /* need temp space due to linked values */
93         float ob_dims[3];
94         short link_scale;
95         float ve_median[NBR_TRANSFORM_PROPERTIES];
96 } TransformProperties;
97
98 /* Helper function to compute a median changed value,
99  * when the value should be clamped in [0.0, 1.0].
100  * Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor
101  * for scale down, or a negative one for scale up.
102  */
103 static float compute_scale_factor(const float ve_median, const float median)
104 {
105         if (ve_median <= 0.0f)
106                 return 0.0f;
107         else if (ve_median >= 1.0f)
108                 return 1.0f;
109         else {
110                 /* Scale value to target median. */
111                 float median_new = ve_median;
112                 float median_orig = ve_median - median; /* Previous median value. */
113
114                 /* In case of floating point error. */
115                 CLAMP(median_orig, 0.0f, 1.0f);
116                 CLAMP(median_new, 0.0f, 1.0f);
117
118                 if (median_new <= median_orig) {
119                         /* Scale down. */
120                         return median_new / median_orig;
121                 }
122                 else {
123                         /* Scale up, negative to indicate it... */
124                         return -(1.0f - median_new) / (1.0f - median_orig);
125                 }
126         }
127 }
128
129 /* Apply helpers.
130  * Note: In case we only have one element, copy directly the value instead of applying the diff or scale factor.
131  *       Avoids some glitches when going e.g. from 3 to 0.0001 (see T37327).
132  */
133 static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
134 {
135         *val = (tot == 1) ? ve_median : (*val + median);
136 }
137
138 static void apply_raw_diff_v3(float val[3], const int tot, const float ve_median[3], const float median[3])
139 {
140         if (tot == 1) {
141                 copy_v3_v3(val, ve_median);
142         }
143         else {
144                 add_v3_v3(val, median);
145         }
146 }
147
148 static void apply_scale_factor(float *val, const int tot, const float ve_median, const float median, const float sca)
149 {
150         if (tot == 1 || ve_median == median) {
151                 *val = ve_median;
152         }
153         else {
154                 *val *= sca;
155         }
156 }
157
158 static void apply_scale_factor_clamp(float *val, const int tot, const float ve_median, const float sca)
159 {
160         if (tot == 1) {
161                 *val = ve_median;
162                 CLAMP(*val, 0.0f, 1.0f);
163         }
164         else if (ELEM(sca, 0.0f, 1.0f)) {
165                 *val = sca;
166         }
167         else {
168                 *val = (sca > 0.0f) ? (*val * sca) : (1.0f + ((1.0f - *val) * sca));
169                 CLAMP(*val, 0.0f, 1.0f);
170         }
171 }
172
173 /* is used for both read and write... */
174 static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim)
175 {
176 /* Get rid of those ugly magic numbers, even in a single func they become confusing! */
177 /* Location, common to all. */
178 /* Next three *must* remain contiguous (used as array)! */
179 #define LOC_X        0
180 #define LOC_Y        1
181 #define LOC_Z        2
182 /* Meshes... */
183 #define M_BV_WEIGHT  3
184 /* Next two *must* remain contiguous (used as array)! */
185 #define M_SKIN_X     4
186 #define M_SKIN_Y     5
187 #define M_BE_WEIGHT  6
188 #define M_CREASE     7
189 /* Curves... */
190 #define C_BWEIGHT    3
191 #define C_WEIGHT     4
192 #define C_RADIUS     5
193 #define C_TILT       6
194 /*Lattice... */
195 #define L_WEIGHT     4
196
197         uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : NULL;
198         TransformProperties *tfp;
199         float median[NBR_TRANSFORM_PROPERTIES], ve_median[NBR_TRANSFORM_PROPERTIES];
200         int tot, totedgedata, totcurvedata, totlattdata, totcurvebweight;
201         bool has_meshdata = false;
202         bool has_skinradius = false;
203         PointerRNA data_ptr;
204
205         copy_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
206         tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
207
208         /* make sure we got storage */
209         if (v3d->properties_storage == NULL)
210                 v3d->properties_storage = MEM_callocN(sizeof(TransformProperties), "TransformProperties");
211         tfp = v3d->properties_storage;
212
213         if (ob->type == OB_MESH) {
214                 Mesh *me = ob->data;
215                 BMEditMesh *em = me->edit_btmesh;
216                 BMesh *bm = em->bm;
217                 BMVert *eve;
218                 BMEdge *eed;
219                 BMIter iter;
220
221                 const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
222                 const int cd_vert_skin_offset    = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
223                 const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
224                 const int cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);
225
226                 has_skinradius = (cd_vert_skin_offset != -1);
227
228                 if (bm->totvertsel) {
229                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
230                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
231                                         tot++;
232                                         add_v3_v3(&median[LOC_X], eve->co);
233
234                                         if (cd_vert_bweight_offset != -1) {
235                                                 median[M_BV_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
236                                         }
237
238                                         if (has_skinradius) {
239                                                 MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
240                                                 add_v2_v2(&median[M_SKIN_X], vs->radius); /* Third val not used currently. */
241                                         }
242                                 }
243                         }
244                 }
245
246                 if ((cd_edge_bweight_offset != -1) || (cd_edge_crease_offset  != -1)) {
247                         if (bm->totedgesel) {
248                                 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
249                                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
250                                                 if (cd_edge_bweight_offset != -1) {
251                                                         median[M_BE_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
252                                                 }
253
254                                                 if (cd_edge_crease_offset != -1) {
255                                                         median[M_CREASE] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
256                                                 }
257
258                                                 totedgedata++;
259                                         }
260                                 }
261                         }
262                 }
263                 else {
264                         totedgedata = bm->totedgesel;
265                 }
266
267                 has_meshdata = (tot || totedgedata);
268         }
269         else if (ob->type == OB_CURVE || ob->type == OB_SURF) {
270                 Curve *cu = ob->data;
271                 Nurb *nu;
272                 BPoint *bp;
273                 BezTriple *bezt;
274                 int a;
275                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
276                 StructRNA *seltype = NULL;
277                 void *selp = NULL;
278
279                 nu = nurbs->first;
280                 while (nu) {
281                         if (nu->type == CU_BEZIER) {
282                                 bezt = nu->bezt;
283                                 a = nu->pntsu;
284                                 while (a--) {
285                                         if (bezt->f2 & SELECT) {
286                                                 add_v3_v3(&median[LOC_X], bezt->vec[1]);
287                                                 tot++;
288                                                 median[C_WEIGHT] += bezt->weight;
289                                                 median[C_RADIUS] += bezt->radius;
290                                                 median[C_TILT] += bezt->alfa;
291                                                 if (!totcurvedata) { /* I.e. first time... */
292                                                         selp = bezt;
293                                                         seltype = &RNA_BezierSplinePoint;
294                                                 }
295                                                 totcurvedata++;
296                                         }
297                                         else {
298                                                 if (bezt->f1 & SELECT) {
299                                                         add_v3_v3(&median[LOC_X], bezt->vec[0]);
300                                                         tot++;
301                                                 }
302                                                 if (bezt->f3 & SELECT) {
303                                                         add_v3_v3(&median[LOC_X], bezt->vec[2]);
304                                                         tot++;
305                                                 }
306                                         }
307                                         bezt++;
308                                 }
309                         }
310                         else {
311                                 bp = nu->bp;
312                                 a = nu->pntsu * nu->pntsv;
313                                 while (a--) {
314                                         if (bp->f1 & SELECT) {
315                                                 add_v3_v3(&median[LOC_X], bp->vec);
316                                                 median[C_BWEIGHT] += bp->vec[3];
317                                                 totcurvebweight++;
318                                                 tot++;
319                                                 median[C_WEIGHT] += bp->weight;
320                                                 median[C_RADIUS] += bp->radius;
321                                                 median[C_TILT] += bp->alfa;
322                                                 if (!totcurvedata) { /* I.e. first time... */
323                                                         selp = bp;
324                                                         seltype = &RNA_SplinePoint;
325                                                 }
326                                                 totcurvedata++;
327                                         }
328                                         bp++;
329                                 }
330                         }
331                         nu = nu->next;
332                 }
333
334                 if (totcurvedata == 1)
335                         RNA_pointer_create(&cu->id, seltype, selp, &data_ptr);
336         }
337         else if (ob->type == OB_LATTICE) {
338                 Lattice *lt = ob->data;
339                 BPoint *bp;
340                 int a;
341                 StructRNA *seltype = NULL;
342                 void *selp = NULL;
343
344                 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
345                 bp = lt->editlatt->latt->def;
346                 while (a--) {
347                         if (bp->f1 & SELECT) {
348                                 add_v3_v3(&median[LOC_X], bp->vec);
349                                 tot++;
350                                 median[L_WEIGHT] += bp->weight;
351                                 if (!totlattdata) { /* I.e. first time... */
352                                         selp = bp;
353                                         seltype = &RNA_LatticePoint;
354                                 }
355                                 totlattdata++;
356                         }
357                         bp++;
358                 }
359
360                 if (totlattdata == 1)
361                         RNA_pointer_create(&lt->id, seltype, selp, &data_ptr);
362         }
363
364         if (tot == 0) {
365                 uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, NULL, 0, 0, 0, 0, "");
366                 return;
367         }
368
369         /* Location, X/Y/Z */
370         mul_v3_fl(&median[LOC_X], 1.0f / (float)tot);
371         if (v3d->flag & V3D_GLOBAL_STATS)
372                 mul_m4_v3(ob->obmat, &median[LOC_X]);
373
374         if (has_meshdata) {
375                 if (totedgedata) {
376                         median[M_CREASE] /= (float)totedgedata;
377                         median[M_BE_WEIGHT] /= (float)totedgedata;
378                 }
379                 if (tot) {
380                         median[M_BV_WEIGHT] /= (float)tot;
381                         if (has_skinradius) {
382                                 median[M_SKIN_X] /= (float)tot;
383                                 median[M_SKIN_Y] /= (float)tot;
384                         }
385                 }
386         }
387         else if (totcurvedata) {
388                 if (totcurvebweight) {
389                         median[C_BWEIGHT] /= (float)totcurvebweight;
390                 }
391                 median[C_WEIGHT] /= (float)totcurvedata;
392                 median[C_RADIUS] /= (float)totcurvedata;
393                 median[C_TILT] /= (float)totcurvedata;
394         }
395         else if (totlattdata) {
396                 median[L_WEIGHT] /= (float)totlattdata;
397         }
398
399         if (block) { /* buttons */
400                 uiBut *but;
401                 int yi = 200;
402                 const float tilt_limit = DEG2RADF(21600.0f);
403                 const int buth = 20 * UI_DPI_FAC;
404                 const int but_margin = 2;
405                 const char *c;
406
407                 memcpy(tfp->ve_median, median, sizeof(tfp->ve_median));
408
409                 UI_block_align_begin(block);
410                 if (tot == 1) {
411                         if (totcurvedata) /* Curve */
412                                 c = IFACE_("Control Point:");
413                         else /* Mesh or lattice */
414                                 c = IFACE_("Vertex:");
415                 }
416                 else
417                         c = IFACE_("Median:");
418                 uiDefBut(block, UI_BTYPE_LABEL, 0, c, 0, yi -= buth, 200, buth, NULL, 0, 0, 0, 0, "");
419
420                 UI_block_align_begin(block);
421
422                 /* Should be no need to translate these. */
423                 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("X:"), 0, yi -= buth, 200, buth,
424                                 &(tfp->ve_median[LOC_X]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
425                 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
426                 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Y:"), 0, yi -= buth, 200, buth,
427                                 &(tfp->ve_median[LOC_Y]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
428                 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
429                 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Z:"), 0, yi -= buth, 200, buth,
430                                 &(tfp->ve_median[LOC_Z]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
431                 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
432
433                 if (totcurvebweight == tot) {
434                         uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("W:"), 0, yi -= buth, 200, buth,
435                                   &(tfp->ve_median[C_BWEIGHT]), 0.01, 100.0, 1, 3, "");
436                 }
437
438                 UI_block_align_begin(block);
439                 uiDefButBitS(block, UI_BTYPE_TOGGLE, V3D_GLOBAL_STATS, B_REDR, IFACE_("Global"),
440                              0, yi -= buth + but_margin, 100, buth,
441                              &v3d->flag, 0, 0, 0, 0, TIP_("Displays global values"));
442                 uiDefButBitS(block, UI_BTYPE_TOGGLE_N, V3D_GLOBAL_STATS, B_REDR, IFACE_("Local"),
443                              100, yi, 100, buth,
444                              &v3d->flag, 0, 0, 0, 0, TIP_("Displays local values"));
445                 UI_block_align_end(block);
446
447                 /* Meshes... */
448                 if (has_meshdata) {
449                         if (tot) {
450                                 uiDefBut(block, UI_BTYPE_LABEL, 0, tot == 1 ? IFACE_("Vertex Data:") : IFACE_("Vertices Data:"),
451                                          0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
452                                 /* customdata layer added on demand */
453                                 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
454                                           tot == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
455                                           0, yi -= buth + but_margin, 200, buth,
456                                           &(tfp->ve_median[M_BV_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Vertex weight used by Bevel modifier"));
457                         }
458                         if (has_skinradius) {
459                                 UI_block_align_begin(block);
460                                 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
461                                           tot == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
462                                           0, yi -= buth + but_margin, 200, buth,
463                                           &(tfp->ve_median[M_SKIN_X]), 0.0, 100.0, 1, 3, TIP_("X radius used by Skin modifier"));
464                                 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
465                                           tot == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
466                                           0, yi -= buth + but_margin, 200, buth,
467                                           &(tfp->ve_median[M_SKIN_Y]), 0.0, 100.0, 1, 3, TIP_("Y radius used by Skin modifier"));
468                                 UI_block_align_end(block);
469                         }
470                         if (totedgedata) {
471                                 uiDefBut(block, UI_BTYPE_LABEL, 0, totedgedata == 1 ? IFACE_("Edge Data:") : IFACE_("Edges Data:"),
472                                          0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
473                                 /* customdata layer added on demand */
474                                 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
475                                           totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
476                                           0, yi -= buth + but_margin, 200, buth,
477                                           &(tfp->ve_median[M_BE_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Edge weight used by Bevel modifier"));
478                                 /* customdata layer added on demand */
479                                 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
480                                           totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
481                                           0, yi -= buth + but_margin, 200, buth,
482                                           &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier"));
483                         }
484                 }
485                 /* Curve... */
486                 else if (totcurvedata == 1) {
487                         uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
488                                   &data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
489                         uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Radius:"), 0, yi -= buth + but_margin, 200, buth,
490                                   &data_ptr, "radius", 0, 0.0, 100.0, 1, 3, NULL);
491                         uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Tilt:"), 0, yi -= buth + but_margin, 200, buth,
492                                   &data_ptr, "tilt", 0, -tilt_limit, tilt_limit, 1, 3, NULL);
493                 }
494                 else if (totcurvedata > 1) {
495                         uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
496                                   0, yi -= buth + but_margin, 200, buth,
497                                   &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
498                         uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
499                                   0, yi -= buth + but_margin, 200, buth,
500                                   &(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points"));
501                         but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Tilt:"),
502                                         0, yi -= buth + but_margin, 200, buth,
503                                         &(tfp->ve_median[C_TILT]), -tilt_limit, tilt_limit, 1, 3,
504                                         TIP_("Tilt of curve control points"));
505                         UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
506                 }
507                 /* Lattice... */
508                 else if (totlattdata == 1) {
509                         uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
510                                   &data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
511                 }
512                 else if (totlattdata > 1) {
513                         uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
514                                   0, yi -= buth + but_margin, 200, buth,
515                                   &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
516                 }
517
518                 UI_block_align_end(block);
519         }
520         else { /* apply */
521                 int i;
522                 bool apply_vcos;
523
524                 memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median));
525
526                 if (v3d->flag & V3D_GLOBAL_STATS) {
527                         invert_m4_m4(ob->imat, ob->obmat);
528                         mul_m4_v3(ob->imat, &median[LOC_X]);
529                         mul_m4_v3(ob->imat, &ve_median[LOC_X]);
530                 }
531                 i = NBR_TRANSFORM_PROPERTIES;
532                 while (i--)
533                         median[i] = ve_median[i] - median[i];
534
535                 /* Note with a single element selected, we always do. */
536                 apply_vcos = (tot == 1) || (len_squared_v3(&median[LOC_X]) != 0.0f);
537
538                 if ((ob->type == OB_MESH) &&
539                     (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y] ||
540                      median[M_BE_WEIGHT] || median[M_CREASE]))
541                 {
542                         Mesh *me = ob->data;
543                         BMEditMesh *em = me->edit_btmesh;
544                         BMesh *bm = em->bm;
545                         BMIter iter;
546                         BMVert *eve;
547                         BMEdge *eed;
548
549                         int cd_vert_bweight_offset = -1;
550                         int cd_vert_skin_offset = -1;
551                         int cd_edge_bweight_offset = -1;
552                         int cd_edge_crease_offset = -1;
553
554                         float scale_bv_weight = 1.0f;
555                         float scale_skin_x = 1.0f;
556                         float scale_skin_y = 1.0f;
557                         float scale_be_weight = 1.0f;
558                         float scale_crease = 1.0f;
559
560                         /* Vertices */
561
562                         if (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y]) {
563                                 if (median[M_BV_WEIGHT]) {
564                                         BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
565                                         cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
566                                         BLI_assert(cd_vert_bweight_offset != -1);
567
568                                         scale_bv_weight = compute_scale_factor(ve_median[M_BV_WEIGHT], median[M_BV_WEIGHT]);
569                                 }
570
571                                 if (median[M_SKIN_X]) {
572                                         cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
573                                         BLI_assert(cd_vert_skin_offset != -1);
574
575                                         if (ve_median[M_SKIN_X] != median[M_SKIN_X]) {
576                                                 scale_skin_x = ve_median[M_SKIN_X] / (ve_median[M_SKIN_X] - median[M_SKIN_X]);
577                                         }
578                                 }
579                                 if (median[M_SKIN_Y]) {
580                                         if (cd_vert_skin_offset == -1) {
581                                                 cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
582                                                 BLI_assert(cd_vert_skin_offset != -1);
583                                         }
584
585                                         if (ve_median[M_SKIN_Y] != median[M_SKIN_Y]) {
586                                                 scale_skin_y = ve_median[M_SKIN_Y] / (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
587                                         }
588                                 }
589
590                                 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
591                                         if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
592                                                 if (apply_vcos) {
593                                                         apply_raw_diff_v3(eve->co, tot, &ve_median[LOC_X], &median[LOC_X]);
594                                                 }
595
596                                                 if (cd_vert_bweight_offset != -1) {
597                                                         float *bweight = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset);
598                                                         apply_scale_factor_clamp(bweight, tot, ve_median[M_BV_WEIGHT], scale_bv_weight);
599                                                 }
600
601                                                 if (cd_vert_skin_offset != -1) {
602                                                         MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
603
604                                                         /* That one is not clamped to [0.0, 1.0]. */
605                                                         if (median[M_SKIN_X] != 0.0f) {
606                                                                 apply_scale_factor(&vs->radius[0], tot, ve_median[M_SKIN_X], median[M_SKIN_X],
607                                                                                    scale_skin_x);
608                                                         }
609                                                         if (median[M_SKIN_Y] != 0.0f) {
610                                                                 apply_scale_factor(&vs->radius[1], tot, ve_median[M_SKIN_Y], median[M_SKIN_Y],
611                                                                                    scale_skin_y);
612                                                         }
613                                                 }
614                                         }
615                                 }
616                         }
617
618                         if (apply_vcos) {
619                                 EDBM_mesh_normals_update(em);
620                         }
621
622                         /* Edges */
623
624                         if (median[M_BE_WEIGHT] || median[M_CREASE]) {
625                                 if (median[M_BE_WEIGHT]) {
626                                         BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
627                                         cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
628                                         BLI_assert(cd_edge_bweight_offset != -1);
629
630                                         scale_be_weight = compute_scale_factor(ve_median[M_BE_WEIGHT], median[M_BE_WEIGHT]);
631                                 }
632
633                                 if (median[M_CREASE]) {
634                                         BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
635                                         cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
636                                         BLI_assert(cd_edge_crease_offset != -1);
637
638                                         scale_crease = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
639                                 }
640
641                                 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
642                                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
643                                                 if (median[M_BE_WEIGHT] != 0.0f) {
644                                                         float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
645                                                         apply_scale_factor_clamp(bweight, tot, ve_median[M_BE_WEIGHT], scale_be_weight);
646                                                 }
647
648                                                 if (median[M_CREASE] != 0.0f) {
649                                                         float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
650                                                         apply_scale_factor_clamp(crease, tot, ve_median[M_CREASE], scale_crease);
651                                                 }
652                                         }
653                                 }
654                         }
655                 }
656                 else if (ELEM(ob->type, OB_CURVE, OB_SURF) &&
657                          (apply_vcos || median[C_BWEIGHT] || median[C_WEIGHT] || median[C_RADIUS] || median[C_TILT]))
658                 {
659                         Curve *cu = ob->data;
660                         Nurb *nu;
661                         BPoint *bp;
662                         BezTriple *bezt;
663                         int a;
664                         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
665                         const float scale_w = compute_scale_factor(ve_median[C_WEIGHT], median[C_WEIGHT]);
666
667                         nu = nurbs->first;
668                         while (nu) {
669                                 if (nu->type == CU_BEZIER) {
670                                         for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
671                                                 if (bezt->f2 & SELECT) {
672                                                         if (apply_vcos) {
673                                                                 /* Here we always have to use the diff... :/
674                                                                  * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see T37327),
675                                                                  * unless we use doubles.
676                                                                  */
677                                                                 add_v3_v3(bezt->vec[0], &median[LOC_X]);
678                                                                 add_v3_v3(bezt->vec[1], &median[LOC_X]);
679                                                                 add_v3_v3(bezt->vec[2], &median[LOC_X]);
680                                                         }
681                                                         if (median[C_WEIGHT]) {
682                                                                 apply_scale_factor_clamp(&bezt->weight, tot, ve_median[C_WEIGHT], scale_w);
683                                                         }
684                                                         if (median[C_RADIUS]) {
685                                                                 apply_raw_diff(&bezt->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
686                                                         }
687                                                         if (median[C_TILT]) {
688                                                                 apply_raw_diff(&bezt->alfa, tot, ve_median[C_TILT], median[C_TILT]);
689                                                         }
690                                                 }
691                                                 else if (apply_vcos) {  /* Handles can only have their coordinates changed here. */
692                                                         if (bezt->f1 & SELECT) {
693                                                                 apply_raw_diff_v3(bezt->vec[0], tot, &ve_median[LOC_X], &median[LOC_X]);
694                                                         }
695                                                         if (bezt->f3 & SELECT) {
696                                                                 apply_raw_diff_v3(bezt->vec[2], tot, &ve_median[LOC_X], &median[LOC_X]);
697                                                         }
698                                                 }
699                                         }
700                                 }
701                                 else {
702                                         for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a--; bp++) {
703                                                 if (bp->f1 & SELECT) {
704                                                         if (apply_vcos) {
705                                                                 apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
706                                                         }
707                                                         if (median[C_BWEIGHT]) {
708                                                                 apply_raw_diff(&bp->vec[3], tot, ve_median[C_BWEIGHT], median[C_BWEIGHT]);
709                                                         }
710                                                         if (median[C_WEIGHT]) {
711                                                                 apply_scale_factor_clamp(&bp->weight, tot, ve_median[C_WEIGHT], scale_w);
712                                                         }
713                                                         if (median[C_RADIUS]) {
714                                                                 apply_raw_diff(&bp->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
715                                                         }
716                                                         if (median[C_TILT]) {
717                                                                 apply_raw_diff(&bp->alfa, tot, ve_median[C_TILT], median[C_TILT]);
718                                                         }
719                                                 }
720                                         }
721                                 }
722                                 BKE_nurb_test_2d(nu);
723                                 BKE_nurb_handles_test(nu, true); /* test for bezier too */
724
725                                 nu = nu->next;
726                         }
727                 }
728                 else if ((ob->type == OB_LATTICE) && (apply_vcos || median[L_WEIGHT])) {
729                         Lattice *lt = ob->data;
730                         BPoint *bp;
731                         int a;
732                         const float scale_w = compute_scale_factor(ve_median[L_WEIGHT], median[L_WEIGHT]);
733
734                         a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
735                         bp = lt->editlatt->latt->def;
736                         while (a--) {
737                                 if (bp->f1 & SELECT) {
738                                         if (apply_vcos) {
739                                                 apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
740                                         }
741                                         if (median[L_WEIGHT]) {
742                                                 apply_scale_factor_clamp(&bp->weight, tot, ve_median[L_WEIGHT], scale_w);
743                                         }
744                                 }
745                                 bp++;
746                         }
747                 }
748
749 /*              ED_undo_push(C, "Transform properties"); */
750         }
751
752 /* Clean up! */
753 /* Location, common to all. */
754 #undef LOC_X
755 #undef LOC_Y
756 #undef LOC_Z
757 /* Meshes (and lattice)... */
758 #undef M_BV_WEIGHT
759 #undef M_SKIN_X
760 #undef M_SKIN_Y
761 #undef M_BE_WEIGHT
762 #undef M_CREASE
763 /* Curves... */
764 #undef C_BWEIGHT
765 #undef C_WEIGHT
766 #undef C_RADIUS
767 #undef C_TILT
768 /* Lattice... */
769 #undef L_WEIGHT
770 }
771 #undef NBR_TRANSFORM_PROPERTIES
772
773 #define B_VGRP_PNL_EDIT_SINGLE 8       /* or greater */
774
775 static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
776 {
777         if (event < B_VGRP_PNL_EDIT_SINGLE) {
778                 /* not for me */
779                 return;
780         }
781         else {
782                 ViewLayer *view_layer = CTX_data_view_layer(C);
783                 Object *ob = view_layer->basact->object;
784                 ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
785                 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
786                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
787         }
788 }
789
790 static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
791 {
792         ViewLayer *view_layer = CTX_data_view_layer(C);
793         Object *ob = OBACT(view_layer);
794         if (ob && (BKE_object_is_in_editmode_vgroup(ob) ||
795                    BKE_object_is_in_wpaint_select_vert(ob)))
796         {
797                 MDeformVert *dvert_act = ED_mesh_active_dvert_get_only(ob);
798                 if (dvert_act) {
799                         return (dvert_act->totweight != 0);
800                 }
801         }
802
803         return false;
804 }
805
806
807 static void view3d_panel_vgroup(const bContext *C, Panel *pa)
808 {
809         uiBlock *block = uiLayoutAbsoluteBlock(pa->layout);
810         Scene *scene = CTX_data_scene(C);
811         ViewLayer *view_layer = CTX_data_view_layer(C);
812         Object *ob = view_layer->basact->object;
813
814         MDeformVert *dv;
815
816         dv = ED_mesh_active_dvert_get_only(ob);
817
818         if (dv && dv->totweight) {
819                 ToolSettings *ts = scene->toolsettings;
820
821                 wmOperatorType *ot;
822                 PointerRNA op_ptr, tools_ptr;
823                 PointerRNA *but_ptr;
824
825                 uiLayout *col, *bcol;
826                 uiLayout *row;
827                 uiBut *but;
828                 bDeformGroup *dg;
829                 unsigned int i;
830                 int subset_count, vgroup_tot;
831                 const bool *vgroup_validmap;
832                 eVGroupSelect subset_type = ts->vgroupsubset;
833                 int yco = 0;
834                 int lock_count = 0;
835
836                 UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL);
837
838                 bcol = uiLayoutColumn(pa->layout, true);
839                 row = uiLayoutRow(bcol, true); /* The filter button row */
840
841                 RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr);
842                 uiItemR(row, &tools_ptr, "vertex_group_subset", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
843
844                 col = uiLayoutColumn(bcol, true);
845
846                 vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
847                 for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) {
848                         bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0;
849                         if (vgroup_validmap[i]) {
850                                 MDeformWeight *dw = defvert_find_index(dv, i);
851                                 if (dw) {
852                                         int x, xco = 0;
853                                         int icon;
854                                         uiLayout *split = uiLayoutSplit(col, 0.45, true);
855                                         row = uiLayoutRow(split, true);
856
857                                         /* The Weight Group Name */
858
859                                         ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
860                                         but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
861                                                             xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
862                                         but_ptr = UI_but_operator_ptr_get(but);
863                                         RNA_int_set(but_ptr, "weight_group", i);
864                                         UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
865                                         if (ob->actdef != i + 1) {
866                                                 UI_but_flag_enable(but, UI_BUT_INACTIVE);
867                                         }
868                                         xco += x;
869
870                                         row = uiLayoutRow(split, true);
871                                         uiLayoutSetEnabled(row, !locked);
872
873                                         /* The weight group value */
874                                         /* To be reworked still */
875                                         but = uiDefButF(block, UI_BTYPE_NUM, B_VGRP_PNL_EDIT_SINGLE + i, "",
876                                                         xco, yco, (x = UI_UNIT_X * 4), UI_UNIT_Y,
877                                                         &dw->weight, 0.0, 1.0, 1, 3, "");
878                                         UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT);
879                                         if (locked) {
880                                                 lock_count++;
881                                         }
882                                         xco += x;
883
884                                         /* The weight group paste function */
885                                         icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
886                                         uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
887                                         RNA_int_set(&op_ptr, "weight_group", i);
888
889                                         /* The weight entry delete function */
890                                         icon = (locked) ? ICON_LOCKED : ICON_X;
891                                         uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
892                                         RNA_int_set(&op_ptr, "weight_group", i);
893
894                                         yco -= UI_UNIT_Y;
895                                 }
896                         }
897                 }
898                 MEM_freeN((void *)vgroup_validmap);
899
900                 yco -= 2;
901
902                 col = uiLayoutColumn(pa->layout, true);
903                 row = uiLayoutRow(col, true);
904
905                 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1);
906                 but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Normalize",
907                                     0, yco, UI_UNIT_X * 5, UI_UNIT_Y,
908                                     TIP_("Normalize weights of active vertex (if affected groups are unlocked)"));
909                 if (lock_count) {
910                         UI_but_flag_enable(but, UI_BUT_DISABLED);
911                 }
912
913                 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_copy", 1);
914                 but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Copy",
915                                     UI_UNIT_X * 5, yco, UI_UNIT_X * 5, UI_UNIT_Y,
916                                     TIP_("Copy active vertex to other selected vertices (if affected groups are unlocked)"));
917                 if (lock_count) {
918                         UI_but_flag_enable(but, UI_BUT_DISABLED);
919                 }
920
921         }
922 }
923
924 static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
925 {
926         uiLayout *split, *colsub;
927
928         split = uiLayoutSplit(layout, 0.8f, false);
929
930         if (ptr->type == &RNA_PoseBone) {
931                 PointerRNA boneptr;
932                 Bone *bone;
933
934                 boneptr = RNA_pointer_get(ptr, "bone");
935                 bone = boneptr.data;
936                 uiLayoutSetActive(split, !(bone->parent && bone->flag & BONE_CONNECTED));
937         }
938         colsub = uiLayoutColumn(split, true);
939         uiItemR(colsub, ptr, "location", 0, NULL, ICON_NONE);
940         colsub = uiLayoutColumn(split, true);
941         uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
942         uiItemL(colsub, "", ICON_NONE);
943         uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
944
945         split = uiLayoutSplit(layout, 0.8f, false);
946
947         switch (RNA_enum_get(ptr, "rotation_mode")) {
948                 case ROT_MODE_QUAT: /* quaternion */
949                         colsub = uiLayoutColumn(split, true);
950                         uiItemR(colsub, ptr, "rotation_quaternion", 0, IFACE_("Rotation"), ICON_NONE);
951                         colsub = uiLayoutColumn(split, true);
952                         uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
953                         uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
954                         if (RNA_boolean_get(ptr, "lock_rotations_4d"))
955                                 uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
956                         else
957                                 uiItemL(colsub, "", ICON_NONE);
958                         uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
959                         break;
960                 case ROT_MODE_AXISANGLE: /* axis angle */
961                         colsub = uiLayoutColumn(split, true);
962                         uiItemR(colsub, ptr, "rotation_axis_angle", 0, IFACE_("Rotation"), ICON_NONE);
963                         colsub = uiLayoutColumn(split, true);
964                         uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
965                         uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
966                         if (RNA_boolean_get(ptr, "lock_rotations_4d"))
967                                 uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
968                         else
969                                 uiItemL(colsub, "", ICON_NONE);
970                         uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
971                         break;
972                 default: /* euler rotations */
973                         colsub = uiLayoutColumn(split, true);
974                         uiItemR(colsub, ptr, "rotation_euler", 0, IFACE_("Rotation"), ICON_NONE);
975                         colsub = uiLayoutColumn(split, true);
976                         uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
977                         uiItemL(colsub, "", ICON_NONE);
978                         uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
979                         break;
980         }
981         uiItemR(layout, ptr, "rotation_mode", 0, "", ICON_NONE);
982
983         split = uiLayoutSplit(layout, 0.8f, false);
984         colsub = uiLayoutColumn(split, true);
985         uiItemR(colsub, ptr, "scale", 0, NULL, ICON_NONE);
986         colsub = uiLayoutColumn(split, true);
987         uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
988         uiItemL(colsub, "", ICON_NONE);
989         uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
990
991         if (ptr->type == &RNA_Object) {
992                 Object *ob = ptr->data;
993                 /* dimensions and editmode just happen to be the same checks */
994                 if (OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
995                         uiItemR(layout, ptr, "dimensions", 0, NULL, ICON_NONE);
996                 }
997         }
998 }
999
1000 static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
1001 {
1002         bPoseChannel *pchan;
1003         PointerRNA pchanptr;
1004         uiLayout *col;
1005
1006         pchan = BKE_pose_channel_active(ob);
1007
1008         if (!pchan) {
1009                 uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
1010                 return;
1011         }
1012
1013         RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &pchanptr);
1014
1015         col = uiLayoutColumn(layout, false);
1016
1017         /* XXX: RNA buts show data in native types (i.e. quats, 4-component axis/angle, etc.)
1018          * but old-school UI shows in eulers always. Do we want to be able to still display in Eulers?
1019          * Maybe needs RNA/ui options to display rotations as different types... */
1020         v3d_transform_butsR(col, &pchanptr);
1021 }
1022
1023 static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
1024 {
1025         bArmature *arm = ob->data;
1026         EditBone *ebone;
1027         uiLayout *col;
1028         PointerRNA eboneptr;
1029
1030         ebone = arm->act_edbone;
1031
1032         if (!ebone || (ebone->layer & arm->layer) == 0) {
1033                 uiItemL(layout, IFACE_("Nothing selected"), ICON_NONE);
1034                 return;
1035         }
1036
1037         RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &eboneptr);
1038
1039         col = uiLayoutColumn(layout, false);
1040         uiItemR(col, &eboneptr, "head", 0, NULL, ICON_NONE);
1041         if (ebone->parent && ebone->flag & BONE_CONNECTED) {
1042                 PointerRNA parptr = RNA_pointer_get(&eboneptr, "parent");
1043                 uiItemR(col, &parptr, "tail_radius", 0, IFACE_("Radius (Parent)"), ICON_NONE);
1044         }
1045         else {
1046                 uiItemR(col, &eboneptr, "head_radius", 0, IFACE_("Radius"), ICON_NONE);
1047         }
1048
1049         uiItemR(col, &eboneptr, "tail", 0, NULL, ICON_NONE);
1050         uiItemR(col, &eboneptr, "tail_radius", 0, IFACE_("Radius"), ICON_NONE);
1051
1052         uiItemR(col, &eboneptr, "roll", 0, NULL, ICON_NONE);
1053         uiItemR(col, &eboneptr, "envelope_distance", 0, IFACE_("Envelope"), ICON_NONE);
1054 }
1055
1056 static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
1057 {
1058         PointerRNA mbptr, ptr;
1059         MetaBall *mball = ob->data;
1060         uiLayout *col;
1061
1062         if (!mball || !(mball->lastelem))
1063                 return;
1064
1065         RNA_pointer_create(&mball->id, &RNA_MetaBall, mball, &mbptr);
1066
1067         RNA_pointer_create(&mball->id, &RNA_MetaElement, mball->lastelem, &ptr);
1068
1069         col = uiLayoutColumn(layout, false);
1070         uiItemR(col, &ptr, "co", 0, NULL, ICON_NONE);
1071
1072         uiItemR(col, &ptr, "radius", 0, NULL, ICON_NONE);
1073         uiItemR(col, &ptr, "stiffness", 0, NULL, ICON_NONE);
1074
1075         uiItemR(col, &ptr, "type", 0, NULL, ICON_NONE);
1076
1077         col = uiLayoutColumn(layout, true);
1078         switch (RNA_enum_get(&ptr, "type")) {
1079                 case MB_BALL:
1080                         break;
1081                 case MB_CUBE:
1082                         uiItemL(col, IFACE_("Size:"), ICON_NONE);
1083                         uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1084                         uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1085                         uiItemR(col, &ptr, "size_z", 0, "Z", ICON_NONE);
1086                         break;
1087                 case MB_TUBE:
1088                         uiItemL(col, IFACE_("Size:"), ICON_NONE);
1089                         uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1090                         break;
1091                 case MB_PLANE:
1092                         uiItemL(col, IFACE_("Size:"), ICON_NONE);
1093                         uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1094                         uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1095                         break;
1096                 case MB_ELIPSOID:
1097                         uiItemL(col, IFACE_("Size:"), ICON_NONE);
1098                         uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1099                         uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1100                         uiItemR(col, &ptr, "size_z", 0, "Z", ICON_NONE);
1101                         break;
1102         }
1103 }
1104
1105 static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event)
1106 {
1107         ViewLayer *view_layer = CTX_data_view_layer(C);
1108         View3D *v3d = CTX_wm_view3d(C);
1109         Object *ob = OBACT(view_layer);
1110
1111         switch (event) {
1112
1113                 case B_REDR:
1114                         ED_area_tag_redraw(CTX_wm_area(C));
1115                         return; /* no notifier! */
1116
1117                 case B_OBJECTPANELMEDIAN:
1118                         if (ob) {
1119                                 v3d_editvertex_buts(NULL, v3d, ob, 1.0);
1120                                 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
1121                         }
1122                         break;
1123         }
1124
1125         /* default for now */
1126         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1127 }
1128
1129 static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
1130 {
1131         ViewLayer *view_layer = CTX_data_view_layer(C);
1132         return (view_layer->basact != NULL);
1133 }
1134
1135 static void view3d_panel_transform(const bContext *C, Panel *pa)
1136 {
1137         uiBlock *block;
1138         Scene *scene = CTX_data_scene(C);
1139         ViewLayer *view_layer = CTX_data_view_layer(C);
1140         Object *obedit = CTX_data_edit_object(C);
1141         Object *ob = view_layer->basact->object;
1142         uiLayout *col;
1143
1144         block = uiLayoutGetBlock(pa->layout);
1145         UI_block_func_handle_set(block, do_view3d_region_buttons, NULL);
1146
1147         col = uiLayoutColumn(pa->layout, false);
1148
1149         if (ob == obedit) {
1150                 if (ob->type == OB_ARMATURE) {
1151                         v3d_editarmature_buts(col, ob);
1152                 }
1153                 else if (ob->type == OB_MBALL) {
1154                         v3d_editmetaball_buts(col, ob);
1155                 }
1156                 else {
1157                         View3D *v3d = CTX_wm_view3d(C);
1158                         const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
1159                         v3d_editvertex_buts(col, v3d, ob, lim);
1160                 }
1161         }
1162         else if (ob->mode & OB_MODE_POSE) {
1163                 v3d_posearmature_buts(col, ob);
1164         }
1165         else {
1166                 PointerRNA obptr;
1167
1168                 RNA_id_pointer_create(&ob->id, &obptr);
1169                 v3d_transform_butsR(col, &obptr);
1170         }
1171 }
1172
1173 static void hide_collections_menu_draw(const bContext *C, Menu *menu)
1174 {
1175         ED_collection_hide_menu_draw(C, menu->layout);
1176 }
1177
1178 void view3d_buttons_register(ARegionType *art)
1179 {
1180         PanelType *pt;
1181
1182         pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object");
1183         strcpy(pt->idname, "VIEW3D_PT_transform");
1184         strcpy(pt->label, N_("Transform"));  /* XXX C panels not  available through RNA (bpy.types)! */
1185         strcpy(pt->category, "View");
1186         strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1187         pt->draw = view3d_panel_transform;
1188         pt->poll = view3d_panel_transform_poll;
1189         BLI_addtail(&art->paneltypes, pt);
1190
1191         pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
1192         strcpy(pt->idname, "VIEW3D_PT_vgroup");
1193         strcpy(pt->label, N_("Vertex Weights"));  /* XXX C panels are not available through RNA (bpy.types)! */
1194         strcpy(pt->category, "View");
1195         strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1196         pt->draw = view3d_panel_vgroup;
1197         pt->poll = view3d_panel_vgroup_poll;
1198         BLI_addtail(&art->paneltypes, pt);
1199
1200         MenuType *mt;
1201
1202         mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections");
1203         strcpy(mt->idname, "VIEW3D_MT_collection");
1204         strcpy(mt->label, N_("Collection"));
1205         strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1206         mt->draw = hide_collections_menu_draw;
1207         WM_menutype_add(mt);
1208 }
1209
1210 static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1211 {
1212         ScrArea *sa = CTX_wm_area(C);
1213         ARegion *ar = view3d_has_buttons_region(sa);
1214
1215         if (ar)
1216                 ED_region_toggle_hidden(C, ar);
1217
1218         return OPERATOR_FINISHED;
1219 }
1220
1221 void VIEW3D_OT_properties(wmOperatorType *ot)
1222 {
1223         ot->name = "Toggle Sidebar";
1224         ot->description = "Toggle the properties region visibility";
1225         ot->idname = "VIEW3D_OT_properties";
1226
1227         ot->exec = view3d_properties_toggle_exec;
1228         ot->poll = ED_operator_view3d_active;
1229
1230         /* flags */
1231         ot->flag = 0;
1232 }
1233
1234 static int view3d_object_mode_menu(bContext *C, wmOperator *op)
1235 {
1236         Object *ob = CTX_data_active_object(C);
1237         if (ob == NULL) {
1238                 BKE_report(op->reports, RPT_WARNING, "No active object found");
1239                 return OPERATOR_CANCELLED;
1240         }
1241         else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) {
1242                 ED_object_mode_toggle(C, OB_MODE_POSE);
1243                 return OPERATOR_CANCELLED;
1244         }
1245         else {
1246                 UI_pie_menu_invoke(C, "VIEW3D_MT_object_mode_pie", CTX_wm_window(C)->eventstate);
1247                 return OPERATOR_CANCELLED;
1248         }
1249 }
1250
1251 void VIEW3D_OT_object_mode_pie_or_toggle(wmOperatorType *ot)
1252 {
1253         ot->name = "Object Mode Menu";
1254         ot->idname = "VIEW3D_OT_object_mode_pie_or_toggle";
1255
1256         ot->exec = view3d_object_mode_menu;
1257         ot->poll = ED_operator_view3d_active;
1258
1259         /* flags */
1260         ot->flag = 0;
1261 }