diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 32b073b..3855ce4 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -262,9 +262,11 @@ static void UI_OT_unset_property_button(wmOperatorType *ot) /* Copy To Selected Operator ------------------------ */ -static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path) +static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, PropertyRNA *prop, ListBase *lb, + bool *use_path_from_id, char **path) { - *use_path = false; + *use_path_from_id = false; + *path = NULL; if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) *lb = CTX_data_collection_get(C, "selected_editable_bones"); @@ -275,15 +277,23 @@ static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bo else { ID *id = ptr->id.data; - if (id && GS(id->name) == ID_OB) { - *lb = CTX_data_collection_get(C, "selected_editable_objects"); - *use_path = true; - } - else { - return false; + if (id) { + if (GS(id->name) == ID_OB) { + *lb = CTX_data_collection_get(C, "selected_editable_objects"); + *use_path_from_id = true; + *path = RNA_path_from_ID_to_property(ptr, prop); + } + else if (GS(id->name) == ID_SCE) { /* Sequencer's ID is scene :/ */ + /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */ + if ((*path = RNA_path_from_ancestor_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + *lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } + } + return (*path != NULL); } + return false; } - + return true; } @@ -307,47 +317,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) /* if there is a valid property that is editable... */ if (ptr.data && prop) { char *path = NULL; - bool use_path; + bool use_path_from_id; CollectionPointerLink *link; ListBase lb; - if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) + if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) return success; - if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { - for (link = lb.first; link; link = link->next) { - if (link->ptr.data != ptr.data) { - if (use_path) { - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + for (link = lb.first; link; link = link->next) { + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - if (lprop == prop) { - if (RNA_property_editable(&lptr, lprop)) { - if (poll) { + if (lptr.data == ptr.data) { + /* lptr might not be the same as link->ptr! */ + continue; + } + + if (lprop == prop) { + if (RNA_property_editable(&lptr, lprop)) { + if (poll) { + success = true; + break; + } + else { + if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { + RNA_property_update(C, &lptr, prop); success = true; - break; - } - else { - if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { - RNA_property_update(C, &lptr, prop); - success = true; - } } } } } } - - if (path) - MEM_freeN(path); } + MEM_SAFE_FREE(path); BLI_freelistN(&lb); } diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a2bbaf6..f888734 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -930,6 +930,8 @@ bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); +char *RNA_path_from_ancestor_type_to_property(struct PointerRNA *ptr, struct PropertyRNA *prop, struct StructRNA *type); + char *RNA_path_full_ID_py(struct ID *id); char *RNA_path_full_struct_py(struct PointerRNA *ptr); char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 271f907..d98ef45 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4498,6 +4498,40 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) } /** + * Assumes ptr is not an instance of type! + * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL). + */ +char *RNA_path_from_ancestor_type_to_property(PointerRNA *ptr, PropertyRNA *prop, StructRNA *type) +{ + /* Try to recursively find an "type"'d ancestor, to handle situations where path from ID is not enough. */ + PointerRNA idptr, tptr; + PropertyRNA *tprop; + char *path = NULL; + char *full_path = RNA_path_from_ID_to_property(ptr, prop); + char *path_t1 = RNA_path_back(full_path); /* We remove property... */ + char *path_t2 = RNA_path_back(path_t1); /* ... and first struct, which we assume as 'invalid'. */ + MEM_SAFE_FREE(path_t1); + path_t1 = path_t2; + + RNA_id_pointer_create(ptr->id.data, &idptr); + + while (path_t1 && RNA_path_resolve(&idptr, path_t1, &tptr, &tprop)) { + if (RNA_struct_is_a(tptr.type, type)) { + path = BLI_strdup(full_path + strlen(path_t1) + 1); /* +1 for the linking '.' */ + MEM_SAFE_FREE(path_t1); + break; + } + + path_t2 = RNA_path_back(path_t1); + MEM_SAFE_FREE(path_t1); + path_t1 = path_t2; + } + + MEM_SAFE_FREE(full_path); + return path; +} + +/** * Get the ID as a python representation, eg: * bpy.data.foo["bar"] */