I want to have an HBoxContainer
that holds TextureRect
s and scales them down to fit the container’s width, so I don’t have to scroll horizontally to see more. The container should however adapt its height to the tallest TextureRect
so basically, fixed width (e.g., screen’s width) and variable height (i.e., tallest content). I’ve been messing around with pretty much every control I could find in the inspector, both for the container and the images, but I can’t find a solution.
Alternatively, I’d be happy to set the TextureRect
s’ widths (since I’m creating them programmatically anyway) but it seems that, when a TextureRect
is inside a container, the container dictates its size.
So I created a canvas layer, added a control node, added a hbox, added 4 texture rects, 3 with the default Icon and one with a tiny tick icon. The tick icon I had to change the container to shrink-begin otherwise it stretched by default, and I got this:
Is that what you wanted?
Then I thought perhaps you wanted the icons to shrink to fit into the width of the screen when it was longer than the viewport? Is that what you were after?
If so, I added a margin container to cover the full width at the top of the page.
The Icons I changed to fill and expand. The texture rects were changed to ignore size and keep aspect.
Here it is with 9 icons that just about fit on the screen.
When I add 5 more they begin to shrink to fit.
So it all appears to work fine.
Sometimes with control nodes, especially when you are ‘trying things out’ there are so many options that the structure can become either too complex or we click things we forget to revert, especially when it appears to initially have no affect. My advice would be to start again with a fresh scene, and not change any settings until you have at least your basic main structure laid out. Starting again with control nodes is often a good idea if you find yourself stuggling.
Also, if I am making a similar thing, I would ensure all my icons are the same size to start with, both width and height, even if that means that I need to have duplicate icons at different sizes if needed in different places.
Anyway I hope that helps, but if not, post some diagrams of what you are trying to achieve and I will see if I can help further.
OK, so, yes, this is what I want, and I was able to replicate it creating nodes with the editor. However, when I go and do it programmatically, the HBoxContainer
(and therefore the TextureRects
within) have 0 height, so I see nothing. Here’s the code.
var carousel = HBoxContainer.new()
carousel.alignment = BoxContainer.ALIGNMENT_CENTER
carousel.add_theme_constant_override("separation", 50)
vbox_container.add_child(carousel)
for k in range(content_block["content"].size()):
var image = TextureRect.new()
image.texture = load(content_block["content"][k]["thumbnail"])
image.size_flags_horizontal = Control.SIZE_FILL | Control.SIZE_EXPAND
image.size_flags_vertical = Control.SIZE_FILL
image.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
image.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT
image.connect("gui_input", _on_image_pressed.bind(k, content_block["content"].map(func(c): return c["thumbnail"]), content_block["content"].map(func(c): return c["content"]), content_block["content"].map(func(c): return c["caption"][lang])))
carousel.add_child(image)
So I am not sure and have not replicated your code. However I often get this problem where when you create a container in code it needs a frame to process itself and reset it sizes etc. Try adding an await one frame before filling your vbox_container.
await get_tree().process_frame
I hope that helps.
Also try this:
carousel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
carousel.set_anchors_preset(Control.PRESET_FULL_RECT)
I got this working:
With this (slightly simplified version of your code):
func _ready() -> void:
var carousel = HBoxContainer.new()
carousel.alignment = BoxContainer.ALIGNMENT_CENTER
carousel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
carousel.set_anchors_preset(Control.PRESET_FULL_RECT)
carousel.add_theme_constant_override("separation", 50)
add_child(carousel)
await get_tree().process_frame
for k in range(10):
var image = TextureRect.new()
image.texture = load("res://icon.svg")
image.size_flags_horizontal = Control.SIZE_FILL | Control.SIZE_EXPAND
image.size_flags_vertical = Control.SIZE_FILL
image.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
image.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT
carousel.add_child(image)
And this result as I expected:
And with more icons:

Hope that helps.
PS I did test not using the full_rect, but the added hbox needs a height. You could set the min height by calculating from the number of icons and the width of your screen and their size ratios. Or you could set a max number of icons and test for a min height at that number. Or you could just set a min height to each texture. Neither solution I have found is exactly what you wanted apart from using a full rect, which probably will cause you problems elsewhere.
PPS You do not need to wait for a frame to process in this example BTW
1 Like