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