37#include "RNA_prototypes.hh"
50struct PanelOpenProperty {
56 geo_log::GeoTreeLog *tree_log =
nullptr;
61struct ModifierSearchData {
66struct OperatorSearchData {
71struct SocketSearchData {
72 std::variant<ModifierSearchData, OperatorSearchData> search_data;
76 SearchInfo info(
const bContext &
C)
const;
81struct DrawGroupInputsContext {
84 geo_log::GeoTreeLog *tree_log;
86 PointerRNA *properties_ptr;
87 PointerRNA *bmain_ptr;
88 Array<nodes::socket_usage_inference::SocketUsage> input_usages;
89 Array<nodes::socket_usage_inference::SocketUsage> output_usages;
90 bool use_name_for_ids =
false;
94 draw_attribute_toggle_fn;
98 return this->input_usages[this->
tree->interface_input_index(socket)].is_visible;
103 return this->input_usages[this->
tree->interface_input_index(socket)].is_used;
114 return &nmd.
runtime->eval_log->get_tree_log(compute_context.
hash());
119 const ModifierSearchData &
data)
130 if (
object ==
nullptr) {
141SearchInfo SocketSearchData::info(
const bContext &
C)
const
143 if (
const auto *modifier_search_data = std::get_if<ModifierSearchData>(&this->search_data)) {
146 if (nmd ==
nullptr) {
155 if (
const auto *operator_search_data = std::get_if<OperatorSearchData>(&this->search_data)) {
156 return operator_search_data->info;
164 const SocketSearchData &
data = *
static_cast<SocketSearchData *
>(arg);
165 const SearchInfo info =
data.info(*
C);
166 if (!info.tree || !info.tree_log) {
169 info.tree_log->ensure_layer_names();
170 info.tree->ensure_topology_cache();
173 for (
const bNode *node : info.tree->group_input_nodes()) {
174 for (
const bNodeSocket *socket : node->output_sockets()) {
176 sockets_to_check.
append(socket);
183 for (
const bNodeSocket *socket : sockets_to_check) {
184 const geo_log::ValueLog *value_log = info.tree_log->find_socket_value_log(*socket);
185 if (value_log ==
nullptr) {
189 if (
const std::optional<geo_log::GeometryInfoLog::GreasePencilInfo> &grease_pencil_info =
192 for (
const std::string &
name : grease_pencil_info->layer_names) {
206 const SocketSearchData &
data = *
static_cast<SocketSearchData *
>(data_v);
207 const std::string *item =
static_cast<std::string *
>(item_v);
211 const SearchInfo info =
data.info(*
C);
212 if (!info.properties) {
245 ICON_OUTLINER_DATA_GP_LAYER,
256 layout->
label(
"", ICON_BLANK1);
260 if (
object ==
nullptr) {
266 SocketSearchData *
data =
static_cast<SocketSearchData *
>(
268 *
data = ctx.socket_search_data_fn(socket);
284 SocketSearchData &
data = *
static_cast<SocketSearchData *
>(arg);
285 const SearchInfo info =
data.info(*
C);
286 if (!info.tree || !info.tree_log) {
289 info.tree_log->ensure_existing_attributes();
290 info.tree->ensure_topology_cache();
293 if (
data.is_output) {
294 for (
const bNode *node : info.tree->nodes_by_type(
"NodeGroupOutput")) {
295 for (
const bNodeSocket *socket : node->input_sockets()) {
297 sockets_to_check.
append(socket);
303 for (
const bNode *node : info.tree->group_input_nodes()) {
304 for (
const bNodeSocket *socket : node->output_sockets()) {
306 sockets_to_check.
append(socket);
313 for (
const bNodeSocket *socket : sockets_to_check) {
314 const geo_log::ValueLog *value_log = info.tree_log->find_socket_value_log(*socket);
315 if (value_log ==
nullptr) {
320 if (names.
add(attribute.
name)) {
321 attributes.
append(&attribute);
331 if (item_v ==
nullptr) {
334 SocketSearchData &
data = *
static_cast<SocketSearchData *
>(data_v);
336 const SearchInfo info =
data.info(*
C);
337 if (!info.properties) {
341 const std::string attribute_prop_name =
data.socket_identifier +
355 layout->
prop(ctx.properties_ptr, rna_path_attribute_name,
UI_ITEM_NONE,
"", ICON_NONE);
370 rna_path_attribute_name,
376 if (
object ==
nullptr) {
382 SocketSearchData *
data =
static_cast<SocketSearchData *
>(
384 *
data = ctx.socket_search_data_fn(socket);
396 std::string attribute_name =
RNA_string_get(ctx.properties_ptr, rna_path_attribute_name.
c_str());
398 if (!access_allowed) {
404 DrawGroupInputsContext &ctx,
408 const std::optional<StringRefNull> use_name = std::nullopt)
412 const std::string rna_path_attribute_name = fmt::format(
430 name_row->
label(
"", ICON_NONE);
431 prop_row = &
split->row(
true);
434 prop_row = &layout->
row(
true);
442 if (attribute_name) {
444 prop_row = &
split->row(
true);
446 layout->
label(
"", ICON_BLANK1);
454 ctx.draw_attribute_toggle_fn(*prop_row, ICON_SPREADSHEET, socket);
473 const std::optional<StringRef> parent_name = std::nullopt)
481 if (property ==
nullptr ||
487 const int input_index = ctx.tree->interface_input_index(socket);
488 if (!ctx.input_is_visible(socket)) {
509 if (parent_name.has_value()) {
510 const StringRef prefix_to_remove = *parent_name;
511 const int prefix_size = prefix_to_remove.
size();
512 const int pos =
name.find(prefix_to_remove);
513 if (
pos == 0 &&
name.size() > prefix_size &&
name[prefix_size] ==
' ') {
514 name =
name.substr(prefix_size + 1);
521 ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"objects",
name, ICON_OBJECT_DATA);
530 ICON_OUTLINER_COLLECTION);
535 ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"materials",
name, ICON_MATERIAL);
540 ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"textures",
name, ICON_TEXTURE);
560 row->
prop_search(ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"images",
name, ICON_IMAGE);
568 row->
prop(ctx.properties_ptr,
583 row->
label(
"", ICON_BLANK1);
598 row->
label(
"", ICON_BLANK1);
613 if (ctx.input_is_visible(socket)) {
641 if (ctx.input_is_active(socket)) {
656 DrawGroupInputsContext &ctx,
659 const bool skip_first =
false,
660 const std::optional<StringRef> parent_name = std::nullopt);
669 PanelOpenProperty open_property = ctx.panel_open_property_fn(interface_panel);
671 bool skip_first =
false;
680 if (property ==
nullptr ||
695 panel_layout = layout.
panel_prop(&ctx.C, &open_property.ptr, open_property.name);
704 const auto *panel = static_cast<bNodeTreeInterfacePanel *>(panel_arg);
705 return StringRef(panel->description);
710 if (panel_layout.
body) {
718 const bool skip_first,
719 const std::optional<StringRef> parent_name)
743 const int num_warnings,
746 fmt::memory_buffer buffer;
747 fmt::appender buf = fmt::appender(buffer);
748 if (num_errors > 0) {
749 fmt::format_to(buf,
"{} ({})",
IFACE_(
"Errors"), num_errors);
751 if (num_warnings > 0) {
752 if (num_errors > 0) {
753 fmt::format_to(buf,
", ");
755 fmt::format_to(buf,
"{} ({})",
IFACE_(
"Warnings"), num_warnings);
758 if (num_errors > 0 || num_warnings > 0) {
759 fmt::format_to(buf,
", ");
761 fmt::format_to(buf,
"{} ({})",
IFACE_(
"Info"), num_infos);
763 return std::string(buffer.data(), buffer.size());
771 if (
G.is_rendering) {
781 const int warnings_num = tree_log->all_warnings.size();
782 if (warnings_num == 0) {
786 for (
const NodeWarning &warning : tree_log->all_warnings) {
794 panel.
header->
label(panel_name.c_str(), ICON_NONE);
800 warnings[
i] = &tree_log->all_warnings[
i];
802 std::sort(warnings.
begin(), warnings.
end(), [](
const NodeWarning *a,
const NodeWarning *
b) {
803 const int severity_a = node_warning_type_severity(a->type);
804 const int severity_b = node_warning_type_severity(b->type);
805 if (severity_a > severity_b) {
808 if (severity_a < severity_b) {
816 for (
const NodeWarning *warning : warnings) {
820 block,
ButType::Label, 0, icon, message, 0, 0, 1,
UI_UNIT_Y,
nullptr, std::nullopt);
826 return *
static_cast<std::string *
>(argN);
828 MEM_new<std::string>(__func__, message),
829 [](
void *arg) { MEM_delete(
static_cast<std::string *
>(arg)); });
852 const std::string rna_path_attribute_name = fmt::format(
866 if (!ctx.tree || !ctx.properties) {
874 if (!ctx.output_usages[
i].is_visible) {
886 col->use_property_split_set(
true);
887 col->use_property_decorate_set(
false);
888 col->prop(modifier_ptr,
"bake_target",
UI_ITEM_NONE, std::nullopt, ICON_NONE);
894 if (
G.is_rendering) {
899 if (tree_log ==
nullptr) {
907 if (usage_by_attribute.
is_empty()) {
908 layout->
label(
RPT_(
"No named attributes used"), ICON_INFO);
912 struct NameWithUsage {
918 for (
auto &&item : usage_by_attribute.
items()) {
919 sorted_used_attribute.
append({item.key, item.value});
921 std::sort(sorted_used_attribute.
begin(),
922 sorted_used_attribute.
end(),
923 [](
const NameWithUsage &a,
const NameWithUsage &
b) {
924 return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) < 0;
927 for (
const NameWithUsage &attribute : sorted_used_attribute) {
928 const StringRef attribute_name = attribute.name;
934 std::stringstream ss;
947 if (
i < usages.size() - 1) {
955 row->
label(ss.str(), ICON_NONE);
957 row = &
split->row(
false);
958 row->
label(attribute_name, ICON_NONE);
968 C, modifier_ptr,
"open_bake_panel",
IFACE_(
"Bake")))
973 C, modifier_ptr,
"open_named_attributes_panel",
IFACE_(
"Named Attributes")))
986 DrawGroupInputsContext ctx{
C,
996 modifier_ptr->
owner_id, &RNA_NodesModifierPanel, panel);
997 return {panel_ptr,
"is_open"};
1000 SocketSearchData
data{};
1001 ModifierSearchData &modifier_search_data =
data.search_data.emplace<ModifierSearchData>();
1002 modifier_search_data.object_session_uid =
object.id.session_uid;
1008 ctx.draw_attribute_toggle_fn =
1010 PointerRNA props = layout.
op(
"object.geometry_nodes_input_attribute_toggle",
1025 const char *newop = (nmd.
node_group ==
nullptr) ?
"node.new_geometry_node_group_assign" :
1026 "object.geometry_node_tree_copy_assign";
1027 uiTemplateID(&layout, &
C, modifier_ptr,
"node_group", newop,
nullptr,
nullptr);
1031 nmd.
runtime->usage_cache.ensure(nmd);
1032 ctx.input_usages = nmd.
runtime->usage_cache.inputs;
1033 ctx.output_usages = nmd.
runtime->usage_cache.outputs;
1043 &
C, modifier_ptr,
"open_output_attributes_panel",
IFACE_(
"Output Attributes")))
1051 &
C, modifier_ptr,
"open_manage_panel",
IFACE_(
"Manage")))
1072 "node_operator_panel_" + std::to_string(io_panel.identifier),
1075 return {state_ptr,
"is_open"};
1078 SocketSearchData
data{};
1079 OperatorSearchData &operator_search_data =
data.search_data.emplace<OperatorSearchData>();
1080 operator_search_data.info.tree = &
tree;
1081 operator_search_data.info.tree_log = tree_log;
1082 operator_search_data.info.properties = op.
properties;
1087 ctx.draw_attribute_toggle_fn =
1089 const std::string prop_name = fmt::format(
1093 ctx.use_name_for_ids =
true;
1100 tree.ensure_interface_cache();
1101 ctx.input_usages.reinitialize(
tree.interface_inputs().size());
1102 ctx.output_usages.reinitialize(
tree.interface_outputs().size());
1104 tree, ctx.properties, ctx.input_usages, ctx.output_usages);
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, blender::StringRef name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void IDP_AssignString(IDProperty *prop, const char *st) ATTR_NONNULL()
IDProperty * IDP_GetPropertyFromGroup_null(const IDProperty *prop, blender::StringRef name) ATTR_WARN_UNUSED_RESULT
ID * BKE_libblock_find_session_uid(Main *bmain, short type, uint32_t session_uid)
ModifierData * BKE_modifiers_findby_name(const Object *ob, const char *name)
LayoutPanelState * BKE_panel_layout_panel_state_ensure(Panel *panel, blender::StringRef idname, bool default_closed)
#define BLI_STATIC_ASSERT(a, msg)
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
struct IDProperty IDProperty
@ NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR
@ NODES_MODIFIER_HIDE_MANAGE_PANEL
NodeTreeInterfaceItemType
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NODE_INTERFACE_SOCKET_OUTPUT
@ NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER
@ NODE_INTERFACE_SOCKET_INPUT
@ NODE_INTERFACE_SOCKET_MENU_EXPANDED
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct bNodeTreeInterfacePanel bNodeTreeInterfacePanel
struct bNodeTree bNodeTree
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_undo_push(bContext *C, const char *str)
static void split(const char *text, const char *seps, char ***str, int *count)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
uiBut * uiDefIconTextBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, std::optional< blender::StringRef > tip)
void UI_but_placeholder_set(uiBut *but, blender::StringRef placeholder_text)
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
@ UI_TEMPLATE_ID_FILTER_ALL
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, blender::StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, std::optional< blender::StringRef > text=std::nullopt)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
uiBut * uiDefIconTextButR(uiBlock *block, ButType type, int retval, int icon, std::optional< blender::StringRefNull > str, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
void uiLayoutSetTooltipFunc(uiLayout *layout, uiButToolTipFunc func, void *arg, uiCopyArgFunc copy_arg, uiFreeArgFunc free_arg)
BMesh const char void * data
const ComputeContextHash & hash() const
Value lookup_default(const Key &key, const Value &default_value) const
ItemIterator items() const &
Value & lookup_or_add(const Key &key, const Value &value)
constexpr IndexRange index_range() const
constexpr int64_t size() const
constexpr const char * c_str() const
void append(const T &value)
IndexRange index_range() const
Span< T > as_span() const
void ensure_used_named_attributes()
Map< StringRefNull, NamedAttributeUsage > used_named_attributes
static const char * modifier_name[LS_MODIFIER_NUM]
void * MEM_mallocN(size_t len, const char *str)
bool allow_procedural_attribute_access(StringRef attribute_name)
Object * context_object(const bContext *C)
void infer_group_interface_usage(const bNodeTree &group, const Span< InferenceValue > group_input_values, const MutableSpan< SocketUsage > r_input_usages, const std::optional< MutableSpan< SocketUsage > > r_output_usages)
std::optional< StringRef > input_attribute_name_get(const IDProperty *properties, const bNodeTreeInterfaceSocket &io_input)
static void draw_output_attributes_panel(DrawGroupInputsContext &ctx, uiLayout *layout)
bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
static void add_layer_name_search_button(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfaceSocket &socket)
static void draw_warnings(const bContext *C, const NodesModifierData &nmd, uiLayout *layout, PointerRNA *md_ptr)
static bool interface_panel_affects_output(DrawGroupInputsContext &ctx, const bNodeTreeInterfacePanel &panel)
bool id_property_type_matches_socket(const bNodeTreeInterfaceSocket &socket, const IDProperty &property, const bool use_name_for_ids)
int node_warning_type_icon(const NodeWarningType type)
static geo_log::GeoTreeLog * get_root_tree_log(const NodesModifierData &nmd)
static void add_attribute_search_or_value_buttons(DrawGroupInputsContext &ctx, uiLayout *layout, const StringRefNull rna_path, const bNodeTreeInterfaceSocket &socket, const std::optional< StringRefNull > use_name=std::nullopt)
static void draw_bake_panel(uiLayout *layout, PointerRNA *modifier_ptr)
void draw_geometry_nodes_modifier_ui(const bContext &C, PointerRNA *modifier_ptr, uiLayout &layout)
static void layer_name_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static void draw_manage_panel(const bContext *C, uiLayout *layout, PointerRNA *modifier_ptr, NodesModifierData &nmd)
static void attribute_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static void draw_interface_panel_as_panel(DrawGroupInputsContext &ctx, uiLayout &layout, const bNodeTreeInterfacePanel &interface_panel)
static std::string get_node_warning_panel_name(const int num_errors, const int num_warnings, const int num_infos)
static void draw_named_attributes_panel(uiLayout *layout, NodesModifierData &nmd)
static void draw_interface_panel_content(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfacePanel &interface_panel, const bool skip_first=false, const std::optional< StringRef > parent_name=std::nullopt)
static void layer_name_search_exec_fn(bContext *C, void *data_v, void *item_v)
static void add_attribute_search_button(DrawGroupInputsContext &ctx, uiLayout *layout, const StringRefNull rna_path_attribute_name, const bNodeTreeInterfaceSocket &socket)
static bool interface_panel_has_socket(DrawGroupInputsContext &ctx, const bNodeTreeInterfacePanel &interface_panel)
static NodesModifierData * get_modifier_data(Main &bmain, const wmWindowManager &wm, const ModifierSearchData &data)
static void draw_property_for_socket(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfaceSocket &socket, const std::optional< StringRef > parent_name=std::nullopt)
void draw_geometry_nodes_operator_redo_ui(const bContext &C, wmOperator &op, bNodeTree &tree, geo_eval_log::GeoTreeLog *tree_log)
bool socket_type_has_attribute_toggle(const eNodeSocketDatatype type)
constexpr StringRef input_attribute_name_suffix
static bool has_output_attribute(const bNodeTree *tree)
constexpr StringRef input_use_attribute_suffix
static NodesModifierPanel * find_panel_by_id(NodesModifierData &nmd, const int id)
static void draw_property_for_output_socket(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfaceSocket &socket)
void grease_pencil_layer_search_add_items(StringRef str, Span< const std::string * > layer_names, uiSearchItems &items, bool is_first)
void attribute_search_add_items(StringRef str, bool can_create_attribute, Span< const nodes::geo_eval_log::GeometryAttributeInfo * > infos, uiSearchItems *items, bool is_first)
bool is_layer_selection_field(const bNodeTreeInterfaceSocket &socket)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_main_pointer_create(Main *main)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
#define UI_MENU_ARROW_SEP
NodesModifierPanel * panels
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
struct NodesModifierSettings settings
struct IDProperty * properties
bNodeTreeInterfacePanel root_panel
bNodeTreeInterface tree_interface
void use_property_decorate_set(bool is_sep)
void alignment_set(blender::ui::LayoutAlign alignment)
void decorator(PointerRNA *ptr, PropertyRNA *prop, int index)
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
PanelLayout panel_prop_with_bool_header(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name, PointerRNA *bool_prop_owner, blender::StringRefNull bool_prop_name, std::optional< blender::StringRef > label)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void prop_search(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop, PropertyRNA *item_searchpropname, std::optional< blender::StringRefNull > name, int icon, bool results_are_suggestions)
void active_set(bool active)
uiLayout & row(bool align)
uiLayout & split(float percentage, bool align)
Panel * root_panel() const
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)