Creating previews of 2D nodes

Godot Version

4.5.1

Question

I’m making an application for editing certain files. At some point in my app, there is a list of items: clicking on an item opens an interface for editing it. In the list, I want to show a little visual preview for each item, so it’s visually easy to find the item you want to edit. The thing is, these items are made of 2D nodes (and my UI is made of Control nodes).

I could instantiate all the items in a separate viewport and have one SubViewportContainer for each preview, but I doubt this would perform well with thousands of items.

Perhaps I could pre-render all the items beforehand. How would that work?
Or is there a neat built-in solution I haven’t noticed?

You can mix Control and Node2D nodes.

Of course I know we can mix Control and Node2D, but as you should know, we can’t use anchors and/or containers on a Node2D.

So, I wrote a function that manually positions and scales a Node2D to fit inside some preview rectangle.

func _fit_inside_preview_rect(preview_rect: Rect2D) -> void:
	# Assuming you know the leftmost_point, rightmost_point,
	# topmost_point and bottommost_point of your node...

	var width: float = rightmost_point - leftmost_point
	var height: float = bottommost_point - topmost_point

	# Prevent division by zero
	if width == 0.0 or height == 0.0:
		return

	# Determine the scale ratio (e.g. if the node
	# is 3x bigger than it should be, then we need to scale by 1/3)
	# To preserve the aspect ratio,
	# we need to multiply by the smallest of the two ratios.
	var scale_ratio: float = (
			minf(preview_rect.size.x / width, preview_rect.size.y / height)
	)
	position = Vector2(
			preview_rect.position.x - leftmost_point * scale_ratio,
			preview_rect.position.y - topmost_point * scale_ratio
	)
	scale = Vector2(scale_ratio, scale_ratio)

It does work. It feels a bit hacky, though. I wish there was a built-in way to do this without code.

I have a feeling that if you need to show thousands of Node2D on UI, maybe you need to rethink of your whole architecture.

Anyway, one possible solution I can think of is..
If your Node2Ds have only one sprite2D, you can pass texture info of sprite to a texturerect node.