UI: Allow passing named integers via context

Similar to 2fbf206491, but for integers (not strings). Essentially this
allows passing named integer values through UI abstractions in a clean
way.

I used 64 bit integers here, since space isn't an issue here, and it
fits common integer types (so we don't have to add APIs for multiple
integer types).

Planned to be used to fix #111463 (following commit).
This commit is contained in:
Julian Eisel
2024-12-10 14:49:11 +01:00
parent 317be33e95
commit f6a4d01703
6 changed files with 99 additions and 19 deletions

View File

@@ -102,7 +102,7 @@ using bContextDataCallback = int /*eContextResult*/ (*)(const bContext *C,
struct bContextStoreEntry {
std::string name;
std::variant<PointerRNA, std::string> value;
std::variant<PointerRNA, std::string, int64_t> value;
};
struct bContextStore {
@@ -162,6 +162,9 @@ bContextStore *CTX_store_add(blender::Vector<std::unique_ptr<bContextStore>> &co
bContextStore *CTX_store_add(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
blender::StringRef name,
blender::StringRef str);
bContextStore *CTX_store_add(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
blender::StringRef name,
int64_t value);
bContextStore *CTX_store_add_all(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
const bContextStore *context);
const bContextStore *CTX_store_get(const bContext *C);
@@ -171,6 +174,7 @@ const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
const StructRNA *type = nullptr);
std::optional<blender::StringRefNull> CTX_store_string_lookup(const bContextStore *store,
blender::StringRef name);
std::optional<int64_t> CTX_store_int_lookup(const bContextStore *store, blender::StringRef name);
/* need to store if python is initialized or not */
bool CTX_py_init_get(bContext *C);
@@ -269,6 +273,7 @@ enum {
CTX_DATA_TYPE_COLLECTION,
CTX_DATA_TYPE_PROPERTY,
CTX_DATA_TYPE_STRING,
CTX_DATA_TYPE_INT64,
};
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member);
@@ -290,6 +295,7 @@ void CTX_data_collection_remap_property(blender::MutableSpan<PointerRNA> collect
const char *propname);
std::optional<blender::StringRefNull> CTX_data_string_get(const bContext *C, const char *member);
std::optional<int64_t> CTX_data_int_get(const bContext *C, const char *member);
/**
* \param C: Context.
@@ -306,6 +312,7 @@ int /*eContextResult*/ CTX_data_get(const bContext *C,
PropertyRNA **r_prop,
int *r_index,
blender::StringRef *r_str,
std::optional<int64_t> *r_int_value,
short *r_type);
void CTX_data_id_pointer_set(bContextDataResult *result, ID *id);

View File

@@ -167,6 +167,15 @@ bContextStore *CTX_store_add(Vector<std::unique_ptr<bContextStore>> &contexts,
return ctx;
}
bContextStore *CTX_store_add(Vector<std::unique_ptr<bContextStore>> &contexts,
const blender::StringRef name,
const int64_t value)
{
bContextStore *ctx = ctx_store_extend(contexts);
ctx->entries.append(bContextStoreEntry{name, value});
return ctx;
}
bContextStore *CTX_store_add_all(Vector<std::unique_ptr<bContextStore>> &contexts,
const bContextStore *context)
{
@@ -202,17 +211,29 @@ const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
return nullptr;
}
std::optional<blender::StringRefNull> CTX_store_string_lookup(const bContextStore *store,
const blender::StringRef name)
template<typename T>
std::optional<T> ctx_store_lookup_impl(const bContextStore *store, const blender::StringRef name)
{
for (auto entry = store->entries.rbegin(); entry != store->entries.rend(); ++entry) {
if (entry->name == name && std::holds_alternative<std::string>(entry->value)) {
return std::get<std::string>(entry->value);
if (entry->name == name && std::holds_alternative<T>(entry->value)) {
return std::get<T>(entry->value);
}
}
return {};
}
std::optional<blender::StringRefNull> CTX_store_string_lookup(const bContextStore *store,
const blender::StringRef name)
{
return ctx_store_lookup_impl<std::string>(store, name);
}
std::optional<int64_t> CTX_store_int_lookup(const bContextStore *store,
const blender::StringRef name)
{
return ctx_store_lookup_impl<int64_t>(store, name);
}
/* is python initialized? */
bool CTX_py_init_get(bContext *C)
@@ -255,6 +276,7 @@ struct bContextDataResult {
PropertyRNA *prop;
int index;
blender::StringRefNull str;
std::optional<int64_t> int_value;
const char **dir;
short type; /* 0: normal, 1: seq */
};
@@ -327,20 +349,21 @@ static eContextResult ctx_data_get(bContext *C, const char *member, bContextData
if (done != 1 && recursion < 1 && C->wm.store) {
C->data.recursion = 1;
const PointerRNA *ptr = CTX_store_ptr_lookup(C->wm.store, member, nullptr);
if (ptr) {
if (const PointerRNA *ptr = CTX_store_ptr_lookup(C->wm.store, member, nullptr)) {
result->ptr = *ptr;
done = 1;
}
else {
std::optional<blender::StringRefNull> str = CTX_store_string_lookup(C->wm.store, member);
if (str) {
result->str = *str;
result->type = CTX_DATA_TYPE_STRING;
done = 1;
}
else if (std::optional<blender::StringRefNull> str = CTX_store_string_lookup(C->wm.store,
member))
{
result->str = *str;
result->type = CTX_DATA_TYPE_STRING;
done = 1;
}
else if (std::optional<int64_t> int_value = CTX_store_int_lookup(C->wm.store, member)) {
result->int_value = *int_value;
result->type = CTX_DATA_TYPE_INT64;
done = 1;
}
}
if (done != 1 && recursion < 2 && (region = CTX_wm_region(C))) {
@@ -527,6 +550,17 @@ std::optional<blender::StringRefNull> CTX_data_string_get(const bContext *C, con
return {};
}
std::optional<int64_t> CTX_data_int_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_INT64);
return result.int_value;
}
return {};
}
int /*eContextResult*/ CTX_data_get(const bContext *C,
const char *member,
PointerRNA *r_ptr,
@@ -534,6 +568,7 @@ int /*eContextResult*/ CTX_data_get(const bContext *C,
PropertyRNA **r_prop,
int *r_index,
blender::StringRef *r_str,
std::optional<int64_t> *r_int_value,
short *r_type)
{
bContextDataResult result;
@@ -545,12 +580,14 @@ int /*eContextResult*/ CTX_data_get(const bContext *C,
*r_prop = result.prop;
*r_index = result.index;
*r_str = result.str;
*r_int_value = result.int_value;
*r_type = result.type;
}
else {
*r_ptr = {};
r_lb->clear();
*r_str = "";
*r_int_value = {};
*r_type = 0;
}

View File

@@ -1457,11 +1457,13 @@ void UI_but_context_ptr_set(uiBlock *block,
uiBut *but,
blender::StringRef name,
const PointerRNA *ptr);
void UI_but_context_int_set(uiBlock *block, uiBut *but, blender::StringRef name, int64_t value);
const PointerRNA *UI_but_context_ptr_get(const uiBut *but,
blender::StringRef name,
const StructRNA *type = nullptr);
std::optional<blender::StringRefNull> UI_but_context_string_get(const uiBut *but,
blender::StringRef name);
std::optional<int64_t> UI_but_context_int_get(const uiBut *but, blender::StringRef name);
const bContextStore *UI_but_context_get(const uiBut *but);
void UI_but_unit_type_set(uiBut *but, int unit_type);
@@ -2274,6 +2276,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout);
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, blender::StringRef name, PointerRNA *ptr);
void uiLayoutSetContextString(uiLayout *layout, blender::StringRef name, blender::StringRef value);
void uiLayoutSetContextInt(uiLayout *layout, blender::StringRef name, int64_t value);
bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context);

View File

@@ -6041,6 +6041,13 @@ void UI_but_context_ptr_set(uiBlock *block,
but->context = ctx;
}
void UI_but_context_int_set(uiBlock *block, uiBut *but, const StringRef name, const int64_t value)
{
bContextStore *ctx = CTX_store_add(block->contexts, name, value);
ctx->used = true;
but->context = ctx;
}
const PointerRNA *UI_but_context_ptr_get(const uiBut *but,
const StringRef name,
const StructRNA *type)
@@ -6057,6 +6064,14 @@ std::optional<blender::StringRefNull> UI_but_context_string_get(const uiBut *but
return CTX_store_string_lookup(but->context, name);
}
std::optional<int64_t> UI_but_context_int_get(const uiBut *but, const StringRef name)
{
if (!but->context) {
return {};
}
return CTX_store_int_lookup(but->context, name);
}
const bContextStore *UI_but_context_get(const uiBut *but)
{
return but->context;

View File

@@ -6084,6 +6084,12 @@ void uiLayoutSetContextString(uiLayout *layout, StringRef name, blender::StringR
layout->context = CTX_store_add(block->contexts, name, value);
}
void uiLayoutSetContextInt(uiLayout *layout, StringRef name, int64_t value)
{
uiBlock *block = layout->root->block;
layout->context = CTX_store_add(block->contexts, name, value);
}
bContextStore *uiLayoutGetContextStore(uiLayout *layout)
{
return layout->context;

View File

@@ -4446,14 +4446,15 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
PropertyRNA *newprop;
int newindex;
blender::StringRef newstr;
std::optional<int64_t> newint;
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 = eContextResult(
CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newtype));
done = eContextResult(CTX_data_get(
C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newint, &newtype));
}
else {
/* Fall through to built-in `getattr`. */
@@ -4481,6 +4482,16 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
}
break;
}
case CTX_DATA_TYPE_INT64: {
if (!newint.has_value()) {
ret = Py_None;
Py_INCREF(ret);
}
else {
ret = PyLong_FromLong(*newint);
}
break;
}
case CTX_DATA_TYPE_COLLECTION: {
ret = PyList_New(0);
for (PointerRNA &ptr : newlb) {
@@ -4721,10 +4732,11 @@ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject
PropertyRNA *newprop;
int newindex;
blender::StringRef newstr;
std::optional<int64_t> newint;
short newtype;
const eContextResult done = eContextResult(
CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newtype));
CTX_data_get(C, name, &newptr, &newlb, &newprop, &newindex, &newstr, &newint, &newtype));
if (done == CTX_RESULT_OK) {
PyErr_Format(