Refactor: Nodes: improve drawing of nodes based on node declaration
The main goal is to simplify adding support for nested node panels. The patch
makes use of the updated recursive node declarations introduced in
6ffc585fb8.
The main changes are:
* Rewritten node drawing in a way that makes ui design decisions like panel
visibility and margins more explicit. Especially the handling of margins is
much better now imo. Previously, it was very hard to change the margin for
specific cases without accidentally breaking other situations. Now each
possible case has an explicit margin. This needs a few more lines of code but
is much easier to work with.
* Rewritten node drawing in panel (sidebar + material properties) using the new
ways to iterate over the declaration.
* It's possible to add custom layouts at any point in the node declaration now.
This also replaces the need for having a `draw_buttons` callback for panels.
Pull Request: https://projects.blender.org/blender/blender/pulls/128822
This commit is contained in:
@@ -262,16 +262,19 @@ class bNodeSocketRuntime : NonCopyable, NonMovable {
|
||||
int index_in_inout_sockets = -1;
|
||||
};
|
||||
|
||||
struct bNodePanelExtent {
|
||||
float min_y;
|
||||
float max_y;
|
||||
bool fill_node_end = false;
|
||||
};
|
||||
|
||||
class bNodePanelRuntime : NonCopyable, NonMovable {
|
||||
public:
|
||||
/* The vertical location of the panel in the tree, calculated while drawing the nodes and invalid
|
||||
* if the node tree hasn't been drawn yet. In the node tree's "world space" (the same as
|
||||
* #bNode::runtime::totr). */
|
||||
float location_y;
|
||||
/* Vertical start location of the panel content. */
|
||||
float min_content_y;
|
||||
/* Vertical end location of the panel content. */
|
||||
float max_content_y;
|
||||
std::optional<float> header_center_y;
|
||||
std::optional<bNodePanelExtent> content_extent;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "NOD_geometry_nodes_lazy_function.hh"
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
||||
namespace blender::bke::node_tree_runtime {
|
||||
|
||||
@@ -651,3 +652,13 @@ const bNode *bNodeTree::find_nested_node(const int32_t nested_node_id,
|
||||
}
|
||||
return group->find_nested_node(ref->path.id_in_node, r_tree);
|
||||
}
|
||||
|
||||
const bNodeSocket &bNode::socket_by_decl(const blender::nodes::SocketDeclaration &decl) const
|
||||
{
|
||||
return decl.in_out == SOCK_IN ? this->input_socket(decl.index) : this->output_socket(decl.index);
|
||||
}
|
||||
|
||||
bNodeSocket &bNode::socket_by_decl(const blender::nodes::SocketDeclaration &decl)
|
||||
{
|
||||
return decl.in_out == SOCK_IN ? this->input_socket(decl.index) : this->output_socket(decl.index);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
* \{ */
|
||||
|
||||
using blender::nodes::ItemDeclaration;
|
||||
using blender::nodes::LayoutDeclaration;
|
||||
using blender::nodes::NodeDeclaration;
|
||||
using blender::nodes::PanelDeclaration;
|
||||
using blender::nodes::SocketDeclaration;
|
||||
@@ -66,54 +67,37 @@ static void draw_node_input(bContext *C,
|
||||
socket.typeinfo->draw(C, row, &socket_ptr, node_ptr, text);
|
||||
}
|
||||
|
||||
static void draw_node_input(bContext *C,
|
||||
uiLayout *layout,
|
||||
PointerRNA *node_ptr,
|
||||
StringRefNull identifier)
|
||||
static void draw_node_inputs_recursive(bContext *C,
|
||||
uiLayout *layout,
|
||||
bNode &node,
|
||||
PointerRNA *node_ptr,
|
||||
const blender::nodes::PanelDeclaration &panel_decl)
|
||||
{
|
||||
bNode &node = *static_cast<bNode *>(node_ptr->data);
|
||||
bNodeSocket *socket = node.runtime->inputs_by_identifier.lookup(identifier);
|
||||
draw_node_input(C, layout, node_ptr, *socket);
|
||||
}
|
||||
|
||||
/* Consume the item range, draw buttons if layout is not null. */
|
||||
static void handle_node_declaration_items(bContext *C,
|
||||
Panel *root_panel,
|
||||
uiLayout *layout,
|
||||
PointerRNA *node_ptr,
|
||||
ItemIterator &item_iter,
|
||||
const ItemIterator item_end)
|
||||
{
|
||||
while (item_iter != item_end) {
|
||||
const ItemDeclaration *item_decl = item_iter->get();
|
||||
++item_iter;
|
||||
|
||||
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl))
|
||||
{
|
||||
if (layout && socket_decl->in_out == SOCK_IN) {
|
||||
draw_node_input(C, layout, node_ptr, socket_decl->identifier);
|
||||
/* Use a root panel property to toggle open/closed state. */
|
||||
/* TODO: Use flag on the panel state instead which is better for dynamic panel amounts. */
|
||||
const std::string panel_idname = "NodePanel" + std::to_string(panel_decl.identifier);
|
||||
Panel *root_panel = uiLayoutGetRootPanel(layout);
|
||||
LayoutPanelState *state = BKE_panel_layout_panel_state_ensure(
|
||||
root_panel, panel_idname.c_str(), panel_decl.default_collapsed);
|
||||
PointerRNA state_ptr = RNA_pointer_create(nullptr, &RNA_LayoutPanelState, state);
|
||||
uiLayout *panel_layout = uiLayoutPanelProp(
|
||||
C, layout, &state_ptr, "is_open", IFACE_(panel_decl.name.c_str()));
|
||||
if (!(state->flag & LAYOUT_PANEL_STATE_FLAG_OPEN)) {
|
||||
return;
|
||||
}
|
||||
for (const ItemDeclaration *item_decl : panel_decl.items) {
|
||||
if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
|
||||
if (socket_decl->in_out == SOCK_IN) {
|
||||
draw_node_input(C, panel_layout, node_ptr, node.socket_by_decl(*socket_decl));
|
||||
}
|
||||
}
|
||||
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
|
||||
item_decl))
|
||||
{
|
||||
const ItemIterator panel_item_end = item_iter + panel_decl->items.size();
|
||||
BLI_assert(panel_item_end <= item_end);
|
||||
|
||||
/* Use a root panel property to toggle open/closed state. */
|
||||
const std::string panel_idname = "NodePanel" + std::to_string(panel_decl->identifier);
|
||||
LayoutPanelState *state = BKE_panel_layout_panel_state_ensure(
|
||||
root_panel, panel_idname.c_str(), panel_decl->default_collapsed);
|
||||
PointerRNA state_ptr = RNA_pointer_create(nullptr, &RNA_LayoutPanelState, state);
|
||||
uiLayout *panel_layout = uiLayoutPanelProp(
|
||||
C, layout, &state_ptr, "is_open", IFACE_(panel_decl->name.c_str()));
|
||||
/* Draw panel buttons at the top of each panel section. */
|
||||
if (panel_layout && panel_decl->draw_buttons) {
|
||||
panel_decl->draw_buttons(panel_layout, C, node_ptr);
|
||||
else if (const auto *sub_panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
|
||||
draw_node_inputs_recursive(C, panel_layout, node, node_ptr, *sub_panel_decl);
|
||||
}
|
||||
else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
|
||||
if (!layout_decl->is_default) {
|
||||
layout_decl->draw(panel_layout, C, node_ptr);
|
||||
}
|
||||
|
||||
handle_node_declaration_items(
|
||||
C, root_panel, panel_layout, node_ptr, item_iter, panel_item_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,6 +106,7 @@ static void handle_node_declaration_items(bContext *C,
|
||||
|
||||
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::nodes;
|
||||
bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
|
||||
@@ -138,11 +123,22 @@ void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
|
||||
if (node.declaration()) {
|
||||
/* Draw socket inputs and panel buttons in the order of declaration panels. */
|
||||
ItemIterator item_iter = node.declaration()->all_items.begin();
|
||||
const ItemIterator item_end = node.declaration()->all_items.end();
|
||||
Panel *root_panel = uiLayoutGetRootPanel(layout);
|
||||
blender::ui::nodes::handle_node_declaration_items(
|
||||
C, root_panel, layout, ptr, item_iter, item_end);
|
||||
const NodeDeclaration &node_decl = *node.declaration();
|
||||
for (const ItemDeclaration *item_decl : node_decl.root_items) {
|
||||
if (const auto *panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
|
||||
blender::ui::nodes::draw_node_inputs_recursive(C, layout, node, ptr, *panel_decl);
|
||||
}
|
||||
else if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
|
||||
if (socket_decl->in_out == SOCK_IN) {
|
||||
blender::ui::nodes::draw_node_input(C, layout, ptr, node.socket_by_decl(*socket_decl));
|
||||
}
|
||||
}
|
||||
else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
|
||||
if (!layout_decl->is_default) {
|
||||
layout_decl->draw(layout, C, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Draw socket values using the flat inputs list. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -756,11 +756,9 @@ static void node_panel_toggle_button_cb(bContext *C, void *panel_state_argv, voi
|
||||
}
|
||||
|
||||
static void ui_node_draw_panel(uiLayout &layout,
|
||||
bContext &C,
|
||||
bNodeTree &ntree,
|
||||
const nodes::PanelDeclaration &panel_decl,
|
||||
bNodePanelState &panel_state,
|
||||
PointerRNA nodeptr)
|
||||
bNodePanelState &panel_state)
|
||||
{
|
||||
uiLayout *row = uiLayoutRow(&layout, true);
|
||||
uiLayoutSetPropDecorate(row, false);
|
||||
@@ -784,11 +782,40 @@ static void ui_node_draw_panel(uiLayout &layout,
|
||||
UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT | UI_BUT_NO_TOOLTIP);
|
||||
UI_but_func_set(but, node_panel_toggle_button_cb, &panel_state, &ntree);
|
||||
UI_block_emboss_set(block, UI_EMBOSS);
|
||||
}
|
||||
|
||||
/* Panel buttons. */
|
||||
if (!panel_state.is_collapsed() && panel_decl.draw_buttons) {
|
||||
uiLayoutSetPropSep(&layout, true);
|
||||
panel_decl.draw_buttons(&layout, &C, &nodeptr);
|
||||
static void ui_node_draw_recursive(uiLayout &layout,
|
||||
bContext &C,
|
||||
bNodeTree &ntree,
|
||||
bNode &node,
|
||||
const nodes::PanelDeclaration &panel_decl,
|
||||
const int depth)
|
||||
{
|
||||
bNodePanelState &panel_state = node.panel_states_array[panel_decl.index];
|
||||
ui_node_draw_panel(layout, ntree, panel_decl, panel_state);
|
||||
if (panel_state.is_collapsed()) {
|
||||
return;
|
||||
}
|
||||
for (const nodes::ItemDeclaration *item_decl : panel_decl.items) {
|
||||
if (const auto *socket_decl = dynamic_cast<const nodes::SocketDeclaration *>(item_decl)) {
|
||||
if (socket_decl->in_out == SOCK_IN) {
|
||||
ui_node_draw_input(layout,
|
||||
C,
|
||||
ntree,
|
||||
node,
|
||||
node.socket_by_decl(*socket_decl),
|
||||
depth,
|
||||
panel_decl.name.c_str());
|
||||
}
|
||||
}
|
||||
else if (const auto *sub_panel_decl = dynamic_cast<const nodes::PanelDeclaration *>(item_decl))
|
||||
{
|
||||
ui_node_draw_recursive(layout, C, ntree, node, *sub_panel_decl, depth + 1);
|
||||
}
|
||||
else if (const auto *layout_decl = dynamic_cast<const nodes::LayoutDeclaration *>(item_decl)) {
|
||||
PointerRNA nodeptr = RNA_pointer_create(&ntree.id, &RNA_Node, &node);
|
||||
layout_decl->draw(&layout, &C, &nodeptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,51 +824,29 @@ static void ui_node_draw_node(
|
||||
{
|
||||
PointerRNA nodeptr = RNA_pointer_create(&ntree.id, &RNA_Node, &node);
|
||||
|
||||
if (node.typeinfo->draw_buttons) {
|
||||
if (node.type != NODE_GROUP) {
|
||||
uiLayoutSetPropSep(&layout, true);
|
||||
node.typeinfo->draw_buttons(&layout, &C, &nodeptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.declaration() && node.declaration()->use_custom_socket_order) {
|
||||
/* Node with panels. */
|
||||
namespace nodes = blender::nodes;
|
||||
using ItemDeclIterator = blender::Span<nodes::ItemDeclarationPtr>::iterator;
|
||||
using SocketIterator = blender::Span<bNodeSocket *>::iterator;
|
||||
using PanelStateIterator = blender::MutableSpan<bNodePanelState>::iterator;
|
||||
|
||||
ItemDeclIterator item_decl = node.declaration()->all_items.begin();
|
||||
SocketIterator input = node.input_sockets().begin();
|
||||
PanelStateIterator panel_state = node.panel_states().begin();
|
||||
const ItemDeclIterator item_decl_end = node.declaration()->all_items.end();
|
||||
|
||||
bool panel_collapsed = false;
|
||||
const char *panel_label = nullptr;
|
||||
|
||||
for (; item_decl != item_decl_end; ++item_decl) {
|
||||
if (const nodes::SocketDeclaration *socket_decl =
|
||||
dynamic_cast<const nodes::SocketDeclaration *>(item_decl->get()))
|
||||
const nodes::NodeDeclaration &node_decl = *node.declaration();
|
||||
for (const nodes::ItemDeclaration *item_decl : node_decl.root_items) {
|
||||
if (const auto *panel_decl = dynamic_cast<const nodes::PanelDeclaration *>(item_decl)) {
|
||||
ui_node_draw_recursive(layout, C, ntree, node, *panel_decl, depth + 1);
|
||||
}
|
||||
else if (const auto *socket_decl = dynamic_cast<const nodes::SocketDeclaration *>(item_decl))
|
||||
{
|
||||
if (socket_decl->in_out == SOCK_IN) {
|
||||
if (!panel_collapsed) {
|
||||
ui_node_draw_input(layout, C, ntree, node, **input, depth + 1, panel_label);
|
||||
}
|
||||
++input;
|
||||
ui_node_draw_input(
|
||||
layout, C, ntree, node, node.socket_by_decl(*socket_decl), depth, nullptr);
|
||||
}
|
||||
}
|
||||
else if (const nodes::PanelDeclaration *panel_decl =
|
||||
dynamic_cast<const nodes::PanelDeclaration *>(item_decl->get()))
|
||||
{
|
||||
panel_collapsed = panel_state->is_collapsed();
|
||||
panel_label = panel_decl->name.c_str();
|
||||
ui_node_draw_panel(layout, C, ntree, *panel_decl, *panel_state, nodeptr);
|
||||
++panel_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Node without panels. */
|
||||
if (node.typeinfo->draw_buttons) {
|
||||
if (node.type != NODE_GROUP) {
|
||||
uiLayoutSetPropSep(&layout, true);
|
||||
node.typeinfo->draw_buttons(&layout, &C, &nodeptr);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bNodeSocket *, input, &node.inputs) {
|
||||
ui_node_draw_input(layout, C, ntree, node, *input, depth + 1, nullptr);
|
||||
}
|
||||
|
||||
@@ -489,6 +489,9 @@ typedef struct bNode {
|
||||
const bNodeSocket &output_by_identifier(blender::StringRef identifier) const;
|
||||
bNodeSocket &input_by_identifier(blender::StringRef identifier);
|
||||
bNodeSocket &output_by_identifier(blender::StringRef identifier);
|
||||
/** Lookup socket by its declaration. */
|
||||
const bNodeSocket &socket_by_decl(const blender::nodes::SocketDeclaration &decl) const;
|
||||
bNodeSocket &socket_by_decl(const blender::nodes::SocketDeclaration &decl);
|
||||
/** If node is frame, will return all children nodes. */
|
||||
blender::Span<bNode *> direct_children_in_frame() const;
|
||||
blender::Span<bNodePanelState> panel_states() const;
|
||||
|
||||
@@ -190,6 +190,9 @@ class SocketDeclaration : public ItemDeclaration {
|
||||
/** Puts this socket on the same line as the previous one in the UI. */
|
||||
bool align_with_previous_socket = false;
|
||||
|
||||
/** Index in the list of inputs or outputs of the node. */
|
||||
int index = -1;
|
||||
|
||||
InputSocketFieldType input_field_type = InputSocketFieldType::None;
|
||||
OutputFieldDependency output_field_dependency;
|
||||
|
||||
@@ -257,8 +260,6 @@ class PanelDeclarationBuilder;
|
||||
|
||||
class BaseSocketDeclarationBuilder {
|
||||
protected:
|
||||
/* Index of the socket in the list of inputs or outputs. */
|
||||
int index_ = -1;
|
||||
bool reference_pass_all_ = false;
|
||||
bool field_on_all_ = false;
|
||||
bool propagate_from_all_ = false;
|
||||
@@ -414,10 +415,20 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
|
||||
|
||||
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
|
||||
|
||||
using PanelDrawButtonsFunction = void (*)(uiLayout *, bContext *, PointerRNA *);
|
||||
using DrawNodeLayoutFn = void(uiLayout *, bContext *, PointerRNA *);
|
||||
|
||||
class SeparatorDeclaration : public ItemDeclaration {};
|
||||
|
||||
class LayoutDeclaration : public ItemDeclaration {
|
||||
public:
|
||||
std::function<DrawNodeLayoutFn> draw;
|
||||
/**
|
||||
* Sometimes the default layout has special handling (e.g. choose between #draw_buttons and
|
||||
* #draw_buttons_ex).
|
||||
*/
|
||||
bool is_default = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes a panel containing sockets or other panels.
|
||||
*/
|
||||
@@ -428,8 +439,10 @@ class PanelDeclaration : public ItemDeclaration {
|
||||
std::string description;
|
||||
std::string translation_context;
|
||||
bool default_collapsed = false;
|
||||
PanelDrawButtonsFunction draw_buttons = nullptr;
|
||||
Vector<ItemDeclaration *> items;
|
||||
/** Index in the list of panels on the node. */
|
||||
int index = -1;
|
||||
PanelDeclaration *parent_panel = nullptr;
|
||||
|
||||
private:
|
||||
friend NodeDeclarationBuilder;
|
||||
@@ -441,6 +454,8 @@ class PanelDeclaration : public ItemDeclaration {
|
||||
void build(bNodePanelState &panel) const;
|
||||
bool matches(const bNodePanelState &panel) const;
|
||||
void update_or_build(const bNodePanelState &old_panel, bNodePanelState &new_panel) const;
|
||||
|
||||
int depth() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -451,6 +466,7 @@ class DeclarationListBuilder {
|
||||
public:
|
||||
NodeDeclarationBuilder &node_decl_builder;
|
||||
Vector<ItemDeclaration *> &items;
|
||||
PanelDeclaration *parent_panel_decl = nullptr;
|
||||
|
||||
DeclarationListBuilder(NodeDeclarationBuilder &node_decl_builder,
|
||||
Vector<ItemDeclaration *> &items)
|
||||
@@ -484,6 +500,8 @@ class DeclarationListBuilder {
|
||||
PanelDeclarationBuilder &add_panel(StringRef name, int identifier = -1);
|
||||
|
||||
void add_separator();
|
||||
void add_default_layout();
|
||||
void add_layout(std::function<void(uiLayout *, bContext *, PointerRNA *)> draw);
|
||||
};
|
||||
|
||||
class PanelDeclarationBuilder : public DeclarationListBuilder {
|
||||
@@ -497,11 +515,11 @@ class PanelDeclarationBuilder : public DeclarationListBuilder {
|
||||
PanelDeclarationBuilder(NodeDeclarationBuilder &node_builder, PanelDeclaration &decl)
|
||||
: DeclarationListBuilder(node_builder, decl.items), decl_(&decl)
|
||||
{
|
||||
this->parent_panel_decl = &decl;
|
||||
}
|
||||
|
||||
Self &description(std::string value = "");
|
||||
Self &default_closed(bool closed);
|
||||
Self &draw_buttons(PanelDrawButtonsFunction func);
|
||||
};
|
||||
|
||||
using PanelDeclarationPtr = std::unique_ptr<PanelDeclaration>;
|
||||
@@ -515,6 +533,7 @@ class NodeDeclaration {
|
||||
/* All input and output socket declarations. */
|
||||
Vector<SocketDeclaration *> inputs;
|
||||
Vector<SocketDeclaration *> outputs;
|
||||
Vector<PanelDeclaration *> panels;
|
||||
std::unique_ptr<aal::RelationsInNode> anonymous_attribute_relations_;
|
||||
|
||||
/** Leave the sockets in place, even if they don't match the declaration. Used for dynamic
|
||||
@@ -553,6 +572,7 @@ class NodeDeclaration {
|
||||
|
||||
class NodeDeclarationBuilder : public DeclarationListBuilder {
|
||||
private:
|
||||
const bke::bNodeType &typeinfo_;
|
||||
NodeDeclaration &declaration_;
|
||||
const bNodeTree *ntree_ = nullptr;
|
||||
const bNode *node_ = nullptr;
|
||||
@@ -566,7 +586,8 @@ class NodeDeclarationBuilder : public DeclarationListBuilder {
|
||||
friend DeclarationListBuilder;
|
||||
|
||||
public:
|
||||
NodeDeclarationBuilder(NodeDeclaration &declaration,
|
||||
NodeDeclarationBuilder(const bke::bNodeType &typeinfo,
|
||||
NodeDeclaration &declaration,
|
||||
const bNodeTree *ntree = nullptr,
|
||||
const bNode *node = nullptr);
|
||||
|
||||
@@ -686,12 +707,12 @@ inline typename DeclType::Builder &DeclarationListBuilder::add_socket(StringRef
|
||||
|
||||
if (in_out == SOCK_IN) {
|
||||
this->node_decl_builder.input_socket_builders_.append(&socket_decl_builder);
|
||||
socket_decl_builder.index_ = this->node_decl_builder.declaration_.inputs.append_and_get_index(
|
||||
socket_decl.index = this->node_decl_builder.declaration_.inputs.append_and_get_index(
|
||||
&socket_decl);
|
||||
}
|
||||
else {
|
||||
this->node_decl_builder.output_socket_builders_.append(&socket_decl_builder);
|
||||
socket_decl_builder.index_ = this->node_decl_builder.declaration_.outputs.append_and_get_index(
|
||||
socket_decl.index = this->node_decl_builder.declaration_.outputs.append_and_get_index(
|
||||
&socket_decl);
|
||||
}
|
||||
return socket_decl_builder;
|
||||
@@ -705,7 +726,7 @@ inline typename DeclType::Builder &DeclarationListBuilder::add_socket(StringRef
|
||||
|
||||
inline int BaseSocketDeclarationBuilder::index() const
|
||||
{
|
||||
return index_;
|
||||
return decl_base_->index;
|
||||
}
|
||||
|
||||
inline bool BaseSocketDeclarationBuilder::is_input() const
|
||||
|
||||
@@ -31,6 +31,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.use_custom_socket_order();
|
||||
b.allow_any_socket_order();
|
||||
|
||||
b.add_default_layout();
|
||||
|
||||
b.add_input<decl::Geometry>("Geometry");
|
||||
b.add_output<decl::Geometry>("Geometry").propagate_all().align_with_previous();
|
||||
if (node != nullptr) {
|
||||
|
||||
@@ -51,6 +51,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.use_custom_socket_order();
|
||||
b.allow_any_socket_order();
|
||||
|
||||
b.add_default_layout();
|
||||
|
||||
const bNodeTree *ntree = b.tree_or_null();
|
||||
const bNode *node = b.node_or_null();
|
||||
if (!node) {
|
||||
|
||||
@@ -104,6 +104,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const bNode *node = b.node_or_null();
|
||||
const bNodeTree *tree = b.tree_or_null();
|
||||
|
||||
b.add_default_layout();
|
||||
|
||||
if (!node || !tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.use_custom_socket_order();
|
||||
b.allow_any_socket_order();
|
||||
|
||||
b.add_default_layout();
|
||||
|
||||
b.add_input<decl::Bool>("Show").default_value(true).hide_value();
|
||||
b.add_output<decl::Bool>("Show").align_with_previous();
|
||||
b.add_input<decl::String>("Message").hide_label();
|
||||
|
||||
@@ -402,27 +402,42 @@ static void set_default_input_field(const bNodeTreeInterfaceSocket &input, Socke
|
||||
|
||||
static void node_group_declare_panel_recursive(DeclarationListBuilder &b,
|
||||
const bNodeTree &group,
|
||||
const bNodeTreeInterfacePanel &io_parent_panel)
|
||||
const bNodeTreeInterfacePanel &io_parent_panel,
|
||||
const bool is_root)
|
||||
{
|
||||
bool layout_added = false;
|
||||
auto add_layout_if_needed = [&]() {
|
||||
if (is_root && !layout_added) {
|
||||
b.add_default_layout();
|
||||
layout_added = true;
|
||||
}
|
||||
};
|
||||
|
||||
for (const bNodeTreeInterfaceItem *item : io_parent_panel.items()) {
|
||||
switch (item->item_type) {
|
||||
case NODE_INTERFACE_SOCKET: {
|
||||
const auto &io_socket = node_interface::get_item_as<bNodeTreeInterfaceSocket>(*item);
|
||||
const eNodeSocketInOut in_out = (io_socket.flag & NODE_INTERFACE_SOCKET_INPUT) ? SOCK_IN :
|
||||
SOCK_OUT;
|
||||
if (in_out == SOCK_IN) {
|
||||
add_layout_if_needed();
|
||||
}
|
||||
build_interface_socket_declaration(group, io_socket, in_out, b);
|
||||
break;
|
||||
}
|
||||
case NODE_INTERFACE_PANEL: {
|
||||
add_layout_if_needed();
|
||||
const auto &io_panel = node_interface::get_item_as<bNodeTreeInterfacePanel>(*item);
|
||||
auto &panel_b = b.add_panel(StringRef(io_panel.name), io_panel.identifier)
|
||||
.description(StringRef(io_panel.description))
|
||||
.default_closed(io_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED);
|
||||
node_group_declare_panel_recursive(panel_b, group, io_panel);
|
||||
node_group_declare_panel_recursive(panel_b, group, io_panel, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_layout_if_needed();
|
||||
}
|
||||
|
||||
void node_group_declare(NodeDeclarationBuilder &b)
|
||||
@@ -445,7 +460,7 @@ void node_group_declare(NodeDeclarationBuilder &b)
|
||||
/* Allow the node group interface to define the socket order. */
|
||||
r_declaration.use_custom_socket_order = true;
|
||||
|
||||
node_group_declare_panel_recursive(b, *group, group->tree_interface.root_panel);
|
||||
node_group_declare_panel_recursive(b, *group, group->tree_interface.root_panel, true);
|
||||
|
||||
if (group->type == NTREE_GEOMETRY) {
|
||||
group->ensure_interface_cache();
|
||||
|
||||
@@ -30,7 +30,7 @@ void build_node_declaration(const bke::bNodeType &typeinfo,
|
||||
const bNode *node)
|
||||
{
|
||||
reset_declaration(r_declaration);
|
||||
NodeDeclarationBuilder node_decl_builder{r_declaration, ntree, node};
|
||||
NodeDeclarationBuilder node_decl_builder{typeinfo, r_declaration, ntree, node};
|
||||
typeinfo.declare(node_decl_builder);
|
||||
node_decl_builder.finalize();
|
||||
}
|
||||
@@ -57,7 +57,7 @@ void NodeDeclarationBuilder::build_remaining_anonymous_attribute_relations()
|
||||
for (BaseSocketDeclarationBuilder *socket_builder : input_socket_builders_) {
|
||||
if (socket_builder->field_on_all_) {
|
||||
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
|
||||
const int field_input = socket_builder->index_;
|
||||
const int field_input = socket_builder->decl_base_->index;
|
||||
for (const int geometry_input : geometry_inputs) {
|
||||
relations.eval_relations.append({field_input, geometry_input});
|
||||
}
|
||||
@@ -66,14 +66,14 @@ void NodeDeclarationBuilder::build_remaining_anonymous_attribute_relations()
|
||||
for (BaseSocketDeclarationBuilder *socket_builder : output_socket_builders_) {
|
||||
if (socket_builder->field_on_all_) {
|
||||
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
|
||||
const int field_output = socket_builder->index_;
|
||||
const int field_output = socket_builder->decl_base_->index;
|
||||
for (const int geometry_output : geometry_outputs) {
|
||||
relations.available_relations.append({field_output, geometry_output});
|
||||
}
|
||||
}
|
||||
if (socket_builder->reference_pass_all_) {
|
||||
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
|
||||
const int field_output = socket_builder->index_;
|
||||
const int field_output = socket_builder->decl_base_->index;
|
||||
for (const int input_i : declaration_.inputs.index_range()) {
|
||||
SocketDeclaration &input_socket_decl = *declaration_.inputs[input_i];
|
||||
if (input_socket_decl.input_field_type != InputSocketFieldType::None) {
|
||||
@@ -83,7 +83,7 @@ void NodeDeclarationBuilder::build_remaining_anonymous_attribute_relations()
|
||||
}
|
||||
if (socket_builder->propagate_from_all_) {
|
||||
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
|
||||
const int geometry_output = socket_builder->index_;
|
||||
const int geometry_output = socket_builder->decl_base_->index;
|
||||
for (const int geometry_input : geometry_inputs) {
|
||||
relations.propagate_relations.append({geometry_input, geometry_output});
|
||||
}
|
||||
@@ -99,10 +99,12 @@ void NodeDeclarationBuilder::finalize()
|
||||
#endif
|
||||
}
|
||||
|
||||
NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declaration,
|
||||
NodeDeclarationBuilder::NodeDeclarationBuilder(const bke::bNodeType &typeinfo,
|
||||
NodeDeclaration &declaration,
|
||||
const bNodeTree *ntree,
|
||||
const bNode *node)
|
||||
: DeclarationListBuilder(*this, declaration.root_items),
|
||||
typeinfo_(typeinfo),
|
||||
declaration_(declaration),
|
||||
ntree_(ntree),
|
||||
node_(node)
|
||||
@@ -236,8 +238,10 @@ bool NodeDeclaration::matches(const bNode &node) const
|
||||
}
|
||||
++current_panel;
|
||||
}
|
||||
else if (dynamic_cast<const SeparatorDeclaration *>(item_decl.get())) {
|
||||
/* Separators are ignored here because they don't have corresponding data in DNA. */
|
||||
else if (dynamic_cast<const SeparatorDeclaration *>(item_decl.get()) ||
|
||||
dynamic_cast<const LayoutDeclaration *>(item_decl.get()))
|
||||
{
|
||||
/* Ignored because they don't have corresponding data in DNA. */
|
||||
}
|
||||
else {
|
||||
/* Unknown item type. */
|
||||
@@ -416,6 +420,26 @@ void DeclarationListBuilder::add_separator()
|
||||
this->items.append(&decl);
|
||||
}
|
||||
|
||||
void DeclarationListBuilder::add_default_layout()
|
||||
{
|
||||
BLI_assert(this->node_decl_builder.typeinfo_.draw_buttons);
|
||||
this->add_layout([](uiLayout *layout, bContext *C, PointerRNA *ptr) {
|
||||
const bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
node.typeinfo->draw_buttons(layout, C, ptr);
|
||||
});
|
||||
static_cast<LayoutDeclaration &>(*this->items.last()).is_default = true;
|
||||
}
|
||||
|
||||
void DeclarationListBuilder::add_layout(
|
||||
std::function<void(uiLayout *, bContext *, PointerRNA *)> draw)
|
||||
{
|
||||
auto decl_ptr = std::make_unique<LayoutDeclaration>();
|
||||
LayoutDeclaration &decl = *decl_ptr;
|
||||
decl.draw = std::move(draw);
|
||||
this->node_decl_builder.declaration_.all_items.append(std::move(decl_ptr));
|
||||
this->items.append(&decl);
|
||||
}
|
||||
|
||||
PanelDeclarationBuilder &DeclarationListBuilder::add_panel(const StringRef name, int identifier)
|
||||
{
|
||||
auto panel_decl_ptr = std::make_unique<PanelDeclaration>();
|
||||
@@ -432,8 +456,10 @@ PanelDeclarationBuilder &DeclarationListBuilder::add_panel(const StringRef name,
|
||||
panel_decl.identifier = this->node_decl_builder.declaration_.all_items.size();
|
||||
}
|
||||
panel_decl.name = name;
|
||||
panel_decl.parent_panel = this->parent_panel_decl;
|
||||
panel_decl.index = this->node_decl_builder.declaration_.panels.append_and_get_index(&panel_decl);
|
||||
this->node_decl_builder.declaration_.all_items.append(std::move(panel_decl_ptr));
|
||||
this->node_decl_builder.panel_builders_.append(std::move(panel_decl_builder_ptr));
|
||||
this->node_decl_builder.panel_builders_.append_and_get_index(std::move(panel_decl_builder_ptr));
|
||||
this->items.append(&panel_decl);
|
||||
return panel_decl_builder;
|
||||
}
|
||||
@@ -458,6 +484,16 @@ void PanelDeclaration::update_or_build(const bNodePanelState &old_panel,
|
||||
SET_FLAG_FROM_TEST(new_panel.flag, old_panel.is_collapsed(), NODE_PANEL_COLLAPSED);
|
||||
}
|
||||
|
||||
int PanelDeclaration::depth() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const PanelDeclaration *parent = this->parent_panel; parent; parent = parent->parent_panel)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::supports_field()
|
||||
{
|
||||
BLI_assert(this->is_input());
|
||||
@@ -508,7 +544,7 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::reference_pass(
|
||||
for (const int from_input : input_indices) {
|
||||
aal::ReferenceRelation relation;
|
||||
relation.from_field_input = from_input;
|
||||
relation.to_field_output = index_;
|
||||
relation.to_field_output = decl_base_->index;
|
||||
relations.reference_relations.append(relation);
|
||||
}
|
||||
return *this;
|
||||
@@ -521,7 +557,7 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::field_on(const Span<
|
||||
this->supports_field();
|
||||
for (const int input_index : indices) {
|
||||
aal::EvalRelation relation;
|
||||
relation.field_input = index_;
|
||||
relation.field_input = decl_base_->index;
|
||||
relation.geometry_input = input_index;
|
||||
relations.eval_relations.append(relation);
|
||||
}
|
||||
@@ -530,7 +566,7 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::field_on(const Span<
|
||||
this->field_source();
|
||||
for (const int output_index : indices) {
|
||||
aal::AvailableRelation relation;
|
||||
relation.field_output = index_;
|
||||
relation.field_output = decl_base_->index;
|
||||
relation.geometry_output = output_index;
|
||||
relations.available_relations.append(relation);
|
||||
}
|
||||
@@ -783,12 +819,6 @@ PanelDeclarationBuilder &PanelDeclarationBuilder::default_closed(bool closed)
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanelDeclarationBuilder &PanelDeclarationBuilder::draw_buttons(PanelDrawButtonsFunction func)
|
||||
{
|
||||
decl_->draw_buttons = func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace implicit_field_inputs {
|
||||
|
||||
void position(const bNode & /*node*/, void *r_value)
|
||||
|
||||
@@ -81,12 +81,10 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
#define SOCK_DIFFUSE_ROUGHNESS_ID 7
|
||||
|
||||
/* Panel for Subsurface scattering settings. */
|
||||
PanelDeclarationBuilder &sss =
|
||||
b.add_panel("Subsurface")
|
||||
.default_closed(true)
|
||||
.draw_buttons([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
|
||||
uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
});
|
||||
PanelDeclarationBuilder &sss = b.add_panel("Subsurface").default_closed(true);
|
||||
sss.add_layout([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
|
||||
uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
});
|
||||
sss.add_input<decl::Float>("Subsurface Weight")
|
||||
.default_value(0.0f)
|
||||
.min(0.0f)
|
||||
@@ -134,12 +132,10 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
#define SOCK_SUBSURFACE_ANISOTROPY_ID 12
|
||||
|
||||
/* Panel for Specular settings. */
|
||||
PanelDeclarationBuilder &spec =
|
||||
b.add_panel("Specular")
|
||||
.default_closed(true)
|
||||
.draw_buttons([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
|
||||
uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
});
|
||||
PanelDeclarationBuilder &spec = b.add_panel("Specular").default_closed(true);
|
||||
spec.add_layout([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
|
||||
uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
});
|
||||
spec.add_input<decl::Float>("Specular IOR Level")
|
||||
.default_value(0.5f)
|
||||
.min(0.0f)
|
||||
|
||||
Reference in New Issue
Block a user