Nodes: Add dropdown to select group socket subtype #105614
|
@ -889,6 +889,23 @@ class NodeTreeInterfacePanel(Panel):
|
|||
)
|
||||
props.in_out = in_out
|
||||
|
||||
with context.temp_override(interface_socket=active_socket):
|
||||
if bpy.ops.node.tree_socket_change_subtype.poll():
|
||||
layout_row = layout.row(align=True)
|
||||
layout_split = layout_row.split(factor=0.4, align=True)
|
||||
|
||||
label_column = layout_split.column(align=True)
|
||||
label_column.alignment = 'RIGHT'
|
||||
label_column.label(text="Subtype")
|
||||
property_row = layout_split.row(align=True)
|
||||
|
||||
property_row.context_pointer_set("interface_socket", active_socket)
|
||||
props = property_row.operator_menu_enum(
|
||||
"node.tree_socket_change_subtype",
|
||||
"socket_subtype",
|
||||
text=active_socket.bl_subtype_label if active_socket.bl_subtype_label else active_socket.bl_idname
|
||||
)
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
|
|
|
@ -158,6 +158,8 @@ typedef struct bNodeSocketType {
|
|||
char idname[64];
|
||||
/* Type label */
|
||||
char label[64];
|
||||
/* Subtype label */
|
||||
char subtype_label[64];
|
||||
|
||||
void (*draw)(struct bContext *C,
|
||||
struct uiLayout *layout,
|
||||
|
@ -634,6 +636,7 @@ bool nodeIsStaticSocketType(const struct bNodeSocketType *stype);
|
|||
const char *nodeStaticSocketType(int type, int subtype);
|
||||
const char *nodeStaticSocketInterfaceType(int type, int subtype);
|
||||
const char *nodeStaticSocketLabel(int type, int subtype);
|
||||
const char *nodeSocketSubTypeLabel(int subtype);
|
||||
|
||||
/* Helper macros for iterating over node types. */
|
||||
#define NODE_SOCKET_TYPES_BEGIN(stype) \
|
||||
|
|
|
@ -778,6 +778,11 @@ inline const bNodeSocket *bNodeSocket::internal_link_input() const
|
|||
return this->runtime->internal_link_input;
|
||||
}
|
||||
|
||||
template<typename T> T *bNodeSocket::default_value_typed()
|
||||
{
|
||||
return static_cast<T *>(this->default_value);
|
||||
}
|
||||
|
||||
template<typename T> const T *bNodeSocket::default_value_typed() const
|
||||
{
|
||||
return static_cast<const T *>(this->default_value);
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "NOD_common.h"
|
||||
|
@ -1466,6 +1467,15 @@ const char *nodeSocketTypeLabel(const bNodeSocketType *stype)
|
|||
return stype->label[0] != '\0' ? stype->label : RNA_struct_ui_name(stype->ext_socket.srna);
|
||||
}
|
||||
|
||||
const char *nodeSocketSubTypeLabel(int subtype)
|
||||
{
|
||||
const char *name;
|
||||
if (RNA_enum_name(rna_enum_property_subtype_items, subtype, &name)) {
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bNodeSocket *nodeFindSocket(const bNode *node,
|
||||
const eNodeSocketInOut in_out,
|
||||
const char *identifier)
|
||||
|
@ -1673,9 +1683,47 @@ void nodeModifySocketType(bNodeTree *ntree,
|
|||
}
|
||||
|
||||
if (sock->default_value) {
|
||||
socket_id_user_decrement(sock);
|
||||
MEM_freeN(sock->default_value);
|
||||
sock->default_value = nullptr;
|
||||
if (sock->type != socktype->type) {
|
||||
/* Only reallocate the default value if the type changed so that UI data like min and max
|
||||
* isn't removed. This assumes that the default value is stored in the same format for all
|
||||
* socket types with the same #eNodeSocketDatatype. */
|
||||
socket_id_user_decrement(sock);
|
||||
MEM_freeN(sock->default_value);
|
||||
sock->default_value = nullptr;
|
||||
}
|
||||
else {
|
||||
/* Update the socket subtype when the storage isn't freed and recreated. */
|
||||
switch (eNodeSocketDatatype(sock->type)) {
|
||||
case SOCK_FLOAT: {
|
||||
sock->default_value_typed<bNodeSocketValueFloat>()->subtype = socktype->subtype;
|
||||
break;
|
||||
}
|
||||
case SOCK_VECTOR: {
|
||||
sock->default_value_typed<bNodeSocketValueVector>()->subtype = socktype->subtype;
|
||||
break;
|
||||
}
|
||||
case SOCK_INT: {
|
||||
sock->default_value_typed<bNodeSocketValueInt>()->subtype = socktype->subtype;
|
||||
break;
|
||||
}
|
||||
case SOCK_STRING: {
|
||||
sock->default_value_typed<bNodeSocketValueString>()->subtype = socktype->subtype;
|
||||
break;
|
||||
}
|
||||
case SOCK_RGBA:
|
||||
case SOCK_SHADER:
|
||||
case SOCK_BOOLEAN:
|
||||
case SOCK_CUSTOM:
|
||||
case __SOCK_MESH:
|
||||
case SOCK_OBJECT:
|
||||
case SOCK_IMAGE:
|
||||
case SOCK_GEOMETRY:
|
||||
case SOCK_COLLECTION:
|
||||
case SOCK_TEXTURE:
|
||||
case SOCK_MATERIAL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
|
||||
|
|
|
@ -1658,8 +1658,11 @@ void uiItemsFullEnumO(uiLayout *layout,
|
|||
#endif
|
||||
}
|
||||
else {
|
||||
RNA_property_enum_items_gettexted(
|
||||
static_cast<bContext *>(block->evil_C), &ptr, prop, &item_array, &totitem, &free);
|
||||
bContext *C = static_cast<bContext *>(block->evil_C);
|
||||
bContextStore *previous_ctx = CTX_store_get(C);
|
||||
CTX_store_set(C, layout->context);
|
||||
RNA_property_enum_items_gettexted(C, &ptr, prop, &item_array, &totitem, &free);
|
||||
CTX_store_set(C, previous_ctx);
|
||||
}
|
||||
|
||||
/* add items */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "BKE_scene.h"
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "BLI_set.hh"
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
@ -2109,7 +2110,7 @@ void NODE_OT_node_copy_color(wmOperatorType *ot)
|
|||
/** \name Node-Tree Add Interface Socket Operator
|
||||
* \{ */
|
||||
|
||||
static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb)
|
||||
static bNodeSocket *ntree_get_active_interface_socket(const ListBase *lb)
|
||||
{
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, lb) {
|
||||
if (socket->flag & SELECT) {
|
||||
|
@ -2254,7 +2255,6 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Don't handle sub-types for now. */
|
||||
nodeModifySocketType(ntree, nullptr, iosock, socket_type->idname);
|
||||
|
||||
/* Need the extra update here because the loop above does not check for valid links in the node
|
||||
|
@ -2333,6 +2333,155 @@ void NODE_OT_tree_socket_change_type(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node-Tree Change Interface Socket Subtype Operator
|
||||
* \{ */
|
||||
|
||||
static int ntree_socket_change_subtype_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *main = CTX_data_main(C);
|
||||
const int socket_subtype = RNA_enum_get(op->ptr, "socket_subtype");
|
||||
|
||||
PointerRNA io_socket_ptr = CTX_data_pointer_get_type(
|
||||
C, "interface_socket", &RNA_NodeSocketInterface);
|
||||
bNodeSocket *io_socket = static_cast<bNodeSocket *>(io_socket_ptr.data);
|
||||
if (!io_socket) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
bNodeTree &node_tree = *reinterpret_cast<bNodeTree *>(io_socket_ptr.owner_id);
|
||||
|
||||
ListBase *sockets;
|
||||
if (node_tree.interface_inputs().contains(io_socket)) {
|
||||
sockets = &node_tree.inputs;
|
||||
}
|
||||
else if (node_tree.interface_outputs().contains(io_socket)) {
|
||||
sockets = &node_tree.outputs;
|
||||
}
|
||||
else {
|
||||
/* The interface socket should be in the inputs or outputs. */
|
||||
BLI_assert_unreachable();
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
nodeModifySocketTypeStatic(&node_tree, nullptr, io_socket, io_socket->type, socket_subtype);
|
||||
|
||||
/* Deactivate sockets. */
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
|
||||
socket_iter->flag &= ~SELECT;
|
||||
}
|
||||
/* Make the new socket active. */
|
||||
io_socket->flag |= SELECT;
|
||||
|
||||
BKE_ntree_update_tag_interface(&node_tree);
|
||||
ED_node_tree_propagate_change(C, main, &node_tree);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static Set<int> socket_type_get_subtypes(const eNodeSocketDatatype type)
|
||||
{
|
||||
switch (type) {
|
||||
case SOCK_FLOAT:
|
||||
return {PROP_PERCENTAGE,
|
||||
PROP_FACTOR,
|
||||
PROP_ANGLE,
|
||||
PROP_TIME,
|
||||
PROP_TIME_ABSOLUTE,
|
||||
PROP_DISTANCE,
|
||||
PROP_NONE};
|
||||
case SOCK_INT:
|
||||
return {PROP_PERCENTAGE, PROP_FACTOR, PROP_NONE};
|
||||
case SOCK_VECTOR:
|
||||
return {PROP_TRANSLATION,
|
||||
/* Direction doesn't seem to work. */
|
||||
// PROP_DIRECTION,
|
||||
PROP_VELOCITY,
|
||||
PROP_ACCELERATION,
|
||||
PROP_EULER,
|
||||
PROP_XYZ,
|
||||
PROP_NONE};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *socket_change_subtype_itemf(bContext *C,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
if (!C) {
|
||||
return DummyRNA_NULL_items;
|
||||
}
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
if (!snode || !snode->edittree) {
|
||||
return DummyRNA_NULL_items;
|
||||
}
|
||||
|
||||
PointerRNA active_socket_ptr = CTX_data_pointer_get_type(
|
||||
C, "interface_socket", &RNA_NodeSocketInterface);
|
||||
const bNodeSocket *active_socket = static_cast<const bNodeSocket *>(active_socket_ptr.data);
|
||||
if (!active_socket) {
|
||||
return DummyRNA_NULL_items;
|
||||
}
|
||||
|
||||
const Set<int> subtypes = socket_type_get_subtypes(eNodeSocketDatatype(active_socket->type));
|
||||
if (subtypes.is_empty()) {
|
||||
return DummyRNA_NULL_items;
|
||||
}
|
||||
|
||||
EnumPropertyItem *items = NULL;
|
||||
int items_count = 0;
|
||||
for (const EnumPropertyItem *item = rna_enum_property_subtype_items; item->name != NULL;
|
||||
item++) {
|
||||
if (subtypes.contains(item->value)) {
|
||||
RNA_enum_item_add(&items, &items_count, item);
|
||||
}
|
||||
}
|
||||
|
||||
if (items_count == 0) {
|
||||
return DummyRNA_NULL_items;
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&items, &items_count);
|
||||
*r_free = true;
|
||||
return items;
|
||||
}
|
||||
|
||||
static bool ntree_socket_change_subtype_poll(bContext *C)
|
||||
{
|
||||
if (!ED_operator_node_editable(C)) {
|
||||
return false;
|
||||
}
|
||||
PointerRNA io_socket_ptr = CTX_data_pointer_get_type(
|
||||
C, "interface_socket", &RNA_NodeSocketInterface);
|
||||
const bNodeSocket *io_socket = static_cast<const bNodeSocket *>(io_socket_ptr.data);
|
||||
if (!io_socket) {
|
||||
return false;
|
||||
}
|
||||
return !socket_type_get_subtypes(eNodeSocketDatatype(io_socket->type)).is_empty();
|
||||
}
|
||||
|
||||
void NODE_OT_tree_socket_change_subtype(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Change Node Tree Socket Subtype";
|
||||
ot->description = "Change the subtype of a socket of the active node tree";
|
||||
ot->idname = "NODE_OT_tree_socket_change_subtype";
|
||||
|
||||
ot->invoke = WM_menu_invoke;
|
||||
ot->exec = ntree_socket_change_subtype_exec;
|
||||
ot->poll = ntree_socket_change_subtype_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
ot->prop = RNA_def_enum(
|
||||
ot->srna, "socket_subtype", DummyRNA_DEFAULT_items, 0, "Socket Subtype", "");
|
||||
RNA_def_enum_funcs(ot->prop, socket_change_subtype_itemf);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node-Tree Move Interface Socket Operator
|
||||
* \{ */
|
||||
|
|
|
@ -356,6 +356,7 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot);
|
|||
void NODE_OT_tree_socket_add(wmOperatorType *ot);
|
||||
void NODE_OT_tree_socket_remove(wmOperatorType *ot);
|
||||
void NODE_OT_tree_socket_change_type(wmOperatorType *ot);
|
||||
void NODE_OT_tree_socket_change_subtype(wmOperatorType *ot);
|
||||
void NODE_OT_tree_socket_move(wmOperatorType *ot);
|
||||
|
||||
void NODE_OT_shader_script_update(wmOperatorType *ot);
|
||||
|
|
|
@ -108,6 +108,7 @@ void node_operatortypes()
|
|||
WM_operatortype_append(NODE_OT_tree_socket_add);
|
||||
WM_operatortype_append(NODE_OT_tree_socket_remove);
|
||||
WM_operatortype_append(NODE_OT_tree_socket_change_type);
|
||||
WM_operatortype_append(NODE_OT_tree_socket_change_subtype);
|
||||
WM_operatortype_append(NODE_OT_tree_socket_move);
|
||||
|
||||
WM_operatortype_append(NODE_OT_cryptomatte_layer_add);
|
||||
|
|
|
@ -176,6 +176,7 @@ typedef struct bNodeSocket {
|
|||
bool is_output() const;
|
||||
|
||||
/** Utility to access the value of the socket. */
|
||||
template<typename T> T *default_value_typed();
|
||||
template<typename T> const T *default_value_typed() const;
|
||||
|
||||
/* The following methods are only available when #bNodeTree.ensure_topology_cache has been
|
||||
|
|
|
@ -11216,6 +11216,12 @@ static void rna_def_node_socket(BlenderRNA *brna)
|
|||
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
|
||||
RNA_def_property_ui_text(prop, "Type Label", "Label to display for the socket type in the UI");
|
||||
|
||||
prop = RNA_def_property(srna, "bl_subtype_label", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "typeinfo->subtype_label");
|
||||
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Subtype Label", "Label to display for the socket subtype in the UI");
|
||||
|
||||
/* draw socket */
|
||||
func = RNA_def_function(srna, "draw", NULL);
|
||||
RNA_def_function_ui_description(func, "Draw socket");
|
||||
|
@ -11333,6 +11339,11 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
|
|||
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
|
||||
RNA_def_property_ui_text(prop, "Type Label", "Label to display for the socket type in the UI");
|
||||
|
||||
prop = RNA_def_property(srna, "bl_subtype_label", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "typeinfo->subtype_label");
|
||||
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
|
||||
RNA_def_property_ui_text(prop, "Subtype Label", "Label to display for the socket subtype in the UI");
|
||||
|
||||
func = RNA_def_function(srna, "draw", NULL);
|
||||
RNA_def_function_ui_description(func, "Draw template settings");
|
||||
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
|
||||
|
|
|
@ -537,6 +537,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
|
|||
const char *socket_idname = nodeStaticSocketType(type, subtype);
|
||||
const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype);
|
||||
const char *socket_label = nodeStaticSocketLabel(type, subtype);
|
||||
const char *socket_subtype_label = nodeSocketSubTypeLabel(subtype);
|
||||
bNodeSocketType *stype;
|
||||
StructRNA *srna;
|
||||
|
||||
|
@ -544,6 +545,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
|
|||
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
|
||||
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
|
||||
BLI_strncpy(stype->label, socket_label, sizeof(stype->label));
|
||||
BLI_strncpy(stype->subtype_label, socket_subtype_label, sizeof(stype->subtype_label));
|
||||
|
||||
/* set the RNA type
|
||||
* uses the exact same identifier as the socket type idname */
|
||||
|
|
Loading…
Reference in New Issue