diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2014-08-05 20:59:02 +0400 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2014-08-05 21:21:14 +0400 |
commit | 5336e68e110252b1da18bf8749b62b6a9f01c10a (patch) | |
tree | 73914dc8a299f0e2f30f49cc6bf8ba8fb2935016 | |
parent | b37b3171734b22f649e3de205377fe7e994a407c (diff) |
Fix T41062: "copy to selected" doens't work for all attributes.
The issue was that some properties are no direct children of the struct we support in 'copy to selected'
(RNA_Sequence in this case). Since we can't use the ID of sequences here (it's the scene, while we need
a sequence level of control), we had to add a new API helper to RNA path, which takes a RNA type
and return a path relative to the closest ancester of that type.
This way, we get a path from the RNA_Sequence, and can easily apply it to all other valid sequences
to copy the property.
Review, suggestions and edits by Campbell Barton, thanks!
-rw-r--r-- | source/blender/editors/interface/interface_ops.c | 106 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 13 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_access.c | 104 |
3 files changed, 170 insertions, 53 deletions
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 32b073ba269..458aca444cb 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -262,28 +262,43 @@ 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 *r_lb, bool *r_use_path_from_id, char **r_path) { - *use_path = false; + *r_use_path_from_id = false; + *r_path = NULL; - if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) - *lb = CTX_data_collection_get(C, "selected_editable_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) - *lb = CTX_data_collection_get(C, "selected_pose_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) - *lb = CTX_data_collection_get(C, "selected_editable_sequences"); - else { + if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) { + *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } + else if (ptr->id.data) { ID *id = ptr->id.data; - if (id && GS(id->name) == ID_OB) { - *lb = CTX_data_collection_get(C, "selected_editable_objects"); - *use_path = true; + if (GS(id->name) == ID_OB) { + *r_lb = CTX_data_collection_get(C, "selected_editable_objects"); + *r_use_path_from_id = true; + *r_path = RNA_path_from_ID_to_property(ptr, prop); } - else { - return false; + 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 ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } } + return (*r_path != NULL); } - + else { + return false; + } + return true; } @@ -307,47 +322,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 a2bbaf67c1a..ba2dd8b5d69 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -927,9 +927,22 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index); +typedef struct PropertyElemRNA PropertyElemRNA; +struct PropertyElemRNA { + PropertyElemRNA *next, *prev; + PointerRNA ptr; + PropertyRNA *prop; + int index; +}; +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); + char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); +char *RNA_path_resolve_from_type_to_property( + struct PointerRNA *ptr, struct PropertyRNA *prop, + const 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 271f9079162..8c76edd2f17 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4015,11 +4015,14 @@ static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, Prope } static bool rna_path_parse(PointerRNA *ptr, const char *path, - PointerRNA *r_ptr, PropertyRNA **r_prop, int *index, + PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, + ListBase *r_elements, const bool eval_pointer) { PropertyRNA *prop; PointerRNA curptr; + PropertyElemRNA *prop_elem = NULL; + int index = -1; char fixedbuf[256]; int type; @@ -4061,6 +4064,14 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, if (!prop) return false; + if (r_elements) { + prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = -1; /* index will be added later, if needed. */ + BLI_addtail(r_elements, prop_elem); + } + type = RNA_property_type(prop); /* now look up the value of this property if it is a pointer or @@ -4076,7 +4087,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } @@ -4093,21 +4104,38 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } default: - if (index) { - if (!rna_path_parse_array_index(&path, &curptr, prop, index)) + if (r_index || prop_elem) { + if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { return false; + } + + if (prop_elem) { + prop_elem->index = index; + } } break; } } - *r_ptr = curptr; - *r_prop = prop; + if (r_ptr) + *r_ptr = curptr; + if (r_prop) + *r_prop = prop; + if (r_index) + *r_index = index; + + if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) { + PropertyElemRNA *prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = index; + BLI_addtail(r_elements, prop_elem); + } return true; } @@ -4120,7 +4148,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, */ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, true)) return false; return r_ptr->data != NULL; @@ -4134,7 +4162,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop */ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, true)) return false; return r_ptr->data != NULL; @@ -4149,7 +4177,7 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, */ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; @@ -4165,12 +4193,25 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ */ bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; } +/** + * Resolve the given RNA Path into a linked list of PropertyElemRNA's. + * + * To be used when complex operations over path are needed, like e.g. get relative paths, to avoid too much + * string operations. + * + * \return True if there was no error while resolving the path + * \note Assumes all pointers provided are valid + */ +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) +{ + return rna_path_parse(ptr, path, NULL, NULL, NULL, r_elements, false); +} char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey) { @@ -4498,6 +4539,47 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) } /** + * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL). + */ +char *RNA_path_resolve_from_type_to_property( + PointerRNA *ptr, PropertyRNA *prop, + const StructRNA *type) +{ + /* Try to recursively find an "type"'d ancestor, + * to handle situations where path from ID is not enough. */ + PointerRNA idptr; + ListBase path_elems = {NULL}; + char *path = NULL; + char *full_path = RNA_path_from_ID_to_property(ptr, prop); + + if (full_path == NULL) { + return NULL; + } + + RNA_id_pointer_create(ptr->id.data, &idptr); + + if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { + PropertyElemRNA *prop_elem; + + for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) { + if (RNA_struct_is_a(prop_elem->ptr.type, type)) { + char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); + if (ref_path) { + path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ + MEM_freeN(ref_path); + } + break; + } + } + + BLI_freelistN(&path_elems); + } + + MEM_freeN(full_path); + return path; +} + +/** * Get the ID as a python representation, eg: * bpy.data.foo["bar"] */ |