2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2009 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_view3d/view3d_buttons.c
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"
46 #include "MEM_guardedalloc.h"
48 #include "BLT_translation.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_utildefines.h"
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_curve.h"
57 #include "BKE_customdata.h"
58 #include "BKE_screen.h"
59 #include "BKE_editmesh.h"
60 #include "BKE_deform.h"
61 #include "BKE_object.h"
62 #include "BKE_object_deform.h"
63 #include "BKE_report.h"
65 #include "DEG_depsgraph.h"
70 #include "RNA_access.h"
72 #include "ED_armature.h"
73 #include "ED_object.h"
75 #include "ED_screen.h"
77 #include "UI_interface.h"
78 #include "UI_resources.h"
80 #include "view3d_intern.h" /* own include */
83 /* ******************* view3d space & buttons ************** */
85 #define B_OBJECTPANELMEDIAN 1008
86 #define B_OBJECTPANEL_DIMS 1009
88 #define NBR_TRANSFORM_PROPERTIES 8
90 /* temporary struct for storing transform properties */
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_orig[3];
97 float ve_median[NBR_TRANSFORM_PROPERTIES];
98 } TransformProperties;
100 /* Helper function to compute a median changed value,
101 * when the value should be clamped in [0.0, 1.0].
102 * Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor
103 * for scale down, or a negative one for scale up.
105 static float compute_scale_factor(const float ve_median, const float median)
107 if (ve_median <= 0.0f)
109 else if (ve_median >= 1.0f)
112 /* Scale value to target median. */
113 float median_new = ve_median;
114 float median_orig = ve_median - median; /* Previous median value. */
116 /* In case of floating point error. */
117 CLAMP(median_orig, 0.0f, 1.0f);
118 CLAMP(median_new, 0.0f, 1.0f);
120 if (median_new <= median_orig) {
122 return median_new / median_orig;
125 /* Scale up, negative to indicate it... */
126 return -(1.0f - median_new) / (1.0f - median_orig);
132 * Note: In case we only have one element, copy directly the value instead of applying the diff or scale factor.
133 * Avoids some glitches when going e.g. from 3 to 0.0001 (see T37327).
135 static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
137 *val = (tot == 1) ? ve_median : (*val + median);
140 static void apply_raw_diff_v3(float val[3], const int tot, const float ve_median[3], const float median[3])
143 copy_v3_v3(val, ve_median);
146 add_v3_v3(val, median);
150 static void apply_scale_factor(float *val, const int tot, const float ve_median, const float median, const float sca)
152 if (tot == 1 || ve_median == median) {
160 static void apply_scale_factor_clamp(float *val, const int tot, const float ve_median, const float sca)
164 CLAMP(*val, 0.0f, 1.0f);
166 else if (ELEM(sca, 0.0f, 1.0f)) {
170 *val = (sca > 0.0f) ? (*val * sca) : (1.0f + ((1.0f - *val) * sca));
171 CLAMP(*val, 0.0f, 1.0f);
175 static TransformProperties *v3d_transform_props_ensure(View3D *v3d)
177 if (v3d->properties_storage == NULL) {
178 v3d->properties_storage = MEM_callocN(sizeof(TransformProperties), "TransformProperties");
180 return v3d->properties_storage;
183 /* is used for both read and write... */
184 static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim)
186 /* Get rid of those ugly magic numbers, even in a single func they become confusing! */
187 /* Location, common to all. */
188 /* Next three *must* remain contiguous (used as array)! */
193 #define M_BV_WEIGHT 3
194 /* Next two *must* remain contiguous (used as array)! */
197 #define M_BE_WEIGHT 6
207 uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : NULL;
208 TransformProperties *tfp = v3d_transform_props_ensure(v3d);
209 float median[NBR_TRANSFORM_PROPERTIES], ve_median[NBR_TRANSFORM_PROPERTIES];
210 int tot, totedgedata, totcurvedata, totlattdata, totcurvebweight;
211 bool has_meshdata = false;
212 bool has_skinradius = false;
215 copy_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
216 tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
218 if (ob->type == OB_MESH) {
220 BMEditMesh *em = me->edit_btmesh;
226 const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
227 const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
228 const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
229 const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
231 has_skinradius = (cd_vert_skin_offset != -1);
233 if (bm->totvertsel) {
234 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
235 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
237 add_v3_v3(&median[LOC_X], eve->co);
239 if (cd_vert_bweight_offset != -1) {
240 median[M_BV_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
243 if (has_skinradius) {
244 MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
245 add_v2_v2(&median[M_SKIN_X], vs->radius); /* Third val not used currently. */
251 if ((cd_edge_bweight_offset != -1) || (cd_edge_crease_offset != -1)) {
252 if (bm->totedgesel) {
253 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
254 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
255 if (cd_edge_bweight_offset != -1) {
256 median[M_BE_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
259 if (cd_edge_crease_offset != -1) {
260 median[M_CREASE] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
269 totedgedata = bm->totedgesel;
272 has_meshdata = (tot || totedgedata);
274 else if (ob->type == OB_CURVE || ob->type == OB_SURF) {
275 Curve *cu = ob->data;
280 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
281 StructRNA *seltype = NULL;
286 if (nu->type == CU_BEZIER) {
290 if (bezt->f2 & SELECT) {
291 add_v3_v3(&median[LOC_X], bezt->vec[1]);
293 median[C_WEIGHT] += bezt->weight;
294 median[C_RADIUS] += bezt->radius;
295 median[C_TILT] += bezt->alfa;
296 if (!totcurvedata) { /* I.e. first time... */
298 seltype = &RNA_BezierSplinePoint;
303 if (bezt->f1 & SELECT) {
304 add_v3_v3(&median[LOC_X], bezt->vec[0]);
307 if (bezt->f3 & SELECT) {
308 add_v3_v3(&median[LOC_X], bezt->vec[2]);
317 a = nu->pntsu * nu->pntsv;
319 if (bp->f1 & SELECT) {
320 add_v3_v3(&median[LOC_X], bp->vec);
321 median[C_BWEIGHT] += bp->vec[3];
324 median[C_WEIGHT] += bp->weight;
325 median[C_RADIUS] += bp->radius;
326 median[C_TILT] += bp->alfa;
327 if (!totcurvedata) { /* I.e. first time... */
329 seltype = &RNA_SplinePoint;
339 if (totcurvedata == 1)
340 RNA_pointer_create(&cu->id, seltype, selp, &data_ptr);
342 else if (ob->type == OB_LATTICE) {
343 Lattice *lt = ob->data;
346 StructRNA *seltype = NULL;
349 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
350 bp = lt->editlatt->latt->def;
352 if (bp->f1 & SELECT) {
353 add_v3_v3(&median[LOC_X], bp->vec);
355 median[L_WEIGHT] += bp->weight;
356 if (!totlattdata) { /* I.e. first time... */
358 seltype = &RNA_LatticePoint;
365 if (totlattdata == 1)
366 RNA_pointer_create(<->id, seltype, selp, &data_ptr);
370 uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, NULL, 0, 0, 0, 0, "");
374 /* Location, X/Y/Z */
375 mul_v3_fl(&median[LOC_X], 1.0f / (float)tot);
376 if (v3d->flag & V3D_GLOBAL_STATS)
377 mul_m4_v3(ob->obmat, &median[LOC_X]);
381 median[M_CREASE] /= (float)totedgedata;
382 median[M_BE_WEIGHT] /= (float)totedgedata;
385 median[M_BV_WEIGHT] /= (float)tot;
386 if (has_skinradius) {
387 median[M_SKIN_X] /= (float)tot;
388 median[M_SKIN_Y] /= (float)tot;
392 else if (totcurvedata) {
393 if (totcurvebweight) {
394 median[C_BWEIGHT] /= (float)totcurvebweight;
396 median[C_WEIGHT] /= (float)totcurvedata;
397 median[C_RADIUS] /= (float)totcurvedata;
398 median[C_TILT] /= (float)totcurvedata;
400 else if (totlattdata) {
401 median[L_WEIGHT] /= (float)totlattdata;
404 if (block) { /* buttons */
407 const float tilt_limit = DEG2RADF(21600.0f);
408 const int buth = 20 * UI_DPI_FAC;
409 const int but_margin = 2;
412 memcpy(tfp->ve_median, median, sizeof(tfp->ve_median));
414 UI_block_align_begin(block);
416 if (totcurvedata) /* Curve */
417 c = IFACE_("Control Point:");
418 else /* Mesh or lattice */
419 c = IFACE_("Vertex:");
422 c = IFACE_("Median:");
423 uiDefBut(block, UI_BTYPE_LABEL, 0, c, 0, yi -= buth, 200, buth, NULL, 0, 0, 0, 0, "");
425 UI_block_align_begin(block);
427 /* Should be no need to translate these. */
428 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("X:"), 0, yi -= buth, 200, buth,
429 &(tfp->ve_median[LOC_X]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
430 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
431 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Y:"), 0, yi -= buth, 200, buth,
432 &(tfp->ve_median[LOC_Y]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
433 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
434 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Z:"), 0, yi -= buth, 200, buth,
435 &(tfp->ve_median[LOC_Z]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
436 UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
438 if (totcurvebweight == tot) {
439 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("W:"), 0, yi -= buth, 200, buth,
440 &(tfp->ve_median[C_BWEIGHT]), 0.01, 100.0, 1, 3, "");
443 UI_block_align_begin(block);
444 uiDefButBitS(block, UI_BTYPE_TOGGLE, V3D_GLOBAL_STATS, B_REDR, IFACE_("Global"),
445 0, yi -= buth + but_margin, 100, buth,
446 &v3d->flag, 0, 0, 0, 0, TIP_("Displays global values"));
447 uiDefButBitS(block, UI_BTYPE_TOGGLE_N, V3D_GLOBAL_STATS, B_REDR, IFACE_("Local"),
449 &v3d->flag, 0, 0, 0, 0, TIP_("Displays local values"));
450 UI_block_align_end(block);
455 uiDefBut(block, UI_BTYPE_LABEL, 0, tot == 1 ? IFACE_("Vertex Data:") : IFACE_("Vertices Data:"),
456 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
457 /* customdata layer added on demand */
458 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
459 tot == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
460 0, yi -= buth + but_margin, 200, buth,
461 &(tfp->ve_median[M_BV_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Vertex weight used by Bevel modifier"));
463 if (has_skinradius) {
464 UI_block_align_begin(block);
465 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
466 tot == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
467 0, yi -= buth + but_margin, 200, buth,
468 &(tfp->ve_median[M_SKIN_X]), 0.0, 100.0, 1, 3, TIP_("X radius used by Skin modifier"));
469 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
470 tot == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
471 0, yi -= buth + but_margin, 200, buth,
472 &(tfp->ve_median[M_SKIN_Y]), 0.0, 100.0, 1, 3, TIP_("Y radius used by Skin modifier"));
473 UI_block_align_end(block);
476 uiDefBut(block, UI_BTYPE_LABEL, 0, totedgedata == 1 ? IFACE_("Edge Data:") : IFACE_("Edges Data:"),
477 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
478 /* customdata layer added on demand */
479 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
480 totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
481 0, yi -= buth + but_margin, 200, buth,
482 &(tfp->ve_median[M_BE_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Edge weight used by Bevel modifier"));
483 /* customdata layer added on demand */
484 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
485 totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
486 0, yi -= buth + but_margin, 200, buth,
487 &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier"));
491 else if (totcurvedata == 1) {
492 uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
493 &data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
494 uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Radius:"), 0, yi -= buth + but_margin, 200, buth,
495 &data_ptr, "radius", 0, 0.0, 100.0, 1, 3, NULL);
496 uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Tilt:"), 0, yi -= buth + but_margin, 200, buth,
497 &data_ptr, "tilt", 0, -tilt_limit, tilt_limit, 1, 3, NULL);
499 else if (totcurvedata > 1) {
500 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
501 0, yi -= buth + but_margin, 200, buth,
502 &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
503 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
504 0, yi -= buth + but_margin, 200, buth,
505 &(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points"));
506 but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Tilt:"),
507 0, yi -= buth + but_margin, 200, buth,
508 &(tfp->ve_median[C_TILT]), -tilt_limit, tilt_limit, 1, 3,
509 TIP_("Tilt of curve control points"));
510 UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
513 else if (totlattdata == 1) {
514 uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
515 &data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
517 else if (totlattdata > 1) {
518 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
519 0, yi -= buth + but_margin, 200, buth,
520 &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
523 UI_block_align_end(block);
529 memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median));
531 if (v3d->flag & V3D_GLOBAL_STATS) {
532 invert_m4_m4(ob->imat, ob->obmat);
533 mul_m4_v3(ob->imat, &median[LOC_X]);
534 mul_m4_v3(ob->imat, &ve_median[LOC_X]);
536 i = NBR_TRANSFORM_PROPERTIES;
538 median[i] = ve_median[i] - median[i];
540 /* Note with a single element selected, we always do. */
541 apply_vcos = (tot == 1) || (len_squared_v3(&median[LOC_X]) != 0.0f);
543 if ((ob->type == OB_MESH) &&
544 (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y] ||
545 median[M_BE_WEIGHT] || median[M_CREASE]))
548 BMEditMesh *em = me->edit_btmesh;
554 int cd_vert_bweight_offset = -1;
555 int cd_vert_skin_offset = -1;
556 int cd_edge_bweight_offset = -1;
557 int cd_edge_crease_offset = -1;
559 float scale_bv_weight = 1.0f;
560 float scale_skin_x = 1.0f;
561 float scale_skin_y = 1.0f;
562 float scale_be_weight = 1.0f;
563 float scale_crease = 1.0f;
567 if (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y]) {
568 if (median[M_BV_WEIGHT]) {
569 BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
570 cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
571 BLI_assert(cd_vert_bweight_offset != -1);
573 scale_bv_weight = compute_scale_factor(ve_median[M_BV_WEIGHT], median[M_BV_WEIGHT]);
576 if (median[M_SKIN_X]) {
577 cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
578 BLI_assert(cd_vert_skin_offset != -1);
580 if (ve_median[M_SKIN_X] != median[M_SKIN_X]) {
581 scale_skin_x = ve_median[M_SKIN_X] / (ve_median[M_SKIN_X] - median[M_SKIN_X]);
584 if (median[M_SKIN_Y]) {
585 if (cd_vert_skin_offset == -1) {
586 cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
587 BLI_assert(cd_vert_skin_offset != -1);
590 if (ve_median[M_SKIN_Y] != median[M_SKIN_Y]) {
591 scale_skin_y = ve_median[M_SKIN_Y] / (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
595 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
596 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
598 apply_raw_diff_v3(eve->co, tot, &ve_median[LOC_X], &median[LOC_X]);
601 if (cd_vert_bweight_offset != -1) {
602 float *bweight = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset);
603 apply_scale_factor_clamp(bweight, tot, ve_median[M_BV_WEIGHT], scale_bv_weight);
606 if (cd_vert_skin_offset != -1) {
607 MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
609 /* That one is not clamped to [0.0, 1.0]. */
610 if (median[M_SKIN_X] != 0.0f) {
611 apply_scale_factor(&vs->radius[0], tot, ve_median[M_SKIN_X], median[M_SKIN_X],
614 if (median[M_SKIN_Y] != 0.0f) {
615 apply_scale_factor(&vs->radius[1], tot, ve_median[M_SKIN_Y], median[M_SKIN_Y],
624 EDBM_mesh_normals_update(em);
629 if (median[M_BE_WEIGHT] || median[M_CREASE]) {
630 if (median[M_BE_WEIGHT]) {
631 BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
632 cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
633 BLI_assert(cd_edge_bweight_offset != -1);
635 scale_be_weight = compute_scale_factor(ve_median[M_BE_WEIGHT], median[M_BE_WEIGHT]);
638 if (median[M_CREASE]) {
639 BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
640 cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
641 BLI_assert(cd_edge_crease_offset != -1);
643 scale_crease = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
646 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
647 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
648 if (median[M_BE_WEIGHT] != 0.0f) {
649 float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
650 apply_scale_factor_clamp(bweight, tot, ve_median[M_BE_WEIGHT], scale_be_weight);
653 if (median[M_CREASE] != 0.0f) {
654 float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
655 apply_scale_factor_clamp(crease, tot, ve_median[M_CREASE], scale_crease);
661 else if (ELEM(ob->type, OB_CURVE, OB_SURF) &&
662 (apply_vcos || median[C_BWEIGHT] || median[C_WEIGHT] || median[C_RADIUS] || median[C_TILT]))
664 Curve *cu = ob->data;
669 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
670 const float scale_w = compute_scale_factor(ve_median[C_WEIGHT], median[C_WEIGHT]);
674 if (nu->type == CU_BEZIER) {
675 for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
676 if (bezt->f2 & SELECT) {
678 /* Here we always have to use the diff... :/
679 * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see T37327),
680 * unless we use doubles.
682 add_v3_v3(bezt->vec[0], &median[LOC_X]);
683 add_v3_v3(bezt->vec[1], &median[LOC_X]);
684 add_v3_v3(bezt->vec[2], &median[LOC_X]);
686 if (median[C_WEIGHT]) {
687 apply_scale_factor_clamp(&bezt->weight, tot, ve_median[C_WEIGHT], scale_w);
689 if (median[C_RADIUS]) {
690 apply_raw_diff(&bezt->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
692 if (median[C_TILT]) {
693 apply_raw_diff(&bezt->alfa, tot, ve_median[C_TILT], median[C_TILT]);
696 else if (apply_vcos) { /* Handles can only have their coordinates changed here. */
697 if (bezt->f1 & SELECT) {
698 apply_raw_diff_v3(bezt->vec[0], tot, &ve_median[LOC_X], &median[LOC_X]);
700 if (bezt->f3 & SELECT) {
701 apply_raw_diff_v3(bezt->vec[2], tot, &ve_median[LOC_X], &median[LOC_X]);
707 for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a--; bp++) {
708 if (bp->f1 & SELECT) {
710 apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
712 if (median[C_BWEIGHT]) {
713 apply_raw_diff(&bp->vec[3], tot, ve_median[C_BWEIGHT], median[C_BWEIGHT]);
715 if (median[C_WEIGHT]) {
716 apply_scale_factor_clamp(&bp->weight, tot, ve_median[C_WEIGHT], scale_w);
718 if (median[C_RADIUS]) {
719 apply_raw_diff(&bp->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
721 if (median[C_TILT]) {
722 apply_raw_diff(&bp->alfa, tot, ve_median[C_TILT], median[C_TILT]);
727 BKE_nurb_test_2d(nu);
728 BKE_nurb_handles_test(nu, true); /* test for bezier too */
733 else if ((ob->type == OB_LATTICE) && (apply_vcos || median[L_WEIGHT])) {
734 Lattice *lt = ob->data;
737 const float scale_w = compute_scale_factor(ve_median[L_WEIGHT], median[L_WEIGHT]);
739 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
740 bp = lt->editlatt->latt->def;
742 if (bp->f1 & SELECT) {
744 apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
746 if (median[L_WEIGHT]) {
747 apply_scale_factor_clamp(&bp->weight, tot, ve_median[L_WEIGHT], scale_w);
754 /* ED_undo_push(C, "Transform properties"); */
758 /* Location, common to all. */
762 /* Meshes (and lattice)... */
776 #undef NBR_TRANSFORM_PROPERTIES
778 static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d, Object *ob)
780 uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : NULL;
781 TransformProperties *tfp = v3d_transform_props_ensure(v3d);
784 BLI_assert(C == NULL);
787 const int butw = 200;
788 const int buth = 20 * UI_DPI_FAC;
790 BKE_object_dimensions_get(ob, tfp->ob_dims);
791 copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims);
793 uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Dimensions:"), 0, yi -= buth, butw, buth, NULL, 0, 0, 0, 0, "");
794 UI_block_align_begin(block);
795 const float lim = 10000;
796 for (int i = 0; i < 3; i++) {
797 char text[3] = {'X' + i, ':', '\0'};
798 uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANEL_DIMS, text, 0, yi -= buth, butw, buth,
799 &(tfp->ob_dims[i]), 0.0f, lim, 10, 3, "");
801 UI_block_align_end(block);
805 for (int i = 0; i < 3; i++) {
806 if (tfp->ob_dims[i] == tfp->ob_dims_orig[i]) {
807 axis_mask |= (1 << i);
810 BKE_object_dimensions_set(ob, tfp->ob_dims, axis_mask);
813 RNA_id_pointer_create(&ob->id, &obptr);
814 PropertyRNA *prop = RNA_struct_find_property(&obptr, "scale");
815 RNA_property_update(C, &obptr, prop);
819 #define B_VGRP_PNL_EDIT_SINGLE 8 /* or greater */
821 static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
823 if (event < B_VGRP_PNL_EDIT_SINGLE) {
828 ViewLayer *view_layer = CTX_data_view_layer(C);
829 Object *ob = view_layer->basact->object;
830 ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
831 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
832 WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
836 static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
838 ViewLayer *view_layer = CTX_data_view_layer(C);
839 Object *ob = OBACT(view_layer);
840 if (ob && (BKE_object_is_in_editmode_vgroup(ob) ||
841 BKE_object_is_in_wpaint_select_vert(ob)))
843 MDeformVert *dvert_act = ED_mesh_active_dvert_get_only(ob);
845 return (dvert_act->totweight != 0);
853 static void view3d_panel_vgroup(const bContext *C, Panel *pa)
855 uiBlock *block = uiLayoutAbsoluteBlock(pa->layout);
856 Scene *scene = CTX_data_scene(C);
857 ViewLayer *view_layer = CTX_data_view_layer(C);
858 Object *ob = view_layer->basact->object;
862 dv = ED_mesh_active_dvert_get_only(ob);
864 if (dv && dv->totweight) {
865 ToolSettings *ts = scene->toolsettings;
868 PointerRNA op_ptr, tools_ptr;
871 uiLayout *col, *bcol;
876 int subset_count, vgroup_tot;
877 const bool *vgroup_validmap;
878 eVGroupSelect subset_type = ts->vgroupsubset;
882 UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL);
884 bcol = uiLayoutColumn(pa->layout, true);
885 row = uiLayoutRow(bcol, true); /* The filter button row */
887 RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr);
888 uiItemR(row, &tools_ptr, "vertex_group_subset", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
890 col = uiLayoutColumn(bcol, true);
892 vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
893 for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) {
894 bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0;
895 if (vgroup_validmap[i]) {
896 MDeformWeight *dw = defvert_find_index(dv, i);
900 uiLayout *split = uiLayoutSplit(col, 0.45, true);
901 row = uiLayoutRow(split, true);
903 /* The Weight Group Name */
905 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
906 but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
907 xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
908 but_ptr = UI_but_operator_ptr_get(but);
909 RNA_int_set(but_ptr, "weight_group", i);
910 UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
911 if (ob->actdef != i + 1) {
912 UI_but_flag_enable(but, UI_BUT_INACTIVE);
916 row = uiLayoutRow(split, true);
917 uiLayoutSetEnabled(row, !locked);
919 /* The weight group value */
920 /* To be reworked still */
921 but = uiDefButF(block, UI_BTYPE_NUM, B_VGRP_PNL_EDIT_SINGLE + i, "",
922 xco, yco, (x = UI_UNIT_X * 4), UI_UNIT_Y,
923 &dw->weight, 0.0, 1.0, 1, 3, "");
924 UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT);
930 /* The weight group paste function */
931 icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
932 uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
933 RNA_int_set(&op_ptr, "weight_group", i);
935 /* The weight entry delete function */
936 icon = (locked) ? ICON_LOCKED : ICON_X;
937 uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
938 RNA_int_set(&op_ptr, "weight_group", i);
944 MEM_freeN((void *)vgroup_validmap);
948 col = uiLayoutColumn(pa->layout, true);
949 row = uiLayoutRow(col, true);
951 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1);
952 but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Normalize",
953 0, yco, UI_UNIT_X * 5, UI_UNIT_Y,
954 TIP_("Normalize weights of active vertex (if affected groups are unlocked)"));
956 UI_but_flag_enable(but, UI_BUT_DISABLED);
959 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_copy", 1);
960 but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Copy",
961 UI_UNIT_X * 5, yco, UI_UNIT_X * 5, UI_UNIT_Y,
962 TIP_("Copy active vertex to other selected vertices (if affected groups are unlocked)"));
964 UI_but_flag_enable(but, UI_BUT_DISABLED);
970 static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
972 uiLayout *split, *colsub;
974 split = uiLayoutSplit(layout, 0.8f, false);
976 if (ptr->type == &RNA_PoseBone) {
980 boneptr = RNA_pointer_get(ptr, "bone");
982 uiLayoutSetActive(split, !(bone->parent && bone->flag & BONE_CONNECTED));
984 colsub = uiLayoutColumn(split, true);
985 uiItemR(colsub, ptr, "location", 0, NULL, ICON_NONE);
986 colsub = uiLayoutColumn(split, true);
987 uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
988 uiItemL(colsub, "", ICON_NONE);
989 uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
991 split = uiLayoutSplit(layout, 0.8f, false);
993 switch (RNA_enum_get(ptr, "rotation_mode")) {
994 case ROT_MODE_QUAT: /* quaternion */
995 colsub = uiLayoutColumn(split, true);
996 uiItemR(colsub, ptr, "rotation_quaternion", 0, IFACE_("Rotation"), ICON_NONE);
997 colsub = uiLayoutColumn(split, true);
998 uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
999 uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
1000 if (RNA_boolean_get(ptr, "lock_rotations_4d"))
1001 uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1003 uiItemL(colsub, "", ICON_NONE);
1004 uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1006 case ROT_MODE_AXISANGLE: /* axis angle */
1007 colsub = uiLayoutColumn(split, true);
1008 uiItemR(colsub, ptr, "rotation_axis_angle", 0, IFACE_("Rotation"), ICON_NONE);
1009 colsub = uiLayoutColumn(split, true);
1010 uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
1011 uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
1012 if (RNA_boolean_get(ptr, "lock_rotations_4d"))
1013 uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1015 uiItemL(colsub, "", ICON_NONE);
1016 uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1018 default: /* euler rotations */
1019 colsub = uiLayoutColumn(split, true);
1020 uiItemR(colsub, ptr, "rotation_euler", 0, IFACE_("Rotation"), ICON_NONE);
1021 colsub = uiLayoutColumn(split, true);
1022 uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
1023 uiItemL(colsub, "", ICON_NONE);
1024 uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1027 uiItemR(layout, ptr, "rotation_mode", 0, "", ICON_NONE);
1029 split = uiLayoutSplit(layout, 0.8f, false);
1030 colsub = uiLayoutColumn(split, true);
1031 uiItemR(colsub, ptr, "scale", 0, NULL, ICON_NONE);
1032 colsub = uiLayoutColumn(split, true);
1033 uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
1034 uiItemL(colsub, "", ICON_NONE);
1035 uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1038 static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
1040 bPoseChannel *pchan;
1041 PointerRNA pchanptr;
1044 pchan = BKE_pose_channel_active(ob);
1047 uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
1051 RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &pchanptr);
1053 col = uiLayoutColumn(layout, false);
1055 /* XXX: RNA buts show data in native types (i.e. quats, 4-component axis/angle, etc.)
1056 * but old-school UI shows in eulers always. Do we want to be able to still display in Eulers?
1057 * Maybe needs RNA/ui options to display rotations as different types... */
1058 v3d_transform_butsR(col, &pchanptr);
1061 static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
1063 bArmature *arm = ob->data;
1066 PointerRNA eboneptr;
1068 ebone = arm->act_edbone;
1070 if (!ebone || (ebone->layer & arm->layer) == 0) {
1071 uiItemL(layout, IFACE_("Nothing selected"), ICON_NONE);
1075 RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &eboneptr);
1077 col = uiLayoutColumn(layout, false);
1078 uiItemR(col, &eboneptr, "head", 0, NULL, ICON_NONE);
1079 if (ebone->parent && ebone->flag & BONE_CONNECTED) {
1080 PointerRNA parptr = RNA_pointer_get(&eboneptr, "parent");
1081 uiItemR(col, &parptr, "tail_radius", 0, IFACE_("Radius (Parent)"), ICON_NONE);
1084 uiItemR(col, &eboneptr, "head_radius", 0, IFACE_("Radius"), ICON_NONE);
1087 uiItemR(col, &eboneptr, "tail", 0, NULL, ICON_NONE);
1088 uiItemR(col, &eboneptr, "tail_radius", 0, IFACE_("Radius"), ICON_NONE);
1090 uiItemR(col, &eboneptr, "roll", 0, NULL, ICON_NONE);
1091 uiItemR(col, &eboneptr, "envelope_distance", 0, IFACE_("Envelope"), ICON_NONE);
1094 static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
1096 PointerRNA mbptr, ptr;
1097 MetaBall *mball = ob->data;
1100 if (!mball || !(mball->lastelem))
1103 RNA_pointer_create(&mball->id, &RNA_MetaBall, mball, &mbptr);
1105 RNA_pointer_create(&mball->id, &RNA_MetaElement, mball->lastelem, &ptr);
1107 col = uiLayoutColumn(layout, false);
1108 uiItemR(col, &ptr, "co", 0, NULL, ICON_NONE);
1110 uiItemR(col, &ptr, "radius", 0, NULL, ICON_NONE);
1111 uiItemR(col, &ptr, "stiffness", 0, NULL, ICON_NONE);
1113 uiItemR(col, &ptr, "type", 0, NULL, ICON_NONE);
1115 col = uiLayoutColumn(layout, true);
1116 switch (RNA_enum_get(&ptr, "type")) {
1120 uiItemL(col, IFACE_("Size:"), ICON_NONE);
1121 uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1122 uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1123 uiItemR(col, &ptr, "size_z", 0, "Z", ICON_NONE);
1126 uiItemL(col, IFACE_("Size:"), ICON_NONE);
1127 uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1130 uiItemL(col, IFACE_("Size:"), ICON_NONE);
1131 uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1132 uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1135 uiItemL(col, IFACE_("Size:"), ICON_NONE);
1136 uiItemR(col, &ptr, "size_x", 0, "X", ICON_NONE);
1137 uiItemR(col, &ptr, "size_y", 0, "Y", ICON_NONE);
1138 uiItemR(col, &ptr, "size_z", 0, "Z", ICON_NONE);
1143 static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event)
1145 ViewLayer *view_layer = CTX_data_view_layer(C);
1146 View3D *v3d = CTX_wm_view3d(C);
1147 Object *ob = OBACT(view_layer);
1152 ED_area_tag_redraw(CTX_wm_area(C));
1153 return; /* no notifier! */
1155 case B_OBJECTPANELMEDIAN:
1157 v3d_editvertex_buts(NULL, v3d, ob, 1.0);
1158 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
1161 case B_OBJECTPANEL_DIMS:
1163 v3d_object_dimension_buts(C, NULL, v3d, ob);
1168 /* default for now */
1169 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
1172 static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
1174 ViewLayer *view_layer = CTX_data_view_layer(C);
1175 return (view_layer->basact != NULL);
1178 static void view3d_panel_transform(const bContext *C, Panel *pa)
1181 Scene *scene = CTX_data_scene(C);
1182 ViewLayer *view_layer = CTX_data_view_layer(C);
1183 Object *obedit = CTX_data_edit_object(C);
1184 Object *ob = view_layer->basact->object;
1187 block = uiLayoutGetBlock(pa->layout);
1188 UI_block_func_handle_set(block, do_view3d_region_buttons, NULL);
1190 col = uiLayoutColumn(pa->layout, false);
1193 if (ob->type == OB_ARMATURE) {
1194 v3d_editarmature_buts(col, ob);
1196 else if (ob->type == OB_MBALL) {
1197 v3d_editmetaball_buts(col, ob);
1200 View3D *v3d = CTX_wm_view3d(C);
1201 const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
1202 v3d_editvertex_buts(col, v3d, ob, lim);
1205 else if (ob->mode & OB_MODE_POSE) {
1206 v3d_posearmature_buts(col, ob);
1211 RNA_id_pointer_create(&ob->id, &obptr);
1212 v3d_transform_butsR(col, &obptr);
1214 /* dimensions and editmode just happen to be the same checks */
1215 if (OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
1216 View3D *v3d = CTX_wm_view3d(C);
1217 v3d_object_dimension_buts(NULL, col, v3d, ob);
1222 static void hide_collections_menu_draw(const bContext *C, Menu *menu)
1224 ED_collection_hide_menu_draw(C, menu->layout);
1227 void view3d_buttons_register(ARegionType *art)
1231 pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object");
1232 strcpy(pt->idname, "VIEW3D_PT_transform");
1233 strcpy(pt->label, N_("Transform")); /* XXX C panels not available through RNA (bpy.types)! */
1234 strcpy(pt->category, "View");
1235 strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1236 pt->draw = view3d_panel_transform;
1237 pt->poll = view3d_panel_transform_poll;
1238 BLI_addtail(&art->paneltypes, pt);
1240 pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
1241 strcpy(pt->idname, "VIEW3D_PT_vgroup");
1242 strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels are not available through RNA (bpy.types)! */
1243 strcpy(pt->category, "View");
1244 strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1245 pt->draw = view3d_panel_vgroup;
1246 pt->poll = view3d_panel_vgroup_poll;
1247 BLI_addtail(&art->paneltypes, pt);
1251 mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections");
1252 strcpy(mt->idname, "VIEW3D_MT_collection");
1253 strcpy(mt->label, N_("Collection"));
1254 strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
1255 mt->draw = hide_collections_menu_draw;
1256 WM_menutype_add(mt);
1259 static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1261 ScrArea *sa = CTX_wm_area(C);
1262 ARegion *ar = view3d_has_buttons_region(sa);
1265 ED_region_toggle_hidden(C, ar);
1267 return OPERATOR_FINISHED;
1270 void VIEW3D_OT_properties(wmOperatorType *ot)
1272 ot->name = "Toggle Sidebar";
1273 ot->description = "Toggle the properties region visibility";
1274 ot->idname = "VIEW3D_OT_properties";
1276 ot->exec = view3d_properties_toggle_exec;
1277 ot->poll = ED_operator_view3d_active;
1283 static int view3d_object_mode_menu(bContext *C, wmOperator *op)
1285 Object *ob = CTX_data_active_object(C);
1287 BKE_report(op->reports, RPT_WARNING, "No active object found");
1288 return OPERATOR_CANCELLED;
1290 else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) {
1291 ED_object_mode_toggle(C, OB_MODE_POSE);
1292 return OPERATOR_CANCELLED;
1295 UI_pie_menu_invoke(C, "VIEW3D_MT_object_mode_pie", CTX_wm_window(C)->eventstate);
1296 return OPERATOR_CANCELLED;
1300 void VIEW3D_OT_object_mode_pie_or_toggle(wmOperatorType *ot)
1302 ot->name = "Object Mode Menu";
1303 ot->idname = "VIEW3D_OT_object_mode_pie_or_toggle";
1305 ot->exec = view3d_object_mode_menu;
1306 ot->poll = ED_operator_view3d_active;