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