diff --git a/scripts/startup/bl_ui/properties_data_camera.py b/scripts/startup/bl_ui/properties_data_camera.py index 240e613fed9..a826609adf7 100644 --- a/scripts/startup/bl_ui/properties_data_camera.py +++ b/scripts/startup/bl_ui/properties_data_camera.py @@ -253,9 +253,15 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel): col.prop(dof, "focus_object", text="Focus on Object") if dof.focus_object and dof.focus_object.type == 'ARMATURE': col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone") + sub = col.column() sub.active = (dof.focus_object is None) - sub.prop(dof, "focus_distance", text="Focus Distance") + row = sub.row(align=True) + row.prop(dof, "focus_distance", text="Focus Distance") + row.operator( + "ui.eyedropper_depth", + icon='EYEDROPPER', + text="").prop_data_path = "scene.camera.data.dof.focus_distance" class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel): diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_depth.cc b/source/blender/editors/interface/eyedroppers/eyedropper_depth.cc index c8f9cefc1d1..29990db48a3 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_depth.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.cc @@ -24,10 +24,13 @@ #include "BKE_context.hh" #include "BKE_lib_id.hh" +#include "BKE_report.hh" #include "BKE_screen.hh" #include "BKE_unit.hh" #include "RNA_access.hh" +#include "RNA_define.hh" +#include "RNA_path.hh" #include "RNA_prototypes.h" #include "UI_interface.hh" @@ -69,37 +72,119 @@ static void depthdropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, v eyedropper_draw_cursor_text_region(ddr->name_pos, ddr->name); } -static int depthdropper_init(bContext *C, wmOperator *op) +static bool depthdropper_get_path(PointerRNA *ctx_ptr, + wmOperator *op, + const char *prop_path, + PointerRNA *r_ptr, + PropertyRNA **r_prop) { + PropertyRNA *unused_prop; + + if (prop_path[0] == '\0') { + return false; + } + + if (!r_prop) { + r_prop = &unused_prop; + } + + /* Get rna from path. */ + if (!RNA_path_resolve(ctx_ptr, prop_path, r_ptr, r_prop)) { + BKE_reportf(op->reports, RPT_ERROR, "Could not resolve path '%s'", prop_path); + return false; + } + + /* Check property type. */ + PropertyType prop_type = RNA_property_type(*r_prop); + if (prop_type != PROP_FLOAT) { + BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", prop_path); + return false; + } + + /* Success. */ + return true; +} + +static bool depthdropper_test(bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop; int index_dummy; + uiBut *but; - SpaceType *st; - ARegionType *art; + /* Check if the custom prop_data_path is set. */ + if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) && + RNA_property_is_set(op->ptr, prop)) + { + return true; + } - st = BKE_spacetype_from_id(SPACE_VIEW3D); - art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); - - DepthDropper *ddr = MEM_cnew(__func__); - - uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); - - /* fallback to the active camera's dof */ - if (ddr->prop == nullptr) { + /* check if there's an active button taking depth value */ + if ((CTX_wm_window(C) != nullptr) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_NUM) && (prop != nullptr)) + { + if ((RNA_property_type(prop) == PROP_FLOAT) && + (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && + (RNA_property_array_check(prop) == false)) + { + return true; + } + } + else { RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d && rv3d->persp == RV3D_CAMOB) { View3D *v3d = CTX_wm_view3d(C); if (v3d->camera && v3d->camera->data && BKE_id_is_editable(CTX_data_main(C), static_cast(v3d->camera->data))) { - Camera *camera = (Camera *)v3d->camera->data; - ddr->ptr = RNA_pointer_create(&camera->id, &RNA_CameraDOFSettings, &camera->dof); - ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance"); - ddr->is_undo = true; + return true; } } } + + return false; +} + +static int depthdropper_init(bContext *C, wmOperator *op) +{ + DepthDropper *ddr = MEM_cnew(__func__); + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) && + RNA_property_is_set(op->ptr, prop)) + { + char *prop_data_path = RNA_string_get_alloc(op->ptr, "prop_data_path", nullptr, 0, nullptr); + BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(prop_data_path); }); + if (!prop_data_path) { + return false; + } + PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C); + if (!depthdropper_get_path(&ctx_ptr, op, prop_data_path, &ddr->ptr, &ddr->prop)) { + MEM_freeN(ddr); + return false; + } + } else { - ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + /* fallback to the active camera's dof */ + int index_dummy; + uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + if (ddr->prop == nullptr) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && + BKE_id_is_editable(CTX_data_main(C), static_cast(v3d->camera->data))) + { + Camera *camera = (Camera *)v3d->camera->data; + ddr->ptr = RNA_pointer_create(&camera->id, &RNA_CameraDOFSettings, &camera->dof); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance"); + ddr->is_undo = true; + } + } + } + else { + ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + } } if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) || @@ -111,6 +196,9 @@ static int depthdropper_init(bContext *C, wmOperator *op) } op->customdata = ddr; + SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D); + ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + ddr->art = art; ddr->draw_handle_pixel = ED_region_draw_cb_activate( art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); @@ -308,6 +396,10 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Modal Operator init */ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { + if (!depthdropper_test(C, op)) { + /* If the operator can't be executed, make sure to not consume the event. */ + return OPERATOR_PASS_THROUGH; + } /* init */ if (depthdropper_init(C, op)) { wmWindow *win = CTX_wm_window(C); @@ -345,10 +437,13 @@ static bool depthdropper_poll(bContext *C) /* check if there's an active button taking depth value */ if ((CTX_wm_window(C) != nullptr) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_NUM) && (prop != nullptr)) + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy))) { - if ((RNA_property_type(prop) == PROP_FLOAT) && + if (but->icon == ICON_EYEDROPPER) { + return true; + } + if ((but->type == UI_BTYPE_NUM) && (prop != nullptr) && + (RNA_property_type(prop) == PROP_FLOAT) && (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && (RNA_property_array_check(prop) == false)) { @@ -387,5 +482,13 @@ void UI_OT_eyedropper_depth(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL; - /* properties */ + /* Paths relative to the context. */ + PropertyRNA *prop; + prop = RNA_def_string(ot->srna, + "prop_data_path", + nullptr, + 0, + "Data Path", + "Path of property to be set with the depth"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); }