35#include "RNA_prototypes.hh"
48struct PanelOpenProperty {
54 geo_log::GeoTreeLog *tree_log =
nullptr;
59struct ModifierSearchData {
64struct OperatorSearchData {
69struct SocketSearchData {
70 std::variant<ModifierSearchData, OperatorSearchData> search_data;
74 SearchInfo info(
const bContext &
C)
const;
79struct DrawGroupInputsContext {
82 geo_log::GeoTreeLog *tree_log;
83 nodes::PropertiesVectorSet properties;
84 PointerRNA *properties_ptr;
85 PointerRNA *bmain_ptr;
86 Array<nodes::socket_usage_inference::SocketUsage> input_usages;
87 bool use_name_for_ids =
false;
91 draw_attribute_toggle_fn;
95 return this->input_usages[this->
tree->interface_input_index(socket)].is_visible;
100 return this->input_usages[this->
tree->interface_input_index(socket)].is_used;
111 return &nmd.
runtime->eval_log->get_tree_log(compute_context.
hash());
116 const ModifierSearchData &
data)
127 if (
object ==
nullptr) {
138SearchInfo SocketSearchData::info(
const bContext &
C)
const
140 if (
const auto *modifier_search_data = std::get_if<ModifierSearchData>(&this->search_data)) {
143 if (nmd ==
nullptr) {
152 if (
const auto *operator_search_data = std::get_if<OperatorSearchData>(&this->search_data)) {
153 return operator_search_data->info;
161 const SocketSearchData &
data = *
static_cast<SocketSearchData *
>(arg);
162 const SearchInfo info =
data.info(*
C);
163 if (!info.tree || !info.tree_log) {
166 info.tree_log->ensure_layer_names();
167 info.tree->ensure_topology_cache();
170 for (
const bNode *node : info.tree->group_input_nodes()) {
171 for (
const bNodeSocket *socket : node->output_sockets()) {
173 sockets_to_check.
append(socket);
180 for (
const bNodeSocket *socket : sockets_to_check) {
181 const geo_log::ValueLog *value_log = info.tree_log->find_socket_value_log(*socket);
182 if (value_log ==
nullptr) {
186 if (
const std::optional<geo_log::GeometryInfoLog::GreasePencilInfo> &grease_pencil_info =
189 for (
const std::string &name : grease_pencil_info->layer_names) {
190 if (names.
add(name)) {
191 layer_names.
append(&name);
203 const SocketSearchData &
data = *
static_cast<SocketSearchData *
>(data_v);
204 const std::string *item =
static_cast<std::string *
>(item_v);
208 const SearchInfo info =
data.info(*
C);
209 if (!info.properties) {
242 ICON_OUTLINER_DATA_GP_LAYER,
255 layout->
label(
"", ICON_BLANK1);
259 if (
object ==
nullptr) {
265 SocketSearchData *
data =
static_cast<SocketSearchData *
>(
267 *
data = ctx.socket_search_data_fn(socket);
283 SocketSearchData &
data = *
static_cast<SocketSearchData *
>(arg);
284 const SearchInfo info =
data.info(*
C);
285 if (!info.tree || !info.tree_log) {
288 info.tree_log->ensure_existing_attributes();
289 info.tree->ensure_topology_cache();
292 if (
data.is_output) {
293 for (
const bNode *node : info.tree->nodes_by_type(
"NodeGroupOutput")) {
294 for (
const bNodeSocket *socket : node->input_sockets()) {
296 sockets_to_check.
append(socket);
302 for (
const bNode *node : info.tree->group_input_nodes()) {
303 for (
const bNodeSocket *socket : node->output_sockets()) {
305 sockets_to_check.
append(socket);
312 for (
const bNodeSocket *socket : sockets_to_check) {
313 const geo_log::ValueLog *value_log = info.tree_log->find_socket_value_log(*socket);
314 if (value_log ==
nullptr) {
319 if (names.
add(attribute.
name)) {
320 attributes.
append(&attribute);
330 if (item_v ==
nullptr) {
333 SocketSearchData &
data = *
static_cast<SocketSearchData *
>(data_v);
335 const SearchInfo info =
data.info(*
C);
336 if (!info.properties) {
340 const std::string attribute_prop_name =
data.socket_identifier +
354 layout->
prop(ctx.properties_ptr, rna_path_attribute_name,
UI_ITEM_NONE,
"", ICON_NONE);
369 rna_path_attribute_name,
377 if (
object ==
nullptr) {
383 SocketSearchData *
data =
static_cast<SocketSearchData *
>(
385 *
data = ctx.socket_search_data_fn(socket);
398 ctx.properties_ptr, rna_path_attribute_name.
c_str(),
nullptr, 0,
nullptr);
401 if (!access_allowed) {
407 DrawGroupInputsContext &ctx,
411 const std::optional<StringRefNull> use_name = std::nullopt)
415 const std::string rna_path_attribute_name = fmt::format(
433 name_row->
label(
"", ICON_NONE);
434 prop_row = &
split->row(
true);
437 prop_row = &layout->
row(
true);
445 if (attribute_name) {
447 prop_row = &
split->row(
true);
449 layout->
label(
"", ICON_BLANK1);
453 prop_row->
prop(ctx.properties_ptr, rna_path,
UI_ITEM_NONE, name, ICON_NONE);
457 ctx.draw_attribute_toggle_fn(*prop_row, ICON_SPREADSHEET, socket);
476 const std::optional<StringRefNull> parent_name = std::nullopt)
480 IDProperty *
property = ctx.properties.lookup_key_default_as(identifier,
nullptr);
484 if (property ==
nullptr ||
490 const int input_index = ctx.tree->interface_input_index(socket);
491 if (!ctx.input_is_visible(socket)) {
512 if (parent_name.has_value()) {
514 int pos = name.find(prefix_to_remove);
515 if (
pos == 0 && name != prefix_to_remove) {
527 row, ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"objects", name, ICON_OBJECT_DATA);
537 ICON_OUTLINER_COLLECTION);
542 row, ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"materials", name, ICON_MATERIAL);
547 row, ctx.properties_ptr, rna_path, ctx.bmain_ptr,
"textures", name, ICON_TEXTURE);
567 row->
prop(ctx.properties_ptr,
582 row->
label(
"", ICON_BLANK1);
597 row->
label(
"", ICON_BLANK1);
612 if (ctx.input_is_visible(socket)) {
640 if (ctx.input_is_active(socket)) {
655 DrawGroupInputsContext &ctx,
658 const bool skip_first =
false,
659 const std::optional<StringRefNull> parent_name = std::nullopt)
669 PanelOpenProperty open_property = ctx.panel_open_property_fn(sub_interface_panel);
671 bool skip_first =
false;
676 IDProperty *
property = ctx.properties.lookup_key_default_as(identifier,
nullptr);
680 *toggle_socket, *property, ctx.use_name_for_ids))
687 char rna_path[
sizeof(socket_id_esc) + 4];
688 SNPRINTF(rna_path,
"[\"%s\"]", socket_id_esc);
695 IFACE_(sub_interface_panel.name));
699 panel_layout = layout->
panel_prop(&ctx.C, &open_property.ptr, open_property.name);
708 const auto *panel = static_cast<bNodeTreeInterfacePanel *>(panel_arg);
709 return StringRef(panel->description);
714 if (panel_layout.
body) {
715 const StringRefNull panel_name = sub_interface_panel.name ? sub_interface_panel.name :
718 ctx, panel_layout.
body, sub_interface_panel, skip_first, panel_name);
740 if (
G.is_rendering) {
750 const int warnings_num = tree_log->all_warnings.size();
751 if (warnings_num == 0) {
755 panel.
header->
label(fmt::format(fmt::runtime(
IFACE_(
"Warnings ({})")), warnings_num).c_str(),
762 warnings[
i] = &tree_log->all_warnings[
i];
764 std::sort(warnings.
begin(), warnings.
end(), [](
const NodeWarning *a,
const NodeWarning *
b) {
765 const int severity_a = node_warning_type_severity(a->type);
766 const int severity_b = node_warning_type_severity(b->type);
767 if (severity_a > severity_b) {
770 if (severity_a < severity_b) {
777 for (
const NodeWarning *warning : warnings) {
779 col->label(warning->message, icon);
802 const std::string rna_path_attribute_name = fmt::format(
816 if (ctx.tree !=
nullptr && !ctx.properties.is_empty()) {
832 col->prop(modifier_ptr,
"bake_target",
UI_ITEM_NONE, std::nullopt, ICON_NONE);
838 if (
G.is_rendering) {
843 if (tree_log ==
nullptr) {
851 if (usage_by_attribute.
is_empty()) {
852 layout->
label(
RPT_(
"No named attributes used"), ICON_INFO);
856 struct NameWithUsage {
862 for (
auto &&item : usage_by_attribute.
items()) {
863 sorted_used_attribute.
append({item.key, item.value});
865 std::sort(sorted_used_attribute.
begin(),
866 sorted_used_attribute.
end(),
867 [](
const NameWithUsage &a,
const NameWithUsage &
b) {
868 return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) < 0;
871 for (
const NameWithUsage &attribute : sorted_used_attribute) {
872 const StringRef attribute_name = attribute.name;
878 std::stringstream ss;
891 if (
i < usages.size() - 1) {
899 row->
label(ss.str(), ICON_NONE);
901 row = &
split->row(
false);
902 row->
label(attribute_name, ICON_NONE);
912 C, modifier_ptr,
"open_bake_panel",
IFACE_(
"Bake")))
917 C, modifier_ptr,
"open_named_attributes_panel",
IFACE_(
"Named Attributes")))
930 DrawGroupInputsContext ctx{
C,
940 modifier_ptr->
owner_id, &RNA_NodesModifierPanel, panel);
941 return {panel_ptr,
"is_open"};
944 SocketSearchData
data{};
945 ModifierSearchData &modifier_search_data =
data.search_data.emplace<ModifierSearchData>();
946 modifier_search_data.object_session_uid =
object.id.session_uid;
948 STRNCPY(
data.socket_identifier, io_socket.identifier);
952 ctx.draw_attribute_toggle_fn =
954 PointerRNA props = layout.
op(
"object.geometry_nodes_input_attribute_toggle",
969 const char *newop = (nmd.
node_group ==
nullptr) ?
"node.new_geometry_node_group_assign" :
970 "object.geometry_node_tree_copy_assign";
971 uiTemplateID(&layout, &
C, modifier_ptr,
"node_group", newop,
nullptr,
nullptr);
976 ctx.input_usages.reinitialize(nmd.
node_group->interface_inputs().size());
978 *nmd.
node_group, ctx.properties, ctx.input_usages);
988 &
C, modifier_ptr,
"open_output_attributes_panel",
IFACE_(
"Output Attributes")))
995 &
C, modifier_ptr,
"open_manage_panel",
IFACE_(
"Manage")))
1010 DrawGroupInputsContext ctx{
1016 "node_operator_panel_" + std::to_string(io_panel.identifier),
1019 return {state_ptr,
"is_open"};
1022 SocketSearchData
data{};
1023 OperatorSearchData &operator_search_data =
data.search_data.emplace<OperatorSearchData>();
1024 operator_search_data.info.tree = &
tree;
1025 operator_search_data.info.tree_log = tree_log;
1026 operator_search_data.info.properties = op.
properties;
1027 STRNCPY(
data.socket_identifier, io_socket.identifier);
1031 ctx.draw_attribute_toggle_fn =
1033 const std::string prop_name = fmt::format(
1037 ctx.use_name_for_ids =
true;
1044 tree.ensure_interface_cache();
1045 ctx.input_usages.reinitialize(
tree.interface_inputs().size());
1047 tree, ctx.properties, ctx.input_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()
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)
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
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 CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
struct IDProperty IDProperty
@ NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR
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)
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_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
uiBut * uiDefIconTextButR(uiBlock *block, int 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, float min, float max, std::optional< blender::StringRef > tip)
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)
void UI_but_flag_enable(uiBut *but, int flag)
Panel * uiLayoutGetRootPanel(uiLayout *layout)
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, PointerRNA *searchptr, blender::StringRefNull searchpropname, std::optional< blender::StringRefNull > name, int icon)
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, std::optional< blender::StringRefNull > propname, int index)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiLayoutSetTooltipFunc(uiLayout *layout, uiButToolTipFunc func, void *arg, uiCopyArgFunc copy_arg, uiFreeArgFunc free_arg)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
BMesh const char void * data
const ComputeContextHash & hash() const
ItemIterator items() const &
constexpr int64_t size() const
constexpr StringRef trim() 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)
void MEM_freeN(void *vmemh)
bool allow_procedural_attribute_access(StringRef attribute_name)
Object * context_object(const bContext *C)
void infer_group_interface_inputs_usage(const bNodeTree &group, const Span< GPointer > group_input_values, const MutableSpan< SocketUsage > r_input_usages)
static void draw_output_attributes_panel(DrawGroupInputsContext &ctx, uiLayout *layout)
PropertiesVectorSet build_properties_vector_set(const IDProperty *properties)
bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
static void draw_interface_panel_content(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfacePanel &interface_panel, const bool skip_first=false, const std::optional< StringRefNull > parent_name=std::nullopt)
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)
static void draw_property_for_socket(DrawGroupInputsContext &ctx, uiLayout *layout, const bNodeTreeInterfaceSocket &socket, const std::optional< StringRefNull > parent_name=std::nullopt)
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_named_attributes_panel(uiLayout *layout, NodesModifierData &nmd)
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)
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
std::optional< StringRef > input_attribute_name_get(const PropertiesVectorSet &properties, const bNodeTreeInterfaceSocket &io_input)
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)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
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
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
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::StringRefNull > label)
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
uiLayout & row(bool align)
uiLayout & split(float percentage, bool align)
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)