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:
Diffstat (limited to 'source/blender/editors/space_node/node_draw.cc')
-rw-r--r--source/blender/editors/space_node/node_draw.cc281
1 files changed, 232 insertions, 49 deletions
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 8599b159cca..ed88489c63e 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -45,10 +45,10 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -76,6 +76,8 @@
#include "RNA_access.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "node_intern.h" /* own include */
#ifdef WITH_COMPOSITOR
@@ -86,6 +88,9 @@ using blender::Map;
using blender::Set;
using blender::Span;
using blender::Vector;
+using blender::fn::CPPType;
+using blender::fn::GPointer;
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
extern "C" {
/* XXX interface.h */
@@ -833,6 +838,149 @@ void node_socket_color_get(bContext *C,
}
}
+struct SocketTooltipData {
+ bNodeTree *ntree;
+ bNode *node;
+ bNodeSocket *socket;
+};
+
+static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
+ std::stringstream &ss)
+{
+ auto id_to_inspection_string = [&](ID *id) {
+ ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(GS(id->name))
+ << ")";
+ };
+
+ const GPointer value = value_log.value();
+ if (value.is_type<int>()) {
+ ss << *value.get<int>() << TIP_(" (Integer)");
+ }
+ else if (value.is_type<float>()) {
+ ss << *value.get<float>() << TIP_(" (Float)");
+ }
+ else if (value.is_type<blender::float3>()) {
+ ss << *value.get<blender::float3>() << TIP_(" (Vector)");
+ }
+ else if (value.is_type<bool>()) {
+ ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (value.is_type<std::string>()) {
+ ss << *value.get<std::string>() << TIP_(" (String)");
+ }
+ else if (value.is_type<Object *>()) {
+ id_to_inspection_string((ID *)*value.get<Object *>());
+ }
+ else if (value.is_type<Material *>()) {
+ id_to_inspection_string((ID *)*value.get<Material *>());
+ }
+ else if (value.is_type<Tex *>()) {
+ id_to_inspection_string((ID *)*value.get<Tex *>());
+ }
+ else if (value.is_type<Collection *>()) {
+ id_to_inspection_string((ID *)*value.get<Collection *>());
+ }
+}
+
+static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
+ std::stringstream &ss)
+{
+ Span<GeometryComponentType> component_types = value_log.component_types();
+ if (component_types.is_empty()) {
+ ss << TIP_("Empty Geometry");
+ return;
+ }
+
+ auto to_string = [](int value) {
+ char str[16];
+ BLI_str_format_int_grouped(str, value);
+ return std::string(str);
+ };
+
+ ss << TIP_("Geometry:\n");
+ for (GeometryComponentType type : component_types) {
+ const char *line_end = (type == component_types.last()) ? "" : ".\n";
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"),
+ to_string(mesh_info.tot_verts).c_str(),
+ to_string(mesh_info.tot_edges).c_str(),
+ to_string(mesh_info.tot_faces).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info =
+ *value_log.pointcloud_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Point Cloud: %s points"),
+ to_string(pointcloud_info.tot_points).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Curve: %s splines"),
+ to_string(curve_info.tot_splines).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Instances: %s"),
+ to_string(instances_info.tot_instances).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ ss << TIP_("\u2022 Volume") << line_end;
+ break;
+ }
+ }
+ }
+}
+
+static std::optional<std::string> create_socket_inspection_string(bContext *C,
+ bNodeTree &UNUSED(ntree),
+ bNode &node,
+ bNodeSocket &socket)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context(
+ *snode, node, socket);
+ if (socket_log == nullptr) {
+ return {};
+ }
+ const geo_log::ValueLog *value_log = socket_log->value();
+ if (value_log == nullptr) {
+ return {};
+ }
+
+ std::stringstream ss;
+ if (const geo_log::GenericValueLog *generic_value_log =
+ dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
+ create_inspection_string_for_generic_value(*generic_value_log, ss);
+ }
+ else if (const geo_log::GeometryValueLog *geo_value_log =
+ dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
+ create_inspection_string_for_geometry(*geo_value_log, ss);
+ }
+
+ return ss.str();
+}
+
static void node_socket_draw_nested(const bContext *C,
bNodeTree *ntree,
PointerRNA *node_ptr,
@@ -863,6 +1011,55 @@ static void node_socket_draw_nested(const bContext *C,
shape_id,
size_id,
outline_col_id);
+
+ if (ntree->type != NTREE_GEOMETRY) {
+ /* Only geometry nodes has socket value tooltips currently. */
+ return;
+ }
+
+ bNode *node = (bNode *)node_ptr->data;
+ uiBlock *block = node->block;
+
+ /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
+ * button on top of them for the tooltip. */
+ const eUIEmbossType old_emboss = UI_block_emboss_get(block);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_NONE,
+ sock->locx - size / 2,
+ sock->locy - size / 2,
+ size,
+ size,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
+ data->ntree = ntree;
+ data->node = (bNode *)node_ptr->data;
+ data->socket = sock;
+
+ UI_but_func_tooltip_set(
+ but,
+ [](bContext *C, void *argN, const char *UNUSED(tip)) {
+ SocketTooltipData *data = (SocketTooltipData *)argN;
+ std::optional<std::string> str = create_socket_inspection_string(
+ C, *data->ntree, *data->node, *data->socket);
+ if (str.has_value()) {
+ return BLI_strdup(str->c_str());
+ }
+ return BLI_strdup(TIP_("The socket value has not been computed yet"));
+ },
+ data,
+ MEM_freeN);
+ /* Disable the button so that clicks on it are ignored the the link operator still works. */
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ UI_block_emboss_set(block, old_emboss);
}
/**
@@ -1203,14 +1400,14 @@ void node_draw_sockets(const View2D *v2d,
}
}
-static int node_error_type_to_icon(const NodeWarningType type)
+static int node_error_type_to_icon(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return ICON_ERROR;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return ICON_ERROR;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return ICON_INFO;
}
@@ -1218,14 +1415,14 @@ static int node_error_type_to_icon(const NodeWarningType type)
return ICON_ERROR;
}
-static uint8_t node_error_type_priority(const NodeWarningType type)
+static uint8_t node_error_type_priority(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return 3;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return 2;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return 1;
}
@@ -1233,11 +1430,11 @@ static uint8_t node_error_type_priority(const NodeWarningType type)
return 0;
}
-static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
+static geo_log::NodeWarningType node_error_highest_priority(Span<geo_log::NodeWarning> warnings)
{
uint8_t highest_priority = 0;
- NodeWarningType highest_priority_type = NodeWarningType::Info;
- for (const NodeWarning &warning : warnings) {
+ geo_log::NodeWarningType highest_priority_type = geo_log::NodeWarningType::Info;
+ for (const geo_log::NodeWarning &warning : warnings) {
const uint8_t priority = node_error_type_priority(warning.type);
if (priority > highest_priority) {
highest_priority = priority;
@@ -1247,15 +1444,17 @@ static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
return highest_priority_type;
}
+struct NodeErrorsTooltipData {
+ Span<geo_log::NodeWarning> warnings;
+};
+
static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
{
- const NodeUIStorage **storage_pointer_alloc = static_cast<const NodeUIStorage **>(argN);
- const NodeUIStorage *node_ui_storage = *storage_pointer_alloc;
- Span<NodeWarning> warnings = node_ui_storage->warnings;
+ NodeErrorsTooltipData &data = *(NodeErrorsTooltipData *)argN;
std::string complete_string;
- for (const NodeWarning &warning : warnings.drop_back(1)) {
+ for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) {
complete_string += warning.message;
/* Adding the period is not ideal for multi-line messages, but it is consistent
* with other tooltip implementations in Blender, so it is added here. */
@@ -1264,7 +1463,7 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
}
/* Let the tooltip system automatically add the last period. */
- complete_string += warnings.last().message;
+ complete_string += data.warnings.last().message;
return BLI_strdupn(complete_string.c_str(), complete_string.size());
}
@@ -1272,20 +1471,26 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &ntree, bNode &node, const rctf &rect, float &icon_offset)
+ const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
{
- const NodeUIStorage *node_ui_storage = BKE_node_tree_ui_storage_get_from_context(C, ntree, node);
- if (node_ui_storage == nullptr || node_ui_storage->warnings.is_empty()) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
+ node);
+ if (node_log == nullptr) {
+ return;
+ }
+
+ Span<geo_log::NodeWarning> warnings = node_log->warnings();
+
+ if (warnings.is_empty()) {
return;
}
- /* The UI API forces us to allocate memory for each error button, because the
- * ownership of #UI_but_func_tooltip_set's argument is transferred to the button. */
- const NodeUIStorage **storage_pointer_alloc = (const NodeUIStorage **)MEM_mallocN(
- sizeof(NodeUIStorage *), __func__);
- *storage_pointer_alloc = node_ui_storage;
+ NodeErrorsTooltipData *tooltip_data = (NodeErrorsTooltipData *)MEM_mallocN(
+ sizeof(NodeErrorsTooltipData), __func__);
+ tooltip_data->warnings = warnings;
- const NodeWarningType display_type = node_error_highest_priority(node_ui_storage->warnings);
+ const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
@@ -1303,7 +1508,7 @@ static void node_add_error_message_button(
0,
0,
nullptr);
- UI_but_func_tooltip_set(but, node_errors_tooltip_fn, storage_pointer_alloc, MEM_freeN);
+ UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
UI_block_emboss_set(node.block, UI_EMBOSS);
}
@@ -1423,28 +1628,6 @@ static void node_draw_basis(const bContext *C,
"");
UI_block_emboss_set(node->block, UI_EMBOSS);
}
- if (ntree->type == NTREE_GEOMETRY) {
- /* Active preview toggle. */
- iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- int icon = (node->flag & NODE_ACTIVE_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON;
- uiBut *but = uiDefIconBut(node->block,
- UI_BTYPE_BUT_TOGGLE,
- 0,
- icon,
- iconofs,
- rct->ymax - NODE_DY,
- iconbutw,
- UI_UNIT_Y,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "Show this node's geometry output in the spreadsheet");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_active_preview_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
- }
node_add_error_message_button(C, *ntree, *node, *rct, iconofs);