Nodes: Add PanelDeclarationBuilder for panels in builtin nodes #111695
|
@ -513,17 +513,34 @@ class PanelDeclaration : public ItemDeclaration {
|
|||
|
||||
class PanelDeclarationBuilder {
|
||||
protected:
|
||||
using Self = PanelDeclarationBuilder;
|
||||
NodeDeclarationBuilder *node_decl_builder_ = nullptr;
|
||||
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;
|
||||
|
||||
public:
|
||||
PanelDeclarationBuilder &default_closed(bool collapsed)
|
||||
Self &description(std::string value = "")
|
||||
{
|
||||
decl_->default_collapsed = collapsed;
|
||||
decl_->description = std::move(value);
|
||||
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>;
|
||||
|
@ -549,6 +566,9 @@ class NodeDeclaration {
|
|||
|
||||
friend NodeDeclarationBuilder;
|
||||
|
||||
/** Returns true if the declaration is considered valid. */
|
||||
bool is_valid() const;
|
||||
|
||||
bool matches(const bNode &node) const;
|
||||
Span<SocketDeclaration *> sockets(eNodeSocketInOut in_out) const;
|
||||
|
||||
|
@ -565,8 +585,12 @@ class NodeDeclarationBuilder {
|
|||
NodeDeclaration &declaration_;
|
||||
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
|
||||
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
|
||||
Vector<std::unique_ptr<PanelDeclarationBuilder>> panel_builders_;
|
||||
bool is_function_node_ = false;
|
||||
|
||||
private:
|
||||
friend PanelDeclarationBuilder;
|
||||
|
||||
public:
|
||||
NodeDeclarationBuilder(NodeDeclaration &declaration);
|
||||
|
||||
|
@ -581,10 +605,13 @@ class NodeDeclarationBuilder {
|
|||
|
||||
void finalize();
|
||||
|
||||
void use_custom_socket_order(bool enable = true);
|
||||
|
||||
template<typename DeclType>
|
||||
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
|
||||
template<typename DeclType>
|
||||
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
|
||||
PanelDeclarationBuilder &add_panel(StringRef name, int identifier = -1);
|
||||
|
||||
aal::RelationsInNode &get_anonymous_attribute_relations()
|
||||
{
|
||||
|
@ -599,6 +626,10 @@ class NodeDeclarationBuilder {
|
|||
typename DeclType::Builder &add_socket(StringRef name,
|
||||
StringRef identifier,
|
||||
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 {
|
||||
|
@ -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
|
||||
* \{ */
|
||||
|
@ -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>
|
||||
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
|
||||
StringRef identifier)
|
||||
{
|
||||
set_active_panel_builder(nullptr);
|
||||
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,
|
||||
StringRef identifier)
|
||||
{
|
||||
set_active_panel_builder(nullptr);
|
||||
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_builder->index_ = declarations.append_and_get_index(socket_decl.get());
|
||||
declaration_.items.append(std::move(socket_decl));
|
||||
|
||||
Builder &socket_decl_builder_ref = *socket_decl_builder;
|
||||
((in_out == SOCK_IN) ? input_builders_ : output_builders_)
|
||||
.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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "NOD_socket_declarations.hh"
|
||||
#include "NOD_socket_declarations_geometry.hh"
|
||||
|
||||
#include "BLI_stack.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_geometry_fields.hh"
|
||||
|
@ -33,6 +34,8 @@ void build_node_declaration_dynamic(const bNodeTree &node_tree,
|
|||
|
||||
void NodeDeclarationBuilder::finalize()
|
||||
{
|
||||
BLI_assert(declaration_.is_valid());
|
||||
|
||||
if (is_function_node_) {
|
||||
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
|
||||
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 {
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
panel = {0};
|
||||
|
|
Loading…
Reference in New Issue
Proper doxygen syntax for multi-line class variable documentation (just for consistency)