Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_draw.cc
| Show First 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | |||||
| #include "node_intern.hh" /* own include */ | #include "node_intern.hh" /* own include */ | ||||
| using blender::GPointer; | using blender::GPointer; | ||||
| using blender::fn::FieldCPPType; | using blender::fn::FieldCPPType; | ||||
| using blender::fn::FieldInput; | using blender::fn::FieldInput; | ||||
| using blender::fn::GField; | using blender::fn::GField; | ||||
| namespace geo_log = blender::nodes::geometry_nodes_eval_log; | namespace geo_log = blender::nodes::geometry_nodes_eval_log; | ||||
| using geo_log::NamedAttributeUsage; | |||||
| extern "C" { | extern "C" { | ||||
| /* XXX interface.h */ | /* XXX interface.h */ | ||||
| extern void ui_draw_dropshadow( | extern void ui_draw_dropshadow( | ||||
| const rctf *rct, float radius, float aspect, float alpha, int select); | const rctf *rct, float radius, float aspect, float alpha, int select); | ||||
| } | } | ||||
| float ED_node_grid_size() | float ED_node_grid_size() | ||||
| ▲ Show 20 Lines • Show All 1,532 Lines • ▼ Show 20 Lines | static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node) | ||||
| std::stringstream stream; | std::stringstream stream; | ||||
| stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f); | stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f); | ||||
| return stream.str() + " ms"; | return stream.str() + " ms"; | ||||
| } | } | ||||
| struct NodeExtraInfoRow { | struct NodeExtraInfoRow { | ||||
| std::string text; | std::string text; | ||||
| const char *tooltip; | const char *tooltip; | ||||
| std::string tooltip_dynamic; | |||||
| int icon; | int icon; | ||||
| }; | }; | ||||
| static NodeExtraInfoRow row_from_used_named_attribute( | |||||
| const Map<StringRefNull, NamedAttributeUsage> &usage_by_attribute_name) | |||||
| { | |||||
| std::stringstream ss; | |||||
| ss << TIP_("Accessed attribute names:\n"); | |||||
| Vector<std::pair<StringRefNull, NamedAttributeUsage>> sorted_used_attribute; | |||||
| for (auto &&item : usage_by_attribute_name.items()) { | |||||
| sorted_used_attribute.append({item.key, item.value}); | |||||
| } | |||||
| std::sort(sorted_used_attribute.begin(), sorted_used_attribute.end()); | |||||
| for (const std::pair<StringRefNull, NamedAttributeUsage> &attribute : sorted_used_attribute) { | |||||
| const StringRefNull name = attribute.first; | |||||
| const NamedAttributeUsage usage = attribute.second; | |||||
| ss << " \u2022 \"" << name << "\": "; | |||||
| Vector<std::string> usages; | |||||
| if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) { | |||||
| usages.append(TIP_("read")); | |||||
| } | |||||
| if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) { | |||||
| usages.append(TIP_("write")); | |||||
| } | |||||
| if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) { | |||||
| usages.append(TIP_("remove")); | |||||
| } | |||||
| for (const int i : usages.index_range()) { | |||||
| ss << usages[i]; | |||||
| if (i < usages.size() - 1) { | |||||
| ss << ", "; | |||||
| } | |||||
| } | |||||
| ss << "\n"; | |||||
| } | |||||
| ss << "\n"; | |||||
| ss << TIP_( | |||||
| "Attributes with these names created, read, modified or removed within the " | |||||
| "node group. Make sure they don't unintentionally conflict with existing attributes. " | |||||
| "Generally, prefer passing attributes explicitly using input and output sockets"); | |||||
| NodeExtraInfoRow row; | |||||
| row.text = "Attributes"; | |||||
HooglyBoogly: `TIP_` | |||||
| row.icon = ICON_SPREADSHEET; | |||||
| row.tooltip_dynamic = ss.str(); | |||||
| return row; | |||||
| } | |||||
| static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const SpaceNode &snode, | |||||
| const bNode &node) | |||||
| { | |||||
| if (node.type == NODE_GROUP) { | |||||
| const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( | |||||
| snode); | |||||
| if (root_tree_log == nullptr) { | |||||
| return std::nullopt; | |||||
| } | |||||
| const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name); | |||||
| if (tree_log == nullptr) { | |||||
| return std::nullopt; | |||||
| } | |||||
| Map<StringRefNull, NamedAttributeUsage> usage_by_attribute; | |||||
| tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { | |||||
| for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) { | |||||
| usage_by_attribute.lookup_or_add(used_attribute.name, | |||||
| used_attribute.usage) |= used_attribute.usage; | |||||
| } | |||||
| }); | |||||
| if (usage_by_attribute.is_empty()) { | |||||
| return std::nullopt; | |||||
| } | |||||
| return row_from_used_named_attribute(usage_by_attribute); | |||||
| } | |||||
| if (ELEM(node.type, | |||||
| GEO_NODE_STORE_NAMED_ATTRIBUTE, | |||||
| GEO_NODE_REMOVE_ATTRIBUTE, | |||||
| GEO_NODE_INPUT_NAMED_ATTRIBUTE)) { | |||||
| const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( | |||||
| snode, node.name); | |||||
| if (node_log == nullptr) { | |||||
| return std::nullopt; | |||||
| } | |||||
| Map<StringRefNull, NamedAttributeUsage> usage_by_attribute; | |||||
| for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) { | |||||
| usage_by_attribute.lookup_or_add(used_attribute.name, | |||||
| used_attribute.usage) |= used_attribute.usage; | |||||
| } | |||||
| if (usage_by_attribute.is_empty()) { | |||||
| return std::nullopt; | |||||
| } | |||||
| return row_from_used_named_attribute(usage_by_attribute); | |||||
| } | |||||
| return std::nullopt; | |||||
| } | |||||
| static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node) | static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node) | ||||
| { | { | ||||
| Vector<NodeExtraInfoRow> rows; | Vector<NodeExtraInfoRow> rows; | ||||
| if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) { | if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) { | ||||
| return rows; | return rows; | ||||
| } | } | ||||
| if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY && | if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY && | ||||
| Show All 14 Lines | static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node) | ||||
| if (node_log != nullptr) { | if (node_log != nullptr) { | ||||
| for (const std::string &message : node_log->debug_messages()) { | for (const std::string &message : node_log->debug_messages()) { | ||||
| NodeExtraInfoRow row; | NodeExtraInfoRow row; | ||||
| row.text = message; | row.text = message; | ||||
| row.icon = ICON_INFO; | row.icon = ICON_INFO; | ||||
| rows.append(std::move(row)); | rows.append(std::move(row)); | ||||
| } | } | ||||
| } | } | ||||
| if (snode.overlay.flag & SN_OVERLAY_SHOW_NAMED_ATTRIBUTES && | |||||
| snode.edittree->type == NTREE_GEOMETRY) { | |||||
| if (std::optional<NodeExtraInfoRow> row = node_get_accessed_attributes_row(snode, node)) { | |||||
| rows.append(std::move(*row)); | |||||
| } | |||||
| } | |||||
| return rows; | return rows; | ||||
| } | } | ||||
| static void node_draw_extra_info_row(const bNode &node, | static void node_draw_extra_info_row(const bNode &node, | ||||
| uiBlock &block, | uiBlock &block, | ||||
| const rctf &rect, | const rctf &rect, | ||||
| const int row, | const int row, | ||||
| const NodeExtraInfoRow &extra_info_row) | const NodeExtraInfoRow &extra_info_row) | ||||
| { | { | ||||
| uiBut *but_timing = uiDefBut(&block, | uiBut *but_text = uiDefBut(&block, | ||||
| UI_BTYPE_LABEL, | UI_BTYPE_LABEL, | ||||
| 0, | 0, | ||||
| extra_info_row.text.c_str(), | extra_info_row.text.c_str(), | ||||
| (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f), | (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f), | ||||
| (int)(rect.ymin + row * (20.0f * U.dpi_fac)), | (int)(rect.ymin + row * (20.0f * U.dpi_fac)), | ||||
| (short)(rect.xmax - rect.xmin), | (short)(rect.xmax - rect.xmin), | ||||
| (short)NODE_DY, | (short)NODE_DY, | ||||
| nullptr, | nullptr, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| ""); | ""); | ||||
| UI_block_emboss_set(&block, UI_EMBOSS_NONE); | UI_block_emboss_set(&block, UI_EMBOSS_NONE); | ||||
| uiBut *but_icon = uiDefIconBut(&block, | uiBut *but_icon = uiDefIconBut(&block, | ||||
| UI_BTYPE_BUT, | UI_BTYPE_BUT, | ||||
| 0, | 0, | ||||
| extra_info_row.icon, | extra_info_row.icon, | ||||
| (int)(rect.xmin + 6.0f * U.dpi_fac), | (int)(rect.xmin + 6.0f * U.dpi_fac), | ||||
| (int)(rect.ymin + row * (20.0f * U.dpi_fac)), | (int)(rect.ymin + row * (20.0f * U.dpi_fac)), | ||||
| NODE_HEADER_ICON_SIZE * 0.8f, | NODE_HEADER_ICON_SIZE * 0.8f, | ||||
| UI_UNIT_Y, | UI_UNIT_Y, | ||||
| nullptr, | nullptr, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| extra_info_row.tooltip); | extra_info_row.tooltip); | ||||
| if (!extra_info_row.tooltip_dynamic.empty()) { | |||||
| UI_but_func_tooltip_set( | |||||
| but_icon, | |||||
| [](struct bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) { | |||||
| return BLI_strdup(static_cast<const char *>(argN)); | |||||
| }, | |||||
| BLI_strdup(extra_info_row.tooltip_dynamic.c_str()), | |||||
| MEM_freeN); | |||||
HooglyBooglyUnsubmitted Not Done Inline ActionsI would expect this string to be built by a callback rather than all the time. I think a pointer to the node (or its name or index) would be all that's necessary to pass to a callback. HooglyBoogly: I would expect this string to be built by a callback rather than all the time. I think a… | |||||
JacquesLuckeAuthorUnsubmitted Done Inline ActionsI moved some of the stuff in the callback, but it doesn't work super nicely yet, because the bulk of the work (finding the used attributes) still has to be all the time. Think that can be improved with a more general logger refactor. JacquesLucke: I moved some of the stuff in the callback, but it doesn't work super nicely yet, because the… | |||||
HooglyBooglyUnsubmitted Not Done Inline ActionsHmm, right, because finding whether there are any named attribute usages in a node group is basically the same work as gathering them for a tooltip. The iteration over all nodes in a group is ugly, but I agree that it's a more general problem that's out of scope here. HooglyBoogly: Hmm, right, because finding whether there are any named attribute usages in a node group is… | |||||
| } | |||||
| UI_block_emboss_set(&block, UI_EMBOSS); | UI_block_emboss_set(&block, UI_EMBOSS); | ||||
| if (node.flag & NODE_MUTED) { | if (node.flag & NODE_MUTED) { | ||||
| UI_but_flag_enable(but_timing, UI_BUT_INACTIVE); | UI_but_flag_enable(but_text, UI_BUT_INACTIVE); | ||||
| UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); | UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); | ||||
| } | } | ||||
| } | } | ||||
| static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block) | static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block) | ||||
| { | { | ||||
| Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node); | Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node); | ||||
| ▲ Show 20 Lines • Show All 1,192 Lines • Show Last 20 Lines | |||||
TIP_