Node Editor: Add overlay to automatically label reroute nodes #113368
|
@ -862,6 +862,7 @@ class NODE_PT_overlay(Panel):
|
|||
|
||||
col = layout.column()
|
||||
col.prop(overlay, "show_wire_color", text="Wire Colors")
|
||||
col.prop(overlay, "show_reroute_auto_labels", text="Reroute Auto Labels")
|
||||
|
||||
col.separator()
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 33
|
||||
#define BLENDER_FILE_SUBVERSION 34
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -1679,6 +1679,8 @@ void node_type_size_preset(bNodeType *ntype, eNodeSizePreset size);
|
|||
/** \name Node Generic Functions
|
||||
* \{ */
|
||||
|
||||
void ntree_update_auto_labels(bNodeTree &ntree);
|
||||
|
||||
bool node_is_connected_to_output(const bNodeTree *ntree, const bNode *node);
|
||||
|
||||
bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);
|
||||
|
|
|
@ -3479,6 +3479,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 34)) {
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_NODE) {
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
snode->overlay.flag |= SN_OVERLAY_SHOW_REROUTE_AUTO_LABELS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -2046,6 +2046,15 @@ void node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4],
|
|||
GPU_blend(state);
|
||||
}
|
||||
|
||||
/* Some elements of the node UI are hidden, when they get too small. */
|
||||
#define NODE_TREE_SCALE_SMALL 0.2f
|
||||
|
||||
/* The node tree scales both with the view and with the UI. */
|
||||
static float node_tree_view_scale(const SpaceNode &snode)
|
||||
{
|
||||
return (1.0f / snode.runtime->aspect) * UI_SCALE_FAC;
|
||||
}
|
||||
|
||||
static void node_draw_preview_background(rctf *rect)
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
|
@ -3568,11 +3577,8 @@ static void node_draw_basis(const bContext &C,
|
|||
UI_draw_roundbox_4fv(&rect, false, BASIS_RAD + outline_width, color_outline);
|
||||
}
|
||||
|
||||
float scale;
|
||||
UI_view2d_scale_get(&v2d, &scale, nullptr);
|
||||
|
||||
/* Skip slow socket drawing if zoom is small. */
|
||||
if (scale > 0.2f) {
|
||||
if (node_tree_view_scale(snode) > NODE_TREE_SCALE_SMALL) {
|
||||
node_draw_sockets(v2d, C, ntree, node, block, true, false);
|
||||
}
|
||||
|
||||
|
@ -4094,8 +4100,45 @@ static void frame_node_draw(const bContext &C,
|
|||
UI_block_draw(&C, &block);
|
||||
}
|
||||
|
||||
static void reroute_node_draw(
|
||||
const bContext &C, ARegion ®ion, bNodeTree &ntree, const bNode &node, uiBlock &block)
|
||||
static void reroute_node_draw_label(const SpaceNode &snode, const bNode &node, uiBlock &block)
|
||||
{
|
||||
const bool has_label = node.label[0] != '\0';
|
||||
const bool use_auto_label = !has_label && (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) &&
|
||||
(snode.overlay.flag & SN_OVERLAY_SHOW_REROUTE_AUTO_LABELS);
|
||||
|
||||
if (!has_label && !use_auto_label) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't show the automatic label, when being zoomed out. */
|
||||
if (!has_label && node_tree_view_scale(snode) < NODE_TREE_SCALE_SMALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bNodeSocket *output = static_cast<bNodeSocket *>(node.outputs.first);
|
||||
char showname[128]; /* 128 used below */
|
||||
STRNCPY(showname, use_auto_label ? output->label : node.label);
|
||||
|
||||
const short width = 512;
|
||||
const int x = BLI_rctf_cent_x(&node.runtime->totr) - (width / 2);
|
||||
const int y = node.runtime->totr.ymax;
|
||||
|
||||
uiBut *label_but = uiDefBut(
|
||||
&block, UI_BTYPE_LABEL, 0, showname, x, y, width, short(NODE_DY), nullptr, 0, 0, nullptr);
|
||||
|
||||
UI_but_drawflag_disable(label_but, UI_BUT_TEXT_LEFT);
|
||||
|
||||
if (use_auto_label && !(node.flag & NODE_SELECT)) {
|
||||
UI_but_flag_enable(label_but, UI_BUT_INACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
static void reroute_node_draw(const bContext &C,
|
||||
ARegion ®ion,
|
||||
const SpaceNode &snode,
|
||||
bNodeTree &ntree,
|
||||
const bNode &node,
|
||||
uiBlock &block)
|
||||
{
|
||||
/* Skip if out of view. */
|
||||
const rctf &rct = node.runtime->totr;
|
||||
|
@ -4106,19 +4149,7 @@ static void reroute_node_draw(
|
|||
return;
|
||||
}
|
||||
|
||||
if (node.label[0] != '\0') {
|
||||
/* Draw title (node label). */
|
||||
char showname[128]; /* 128 used below */
|
||||
STRNCPY(showname, node.label);
|
||||
const short width = 512;
|
||||
const int x = BLI_rctf_cent_x(&node.runtime->totr) - (width / 2);
|
||||
const int y = node.runtime->totr.ymax;
|
||||
|
||||
uiBut *label_but = uiDefBut(
|
||||
&block, UI_BTYPE_LABEL, 0, showname, x, y, width, short(NODE_DY), nullptr, 0, 0, nullptr);
|
||||
|
||||
UI_but_drawflag_disable(label_but, UI_BUT_TEXT_LEFT);
|
||||
}
|
||||
reroute_node_draw_label(snode, node, block);
|
||||
|
||||
/* Only draw input socket as they all are placed on the same position highlight
|
||||
* if node itself is selected, since we don't display the node body separately. */
|
||||
|
@ -4141,7 +4172,7 @@ static void node_draw(const bContext &C,
|
|||
frame_node_draw(C, tree_draw_ctx, region, snode, ntree, node, block);
|
||||
}
|
||||
else if (node.is_reroute()) {
|
||||
reroute_node_draw(C, region, ntree, node, block);
|
||||
reroute_node_draw(C, region, snode, ntree, node, block);
|
||||
}
|
||||
else {
|
||||
const View2D &v2d = region.v2d;
|
||||
|
|
|
@ -1555,6 +1555,7 @@ typedef enum eSpaceNodeOverlay_Flag {
|
|||
SN_OVERLAY_SHOW_PATH = (1 << 4),
|
||||
SN_OVERLAY_SHOW_NAMED_ATTRIBUTES = (1 << 5),
|
||||
SN_OVERLAY_SHOW_PREVIEWS = (1 << 6),
|
||||
SN_OVERLAY_SHOW_REROUTE_AUTO_LABELS = (1 << 7),
|
||||
} eSpaceNodeOverlay_Flag;
|
||||
|
||||
typedef enum eSpaceNodeOverlay_preview_shape {
|
||||
|
|
|
@ -2221,6 +2221,16 @@ void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr)
|
|||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
static void rna_Node_update_node_labels(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
const bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
|
||||
if (node.is_reroute()) {
|
||||
blender::bke::ntree_update_auto_labels(ntree);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Node_socket_value_update(ID *id, bNode * /*node*/, bContext *C)
|
||||
{
|
||||
BKE_ntree_update_tag_all(reinterpret_cast<bNodeTree *>(id));
|
||||
|
@ -9955,7 +9965,7 @@ static void rna_def_node(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "label");
|
||||
RNA_def_property_ui_text(prop, "Label", "Optional custom node label");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, nullptr);
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_Node_update_node_labels");
|
||||
|
||||
prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, nullptr, "inputs", nullptr);
|
||||
|
|
|
@ -7573,6 +7573,15 @@ static void rna_def_space_node_overlay(BlenderRNA *brna)
|
|||
prop, "Show Wire Colors", "Color node links based on their connected sockets");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "show_reroute_auto_labels", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "overlay.flag", SN_OVERLAY_SHOW_REROUTE_AUTO_LABELS);
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Show Reroute Auto Labels",
|
||||
"Label reroute nodes based on the label of connected reroute nodes");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS);
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
|
|
|
@ -585,6 +585,52 @@ void register_node_type_reroute()
|
|||
nodeRegisterType(ntype);
|
||||
}
|
||||
|
||||
/* NOTE: This uses the label of the reroute node's output socket to
|
||||
* propagate the label from connected reroute nodes. */
|
||||
static void update_reroute_node_auto_labels(bNodeTree *ntree)
|
||||
{
|
||||
using namespace blender;
|
||||
ntree->ensure_topology_cache();
|
||||
|
||||
/* Clear auto-label. */
|
||||
LISTBASE_FOREACH (bNode *, reroute, &ntree->nodes) {
|
||||
if (!reroute->is_reroute()) {
|
||||
continue;
|
||||
}
|
||||
bNodeSocket *output = reroute->output_sockets().first();
|
||||
node_sock_label_clear(output);
|
||||
}
|
||||
|
||||
for (bNode *reroute : ntree->toposort_left_to_right()) {
|
||||
if (!reroute->is_reroute()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bNodeSocket *output = reroute->output_sockets().first();
|
||||
const bNodeSocket &input = *reroute->input_sockets().first();
|
||||
const Span<const bNodeSocket *> linked_sockets = input.directly_linked_sockets();
|
||||
|
||||
if (linked_sockets.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bNodeSocket &from_sock = *linked_sockets.first();
|
||||
const bNode &from_node = from_sock.owner_node();
|
||||
|
||||
if (!from_node.is_reroute()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (from_node.label[0] != '\0') {
|
||||
/* Use the connected reroute's label to also label this reroute. */
|
||||
node_sock_label(output, from_node.label);
|
||||
continue;
|
||||
}
|
||||
|
||||
node_sock_label(output, from_sock.label);
|
||||
}
|
||||
}
|
||||
|
||||
static void propagate_reroute_type_from_start_socket(
|
||||
bNodeSocket *start_socket,
|
||||
const MultiValueMap<bNodeSocket *, bNodeLink *> &links_map,
|
||||
|
@ -618,7 +664,7 @@ static void propagate_reroute_type_from_start_socket(
|
|||
}
|
||||
}
|
||||
|
||||
void ntree_update_reroute_nodes(bNodeTree *ntree)
|
||||
void update_reroute_node_socket_types(bNodeTree *ntree)
|
||||
{
|
||||
/* Contains nodes that are linked to at least one reroute node. */
|
||||
Set<bNode *> nodes_linked_with_reroutes;
|
||||
|
@ -676,6 +722,17 @@ void ntree_update_reroute_nodes(bNodeTree *ntree)
|
|||
}
|
||||
}
|
||||
|
||||
void ntree_update_reroute_nodes(bNodeTree *ntree)
|
||||
{
|
||||
update_reroute_node_socket_types(ntree);
|
||||
update_reroute_node_auto_labels(ntree);
|
||||
}
|
||||
|
||||
void blender::bke::ntree_update_auto_labels(bNodeTree &ntree)
|
||||
{
|
||||
update_reroute_node_auto_labels(&ntree);
|
||||
}
|
||||
|
||||
bool blender::bke::node_is_connected_to_output(const bNodeTree *ntree, const bNode *node)
|
||||
{
|
||||
ntree->ensure_topology_cache();
|
||||
|
|
Loading…
Reference in New Issue