diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 3cff4c11cad..7f16a5796ba 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -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; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 82ab9039db5..08f560d16e9 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -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); + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 53e346ee86a..d1f210ca772 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -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) diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 28b39786bbc..306502ab3bc 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -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", ¶ms); \ } \ ((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; +} diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 95d2b4d6439..d76dba63262 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -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); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index 663c8a0baed..608b87b0bf6 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -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, diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c index 7853c7096dd..9d212798f39 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c @@ -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);