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
11 changed files with 276 additions and 296 deletions
Showing only changes of commit f172423441 - Show all commits

View File

@ -244,7 +244,7 @@ class NODE_OT_tree_path_parent(Operator):
return {'FINISHED'}
class NodeSocketCategoryOperator():
class NodeSocketPanelOperator():
@classmethod
def poll(cls, context):
snode = context.space_data
@ -258,48 +258,48 @@ class NodeSocketCategoryOperator():
return True
class NODE_OT_socket_category_add(NodeSocketCategoryOperator, Operator):
'''Add a new socket category to the tree'''
bl_idname = "node.function_parameter_add"
bl_label = "Add Socket Category"
class NODE_OT_socket_panel_add(NodeSocketPanelOperator, Operator):
'''Add a new socket panel to the tree'''
bl_idname = "node.socket_panel_add"
bl_label = "Add Socket Panel"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
snode = context.space_data
tree = snode.edit_tree
categories = tree.socket_categories
panels = tree.socket_panels
# Remember index to move the item.
LukasTonne marked this conversation as resolved Outdated

Period at the end of the comment.

Period at the end of the comment.
dst_index = min(categories.active_index + 1, len(categories))
categories.new("Category")
categories.move(len(categories) - 1, dst_index)
categories.active_index = dst_index
dst_index = min(panels.active_index + 1, len(panels))
panels.new("Panel")
panels.move(len(panels) - 1, dst_index)
panels.active_index = dst_index
return {'FINISHED'}
class NODE_OT_socket_category_remove(NodeSocketCategoryOperator, Operator):
'''Remove a socket category from the tree'''
bl_idname = "node.function_parameter_remove"
bl_label = "Remove Socket Category"
class NODE_OT_socket_panel_remove(NodeSocketPanelOperator, Operator):
'''Remove a socket panel from the tree'''
bl_idname = "node.socket_panel_remove"
bl_label = "Remove Socket Panel"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
snode = context.space_data
tree = snode.edit_tree
categories = tree.socket_categories
panels = tree.socket_panels
if categories.active:
categories.remove(categories.active)
categories.active_index = min(categories.active_index, len(categories) - 1)
if panels.active:
panels.remove(panels.active)
panels.active_index = min(panels.active_index, len(panels) - 1)
return {'FINISHED'}
class NODE_OT_socket_category_move(NodeSocketCategoryOperator, Operator):
'''Move a socket category to another position'''
bl_idname = "node.function_parameter_move"
bl_label = "Move Socket Category"
class NODE_OT_socket_panel_move(NodeSocketPanelOperator, Operator):
'''Move a socket panel to another position'''
bl_idname = "node.socket_panel_move"
bl_label = "Move Socket Panel"
bl_options = {'REGISTER', 'UNDO'}
direction: EnumProperty(
@ -311,14 +311,14 @@ class NODE_OT_socket_category_move(NodeSocketCategoryOperator, Operator):
def execute(self, context):
snode = context.space_data
tree = snode.edit_tree
categories = tree.socket_categories
panels = tree.socket_panels
if self.direction == 'UP' and categories.active_index > 0:
categories.move(categories.active_index, categories.active_index - 1)
categories.active_index -= 1
elif self.direction == 'DOWN' and categories.active_index < len(categories) - 1:
categories.move(categories.active_index, categories.active_index + 1)
categories.active_index += 1
if self.direction == 'UP' and panels.active_index > 0:
panels.move(panels.active_index, panels.active_index - 1)
panels.active_index -= 1
elif self.direction == 'DOWN' and panels.active_index < len(panels) - 1:
panels.move(panels.active_index, panels.active_index + 1)
panels.active_index += 1
return {'FINISHED'}
@ -329,8 +329,8 @@ classes = (
NODE_OT_add_node,
NODE_OT_add_simulation_zone,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_socket_category_add,
NODE_OT_socket_category_remove,
NODE_OT_socket_category_move,
NODE_OT_socket_panel_add,
NODE_OT_socket_panel_remove,
NODE_OT_socket_panel_move,
NODE_OT_tree_path_parent,
)

View File

@ -954,17 +954,17 @@ class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel):
self.draw_socket_list(context, "OUT", "outputs", "active_output")
class NODE_UL_socket_categories(bpy.types.UIList):
class NODE_UL_socket_panels(bpy.types.UIList):
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index):
row = layout.row(align=True)
row.prop(item, "name", text="", emboss=False, icon_value=icon)
class NODE_PT_socket_categories(Panel):
class NODE_PT_socket_panels(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Group"
bl_label = "Socket Categories"
bl_label = "Socket Panels"
@classmethod
def poll(cls, context):
@ -986,30 +986,30 @@ class NODE_PT_socket_categories(Panel):
split = layout.row()
split.template_list(
"NODE_UL_socket_categories",
"NODE_UL_socket_panels",
"",
tree,
"socket_categories",
tree.socket_categories,
"socket_panels",
tree.socket_panels,
"active_index")
ops_col = split.column()
add_remove_col = ops_col.column(align=True)
add_remove_col.operator("node.function_parameter_add", icon='ADD', text="")
add_remove_col.operator("node.function_parameter_remove", icon='REMOVE', text="")
add_remove_col.operator("node.socket_panel_add", icon='ADD', text="")
add_remove_col.operator("node.socket_panel_remove", icon='REMOVE', text="")
ops_col.separator()
up_down_col = ops_col.column(align=True)
props = up_down_col.operator("node.function_parameter_move", icon='TRIA_UP', text="")
props = up_down_col.operator("node.socket_panel_move", icon='TRIA_UP', text="")
props.direction = 'UP'
props = up_down_col.operator("node.function_parameter_move", icon='TRIA_DOWN', text="")
props = up_down_col.operator("node.socket_panel_move", icon='TRIA_DOWN', text="")
props.direction = 'DOWN'
active_category = tree.socket_categories.active
if active_category is not None:
layout.prop(active_category, "name")
active_panel = tree.socket_panels.active
if active_panel is not None:
layout.prop(active_panel, "name")

I know I started this with the socket list, but I'm regretting it now. Maybe we can skip exposing the name property separate from the list. It should be clear that you can rename in the list.

I know I started this with the socket list, but I'm regretting it now. Maybe we can skip exposing the name property separate from the list. It should be clear that you can rename in the list.

Not sure, we may want to add more settings to categories, such as options to close categories by default, doc strings, etc.

Not sure, we may want to add more settings to categories, such as options to close categories by default, doc strings, etc.

Ideally i'd like to display the node tree declarations in a way that resembles the final node output, to make it more intuitive. The vertical UI layout of the node editor sidebar makes that a bit challenging. But lets say we could arrange it any way we like, then you'd have inputs on the left and outputs on the right. Categories would show in a kind of tree view matching the panels in modifiers. Socket details and category details would be displayed close to active element.

Ideally i'd like to display the node tree declarations in a way that resembles the final node output, to make it more intuitive. The vertical UI layout of the node editor sidebar makes that a bit challenging. But lets say we could arrange it any way we like, then you'd have inputs on the left and outputs on the right. Categories would show in a kind of tree view matching the panels in modifiers. Socket details and category details would be displayed close to active element. ![](/attachments/b3fb4846-83b0-4d4b-b172-097ff3be0091)

Hmm, all I mean is that there's no need to have the separate name property outside of the list. Not that displaying more options doesn't make sense.

For he other stuff, the inputs and outputs used to be side-by-side, but it doesn't work well with Blender's single-column UI layout paradigm. But that can be discussed more later.

Hmm, all I mean is that there's no need to have the separate name property outside of the list. Not that displaying more options doesn't make sense. For he other stuff, the inputs and outputs used to be side-by-side, but it doesn't work well with Blender's single-column UI layout paradigm. But that can be discussed more later.
class NODE_UL_simulation_zone_items(bpy.types.UIList):
@ -1155,8 +1155,8 @@ classes = (
NODE_UL_interface_sockets,
NODE_PT_node_tree_interface_inputs,
NODE_PT_node_tree_interface_outputs,
NODE_UL_socket_categories,
NODE_PT_socket_categories,
NODE_UL_socket_panels,
NODE_PT_socket_panels,
NODE_UL_simulation_zone_items,
NODE_PT_simulation_zone_items,

View File

@ -542,8 +542,8 @@ void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree);
/** \name Node Tree Interface
* \{ */
/** Run this after relevant changes to categories to ensure sockets remain sorted by category. */
void ntreeEnsureSocketCategoryOrder(bNodeTree *ntree);
/** Run this after relevant changes to panels to ensure sockets remain sorted by panel. */
void ntreeEnsureSocketInterfacePanelOrder(bNodeTree *ntree);
LukasTonne marked this conversation as resolved Outdated

This comment fits on one line

This comment fits on one line
Review

This is currently in the public API because the NODE_OT_tree_socket_move operator works directly on DNA and needs to call this after it moves sockets. That operator should also use an API method so the update function does not need to be exposed. I suggest a separate fix.

This is currently in the public API because the `NODE_OT_tree_socket_move` operator works directly on DNA and needs to call this after it moves sockets. That operator should also use an API method so the update function does not need to be exposed. I suggest a separate fix.
void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock);
@ -552,52 +552,47 @@ struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree,
const char *idname,
const char *name);
/** Set the category of the interface socket. */
void ntreeSetSocketInterfaceCategory(bNodeTree *ntree,
bNodeSocket *sock,
bNodeSocketCategory *category);
/** Set the panel of the interface socket. */
void ntreeSetSocketInterfacePanel(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketPanel *panel);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Tree Socket Categories
/** \name Node Tree Socket Panels
* \{ */
/**
* Find a socket category by its unique ID.
* \param id: Unique ID of the category within the node tree.
* Find a socket panel by its unique ID.
* \param id: Unique ID of the panel within the node tree.
*/
bNodeSocketCategory *ntreeFindSocketCategoryByID(bNodeTree *ntree, int id);
bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id);
/**
* Add a new socket category to the node tree.
* \param name: Name of the new category.
* \param flag: Flags of the new category.
* Add a new socket panel to 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:`
* \param name: Name of the new panel.
* \param flag: Flags of the new panel.
*/
bNodeSocketCategory *ntreeAddSocketCategory(bNodeTree *ntree, const char *name, int flag);
bNodeSocketPanel *ntreeAddSocketPanel(bNodeTree *ntree, const char *name, int flag);
/**
* Insert a new socket category in the node tree.
* \param name: Name of the new category.
* \param flag: Flags of the new category.
* \param index: Index at which to insert the category.
* Insert a new socket panel in the node tree.
* \param name: Name of the new panel.
* \param flag: Flags of the new panel.
* \param index: Index at which to insert the panel.
*/
bNodeSocketCategory *ntreeInsertSocketCategory(bNodeTree *ntree,
const char *name,
int flag,
int index);
bNodeSocketPanel *ntreeInsertSocketPanel(bNodeTree *ntree, const char *name, int flag, int index);
/** Remove a socket category from the node tree. */
void ntreeRemoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category);
/** Remove a socket panel from the node tree. */
void ntreeRemoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel);
/** Remove all socket categories from the node tree. */
void ntreeClearSocketCategories(bNodeTree *ntree);
/** Remove all socket panels from the node tree. */
void ntreeClearSocketPanels(bNodeTree *ntree);
/**
* Move a socket category up or down in the node tree.
* \param index: Index to which to move the category.
* Move a socket panel up or down in the node tree.
* \param index: Index to which to move the panel.
*/
void ntreeMoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category, int new_index);
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index);
/** \} */

View File

@ -516,18 +516,16 @@ inline blender::Span<bNode *> bNodeTree::root_frames() const
return this->runtime->root_frames;
}
inline blender::Span<bNodeSocketCategory> bNodeTree::socket_categories() const
inline blender::Span<bNodeSocketPanel> bNodeTree::socket_panels() const
{
return blender::Span(socket_categories_array, socket_categories_num);
return blender::Span(socket_panels_array, socket_panels_num);
}
inline blender::MutableSpan<bNodeSocketCategory> bNodeTree::socket_categories_for_write()
inline blender::MutableSpan<bNodeSocketPanel> bNodeTree::socket_panels_for_write()
{
return blender::MutableSpan(socket_categories_array, socket_categories_num);
return blender::MutableSpan(socket_panels_array, socket_panels_num);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #bNode Inline Methods
* \{ */

View File

@ -646,9 +646,9 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
BLO_write_struct_array(
writer, bNodeSocketCategory, ntree->socket_categories_num, ntree->socket_categories_array);
for (const bNodeSocketCategory &category : ntree->socket_categories()) {
BLO_write_string(writer, category.name);
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);
@ -871,9 +871,9 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &link->tosock);
}
BLO_read_data_address(reader, &ntree->socket_categories_array);
for (bNodeSocketCategory &category : ntree->socket_categories_for_write()) {
BLO_read_data_address(reader, &category.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... */
@ -3661,16 +3661,16 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
STRNCPY(sock->name, name);
sock->storage = nullptr;
sock->flag |= SOCK_COLLAPSED;
sock->category_id = -1;
sock->panel_id = -1;
return sock;
}
static int node_socket_category_cmp(const void *a, const void *b)
static int node_socket_panel_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_id > sock_b->category_id) ? 1 : 0;
return (sock_a->panel_id > sock_b->panel_id) ? 1 : 0;
}
bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree,
@ -3688,32 +3688,30 @@ bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree,
} // namespace blender::bke
void ntreeEnsureSocketCategoryOrder(bNodeTree *ntree)
void ntreeEnsureSocketInterfacePanelOrder(bNodeTree *ntree)
{
/* XXX Hack: store category index in category_id temporarily for sorting. */
/* XXX Hack: store panel index in panel_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);
const bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, iosock->panel_id);
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_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);
const bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, iosock->panel_id);
iosock->panel_id = panel == nullptr ? -1 : (int)(panel - ntree->socket_panels_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. */
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->category_id >= 0) {
const bNodeSocketCategory &category = ntree->socket_categories()[iosock->category_id];
iosock->category_id = category.identifier;
if (iosock->panel_id >= 0) {
const bNodeSocketPanel &panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel.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;
if (iosock->panel_id >= 0) {
const bNodeSocketPanel &panel = ntree->socket_panels()[iosock->panel_id];
iosock->panel_id = panel.identifier;
}
}
}
@ -3731,24 +3729,22 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
BLI_addtail(&ntree->outputs, iosock);
}
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
BKE_ntree_update_tag_interface(ntree);
return iosock;
}
void ntreeSetSocketInterfaceCategory(bNodeTree *ntree,
bNodeSocket *socket,
bNodeSocketCategory *category)
void ntreeSetSocketInterfacePanel(bNodeTree *ntree, bNodeSocket *socket, bNodeSocketPanel *panel)
{
if (category == NULL) {
socket->category_id = -1;
if (panel == NULL) {
socket->panel_id = -1;
return;
}
socket->category_id = category->identifier;
socket->panel_id = panel->identifier;
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
BKE_ntree_update_tag_interface(ntree);
}
@ -3769,7 +3765,7 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
}
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
BKE_ntree_update_tag_interface(ntree);
return iosock;
@ -3826,138 +3822,128 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
blender::bke::node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
/* No need to resort by category, removing doesn't change anything. */
/* No need to resort by panel, removing doesn't change anything. */
BKE_ntree_update_tag_interface(ntree);
}
bNodeSocketCategory *ntreeFindSocketCategoryByID(bNodeTree *ntree, int id)
bNodeSocketPanel *ntreeFindSocketPanelByID(bNodeTree *ntree, int id)
{
for (bNodeSocketCategory &category : ntree->socket_categories_for_write()) {
if (category.identifier == id) {
return &category;
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;
}
bNodeSocketCategory *ntreeAddSocketCategory(bNodeTree *ntree, const char *name, int flag)
bNodeSocketPanel *ntreeAddSocketPanel(bNodeTree *ntree, const char *name, int flag)
{
bNodeSocketCategory *old_categories_array = ntree->socket_categories_array;
const Span<bNodeSocketCategory> old_categories = ntree->socket_categories();
ntree->socket_categories_array = MEM_cnew_array<bNodeSocketCategory>(
ntree->socket_categories_num + 1, __func__);
++ntree->socket_categories_num;
const MutableSpan<bNodeSocketCategory> new_categories = ntree->socket_categories_for_write();
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_categories.begin(), old_categories.end(), new_categories.data());
bNodeSocketCategory &new_category = new_categories[new_categories.size() - 1];
new_category = {BLI_strdup(name), flag, ntree->next_socket_category_identifier++};
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_categories_array);
MEM_SAFE_FREE(old_panels_array);
/* No need to sort sockets, nothing is using the new category yet */
/* No need to sort sockets, nothing is using the new panel yet */
return &new_category;
return &new_panel;
}
bNodeSocketCategory *ntreeInsertSocketCategory(bNodeTree *ntree,
const char *name,
int flag,
int index)
bNodeSocketPanel *ntreeInsertSocketPanel(bNodeTree *ntree, const char *name, int flag, int index)
{
if (!blender::IndexRange(ntree->socket_categories().size() + 1).contains(index)) {
if (!blender::IndexRange(ntree->socket_panels().size() + 1).contains(index)) {
return nullptr;
}
bNodeSocketCategory *old_categories_array = ntree->socket_categories_array;
const Span<bNodeSocketCategory> old_categories = ntree->socket_categories();
ntree->socket_categories_array = MEM_cnew_array<bNodeSocketCategory>(
ntree->socket_categories_num + 1, __func__);
++ntree->socket_categories_num;
const MutableSpan<bNodeSocketCategory> new_categories = ntree->socket_categories_for_write();
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_categories_front = old_categories.take_front(index);
Span old_categories_back = old_categories.drop_front(index);
std::copy(old_categories_front.begin(), old_categories_front.end(), new_categories.data());
std::copy(old_categories_back.begin(),
old_categories_back.end(),
new_categories.drop_front(index + 1).data());
bNodeSocketCategory &new_category = new_categories[index];
new_category = {BLI_strdup(name), flag, ntree->next_socket_category_identifier++};
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_categories_array);
MEM_SAFE_FREE(old_panels_array);
/* No need to sort sockets, nothing is using the new category yet */
/* No need to sort sockets, nothing is using the new panel yet */
return &new_category;
return &new_panel;
}
void ntreeRemoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category)
void ntreeRemoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel)
{
const int index = category - ntree->socket_categories_array;
if (!ntree->socket_categories().contains_ptr(category)) {
const int index = panel - ntree->socket_panels_array;
if (!ntree->socket_panels().contains_ptr(panel)) {
return;
}
bNodeSocketCategory *old_categories_array = ntree->socket_categories_array;
const Span<bNodeSocketCategory> old_categories = ntree->socket_categories();
ntree->socket_categories_array = MEM_cnew_array<bNodeSocketCategory>(
ntree->socket_categories_num - 1, __func__);
--ntree->socket_categories_num;
const MutableSpan<bNodeSocketCategory> new_categories = ntree->socket_categories_for_write();
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_categories_front = old_categories.take_front(index);
Span old_categories_back = old_categories.drop_front(index + 1);
std::copy(old_categories_front.begin(), old_categories_front.end(), new_categories.data());
std::copy(old_categories_back.begin(),
old_categories_back.end(),
new_categories.drop_front(index).data());
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_categories_array);
MEM_SAFE_FREE(old_panels_array);
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
}
void ntreeClearSocketCategories(bNodeTree *ntree)
void ntreeClearSocketPanels(bNodeTree *ntree)
{
MEM_SAFE_FREE(ntree->socket_categories_array);
ntree->socket_categories_array = nullptr;
ntree->socket_categories_num = 0;
MEM_SAFE_FREE(ntree->socket_panels_array);
ntree->socket_panels_array = nullptr;
ntree->socket_panels_num = 0;
/* No need to sort sockets, only null category exists, relative order remains unchanged. */
/* No need to sort sockets, only null panel exists, relative order remains unchanged. */
}
void ntreeMoveSocketCategory(bNodeTree *ntree, bNodeSocketCategory *category, int new_index)
void ntreeMoveSocketPanel(bNodeTree *ntree, bNodeSocketPanel *panel, int new_index)
{
if (!ntree->socket_categories().contains_ptr(category)) {
if (!ntree->socket_panels().contains_ptr(panel)) {
return;
}
const MutableSpan<bNodeSocketCategory> categories = ntree->socket_categories_for_write();
const int old_index = category - ntree->socket_categories_array;
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<bNodeSocketCategory> moved_categories = categories.slice(old_index + 1,
new_index - old_index);
const bNodeSocketCategory tmp = categories[old_index];
std::copy(
moved_categories.begin(), moved_categories.end(), categories.drop_front(old_index).data());
categories[new_index] = tmp;
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<bNodeSocketCategory> moved_categories = categories.slice(new_index,
old_index - new_index);
const bNodeSocketCategory tmp = categories[old_index];
std::copy_backward(moved_categories.begin(),
moved_categories.end(),
categories.drop_front(old_index + 1).data());
categories[new_index] = tmp;
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;
}
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
}
namespace blender::bke {

View File

@ -150,13 +150,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_id")) {
if (!DNA_struct_elem_find(fd->filesdna, "bNodeSocket", "int", "panel_id")) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
socket->category_id = -1;
socket->panel_id = -1;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
socket->category_id = -1;
socket->panel_id = -1;
}
}
FOREACH_NODETREE_END;

View File

@ -1481,7 +1481,7 @@ static void std_node_socket_interface_draw(bContext * /*C*/, uiLayout *layout, P
uiItemR(col, ptr, "hide_in_modifier", DEFAULT_FLAGS, nullptr, 0);
}
uiItemPointerR(col, ptr, "category", &tree_ptr, "socket_categories", nullptr, 0);
uiItemPointerR(col, ptr, "panel", &tree_ptr, "socket_panels", nullptr, 0);
}
static void node_socket_virtual_draw_color(bContext * /*C*/,

View File

@ -2191,8 +2191,8 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
ntree, in_out, active_sock->idname, active_sock->next, active_sock->name);
/* 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_id = active_sock->category_id;
/* Inherit socket panel from the active socket interface. */
sock->panel_id = active_sock->panel_id;
}
else {
/* XXX TODO: define default socket type for a tree! */
@ -2584,7 +2584,7 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
}
}
ntreeEnsureSocketCategoryOrder(ntree);
ntreeEnsureSocketInterfacePanelOrder(ntree);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);

View File

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

View File

@ -168,8 +168,8 @@ typedef struct bNodeSocket {
/** Custom data for inputs, only UI writes in this. */
bNodeStack ns DNA_DEPRECATED;
/* ID of the UI category of the socket. */
int category_id;
/* ID of the UI panel of the socket. */
int panel_id;
int _pad2;
bNodeSocketRuntimeHandle *runtime;
@ -535,11 +535,12 @@ typedef struct bNodeLink {
#define NTREE_CHUNKSIZE_512 512
#define NTREE_CHUNKSIZE_1024 1024
typedef struct bNodeSocketCategory {
/** Panel in node tree for grouping sockets. */
typedef struct bNodeSocketPanel {
char *name;
int flag;
int identifier;
} bNodeSocketCategory;
} bNodeSocketPanel;
/* the basis for a Node tree, all links and nodes reside internal here */
/* only re-usable node trees are in the library though,
@ -604,11 +605,11 @@ typedef struct bNodeTree {
/** Image representing what the node group does. */
struct PreviewImage *preview;
/* UI categories for sockets */
struct bNodeSocketCategory *socket_categories_array;
int socket_categories_num;
int active_socket_category;
int next_socket_category_identifier;
/* UI panels for sockets */
struct bNodeSocketPanel *socket_panels_array;
int socket_panels_num;
int active_socket_panel;
int next_socket_panel_identifier;
char _pad2[4];
bNodeTreeRuntimeHandle *runtime;
@ -675,8 +676,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<bNodeSocketCategory> socket_categories() const;
blender::MutableSpan<bNodeSocketCategory> socket_categories_for_write();
blender::Span<bNodeSocketPanel> socket_panels() const;
blender::MutableSpan<bNodeSocketPanel> socket_panels_for_write();
#endif
} bNodeTree;

View File

@ -3164,46 +3164,46 @@ static IDProperty **rna_NodeSocketInterface_idprops(PointerRNA *ptr)
return &sock->prop;
}
static PointerRNA rna_NodeSocketInterface_category_get(PointerRNA *ptr)
static PointerRNA rna_NodeSocketInterface_panel_get(PointerRNA *ptr)
{
bNodeSocket *socket = (bNodeSocket *)ptr->data;
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketCategory *category = ntreeFindSocketCategoryByID(ntree, socket->category_id);
bNodeSocketPanel *panel = ntreeFindSocketPanelByID(ntree, socket->panel_id);
PointerRNA r_ptr;
RNA_pointer_create(&ntree->id, &RNA_NodeSocketCategory, category, &r_ptr);
RNA_pointer_create(&ntree->id, &RNA_NodeSocketPanel, panel, &r_ptr);
return r_ptr;
}
static void rna_NodeSocketInterface_category_set(PointerRNA *ptr,
static void rna_NodeSocketInterface_panel_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *reports)
{
bNodeSocket *socket = (bNodeSocket *)ptr->data;
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketCategory *category = (bNodeSocketCategory *)value.data;
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
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");
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;
}
}
ntreeSetSocketInterfaceCategory(ntree, socket, category);
ntreeSetSocketInterfacePanel(ntree, socket, panel);
}
static bool rna_NodeSocketInterface_category_poll(PointerRNA *ptr, PointerRNA value)
static bool rna_NodeSocketInterface_panel_poll(PointerRNA *ptr, PointerRNA value)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocketCategory *category = (bNodeSocketCategory *)value.data;
if (category == NULL) {
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
if (panel == NULL) {
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 = category - ntree->socket_categories_array;
if (index < 0 || index >= ntree->socket_categories_num) {
const int64_t index = panel - ntree->socket_panels_array;
if (index < 0 || index >= ntree->socket_panels_num) {
return false;
}
@ -3329,24 +3329,24 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C,
DEG_relations_tag_update(bmain);
}
/* ******** Node Socket Categories ******** */
/* ******** Node Socket Panels ******** */
static void rna_NodeSocketCategory_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
static void rna_NodeSocketPanel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bNodeSocketCategory *rna_NodeTree_socket_categories_new(bNodeTree *ntree,
static bNodeSocketPanel *rna_NodeTree_socket_panels_new(bNodeTree *ntree,
Main *bmain,
ReportList *reports,
const char *name)
{
bNodeSocketCategory *category = ntreeAddSocketCategory(ntree, name, 0);
bNodeSocketPanel *panel = ntreeAddSocketPanel(ntree, name, 0);
if (category == NULL) {
BKE_report(reports, RPT_ERROR, "Unable to create socket category");
if (panel == NULL) {
BKE_report(reports, RPT_ERROR, "Unable to create socket panel");
}
else {
BKE_ntree_update_tag_interface(ntree);
@ -3354,69 +3354,69 @@ static bNodeSocketCategory *rna_NodeTree_socket_categories_new(bNodeTree *ntree,
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return category;
return panel;
}
static void rna_NodeTree_socket_categories_remove(bNodeTree *ntree,
static void rna_NodeTree_socket_panels_remove(bNodeTree *ntree,
Main *bmain,
bNodeSocketCategory *category)
bNodeSocketPanel *panel)
{
ntreeRemoveSocketCategory(ntree, category);
ntreeRemoveSocketPanel(ntree, panel);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static void rna_NodeTree_socket_categories_clear(bNodeTree *ntree, Main *bmain)
static void rna_NodeTree_socket_panels_clear(bNodeTree *ntree, Main *bmain)
{
ntreeClearSocketCategories(ntree);
ntreeClearSocketPanels(ntree);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static void rna_NodeTree_socket_categories_move(bNodeTree *ntree,
static void rna_NodeTree_socket_panels_move(bNodeTree *ntree,
Main *bmain,
int from_index,
int to_index)
{
if (from_index < 0 || from_index >= ntree->socket_categories_num || to_index < 0 ||
to_index >= ntree->socket_categories_num)
if (from_index < 0 || from_index >= ntree->socket_panels_num || to_index < 0 ||
to_index >= ntree->socket_panels_num)
{
return;
}
ntreeMoveSocketCategory(ntree, &ntree->socket_categories_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);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static PointerRNA rna_NodeTree_active_socket_category_get(PointerRNA *ptr)
static PointerRNA rna_NodeTree_active_socket_panel_get(PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->data;
bNodeSocketCategory *category = NULL;
if (ntree->active_socket_category >= 0 &&
ntree->active_socket_category < ntree->socket_categories_num)
bNodeSocketPanel *panel = NULL;
if (ntree->active_socket_panel >= 0 &&
ntree->active_socket_panel < ntree->socket_panels_num)
{
category = &ntree->socket_categories_array[ntree->active_socket_category];
panel = &ntree->socket_panels_array[ntree->active_socket_panel];
}
PointerRNA r_ptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocketCategory, category, &r_ptr);
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocketPanel, panel, &r_ptr);
return r_ptr;
}
static void rna_NodeTree_active_socket_category_set(PointerRNA *ptr,
static void rna_NodeTree_active_socket_panel_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
{
bNodeSocketCategory *category = (bNodeSocketCategory *)value.data;
bNodeSocketPanel *panel = (bNodeSocketPanel *)value.data;
bNodeTree *ntree = (bNodeTree *)ptr->data;
ntree->active_socket_category = category - ntree->socket_categories_array;
ntree->active_socket_panel = panel - ntree->socket_panels_array;
}
/* ******** Node Types ******** */
@ -11746,16 +11746,16 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
"Don't show the input value in the geometry nodes modifier interface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
prop = RNA_def_property(srna, "category", PROP_POINTER, PROP_NONE);
prop = RNA_def_property(srna, "panel", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop,
"rna_NodeSocketInterface_category_get",
"rna_NodeSocketInterface_category_set",
"rna_NodeSocketInterface_panel_get",
"rna_NodeSocketInterface_panel_set",
NULL,
"rna_NodeSocketInterface_category_poll");
RNA_def_property_struct_type(prop, "NodeSocketCategory");
"rna_NodeSocketInterface_panel_poll");
RNA_def_property_struct_type(prop, "NodeSocketPanel");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Socket Category", "Category to group sockets together in the UI");
prop, "Socket Panel", "Panel to group sockets together in the UI");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
@ -13026,21 +13026,21 @@ static void rna_def_node_link(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Hidden", "Link is hidden due to invisible sockets");
}
static void rna_def_node_socket_category(BlenderRNA *brna)
static void rna_def_node_socket_panel(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NodeSocketCategory", NULL);
RNA_def_struct_ui_text(srna, "NodeSocketCategory", "Group of sockets in node tree interface");
RNA_def_struct_sdna(srna, "bNodeSocketCategory");
srna = RNA_def_struct(brna, "NodeSocketPanel", NULL);
RNA_def_struct_ui_text(srna, "NodeSocketPanel", "Group of sockets in node tree interface");
RNA_def_struct_sdna(srna, "bNodeSocketPanel");
RNA_def_struct_ui_icon(srna, ICON_NODE);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Name", "Name of the socket category");
RNA_def_property_ui_text(prop, "Name", "Name of the socket panel");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketCategory_update");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketPanel_update");
}
static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop)
@ -13182,63 +13182,63 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_node_tree_socket_categories_api(BlenderRNA *brna, PropertyRNA *cprop)
static void rna_def_node_tree_socket_panels_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *prop;
PropertyRNA *parm;
FunctionRNA *func;
RNA_def_property_srna(cprop, "NodeSocketCategories");
srna = RNA_def_struct(brna, "NodeSocketCategories", NULL);
RNA_def_property_srna(cprop, "NodeSocketPanels");
srna = RNA_def_struct(brna, "NodeSocketPanels", NULL);
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_text(
srna, "Node Tree Socket Categories", "Collection of socket categories in a node tree");
srna, "Node Tree Socket Panels", "Collection of socket panels in a node tree");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "active_socket_category");
RNA_def_property_ui_text(prop, "Active Index", "Index of the active category");
RNA_def_property_int_sdna(prop, NULL, "active_socket_panel");
RNA_def_property_ui_text(prop, "Active Index", "Index of the active panel");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "NodeSocketCategory");
RNA_def_property_struct_type(prop, "NodeSocketPanel");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop,
"rna_NodeTree_active_socket_category_get",
"rna_NodeTree_active_socket_category_set",
"rna_NodeTree_active_socket_panel_get",
"rna_NodeTree_active_socket_panel_set",
NULL,
NULL);
RNA_def_property_ui_text(prop, "Active", "Active category");
RNA_def_property_ui_text(prop, "Active", "Active panel");
RNA_def_property_update(prop, NC_NODE, NULL);
func = RNA_def_function(srna, "new", "rna_NodeTree_socket_categories_new");
RNA_def_function_ui_description(func, "Add a new socket category to the tree");
func = RNA_def_function(srna, "new", "rna_NodeTree_socket_panels_new");
RNA_def_function_ui_description(func, "Add a new socket panel to the tree");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "category", "NodeSocketCategory", "", "New category");
parm = RNA_def_pointer(func, "panel", "NodeSocketPanel", "", "New panel");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_NodeTree_socket_categories_remove");
RNA_def_function_ui_description(func, "Remove a socket category from the tree");
func = RNA_def_function(srna, "remove", "rna_NodeTree_socket_panels_remove");
RNA_def_function_ui_description(func, "Remove a socket panel from the tree");
RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "category", "NodeSocketCategory", "", "The category to remove");
parm = RNA_def_pointer(func, "panel", "NodeSocketPanel", "", "The panel to remove");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", "rna_NodeTree_socket_categories_clear");
RNA_def_function_ui_description(func, "Remove all categories from the tree");
func = RNA_def_function(srna, "clear", "rna_NodeTree_socket_panels_clear");
RNA_def_function_ui_description(func, "Remove all panels from the tree");
RNA_def_function_flag(func, FUNC_USE_MAIN);
func = RNA_def_function(srna, "move", "rna_NodeTree_socket_categories_move");
RNA_def_function_ui_description(func, "Move a socket category to another position");
func = RNA_def_function(srna, "move", "rna_NodeTree_socket_panels_move");
RNA_def_function_ui_description(func, "Move a socket panel to another position");
RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_int(
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the category to move", 0, 10000);
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the panel to move", 0, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the category", 0, 10000);
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the panel", 0, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
@ -13344,13 +13344,13 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "socket_categories", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "socket_categories_array", "socket_categories_num");
RNA_def_property_struct_type(prop, "NodeSocketCategory");
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_struct_type(prop, "NodeSocketPanel");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Socket Categories", "Socket categories for structuring the node tree interface");
rna_def_node_tree_socket_categories_api(brna, prop);
prop, "Socket Panels", "Socket panels for structuring the node tree interface");
rna_def_node_tree_socket_panels_api(brna, prop);
/* exposed as a function for runtime interface type properties */
func = RNA_def_function(srna, "interface_update", "rna_NodeTree_interface_update");
@ -13622,7 +13622,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_simulation_state_item(brna);
rna_def_function_node(brna);
rna_def_node_socket_category(brna);
rna_def_node_socket_panel(brna);
rna_def_nodetree(brna);
rna_def_node_socket_standard_types(brna);