diff --git a/source/blender/blenkernel/BKE_context.hh b/source/blender/blenkernel/BKE_context.hh index 92ba8c98ba6..aa1e11591e9 100644 --- a/source/blender/blenkernel/BKE_context.hh +++ b/source/blender/blenkernel/BKE_context.hh @@ -8,6 +8,8 @@ * \ingroup bke */ +#include + /* XXX temporary, until AssetHandle is designed properly and queries can return a pointer to it. */ #include "DNA_asset_types.h" @@ -102,7 +104,7 @@ using bContextDataCallback = int /*eContextResult*/ (*)(const bContext *C, struct bContextStoreEntry { std::string name; - PointerRNA ptr; + std::variant value; }; struct bContextStore { @@ -158,6 +160,9 @@ bContext *CTX_copy(const bContext *C); bContextStore *CTX_store_add(blender::Vector> &contexts, blender::StringRefNull name, const PointerRNA *ptr); +bContextStore *CTX_store_add(blender::Vector> &contexts, + blender::StringRefNull name, + blender::StringRef str); bContextStore *CTX_store_add_all(blender::Vector> &contexts, const bContextStore *context); const bContextStore *CTX_store_get(const bContext *C); @@ -165,6 +170,8 @@ void CTX_store_set(bContext *C, const bContextStore *store); const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store, blender::StringRefNull name, const StructRNA *type = nullptr); +std::optional CTX_store_string_lookup(const bContextStore *store, + blender::StringRefNull name); /* need to store if python is initialized or not */ bool CTX_py_init_get(bContext *C); @@ -262,6 +269,7 @@ enum { CTX_DATA_TYPE_POINTER = 0, CTX_DATA_TYPE_COLLECTION, CTX_DATA_TYPE_PROPERTY, + CTX_DATA_TYPE_STRING, }; PointerRNA CTX_data_pointer_get(const bContext *C, const char *member); @@ -282,6 +290,8 @@ blender::Vector CTX_data_collection_get(const bContext *C, const cha void CTX_data_collection_remap_property(blender::MutableSpan collection_pointers, const char *propname); +std::optional CTX_data_string_get(const bContext *C, const char *member); + /** * \param C: Context. * \param use_store: Use 'C->wm.store'. @@ -296,6 +306,7 @@ int /*eContextResult*/ CTX_data_get(const bContext *C, blender::Vector *r_lb, PropertyRNA **r_prop, int *r_index, + blender::StringRef *r_str, short *r_type); void CTX_data_id_pointer_set(bContextDataResult *result, ID *id); diff --git a/source/blender/blenkernel/intern/context.cc b/source/blender/blenkernel/intern/context.cc index e1a4321eab1..75d690896b7 100644 --- a/source/blender/blenkernel/intern/context.cc +++ b/source/blender/blenkernel/intern/context.cc @@ -131,9 +131,10 @@ void CTX_free(bContext *C) /* store */ -bContextStore *CTX_store_add(Vector> &contexts, - const blender::StringRefNull name, - const PointerRNA *ptr) +/** + * Append a new context store to \a contexts, copying entries from the previous one if any. + */ +static bContextStore *ctx_store_extend(Vector> &contexts) { /* ensure we have a context to put the entry in, if it was already used * we have to copy the context to ensure */ @@ -145,25 +146,31 @@ bContextStore *CTX_store_add(Vector> &contexts, contexts.append(std::move(new_ctx)); } - bContextStore *ctx = contexts.last().get(); + return contexts.last().get(); +} + +bContextStore *CTX_store_add(Vector> &contexts, + const blender::StringRefNull name, + const PointerRNA *ptr) +{ + bContextStore *ctx = ctx_store_extend(contexts); ctx->entries.append(bContextStoreEntry{name, *ptr}); return ctx; } +bContextStore *CTX_store_add(Vector> &contexts, + const blender::StringRefNull name, + const blender::StringRef str) +{ + bContextStore *ctx = ctx_store_extend(contexts); + ctx->entries.append(bContextStoreEntry{name, std::string{str}}); + return ctx; +} + bContextStore *CTX_store_add_all(Vector> &contexts, const bContextStore *context) { - /* ensure we have a context to put the entry in, if it was already used - * we have to copy the context to ensure */ - if (contexts.is_empty()) { - contexts.append(std::make_unique()); - } - else if (contexts.last()->used) { - auto new_ctx = std::make_unique(bContextStore{contexts.last()->entries, false}); - contexts.append(std::move(new_ctx)); - } - - bContextStore *ctx = contexts.last().get(); + bContextStore *ctx = ctx_store_extend(contexts); for (const bContextStoreEntry &src_entry : context->entries) { ctx->entries.append(src_entry); } @@ -185,15 +192,27 @@ const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store, const StructRNA *type) { for (auto entry = store->entries.rbegin(); entry != store->entries.rend(); ++entry) { - if (entry->name == name) { - if (!type || RNA_struct_is_a(entry->ptr.type, type)) { - return &entry->ptr; + if (entry->name == name && std::holds_alternative(entry->value)) { + const PointerRNA &ptr = std::get(entry->value); + if (!type || RNA_struct_is_a(ptr.type, type)) { + return &ptr; } } } return nullptr; } +std::optional CTX_store_string_lookup(const bContextStore *store, + const blender::StringRefNull name) +{ + for (auto entry = store->entries.rbegin(); entry != store->entries.rend(); ++entry) { + if (entry->name == name && std::holds_alternative(entry->value)) { + return std::get(entry->value); + } + } + return {}; +} + /* is python initialized? */ bool CTX_py_init_get(bContext *C) @@ -235,6 +254,7 @@ struct bContextDataResult { Vector list; PropertyRNA *prop; int index; + blender::StringRefNull str; const char **dir; short type; /* 0: normal, 1: seq */ }; @@ -313,6 +333,15 @@ static eContextResult ctx_data_get(bContext *C, const char *member, bContextData result->ptr = *ptr; done = 1; } + else { + std::optional str = CTX_store_string_lookup(C->wm.store, member); + + if (str) { + result->str = *str; + result->type = CTX_DATA_TYPE_STRING; + done = 1; + } + } } if (done != 1 && recursion < 2 && (region = CTX_wm_region(C))) { C->data.recursion = 2; @@ -487,12 +516,24 @@ void CTX_data_collection_remap_property(blender::MutableSpan collect } } +std::optional CTX_data_string_get(const bContext *C, const char *member) +{ + bContextDataResult result; + if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) { + BLI_assert(result.type == CTX_DATA_TYPE_STRING); + return result.str; + } + + return {}; +} + int /*eContextResult*/ CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, Vector *r_lb, PropertyRNA **r_prop, int *r_index, + blender::StringRef *r_str, short *r_type) { bContextDataResult result; @@ -503,11 +544,13 @@ int /*eContextResult*/ CTX_data_get(const bContext *C, *r_lb = result.list; *r_prop = result.prop; *r_index = result.index; + *r_str = result.str; *r_type = result.type; } else { memset(r_ptr, 0, sizeof(*r_ptr)); r_lb->clear(); + *r_str = ""; *r_type = 0; } diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index bda8ab26a7b..9218f922fb8 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -1375,6 +1375,8 @@ void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const char *name, const const PointerRNA *UI_but_context_ptr_get(const uiBut *but, const char *name, const StructRNA *type = nullptr); +std::optional UI_but_context_string_get(const uiBut *but, + const char *name); const bContextStore *UI_but_context_get(const uiBut *but); void UI_but_unit_type_set(uiBut *but, int unit_type); @@ -2164,6 +2166,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout); void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr); +void uiLayoutSetContextString(uiLayout *layout, const char *name, blender::StringRef value); bContextStore *uiLayoutGetContextStore(uiLayout *layout); void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context); diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index f3f25fe18d6..d3071793127 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -5769,6 +5769,14 @@ const PointerRNA *UI_but_context_ptr_get(const uiBut *but, const char *name, con return CTX_store_ptr_lookup(but->context, name, type); } +std::optional UI_but_context_string_get(const uiBut *but, const char *name) +{ + if (!but->context) { + return {}; + } + return CTX_store_string_lookup(but->context, name); +} + const bContextStore *UI_but_context_get(const uiBut *but) { return but->context; diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index 750be6fc954..4cf7f987d5a 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -25,6 +25,7 @@ #include "BLI_memory_utils.hh" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BLT_translation.hh" @@ -5999,6 +6000,12 @@ void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *p layout->context = CTX_store_add(block->contexts, name, ptr); } +void uiLayoutSetContextString(uiLayout *layout, const char *name, blender::StringRef value) +{ + uiBlock *block = layout->root->block; + layout->context = CTX_store_add(block->contexts, name, value); +} + bContextStore *uiLayoutGetContextStore(uiLayout *layout) { return layout->context; diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index b0f260e0834..4389e6fd11e 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -1587,6 +1587,12 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context"); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED | PARM_RNAPTR); + func = RNA_def_function(srna, "context_string_set", "uiLayoutSetContextString"); + parm = RNA_def_string(func, "name", nullptr, 0, "Name", "Name of entry in the context"); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); + parm = RNA_def_string(func, "value", nullptr, 0, "Value", "String to put in context"); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED | PARM_RNAPTR); + /* templates */ func = RNA_def_function(srna, "template_header", "uiTemplateHeader"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/python/intern/bpy_rna.cc b/source/blender/python/intern/bpy_rna.cc index 1464ab24a94..2b05eacb0a9 100644 --- a/source/blender/python/intern/bpy_rna.cc +++ b/source/blender/python/intern/bpy_rna.cc @@ -4438,6 +4438,7 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) blender::Vector newlb; PropertyRNA *newprop; int newindex; + blender::StringRef newstr; short newtype; /* An empty string is used to implement #CTX_data_dir_get, @@ -4445,7 +4446,7 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) eContextResult done; if (name[0]) { done = eContextResult( - CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newtype)); + CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newtype)); } else { /* Fall through to built-in `getattr`. */ @@ -4463,6 +4464,16 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) ret = pyrna_struct_CreatePyObject(&newptr); } break; + case CTX_DATA_TYPE_STRING: { + if (newstr.is_empty()) { + ret = Py_None; + Py_INCREF(ret); + } + else { + ret = PyUnicode_FromStringAndSize(newstr.data(), newstr.size()); + } + break; + } case CTX_DATA_TYPE_COLLECTION: { ret = PyList_New(0); for (PointerRNA &ptr : newlb) { @@ -4702,10 +4713,11 @@ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject blender::Vector newlb; PropertyRNA *newprop; int newindex; + blender::StringRef newstr; short newtype; const eContextResult done = eContextResult( - CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newtype)); + CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newtype)); if (done == CTX_RESULT_OK) { PyErr_Format(