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