How do i create a scrolling Card Display container?

Godot Version

4.4.1

Question

Edit:
Since my original text soup seems to be a little to vague, ill try to give a more concise description of my problem. I want to create a UI to display cards in a collection (think Hearthstone or MTG arena). The cards are 3D scenes, that wiggle a little for flavor when you mouse over them. I can display them in the UI with Viewport Containers without any problems. I want to use a ScrollContainer to display multiple cards in a row, and scroll horizontally. This UI should be able to adjust to any Height, so i can not just give the cards a fixed size. With the height of the containers determined by the parent, the width should automatically adjust. Currently, scrolling only happens when there are so many cards displayed, that they are shrunk to their minimum size, which is non adaptive, so the cards overlap.

TextureRect has the exact behaviour i want in “ExpandMode”:“FitWidthProportional”, but frustratingly, i cannot find it in any other control nodes.

Original post:

Hey everyone, i hope some UI wizard can figure something out for me. I want to have a scrolling image gallery, that displays multiple images and eventually extends horizontally. I am using a Scroll container, a Hboxcontainer and multiple margin containers. When i put imageRects inside these margin containers, everything works as it should, because i can set the “ExpandMode” to “FitWidthProportional” Forcing the Texture Rect to have a width that is based on the height, and thus making the Scroll container eventually having to scroll.

However my actual UI contains SubViewportContainers, instead of image Rects, since i want to display 3d elements. How do i force these SubViewportContainers (or margin containers or whatever) to ask the parent container for a width that fits their aspect ratio with regards of their heights. Essentially adjusting the minimum width, with respect to the current height.

I have fiddled around with "Aspect ration container"s, but i think they do exactly the opposite of what i want. They just force whatever is inside them to always have the same aspect. But they do not ask the parent container for space, with respect to their height. Why is it, that i can only find this “ExpandMode” on TextureRects?

The following does not work, since the containers cant ask for more width, proportional the their height:

It seems there is no Container that actually asks for space from the parent container, depending on the height or width.

I also posted this on reddit: https://www.reddit.com/r/godot/comments/1o4sqwy/help_with_scroll_container/

Do you want to display 3D elements inside your sub viewports? What’s your end goal? What are you trying to achieve??

Here’s a project I made where I tried to replicate what you’re trying to do…

Yes, eventually i want to display 3D elements in these subviewports. The sprite2D are just standins for the real thing. That is however not the problem. THe problem is, that i cannot get these to simultaniously be adjustable in height, depending on the parent container height, while also taking the required amount of width inside the scrolling container, and be scrollable.

I took a look at your project. The problem is, that the sprites do not scale with the height of the parent container. If you where to replace them with TextureRects, set them to fill the height, they would take up the whole height of the parent container, and then take up the amount of width they need.
Edit: You also obviously need to set the HBox container to fill vertically.
What your project looks like:

What i want:

Yeah now I understand what you’re trying to say. The default godot sprite doesn’t fit into sub viewport since it’s dimentions are 128x128 but it’s origin is center. So you have to manually change the subviewport dimentions and the offset of sprite2d, to match 128x128. I haven’t came across any thing that matches dimentions from parents to child automatically because they are different.
Are you trying to make a load screen where you save the state of the player and a screenshot of where he’s been on the map like in cyberpunk 2077…???

I managed to come up with a custom container, that works in scrolling environments and sets the width, or height of itself to whatever aspect ration you want:

@tool 
extends Container
class_name ProportionalFitContainer

@export_range(0.01, 100.0, 0.01) var aspect: float = 0.75: set = set_aspect # width/height, e.g. 0.75 for 3:4

enum FitMode {FitHeight, FitWidth}
@export var fit_mode:FitMode = FitMode.FitWidth


func set_aspect(new_aspect):
    aspect = new_aspect
    queue_sort()

func _notification(what):
    if what == NOTIFICATION_SORT_CHILDREN:
        # Must re-sort the children
        for c in get_children():
            # Fit to own size
            fit_child_in_rect(c, Rect2(Vector2(), size))

func _get_minimum_size() -> Vector2:
    var current_width = size.x
    var current_height = size.y
    var return_size:Vector2
    if self.fit_mode == FitMode.FitHeight:
        var width = current_width 
        var height = current_width/aspect 
        return_size = Vector2(width,height)
    elif self.fit_mode == FitMode.FitWidth:
        var height = current_height 
        var width = height*aspect 
        return_size = Vector2(width, height)
    return return_size
1 Like

Hi. I was going through the docs and I found this method. Maybe it can help you somewhere else in your project where you want parent area size… BTW you made a great solution :slight_smile:
Control — Godot Engine (4.5) documentation in English.