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