Nodes: Support adding multiple nodes from search menu
Needed for the simulation zone addition to the add menu search. Link-drag search isn't supported yet, but a similar change should be possible there. Now the search item exposed through the public nodes namespace returns several items directly, and the "after add function" is just handled as a sub-case of that for convenience.
This commit is contained in:
@@ -37,16 +37,10 @@ struct bContext;
|
||||
|
||||
namespace blender::ed::space_node {
|
||||
|
||||
struct AddNodeItem {
|
||||
nodes::AddNodeInfo info;
|
||||
std::string identifier;
|
||||
const AssetRepresentation *asset;
|
||||
};
|
||||
|
||||
struct AddNodeSearchStorage {
|
||||
float2 cursor;
|
||||
bool use_transform;
|
||||
Vector<AddNodeItem> search_add_items;
|
||||
Vector<nodes::AddNodeItem> search_add_items;
|
||||
char search[256];
|
||||
bool update_items_tag = true;
|
||||
};
|
||||
@@ -67,7 +61,7 @@ static void add_node_search_listen_fn(const wmRegionListenerParams *params, void
|
||||
|
||||
static void search_items_for_asset_metadata(const bNodeTree &node_tree,
|
||||
const AssetHandle asset_handle,
|
||||
Vector<AddNodeItem> &search_items)
|
||||
nodes::GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset_handle);
|
||||
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type");
|
||||
@@ -76,28 +70,27 @@ static void search_items_for_asset_metadata(const bNodeTree &node_tree,
|
||||
}
|
||||
|
||||
const AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle);
|
||||
AddNodeItem item{};
|
||||
item.info.ui_name = ED_asset_handle_get_name(&asset_handle);
|
||||
item.identifier = node_tree.typeinfo->group_idname;
|
||||
item.info.description = asset_data.description == nullptr ? "" : asset_data.description;
|
||||
item.asset = asset;
|
||||
item.info.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.flag &= ~NODE_OPTIONS;
|
||||
node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT);
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(&node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
};
|
||||
|
||||
search_items.append(std::move(item));
|
||||
params.add_single_node_item(ED_asset_handle_get_name(&asset_handle),
|
||||
asset_data.description == nullptr ? "" : asset_data.description,
|
||||
[asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.flag &= ~NODE_OPTIONS;
|
||||
node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(
|
||||
&bmain, asset, ID_NT);
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(&node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
});
|
||||
}
|
||||
|
||||
static void gather_search_items_for_all_assets(const bContext &C,
|
||||
const bNodeTree &node_tree,
|
||||
Set<std::string> &r_added_assets,
|
||||
Vector<AddNodeItem> &search_items)
|
||||
Vector<nodes::AddNodeItem> &search_items)
|
||||
{
|
||||
const bNodeType &group_node_type = *nodeTypeFind(node_tree.typeinfo->group_idname);
|
||||
nodes::GatherAddNodeSearchParams params(C, group_node_type, node_tree, search_items);
|
||||
|
||||
AssetLibraryReference library_ref{};
|
||||
library_ref.custom_library_index = -1;
|
||||
library_ref.type = ASSET_LIBRARY_ALL;
|
||||
@@ -115,7 +108,7 @@ static void gather_search_items_for_all_assets(const bContext &C,
|
||||
/* If an asset with the same name has already been added, skip this. */
|
||||
return true;
|
||||
}
|
||||
search_items_for_asset_metadata(node_tree, asset, search_items);
|
||||
search_items_for_asset_metadata(node_tree, asset, params);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -123,9 +116,11 @@ static void gather_search_items_for_all_assets(const bContext &C,
|
||||
static void gather_search_items_for_node_groups(const bContext &C,
|
||||
const bNodeTree &node_tree,
|
||||
const Set<std::string> &local_assets,
|
||||
Vector<AddNodeItem> &search_items)
|
||||
Vector<nodes::AddNodeItem> &search_items)
|
||||
{
|
||||
const StringRef group_node_id = node_tree.typeinfo->group_idname;
|
||||
const StringRefNull group_node_id = node_tree.typeinfo->group_idname;
|
||||
const bNodeType &group_node_type = *nodeTypeFind(group_node_id.c_str());
|
||||
nodes::GatherAddNodeSearchParams params(C, group_node_type, node_tree, search_items);
|
||||
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
LISTBASE_FOREACH (bNodeTree *, node_group, &bmain.nodetrees) {
|
||||
@@ -138,23 +133,22 @@ static void gather_search_items_for_node_groups(const bContext &C,
|
||||
if (!nodeGroupPoll(&node_tree, node_group, nullptr)) {
|
||||
continue;
|
||||
}
|
||||
AddNodeItem item{};
|
||||
item.info.ui_name = node_group->id.name + 2;
|
||||
item.identifier = node_tree.typeinfo->group_idname;
|
||||
item.info.after_add_fn = [node_group](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.id = &node_group->id;
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(&node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
};
|
||||
search_items.append(std::move(item));
|
||||
params.add_single_node_item(
|
||||
node_group->id.name + 2,
|
||||
"",
|
||||
[node_group](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.id = &node_group->id;
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(&node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void gather_add_node_operations(const bContext &C,
|
||||
bNodeTree &node_tree,
|
||||
Vector<AddNodeItem> &r_search_items)
|
||||
Vector<nodes::AddNodeItem> &r_search_items)
|
||||
{
|
||||
NODE_TYPES_BEGIN (node_type) {
|
||||
const char *disabled_hint;
|
||||
@@ -167,15 +161,8 @@ static void gather_add_node_operations(const bContext &C,
|
||||
if (!node_type->gather_add_node_search_ops) {
|
||||
continue;
|
||||
}
|
||||
Vector<nodes::AddNodeInfo> info_items;
|
||||
nodes::GatherAddNodeSearchParams params(C, *node_type, node_tree, info_items);
|
||||
nodes::GatherAddNodeSearchParams params(C, *node_type, node_tree, r_search_items);
|
||||
node_type->gather_add_node_search_ops(params);
|
||||
for (nodes::AddNodeInfo &info : info_items) {
|
||||
AddNodeItem item{};
|
||||
item.info = std::move(info);
|
||||
item.identifier = node_type->idname;
|
||||
r_search_items.append(item);
|
||||
}
|
||||
}
|
||||
NODE_TYPES_END;
|
||||
|
||||
@@ -200,19 +187,19 @@ static void add_node_search_update_fn(
|
||||
|
||||
StringSearch *search = BLI_string_search_new();
|
||||
|
||||
for (AddNodeItem &item : storage.search_add_items) {
|
||||
BLI_string_search_add(search, item.info.ui_name.c_str(), &item, item.info.weight);
|
||||
for (nodes::AddNodeItem &item : storage.search_add_items) {
|
||||
BLI_string_search_add(search, item.ui_name.c_str(), &item, item.weight);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
AddNodeItem **filtered_items;
|
||||
nodes::AddNodeItem **filtered_items;
|
||||
const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
|
||||
|
||||
for (const int i : IndexRange(filtered_amount)) {
|
||||
AddNodeItem &item = *filtered_items[i];
|
||||
if (!UI_search_item_add(items, item.info.ui_name.c_str(), &item, ICON_NONE, 0, 0)) {
|
||||
nodes::AddNodeItem &item = *filtered_items[i];
|
||||
if (!UI_search_item_add(items, item.ui_name.c_str(), &item, ICON_NONE, 0, 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -227,24 +214,13 @@ static void add_node_search_exec_fn(bContext *C, void *arg1, void *arg2)
|
||||
SpaceNode &snode = *CTX_wm_space_node(C);
|
||||
bNodeTree &node_tree = *snode.edittree;
|
||||
AddNodeSearchStorage &storage = *static_cast<AddNodeSearchStorage *>(arg1);
|
||||
AddNodeItem *item = static_cast<AddNodeItem *>(arg2);
|
||||
nodes::AddNodeItem *item = static_cast<nodes::AddNodeItem *>(arg2);
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
node_deselect_all(node_tree);
|
||||
bNode *new_node = nodeAddNode(C, &node_tree, item->identifier.c_str());
|
||||
BLI_assert(new_node != nullptr);
|
||||
|
||||
if (item->info.after_add_fn) {
|
||||
item->info.after_add_fn(*C, node_tree, *new_node);
|
||||
}
|
||||
|
||||
new_node->locx = storage.cursor.x / UI_SCALE_FAC;
|
||||
new_node->locy = storage.cursor.y / UI_SCALE_FAC + 20;
|
||||
|
||||
nodeSetSelected(new_node, true);
|
||||
nodeSetActive(&node_tree, new_node);
|
||||
Vector<bNode *> new_nodes = item->add_fn(*C, node_tree, storage.cursor);
|
||||
|
||||
/* Ideally it would be possible to tag the node tree in some way so it updates only after the
|
||||
* translate operation is finished, but normally moving nodes around doesn't cause updates. */
|
||||
@@ -263,13 +239,12 @@ static void add_node_search_exec_fn(bContext *C, void *arg1, void *arg2)
|
||||
static ARegion *add_node_search_tooltip_fn(
|
||||
bContext *C, ARegion *region, const rcti *item_rect, void * /*arg*/, void *active)
|
||||
{
|
||||
const AddNodeItem *item = static_cast<const AddNodeItem *>(active);
|
||||
const nodes::AddNodeItem *item = static_cast<const nodes::AddNodeItem *>(active);
|
||||
|
||||
uiSearchItemTooltipData tooltip_data{};
|
||||
|
||||
BLI_strncpy(tooltip_data.description,
|
||||
item->asset ? item->info.description.c_str() : TIP_(item->info.description.c_str()),
|
||||
sizeof(tooltip_data.description));
|
||||
BLI_strncpy(
|
||||
tooltip_data.description, TIP_(item->description.c_str()), sizeof(tooltip_data.description));
|
||||
|
||||
return UI_tooltip_create_from_search_item_generic(C, region, item_rect, &tooltip_data);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <functional>
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@@ -16,25 +17,27 @@ struct bContext;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
struct AddNodeInfo {
|
||||
using AfterAddFn = std::function<void(const bContext &C, bNodeTree &node_tree, bNode &node)>;
|
||||
struct AddNodeItem {
|
||||
using AddFn =
|
||||
std::function<Vector<bNode *>(const bContext &C, bNodeTree &node_tree, float2 cursor)>;
|
||||
std::string ui_name;
|
||||
std::string description;
|
||||
AfterAddFn after_add_fn;
|
||||
int weight = 0;
|
||||
AddFn add_fn;
|
||||
};
|
||||
|
||||
class GatherAddNodeSearchParams {
|
||||
using AfterAddFn = std::function<void(const bContext &C, bNodeTree &node_tree, bNode &node)>;
|
||||
const bContext &C_;
|
||||
const bNodeType &node_type_;
|
||||
const bNodeTree &node_tree_;
|
||||
Vector<AddNodeInfo> &r_items;
|
||||
Vector<AddNodeItem> &r_items;
|
||||
|
||||
public:
|
||||
GatherAddNodeSearchParams(const bContext &C,
|
||||
const bNodeType &node_type,
|
||||
const bNodeTree &node_tree,
|
||||
Vector<AddNodeInfo> &r_items)
|
||||
Vector<AddNodeItem> &r_items)
|
||||
: C_(C), node_type_(node_type), node_tree_(node_tree), r_items(r_items)
|
||||
{
|
||||
}
|
||||
@@ -57,10 +60,11 @@ class GatherAddNodeSearchParams {
|
||||
/**
|
||||
* \param weight: Used to customize the order when multiple search items match.
|
||||
*/
|
||||
void add_item(std::string ui_name,
|
||||
std::string description,
|
||||
AddNodeInfo::AfterAddFn fn = {},
|
||||
int weight = 0);
|
||||
void add_single_node_item(std::string ui_name,
|
||||
std::string description,
|
||||
AfterAddFn after_add_fn = {},
|
||||
int weight = 0);
|
||||
void add_item(AddNodeItem item);
|
||||
};
|
||||
|
||||
void search_node_add_ops_for_basic_node(GatherAddNodeSearchParams ¶ms);
|
||||
|
||||
@@ -9,17 +9,39 @@
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
void GatherAddNodeSearchParams::add_item(std::string ui_name,
|
||||
std::string description,
|
||||
AddNodeInfo::AfterAddFn fn,
|
||||
int weight)
|
||||
void GatherAddNodeSearchParams::add_single_node_item(std::string ui_name,
|
||||
std::string description,
|
||||
AfterAddFn after_add_fn,
|
||||
int weight)
|
||||
{
|
||||
r_items.append(AddNodeInfo{std::move(ui_name), std::move(description), std::move(fn), weight});
|
||||
AddNodeItem item;
|
||||
item.ui_name = std::move(ui_name);
|
||||
item.description = std::move(description);
|
||||
item.weight = weight;
|
||||
item.add_fn = [after_add_fn = std::move(after_add_fn), node_type = node_type_](
|
||||
const bContext &C, bNodeTree &node_tree, const float2 cursor) {
|
||||
bNode *new_node = nodeAddNode(&C, &node_tree, node_type.idname);
|
||||
new_node->locx = cursor.x / UI_SCALE_FAC;
|
||||
new_node->locy = cursor.y / UI_SCALE_FAC + 20;
|
||||
nodeSetSelected(new_node, true);
|
||||
nodeSetActive(&node_tree, new_node);
|
||||
if (after_add_fn) {
|
||||
after_add_fn(C, node_tree, *new_node);
|
||||
}
|
||||
return Vector<bNode *>{new_node};
|
||||
};
|
||||
r_items.append(std::move(item));
|
||||
}
|
||||
|
||||
void GatherAddNodeSearchParams::add_item(AddNodeItem item)
|
||||
{
|
||||
r_items.append(std::move(item));
|
||||
}
|
||||
|
||||
void search_node_add_ops_for_basic_node(GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
params.add_item(IFACE_(params.node_type().ui_name), TIP_(params.node_type().ui_description));
|
||||
params.add_single_node_item(IFACE_(params.node_type().ui_name),
|
||||
TIP_(params.node_type().ui_description));
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
@@ -227,12 +227,12 @@ static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
||||
|
||||
static void gather_add_node_searches(GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
params.add_item(IFACE_("Mix"), params.node_type().ui_description);
|
||||
params.add_item(IFACE_("Mix Color"),
|
||||
params.node_type().ui_description,
|
||||
[](const bContext & /*C*/, bNodeTree & /*node_tree*/, bNode &node) {
|
||||
node_storage(node).data_type = SOCK_RGBA;
|
||||
});
|
||||
params.add_single_node_item(IFACE_("Mix"), params.node_type().ui_description);
|
||||
params.add_single_node_item(IFACE_("Mix Color"),
|
||||
params.node_type().ui_description,
|
||||
[](const bContext & /*C*/, bNodeTree & /*node_tree*/, bNode &node) {
|
||||
node_storage(node).data_type = SOCK_RGBA;
|
||||
});
|
||||
}
|
||||
|
||||
static void node_mix_init(bNodeTree * /*tree*/, bNode *node)
|
||||
|
||||
Reference in New Issue
Block a user