UI: Draw real node sockets for node input buttons

For buttons representing node inputs (e.g. in the material properties)
rather than drawing some generic socket icon, the actual sockets are
drawn now. That includes color, shape and the selection outline.

This should make it easier to understand what these buttons relate to.

Screenshots: {F8469252}, {F8469248} (The left alignment will be done in
a follow-up commit.)

Differential Revision: https://developer.blender.org/D7409

Reviewed by: Brecht Van Lommel, Clément Foucault, William Reynish
This commit is contained in:
Julian Eisel 2020-04-16 15:09:49 +02:00
parent 737a4309e8
commit 675d42dfc3
9 changed files with 265 additions and 104 deletions

View File

@ -37,6 +37,7 @@ struct Tex;
struct View2D;
struct bContext;
struct bNode;
struct bNodeSocket;
struct bNodeSocketType;
struct bNodeTree;
struct bNodeTree;
@ -79,6 +80,10 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.c */
void ED_node_socket_draw(struct bNodeSocket *sock,
const struct rcti *rect,
const float color[4],
float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);

View File

@ -1585,6 +1585,8 @@ int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
@ -2088,6 +2090,7 @@ void uiTemplateList(uiLayout *layout,
bool sort_reverse,
bool sort_lock);
void uiTemplateNodeLink(uiLayout *layout,
struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
struct bNodeSocket *input);

View File

@ -6486,6 +6486,13 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
but->custom_data = socket;
rgba_float_to_uchar(but->col, draw_color);
}
/**
* push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup

View File

@ -42,6 +42,8 @@
#include "BLF_api.h"
#include "ED_node.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
@ -2394,6 +2396,30 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol,
}
}
static void widget_draw_node_link_socket(const uiWidgetColors *wcol,
const rcti *rect,
uiBut *but,
float alpha)
{
/* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
if (but->custom_data) {
const float scale = 0.9f / but->block->aspect;
float col[4];
rgba_uchar_to_float(col, but->col);
col[3] *= alpha;
GPU_blend(true);
UI_widgetbase_draw_cache_flush();
GPU_blend(false);
ED_node_socket_draw(but->custom_data, rect, col, scale);
}
else {
widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
}
}
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
@ -2403,15 +2429,27 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
bool no_text_padding = false;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text);
rect->xmax = temp.xmin;
const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
if (but->drawflag & UI_BUT_ICON_LEFT) {
temp.xmax = rect->xmin + size;
rect->xmin = temp.xmax;
/* Further padding looks off. */
no_text_padding = true;
}
else {
temp.xmin = rect->xmax - size;
rect->xmax = temp.xmin;
}
widget_draw_node_link_socket(wcol, &temp, but, alpha);
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
@ -2496,28 +2534,30 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
rect->xmin += icon_size + icon_padding;
}
int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
if (but->editstr) {
rect->xmin += text_padding;
}
else if (but->flag & UI_BUT_DRAG_MULTI) {
bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
if (text_is_edited) {
if (!no_text_padding) {
int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
if (but->editstr) {
rect->xmin += text_padding;
}
}
else if (but->drawflag & UI_BUT_TEXT_LEFT) {
/* Reduce the left padding for labels without an icon. */
if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
!ui_block_is_menu(but->block)) {
text_padding /= 2;
else if (but->flag & UI_BUT_DRAG_MULTI) {
bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
if (text_is_edited) {
rect->xmin += text_padding;
}
}
else if (but->drawflag & UI_BUT_TEXT_LEFT) {
rect->xmin += text_padding;
}
else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
rect->xmax -= text_padding;
/* Reduce the left padding for labels without an icon. */
if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
!ui_block_is_menu(but->block)) {
text_padding /= 2;
}
rect->xmin += text_padding;
}
else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
rect->xmax -= text_padding;
}
}
/* Menu contains sub-menu items with triangle icon on their right. Shortcut

View File

@ -84,7 +84,7 @@ static void node_sockets_panel(const bContext *C, Panel *panel)
split = uiLayoutSplit(layout, 0.35f, false);
uiItemL(split, name, ICON_NONE);
uiTemplateNodeLink(split, ntree, node, sock);
uiTemplateNodeLink(split, (bContext *)C, ntree, node, sock);
}
}

View File

@ -707,39 +707,19 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
#define MARKER_SHAPE_CIRCLE 0x2
#define MARKER_SHAPE_INNER_DOT 0x10
static void node_socket_draw(const bContext *C,
bNodeTree *ntree,
PointerRNA node_ptr,
bNodeSocket *sock,
static void node_socket_draw(const bNodeSocket *sock,
const float color[4],
const float color_outline[4],
float size,
int locx,
int locy,
uint pos_id,
uint col_id,
uint shape_id,
uint size_id,
uint outline_col_id,
float size,
bool selected)
uint outline_col_id)
{
PointerRNA ptr;
float color[4];
float outline_color[4];
uint flags = 0;
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
bNode *node = node_ptr.data;
if (node->flag & NODE_MUTED) {
color[3] *= 0.25f;
}
if (selected) {
UI_GetThemeColor4fv(TH_TEXT_HI, outline_color);
outline_color[3] = 0.9f;
}
else {
copy_v4_fl(outline_color, 0.0f);
outline_color[3] = 0.6f;
}
int flags;
/* sets shape flags */
switch (sock->display_shape) {
@ -768,8 +748,120 @@ static void node_socket_draw(const bContext *C,
immAttr4fv(col_id, color);
immAttr1u(shape_id, flags);
immAttr1f(size_id, size);
immAttr4fv(outline_col_id, outline_color);
immVertex2f(pos_id, sock->locx, sock->locy);
immAttr4fv(outline_col_id, color_outline);
immVertex2f(pos_id, locx, locy);
}
static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
{
if (selected) {
UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
r_outline_color[3] = 0.9f;
}
else {
copy_v4_fl(r_outline_color, 0.0f);
r_outline_color[3] = 0.6f;
}
}
/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
* color property socket). */
void node_socket_color_get(
bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
{
PointerRNA ptr;
BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
bNode *node = node_ptr->data;
if (node->flag & NODE_MUTED) {
r_color[3] *= 0.25f;
}
}
static void node_socket_draw_nested(const bContext *C,
bNodeTree *ntree,
PointerRNA *node_ptr,
bNodeSocket *sock,
uint pos_id,
uint col_id,
uint shape_id,
uint size_id,
uint outline_col_id,
float size,
bool selected)
{
float color[4];
float outline_color[4];
node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
node_socket_outline_color_get(selected, outline_color);
node_socket_draw(sock,
color,
outline_color,
size,
sock->locx,
sock->locy,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
}
/**
* Draw a single node socket at default size.
* \note this is only called from external code, internally #node_socket_draw_nested() is used for
* optimized drawing of multiple/all sockets of a node.
*/
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
const float size = 2.25f * NODE_SOCKSIZE * scale;
rcti draw_rect = *rect;
float outline_color[4] = {0};
node_socket_outline_color_get(sock->flag & SELECT, outline_color);
BLI_rcti_resize(&draw_rect, size, size);
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
uint outline_col_id = GPU_vertformat_attr_add(
format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
gpuPushAttr(GPU_BLEND_BIT);
GPU_blend(true);
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
immUniform1f("outline_scale", 0.7f);
immUniform2f("ViewportSize", -1.0f, -1.0f);
/* Single point */
immBegin(GPU_PRIM_POINTS, 1);
node_socket_draw(sock,
color,
outline_color,
BLI_rcti_size_y(&draw_rect),
BLI_rcti_cent_x(&draw_rect),
BLI_rcti_cent_y(&draw_rect),
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
immEnd();
immUnbindProgram();
GPU_program_point_size(false);
gpuPopAttr();
}
/* ************** Socket callbacks *********** */
@ -962,17 +1054,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
node_socket_draw(C,
ntree,
node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
node_socket_draw_nested(C,
ntree,
&node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
}
/* socket outputs */
@ -987,17 +1079,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
node_socket_draw(C,
ntree,
node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
node_socket_draw_nested(C,
ntree,
&node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
}
}
@ -1020,17 +1112,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw(C,
ntree,
node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
node_socket_draw_nested(C,
ntree,
&node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
if (--selected_input_len == 0) {
break; /* stop as soon as last one is drawn */
}
@ -1045,17 +1137,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw(C,
ntree,
node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
node_socket_draw_nested(C,
ntree,
&node_ptr,
sock,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id,
scale,
selected);
if (--selected_output_len == 0) {
break; /* stop as soon as last one is drawn */
}

View File

@ -38,6 +38,7 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
@ -77,6 +78,11 @@ void node_draw_sockets(struct View2D *v2d,
void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
int node_select_area_default(struct bNode *node, int x, int y);
int node_tweak_area_default(struct bNode *node, int x, int y);
void node_socket_color_get(struct bContext *C,
struct bNodeTree *ntree,
struct PointerRNA *node_ptr,
struct bNodeSocket *sock,
float r_color[4]);
void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree);
void node_draw_nodetree(const struct bContext *C,
struct ARegion *region,
@ -122,7 +128,7 @@ void NODE_OT_find_node(struct wmOperatorType *ot);
/* node_view.c */
int space_node_view_flag(struct bContext *C,
SpaceNode *snode,
struct SpaceNode *snode,
ARegion *region,
const int node_flag,
const int smooth_viewtx);
@ -196,7 +202,7 @@ void NODE_OT_detach(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
void NODE_OT_insert_offset(struct wmOperatorType *ot);
/* node_edit.c */
void snode_notify(struct bContext *C, struct SpaceNode *snode);
@ -207,8 +213,8 @@ void snode_update(struct SpaceNode *snode, struct bNode *node);
bool composite_node_active(struct bContext *C);
bool composite_node_editable(struct bContext *C);
int node_has_hidden_sockets(bNode *node);
void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
int node_has_hidden_sockets(struct bNode *node);
void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, struct wmOperator *);
int node_find_indicated_socket(struct SpaceNode *snode,
struct bNode **nodep,

View File

@ -45,6 +45,7 @@
#include "UI_interface.h"
#include "ED_node.h" /* own include */
#include "node_intern.h"
#include "ED_undo.h"
@ -662,17 +663,23 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
void uiTemplateNodeLink(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
float socket_col[4];
arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = sock;
PointerRNA node_ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
node_socket_color_get(C, ntree, &node_ptr, sock, socket_col);
UI_block_layout_set_current(block, layout);
if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
@ -687,8 +694,8 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
}
UI_but_type_set_menu_from_pulldown(but);
UI_but_node_link_set(but, sock, socket_col);
but->flag |= UI_BUT_NODE_LINK;
but->poin = (char *)but;
but->func_argN = arg;
@ -798,7 +805,7 @@ static void ui_node_draw_input(
}
else if (lnode) {
/* input linked to a node */
uiTemplateNodeLink(split, ntree, node, input);
uiTemplateNodeLink(split, C, ntree, node, input);
if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
if (depth == 0) {
@ -835,7 +842,7 @@ static void ui_node_draw_input(
row = uiLayoutRow(split, false);
}
uiTemplateNodeLink(row, ntree, node, input);
uiTemplateNodeLink(row, C, ntree, node, input);
}
/* clear */

View File

@ -1492,6 +1492,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");