The same question was asked on reddit but the thread was archived. I want a container similar to the existing HBoxContainer that wraps the items if their width exceeds the horizontal size limit. The items have variable size.

Maybe it's also a good thing to put into the Asset-Library. At the moment there is only a Circular Container.

Someone who coded this already and willing to share his/her code?

5 days later

Ok, so for now I created a container that wraps horizontally and that exports an angle variable to style some ratio:

# reference:
# sciter's flow: https://sciter.com/docs/flex-flow/flex-layout.htm
# css3 flexbox, short: https://www.w3schools.com/csS/css3_flexbox.asp
# css3 flexbox, long: https://www.w3.org/TR/css-flexbox-1/#layout-algorithm
tool
extends Container

export (float, 0.0, 90.0) var angle = 0.0 setget set_angle

func _notification(what):
  if (what==NOTIFICATION_SORT_CHILDREN):
    var xOff = 0
    var yOff = 0
    var line_height = 0
    for c in get_children():
      if not c is Control:
        continue
      # wrap
      if xOff > 0 and xOff + c.rect_size.x > self.rect_size.x:
        xOff = 0
        yOff += line_height
        line_height = 0
      fit_child_in_rect( c, Rect2( xOff, yOff, c.rect_size.x, c.rect_size.y ) )
      xOff += c.rect_size.x
      line_height = max(line_height, c.rect_size.y)

# set horizontal size so that angle is approximated
func _get_minimum_size():
  # algorithm
  #  - start with one line
  #  - in each step, shorten by one pixel and shrink to max line-length
  #  - until no shrinking possible anymore
  #
  # a dynamic programming idea would start with something like following table:
  #  1,4 2,4 3,4 4,4
  #  1,3 2,3 3,3
  #  1,2 2,2
  #  1,1
  var variant
  var approximation = 1e6
  var next_variant = _shrink_width(1e6)
  if next_variant.x == 0:
    return Rect2(0, 0, 0, 0)
  var next_approximation = atan(next_variant.y / next_variant.x) / PI * 180
  while abs(angle - next_approximation) < abs(angle - approximation):
    variant = next_variant
    approximation = next_approximation
    next_variant = _shrink_width(variant.x - 1)
    next_approximation = atan(next_variant.y / next_variant.x) / PI * 180
  return variant

func _shrink_width(width):
  var xOff = 0
  var yOff = 0
  var max_width = 0
  var line_height = 0
  for c in get_children():
    if not c is Control:
      continue
    # wrap
    if xOff > 0 and xOff + c.rect_size.x > width:
      xOff = 0
      yOff += line_height
      line_height = 0
    xOff += c.rect_size.x
    max_width = max(max_width, xOff)
    line_height = max(line_height, c.rect_size.y)
  return Vector2(max_width, yOff + line_height)

func set_angle(new_angle):
  angle = new_angle
  minimum_size_changed()

I'm open to feedback and some feature requests. When my colleague and I will be through some iterations and if there is any interest, I will consider adding a plugin. Still I'm also open for your code.

3 years later