How to resize VBoxContainer to make its height less than the children needed

Godot Version

Godot4.4

Question

How to resize VBoxContainer to make its height less than the children needed?

I’m making a new Control called Expandable, it was designed with these features:

  • Expand and shrink animation
  • Show and hide Children

The structure of the control is

  • Expandable (PanelContainer)
    • UIContainer (VBoxContainer)
      • UIHeader (Clickable) (Just like a button)

The children will be added into UIContainer, and when the control shrinks, I expected the control will shrink and only UIHeader will be shown. But after I clicked UIHeader, all the children are still shown, only the height more than the children needed are removed, all the childrens are still shown. How can I force the control to shrink ignoring the height the children needs? (Please don’t resize the children)

Here’s my source code, and I think the problem happens in ToggleExpand(). Thanks!

using Godot;
using System;

public partial class ExpandableLite : Node
{
    [Export]
    public VBoxContainer UIContainer;
    [Export]
    public Clickable UIHeader;

    public bool IsExpand = true;
    public Tween _tween;

    public override void _Ready()
    {
        UIHeader.Clicked += UIHeader_Clicked;
    }

    private void UIHeader_Clicked()
    {
        IsExpand = !IsExpand;
        ToggleExpand();
    }

    public void ToggleExpand()
    {
        if (_tween != null)
        {
            _tween.Kill();
        }
        float targetHeight = UIHeader.Size.Y;
        if (IsExpand)
        {
            targetHeight += GetChildPanelTargetHeight();
        }
        _tween = CreateTween()
            .SetEase(Tween.EaseType.Out)
            .SetTrans(Tween.TransitionType.Circ);

        _tween.TweenProperty(this, "size", new Vector2(UIContainer.Size.X, targetHeight), 0.35);
    }

    private float GetChildPanelTargetHeight()
    {
        float totalHeight = 0f;

        var container = UIContainer as Container;
        var padding = container?.GetThemeConstant("margin_top") ?? 0f
                    + container?.GetThemeConstant("margin_bottom") ?? 0f;

        foreach (Node child in UIContainer.GetChildren())
        {
            if (child is Control control && control.Visible)
            {
                totalHeight += control.Size.Y;

                if (UIContainer is VBoxContainer vbox)
                {
                    totalHeight += vbox.GetThemeConstant("separation");
                }
            }
        }
        return totalHeight + padding;
    }
}

Try use scroll container as the parent of the UIContainer. The PanelContainer mostly used to contain and follow what the child sizes are.

1 Like

Thanks! It works, but another problem occurred. When Expandable is shrinked, if the mouse wheel scrolls, it will scroll. If I set Vertical scroll mode to Disabled, The panel will not able to keep its size. Is it possible to solve that?

Expand:

Shrink:
image

Shrink, and scroll:
image

Okay it’s all solved, Thanks!

I added this code on scroll container

using Godot;
using System;

public partial class LockScrollContainer : ScrollContainer
{
    public bool AllowScrolling = false;

    public override void _GuiInput(InputEvent @event)
    {
        if (@event is InputEventMouseButton mouseEvent &&
            (mouseEvent.ButtonIndex == MouseButton.WheelUp ||
             mouseEvent.ButtonIndex == MouseButton.WheelDown))
        {
            if (!AllowScrolling)
            {
                AcceptEvent();
            }
        }

        if (@event is InputEventPanGesture panGesture)
        {
            if (!AllowScrolling)
            {
                AcceptEvent();
            }
        }

        base._GuiInput(@event);
    }
}
1 Like