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.