Python API: add bpy.context.property, for property under the mouse cursor
This can be useful for example to add custom operators to the property context menu. Pull Request: https://projects.blender.org/blender/blender/pulls/107280
This commit is contained in:
parent
ea937b304d
commit
6ba0346797
10
doc/python_api/examples/bpy.context.property.py
Normal file
10
doc/python_api/examples/bpy.context.property.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""
|
||||
Get the property associated with a hovered button.
|
||||
Returns a tuple of the datablock, data path to the property, and array index.
|
||||
"""
|
||||
|
||||
# Example inserting keyframe for the hovered property.
|
||||
active_property = bpy.context.property
|
||||
if active_property:
|
||||
datablock, data_path, index = active_property
|
||||
datablock.keyframe_insert(data_path=data_path, index=index, frame=1)
|
@ -1202,6 +1202,7 @@ context_type_map = {
|
||||
"particle_settings": ("ParticleSettings", False),
|
||||
"particle_system": ("ParticleSystem", False),
|
||||
"particle_system_editable": ("ParticleSystem", False),
|
||||
"property": ("(:class:`bpy.types.ID`, :class:`string`, :class:`int`)", False),
|
||||
"pointcloud": ("PointCloud", False),
|
||||
"pose_bone": ("PoseBone", False),
|
||||
"pose_object": ("Object", False),
|
||||
@ -1347,7 +1348,11 @@ def pycontext2sphinx(basepath):
|
||||
raise SystemExit(
|
||||
"Error: context key %r not found in context_type_map; update %s" %
|
||||
(member, __file__)) from None
|
||||
fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type))
|
||||
|
||||
if member_type.isidentifier():
|
||||
member_type = ":class:`bpy.types.%s`" % member_type
|
||||
fw(" :type: %s %s\n\n" % ("sequence of " if is_seq else "", member_type))
|
||||
write_example_ref(" ", fw, "bpy.context." + member)
|
||||
|
||||
# Generate type-map:
|
||||
# for member in sorted(unique_context_strings):
|
||||
|
@ -244,6 +244,7 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C);
|
||||
enum {
|
||||
CTX_DATA_TYPE_POINTER = 0,
|
||||
CTX_DATA_TYPE_COLLECTION,
|
||||
CTX_DATA_TYPE_PROPERTY,
|
||||
};
|
||||
|
||||
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member);
|
||||
@ -261,7 +262,7 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member);
|
||||
ListBase CTX_data_dir_get_ex(const bContext *C, bool use_store, bool use_rna, bool use_all);
|
||||
ListBase CTX_data_dir_get(const bContext *C);
|
||||
int /*eContextResult*/ CTX_data_get(
|
||||
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type);
|
||||
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, PropertyRNA **r_prop, int *r_index, short *r_type);
|
||||
|
||||
void CTX_data_id_pointer_set(bContextDataResult *result, struct ID *id);
|
||||
void CTX_data_pointer_set_ptr(bContextDataResult *result, const PointerRNA *ptr);
|
||||
@ -271,6 +272,14 @@ void CTX_data_id_list_add(bContextDataResult *result, struct ID *id);
|
||||
void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr);
|
||||
void CTX_data_list_add(bContextDataResult *result, struct ID *id, StructRNA *type, void *data);
|
||||
|
||||
/**
|
||||
* Stores a property in a result. Make sure to also call 'CTX_data_type_set(result, CTX_DATA_TYPE_PROPERTY)'.
|
||||
* \param result: The result to store the property in.
|
||||
* \param prop: The property to store.
|
||||
* \param index: The particular index in the property to store.
|
||||
*/
|
||||
void CTX_data_prop_set(bContextDataResult *result, PropertyRNA *prop, int index);
|
||||
|
||||
void CTX_data_dir_set(bContextDataResult *result, const char **dir);
|
||||
|
||||
void CTX_data_type_set(struct bContextDataResult *result, short type);
|
||||
|
@ -247,6 +247,8 @@ void CTX_py_state_pop(bContext *C, bContext_PyState *pystate)
|
||||
struct bContextDataResult {
|
||||
PointerRNA ptr;
|
||||
ListBase list;
|
||||
PropertyRNA *prop;
|
||||
int index;
|
||||
const char **dir;
|
||||
short type; /* 0: normal, 1: seq */
|
||||
};
|
||||
@ -497,7 +499,7 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member)
|
||||
}
|
||||
|
||||
int /*eContextResult*/ CTX_data_get(
|
||||
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type)
|
||||
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, PropertyRNA **r_prop, int *r_index, short *r_type)
|
||||
{
|
||||
bContextDataResult result;
|
||||
eContextResult ret = ctx_data_get((bContext *)C, member, &result);
|
||||
@ -505,6 +507,8 @@ int /*eContextResult*/ CTX_data_get(
|
||||
if (ret == CTX_RESULT_OK) {
|
||||
*r_ptr = result.ptr;
|
||||
*r_lb = result.list;
|
||||
*r_prop = result.prop;
|
||||
*r_index = result.index;
|
||||
*r_type = result.type;
|
||||
}
|
||||
else {
|
||||
@ -675,6 +679,12 @@ int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBa
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CTX_data_prop_set(bContextDataResult *result, PropertyRNA *prop, int index)
|
||||
{
|
||||
result->prop = prop;
|
||||
result->index = index;
|
||||
}
|
||||
|
||||
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
|
||||
{
|
||||
result->dir = dir;
|
||||
|
@ -110,6 +110,7 @@ const char *screen_context_dir[] = {
|
||||
"active_editable_fcurve",
|
||||
"selected_editable_keyframes",
|
||||
"ui_list",
|
||||
"property",
|
||||
"asset_library_ref",
|
||||
NULL,
|
||||
};
|
||||
@ -537,6 +538,27 @@ static eContextResult screen_ctx_active_object(const bContext *C, bContextDataRe
|
||||
|
||||
return CTX_RESULT_OK;
|
||||
}
|
||||
|
||||
static eContextResult screen_ctx_property(const bContext *C, bContextDataResult *result)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
int index;
|
||||
|
||||
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
|
||||
/* UI_context_active_but_prop_get returns an index of 0 if the property is not
|
||||
* an array, but other functions expect -1 for non-arrays. */
|
||||
if (!RNA_property_array_check(prop)) {
|
||||
index = -1;
|
||||
}
|
||||
|
||||
CTX_data_type_set(result, CTX_DATA_TYPE_PROPERTY);
|
||||
CTX_data_pointer_set_ptr(result, &ptr);
|
||||
CTX_data_prop_set(result, prop, index);
|
||||
|
||||
return CTX_RESULT_OK;
|
||||
}
|
||||
|
||||
static eContextResult screen_ctx_object(const bContext *C, bContextDataResult *result)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
@ -1347,6 +1369,7 @@ static void ensure_ed_screen_context_functions(void)
|
||||
register_context_function("selected_editable_keyframes", screen_ctx_selected_editable_keyframes);
|
||||
register_context_function("asset_library_ref", screen_ctx_asset_library);
|
||||
register_context_function("ui_list", screen_ctx_ui_list);
|
||||
register_context_function("property", screen_ctx_property);
|
||||
}
|
||||
|
||||
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
|
||||
|
@ -4378,13 +4378,15 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
|
||||
else {
|
||||
PointerRNA newptr;
|
||||
ListBase newlb;
|
||||
PropertyRNA *newprop;
|
||||
int newindex;
|
||||
short newtype;
|
||||
|
||||
/* An empty string is used to implement #CTX_data_dir_get,
|
||||
* without this check `getattr(context, "")` succeeds. */
|
||||
eContextResult done;
|
||||
if (name[0]) {
|
||||
done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
|
||||
done = CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newtype);
|
||||
}
|
||||
else {
|
||||
/* Fall through to built-in `getattr`. */
|
||||
@ -4413,6 +4415,27 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CTX_DATA_TYPE_PROPERTY: {
|
||||
if (newprop != NULL) {
|
||||
/* Create pointer to parent ID, and path from ID to property. */
|
||||
PointerRNA idptr;
|
||||
RNA_id_pointer_create(newptr.owner_id, &idptr);
|
||||
char *path_str = RNA_path_from_ID_to_property(&newptr, newprop);
|
||||
|
||||
ret = PyTuple_New(3);
|
||||
PyTuple_SET_ITEMS(ret,
|
||||
pyrna_struct_CreatePyObject(&idptr),
|
||||
PyUnicode_FromString(path_str),
|
||||
PyLong_FromLong(newindex));
|
||||
|
||||
MEM_freeN(path_str);
|
||||
}
|
||||
else {
|
||||
ret = Py_None;
|
||||
Py_INCREF(ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Should never happen. */
|
||||
BLI_assert_msg(0, "Invalid context type");
|
||||
@ -4605,9 +4628,12 @@ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject
|
||||
|
||||
PointerRNA newptr;
|
||||
ListBase newlb;
|
||||
PropertyRNA *newprop;
|
||||
int newindex;
|
||||
short newtype;
|
||||
|
||||
const eContextResult done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
|
||||
const eContextResult done = CTX_data_get(
|
||||
C, name, &newptr, &newlb, &newprop, &newindex, &newtype);
|
||||
|
||||
if (done == CTX_RESULT_OK) {
|
||||
PyErr_Format(
|
||||
|
Loading…
Reference in New Issue
Block a user