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:
authorHans Goudey <h.goudey@me.com>2021-10-21 21:54:48 +0300
committerHans Goudey <h.goudey@me.com>2021-10-21 21:54:48 +0300
commit1d96a482675dd2ccad2af31c274f74b9f6603d6b (patch)
treebeb0406f7a9f1e6b826cc590eeab69e361a83b3b /source/blender
parent65490e62708c6bb0c03d9c73fd7179fdf71355a5 (diff)
Geometry Nodes: Attribute search in the modifier
This adds attribute search to the geometry nodes modifier for the input and output attributes. The "New" search item is only shown for the output attributes. Some of the attribute search code is extracted to a new file in the interface code, to avoid some code duplication. The UI code required two fixes so that the search would work for dynamic length strings (IDProperties do not have a fixed size). Since this does changes to the UI layout of the modifier, I also addressed T91485 here. Differential Revisiion: https://developer.blender.org/D12788
Diffstat (limited to 'source/blender')
-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);