Gizmo: add undo and name #104888

Open
Weizhen Huang wants to merge 5 commits from weizhen/blender:enable_gizmo_undo into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
11 changed files with 314 additions and 172 deletions

View File

@ -1078,11 +1078,29 @@ static int gizmo_cage2d_modal(bContext *C,
}
}
wmGizmoProperty *gz_prop;
/* Get properties. */
{
wmGizmoProperty *gz_prop;
gz_prop = WM_gizmo_target_property_find(gz, "matrix");
if (gz_prop->type != NULL) {
WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
gz_prop = WM_gizmo_target_property_find(gz, "size");
if (gz_prop->type != NULL) {
float size[2];
if (WM_gizmo_target_property_array_length(gz, gz_prop) == 2) {
WM_gizmo_target_property_float_get_array(gz, gz_prop, size);
gz->matrix_offset[0][0] = size[0];
gz->matrix_offset[1][1] = size[1];
}
else {
gz->matrix_offset[0][0] = gz->matrix_offset[1][1] = WM_gizmo_target_property_float_get(
gz, gz_prop);
}
}
/* Overwrite if other properties exist. */
gz_prop = WM_gizmo_target_property_find(gz, "matrix");
if (gz_prop->type != NULL) {
WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
}
}
if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
@ -1215,8 +1233,27 @@ static int gizmo_cage2d_modal(bContext *C,
mul_m4_m4_post(gz->matrix_offset, matrix_scale);
}
if (gz_prop->type != NULL) {
WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &gz->matrix_offset[0][0]);
/* Set properties. */
{
wmGizmoProperty *gz_prop;
gz_prop = WM_gizmo_target_property_find(gz, "size");
if (gz_prop->type != NULL) {
float size[2];
size[0] = gz->matrix_offset[0][0];
if (WM_gizmo_target_property_array_length(gz, gz_prop) == 2) {
size[1] = gz->matrix_offset[1][1];
WM_gizmo_target_property_float_set_array(C, gz, gz_prop, size);
}
else {
WM_gizmo_target_property_float_set(C, gz, gz_prop, size[0]);
}
}
gz_prop = WM_gizmo_target_property_find(gz, "matrix");
if (gz_prop->type != NULL) {
WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &gz->matrix_offset[0][0]);
}
}
/* tag the region for redraw */
@ -1236,6 +1273,24 @@ static void gizmo_cage2d_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
BLI_assert(0);
}
}
else if (STREQ(gz_prop->type->idname, "size")) {
if (WM_gizmo_target_property_array_length(gz, gz_prop) == 2) {
float size[2];
WM_gizmo_target_property_float_get_array(gz, gz_prop, size);
gz->matrix_offset[0][0] = size[0];
int flag = RNA_enum_get(gz->ptr, "transform");
if (flag & ED_GIZMO_CAGE_XFORM_FLAG_SHAPE_UNIFORM) {
gz->matrix_offset[1][1] = size[0];
}
else {
gz->matrix_offset[1][1] = size[1];
}
}
else {
gz->matrix_offset[0][0] = gz->matrix_offset[1][1] = WM_gizmo_target_property_float_get(
gz, gz_prop);
}
}
else {
BLI_assert(0);
}
@ -1253,7 +1308,15 @@ static void gizmo_cage2d_exit(bContext *C, wmGizmo *gz, const bool cancel)
wmGizmoProperty *gz_prop;
/* reset properties */
/* Reset properties. */
gz_prop = WM_gizmo_target_property_find(gz, "size");
if (gz_prop->type != NULL) {
float size[2];
size[0] = data->orig_matrix_offset[0][0];
size[1] = data->orig_matrix_offset[1][1];
WM_gizmo_target_property_float_set_array(C, gz, gz_prop, size);
}
gz_prop = WM_gizmo_target_property_find(gz, "matrix");
if (gz_prop->type != NULL) {
WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &data->orig_matrix_offset[0][0]);
@ -1320,6 +1383,7 @@ static void GIZMO_GT_cage_2d(wmGizmoType *gzt)
"");
WM_gizmotype_target_property_def(gzt, "matrix", PROP_FLOAT, 16);
WM_gizmotype_target_property_def(gzt, "size", PROP_FLOAT, 2);
}
void ED_gizmotypes_cage_2d(void)

View File

@ -102,6 +102,7 @@ enum {
ED_GIZMO_CAGE_XFORM_FLAG_SCALE = (1 << 2), /* Scales */
ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM = (1 << 3), /* Scales uniformly */
ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED = (1 << 4), /* Negative scale allowed */
ED_GIZMO_CAGE_XFORM_FLAG_SHAPE_UNIFORM = (1 << 5), /* Equal size along all axes */
};
/* draw_style */

View File

@ -996,8 +996,6 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
{
uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
/* TODO(@ideasman42): a way for gizmos to have their own descriptions (low priority). */
/* Operator Actions */
{
const bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part;
@ -1054,6 +1052,13 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
}
}
/* Gizmo description. */
if (gz->name && gz->name[0]) {
uiTooltipField *field = text_field_add(
data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_strdup(TIP_(gz->name));
Review

Usually description is used here, but looks rather lengthy if there is already description for RNA properties, so I use name instead.
image

Usually `description` is used here, but looks rather lengthy if there is already description for RNA properties, so I use `name` instead. ![image](/attachments/f50d0277-867d-4835-b0cf-f619bdf330cc)
}
/* Property Actions */
if (gz->type->target_property_defs_len) {
wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);

View File

@ -45,17 +45,11 @@ typedef struct LightSpotWidgetGroup {
wmGizmo *spot_radius;
} LightSpotWidgetGroup;
static void gizmo_spot_blend_prop_matrix_get(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
void *value_p)
static void gizmo_spot_blend_prop_size_get(wmGizmoProperty *gz_prop, void *value)
{
BLI_assert(gz_prop->type->array_length == 16);
float(*matrix)[4] = value_p;
float *blend = value;
const bContext *C = gz_prop->custom_func.user_data;
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(CTX_data_scene(C), view_layer);
Light *la = BKE_view_layer_active_object_get(view_layer)->data;
Light *la = gz_prop->ptr.data;
float a = cosf(la->spotsize * 0.5f);
float b = la->spotblend;
@ -64,76 +58,33 @@ static void gizmo_spot_blend_prop_matrix_get(const wmGizmo *UNUSED(gz),
/* Tangent. */
float t = sqrtf(1.0f - c * c) / c;
matrix[0][0] = 2.0f * CONE_SCALE * t * a;
matrix[1][1] = 2.0f * CONE_SCALE * t * a;
*blend = 2.0f * CONE_SCALE * t * a;
}
static void gizmo_spot_blend_prop_matrix_set(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
const void *value_p)
static void gizmo_spot_blend_prop_size_set(wmGizmoProperty *gz_prop, void *value)
{
const float(*matrix)[4] = value_p;
BLI_assert(gz_prop->type->array_length == 16);
float *blend = value;
const bContext *C = gz_prop->custom_func.user_data;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(scene, view_layer);
Light *la = BKE_view_layer_active_object_get(view_layer)->data;
Light *la = gz_prop->ptr.data;
float a = cosf(la->spotsize * 0.5f);
float t = matrix[0][0] * 0.5f * INV_CONE_SCALE / a;
float t = *blend * 0.5f * INV_CONE_SCALE / a;
float c = 1.0f / sqrt(t * t + 1.0f);
float spot_blend = safe_divide(clamp_f(c - a, 0.0f, 1.0f - a), 1.0f - a);
PointerRNA light_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &light_ptr);
PropertyRNA *spot_blend_prop = RNA_struct_find_property(&light_ptr, "spot_blend");
RNA_property_float_set(&light_ptr, spot_blend_prop, spot_blend);
RNA_property_update_main(CTX_data_main(C), scene, &light_ptr, spot_blend_prop);
*blend = safe_divide(clamp_f(c - a, 0.0f, 1.0f - a), 1.0f - a);
}
/* Used by spot light and point light. */
static void gizmo_light_radius_prop_matrix_get(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
void *value_p)
static void gizmo_light_radius_prop_size_get(wmGizmoProperty *UNUSED(gz_prop), void *radius)
{
BLI_assert(gz_prop->type->array_length == 16);
float(*matrix)[4] = value_p;
const bContext *C = gz_prop->custom_func.user_data;
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(CTX_data_scene(C), view_layer);
const Light *la = BKE_view_layer_active_object_get(view_layer)->data;
const float diameter = 2.0f * la->radius;
matrix[0][0] = diameter;
matrix[1][1] = diameter;
float *diameter = radius;
*diameter = 2.0f * (*(float *)radius);
}
static void gizmo_light_radius_prop_matrix_set(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
const void *value_p)
static void gizmo_light_radius_prop_size_set(wmGizmoProperty *UNUSED(gz_prop), void *diameter)
{
const float(*matrix)[4] = value_p;
BLI_assert(gz_prop->type->array_length == 16);
const bContext *C = gz_prop->custom_func.user_data;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(scene, view_layer);
Light *la = BKE_view_layer_active_object_get(view_layer)->data;
const float radius = 0.5f * len_v3(matrix[0]);
PointerRNA light_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &light_ptr);
PropertyRNA *radius_prop = RNA_struct_find_property(&light_ptr, "shadow_soft_size");
RNA_property_float_set(&light_ptr, radius_prop, radius);
RNA_property_update_main(CTX_data_main(C), scene, &light_ptr, radius_prop);
float *radius = diameter;
*radius = 0.5f * (*(float *)diameter);
}
static bool WIDGETGROUP_light_spot_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
@ -160,7 +111,7 @@ static bool WIDGETGROUP_light_spot_poll(const bContext *C, wmGizmoGroupType *UNU
return false;
}
static void WIDGETGROUP_light_spot_setup(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_light_spot_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
LightSpotWidgetGroup *ls_gzgroup = MEM_mallocN(sizeof(LightSpotWidgetGroup), __func__);
@ -173,6 +124,8 @@ static void WIDGETGROUP_light_spot_setup(const bContext *C, wmGizmoGroup *gzgrou
RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_INVERTED);
ED_gizmo_arrow3d_set_range_fac(gz, 4.0f);
UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, gz->color);
WM_gizmo_enable_undo(gz, "Adjust");
}
/* Spot blend gizmo. */
@ -187,14 +140,7 @@ static void WIDGETGROUP_light_spot_setup(const bContext *C, wmGizmoGroup *gzgrou
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
WM_gizmo_target_property_def_func(gz,
"matrix",
&(const struct wmGizmoPropertyFnParams){
.value_get_fn = gizmo_spot_blend_prop_matrix_get,
.value_set_fn = gizmo_spot_blend_prop_matrix_set,
.range_get_fn = NULL,
.user_data = (void *)C,
});
WM_gizmo_enable_undo(gz, "Adjust");
}
/* Spot radius gizmo. */
@ -209,14 +155,7 @@ static void WIDGETGROUP_light_spot_setup(const bContext *C, wmGizmoGroup *gzgrou
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
WM_gizmo_target_property_def_func(gz,
"matrix",
&(const struct wmGizmoPropertyFnParams){
.value_get_fn = gizmo_light_radius_prop_matrix_get,
.value_set_fn = gizmo_light_radius_prop_matrix_set,
.range_get_fn = NULL,
.user_data = (void *)C,
});
WM_gizmo_enable_undo(gz, "Adjust");
}
}
@ -229,11 +168,13 @@ static void WIDGETGROUP_light_spot_refresh(const bContext *C, wmGizmoGroup *gzgr
Object *ob = BKE_view_layer_active_object_get(view_layer);
Light *la = ob->data;
PointerRNA lamp_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr);
/* Need to set property here for `lamp_ptr`. TODO: would prefer to do this in _init. */
/* Spot angle gizmo. */
{
PointerRNA lamp_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr);
wmGizmo *gz = ls_gzgroup->spot_angle;
float dir[3];
negate_v3_v3(dir, ob->object_to_world[2]);
@ -255,6 +196,30 @@ static void WIDGETGROUP_light_spot_refresh(const bContext *C, wmGizmoGroup *gzgr
negate_v3_v3(dir, ob->object_to_world[2]);
mul_v3_fl(dir, CONE_SCALE * cosf(0.5f * la->spotsize));
add_v3_v3(gz->matrix_basis[3], dir);
WM_gizmo_target_property_def_rna_func(gz,
"size",
&lamp_ptr,
"spot_blend",
-1,
&(const struct wmGizmoPropertyFnParams){
.transform_get_fn = gizmo_spot_blend_prop_size_get,
.transform_set_fn = gizmo_spot_blend_prop_size_set,
});
}
/* Spot radius gizmo. */
{
wmGizmo *gz = ls_gzgroup->spot_radius;
WM_gizmo_target_property_def_rna_func(gz,
"size",
&lamp_ptr,
"shadow_soft_size",
-1,
&(const struct wmGizmoPropertyFnParams){
.transform_get_fn = gizmo_light_radius_prop_size_get,
.transform_set_fn = gizmo_light_radius_prop_size_set,
});
}
}
@ -319,7 +284,7 @@ static bool WIDGETGROUP_light_point_poll(const bContext *C, wmGizmoGroupType *UN
return false;
}
static void WIDGETGROUP_light_point_setup(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_light_point_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
@ -335,14 +300,7 @@ static void WIDGETGROUP_light_point_setup(const bContext *C, wmGizmoGroup *gzgro
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
WM_gizmo_target_property_def_func(gz,
"matrix",
&(const struct wmGizmoPropertyFnParams){
.value_get_fn = gizmo_light_radius_prop_matrix_get,
.value_set_fn = gizmo_light_radius_prop_matrix_set,
.range_get_fn = NULL,
.user_data = (void *)C,
});
WM_gizmo_enable_undo(gz, "Adjust");
}
static void WIDGETGROUP_light_point_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
@ -362,6 +320,29 @@ static void WIDGETGROUP_light_point_draw_prepare(const bContext *C, wmGizmoGroup
WM_gizmo_set_matrix_location(gz, ob->object_to_world[3]);
}
static void WIDGETGROUP_light_point_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
wmGizmoWrapper *wwrapper = gzgroup->customdata;
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(CTX_data_scene(C), view_layer);
Light *la = BKE_view_layer_active_object_get(view_layer)->data;
PointerRNA lamp_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr);
/* Need to set property here for `lamp_ptr`. TODO: would prefer to do this in _init. */
WM_gizmo_target_property_def_rna_func(wwrapper->gizmo,
"size",
&lamp_ptr,
"shadow_soft_size",
-1,
&(const struct wmGizmoPropertyFnParams){
.transform_get_fn = gizmo_light_radius_prop_size_get,
.transform_set_fn = gizmo_light_radius_prop_size_set,
});
}
void VIEW3D_GGT_light_point(wmGizmoGroupType *gzgt)
{
gzgt->name = "Point Light Widgets";
@ -372,6 +353,7 @@ void VIEW3D_GGT_light_point(wmGizmoGroupType *gzgt)
gzgt->poll = WIDGETGROUP_light_point_poll;
gzgt->setup = WIDGETGROUP_light_point_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_light_point_refresh;
gzgt->draw_prepare = WIDGETGROUP_light_point_draw_prepare;
}
@ -381,40 +363,6 @@ void VIEW3D_GGT_light_point(wmGizmoGroupType *gzgt)
/** \name Area Light Gizmos
* \{ */
/* scale callbacks */
static void gizmo_area_light_prop_matrix_get(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
void *value_p)
{
BLI_assert(gz_prop->type->array_length == 16);
float(*matrix)[4] = value_p;
const Light *la = gz_prop->custom_func.user_data;
matrix[0][0] = la->area_size;
matrix[1][1] = ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE) ? la->area_sizey :
la->area_size;
}
static void gizmo_area_light_prop_matrix_set(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
const void *value_p)
{
const float(*matrix)[4] = value_p;
BLI_assert(gz_prop->type->array_length == 16);
Light *la = gz_prop->custom_func.user_data;
if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
la->area_size = len_v3(matrix[0]);
la->area_sizey = len_v3(matrix[1]);
}
else {
la->area_size = len_v3(matrix[0]);
}
DEG_id_tag_update(&la->id, ID_RECALC_COPY_ON_WRITE);
WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, la);
}
static bool WIDGETGROUP_light_area_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
{
View3D *v3d = CTX_wm_view3d(C);
@ -452,6 +400,8 @@ static void WIDGETGROUP_light_area_setup(const bContext *UNUSED(C), wmGizmoGroup
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
WM_gizmo_enable_undo(gz, "Resize");
}
static void WIDGETGROUP_light_area_refresh(const bContext *C, wmGizmoGroup *gzgroup)
@ -469,18 +419,15 @@ static void WIDGETGROUP_light_area_refresh(const bContext *C, wmGizmoGroup *gzgr
int flag = ED_GIZMO_CAGE_XFORM_FLAG_SCALE;
if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) {
flag |= ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM;
flag |= ED_GIZMO_CAGE_XFORM_FLAG_SHAPE_UNIFORM;
}
RNA_enum_set(gz->ptr, "transform", flag);
/* need to set property here for undo. TODO: would prefer to do this in _init. */
WM_gizmo_target_property_def_func(gz,
"matrix",
&(const struct wmGizmoPropertyFnParams){
.value_get_fn = gizmo_area_light_prop_matrix_get,
.value_set_fn = gizmo_area_light_prop_matrix_set,
.range_get_fn = NULL,
.user_data = la,
});
PointerRNA lamp_ptr;
RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr);
/* Need to set property here for `lamp_ptr`. TODO: would prefer to do this in _init. */
WM_gizmo_target_property_def_rna(gz, "size", &lamp_ptr, "size_xy", -1);
}
void VIEW3D_GGT_light_area(wmGizmoGroupType *gzgt)

View File

@ -88,6 +88,20 @@ static void rna_Light_use_nodes_update(bContext *C, PointerRNA *ptr)
rna_Light_update(CTX_data_main(C), CTX_data_scene(C), ptr);
}
static void rna_area_light_size_get(PointerRNA *ptr, float *values)
{
Light *la = (Light *)ptr->data;
values[0] = la->area_size;
values[1] = la->area_sizey;
}
static void rna_area_light_size_set(PointerRNA *ptr, const float *values)
{
Light *la = (Light *)ptr->data;
la->area_size = values[0];
la->area_sizey = values[1];
}
#else
/* Don't define icons here, so they don't show up in the Light UI (properties Editor) - DingTo */
const EnumPropertyItem rna_enum_light_type_items[] = {
@ -452,6 +466,7 @@ static void rna_def_area_light(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape", "Shape of the area Light");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
/* TODO: deprecate `size` and `size_y`, rename `size_xy` to `size`. */
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
@ -470,6 +485,14 @@ static void rna_def_area_light(BlenderRNA *brna)
"Size of the area of the area light in the Y direction for rectangle shapes");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "size_xy", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_float_funcs(prop, "rna_area_light_size_get", "rna_area_light_size_set", NULL);
RNA_def_property_ui_text(prop, "Area Size", "Size of the area light");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "area_spread");
RNA_def_property_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f));

View File

@ -266,9 +266,16 @@ void WM_gizmo_target_property_def_func(struct wmGizmo *gz,
void WM_gizmo_target_property_clear_rna_ptr(struct wmGizmo *gz,
const struct wmGizmoPropertyType *gz_prop_type);
void WM_gizmo_target_property_clear_rna(struct wmGizmo *gz, const char *idname);
void WM_gizmo_target_property_def_rna_func(struct wmGizmo *gz,
const char *idname,
struct PointerRNA *ptr,
const char *propname,
int index,
const wmGizmoPropertyFnParams *params);
bool WM_gizmo_target_property_is_valid_any(struct wmGizmo *gz);
bool WM_gizmo_target_property_is_valid(const struct wmGizmoProperty *gz_prop);
struct wmGizmoProperty *WM_gizmo_target_property_get_unique(struct wmGizmo *gz);
float WM_gizmo_target_property_float_get(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
void WM_gizmo_target_property_float_set(struct bContext *C,
@ -508,6 +515,8 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
void WM_gizmo_enable_undo(struct wmGizmo *gz, const char *name);
/* Wrap Group Type Callbacks. */
bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);

View File

@ -82,6 +82,9 @@ typedef enum eWM_GizmoFlag {
/** Don't use tool-tips for this gizmo (can be distracting). */
WM_GIZMO_NO_TOOLTIP = (1 << 12),
/** Do an undo push after gizmo tweaking is finished.*/
WM_GIZMO_UNDO = (1 << 13),
} eWM_GizmoFlag;
ENUM_OPERATORS(eWM_GizmoFlag, WM_GIZMO_NO_TOOLTIP);
@ -206,6 +209,9 @@ typedef struct wmGizmoOpElem {
struct wmGizmo {
struct wmGizmo *next, *prev;
/** Text for tooltip, undo. */
const char *name;
/** While we don't have a real type, use this to put type-like vars. */
const struct wmGizmoType *type;
@ -298,13 +304,8 @@ typedef struct wmGizmoProperty {
int index;
/* Optional functions for converting to/from RNA. */
struct {
wmGizmoPropertyFnGet value_get_fn;
wmGizmoPropertyFnSet value_set_fn;
wmGizmoPropertyFnRangeGet range_get_fn;
wmGizmoPropertyFnFree free_fn;
void *user_data;
} custom_func;
wmGizmoPropertyFnParams custom_func;
} wmGizmoProperty;
typedef struct wmGizmoPropertyType {

View File

@ -738,4 +738,13 @@ bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapD
return true;
}
void WM_gizmo_enable_undo(wmGizmo *gz, const char *name)
{
/* Operators handle undo themselves. */
BLI_assert(gz->op_data == NULL);
WM_gizmo_set_flag(gz, WM_GIZMO_UNDO, true);
gz->name = name;
}
/** \} */

View File

@ -35,6 +35,8 @@
#include "ED_screen.h"
#include "ED_undo.h"
#include "BLT_translation.h"
/* own includes */
#include "wm_gizmo_intern.h"
#include "wm_gizmo_wmapi.h"
@ -451,8 +453,25 @@ static bool gizmo_tweak_start_and_finish(
static void gizmo_tweak_finish(bContext *C, wmOperator *op, const bool cancel, bool clear_modal)
{
GizmoTweakData *mtweak = op->customdata;
if (mtweak->gz_modal->type->exit) {
mtweak->gz_modal->type->exit(C, mtweak->gz_modal, cancel);
wmGizmo *gz = mtweak->gz_modal;
if (gz->type->exit) {
/* Push undo if needed. */
if ((gz->flag & WM_GIZMO_UNDO) && !cancel) {
const wmGizmoProperty *gz_prop = WM_gizmo_target_property_get_unique(gz);
Review

I find this get_unique concept quite strange, it is here because gizmos are allowed to have multiple properties, and if there are multiple I don't know which one just got edited, and could it be that only one of them has undo.

I find this `get_unique` concept quite strange, it is here because gizmos are allowed to have multiple properties, and if there are multiple I don't know which one just got edited, and could it be that only one of them has undo.
if (!gz_prop || RNA_struct_undo_check(gz_prop->ptr.type)) {
/* Use the name of `wmGizmoGroupType` if we don't know which RNA property this gizmo is
* editting. */
const char *prop_name = gz_prop ? RNA_property_ui_name(gz_prop->prop) :
N_(gz->parent_gzgroup->type->name);
char *undo_str = (gz->name && gz->name[0]) ?
BLI_sprintfN("%s: %s", TIP_(gz->name), prop_name) :
BLI_strdup(prop_name);
ED_undo_push(C, undo_str);
MEM_freeN(undo_str);
}
}
gz->type->exit(C, mtweak->gz_modal, cancel);
}
if (clear_modal) {
/* The gizmo may have been removed. */
@ -606,12 +625,6 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
/* api callbacks */
ot->invoke = gizmo_tweak_invoke;
ot->modal = gizmo_tweak_modal;
/* TODO(@ideasman42): This causes problems tweaking settings for operators,
* need to find a way to support this. */
#if 0
ot->flag = OPTYPE_UNDO;
#endif
}
wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf)

View File

@ -103,12 +103,7 @@ void WM_gizmo_target_property_def_func_ptr(wmGizmo *gz,
BLI_assert(gz->op_data == NULL);
gz_prop->type = gz_prop_type;
gz_prop->custom_func.value_get_fn = params->value_get_fn;
gz_prop->custom_func.value_set_fn = params->value_set_fn;
gz_prop->custom_func.range_get_fn = params->range_get_fn;
gz_prop->custom_func.free_fn = params->free_fn;
gz_prop->custom_func.user_data = params->user_data;
gz_prop->custom_func = *params;
if (gz->type->property_update) {
gz->type->property_update(gz, gz_prop);
@ -123,6 +118,17 @@ void WM_gizmo_target_property_def_func(wmGizmo *gz,
WM_gizmo_target_property_def_func_ptr(gz, gz_prop_type, params);
}
void WM_gizmo_target_property_def_rna_func(wmGizmo *gz,
const char *idname,
PointerRNA *ptr,
const char *propname,
int index,
const wmGizmoPropertyFnParams *params)
{
WM_gizmo_target_property_def_rna(gz, idname, ptr, propname, index);
WM_gizmo_target_property_def_func(gz, idname, params);
}
void WM_gizmo_target_property_clear_rna_ptr(wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type)
{
wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
@ -161,6 +167,28 @@ bool WM_gizmo_target_property_is_valid_any(wmGizmo *gz)
return false;
}
/* Get the `*wmGizmoProperty` with valid `PropertyRNA`. If there is none or multiple, returns
* `NULL`. */
wmGizmoProperty *WM_gizmo_target_property_get_unique(wmGizmo *gz)
{
int count = 0;
wmGizmoProperty *gz_unique_prop;
wmGizmoProperty *gz_prop_array = wm_gizmo_target_property_array(gz);
for (int i = 0; i < gz->type->target_property_defs_len; i++) {
wmGizmoProperty *gz_prop = &gz_prop_array[i];
if (gz_prop->prop != NULL) {
count++;
gz_unique_prop = gz_prop;
}
}
if (count == 1) {
return gz_unique_prop;
}
return NULL;
}
bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
{
return ((gz_prop->prop != NULL) ||
@ -169,23 +197,32 @@ bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
float WM_gizmo_target_property_float_get(const wmGizmo *gz, wmGizmoProperty *gz_prop)
{
float value = 0.0f;
if (gz_prop->custom_func.value_get_fn) {
float value = 0.0f;
BLI_assert(gz_prop->type->array_length == 1);
gz_prop->custom_func.value_get_fn(gz, gz_prop, &value);
return value;
}
if (gz_prop->index == -1) {
return RNA_property_float_get(&gz_prop->ptr, gz_prop->prop);
value = RNA_property_float_get(&gz_prop->ptr, gz_prop->prop);
}
return RNA_property_float_get_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index);
else {
value = RNA_property_float_get_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index);
}
if (gz_prop->custom_func.transform_get_fn) {
gz_prop->custom_func.transform_get_fn(gz_prop, &value);
}
return value;
}
void WM_gizmo_target_property_float_set(bContext *C,
const wmGizmo *gz,
wmGizmoProperty *gz_prop,
const float value)
float value)
{
if (gz_prop->custom_func.value_set_fn) {
BLI_assert(gz_prop->type->array_length == 1);
@ -193,7 +230,11 @@ void WM_gizmo_target_property_float_set(bContext *C,
return;
}
/* reset property */
if (gz_prop->custom_func.transform_set_fn) {
gz_prop->custom_func.transform_set_fn(gz_prop, &value);
}
/* Set property. */
if (gz_prop->index == -1) {
RNA_property_float_set(&gz_prop->ptr, gz_prop->prop, value);
}
@ -212,6 +253,10 @@ void WM_gizmo_target_property_float_get_array(const wmGizmo *gz,
return;
}
RNA_property_float_get_array(&gz_prop->ptr, gz_prop->prop, value);
if (gz_prop->custom_func.transform_get_fn) {
gz_prop->custom_func.transform_get_fn(gz_prop, value);
}
}
void WM_gizmo_target_property_float_set_array(bContext *C,
@ -223,7 +268,21 @@ void WM_gizmo_target_property_float_set_array(bContext *C,
gz_prop->custom_func.value_set_fn(gz, gz_prop, value);
return;
}
RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, value);
if (gz_prop->custom_func.transform_set_fn) {
/* Copy array. */
int length = WM_gizmo_target_property_array_length(gz, gz_prop);
float *transformed = MEM_malloc_arrayN(length, sizeof(float), __func__);
memcpy(transformed, value, sizeof(float) * length);
gz_prop->custom_func.transform_set_fn(gz_prop, transformed);
RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, transformed);
MEM_freeN(transformed);
}
else {
RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, value);
}
RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
}

View File

@ -63,6 +63,15 @@ typedef void (*wmGizmoPropertyFnSet)(const struct wmGizmo *,
struct wmGizmoProperty *,
/* typically 'const float *' */
const void *value);
/* Used for transforming the RNA properties. */
typedef void (*wmGizmoPropertyFnTransformGet)(struct wmGizmoProperty *,
/* typically 'float *' */
void *value);
typedef void (*wmGizmoPropertyFnTransformSet)(struct wmGizmoProperty *,
/* typically 'float *' */
void *value);
typedef void (*wmGizmoPropertyFnRangeGet)(const struct wmGizmo *,
struct wmGizmoProperty *,
/* typically 'float[2]' */
@ -72,6 +81,8 @@ typedef void (*wmGizmoPropertyFnFree)(const struct wmGizmo *, struct wmGizmoProp
typedef struct wmGizmoPropertyFnParams {
wmGizmoPropertyFnGet value_get_fn;
wmGizmoPropertyFnSet value_set_fn;
wmGizmoPropertyFnTransformGet transform_get_fn;
wmGizmoPropertyFnTransformSet transform_set_fn;
Review

I find it a bit confusing that there are two groups of getter/setters. The new transform_set_fn could modify the value, and I don't want to drop the const specifier for value_set_fn. Or could there be better function names?

I find it a bit confusing that there are two groups of getter/setters. The new `transform_set_fn` could modify the value, and I don't want to drop the `const` specifier for `value_set_fn`. Or could there be better function names?
wmGizmoPropertyFnRangeGet range_get_fn;
wmGizmoPropertyFnFree free_fn;
void *user_data;