Fix #112588: Hide node panels when all sockets are hidden

The panel state gets a new flag to indicate if content is visible.
This gets updated in the visibility pass during node drawing.

Pull Request: https://projects.blender.org/blender/blender/pulls/113003
This commit is contained in:
Lukas Tönne
2023-09-28 11:24:48 +02:00
parent 1930ebdb4f
commit 9e79487c4f
3 changed files with 63 additions and 34 deletions

View File

@@ -915,4 +915,9 @@ inline bool bNodePanelState::is_parent_collapsed() const
return flag & NODE_PANEL_PARENT_COLLAPSED;
}
inline bool bNodePanelState::has_visible_content() const
{
return flag & NODE_PANEL_CONTENT_VISIBLE;
}
/** \} */

View File

@@ -631,8 +631,10 @@ struct VisibilityUpdateState {
/* Recursive function to determine visibility of items before drawing. */
static void node_update_panel_items_visibility_recursive(int num_items,
const bool is_parent_collapsed,
bNodePanelState &parent_state,
VisibilityUpdateState &state)
{
parent_state.flag &= ~NODE_PANEL_CONTENT_VISIBLE;
while (state.item_iter != state.item_end) {
/* Stop after adding the expected number of items.
* Root panel consumes all remaining items (num_items == -1). */
@@ -651,14 +653,24 @@ static void node_update_panel_items_visibility_recursive(int num_items,
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
node_update_panel_items_visibility_recursive(
item.panel_decl->num_child_decls, is_collapsed, state);
item.panel_decl->num_child_decls, is_collapsed, *item.state, state);
if (item.state->flag & NODE_PANEL_CONTENT_VISIBLE) {
/* If child panel is visible so is the parent panel. */
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
}
}
else if (item.is_valid_socket()) {
if (item.input) {
SET_FLAG_FROM_TEST(item.input->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
if (item.input->is_visible()) {
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
}
}
if (item.output) {
SET_FLAG_FROM_TEST(item.output->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
if (item.output->is_visible()) {
parent_state.flag |= NODE_PANEL_CONTENT_VISIBLE;
}
}
}
else {
@@ -719,36 +731,41 @@ static void add_panel_items_recursive(const bContext &C,
C, ntree, node, node.typeinfo->draw_buttons, block, locy);
}
if (!is_parent_collapsed) {
locy -= NODE_DY;
state.is_first = false;
}
/* Panel visible if any content is visible. */
if (item.state->has_visible_content()) {
if (!is_parent_collapsed) {
locy -= NODE_DY;
state.is_first = false;
}
/* New top panel is collapsed if self or parent is collapsed. */
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
/* New top panel is collapsed if self or parent is collapsed. */
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
/* Round the socket location to stop it from jiggling. */
item.runtime->location_y = round(locy + NODE_DYS);
if (!is_collapsed) {
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at bottom of panel header. */
}
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);
}
/* Round the socket location to stop it from jiggling. */
item.runtime->location_y = round(locy + NODE_DYS);
if (is_collapsed) {
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
}
else {
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at bottom of panel header. */
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
locy -= NODE_ITEM_SPACING_Y; /* Space at top of panel contents. */
add_panel_items_recursive(C,
ntree,
node,
block,
locx,
locy,
item.panel_decl->num_child_decls,
is_collapsed,
item.panel_decl->name.c_str(),
item.runtime,
state);
node_update_basis_buttons(C, ntree, node, item.panel_decl->draw_buttons, block, locy);
}
add_panel_items_recursive(C,
ntree,
node,
block,
locx,
locy,
item.panel_decl->num_child_decls,
is_collapsed,
item.panel_decl->name.c_str(),
item.runtime,
state);
}
}
else if (item.is_valid_socket()) {
if (item.input) {
@@ -804,7 +821,7 @@ static void add_panel_items_recursive(const bContext &C,
}
locy -= NODE_ITEM_SPACING_Y / 2; /* Space at top of next panel header. */
}
};
}
/* Advanced drawing with panels and arbitrary input/output ordering. */
static void node_update_basis_from_declaration(
@@ -819,7 +836,9 @@ static void node_update_basis_from_declaration(
/* Update item visibility flags first. */
VisibilityUpdateState visibility_state(item_data);
node_update_panel_items_visibility_recursive(-1, false, visibility_state);
/* Dummy state item to write into, unused. */
bNodePanelState root_panel_state;
node_update_panel_items_visibility_recursive(-1, false, root_panel_state, visibility_state);
/* Space at the top. */
locy -= NODE_DYS / 2;
@@ -2015,10 +2034,11 @@ static void node_draw_panels_background(const bNode &node, uiBlock &block)
const bke::bNodePanelRuntime &runtime = node.runtime->panels[panel_i];
/* Don't draw hidden or collapsed panels. */
const bool is_visible = !(state.is_collapsed() || state.is_parent_collapsed());
is_last_panel_visible = is_visible;
const bool is_background_visible = state.has_visible_content() &&
!(state.is_collapsed() || state.is_parent_collapsed());
is_last_panel_visible = is_background_visible;
last_panel_content_y = runtime.max_content_y;
if (!is_visible) {
if (!is_background_visible) {
++panel_i;
continue;
}
@@ -2068,7 +2088,8 @@ static void node_draw_panels(bNodeTree &ntree, const bNode &node, uiBlock &block
const bNodePanelState &state = node.panel_states()[panel_i];
/* Don't draw hidden panels. */
if (state.is_parent_collapsed()) {
const bool is_header_visible = state.has_visible_content() && !state.is_parent_collapsed();
if (!is_header_visible) {
++panel_i;
continue;
}

View File

@@ -315,6 +315,8 @@ typedef enum eNodePanelFlag {
NODE_PANEL_COLLAPSED = (1 << 0),
/* The parent panel is collapsed. */
NODE_PANEL_PARENT_COLLAPSED = (1 << 1),
/* The panel has visible content. */
NODE_PANEL_CONTENT_VISIBLE = (1 << 2),
} eNodePanelFlag;
typedef struct bNodePanelState {
@@ -327,6 +329,7 @@ typedef struct bNodePanelState {
#ifdef __cplusplus
bool is_collapsed() const;
bool is_parent_collapsed() const;
bool has_visible_content() const;
#endif
} bNodePanelState;