#Getting Custom Containers to update in the editor.

4 messages · Page 1 of 1 (latest)

vernal umbra
#

I'm working on some custom containers ported from my unity UI, and I was wondering if there's a way to make the objects in the editor update like the non-custom ones.

I read the docs here and this got me 90% of the way there, but it's really all I can find about custom containers.
https://docs.godotengine.org/en/stable/tutorials/ui/gui_containers.html#creating-custom-containers

Here's my first test, and while this works at runtime the code won't execute in the editor so I have to keep running the UI scene to test if it worked. Is there something I have to do to make it.

using Godot;
public partial class FitterTest : Container
{
    [Export(PropertyHint.Range, "0.0, 0.5")] float margin;
    public override void _Notification(int what)
    {
        if (what == NotificationSortChildren)
        {
            var anchorPosition = new Vector2(margin, margin);
            var anchorEnd = new Vector2(1.0f, 1.0f) - new Vector2(margin, margin);


            foreach (Control c in GetChildren())
            {
                c.SetAnchorAndOffset(Side.Left, anchorPosition.X, 0);
                c.SetAnchorAndOffset(Side.Right, anchorEnd.X, 0);
                c.SetAnchorAndOffset(Side.Top, anchorPosition.Y, 0);
                c.SetAnchorAndOffset(Side.Bottom, anchorEnd.Y, 0);
            }
        }
    }
    public void SetSomeSetting()
    {
        QueueSort();
    }
}

I do recognize that there is a margin container already, but the final container code is going to be much more involved, I just want to know if there's a solution that makes it run in the editor to speed up development time.

Any help is appreciated!

vernal umbra
#

Okay so with some help on mastodon we have at least a temporary solution
https://mastodon.gamedev.place/@snowdrama/111086666285264378

Basically we change the script to a tool, which processes every frame. We check for changes in the settings state or size of the window, and then update if that's changed.

using Godot;

[Tool]
public partial class FitterTest : Container
{
    [Export(PropertyHint.Range, "0.0, 0.5")]
    float margin;
    private float oldMargin;
    private Vector2 oldSize;
    public override void _Process(double delta)
    {
        //if the state changed 
        if(oldMargin != margin || oldSize != Size)
        {
            UpdateContainerContents();
            oldMargin = margin;
            oldSize = Size;
        }
    }

    private void UpdateContainerContents()
    {
        GD.Print("Updating the container contents");
        // Must re-sort the children
        var anchorPosition = new Vector2(margin, margin);
        var anchorEnd = new Vector2(1.0f, 1.0f) - new Vector2(margin, margin);
        foreach (Control c in GetChildren())
        {
            c.SetAnchorAndOffset(Side.Left, anchorPosition.X, 0);
            c.SetAnchorAndOffset(Side.Right, anchorEnd.X, 0);
            c.SetAnchorAndOffset(Side.Top, anchorPosition.Y, 0);
            c.SetAnchorAndOffset(Side.Bottom, anchorEnd.Y, 0);
        }
    }
}
#

The one issue I still have with this solution is that I have to do all the state comparison, the original documentation seems to imply that the _Notification function will be fired whenever the size of the container or window changes. But that doesn't seem to fire off in the editor at all.

vernal umbra
#

So we have to include both solutions and then wrap the _Process one that runs in the editor in an editor hint(and I added a preprocessor define to remove the process entirely from release builds)

using Godot;

[Tool]
public partial class FitterTest : Container
{
    [Export(PropertyHint.Range, "0.0, 0.5")]
    float margin;
    private float oldMargin;
    private Vector2 oldSize;

#if TOOLS //removes below in release builds
    public override void _Process(double delta)
    {
        if (Engine.IsEditorHint())
        {
            //if the state changed 
            if(oldMargin != margin || oldSize != Size)
            {            
                GD.Print("Process in the editor!");
                UpdateContainerContents();
                oldMargin = margin;
                oldSize = Size;
            }
        }
    }
#endif

    public override void _Notification(int what)
    {
        if (what == NotificationSortChildren)
        {
            GD.Print("Updating in Sort");
            UpdateContainerContents();
        }
    }

    public void SetSomeSetting()
    {
        QueueSort();
    }
    private void UpdateContainerContents()
    {
        GD.Print("Updating the container contents");
        // Must re-sort the children
        var anchorPosition = new Vector2(margin, margin);
        var anchorEnd = new Vector2(1.0f, 1.0f) - new Vector2(margin, margin);
        foreach (Control c in GetChildren())
        {
            c.SetAnchorAndOffset(Side.Left, anchorPosition.X, 0);
            c.SetAnchorAndOffset(Side.Right, anchorEnd.X, 0);
            c.SetAnchorAndOffset(Side.Top, anchorPosition.Y, 0);
            c.SetAnchorAndOffset(Side.Bottom, anchorEnd.Y, 0);
        }
    }
}