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.hh14
-rw-r--r--source/blender/editors/interface/CMakeLists.txt3
-rw-r--r--source/blender/editors/interface/interface_region_search.c11
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc125
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc78
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc211
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh23
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc11
8 files changed, 362 insertions, 114 deletions
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 4a583d0225e..5edccfa8c88 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -24,10 +24,22 @@
#include "BLI_string_ref.hh"
+namespace blender::nodes::geometry_nodes_eval_log {
+struct GeometryAttributeInfo;
+}
+
struct uiBlock;
namespace blender::ui {
class AbstractTreeView;
-}
+
+void attribute_search_add_items(
+ StringRefNull str,
+ const bool is_output,
+ Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
+ uiSearchItems *items,
+ const bool is_first);
+
+} // namespace blender::ui
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 8fcc704a301..b2659f5ed52 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -25,9 +25,11 @@ set(INC
../../depsgraph
../../draw
../../gpu
+ ../../functions
../../imbuf
../../makesdna
../../makesrna
+ ../../nodes
../../python
../../render
../../windowmanager
@@ -69,6 +71,7 @@ set(SRC
interface_style.c
interface_template_asset_view.cc
interface_template_list.cc
+ interface_template_attribute_search.cc
interface_template_search_menu.c
interface_template_search_operator.c
interface_templates.c
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 1cd3ef89ed3..5bea03dee63 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -316,7 +316,11 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
- BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen);
+ /* Search button with dynamic string properties may have their own method of applying
+ * the search results, so only copy the result if there is a proper space for it. */
+ if (but->hardmax != 0) {
+ BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen);
+ }
search_but->item_active = data->items.pointers[data->active];
@@ -878,7 +882,8 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
else {
data->items.maxitem = SEARCH_ITEMS;
}
- data->items.maxstrlen = but->hardmax;
+ /* In case the button's string is dynamic, make sure there are buffers available. */
+ data->items.maxstrlen = but->hardmax == 0 ? UI_MAX_NAME_STR : but->hardmax;
data->items.totitem = 0;
data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names");
data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers");
@@ -886,7 +891,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags");
data->items.name_prefix_offsets = NULL; /* Lazy initialized as needed. */
for (int i = 0; i < data->items.maxitem; i++) {
- data->items.names[i] = MEM_callocN(but->hardmax + 1, "search pointers");
+ data->items.names[i] = MEM_callocN(data->items.maxstrlen + 1, "search pointers");
}
return region;
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
new file mode 100644
index 00000000000..0157d0b66a3
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -0,0 +1,125 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BLI_string_ref.hh"
+#include "BLI_string_search.h"
+
+#include "DNA_customdata_types.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_geometry_nodes_eval_log.hh"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo;
+
+namespace blender::ui {
+
+static StringRef attribute_data_type_string(const CustomDataType type)
+{
+ const char *name = nullptr;
+ RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name);
+ return StringRef(IFACE_(name));
+}
+
+static StringRef attribute_domain_string(const AttributeDomain domain)
+{
+ const char *name = nullptr;
+ RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
+ return StringRef(IFACE_(name));
+}
+
+static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
+{
+ const StringRef data_type_name = attribute_data_type_string(item.data_type);
+ const StringRef domain_name = attribute_domain_string(item.domain);
+ std::string search_item_text = domain_name + " " + UI_MENU_ARROW_SEP + item.name + UI_SEP_CHAR +
+ data_type_name;
+
+ return UI_search_item_add(
+ items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
+}
+
+void attribute_search_add_items(StringRefNull str,
+ const bool is_output,
+ Span<const GeometryAttributeInfo *> infos,
+ uiSearchItems *seach_items,
+ const bool is_first)
+{
+ static GeometryAttributeInfo dummy_info;
+
+ /* Any string may be valid, so add the current search string along with the hints. */
+ if (str[0] != '\0') {
+ bool contained = false;
+ for (const GeometryAttributeInfo *attribute_info : infos) {
+ if (attribute_info->name == str) {
+ contained = true;
+ break;
+ }
+ }
+ if (!contained && is_output) {
+ dummy_info.name = str;
+ UI_search_item_add(seach_items, str.c_str(), &dummy_info, ICON_ADD, 0, 0);
+ }
+ }
+
+ if (str[0] == '\0' && !is_first) {
+ /* Allow clearing the text field when the string is empty, but not on the first pass,
+ * or opening an attribute field for the first time would show this search item. */
+ dummy_info.name = str;
+ UI_search_item_add(seach_items, str.c_str(), &dummy_info, ICON_X, 0, 0);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str.c_str();
+
+ StringSearch *search = BLI_string_search_new();
+ for (const GeometryAttributeInfo *item : infos) {
+
+ /* Don't show the legacy "normal" attribute. */
+ if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) {
+ continue;
+ }
+
+ BLI_string_search_add(search, item->name.c_str(), (void *)item);
+ }
+
+ GeometryAttributeInfo **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ const GeometryAttributeInfo *item = filtered_items[i];
+ if (!attribute_search_item_add(seach_items, *item)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+} // namespace blender::ui \ No newline at end of file
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index a69109db69c..d0ccbb03107 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
#include "UI_interface.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "NOD_geometry_nodes_eval_log.hh"
@@ -60,37 +61,6 @@ struct AttributeSearchData {
/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
-static StringRef attribute_data_type_string(const CustomDataType type)
-{
- const char *name = nullptr;
- RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name);
- return StringRef(IFACE_(name));
-}
-
-static StringRef attribute_domain_string(const AttributeDomain domain)
-{
- const char *name = nullptr;
- RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
- return StringRef(IFACE_(name));
-}
-
-static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
-{
- const StringRef data_type_name = attribute_data_type_string(item.data_type);
- const StringRef domain_name = attribute_domain_string(item.domain);
- std::string search_item_text = domain_name + " " + UI_MENU_ARROW_SEP + item.name + UI_SEP_CHAR +
- data_type_name;
-
- return UI_search_item_add(
- items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
-}
-
-static GeometryAttributeInfo &get_dummy_item_info()
-{
- static GeometryAttributeInfo info;
- return info;
-}
-
static void attribute_search_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
@@ -104,51 +74,7 @@ static void attribute_search_update_fn(
}
blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes();
- GeometryAttributeInfo &dummy_info = get_dummy_item_info();
-
- /* Any string may be valid, so add the current search string along with the hints. */
- if (str[0] != '\0') {
- bool contained = false;
- for (const GeometryAttributeInfo *attribute_info : infos) {
- if (attribute_info->name == str) {
- contained = true;
- break;
- }
- }
- if (!contained) {
- dummy_info.name = str;
- UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0);
- }
- }
-
- if (str[0] == '\0' && !is_first) {
- /* Allow clearing the text field when the string is empty, but not on the first pass,
- * or opening an attribute field for the first time would show this search item. */
- dummy_info.name = str;
- UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0);
- }
-
- /* Don't filter when the menu is first opened, but still run the search
- * so the items are in the same order they will appear in while searching. */
- const char *string = is_first ? "" : str;
-
- StringSearch *search = BLI_string_search_new();
- for (const GeometryAttributeInfo *item : infos) {
- BLI_string_search_add(search, item->name.c_str(), (void *)item);
- }
-
- GeometryAttributeInfo **filtered_items;
- const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
-
- for (const int i : IndexRange(filtered_amount)) {
- const GeometryAttributeInfo *item = filtered_items[i];
- if (!attribute_search_item_add(items, *item)) {
- break;
- }
- }
-
- MEM_freeN(filtered_items);
- BLI_string_search_free(search);
+ blender::ui::attribute_search_add_items(str, true, infos, items, is_first);
}
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 562589e2610..e6cc7663c58 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -27,11 +27,13 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.hh"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
@@ -66,6 +68,7 @@
#include "BLO_read_write.h"
#include "UI_interface.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "BLT_translation.h"
@@ -84,6 +87,7 @@
#include "MOD_ui_common.h"
#include "ED_spreadsheet.h"
+#include "ED_undo.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
@@ -93,6 +97,7 @@
#include "FN_field.hh"
#include "FN_multi_function.hh"
+using blender::Array;
using blender::ColorGeometry4f;
using blender::destruct_ptr;
using blender::float3;
@@ -114,6 +119,7 @@ using blender::nodes::InputSocketFieldType;
using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
+using geo_log::GeometryAttributeInfo;
static void initData(ModifierData *md)
{
@@ -957,9 +963,6 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
}
}
- /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
- input_geometry_set.clear();
-
Vector<DInputSocket> group_outputs;
for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) {
group_outputs.append({root_context, socket_ref});
@@ -974,8 +977,13 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end());
geo_logger.emplace(std::move(preview_sockets));
+
+ geo_logger->log_input_geometry(input_geometry_set);
}
+ /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
+ input_geometry_set.clear();
+
eval_params.input_values = group_inputs;
eval_params.output_sockets = group_outputs;
eval_params.mf_by_node = &mf_by_node;
@@ -985,14 +993,15 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params);
+ GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
+
if (geo_logger.has_value()) {
+ geo_logger->log_output_geometry(output_geometry_set);
NodesModifierData *nmd_orig = (NodesModifierData *)BKE_modifier_get_original(&nmd->modifier);
clear_runtime_data(nmd_orig);
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
}
- GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
-
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
GMutablePointer socket_value = eval_params.r_output_values[socket->index()];
store_output_value_in_geometry(output_geometry_set, nmd, *socket, socket_value);
@@ -1108,6 +1117,154 @@ static void modifyGeometrySet(ModifierData *md,
modifyGeometry(md, ctx, *geometry_set);
}
+struct AttributeSearchData {
+ const geo_log::ModifierLog &modifier_log;
+ IDProperty &name_property;
+ bool is_output;
+};
+
+/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
+BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
+
+static void attribute_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
+
+ const geo_log::GeometryValueLog *geometry_log = data->is_output ?
+ data->modifier_log.output_geometry_log() :
+ data->modifier_log.input_geometry_log();
+ if (geometry_log == nullptr) {
+ return;
+ }
+
+ Span<GeometryAttributeInfo> infos = geometry_log->attributes();
+
+ /* The shared attribute search code expects a span of pointers, so convert to that. */
+ Array<const GeometryAttributeInfo *> info_ptrs(infos.size());
+ for (const int i : infos.index_range()) {
+ info_ptrs[i] = &infos[i];
+ }
+ blender::ui::attribute_search_add_items(
+ str, data->is_output, info_ptrs.as_span(), items, is_first);
+}
+
+static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
+{
+ if (item_v == nullptr) {
+ return;
+ }
+ AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
+ const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
+
+ IDProperty &name_property = data.name_property;
+ BLI_assert(name_property.type == IDP_STRING);
+ IDP_AssignString(&name_property, item.name.c_str(), 0);
+
+ ED_undo_push(C, "Assign Attribute Name");
+}
+
+static void add_attribute_search_button(uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const StringRefNull rna_path_attribute_name,
+ const bNodeSocket &socket,
+ const bool is_output)
+{
+ const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log);
+ if (log == nullptr) {
+ uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, "", ICON_NONE);
+ return;
+ }
+
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but = uiDefIconTextButR(block,
+ UI_BTYPE_SEARCH_MENU,
+ 0,
+ ICON_NONE,
+ "",
+ 0,
+ 0,
+ 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
+ UI_UNIT_Y,
+ md_ptr,
+ rna_path_attribute_name.c_str(),
+ 0,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
+ const std::string use_attribute_prop_name = socket.identifier + attribute_name_suffix;
+ IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
+ use_attribute_prop_name.c_str());
+ BLI_assert(property != nullptr);
+ if (property == nullptr) {
+ return;
+ }
+
+ AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData,
+ {*log, *property, is_output});
+
+ UI_but_func_search_set_results_are_suggestions(but, true);
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ attribute_search_update_fn,
+ static_cast<void *>(data),
+ true,
+ nullptr,
+ attribute_search_exec_fn,
+ nullptr);
+}
+
+static void add_attribute_search_or_value_buttons(uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const bNodeSocket &socket)
+{
+ char socket_id_esc[sizeof(socket.identifier) * 2];
+ BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
+ const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]";
+ const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
+ use_attribute_suffix + "\"]";
+ const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
+ attribute_name_suffix + "\"]";
+
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+
+ PointerRNA props;
+ uiItemFullO(row,
+ "object.geometry_nodes_input_attribute_toggle",
+ "",
+ ICON_SPREADSHEET,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "modifier_name", nmd.modifier.name);
+ RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+
+ const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
+ if (use_attribute) {
+ add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, false);
+ uiItemL(row, "", ICON_BLANK1);
+ }
+ else {
+ uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE);
+ uiItemDecoratorR(row, md_ptr, rna_path.c_str(), 0);
+ }
+}
+
/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
* the node socket identifier for the property names, since they are unique, but also having
* the correct label displayed in the UI. */
@@ -1166,39 +1323,19 @@ static void draw_property_for_socket(uiLayout *layout,
}
default: {
if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
- const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
- use_attribute_suffix + "\"]";
- const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
- attribute_name_suffix + "\"]";
-
- uiLayout *row = uiLayoutRow(layout, true);
- const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
- if (use_attribute) {
- uiItemR(row, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
- }
- else {
- uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
- }
- PointerRNA props;
- uiItemFullO(row,
- "object.geometry_nodes_input_attribute_toggle",
- "",
- ICON_SPREADSHEET,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- &props);
- RNA_string_set(&props, "modifier_name", nmd->modifier.name);
- RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+ add_attribute_search_or_value_buttons(layout, *nmd, md_ptr, socket);
}
else {
- uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ uiItemDecoratorR(row, md_ptr, rna_path, 0);
}
}
}
}
static void draw_property_for_output_socket(uiLayout *layout,
+ const NodesModifierData &nmd,
PointerRNA *md_ptr,
const bNodeSocket &socket)
{
@@ -1207,7 +1344,13 @@ static void draw_property_for_output_socket(uiLayout *layout,
const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
attribute_name_suffix + "\"]";
- uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+ add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, true);
}
static void panel_draw(const bContext *C, Panel *panel)
@@ -1219,7 +1362,9 @@ static void panel_draw(const bContext *C, Panel *panel)
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, true);
+ /* Decorators are added manually for supported properties because the
+ * attribute/value toggle requires a manually built layout anyway. */
+ uiLayoutSetPropDecorate(layout, false);
uiTemplateID(layout,
C,
@@ -1282,7 +1427,7 @@ static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel)
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
if (socket_type_has_attribute_toggle(*socket)) {
- draw_property_for_output_socket(layout, ptr, *socket);
+ draw_property_for_output_socket(layout, *nmd, ptr, *socket);
}
}
}
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index ffe2a0d63c3..830a7d4070c 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -109,7 +109,7 @@ class GeometryValueLog : public ValueLog {
std::optional<PointCloudInfo> pointcloud_info;
std::optional<InstancesInfo> instances_info;
- GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
+ GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry = false);
Span<GeometryAttributeInfo> attributes() const
{
@@ -189,7 +189,12 @@ class GeoLogger {
Set<DSocket> log_full_sockets_;
threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_;
+ /* These are only optional since they don't have a default constructor. */
+ std::unique_ptr<GeometryValueLog> input_geometry_log_;
+ std::unique_ptr<GeometryValueLog> output_geometry_log_;
+
friend LocalGeoLogger;
+ friend ModifierLog;
public:
GeoLogger(Set<DSocket> log_full_sockets)
@@ -198,6 +203,16 @@ class GeoLogger {
{
}
+ void log_input_geometry(const GeometrySet &geometry)
+ {
+ input_geometry_log_ = std::make_unique<GeometryValueLog>(geometry);
+ }
+
+ void log_output_geometry(const GeometrySet &geometry)
+ {
+ output_geometry_log_ = std::make_unique<GeometryValueLog>(geometry);
+ }
+
LocalGeoLogger &local()
{
return threadlocals_.local();
@@ -283,6 +298,9 @@ class ModifierLog {
destruct_ptr<TreeLog> root_tree_logs_;
Vector<destruct_ptr<ValueLog>> logged_values_;
+ std::unique_ptr<GeometryValueLog> input_geometry_log_;
+ std::unique_ptr<GeometryValueLog> output_geometry_log_;
+
public:
ModifierLog(GeoLogger &logger);
@@ -303,6 +321,9 @@ class ModifierLog {
const SpaceSpreadsheet &sspreadsheet);
void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const;
+ const GeometryValueLog *input_geometry_log() const;
+ const GeometryValueLog *output_geometry_log() const;
+
private:
using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index d39f8367686..852f52f38cd 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -26,6 +26,8 @@ namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
ModifierLog::ModifierLog(GeoLogger &logger)
+ : input_geometry_log_(std::move(logger.input_geometry_log_)),
+ output_geometry_log_(std::move(logger.output_geometry_log_))
{
root_tree_logs_ = allocator_.construct<TreeLog>();
@@ -106,6 +108,15 @@ void ModifierLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const
}
}
+const GeometryValueLog *ModifierLog::input_geometry_log() const
+{
+ return input_geometry_log_.get();
+}
+const GeometryValueLog *ModifierLog::output_geometry_log() const
+{
+ return output_geometry_log_.get();
+}
+
const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
{
const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);