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:
parent
39150096d8
commit
7f8d4df410
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user