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

View File

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

View File

@ -516,6 +516,16 @@ 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,9 +643,10 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
write_node_socket_interface(writer, sock);
}
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
BLO_write_struct(writer, bNodeSocketPanel, panel);
BLO_write_string(writer, panel->name);
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);
}
BKE_previewimg_blend_write(writer, ntree->preview);
@ -868,9 +869,9 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &link->tosock);
}
BLO_read_list(reader, &ntree->socket_panels);
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
BLO_read_data_address(reader, &panel->name);
BLO_read_data_address(reader, &ntree->socket_panels_array);
for (bNodeSocketPanel &panel : ntree->socket_panels_for_write()) {
BLO_read_data_address(reader, &panel.name);
}
/* TODO: should be dealt by new generic cache handling of IDs... */
@ -3681,27 +3682,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 : BLI_findindex(&ntree->socket_panels, panel));
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_array);
}
LISTBASE_FOREACH (bNodeSocket *, iosock, &ntree->outputs) {
const bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, iosock->panel_id);
iosock->panel_id = panel == nullptr ? -1 : BLI_findindex(&ntree->socket_panels, panel);
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_array);
}
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 = static_cast<bNodeSocketPanel *>(
BLI_findlink(&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 = static_cast<bNodeSocketPanel *>(
BLI_findlink(&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;
}
}
}
@ -3819,9 +3818,9 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
{
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
if (panel->identifier == id) {
return panel;
for (bNodeSocketPanel &panel : ntree->socket_panels_for_write()) {
if (panel.identifier == id) {
return &panel;
}
}
return nullptr;
@ -3829,53 +3828,111 @@ bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
bNodeSocketPanel *ntreeAddSocketPanel(bNodeTree *ntree, const char *name, int flag)
{
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 *old_panels_array = ntree->socket_panels_array;
const Span<bNodeSocketPanel> old_panels = ntree->socket_panels();
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.
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();
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());`
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);
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)
{
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++;
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 *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)
{
if (BLI_remlink_safe(&ntree->socket_panels, panel)) {
MEM_SAFE_FREE(panel->name);
MEM_delete(panel);
const int index = panel - ntree->socket_panels_array;
if (!ntree->socket_panels().contains_ptr(panel)) {
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__);
--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)
{
LISTBASE_FOREACH (bNodeSocketPanel *, panel, &ntree->socket_panels) {
MEM_SAFE_FREE(panel->name);
}
BLI_freelistN(&ntree->socket_panels);
MEM_SAFE_FREE(ntree->socket_panels_array);
ntree->socket_panels_array = nullptr;
ntree->socket_panels_num = 0;
/* No need to sort sockets, only null panel exists, relative order remains unchanged. */
}
void ntreeMoveSocketPanel(bNodeTree *ntree, int from_index, int to_index)
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index)
{
if (BLI_listbase_move_index(&ntree->socket_panels, from_index, to_index)) {
ntreeEnsureSocketInterfacePanelOrder(ntree);
if (!ntree->socket_panels().contains_ptr(panel)) {
return;
}
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,8 +536,6 @@ typedef struct bNodeLink {
/** Panel in node tree for grouping sockets. */
typedef struct bNodeSocketPanel {
struct bNodeSocketPanel *next, *prev;
char *name;
int flag;
int identifier;
@ -607,9 +605,11 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
/* UI panels for sockets */
ListBase socket_panels;
struct bNodeSocketPanel *socket_panels_array;
int socket_panels_num;
int active_socket_panel;
int next_socket_panel_identifier;
char _pad2[4];
bNodeTreeRuntimeHandle *runtime;
@ -674,6 +674,9 @@ 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;
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();
#endif
} bNodeTree;

View File

@ -3188,9 +3188,12 @@ static void rna_NodeSocketInterface_panel_set(PointerRNA *ptr,
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
if (panel && BLI_findindex(&ntree->socket_panels, panel) < 0) {
BKE_report(reports, RPT_ERROR, "Panel is not in the node tree interface");
return;
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;
}
}
ntreeSetSocketInterfacePanel(ntree, socket, panel);
@ -3204,7 +3207,8 @@ static bool rna_NodeSocketInterface_panel_poll(PointerRNA *ptr, PointerRNA value
return true;
}
if (BLI_findindex(&ntree->socket_panels, panel) < 0) {
const int64_t index = panel - ntree->socket_panels_array;
if (index < 0 || index >= ntree->socket_panels_num) {
return false;
}
@ -3383,7 +3387,13 @@ static void rna_NodeTree_socket_panels_move(bNodeTree *ntree,
int from_index,
int to_index)
{
ntreeMoveSocketPanel(ntree, from_index, 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);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
@ -3393,7 +3403,12 @@ 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 = BLI_findlink(&ntree->socket_panels, ntree->active_socket_panel);
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];
}
PointerRNA r_ptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocketPanel, panel, &r_ptr);
@ -3406,7 +3421,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 = BLI_findindex(&ntree->socket_panels, panel);
ntree->active_socket_panel = panel - ntree->socket_panels_array;
}
/* ******** Node Types ******** */
@ -13335,7 +13350,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", NULL);
RNA_def_property_collection_sdna(prop, NULL, "socket_panels_array", "socket_panels_num");
RNA_def_property_struct_type(prop, "NodeSocketPanel");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(