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
5 changed files with 92 additions and 69 deletions
Showing only changes of commit ab0d8761d2 - Show all commits

View File

@ -561,6 +561,18 @@ void ntreeSetSocketInterfacePanel(bNodeTree *ntree, bNodeSocket *sock, bNodeSock
/** \name Node Tree Socket Panels
* \{ */
/**
* Check if a panel is part of the node tree.
* \return True if the panel is part of the node tree.
*/
bool ntreeContainsSocketPanel(const bNodeTree *ntree, const bNodeSocketPanel *panel);
/**
* Index of a panel in 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:`
* \return Index of the panel in the node tree or -1 if the tree does not contain the panel.
*/
int ntreeGetSocketPanelIndex(const bNodeTree *ntree, const bNodeSocketPanel *panel);
/**
* Find a socket panel by its unique ID.
* \param id: Unique ID of the panel within the node tree.

View File

@ -516,12 +516,12 @@ inline blender::Span<bNode *> bNodeTree::root_frames() const
return this->runtime->root_frames;
}
inline blender::Span<bNodeSocketPanel> bNodeTree::socket_panels() const
inline blender::Span<bNodeSocketPanel *> bNodeTree::socket_panels() const
{
return blender::Span(socket_panels_array, socket_panels_num);
}
inline blender::MutableSpan<bNodeSocketPanel> bNodeTree::socket_panels_for_write()
inline blender::MutableSpan<bNodeSocketPanel *> bNodeTree::socket_panels_for_write()
{
return blender::MutableSpan(socket_panels_array, socket_panels_num);
}

View File

@ -643,10 +643,10 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
write_node_socket_interface(writer, sock);
}
BLO_write_struct_array(
writer, bNodeSocketPanel, ntree->socket_panels_num, ntree->socket_panels_array);
for (const bNodeSocketPanel &panel : ntree->socket_panels()) {
BLO_write_string(writer, panel.name);
BLO_write_pointer_array(writer, ntree->socket_panels_num, ntree->socket_panels_array);
for (const bNodeSocketPanel *panel : ntree->socket_panels()) {
BLO_write_struct(writer, bNodeSocketPanel, panel);
BLO_write_string(writer, panel->name);
}
BKE_previewimg_blend_write(writer, ntree->preview);
@ -869,9 +869,10 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &link->tosock);
}
BLO_read_data_address(reader, &ntree->socket_panels_array);
for (bNodeSocketPanel &panel : ntree->socket_panels_for_write()) {
BLO_read_data_address(reader, &panel.name);
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&ntree->socket_panels_array));
for (const int i : IndexRange(ntree->socket_panels_num)) {
BLO_read_data_address(reader, &ntree->socket_panels_array[i]);
BLO_read_data_address(reader, &ntree->socket_panels_array[i]->name);
}
/* TODO: should be dealt by new generic cache handling of IDs... */
@ -3682,25 +3683,25 @@ void ntreeEnsureSocketInterfacePanelOrder(bNodeTree *ntree)
/* XXX Hack: store panel index in panel_id temporarily for sorting. */
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->inputs) {
const bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, iosock->panel_id);
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_array);
iosock->panel_id = ntreeGetSocketPanelIndex(ntree, panel);
}
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->outputs) {
const bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, iosock->panel_id);
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_array);
iosock->panel_id = ntreeGetSocketPanelIndex(ntree, panel);
}
BLI_listbase_sort(&ntree->inputs, blender::bke::node_socket_panel_cmp);
BLI_listbase_sort(&ntree->outputs, blender::bke::node_socket_panel_cmp);
/* Restore panel_id. */
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->inputs) {
if (iosock->panel_id >= 0) {
const bNodeSocketPanel &panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel.identifier;
const bNodeSocketPanel *panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel->identifier;
}
}
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->outputs) {
if (iosock->panel_id >= 0) {
const bNodeSocketPanel &panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel.identifier;
const bNodeSocketPanel *panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel->identifier;
}
}
}
@ -3816,11 +3817,21 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BKE_ntree_update_tag_interface(ntree);
}
bool ntreeContainsSocketPanel(const bNodeTree *ntree, const bNodeSocketPanel *panel)
{
return ntree->socket_panels().contains(const_cast<bNodeSocketPanel *>(panel));
}
int ntreeGetSocketPanelIndex(const bNodeTree *ntree, const bNodeSocketPanel *panel)
{
return ntree->socket_panels().first_index_try(const_cast<bNodeSocketPanel *>(panel));
}
bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
{
for (bNodeSocketPanel &panel : ntree->socket_panels_for_write()) {
if (panel.identifier == id) {
return &panel;
for (bNodeSocketPanel *panel : ntree->socket_panels_for_write()) {
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.
if (panel->identifier == id) {
return panel;
}
}
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;
@ -3828,22 +3839,24 @@ bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
bNodeSocketPanel *ntreeAddSocketPanel(bNodeTree *ntree, const char *name, int flag)
{
bNodeSocketPanel *old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel>(ntree->socket_panels_num + 1,
__func__);
bNodeSocketPanel **old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel *> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel *>(ntree->socket_panels_num + 1,
__func__);
++ntree->socket_panels_num;
const MutableSpan<bNodeSocketPanel> new_panels = ntree->socket_panels_for_write();
const MutableSpan<bNodeSocketPanel *> new_panels = ntree->socket_panels_for_write();
std::copy(old_panels.begin(), old_panels.end(), new_panels.data());
bNodeSocketPanel &new_panel = new_panels[new_panels.size() - 1];
new_panel = {BLI_strdup(name), flag, ntree->next_socket_panel_identifier++};
bNodeSocketPanel *new_panel = MEM_cnew<bNodeSocketPanel>(__func__);
*new_panel = {BLI_strdup(name), flag, ntree->next_socket_panel_identifier++};
new_panels[new_panels.size() - 1] = new_panel;
MEM_SAFE_FREE(old_panels_array);
/* No need to sort sockets, nothing is using the new panel yet */
return &new_panel;
return new_panel;
}
bNodeSocketPanel *ntreeInsertSocketPanel(bNodeTree *ntree, const char *name, int flag, int index)
@ -3852,47 +3865,51 @@ bNodeSocketPanel *ntreeInsertSocketPanel(bNodeTree *ntree, const char *name, int
return nullptr;
}
bNodeSocketPanel *old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel>(ntree->socket_panels_num + 1,
__func__);
bNodeSocketPanel **old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel *> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel *>(ntree->socket_panels_num + 1,
__func__);
++ntree->socket_panels_num;
const MutableSpan<bNodeSocketPanel> new_panels = ntree->socket_panels_for_write();
const MutableSpan<bNodeSocketPanel *> new_panels = ntree->socket_panels_for_write();
Span old_panels_front = old_panels.take_front(index);
Span old_panels_back = old_panels.drop_front(index);
std::copy(old_panels_front.begin(), old_panels_front.end(), new_panels.data());
std::copy(
old_panels_back.begin(), old_panels_back.end(), new_panels.drop_front(index + 1).data());
bNodeSocketPanel &new_panel = new_panels[index];
new_panel = {BLI_strdup(name), flag, ntree->next_socket_panel_identifier++};
bNodeSocketPanel *new_panel = MEM_cnew<bNodeSocketPanel>(__func__);
*new_panel = {BLI_strdup(name), flag, ntree->next_socket_panel_identifier++};
new_panels[index] = new_panel;
MEM_SAFE_FREE(old_panels_array);
/* No need to sort sockets, nothing is using the new panel yet */
return &new_panel;
return new_panel;
}
void ntreeRemoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel)
{
const int index = panel - ntree->socket_panels_array;
if (!ntree->socket_panels().contains_ptr(panel)) {
const int index = ntreeGetSocketPanelIndex(ntree, panel);
if (index < 0) {
return;
}
bNodeSocketPanel *old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel>(ntree->socket_panels_num - 1,
__func__);
bNodeSocketPanel **old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel *> old_panels = ntree->socket_panels();
ntree->socket_panels_array = MEM_cnew_array<bNodeSocketPanel *>(ntree->socket_panels_num - 1,
__func__);
--ntree->socket_panels_num;
const MutableSpan<bNodeSocketPanel> new_panels = ntree->socket_panels_for_write();
const MutableSpan<bNodeSocketPanel *> new_panels = ntree->socket_panels_for_write();
Span old_panels_front = old_panels.take_front(index);
Span old_panels_back = old_panels.drop_front(index + 1);
std::copy(old_panels_front.begin(), old_panels_front.end(), new_panels.data());
std::copy(old_panels_back.begin(), old_panels_back.end(), new_panels.drop_front(index).data());
MEM_SAFE_FREE(panel->name);
MEM_SAFE_FREE(panel);
MEM_SAFE_FREE(old_panels_array);
ntreeEnsureSocketInterfacePanelOrder(ntree);
@ -3900,6 +3917,10 @@ void ntreeRemoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel)
void ntreeClearSocketPanels(bNodeTree *ntree)
{
for (bNodeSocketPanel *panel : ntree->socket_panels_for_write()) {
MEM_SAFE_FREE(panel->name);
MEM_SAFE_FREE(panel);
}
MEM_SAFE_FREE(ntree->socket_panels_array);
ntree->socket_panels_array = nullptr;
ntree->socket_panels_num = 0;
@ -3909,24 +3930,25 @@ void ntreeClearSocketPanels(bNodeTree *ntree)
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index)
{
if (!ntree->socket_panels().contains_ptr(panel)) {
const int old_index = ntreeGetSocketPanelIndex(ntree, panel);
if (old_index < 0) {
return;
}
const MutableSpan<bNodeSocketPanel> panels = ntree->socket_panels_for_write();
const int old_index = panel - ntree->socket_panels_array;
const MutableSpan<bNodeSocketPanel *> panels = ntree->socket_panels_for_write();
if (old_index == new_index) {
return;
}
else if (old_index < new_index) {
const Span<bNodeSocketPanel> moved_panels = panels.slice(old_index + 1, new_index - old_index);
const bNodeSocketPanel tmp = panels[old_index];
const Span<bNodeSocketPanel *> moved_panels = panels.slice(old_index + 1,
new_index - old_index);
bNodeSocketPanel *tmp = panels[old_index];
std::copy(moved_panels.begin(), moved_panels.end(), panels.drop_front(old_index).data());
panels[new_index] = tmp;
}
else /* old_index > new_index */ {
const Span<bNodeSocketPanel> moved_panels = panels.slice(new_index, old_index - new_index);
const bNodeSocketPanel tmp = panels[old_index];
const Span<bNodeSocketPanel *> moved_panels = panels.slice(new_index, old_index - new_index);
bNodeSocketPanel *tmp = panels[old_index];
std::copy_backward(
moved_panels.begin(), moved_panels.end(), panels.drop_front(old_index + 1).data());
panels[new_index] = tmp;

View File

@ -605,7 +605,7 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
/* UI panels for sockets */
struct bNodeSocketPanel *socket_panels_array;
struct bNodeSocketPanel **socket_panels_array;
int socket_panels_num;
int active_socket_panel;
int next_socket_panel_identifier;
@ -675,8 +675,8 @@ typedef struct bNodeTree {
blender::Span<const bNodeSocket *> interface_inputs() const;
blender::Span<const bNodeSocket *> interface_outputs() const;
LukasTonne marked this conversation as resolved Outdated

panels() should return Span<const bNodePanel *>, so a const bNodeSocket * doesn't give you a mutable bNodePanel

`panels()` should return `Span<const bNodePanel *>`, so a `const bNodeSocket *` doesn't give you a mutable `bNodePanel`
blender::Span<bNodeSocketPanel> socket_panels() const;
blender::MutableSpan<bNodeSocketPanel> socket_panels_for_write();
blender::Span<bNodeSocketPanel *> socket_panels() const;
blender::MutableSpan<bNodeSocketPanel *> socket_panels_for_write();
#endif
} bNodeTree;

View File

@ -3188,12 +3188,9 @@ static void rna_NodeSocketInterface_panel_set(PointerRNA *ptr,
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
if (panel != NULL) {
const int64_t index = panel - ntree->socket_panels_array;
if (index < 0 || index >= ntree->socket_panels_num) {
BKE_report(reports, RPT_ERROR, "Panel is not in the node tree interface");
return;
}
if (panel && !ntreeContainsSocketPanel(ntree, panel)) {
BKE_report(reports, RPT_ERROR, "Panel is not in the node tree interface");
return;
}
ntreeSetSocketInterfacePanel(ntree, socket, panel);
@ -3203,16 +3200,8 @@ static bool rna_NodeSocketInterface_panel_poll(PointerRNA *ptr, PointerRNA value
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
if (panel == NULL) {
return true;
}
const int64_t index = panel - ntree->socket_panels_array;
if (index < 0 || index >= ntree->socket_panels_num) {
return false;
}
return true;
return panel == NULL || ntreeContainsSocketPanel(ntree, panel);
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.
}
static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@ -3393,7 +3382,7 @@ static void rna_NodeTree_socket_panels_move(bNodeTree *ntree,
return;
}
ntreeMoveSocketPanel(ntree, &ntree->socket_panels_array[from_index], to_index);
ntreeMoveSocketPanel(ntree, ntree->socket_panels_array[from_index], to_index);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
@ -3407,7 +3396,7 @@ static PointerRNA rna_NodeTree_active_socket_panel_get(PointerRNA *ptr)
if (ntree->active_socket_panel >= 0 &&
ntree->active_socket_panel < ntree->socket_panels_num)
{
panel = &ntree->socket_panels_array[ntree->active_socket_panel];
panel = ntree->socket_panels_array[ntree->active_socket_panel];
}
PointerRNA r_ptr;
@ -3421,7 +3410,7 @@ static void rna_NodeTree_active_socket_panel_set(PointerRNA *ptr,
{
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
bNodeTree *ntree = (bNodeTree *)ptr->data;
ntree->active_socket_panel = panel - ntree->socket_panels_array;
ntree->active_socket_panel = ntreeGetSocketPanelIndex(ntree, panel);
}
/* ******** Node Types ******** */