Nodes: Panel declarations for grouping sockets #108649

Merged
Lukas Tönne merged 27 commits from LukasTonne/blender:node-socket-categories into main 2023-06-14 18:02:46 +02:00
7 changed files with 65 additions and 71 deletions
Showing only changes of commit c7ab5dc068 - Show all commits

View File

@ -566,18 +566,24 @@ void ntreeSetSocketInterfaceCategory(bNodeTree *ntree,
/** \name Node Tree Socket Categories
* \{ */
/**
* Find a socket category by its unique ID.
* \param id: Unique ID of the category within the node tree.
LukasTonne marked this conversation as resolved Outdated

There's meant to be a colon after the name here: \param name:

There's meant to be a colon after the name here: `\param name:`
*/
bNodeSocketCategory *ntreeFindSocketCategoryByID(bNodeTree *ntree, int id);
/**
* Add a new socket category to the node tree.
* \param name Name of the new category.
* \param name Flags of the new category.
* \param name: Name of the new category.
* \param flag: Flags of the new category.
*/
bNodeSocketCategory *ntreeAddSocketCategory(bNodeTree *ntree, const char *name, int flag);
/**
* Insert a new socket category in the node tree.
* \param name Name of the new category.
* \param name Flags of the new category.
* \param index Index at which to insert the category.
* \param name: Name of the new category.
* \param flag: Flags of the new category.
* \param index: Index at which to insert the category.
*/
bNodeSocketCategory *ntreeInsertSocketCategory(bNodeTree *ntree,
const char *name,

View File

@ -3658,7 +3658,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
STRNCPY(sock->name, name);
sock->storage = nullptr;
sock->flag |= SOCK_COLLAPSED;
sock->category_index = -1;
sock->category_id = -1;
return sock;
}
@ -3667,7 +3667,7 @@ static int node_socket_category_cmp(const void *a, const void *b)
{
const bNodeSocket *sock_a = static_cast<const bNodeSocket *>(a);
const bNodeSocket *sock_b = static_cast<const bNodeSocket *>(b);
return (sock_a->category_index > sock_b->category_index) ? 1 : 0;
return (sock_a->category_id > sock_b->category_id) ? 1 : 0;
}
bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree,
@ -3687,8 +3687,32 @@ bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree,
void ntreeEnsureSocketCategoryOrder(bNodeTree *ntree)
{
/* XXX Hack: store category index in category_id temporarily for sorting. */
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->inputs) {
const bNodeSocketCategory *category = ntreeFindSocketCategoryByID(ntree, iosock->category_id);
iosock->category_id = category == nullptr ? -1 :
(int)(category - ntree->socket_categories_array);
}
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->outputs) {
const bNodeSocketCategory *category = ntreeFindSocketCategoryByID(ntree, iosock->category_id);
iosock->category_id = category == nullptr ? -1 :
(int)(category - ntree->socket_categories_array);
}
BLI_listbase_sort(&ntree->inputs, blender::bke::node_socket_category_cmp);
BLI_listbase_sort(&ntree->outputs, blender::bke::node_socket_category_cmp);
/* Restore category_id. */
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->inputs) {
if (iosock->category_id >= 0) {
const bNodeSocketCategory &category = ntree->socket_categories()[iosock->category_id];
iosock->category_id = category.identifier;
}
}
LukasTonne marked this conversation as resolved Outdated

VectorSet and VectorSet::index_of` are probably a more natural choice here, with a bit less boilerplate.

`VectorSet` and VectorSet::index_of` are probably a more natural choice here, with a bit less boilerplate.
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->outputs) {
if (iosock->category_id >= 0) {
const bNodeSocketCategory &category = ntree->socket_categories()[iosock->category_id];
iosock->category_id = category.identifier;
}
}
}
bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
@ -3715,12 +3739,11 @@ void ntreeSetSocketInterfaceCategory(bNodeTree *ntree,
bNodeSocketCategory *category)
{
if (category == NULL) {
socket->category_index = -1;
socket->category_id = -1;
return;
}
socket->category_index = category - ntree->socket_categories_array;
BLI_assert(ntree->socket_categories().index_range().contains(socket->category_index));
socket->category_id = category->identifier;
ntreeEnsureSocketCategoryOrder(ntree);
@ -3805,25 +3828,16 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BKE_ntree_update_tag_interface(ntree);
}
namespace blender::bke {
/* Fix socket category indices after changes. */
static void remap_socket_categories(bNodeTree &ntree, std::function<int(int)> index_fn)
bNodeSocketCategory *ntreeFindSocketCategoryByID(bNodeTree *ntree, int id)
{
LukasTonne marked this conversation as resolved Outdated

IMO __func__ for the allocation string is nicer than specifying one manually. It just takes up less visual space. I've also seen other developers preferring that too.

IMO `__func__` for the allocation string is nicer than specifying one manually. It just takes up less visual space. I've also seen other developers preferring that too.
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree.inputs) {
socket->category_index = index_fn(socket->category_index);
BLI_assert(socket->category_index == -1 ||
ntree.socket_categories().index_range().contains(socket->category_index));
}
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree.outputs) {
socket->category_index = index_fn(socket->category_index);
BLI_assert(socket->category_index == -1 ||
ntree.socket_categories().index_range().contains(socket->category_index));
for (bNodeSocketCategory &category : ntree->socket_categories_for_write()) {
if (category.identifier == id) {
return &category;
}
LukasTonne marked this conversation as resolved Outdated

Don't have a strong preference, but this seems a bit more idiomatic and clear to me:
std::copy(old_categories.begin(), old_categories.end(), new_categories.data());

Don't have a strong preference, but this seems a bit more idiomatic and clear to me: ` std::copy(old_categories.begin(), old_categories.end(), new_categories.data());`
}
return nullptr;
}
} // namespace blender::bke
bNodeSocketCategory *ntreeAddSocketCategory(bNodeTree *ntree, const char *name, int flag)
{
bNodeSocketCategory *old_categories_array = ntree->socket_categories_array;
@ -3837,11 +3851,10 @@ bNodeSocketCategory *ntreeAddSocketCategory(bNodeTree *ntree, const char *name,
new_categories[i] = old_categories[i];
}
bNodeSocketCategory &new_category = new_categories[new_categories.size() - 1];
new_category = {BLI_strdup(name), flag};
new_category = {BLI_strdup(name), flag, ntree->next_socket_category_identifier++};
MEM_SAFE_FREE(old_categories_array);
/* No need to remap socket categories, in this case old indices stay the same. */
/* No need to sort sockets, nothing is using the new category yet */
return &new_category;
@ -3870,14 +3883,10 @@ bNodeSocketCategory *ntreeInsertSocketCategory(bNodeTree *ntree,
new_categories[i + 1] = old_categories[i];
}
bNodeSocketCategory &new_category = new_categories[index];
new_category = {BLI_strdup(name), flag};
new_category = {BLI_strdup(name), flag, ntree->next_socket_category_identifier++};
MEM_SAFE_FREE(old_categories_array);
blender::bke::remap_socket_categories(*ntree, [index](const int old_category_index) {
return old_category_index < index ? old_category_index : old_category_index + 1;
});
/* No need to sort sockets, nothing is using the new category yet */
return &new_category;
@ -3906,11 +3915,6 @@ void ntreeRemoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category)
MEM_SAFE_FREE(old_categories_array);
blender::bke::remap_socket_categories(*ntree, [index](const int old_category_index) {
return old_category_index < index ? old_category_index :
(old_category_index > index ? old_category_index - 1 : -1);
});
ntreeEnsureSocketCategoryOrder(ntree);
}
@ -3920,8 +3924,6 @@ void ntreeClearSocketCategories(bNodeTree *ntree)
ntree->socket_categories_array = nullptr;
ntree->socket_categories_num = 0;
blender::bke::remap_socket_categories(*ntree, [](const int /*old_index*/) { return -1; });
/* No need to sort sockets, only null category exists, relative order remains unchanged. */
}
@ -3943,13 +3945,6 @@ void ntreeMoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category, in
categories[i] = categories[i + 1];
}
categories[new_index] = tmp;
blender::bke::remap_socket_categories(
*ntree, [old_index, new_index](const int old_category_index) {
return old_category_index < old_index || old_category_index > new_index ?
old_category_index :
(old_category_index == old_index ? new_index : old_category_index - 1);
});
}
else /* old_index > new_index */ {
const bNodeSocketCategory tmp = categories[old_index];
@ -3957,13 +3952,6 @@ void ntreeMoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category, in
categories[i] = categories[i - 1];
}
categories[new_index] = tmp;
blender::bke::remap_socket_categories(
*ntree, [old_index, new_index](const int old_category_index) {
return old_category_index < new_index || old_category_index > old_index ?
old_category_index :
(old_category_index == old_index ? new_index : old_category_index + 1);
});
}
ntreeEnsureSocketCategoryOrder(ntree);

View File

@ -138,13 +138,13 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
{
/* Keep this block, even when empty. */
if (!DNA_struct_elem_find(fd->filesdna, "bNodeSocket", "int", "category_index")) {
if (!DNA_struct_elem_find(fd->filesdna, "bNodeSocket", "int", "category_id")) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
socket->category_index = -1;
socket->category_id = -1;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
socket->category_index = -1;
socket->category_id = -1;
}
}
FOREACH_NODETREE_END;

View File

@ -2192,7 +2192,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
/* XXX this only works for actual sockets, not interface templates! */
// nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr);
/* Inherit socket category from the active socket interface. */
sock->category_index = active_sock->category_index;
sock->category_id = active_sock->category_id;
}
else {
/* XXX TODO: define default socket type for a tree! */

View File

@ -15,7 +15,7 @@
#define _DNA_DEFAULT_bNodeSocket \
{ \
.category_index = -1, \
.category_id = -1, \
}
/** \} */

View File

@ -168,8 +168,8 @@ typedef struct bNodeSocket {
/** Custom data for inputs, only UI writes in this. */
bNodeStack ns DNA_DEPRECATED;
/* UI category index of the socket. */
int category_index;
/* ID of the UI category of the socket. */
int category_id;
int _pad2;
bNodeSocketRuntimeHandle *runtime;
@ -538,7 +538,7 @@ typedef struct bNodeLink {
typedef struct bNodeSocketCategory {
char *name;
int flag;
int _pad;
int identifier;
} bNodeSocketCategory;
/* the basis for a Node tree, all links and nodes reside internal here */
@ -608,6 +608,8 @@ typedef struct bNodeTree {
struct bNodeSocketCategory *socket_categories_array;
int socket_categories_num;
int active_socket_category;
int next_socket_category_identifier;
char _pad2[4];
bNodeTreeRuntimeHandle *runtime;

View File

@ -3168,12 +3168,8 @@ static PointerRNA rna_NodeSocketInterface_category_get(PointerRNA *ptr)
{
bNodeSocket *socket = (bNodeSocket *)ptr->data;
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
const int index = socket->category_index;
bNodeSocketCategory *category = NULL;
if (index >= 0 && index < ntree->socket_categories_num) {
category = &ntree->socket_categories_array[index];
}
bNodeSocketCategory *category = ntreeFindSocketCategoryByID(ntree, socket->category_id);
PointerRNA r_ptr;
RNA_pointer_create(&ntree->id, &RNA_NodeSocketCategory, category, &r_ptr);
@ -3188,10 +3184,12 @@ static void rna_NodeSocketInterface_category_set(PointerRNA *ptr,
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketCategory *category = (bNodeSocketCategory *)value.data;
const size_t index = category - ntree->socket_categories_array;
if (index >= ntree->socket_categories_num) {
BKE_report(reports, RPT_ERROR, "Category is not in the node tree interface");
return;
if (category != NULL) {
const int64_t index = category - ntree->socket_categories_array;
if (index < 0 || index >= ntree->socket_categories_num) {
BKE_report(reports, RPT_ERROR, "Category is not in the node tree interface");
return;
}
}
ntreeSetSocketInterfaceCategory(ntree, socket, category);
@ -3206,7 +3204,7 @@ static bool rna_NodeSocketInterface_category_poll(PointerRNA *ptr, PointerRNA va
return true;
LukasTonne marked this conversation as resolved Outdated

Super picky but this newline isn't helpful IMO, better to more closely connect the variable declaration and the null check.

Super picky but this newline isn't helpful IMO, better to more closely connect the variable declaration and the null check.
}
const int index = category - ntree->socket_categories_array;
const int64_t index = category - ntree->socket_categories_array;
if (index < 0 || index >= ntree->socket_categories_num) {
return false;
}