UI: Add eyedropper button to camera focus distance

Blender already had the ability to sample the depth with an eyedropper
and fill the focus distance (see `"ui.eyedropper_depth"`). But this feature
was fairly hidden. You had to hover over the `focal_distance` property
in the camera data panel and then press `E` (then sample a distance
in the 3D viewport).

This patch adds a `prop_data_path` property to the `ui.eyedropper_depth`
operator to allow specifying the property that should be filled with the
depth value.

The idea for this is taken from `wm.radial_control`, which also uses this
approach to write to a property. This allows us to add the eyedropper
as a button.

Pull Request: https://projects.blender.org/blender/blender/pulls/121486
This commit is contained in:
Falk David 2024-05-13 11:01:57 +02:00 committed by Falk David
parent 39150096d8
commit 7f8d4df410
2 changed files with 131 additions and 22 deletions

@ -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):

@ -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<DepthDropper>(__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<const ID *>(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<DepthDropper>(__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<const ID *>(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);
}