Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/include/UI_interface.h19
-rw-r--r--source/blender/editors/interface/interface_layout.c35
-rw-r--r--source/blender/editors/interface/interface_query.cc2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c6
-rw-r--r--source/blender/editors/space_node/node_draw.cc106
-rw-r--r--source/blender/editors/space_node/node_intern.hh2
-rw-r--r--source/blender/editors/space_node/node_templates.cc16
7 files changed, 150 insertions, 36 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index c14cce28052..3f58aab3e53 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -595,6 +595,7 @@ typedef void (*uiMenuHandleFunc)(struct bContext *C, void *arg, int event);
*/
typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
+typedef void *(*uiCopyArgFunc)(const void *arg);
typedef void (*uiFreeArgFunc)(void *arg);
/* interface_query.c */
@@ -2065,6 +2066,24 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
struct bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
+
+/**
+ * Set tooltip function for all buttons in the layout.
+ * func, arg and free_arg are passed on to UI_but_func_tooltip_set, so their meaning is the same.
+ *
+ * \param func: The callback function that gets called to get tooltip content
+ * \param arg: An optional opaque pointer that gets passed to func
+ * \param free_arg: An optional callback for freeing arg (can be set to e.g. MEM_freeN)
+ * \param copy_arg: An optional callback for duplicating arg in case UI_but_func_tooltip_set
+ * is being called on multiple buttons (can be set to e.g. MEM_dupallocN). If set to NULL, arg will
+ * be passed as-is to all buttons.
+ */
+void uiLayoutSetTooltipFunc(uiLayout *layout,
+ uiButToolTipFunc func,
+ void *arg,
+ uiCopyArgFunc copy_arg,
+ uiFreeArgFunc free_arg);
+
/**
* This is a bit of a hack but best keep it in one place at least.
*/
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index ac807f06891..3e8bae6ea6b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5681,6 +5681,41 @@ void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
layout->context = CTX_store_add_all(&block->contexts, context);
}
+void uiLayoutSetTooltipFunc(uiLayout *layout,
+ uiButToolTipFunc func,
+ void *arg,
+ uiCopyArgFunc copy_arg,
+ uiFreeArgFunc free_arg)
+{
+ bool arg_used = false;
+
+ LISTBASE_FOREACH (uiItem *, item, &layout->items) {
+ /* Each button will call free_arg for "its" argument, so we need to
+ * duplicate the allocation for each button after the first. */
+ if (copy_arg != NULL && arg_used) {
+ arg = copy_arg(arg);
+ }
+ arg_used = true;
+
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *bitem = (uiButtonItem *)item;
+ if (bitem->but->type == UI_BTYPE_DECORATOR) {
+ continue;
+ }
+ UI_but_func_tooltip_set(bitem->but, func, arg, free_arg);
+ }
+ else {
+ uiLayoutSetTooltipFunc(
+ (uiLayout *)item, func, arg, copy_arg, free_arg);
+ }
+ }
+
+ if (!arg_used) {
+ /* Free the original copy of arg in case the layout is empty. */
+ free_arg(arg);
+ }
+}
+
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
{
if (but->opptr) {
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 2767a184619..337b2852d57 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -61,7 +61,7 @@ bool ui_but_is_toggle(const uiBut *but)
bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
- if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == nullptr) {
+ if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == nullptr && but->tip_func == nullptr) {
return false;
}
if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) {
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 29553ff65d1..ca18ec14a54 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -788,8 +788,10 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
}
/* Tip Label (only for buttons not already showing the label).
- * Check prefix instead of comparing because the button may include the shortcut. */
- if (but_label.strinfo && !STRPREFIX(but->drawstr, but_label.strinfo)) {
+ * Check prefix instead of comparing because the button may include the shortcut.
+ * Buttons with dynamic tooltips also don't get their default label here since they
+ * can already provide more accurate and specific tooltip content. */
+ if (but_label.strinfo && !STRPREFIX(but->drawstr, but_label.strinfo) && !but->tip_func) {
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
.style = UI_TIP_STYLE_HEADER,
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 88ab7617932..013413adfe9 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -26,12 +26,10 @@
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
-#include "BLI_vector_set.hh"
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_geometry_set.hh"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -75,8 +73,6 @@
#include "node_intern.hh" /* own include */
using blender::GPointer;
-using blender::fn::FieldCPPType;
-using blender::fn::FieldInput;
using blender::fn::GField;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
@@ -374,6 +370,8 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
const char *socket_label = nodeSocketLabel(nsock);
nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ node_socket_add_tooltip(&ntree, &node, nsock, row);
+
UI_block_align_end(&block);
UI_block_layout_resolve(&block, nullptr, &buty);
@@ -504,6 +502,8 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
const char *socket_label = nodeSocketLabel(nsock);
nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ node_socket_add_tooltip(&ntree, &node, nsock, row);
+
UI_block_align_end(&block);
UI_block_layout_resolve(&block, nullptr, &buty);
@@ -943,6 +943,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
bNodeSocket &socket)
{
SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode == nullptr) {
+ return {};
+ };
+
const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context(
*snode, node, socket);
if (socket_log == nullptr) {
@@ -970,6 +974,78 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
return ss.str();
}
+static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket)
+{
+ if (ntree->type == NTREE_GEOMETRY) {
+ return true;
+ }
+
+ if (socket->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ return !socket_decl.description().is_empty();
+ }
+
+ return false;
+}
+
+static char *node_socket_get_tooltip(bContext *C,
+ bNodeTree *ntree,
+ bNode *node,
+ bNodeSocket *socket)
+{
+ std::stringstream output;
+ if (socket->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ blender::StringRef description = socket_decl.description();
+ if (!description.is_empty()) {
+ output << TIP_(description.data());
+ }
+ }
+
+ if (ntree->type == NTREE_GEOMETRY) {
+ if (!output.str().empty()) {
+ output << ".\n\n";
+ }
+
+ std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
+ C, *node, *socket);
+ if (socket_inspection_str.has_value()) {
+ output << *socket_inspection_str;
+ }
+ else {
+ output << TIP_("The socket value has not been computed yet");
+ }
+ }
+
+ if (output.str().empty()) {
+ output << nodeSocketLabel(socket);
+ }
+
+ return BLI_strdup(output.str().c_str());
+}
+
+void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout)
+{
+ if (!node_socket_has_tooltip(ntree, sock)) {
+ return;
+ }
+
+ SocketTooltipData *data = MEM_cnew<SocketTooltipData>(__func__);
+ data->ntree = ntree;
+ data->node = node;
+ data->socket = sock;
+
+ uiLayoutSetTooltipFunc(
+ layout,
+ [](bContext *C, void *argN, const char *UNUSED(tip)) {
+ SocketTooltipData *data = static_cast<SocketTooltipData *>(argN);
+ return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
+ },
+ data,
+ MEM_dupallocN,
+ MEM_freeN);
+}
+
static void node_socket_draw_nested(const bContext &C,
bNodeTree &ntree,
PointerRNA &node_ptr,
@@ -1001,8 +1077,7 @@ static void node_socket_draw_nested(const bContext &C,
size_id,
outline_col_id);
- if (ntree.type != NTREE_GEOMETRY) {
- /* Only geometry nodes has socket value tooltips currently. */
+ if (!node_socket_has_tooltip(&ntree, &sock)) {
return;
}
@@ -1034,24 +1109,7 @@ static void node_socket_draw_nested(const bContext &C,
but,
[](bContext *C, void *argN, const char *UNUSED(tip)) {
SocketTooltipData *data = (SocketTooltipData *)argN;
- std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
- C, *data->node, *data->socket);
-
- std::stringstream output;
- if (data->socket->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *data->socket->declaration;
- blender::StringRef description = socket_decl.description();
- if (!description.is_empty()) {
- output << TIP_(description.data()) << ".\n\n";
- }
- }
- if (socket_inspection_str.has_value()) {
- output << *socket_inspection_str;
- }
- else {
- output << TIP_("The socket value has not been computed yet");
- }
- return BLI_strdup(output.str().c_str());
+ return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
},
data,
MEM_freeN);
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 44163cd5ae3..10d4ad36d95 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -134,6 +134,8 @@ void node_socket_color_get(const bContext &C,
void node_draw_space(const bContext &C, ARegion &region);
+void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout);
+
/**
* Sort nodes by selection: unselected nodes first, then selected,
* then the active node at the very end. Relative order is kept intact.
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index e92e0571157..58a313c328e 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -852,23 +852,19 @@ static void ui_node_draw_input(
}
}
else {
- row = uiLayoutRow(row, true);
+ uiLayout *sub = uiLayoutRow(row, true);
- uiTemplateNodeLink(row, C, ntree, node, input);
+ uiTemplateNodeLink(sub, C, ntree, node, input);
if (input->flag & SOCK_HIDE_VALUE) {
add_dummy_decorator = true;
}
/* input not linked, show value */
else {
- uiLayout *sub = row;
-
switch (input->type) {
case SOCK_VECTOR:
- if (input->type == SOCK_VECTOR) {
- uiItemS(row);
- sub = uiLayoutColumn(row, true);
- }
+ uiItemS(sub);
+ sub = uiLayoutColumn(sub, true);
ATTR_FALLTHROUGH;
case SOCK_FLOAT:
case SOCK_INT:
@@ -884,7 +880,7 @@ static void ui_node_draw_input(
if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
/* Only add the attribute search in the node editor, in other places there is not
* enough context. */
- node_geometry_add_attribute_search_button(*C, *node, inputptr, *row);
+ node_geometry_add_attribute_search_button(*C, *node, inputptr, *sub);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
@@ -903,6 +899,8 @@ static void ui_node_draw_input(
uiItemDecoratorR(split_wrapper.decorate_column, nullptr, nullptr, 0);
}
+ node_socket_add_tooltip(ntree, node, input, row);
+
/* clear */
node->flag &= ~NODE_TEST;
}