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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user