UI: support drawing buttons inside node panels
With a callback to node panels similar to the one for nodes. Used in the Principled BSDF to place enums in the relevant panels. Longer term we want to make enums into sockets, but even then there are still potentially some types of buttons we want to have in panels. Pull Request: https://projects.blender.org/blender/blender/pulls/112591
This commit is contained in:
@@ -353,11 +353,15 @@ static bool is_node_panels_supported(const bNode &node)
|
||||
}
|
||||
|
||||
/* Draw UI for options, buttons, and previews. */
|
||||
static bool node_update_basis_buttons(
|
||||
const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block, int &dy)
|
||||
static bool node_update_basis_buttons(const bContext &C,
|
||||
bNodeTree &ntree,
|
||||
bNode &node,
|
||||
nodes::PanelDrawButtonsFunction draw_buttons,
|
||||
uiBlock &block,
|
||||
int &dy)
|
||||
{
|
||||
/* Buttons rect? */
|
||||
const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
|
||||
const bool node_options = draw_buttons && (node.flag & NODE_OPTIONS);
|
||||
if (!node_options) {
|
||||
return false;
|
||||
}
|
||||
@@ -388,7 +392,7 @@ static bool node_update_basis_buttons(
|
||||
|
||||
uiLayoutSetContextPointer(layout, "node", &nodeptr);
|
||||
|
||||
node.typeinfo->draw_buttons(layout, (bContext *)&C, &nodeptr);
|
||||
draw_buttons(layout, (bContext *)&C, &nodeptr);
|
||||
|
||||
UI_block_align_end(&block);
|
||||
int buty;
|
||||
@@ -686,7 +690,8 @@ static void node_update_basis_from_declaration(
|
||||
/* Draw buttons before the first panel. */
|
||||
if (!buttons_drawn) {
|
||||
buttons_drawn = true;
|
||||
need_spacer_after_item = node_update_basis_buttons(C, ntree, node, block, locy);
|
||||
need_spacer_after_item = node_update_basis_buttons(
|
||||
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
||||
}
|
||||
|
||||
if (!is_parent_collapsed) {
|
||||
@@ -710,6 +715,7 @@ static void node_update_basis_from_declaration(
|
||||
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
|
||||
if (!is_collapsed) {
|
||||
locy -= NODE_ITEM_SPACING_Y; /* Space at top of panel contents. */
|
||||
node_update_basis_buttons(C, ntree, node, item.panel_decl->draw_buttons, block, locy);
|
||||
}
|
||||
}
|
||||
else if (item.is_valid_socket()) {
|
||||
@@ -718,7 +724,8 @@ static void node_update_basis_from_declaration(
|
||||
/* Draw buttons before the first input, unless it's inline with an output. */
|
||||
if (!item.socket_decl->inline_with_next && !buttons_drawn) {
|
||||
buttons_drawn = true;
|
||||
need_spacer_after_item = node_update_basis_buttons(C, ntree, node, block, locy);
|
||||
need_spacer_after_item = node_update_basis_buttons(
|
||||
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
||||
}
|
||||
|
||||
if (is_parent_collapsed) {
|
||||
@@ -782,7 +789,8 @@ static void node_update_basis_from_declaration(
|
||||
|
||||
/* Draw buttons at the bottom if no inputs exist. */
|
||||
if (!buttons_drawn) {
|
||||
need_spacer_after_item = node_update_basis_buttons(C, ntree, node, block, locy);
|
||||
need_spacer_after_item = node_update_basis_buttons(
|
||||
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
||||
}
|
||||
|
||||
if (need_spacer_after_item) {
|
||||
@@ -821,7 +829,7 @@ static void node_update_basis_from_socket_lists(
|
||||
locy -= NODE_DY / 4;
|
||||
}
|
||||
|
||||
node_update_basis_buttons(C, ntree, node, block, locy);
|
||||
node_update_basis_buttons(C, ntree, node, node.typeinfo->draw_buttons, block, locy);
|
||||
|
||||
/* Input sockets. */
|
||||
for (bNodeSocket *socket : node.input_sockets()) {
|
||||
|
||||
@@ -781,7 +781,8 @@ static void ui_node_draw_panel(uiLayout &layout,
|
||||
bContext &C,
|
||||
bNodeTree &ntree,
|
||||
const nodes::PanelDeclaration &panel_decl,
|
||||
bNodePanelState &panel_state)
|
||||
bNodePanelState &panel_state,
|
||||
PointerRNA nodeptr)
|
||||
{
|
||||
uiLayout *row = uiLayoutRow(&layout, true);
|
||||
uiLayoutSetPropDecorate(row, false);
|
||||
@@ -808,6 +809,12 @@ 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_node(
|
||||
@@ -853,7 +860,7 @@ static void ui_node_draw_node(
|
||||
{
|
||||
panel_collapsed = panel_state->is_collapsed();
|
||||
panel_label = panel_decl->name.c_str();
|
||||
ui_node_draw_panel(layout, C, ntree, *panel_decl, *panel_state);
|
||||
ui_node_draw_panel(layout, C, ntree, *panel_decl, *panel_state, nodeptr);
|
||||
++panel_state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
struct bContext;
|
||||
struct bNode;
|
||||
struct PointerRNA;
|
||||
struct uiLayout;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
@@ -569,6 +572,8 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
|
||||
|
||||
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
|
||||
|
||||
typedef void (*PanelDrawButtonsFunction)(uiLayout *, bContext *, PointerRNA *);
|
||||
|
||||
/**
|
||||
* Describes a panel containing sockets or other panels.
|
||||
*/
|
||||
@@ -580,6 +585,7 @@ class PanelDeclaration : public ItemDeclaration {
|
||||
std::string translation_context;
|
||||
bool default_collapsed = false;
|
||||
int num_child_decls = 0;
|
||||
PanelDrawButtonsFunction draw_buttons = nullptr;
|
||||
|
||||
private:
|
||||
friend NodeDeclarationBuilder;
|
||||
@@ -619,6 +625,12 @@ class PanelDeclarationBuilder {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self &draw_buttons(PanelDrawButtonsFunction func)
|
||||
{
|
||||
decl_->draw_buttons = func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename DeclType>
|
||||
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
|
||||
template<typename DeclType>
|
||||
|
||||
@@ -54,7 +54,12 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
#define SOCK_WEIGHT_ID 7
|
||||
|
||||
/* Panel for Subsurface scattering settings. */
|
||||
PanelDeclarationBuilder &sss = b.add_panel("Subsurface").default_closed(true);
|
||||
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);
|
||||
});
|
||||
sss.add_input<decl::Float>("Subsurface")
|
||||
.default_value(0.0f)
|
||||
.min(0.0f)
|
||||
@@ -93,7 +98,12 @@ 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);
|
||||
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);
|
||||
});
|
||||
spec.add_input<decl::Float>("Specular")
|
||||
.default_value(0.5f)
|
||||
.min(0.0f)
|
||||
@@ -179,12 +189,6 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
#define SOCK_EMISSION_STRENGTH_ID 27
|
||||
}
|
||||
|
||||
static void node_shader_buts_principled(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_shader_init_principled(bNodeTree * /*ntree*/, bNode *node)
|
||||
{
|
||||
node->custom1 = SHD_GLOSSY_MULTI_GGX;
|
||||
@@ -314,7 +318,6 @@ void register_node_type_sh_bsdf_principled()
|
||||
sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.add_ui_poll = object_shader_nodes_poll;
|
||||
ntype.draw_buttons = file_ns::node_shader_buts_principled;
|
||||
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
|
||||
ntype.initfunc = file_ns::node_shader_init_principled;
|
||||
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled;
|
||||
|
||||
Reference in New Issue
Block a user