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 55 additions and 139 deletions
Showing only changes of commit 284a6bd094 - Show all commits

View File

@ -590,9 +590,10 @@ void ntreeClearSocketPanels(bNodeTree *ntree);
/**
* Move a socket panel up or down in the node tree.
* \param index: Index to which to move the panel.
* \param from_index: Current index of the poanel to move.
* \param to_index: Index to which to move the panel.
*/
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index);
void ntreeMoveSocketPanel(bNodeTree *ntree, int from_index, int to_index);
/** \} */

View File

@ -516,16 +516,6 @@ inline blender::Span<bNode *> bNodeTree::root_frames() const
return this->runtime->root_frames;
}
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()
{
return blender::MutableSpan(socket_panels_array, socket_panels_num);
}
/* -------------------------------------------------------------------- */
/** \name #bNode Inline Methods
* \{ */

View File

@ -643,10 +643,9 @@ 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);
LISTBASE_FOREACH (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 +868,9 @@ 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_list(reader, &ntree->socket_panels);
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
BLO_read_data_address(reader, &panel->name);
}
/* TODO: should be dealt by new generic cache handling of IDs... */
@ -3682,25 +3681,27 @@ 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 = (panel == nullptr ? -1 : BLI_findindex(&ntree->socket_panels, 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 = panel == nullptr ? -1 : BLI_findindex(&ntree->socket_panels, 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 = static_cast<bNodeSocketPanel *>(
BLI_findlink(&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 = static_cast<bNodeSocketPanel *>(
BLI_findlink(&ntree->socket_panels, iosock->panel_id));
iosock->panel_id = panel->identifier;
}
}
}
@ -3818,9 +3819,9 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
{
for (bNodeSocketPanel &panel : ntree->socket_panels_for_write()) {
if (panel.identifier == id) {
return &panel;
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
if (panel->identifier == id) {
return panel;
}
}
return nullptr;
@ -3828,111 +3829,53 @@ 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__);
++ntree->socket_panels_num;
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++};
MEM_SAFE_FREE(old_panels_array);
bNodeSocketPanel *new_panel = MEM_cnew<bNodeSocketPanel>(__func__);
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.
new_panel->name = BLI_strdup(name);
new_panel->flag = flag;
new_panel->identifier = ntree->next_socket_panel_identifier++;
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());`
BLI_addtail(&ntree->socket_panels, new_panel);
/* 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)
{
if (!blender::IndexRange(ntree->socket_panels().size() + 1).contains(index)) {
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__);
++ntree->socket_panels_num;
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++};
MEM_SAFE_FREE(old_panels_array);
bNodeSocketPanel *new_panel = MEM_cnew<bNodeSocketPanel>(__func__);
new_panel->name = BLI_strdup(name);
new_panel->flag = flag;
new_panel->identifier = ntree->next_socket_panel_identifier++;
bNodeSocketPanel *panel_after = static_cast<bNodeSocketPanel *>(
BLI_findlink(&ntree->socket_panels, index));
BLI_insertlinkbefore(&ntree->socket_panels, panel_after, new_panel);
/* 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)) {
return;
if (BLI_remlink_safe(&ntree->socket_panels, panel)) {
MEM_SAFE_FREE(panel->name);
MEM_delete(panel);
}
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();
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(old_panels_array);
ntreeEnsureSocketInterfacePanelOrder(ntree);
}
void ntreeClearSocketPanels(bNodeTree *ntree)
{
MEM_SAFE_FREE(ntree->socket_panels_array);
ntree->socket_panels_array = nullptr;
ntree->socket_panels_num = 0;
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
MEM_SAFE_FREE(panel->name);
}
BLI_freelistN(&ntree->socket_panels);
/* No need to sort sockets, only null panel exists, relative order remains unchanged. */
}
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index)
void ntreeMoveSocketPanel(bNodeTree *ntree, int from_index, int to_index)
{
if (!ntree->socket_panels().contains_ptr(panel)) {
return;
if (BLI_listbase_move_index(&ntree->socket_panels, from_index, to_index)) {
ntreeEnsureSocketInterfacePanelOrder(ntree);
}
const MutableSpan<bNodeSocketPanel> panels = ntree->socket_panels_for_write();
const int old_index = panel - ntree->socket_panels_array;
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];
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];
std::copy_backward(
moved_panels.begin(), moved_panels.end(), panels.drop_front(old_index + 1).data());
panels[new_index] = tmp;
}
ntreeEnsureSocketInterfacePanelOrder(ntree);
}
namespace blender::bke {

View File

@ -536,6 +536,8 @@ typedef struct bNodeLink {
/** Panel in node tree for grouping sockets. */
typedef struct bNodeSocketPanel {
struct bNodeSocketPanel *next, *prev;
char *name;
int flag;
int identifier;
@ -605,11 +607,9 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
/* UI panels for sockets */
struct bNodeSocketPanel *socket_panels_array;
int socket_panels_num;
ListBase socket_panels;
int active_socket_panel;
int next_socket_panel_identifier;
char _pad2[4];
bNodeTreeRuntimeHandle *runtime;
@ -674,9 +674,6 @@ typedef struct bNodeTree {
/** Inputs and outputs of the entire node group. */
blender::Span<const bNodeSocket *> interface_inputs() const;
blender::Span<const bNodeSocket *> interface_outputs() const;
blender::Span<bNodeSocketPanel> socket_panels() const;
blender::MutableSpan<bNodeSocketPanel> socket_panels_for_write();
#endif
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`
} 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 && BLI_findindex(&ntree->socket_panels, panel) < 0) {
BKE_report(reports, RPT_ERROR, "Panel is not in the node tree interface");
return;
}
ntreeSetSocketInterfacePanel(ntree, socket, panel);
@ -3207,8 +3204,7 @@ static bool rna_NodeSocketInterface_panel_poll(PointerRNA *ptr, PointerRNA value
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 int64_t index = panel - ntree->socket_panels_array;
if (index < 0 || index >= ntree->socket_panels_num) {
if (BLI_findindex(&ntree->socket_panels, panel) < 0) {
return false;
}
@ -3387,13 +3383,7 @@ static void rna_NodeTree_socket_panels_move(bNodeTree *ntree,
int from_index,
int to_index)
{
if (from_index < 0 || from_index >= ntree->socket_panels_num || to_index < 0 ||
to_index >= ntree->socket_panels_num)
{
return;
}
ntreeMoveSocketPanel(ntree, &ntree->socket_panels_array[from_index], to_index);
ntreeMoveSocketPanel(ntree, from_index, to_index);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
@ -3403,12 +3393,7 @@ static void rna_NodeTree_socket_panels_move(bNodeTree *ntree,
static PointerRNA rna_NodeTree_active_socket_panel_get(PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->data;
bNodeSocketPanel *panel = NULL;
if (ntree->active_socket_panel >= 0 &&
ntree->active_socket_panel < ntree->socket_panels_num)
{
panel = &ntree->socket_panels_array[ntree->active_socket_panel];
}
bNodeSocketPanel *panel = BLI_findlink(&ntree->socket_panels, ntree->active_socket_panel);
PointerRNA r_ptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocketPanel, panel, &r_ptr);
@ -3421,7 +3406,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 = BLI_findindex(&ntree->socket_panels, panel);
}
/* ******** Node Types ******** */
@ -13350,7 +13335,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "socket_panels", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "socket_panels_array", "socket_panels_num");
RNA_def_property_collection_sdna(prop, NULL, "socket_panels", NULL);
RNA_def_property_struct_type(prop, "NodeSocketPanel");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(