Nodes: Add PanelDeclarationBuilder for panels in builtin nodes #111695
|
@ -513,17 +513,34 @@ class PanelDeclaration : public ItemDeclaration {
|
||||||
|
|
||||||
class PanelDeclarationBuilder {
|
class PanelDeclarationBuilder {
|
||||||
protected:
|
protected:
|
||||||
|
using Self = PanelDeclarationBuilder;
|
||||||
NodeDeclarationBuilder *node_decl_builder_ = nullptr;
|
NodeDeclarationBuilder *node_decl_builder_ = nullptr;
|
||||||
PanelDeclaration *decl_;
|
PanelDeclaration *decl_;
|
||||||
|
/**
|
||||||
LukasTonne marked this conversation as resolved
Outdated
|
|||||||
|
* Panel is complete once items are added after it.
|
||||||
|
* Completed panels are locked and no more items can be added.
|
||||||
|
*/
|
||||||
|
bool is_complete_ = false;
|
||||||
|
|
||||||
friend class NodeDeclarationBuilder;
|
friend class NodeDeclarationBuilder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PanelDeclarationBuilder &default_closed(bool collapsed)
|
Self &description(std::string value = "")
|
||||||
{
|
{
|
||||||
decl_->default_collapsed = collapsed;
|
decl_->description = std::move(value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self &default_closed(bool closed)
|
||||||
|
{
|
||||||
|
decl_->default_collapsed = closed;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename DeclType>
|
||||||
|
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
|
||||||
|
template<typename DeclType>
|
||||||
|
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
using PanelDeclarationPtr = std::unique_ptr<PanelDeclaration>;
|
using PanelDeclarationPtr = std::unique_ptr<PanelDeclaration>;
|
||||||
|
@ -549,6 +566,9 @@ class NodeDeclaration {
|
||||||
|
|
||||||
friend NodeDeclarationBuilder;
|
friend NodeDeclarationBuilder;
|
||||||
|
|
||||||
|
/** Returns true if the declaration is considered valid. */
|
||||||
|
bool is_valid() const;
|
||||||
|
|
||||||
bool matches(const bNode &node) const;
|
bool matches(const bNode &node) const;
|
||||||
Span<SocketDeclaration *> sockets(eNodeSocketInOut in_out) const;
|
Span<SocketDeclaration *> sockets(eNodeSocketInOut in_out) const;
|
||||||
|
|
||||||
|
@ -565,8 +585,12 @@ class NodeDeclarationBuilder {
|
||||||
NodeDeclaration &declaration_;
|
NodeDeclaration &declaration_;
|
||||||
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
|
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
|
||||||
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
|
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
|
||||||
|
Vector<std::unique_ptr<PanelDeclarationBuilder>> panel_builders_;
|
||||||
bool is_function_node_ = false;
|
bool is_function_node_ = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend PanelDeclarationBuilder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeDeclarationBuilder(NodeDeclaration &declaration);
|
NodeDeclarationBuilder(NodeDeclaration &declaration);
|
||||||
|
|
||||||
|
@ -581,10 +605,13 @@ class NodeDeclarationBuilder {
|
||||||
|
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
|
void use_custom_socket_order(bool enable = true);
|
||||||
|
|
||||||
template<typename DeclType>
|
template<typename DeclType>
|
||||||
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
|
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
|
||||||
template<typename DeclType>
|
template<typename DeclType>
|
||||||
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
|
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
|
||||||
|
PanelDeclarationBuilder &add_panel(StringRef name, int identifier = -1);
|
||||||
|
|
||||||
aal::RelationsInNode &get_anonymous_attribute_relations()
|
aal::RelationsInNode &get_anonymous_attribute_relations()
|
||||||
{
|
{
|
||||||
|
@ -599,6 +626,10 @@ class NodeDeclarationBuilder {
|
||||||
typename DeclType::Builder &add_socket(StringRef name,
|
typename DeclType::Builder &add_socket(StringRef name,
|
||||||
StringRef identifier,
|
StringRef identifier,
|
||||||
eNodeSocketInOut in_out);
|
eNodeSocketInOut in_out);
|
||||||
|
|
||||||
|
/* Mark the most recent builder as 'complete' when changing builders
|
||||||
|
* so no more items can be added. */
|
||||||
|
void set_active_panel_builder(const PanelDeclarationBuilder *panel_builder);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace implicit_field_inputs {
|
namespace implicit_field_inputs {
|
||||||
|
@ -758,6 +789,38 @@ inline void SocketDeclaration::make_available(bNode &node) const
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name #PanelDeclarationBuilder Inline Methods
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
template<typename DeclType>
|
||||||
|
typename DeclType::Builder &PanelDeclarationBuilder::add_input(StringRef name,
|
||||||
|
StringRef identifier)
|
||||||
|
{
|
||||||
|
if (is_complete_) {
|
||||||
|
static typename DeclType::Builder dummy_builder = {};
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return dummy_builder;
|
||||||
|
}
|
||||||
|
++this->decl_->num_child_decls;
|
||||||
|
return node_decl_builder_->add_socket<DeclType>(name, identifier, SOCK_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename DeclType>
|
||||||
|
typename DeclType::Builder &PanelDeclarationBuilder::add_output(StringRef name,
|
||||||
|
StringRef identifier)
|
||||||
|
{
|
||||||
|
if (is_complete_) {
|
||||||
|
static typename DeclType::Builder dummy_builder = {};
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return dummy_builder;
|
||||||
|
}
|
||||||
|
++this->decl_->num_child_decls;
|
||||||
|
return node_decl_builder_->add_socket<DeclType>(name, identifier, SOCK_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name #NodeDeclarationBuilder Inline Methods
|
/** \name #NodeDeclarationBuilder Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
@ -767,10 +830,16 @@ inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declarati
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void NodeDeclarationBuilder::use_custom_socket_order(bool enable)
|
||||||
|
{
|
||||||
|
declaration_.use_custom_socket_order = enable;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename DeclType>
|
template<typename DeclType>
|
||||||
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
|
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
|
||||||
StringRef identifier)
|
StringRef identifier)
|
||||||
{
|
{
|
||||||
|
set_active_panel_builder(nullptr);
|
||||||
return this->add_socket<DeclType>(name, identifier, SOCK_IN);
|
return this->add_socket<DeclType>(name, identifier, SOCK_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,6 +847,7 @@ template<typename DeclType>
|
||||||
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
|
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
|
||||||
StringRef identifier)
|
StringRef identifier)
|
||||||
{
|
{
|
||||||
|
set_active_panel_builder(nullptr);
|
||||||
return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
|
return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,9 +872,11 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
|
||||||
socket_decl->in_out = in_out;
|
socket_decl->in_out = in_out;
|
||||||
socket_decl_builder->index_ = declarations.append_and_get_index(socket_decl.get());
|
socket_decl_builder->index_ = declarations.append_and_get_index(socket_decl.get());
|
||||||
declaration_.items.append(std::move(socket_decl));
|
declaration_.items.append(std::move(socket_decl));
|
||||||
|
|
||||||
Builder &socket_decl_builder_ref = *socket_decl_builder;
|
Builder &socket_decl_builder_ref = *socket_decl_builder;
|
||||||
((in_out == SOCK_IN) ? input_builders_ : output_builders_)
|
((in_out == SOCK_IN) ? input_builders_ : output_builders_)
|
||||||
.append(std::move(socket_decl_builder));
|
.append(std::move(socket_decl_builder));
|
||||||
|
|
||||||
LukasTonne marked this conversation as resolved
Outdated
Jacques Lucke
commented
This doesn't have to be in the header. This doesn't have to be in the header.
|
|||||||
return socket_decl_builder_ref;
|
return socket_decl_builder_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "NOD_socket_declarations.hh"
|
#include "NOD_socket_declarations.hh"
|
||||||
#include "NOD_socket_declarations_geometry.hh"
|
#include "NOD_socket_declarations_geometry.hh"
|
||||||
|
|
||||||
|
#include "BLI_stack.hh"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BKE_geometry_fields.hh"
|
#include "BKE_geometry_fields.hh"
|
||||||
|
@ -33,6 +34,8 @@ void build_node_declaration_dynamic(const bNodeTree &node_tree,
|
||||||
|
|
||||||
void NodeDeclarationBuilder::finalize()
|
void NodeDeclarationBuilder::finalize()
|
||||||
{
|
{
|
||||||
|
BLI_assert(declaration_.is_valid());
|
||||||
|
|
||||||
if (is_function_node_) {
|
if (is_function_node_) {
|
||||||
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
|
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
|
||||||
SocketDeclaration &socket_decl = *socket_builder->declaration();
|
SocketDeclaration &socket_decl = *socket_builder->declaration();
|
||||||
|
@ -97,6 +100,20 @@ void NodeDeclarationBuilder::finalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeDeclarationBuilder::set_active_panel_builder(const PanelDeclarationBuilder *panel_builder)
|
||||||
|
{
|
||||||
|
if (panel_builders_.is_empty()) {
|
||||||
|
BLI_assert(panel_builder == nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert(!panel_builder || !panel_builder->is_complete_);
|
||||||
|
PanelDeclarationBuilder *last_panel_builder = panel_builders_.last().get();
|
||||||
|
if (last_panel_builder != panel_builder) {
|
||||||
|
last_panel_builder->is_complete_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace anonymous_attribute_lifetime {
|
namespace anonymous_attribute_lifetime {
|
||||||
|
|
||||||
bool operator==(const RelationsInNode &a, const RelationsInNode &b)
|
bool operator==(const RelationsInNode &a, const RelationsInNode &b)
|
||||||
|
@ -141,6 +158,88 @@ std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations)
|
||||||
|
|
||||||
} // namespace anonymous_attribute_lifetime
|
} // namespace anonymous_attribute_lifetime
|
||||||
|
|
||||||
|
bool NodeDeclaration::is_valid() const
|
||||||
|
{
|
||||||
|
if (!this->use_custom_socket_order) {
|
||||||
|
/* Skip validation for conventional socket layouts. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validation state for the interface root items as well as any panel content. */
|
||||||
|
struct ValidationState {
|
||||||
|
/* Remaining number of items expected in a panel */
|
||||||
|
int remaining_items = 0;
|
||||||
|
/* Sockets first, followed by panels. */
|
||||||
|
NodeTreeInterfaceItemType item_type = NODE_INTERFACE_SOCKET;
|
||||||
|
/* Output sockets first, followed by input sockets. */
|
||||||
|
eNodeSocketInOut socket_in_out = SOCK_OUT;
|
||||||
|
};
|
||||||
|
|
||||||
|
Stack<ValidationState> panel_states;
|
||||||
|
panel_states.push({});
|
||||||
|
|
||||||
|
for (const ItemDeclarationPtr &item_decl : items) {
|
||||||
|
BLI_assert(panel_states.size() >= 1);
|
||||||
|
ValidationState &state = panel_states.peek();
|
||||||
|
|
||||||
|
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(
|
||||||
|
item_decl.get()))
|
||||||
|
{
|
||||||
|
if (state.item_type != NODE_INTERFACE_SOCKET) {
|
||||||
|
std::cout << "Socket added after panel" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.socket_in_out == SOCK_OUT && socket_decl->in_out == SOCK_IN) {
|
||||||
|
/* Start of input sockets. */
|
||||||
|
state.socket_in_out = SOCK_IN;
|
||||||
|
}
|
||||||
|
if (socket_decl->in_out != state.socket_in_out) {
|
||||||
|
std::cout << "Output socket added after input socket" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Item counting for the panels, but ignore for root items. */
|
||||||
|
if (panel_states.size() > 1) {
|
||||||
|
if (state.remaining_items <= 0) {
|
||||||
|
std::cout << "More sockets than expected in panel" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
--state.remaining_items;
|
||||||
|
/* Panel closed after last item is added. */
|
||||||
|
if (state.remaining_items == 0) {
|
||||||
|
panel_states.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
|
||||||
|
item_decl.get()))
|
||||||
|
{
|
||||||
|
if (state.item_type == NODE_INTERFACE_SOCKET) {
|
||||||
|
/* Start of panels section */
|
||||||
|
state.item_type = NODE_INTERFACE_PANEL;
|
||||||
|
}
|
||||||
|
BLI_assert(state.item_type == NODE_INTERFACE_PANEL);
|
||||||
|
|
||||||
|
if (panel_decl->num_child_decls > 0) {
|
||||||
|
/* New panel started. */
|
||||||
|
panel_states.push({panel_decl->num_child_decls});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All panels complete? */
|
||||||
|
if (panel_states.size() != 1) {
|
||||||
|
std::cout << "Incomplete last panel" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool NodeDeclaration::matches(const bNode &node) const
|
bool NodeDeclaration::matches(const bNode &node) const
|
||||||
{
|
{
|
||||||
const bNodeSocket *current_input = static_cast<bNodeSocket *>(node.inputs.first);
|
const bNodeSocket *current_input = static_cast<bNodeSocket *>(node.inputs.first);
|
||||||
|
@ -237,6 +336,31 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PanelDeclarationBuilder &NodeDeclarationBuilder::add_panel(StringRef name, int identifier)
|
||||||
|
{
|
||||||
|
std::unique_ptr<PanelDeclaration> panel_decl = std::make_unique<PanelDeclaration>();
|
||||||
|
std::unique_ptr<PanelDeclarationBuilder> panel_decl_builder =
|
||||||
|
std::make_unique<PanelDeclarationBuilder>();
|
||||||
|
panel_decl_builder->decl_ = &*panel_decl;
|
||||||
|
|
||||||
|
panel_decl_builder->node_decl_builder_ = this;
|
||||||
|
if (identifier >= 0) {
|
||||||
|
panel_decl->identifier = identifier;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Use index as identifier. */
|
||||||
|
panel_decl->identifier = declaration_.items.size();
|
||||||
|
}
|
||||||
|
panel_decl->name = name;
|
||||||
|
declaration_.items.append(std::move(panel_decl));
|
||||||
|
|
||||||
|
PanelDeclarationBuilder &builder_ref = *panel_decl_builder;
|
||||||
|
panel_builders_.append(std::move(panel_decl_builder));
|
||||||
|
set_active_panel_builder(&builder_ref);
|
||||||
|
|
||||||
|
return builder_ref;
|
||||||
|
}
|
||||||
|
|
||||||
void PanelDeclaration::build(bNodePanelState &panel) const
|
void PanelDeclaration::build(bNodePanelState &panel) const
|
||||||
{
|
{
|
||||||
panel = {0};
|
panel = {0};
|
||||||
|
|
Loading…
Reference in New Issue
Proper doxygen syntax for multi-line class variable documentation (just for consistency)