42 uiBut *but_ =
nullptr;
46 enum class TooltipBlockType {
53 std::optional<TooltipBlockType> last_block_type_;
61 : tip_data_(tip_data),
63 node_(socket.owner_node()),
72 const bool is_extend =
StringRef(socket_.idname) ==
"NodeSocketVirtual";
74 this->build_tooltip_extend_socket();
77 if (node_.is_dangling_reroute()) {
78 this->build_tooltip_dangling_reroute();
81 if (this->should_show_label()) {
82 this->build_tooltip_label();
84 this->build_tooltip_description();
85 this->build_tooltip_value();
93 void build_tooltip_extend_socket()
95 this->add_text_field(
TIP_(
"Connect a link to create a new socket."));
98 void build_tooltip_dangling_reroute()
103 bool should_show_label()
105 if (this->get_socket_description().value_or(
"").empty()) {
109 if (socket_.is_output()) {
115 if (socket_.runtime->declaration && socket_.runtime->declaration->optional_label) {
121 void build_tooltip_label()
123 this->start_block(TooltipBlockType::Label);
124 if (node_.is_reroute()) {
125 this->add_text_field_header(
TIP_(
"Reroute"));
129 this->add_text_field_header(translated_socket_label);
132 void build_tooltip_description()
134 std::optional<std::string> description_opt = this->get_socket_description();
135 if (!description_opt) {
138 std::string description = std::move(*description_opt);
139 if (description.empty()) {
142 if (description[description.size() - 1] !=
'.') {
145 this->start_block(TooltipBlockType::Description);
146 this->add_text_field(std::move(description));
149 std::optional<std::string> get_socket_description()
151 if (socket_.runtime->declaration ==
nullptr) {
152 if (socket_.description[0]) {
153 return socket_.description;
157 const nodes::SocketDeclaration &socket_decl = *socket_.runtime->declaration;
158 if (!socket_decl.description.empty()) {
159 return TIP_(socket_decl.description);
161 if (socket_decl.align_with_previous_socket) {
162 const Span<nodes::ItemDeclarationPtr> all_items = node_.runtime->declaration->all_items;
164 if (&*all_items[
i] != &socket_decl) {
170 const nodes::SocketDeclaration *previous_socket_decl =
171 dynamic_cast<const nodes::SocketDeclaration *
>(all_items[
i - 1].get());
172 if (!previous_socket_decl) {
175 if (!previous_socket_decl->description.empty()) {
176 return TIP_(previous_socket_decl->description);
184 void build_tooltip_value()
187 geo_log::ContextualGeoTreeLogs geo_tree_logs;
192 if (geo_tree_log && this->build_tooltip_value_from_geometry_nodes_log(*geo_tree_log)) {
196 if (node_.is_reroute()) {
197 if (always_show_value) {
198 this->start_block(TooltipBlockType::Value);
199 this->build_tooltip_value_unknown();
203 if (socket_.is_input()) {
204 if (this->is_socket_default_value_used()) {
205 this->build_tooltip_value_socket_default();
209 if (always_show_value) {
210 this->start_block(TooltipBlockType::Value);
211 this->build_tooltip_value_unknown();
215 void build_tooltip_value_unknown()
217 this->add_text_field_mono(
TIP_(
"Value: Unknown (not evaluated)"));
220 void build_tooltip_value_socket_default()
222 if (socket_.is_multi_input()) {
223 this->start_block(TooltipBlockType::Value);
224 this->add_text_field_mono(
TIP_(
"Values: None"));
227 const nodes::SocketDeclaration *socket_decl = socket_.runtime->declaration;
229 this->start_block(TooltipBlockType::Value);
230 build_tooltip_value_implicit_default(socket_decl->default_input_type);
233 if (socket_decl && socket_decl->structure_type == nodes::StructureType::Grid) {
234 this->start_block(TooltipBlockType::Value);
235 this->build_tooltip_value_and_type_oneline(
TIP_(
"Empty Grid"),
TIP_(
"Volume Grid"));
238 if (socket_.typeinfo->base_cpp_type ==
nullptr) {
241 const CPPType &cpp_type = *socket_.typeinfo->base_cpp_type;
243 socket_.typeinfo->get_base_cpp_value(socket_.default_value, socket_value);
245 this->start_block(TooltipBlockType::Value);
246 this->build_tooltip_value_generic({cpp_type, socket_value});
249 [[nodiscard]]
bool build_tooltip_value_from_geometry_nodes_log(geo_log::GeoTreeLog &geo_tree_log)
251 if (socket_.typeinfo->base_cpp_type ==
nullptr) {
255 if (socket_.is_multi_input()) {
256 return this->build_tooltip_last_value_multi_input(geo_tree_log);
262 this->start_block(TooltipBlockType::Value);
263 this->build_tooltip_value_geo_log(*value_log);
267 bool build_tooltip_last_value_multi_input(geo_log::GeoTreeLog &geo_tree_log)
269 const Span<const bNodeLink *> connected_links = socket_.directly_linked_links();
271 Vector<std::pair<int, geo_log::ValueLog *>> value_logs;
272 bool all_value_logs_missing =
true;
275 if (!link.is_used()) {
283 value_logs.
append({
i, value_log});
285 all_value_logs_missing =
false;
288 if (all_value_logs_missing) {
292 this->start_block(TooltipBlockType::Value);
293 for (
const auto &[
i, value_log] : value_logs) {
294 const int connection_number =
i + 1;
298 this->add_text_field_mono(fmt::format(
"{}:", connection_number));
303 this->build_tooltip_value_geo_log(*value_log);
306 this->build_tooltip_value_unknown();
313 void build_tooltip_value_geo_log(geo_log::ValueLog &value_log)
315 if (
const auto *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *
>(&value_log))
317 this->build_tooltip_value_generic(generic_value_log->value);
319 else if (
const auto *string_value_log =
dynamic_cast<const geo_log::StringLog *
>(&value_log)) {
320 this->build_tooltip_value_string_log(*string_value_log);
322 else if (
const auto *field_value_log =
dynamic_cast<const geo_log::FieldInfoLog *
>(&value_log))
324 this->build_tooltip_value_field_log(*field_value_log);
326 else if (
const auto *geometry_log =
dynamic_cast<const geo_log::GeometryInfoLog *
>(&value_log))
328 this->build_tooltip_value_geometry_log(*geometry_log);
330 else if (
const auto *grid_log =
dynamic_cast<const geo_log::GridInfoLog *
>(&value_log)) {
331 build_tooltip_value_grid_log(*grid_log);
333 else if (
const auto *bundle_log =
dynamic_cast<const geo_log::BundleValueLog *
>(&value_log)) {
334 this->build_tooltip_value_bundle_log(*bundle_log);
336 else if (
const auto *closure_log =
dynamic_cast<const geo_log::ClosureValueLog *
>(&value_log))
338 this->build_tooltip_value_closure_log(*closure_log);
340 else if (
const auto *list_log =
dynamic_cast<const geo_log::ListInfoLog *
>(&value_log)) {
341 this->build_tooltip_value_list_log(*list_log);
345 void build_tooltip_value_and_type_oneline(
const StringRef value,
const StringRef type)
347 this->add_text_field_mono(fmt::format(
"{}: {}",
TIP_(
"Value"), value));
349 this->add_text_field_mono(fmt::format(
"{}: {}",
TIP_(
"Type"), type));
352 template<
typename T> [[nodiscard]]
bool build_tooltip_value_data_block(
const GPointer &value)
354 const CPPType &type = *value.type();
355 if (!type.
is<
T *>()) {
358 const T *
data = *value.get<
T *>();
359 std::string value_str;
364 value_str =
TIP_(
"None");
366 const ID_Type id_type = T::id_type;
369 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(id_type_name));
373 void build_tooltip_value_enum(
const nodes::MenuValue menu_item)
376 if (!storage->enum_items || storage->has_conflict()) {
377 this->build_tooltip_value_and_type_oneline(
TIP_(
"Unknown"),
TIP_(
"Menu"));
380 const bke::RuntimeNodeEnumItem *enum_item = storage->
enum_items->find_item_by_identifier(
385 if (!enum_item->description.empty()) {
389 this->build_tooltip_value_and_type_oneline(
TIP_(enum_item->name),
TIP_(
"Menu"));
392 void build_tooltip_value_int(
const int value)
394 std::string value_str = fmt::format(
"{}", value);
395 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Integer"));
398 void build_tooltip_value_float(
const float value)
400 std::string value_str;
402 if (std::abs(value) > (1 << 24)) {
405 value_str = fmt::format(
"{:.10}", value);
408 value_str = fmt::format(
"{}", value);
410 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Float"));
413 void build_tooltip_value_float3(
const float3 &value)
415 const std::string value_str = fmt::format(
"{} {} {}", value.
x, value.
y, value.
z);
416 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"3D Float Vector"));
421 const std::string value_str = fmt::format(
422 "{} {} {} {} ({})", value.r, value.g, value.b, value.a,
TIP_(
"Linear"));
423 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Float Color"));
426 bool is_gamma =
false;
444 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Rotation"));
447 void build_tooltip_value_bool(
const bool value)
449 std::string value_str = value ?
TIP_(
"True") :
TIP_(
"False");
450 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Boolean"));
453 void build_tooltip_value_float4x4(
const float4x4 &value)
458 std::stringstream ss;
459 for (
const int row_i : IndexRange(4)) {
460 const float4 row = value_transposed[row_i];
461 ss << fmt::format(
"{:7.3} {:7.3} {:7.3} {:7.3}\n", row[0], row[1], row[2], row[3]);
464 this->add_text_field_mono(fmt::format(
"{}:",
TIP_(
"Value")));
466 this->add_text_field_mono(ss.str());
468 this->add_text_field_mono(fmt::format(
"{}: {}",
TIP_(
"Type"),
TIP_(
"4x4 Float Matrix")));
471 void build_tooltip_value_generic(
const GPointer &value)
474 const CPPType &value_type = *value.type();
475 if (this->build_tooltip_value_data_block<Object>(value)) {
478 if (this->build_tooltip_value_data_block<Material>(value)) {
481 if (this->build_tooltip_value_data_block<Tex>(value)) {
484 if (this->build_tooltip_value_data_block<Image>(value)) {
487 if (this->build_tooltip_value_data_block<Collection>(value)) {
492 if (!value_type.
is<nodes::MenuValue>()) {
493 this->build_tooltip_value_unknown();
496 const nodes::MenuValue menu_item = *value.get<nodes::MenuValue>();
497 this->build_tooltip_value_enum(menu_item);
501 const CPPType &socket_base_cpp_type = *socket_.typeinfo->base_cpp_type;
503 if (value_type != socket_base_cpp_type) {
504 if (!conversions.is_convertible(value_type, socket_base_cpp_type)) {
505 this->build_tooltip_value_unknown();
510 conversions.convert_to_uninitialized(
511 value_type, socket_base_cpp_type, value.get(), socket_value);
514 if (socket_base_cpp_type.
is<
int>()) {
515 this->build_tooltip_value_int(*
static_cast<int *
>(socket_value));
518 if (socket_base_cpp_type.
is<
float>()) {
519 this->build_tooltip_value_float(*
static_cast<float *
>(socket_value));
522 if (socket_base_cpp_type.
is<
float3>()) {
523 this->build_tooltip_value_float3(*
static_cast<float3 *
>(socket_value));
527 this->build_tooltip_value_color(*
static_cast<ColorGeometry4f *
>(socket_value));
531 this->build_tooltip_value_quaternion(*
static_cast<math::Quaternion *
>(socket_value));
534 if (socket_base_cpp_type.
is<
bool>()) {
535 this->build_tooltip_value_bool(*
static_cast<bool *
>(socket_value));
539 this->build_tooltip_value_float4x4(*
static_cast<float4x4 *
>(socket_value));
542 this->build_tooltip_value_unknown();
545 void build_tooltip_value_string_log(
const geo_log::StringLog &value_log)
547 std::string value_str = value_log.
value;
551 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"String"));
554 const char *get_field_type_name(
const CPPType &base_type)
556 if (base_type.
is<
int>()) {
557 return TIP_(
"Integer Field");
559 if (base_type.
is<
float>()) {
560 return TIP_(
"Float Field");
563 return TIP_(
"3D Float Vector Field");
565 if (base_type.
is<
bool>()) {
566 return TIP_(
"Boolean Field");
568 if (base_type.
is<std::string>()) {
569 return TIP_(
"String Field");
572 return TIP_(
"Color Field");
575 return TIP_(
"Rotation Field");
578 return TIP_(
"Matrix Field");
581 return TIP_(
"Field");
584 void build_tooltip_value_field_log(
const geo_log::FieldInfoLog &value_log)
586 const CPPType &socket_base_cpp_type = *socket_.typeinfo->base_cpp_type;
587 const Span<std::string> input_tooltips = value_log.
input_tooltips;
595 this->add_text_field_mono(
TIP_(
"Field depending on:"));
597 for (
const std::string &input_tooltip : input_tooltips) {
599 this->add_text_field_mono(fmt::format(
" \u2022 {}", input_tooltip));
603 std::string type_str = this->get_field_type_name(socket_base_cpp_type);
604 this->add_text_field_mono(fmt::format(
"{}: {}",
TIP_(
"Type"), type_str));
607 std::string count_to_string(
const int count)
611 return std::string(
str);
614 void build_tooltip_value_geometry_log(
const geo_log::GeometryInfoLog &geometry_log)
616 Span<bke::GeometryComponent::Type> component_types = geometry_log.
component_types;
618 this->build_tooltip_value_and_type_oneline(
TIP_(
"None"),
TIP_(
"Geometry Set"));
621 this->add_text_field_mono(
TIP_(
"Geometry components:"));
623 std::string component_str;
626 const geo_log::GeometryInfoLog::MeshInfo &info = *geometry_log.
mesh_info;
627 component_str = fmt::format(fmt::runtime(
TIP_(
"Mesh: {} vertices, {} edges, {} faces")),
634 const geo_log::GeometryInfoLog::PointCloudInfo &info = *geometry_log.
pointcloud_info;
635 component_str = fmt::format(fmt::runtime(
TIP_(
"Point Cloud: {} points")),
640 const geo_log::GeometryInfoLog::InstancesInfo &info = *geometry_log.
instances_info;
641 component_str = fmt::format(fmt::runtime(
TIP_(
"Instances: {}")),
646 const geo_log::GeometryInfoLog::VolumeInfo &info = *geometry_log.
volume_info;
647 component_str = fmt::format(fmt::runtime(
TIP_(
"Volume: {} grids")),
648 this->count_to_string(info.
grids.size()));
652 const geo_log::GeometryInfoLog::CurveInfo &info = *geometry_log.
curve_info;
653 component_str = fmt::format(fmt::runtime(
TIP_(
"Curve: {} points, {} splines")),
659 const geo_log::GeometryInfoLog::GreasePencilInfo &info =
661 component_str = fmt::format(fmt::runtime(
TIP_(
"Grease Pencil: {} layers")),
667 const geo_log::GeometryInfoLog::EditDataInfo &info = *geometry_log.
edit_data_info;
668 component_str = fmt::format(
669 fmt::runtime(
TIP_(
"Edit: {}, {}, {}")),
677 if (!component_str.empty()) {
679 this->add_text_field_mono(fmt::format(
" \u2022 {}", component_str));
683 this->add_text_field_mono(
TIP_(
"Type: Geometry Set"));
686 void build_tooltip_value_grid_log(
const geo_log::GridInfoLog &grid_log)
688 std::string value_str;
690 value_str =
TIP_(
"None");
693 value_str =
TIP_(
"Volume Grid");
695 this->build_tooltip_value_and_type_oneline(value_str,
TIP_(
"Volume Grid"));
698 void build_tooltip_value_bundle_log(
const geo_log::BundleValueLog &bundle_log)
701 this->add_text_field_mono(
TIP_(
"Values: None"));
704 this->add_text_field_mono(
TIP_(
"Values:"));
705 Vector<geo_log::BundleValueLog::Item> sorted_items = bundle_log.
items;
706 std::sort(sorted_items.
begin(), sorted_items.
end(), [](
const auto &a,
const auto &
b) {
707 return BLI_strcasecmp_natural(a.key.c_str(), b.key.c_str()) < 0;
709 for (
const geo_log::BundleValueLog::Item &item : sorted_items) {
711 std::string type_name;
712 if (
const bke::bNodeSocketType *
const *socket_type =
713 std::get_if<const bke::bNodeSocketType *>(&item.type))
715 type_name =
TIP_((*socket_type)->label);
717 else if (
const StringRefNull *internal_type_name = std::get_if<StringRefNull>(&item.type))
719 type_name = *internal_type_name;
721 this->add_text_field_mono(
722 fmt::format(fmt::runtime(
"\u2022 \"{}\" ({})\n"), item.key, type_name));
726 this->add_text_field_mono(
TIP_(
"Type: Bundle"));
729 void build_tooltip_value_closure_log(
const geo_log::ClosureValueLog &closure_log)
732 this->add_text_field_mono(
TIP_(
"Value: None"));
736 this->add_text_field_mono(
TIP_(
"Inputs:"));
737 for (
const geo_log::ClosureValueLog::Item &item : closure_log.
inputs) {
740 this->add_text_field_mono(
741 fmt::format(fmt::runtime(
"\u2022 \"{}\" ({})\n"), item.
key, type_name));
746 this->add_text_field_mono(
TIP_(
"Outputs:"));
747 for (
const geo_log::ClosureValueLog::Item &item : closure_log.
outputs) {
750 this->add_text_field_mono(
751 fmt::format(fmt::runtime(
"\u2022 \"{}\" ({})\n"), item.
key, type_name));
756 this->add_text_field_mono(
TIP_(
"Type: Closure"));
759 void build_tooltip_value_list_log(
const geo_log::ListInfoLog &list_log)
761 this->add_text_field_mono(fmt::format(
"{}: {}",
TIP_(
"Length"), list_log.
size));
763 this->add_text_field_mono(
TIP_(
"Type: List"));
775 this->build_tooltip_value_and_type_oneline(
TIP_(
"Index Field"),
780 this->build_tooltip_value_and_type_oneline(
TIP_(
"ID or Index Field"),
785 this->build_tooltip_value_and_type_oneline(
790 this->build_tooltip_value_and_type_oneline(
795 this->build_tooltip_value_and_type_oneline(
800 this->build_tooltip_value_and_type_oneline(
805 this->build_tooltip_value_and_type_oneline(
811 bool is_socket_default_value_used()
814 for (
const bNodeLink *link : socket_.directly_linked_links()) {
815 if (!link->is_used()) {
819 const bNode &from_node = from_socket.owner_node();
820 if (from_node.is_dangling_reroute()) {
828 StringRef get_structure_type_tooltip(
const nodes::StructureType &structure_type)
830 switch (structure_type) {
831 case nodes::StructureType::Single: {
832 return TIP_(
"Single Value");
834 case nodes::StructureType::Dynamic: {
835 return TIP_(
"Dynamic");
837 case nodes::StructureType::Field: {
838 return TIP_(
"Field");
840 case nodes::StructureType::Grid: {
841 return TIP_(
"Volume Grid");
843 case nodes::StructureType::List: {
862 void start_block(
const TooltipBlockType new_block_type)
864 if (last_block_type_.has_value()) {
867 last_block_type_ = new_block_type;
870 void add_text_field_header(std::string text)
886 void add_space(
const int amount = 1)
888 for ([[maybe_unused]]
const int i : IndexRange(amount)) {
893 std::string indent(std::string text)
895 if (indentation_ == 0) {
898 return fmt::format(
"{: <{}}{}",
"", indentation_, text);