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