Fix transform gizmo not updating according to state

Whenever a transform operation is activated by gizmo, the gizmo
modal is maintained, but its drawing remains the same even if the
transform mode or constrain is changed.

So update the gizmo according to the mode or constrain set.

NOTE: Currently only 3D view gizmo is affected
This commit is contained in:
Germano Cavalcante 2023-01-26 07:54:04 -03:00 committed by Germano Cavalcante
parent af0d378177
commit 19b63b932d
Notes: blender-bot 2023-03-27 15:26:24 +02:00
Referenced by commit 8d9d16fb53, Fix #104396: Blender crashes when moving Keyframes in Graph Editor
Referenced by commit 7beb487e9a, Fix T104353: Crash on opening sculpting template
Referenced by issue #104396, Regression: Crash when moving Keyframes in Graph Editor
Referenced by issue #104353, Regression: Crash on opening sculpting template
Referenced by issue #106141, Regression: Node duplication via menu results in a crash
Referenced by pull request #106174, Fix #106141: crash when duplicating a node
Referenced by commit 1bd4a3c9f3, Fix #106141: crash when duplicating a node
7 changed files with 582 additions and 269 deletions

View File

@ -862,6 +862,9 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
else {
setUserConstraint(t, constraint_new, msg_3d);
}
/* Take the opportunity to update the gizmo. */
transform_gizmo_3d_model_from_constraint_and_mode_set(t);
}
t->redraw |= TREDRAW_HARD;
return true;
@ -2057,6 +2060,8 @@ int transformEnd(bContext *C, TransInfo *t)
viewRedrawPost(C, t);
viewRedrawForce(C, t);
transform_gizmo_3d_model_from_constraint_and_mode_restore(t);
}
t->context = NULL;

View File

@ -138,6 +138,9 @@ typedef enum {
/** No cursor wrapping on region bounds */
T_NO_CURSOR_WRAP = 1 << 23,
/** Do not display Xform gizmo even though it is available. */
T_NO_GIZMO = 1 << 24,
} eTFlag;
ENUM_OPERATORS(eTFlag, T_NO_CURSOR_WRAP);
@ -734,6 +737,27 @@ void transform_final_value_get(const TransInfo *t, float *value, int value_num);
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
/**
* Set the #T_NO_GIZMO flag.
*
* \note This maintains the conventional behavior of not displaying the gizmo if the operator has
* been triggered by shortcuts.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t);
/**
* Change the gizmo and its orientation to match the transform state.
*
* \note This used while the modal operator is running so changes to the constraint or mode show
* the gizmo associated with that state, as if it had been the initial gizmo dragged.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t);
/**
* Restores the non-modal state of the gizmo.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t);
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -640,6 +640,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
setTransformViewMatrices(t);
initNumInput(&t->num);
transform_gizmo_3d_model_from_constraint_and_mode_init(t);
}
static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)

View File

@ -70,9 +70,13 @@
#include "GPU_state.h"
static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
const float twmat[4][4],
const float scale[3]);
static wmGizmoGroupType *g_GGT_xform_gizmo = NULL;
static wmGizmoGroupType *g_GGT_xform_gizmo_context = NULL;
static void gizmogroup_refresh_from_matrix(wmGizmoGroup *gzgroup,
const float twmat[4][4],
const float scale[3],
const bool ignore_hidden);
/* return codes for select, and drawing flags */
@ -1135,30 +1139,36 @@ static void gizmo_prepare_mat(const bContext *C,
* Sets up \a r_start and \a r_len to define arrow line range.
* Needed to adjust line drawing for combined gizmo axis types.
*/
static void gizmo_line_range(const int twtype, const short axis_type, float *r_start, float *r_len)
static void gizmo_line_range(const int twtype, const short axis_type, float *r_start, float *r_end)
{
const float ofs = 0.2f;
*r_start = 0.2f;
*r_len = 1.0f;
float start = 0.2f;
float end = 1.0f;
switch (axis_type) {
case MAN_AXES_TRANSLATE:
if (twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) {
*r_start = *r_len - ofs + 0.075f;
start = end - 0.125f;
}
if (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
*r_len += ofs;
/* Avoid rotate and translate gizmos overlap. */
const float rotate_offset = 0.215f;
start += rotate_offset;
end += rotate_offset + 0.2f;
}
break;
case MAN_AXES_SCALE:
if (twtype & (V3D_GIZMO_SHOW_OBJECT_TRANSLATE | V3D_GIZMO_SHOW_OBJECT_ROTATE)) {
*r_len -= ofs + 0.025f;
end -= 0.225f;
}
break;
}
*r_len -= *r_start;
if (r_start) {
*r_start = start;
}
if (r_end) {
*r_end = end;
}
}
static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
@ -1280,9 +1290,9 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
float axis[3],
float center_global[3],
float mval_init[2],
const float axis[3],
const float center_global[3],
const float mval_init[2],
float r_mat_basis[4][4])
{
copy_v3_v3(r_mat_basis[2], axis);
@ -1329,6 +1339,169 @@ static void rotation_set_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
ggd->rotation = *(const float *)value;
}
static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
{
switch (axis_idx) {
/* Arrow. */
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL);
break;
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z:
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_STEM);
break;
/* Primitive. */
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_PLANE);
const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
WM_gizmo_set_matrix_offset_location(axis, ofs);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
}
/* Dial. */
case MAN_AXIS_TRANS_C:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_MODAL, true);
WM_gizmo_set_scale(axis, 0.2f);
/* Prevent axis gizmos overlapping the center point, see: T63744. */
axis->select_bias = 2.0f;
break;
case MAN_AXIS_SCALE_C:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
/* Use 1/6 since this is '0.2' if the main scale is 1.2. */
RNA_float_set(axis->ptr, "arc_inner_factor", 1.0 / 6.0);
WM_gizmo_set_scale(axis, 1.2f);
/* Prevent axis gizmos overlapping the center point, see: T63744. */
axis->select_bias = -2.0f;
break;
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
break;
case MAN_AXIS_ROT_C:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_NOP);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
WM_gizmo_set_scale(axis, 1.2f);
break;
case MAN_AXIS_ROT_T:
RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL);
WM_gizmo_set_flag(axis, WM_GIZMO_SELECT_BACKGROUND, true);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_HOVER, true);
break;
}
switch (axis_idx) {
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
/* Increased line width for better display. */
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH + 1.0f);
break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX:
WM_gizmo_set_line_width(axis, 1.0f);
break;
default:
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
break;
}
const short axis_type = gizmo_get_axis_type(axis_idx);
switch (axis_type) {
case MAN_AXES_ROTATE: {
RNA_float_set(axis->ptr, "incremental_angle", 0.0f);
axis->select_bias = 0.0f;
break;
}
default:
break;
}
}
static void gizmo_3d_setup_draw_from_twtype(wmGizmo *axis, const int axis_idx, const int twtype)
{
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
RNA_enum_set(axis->ptr,
"draw_options",
(twtype & (V3D_GIZMO_SHOW_OBJECT_ROTATE | V3D_GIZMO_SHOW_OBJECT_SCALE)) ?
0 :
ED_GIZMO_ARROW_DRAW_FLAG_STEM);
break;
default:
break;
}
const short axis_type = gizmo_get_axis_type(axis_idx);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z: {
float start_co[3] = {0.0f, 0.0f, 0.0f};
float end;
gizmo_line_range(twtype, axis_type, &start_co[2], &end);
WM_gizmo_set_matrix_offset_location(axis, start_co);
RNA_float_set(axis->ptr, "length", end - start_co[2]);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
}
default:
break;
}
switch (axis_type) {
case MAN_AXES_ROTATE: {
if ((twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) && twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
axis->select_bias = -2.0f;
}
}
}
}
static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx)
{
const short axis_type = gizmo_get_axis_type(axis_idx);
switch (axis_type) {
case MAN_AXES_ROTATE: {
PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
const int dial_flag = RNA_property_enum_get(axis->ptr, prop);
RNA_property_enum_set(axis->ptr, prop, dial_flag | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
break;
}
default:
break;
}
}
static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd;
@ -1342,65 +1515,57 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
wmGizmoPropertyFnParams params = {
.value_get_fn = rotation_get_fn, .value_set_fn = rotation_set_fn, .user_data = ggd};
#define GIZMO_NEW_ARROW(v, draw_style) \
#define GIZMO_NEW_ARROW(v) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_style", draw_style); \
} \
((void)0)
#define GIZMO_NEW_DIAL(v, draw_options) \
#define GIZMO_NEW_DIAL(v) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \
WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", &params); \
} \
((void)0)
#define GIZMO_NEW_PRIM(v, draw_style) \
#define GIZMO_NEW_PRIM(v) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_prim, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_style", draw_style); \
} \
((void)0)
/* add/init widgets - order matters! */
GIZMO_NEW_DIAL(MAN_AXIS_ROT_T, ED_GIZMO_DIAL_DRAW_FLAG_FILL);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_T);
GIZMO_NEW_DIAL(MAN_AXIS_SCALE_C, ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
GIZMO_NEW_DIAL(MAN_AXIS_SCALE_C);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_X, ED_GIZMO_ARROW_STYLE_BOX);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_GIZMO_ARROW_STYLE_BOX);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_GIZMO_ARROW_STYLE_BOX);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_X);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Y);
GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Z);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_XY);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_YZ);
GIZMO_NEW_PRIM(MAN_AXIS_SCALE_ZX);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_X, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_Y, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_Z, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_X);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_Y);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_Z);
/* init screen aligned widget last here, looks better, behaves better */
GIZMO_NEW_DIAL(MAN_AXIS_ROT_C, ED_GIZMO_DIAL_DRAW_FLAG_NOP);
GIZMO_NEW_DIAL(MAN_AXIS_ROT_C);
GIZMO_NEW_DIAL(MAN_AXIS_TRANS_C, ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT);
GIZMO_NEW_DIAL(MAN_AXIS_TRANS_C);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_X, ED_GIZMO_ARROW_STYLE_NORMAL);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_GIZMO_ARROW_STYLE_NORMAL);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_GIZMO_ARROW_STYLE_NORMAL);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_X);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Y);
GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Z);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_XY);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_YZ);
GIZMO_NEW_PRIM(MAN_AXIS_TRANS_ZX);
ggd->gizmos[MAN_AXIS_ROT_T]->flag |= WM_GIZMO_SELECT_BACKGROUND;
/* Prevent axis gizmos overlapping the center point, see: T63744. */
ggd->gizmos[MAN_AXIS_TRANS_C]->select_bias = 2.0f;
ggd->gizmos[MAN_AXIS_SCALE_C]->select_bias = -2.0f;
/* Use 1/6 since this is '0.2' if the main scale is 1.2. */
RNA_float_set(ggd->gizmos[MAN_AXIS_SCALE_C]->ptr, "arc_inner_factor", 1.0 / 6.0);
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
gizmo_3d_setup_draw_default(axis, axis_idx);
}
MAN_ITER_AXES_END;
return ggd;
}
@ -1445,39 +1610,6 @@ static int gizmo_modal(bContext *C,
}
}
else {
GizmoGroup *ggd = gzgroup->customdata;
short axis_type = 0;
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
if (axis == widget) {
axis_type = gizmo_get_axis_type(axis_idx);
break;
}
}
MAN_ITER_AXES_END;
/* Showing axes which aren't being manipulated doesn't always work so well.
*
* For rotate: global axis will reset after finish.
* Also, gimbal axis isn't properly recalculated while transforming.
*/
if (axis_type == MAN_AXES_ROTATE) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
if (axis == widget) {
continue;
}
bool is_plane_dummy;
const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane_dummy);
/* Always show the axis-aligned handle as it's distracting when it's disabled. */
if (aidx_norm == 3) {
continue;
}
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
}
MAN_ITER_AXES_END;
}
wmWindow *win = CTX_wm_window(C);
wmOperator *op = NULL;
for (int i = 0; i < widget->op_data_len; i++) {
@ -1489,6 +1621,10 @@ static int gizmo_modal(bContext *C,
}
if (op != NULL) {
GizmoGroup *ggd = gzgroup->customdata;
const int axis_idx = BLI_array_findindex(ggd->gizmos, ARRAY_SIZE(ggd->gizmos), &widget);
const short axis_type = gizmo_get_axis_type(axis_idx);
float twmat[4][4];
float scale_buf[3];
float *scale = NULL;
@ -1513,7 +1649,7 @@ static int gizmo_modal(bContext *C,
}
if (update) {
gizmo_refresh_from_matrix(gzgroup, twmat, scale);
gizmogroup_refresh_from_matrix(gzgroup, twmat, scale, true);
ED_region_tag_redraw_editor_overlays(region);
}
}
@ -1539,62 +1675,7 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
/* custom handler! */
WM_gizmo_set_fn_custom_modal(axis, gizmo_modal);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z:
if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
int draw_options = 0;
if ((ggd->twtype & (V3D_GIZMO_SHOW_OBJECT_ROTATE | V3D_GIZMO_SHOW_OBJECT_SCALE)) == 0) {
draw_options |= ED_GIZMO_ARROW_DRAW_FLAG_STEM;
}
RNA_enum_set(axis->ptr, "draw_options", draw_options);
}
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
break;
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
/* increased line width for better display */
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH + 1.0f);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
WM_gizmo_set_matrix_offset_location(axis, ofs);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
}
case MAN_AXIS_TRANS_C:
case MAN_AXIS_ROT_C:
case MAN_AXIS_SCALE_C:
case MAN_AXIS_ROT_T:
WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
if (axis_idx == MAN_AXIS_ROT_T) {
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_HOVER, true);
}
else if (axis_idx == MAN_AXIS_ROT_C) {
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
WM_gizmo_set_scale(axis, 1.2f);
}
else if (axis_idx == MAN_AXIS_SCALE_C) {
WM_gizmo_set_scale(axis, 1.2f);
}
else {
WM_gizmo_set_scale(axis, 0.2f);
}
break;
}
gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
switch (axis_type) {
case MAN_AXES_TRANSLATE:
@ -1688,111 +1769,87 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
* \param twmat: The transform matrix (typically #RegionView3D.twmat).
* \param scale: Optional scale, to show scale while modally dragging the scale handles.
*/
static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
static void gizmo_refresh_from_matrix(wmGizmo *axis,
const int axis_idx,
const int twtype,
const float twmat[4][4],
const float scale[3])
{
const short axis_type = gizmo_get_axis_type(axis_idx);
const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
WM_gizmo_set_matrix_location(axis, twmat[3]);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z: {
const float *z_axis = twmat[aidx_norm];
if (axis_type == MAN_AXES_SCALE) {
/* Scale handles are cubes that don't look right when not aligned with other axes.
* This is noticeable when the axis is rotated to something besides the global-axis. */
const int aidx_norm_y = (aidx_norm + 2) % 3;
const float *y_axis = twmat[aidx_norm_y];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
if (scale) {
float start, end;
gizmo_line_range(twtype, axis_type, &start, &end);
RNA_float_set(axis->ptr, "length", (end * scale[aidx_norm]) - start);
}
}
else {
WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
}
break;
}
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
const int aidx_norm_x = (aidx_norm + 1) % 3;
const int aidx_norm_y = (aidx_norm + 2) % 3;
const float *y_axis = twmat[aidx_norm_y];
const float *z_axis = twmat[aidx_norm];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
if (axis_type == MAN_AXES_SCALE) {
float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
if (scale) {
ofs[0] *= scale[aidx_norm_x];
ofs[1] *= scale[aidx_norm_y];
}
WM_gizmo_set_matrix_offset_location(axis, ofs);
}
break;
}
}
}
static void gizmogroup_refresh_from_matrix(wmGizmoGroup *gzgroup,
const float twmat[4][4],
const float scale[3],
const bool ignore_hidden)
{
GizmoGroup *ggd = gzgroup->customdata;
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
WM_gizmo_set_matrix_location(axis, twmat[3]);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z: {
float start_co[3] = {0.0f, 0.0f, 0.0f};
float len;
gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len);
const float *z_axis = twmat[aidx_norm];
if (axis_type == MAN_AXES_SCALE) {
/* Scale handles are cubes that don't look right when not aligned with other axes.
* This is noticeable when the axis is rotated to something besides the global-axis. */
const int aidx_norm_y = (aidx_norm + 2) % 3;
const float *y_axis = twmat[aidx_norm_y];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
}
else {
WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
}
if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
if (ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
/* Avoid rotate and translate arrows overlap. */
start_co[2] += 0.215f;
}
}
if (scale) {
if (axis_type == MAN_AXES_SCALE) {
len = ((start_co[2] + len) * scale[aidx_norm]) - start_co[2];
}
}
RNA_float_set(axis->ptr, "length", len);
WM_gizmo_set_matrix_offset_location(axis, start_co);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
}
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
case MAN_AXIS_ROT_C: {
if (axis_idx != MAN_AXIS_ROT_C) {
WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
}
/* Remove #ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE. It is used only for modal drawing. */
PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
RNA_property_enum_set(axis->ptr,
prop,
RNA_property_enum_get(axis->ptr, prop) &
~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
} break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
const int aidx_norm_x = (aidx_norm + 1) % 3;
const int aidx_norm_y = (aidx_norm + 2) % 3;
const float *y_axis = twmat[aidx_norm_y];
const float *z_axis = twmat[aidx_norm];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
if (axis_type == MAN_AXES_SCALE) {
float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
if (scale) {
ofs[0] *= scale[aidx_norm_x];
ofs[1] *= scale[aidx_norm_y];
}
WM_gizmo_set_matrix_offset_location(axis, ofs);
}
break;
}
if (ignore_hidden && axis->flag & WM_GIZMO_HIDDEN) {
continue;
}
gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, twmat, scale);
}
MAN_ITER_AXES_END;
/* Ensure rotate disks don't overlap scale arrows, especially in ortho view. */
float rotate_select_bias = 0.0f;
if ((ggd->twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) && ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
rotate_select_bias = -2.0f;
}
for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) {
ggd->gizmos[i]->select_bias = rotate_select_bias;
}
}
static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
@ -1835,7 +1892,7 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
gizmo_prepare_mat(C, rv3d, &tbounds);
gizmo_refresh_from_matrix(gzgroup, rv3d->twmat, NULL);
gizmogroup_refresh_from_matrix(gzgroup, rv3d->twmat, NULL, false);
}
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
@ -1850,6 +1907,14 @@ static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo);
}
static void gizmogroup_hide_all(GizmoGroup *ggd)
{
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
}
MAN_ITER_AXES_END;
}
static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
@ -1873,38 +1938,32 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
/* when looking through a selected camera, the gizmo can be at the
* exact same position as the view, skip so we don't break selection */
if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
if (!is_modal) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
}
if (!is_modal) {
gizmogroup_hide_all(ggd);
}
MAN_ITER_AXES_END;
return;
}
gizmo_get_idot(rv3d, idot);
/* *** set properties for axes *** */
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
/* XXX maybe unset _HIDDEN flag on redraw? */
if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
if (!is_modal) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
if (is_modal) {
if (axis->flag & WM_GIZMO_HIDDEN) {
continue;
}
}
else {
if (!is_modal) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
const short axis_type = gizmo_get_axis_type(axis_idx);
if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
/* XXX maybe unset _HIDDEN flag on redraw? */
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
}
else {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
continue;
}
continue;
}
float color[4], color_hi[4];
gizmo_get_axis_color(axis_idx, idot, color, color_hi);
WM_gizmo_set_color(axis, color);
WM_gizmo_set_color_highlight(axis, color_hi);
if (!is_modal) {
/* Align to view. */
switch (axis_idx) {
case MAN_AXIS_TRANS_C:
case MAN_AXIS_ROT_C:
@ -1914,6 +1973,11 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
break;
}
}
float color[4], color_hi[4];
gizmo_get_axis_color(axis_idx, idot, color, color_hi);
WM_gizmo_set_color(axis, color);
WM_gizmo_set_color_highlight(axis, color_hi);
}
MAN_ITER_AXES_END;
@ -1934,13 +1998,59 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
}
}
static void gizmo_3d_draw_invoke(wmGizmoGroup *gzgroup,
const ARegion *region,
const int axis_idx_active,
const float mval[2])
{
GizmoGroup *ggd = gzgroup->customdata;
const RegionView3D *rv3d = region->regiondata;
struct wmGizmo *axis_active = ggd->gizmos[axis_idx_active];
const short axis_active_type = gizmo_get_axis_type(axis_idx_active);
if (axis_active_type == MAN_AXES_ROTATE) {
/* Hide other gizmos except the active one and #MAN_AXIS_ROT_C.
* #MAN_AXIS_ROT_C was displayed before and remains visible by convention. */
gizmogroup_hide_all(ggd);
WM_gizmo_set_flag(axis_active, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(ggd->gizmos[MAN_AXIS_ROT_C], WM_GIZMO_HIDDEN, false);
}
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
if (axis->flag & WM_GIZMO_HIDDEN) {
continue;
}
gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, rv3d->twmat, NULL);
if (ELEM(axis_idx, MAN_AXIS_TRANS_C, MAN_AXIS_SCALE_C, MAN_AXIS_ROT_C, MAN_AXIS_ROT_T)) {
WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
}
if (axis == axis_active) {
if (axis_active_type == MAN_AXES_ROTATE) {
gizmo_3d_dial_matrixbasis_calc(region,
axis_active->matrix_basis[2],
axis_active->matrix_basis[3],
mval,
axis_active->matrix_basis);
}
gizmo_3d_setup_draw_modal(axis_active, axis_idx);
}
}
MAN_ITER_AXES_END;
}
static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
wmGizmoGroup *gzgroup,
wmGizmo *gz,
const wmEvent *event)
{
GizmoGroup *ggd = gzgroup->customdata;
const int axis_idx = BLI_array_findindex(ggd->gizmos, ARRAY_SIZE(ggd->gizmos), &gz);
gizmo_3d_draw_invoke(gzgroup, CTX_wm_region(C), axis_idx, (float[2]){UNPACK2(event->mval)});
/* Support gizmo specific orientation. */
if (gz != ggd->gizmos[MAN_AXIS_ROT_T]) {
@ -1964,7 +2074,6 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
/* Support shift click to constrain axis. */
const int axis_idx = BLI_array_findindex(ggd->gizmos, ARRAY_SIZE(ggd->gizmos), &gz);
int axis = -1;
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
@ -2000,17 +2109,6 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
}
}
else if (ELEM(axis_idx, MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C)) {
gizmo_3d_dial_matrixbasis_calc(CTX_wm_region(C),
gz->matrix_basis[2],
gz->matrix_basis[3],
(float[2]){UNPACK2(event->mval)},
gz->matrix_basis);
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "draw_options");
RNA_property_enum_set(
gz->ptr, prop, RNA_property_enum_get(gz->ptr, prop) | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
RNA_float_set(gz->ptr, "incremental_angle", 0.0f);
}
}
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
@ -2103,6 +2201,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
V3D_GIZMO_SHOW_OBJECT_TRANSLATE,
"Drag Action",
"");
g_GGT_xform_gizmo = gzgt;
}
void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
@ -2120,6 +2220,8 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_gizmo_draw_prepare;
gzgt->invoke_prepare = WIDGETGROUP_gizmo_invoke_prepare;
g_GGT_xform_gizmo_context = gzgt;
}
/** \} */
@ -2558,3 +2660,151 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
}
/** \} */
static wmGizmoGroup *gizmogroup_xform_find(TransInfo *t)
{
wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->gizmo_map);
if (gizmo_modal_current) {
wmGizmoGroup *gzgroup = gizmo_modal_current->parent_gzgroup;
/* Check #wmGizmoGroup::customdata to make sure the GizmoGroup has been initialized. */
if (gzgroup->customdata && ELEM(gzgroup->type, g_GGT_xform_gizmo, g_GGT_xform_gizmo_context)) {
return gzgroup;
}
}
else {
/* See #WM_gizmomap_group_find_ptr. */
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(t->region->gizmo_map)) {
if (ELEM(gzgroup->type, g_GGT_xform_gizmo, g_GGT_xform_gizmo_context)) {
/* Choose the one that has been initialized. */
if (gzgroup->customdata) {
return gzgroup;
}
}
}
}
return NULL;
}
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t)
{
wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->gizmo_map);
if (!gizmo_modal_current || !ELEM(gizmo_modal_current->parent_gzgroup->type,
g_GGT_xform_gizmo,
g_GGT_xform_gizmo_context)) {
t->flag |= T_NO_GIZMO;
}
}
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t)
{
if (t->flag & T_NO_GIZMO) {
return;
}
wmGizmoGroup *gzgroup_xform = gizmogroup_xform_find(t);
if (gzgroup_xform == NULL) {
return;
}
int axis_idx = -1;
if (t->mode == TFM_TRACKBALL) {
axis_idx = MAN_AXIS_ROT_T;
}
else if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
const int axis_map[3][7] = {
{MAN_AXIS_TRANS_X,
MAN_AXIS_TRANS_Y,
MAN_AXIS_TRANS_XY,
MAN_AXIS_TRANS_Z,
MAN_AXIS_TRANS_ZX,
MAN_AXIS_TRANS_YZ,
MAN_AXIS_TRANS_C},
{MAN_AXIS_ROT_X,
MAN_AXIS_ROT_Y,
MAN_AXIS_ROT_Z,
MAN_AXIS_ROT_Z,
MAN_AXIS_ROT_Y,
MAN_AXIS_ROT_X,
MAN_AXIS_ROT_C},
{MAN_AXIS_SCALE_X,
MAN_AXIS_SCALE_Y,
MAN_AXIS_SCALE_XY,
MAN_AXIS_SCALE_Z,
MAN_AXIS_SCALE_ZX,
MAN_AXIS_SCALE_YZ,
MAN_AXIS_SCALE_C},
};
BLI_STATIC_ASSERT(
/* Assert mode values. */
((TFM_ROTATION == TFM_TRANSLATION + 1) && (TFM_RESIZE == TFM_TRANSLATION + 2) &&
/* Assert constrain values. */
(CON_AXIS0 == (1 << 1)) && (CON_AXIS1 == (1 << 2)) && (CON_AXIS2 == (1 << 3))),
"");
const int trans_mode = t->mode - TFM_TRANSLATION;
int con_mode = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) >> 1) - 1;
if (t->con.mode & CON_APPLY) {
con_mode = ((t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) >> 1) - 1;
}
axis_idx = axis_map[trans_mode][con_mode];
}
wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->gizmo_map);
if (axis_idx != -1) {
RegionView3D *rv3d = t->region->regiondata;
bool update_orientation = !(equals_v3v3(rv3d->twmat[0], t->spacemtx[0]) &&
equals_v3v3(rv3d->twmat[1], t->spacemtx[1]) &&
equals_v3v3(rv3d->twmat[2], t->spacemtx[2]));
GizmoGroup *ggd = gzgroup_xform->customdata;
wmGizmo *gizmo_expected = ggd->gizmos[axis_idx];
if (update_orientation || gizmo_modal_current != gizmo_expected) {
if (update_orientation) {
copy_m4_m3(rv3d->twmat, t->spacemtx);
copy_v3_v3(rv3d->twmat[3], t->center_global);
}
wmEvent event = {NULL};
/* Set the initial mouse value. Used for rotation gizmos. */
copy_v2_v2_int(event.mval, t->mouse.imval);
/* We need to update the position of the gizmo before invoking otherwise
* #wmGizmo::scale_final could be calculated wrong. */
gizmo_refresh_from_matrix(gizmo_expected, axis_idx, ggd->twtype, rv3d->twmat, NULL);
BLI_assert_msg(!gizmo_modal_current || gizmo_modal_current->highlight_part == 0,
"Avoid changing the highlight part");
gizmo_expected->highlight_part = 0;
WM_gizmo_modal_set_while_modal(t->region->gizmo_map, t->context, gizmo_expected, &event);
WM_gizmo_highlight_set(t->region->gizmo_map, gizmo_expected);
}
}
else if (gizmo_modal_current) {
WM_gizmo_modal_set_while_modal(t->region->gizmo_map, t->context, NULL, NULL);
}
}
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t)
{
if (t->flag & T_NO_GIZMO) {
return;
}
wmGizmoGroup *gzgroup_xform = gizmogroup_xform_find(t);
if (gzgroup_xform == NULL) {
return;
}
GizmoGroup *ggd = gzgroup_xform->customdata;
/* #wmGizmoGroup::draw_prepare will handle the rest. */
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
gizmo_3d_setup_draw_default(axis, axis_idx);
gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
}
MAN_ITER_AXES_END;
}

View File

@ -1215,6 +1215,8 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
transform_convert_mesh_customdatacorrect_init(t);
}
transform_gizmo_3d_model_from_constraint_and_mode_set(t);
/* TODO(@germano): Some of these operations change the `t->mode`.
* This can be bad for Redo. */
// BLI_assert(t->mode == mode);

View File

@ -87,6 +87,16 @@ void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
int part_index,
const struct wmEvent *event);
/**
* Replaces the current gizmo modal.
* The substitute gizmo start out interactive.
* It is similar to #WM_gizmo_modal_set_from_setup but without operator initialization.
*/
void WM_gizmo_modal_set_while_modal(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
const struct wmEvent *event);
struct wmGizmoOpElem *WM_gizmo_operator_get(struct wmGizmo *gz, int part_index);
struct PointerRNA *WM_gizmo_operator_set(struct wmGizmo *gz,
int part_index,

View File

@ -430,6 +430,26 @@ void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
}
}
void WM_gizmo_modal_set_while_modal(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
const wmEvent *event)
{
if (gzmap->gzmap_context.modal) {
wm_gizmomap_modal_set(gzmap, C, gzmap->gzmap_context.modal, event, false);
}
if (gz) {
wm_gizmo_calculate_scale(gz, C);
/* Set `highlight_part` to -1 to skip operator invocation. */
const int highlight_part = gz->highlight_part;
gz->highlight_part = -1;
wm_gizmomap_modal_set(gzmap, C, gz, event, true);
gz->highlight_part = highlight_part;
}
}
void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
{
const RegionView3D *rv3d = CTX_wm_region_view3d(C);