275 lines
8.4 KiB
C#
275 lines
8.4 KiB
C#
|
|
using Godot;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class UIFlowLayout
|
|
{
|
|
public class ControlPlacement
|
|
{
|
|
public Control control;
|
|
public float offset;
|
|
public float width;
|
|
public float height;
|
|
|
|
public float yOffset = 0;
|
|
|
|
public float maxX => offset + width;
|
|
|
|
public void AlignVertically( float maxHeight, float alignment )
|
|
{
|
|
var bottomAlignement = maxHeight - height;
|
|
|
|
yOffset = Mathf.Lerp( 0, bottomAlignement, alignment );
|
|
}
|
|
|
|
public void Apply( Vector2 parentOffset )
|
|
{
|
|
if ( UIStyling.CanPosition( control ) )
|
|
{
|
|
var container = (UIStylePropertyContainer) control;
|
|
|
|
|
|
var offsetX = UINumber.Compute( control, UIStyleNumberProperty.Left, 0 ) -
|
|
UINumber.Compute( control, UIStyleNumberProperty.Right, 0 );
|
|
|
|
var offsetY = UINumber.Compute( control, UIStyleNumberProperty.Top, 0 ) -
|
|
UINumber.Compute( control, UIStyleNumberProperty.Bottom, 0 );
|
|
|
|
UILayouting.SetPosition( control, parentOffset + new Vector2( offset + offsetX, yOffset + offsetY ) );
|
|
}
|
|
else
|
|
{
|
|
control.Position = parentOffset + new Vector2( offset, yOffset );
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Line
|
|
{
|
|
public float y;
|
|
public float size;
|
|
public float xOffset;
|
|
public List<ControlPlacement> placements = new List<ControlPlacement>();
|
|
|
|
public float maxY => y + size;
|
|
public float maxX => placements.Count == 0 ? 0 : placements[ placements.Count -1 ].maxX ;
|
|
}
|
|
|
|
public static void Apply( UIRegion region )
|
|
{
|
|
var lines = CreateLines( region );
|
|
|
|
AdjustLines( region, lines );
|
|
|
|
var maxWidth = 0f;
|
|
var maxHeight = 0f;
|
|
var maxVerticalPlacementOffset = 0f;
|
|
var maxLineY = lines.Count > 0 ? lines[ lines.Count - 1 ].maxY : 0;
|
|
|
|
region.contentSize.X = 0f;
|
|
region.contentSize.Y = maxLineY;
|
|
|
|
lines.ForEach( l => { region.contentSize.X = Mathf.Max( region.contentSize.X, l.maxX ); } );
|
|
|
|
|
|
if ( UINumber.IsNullOrNone( region, UIStyleNumberProperty.Width ) )
|
|
{
|
|
maxWidth = region.contentSize.X;
|
|
}
|
|
else
|
|
{
|
|
maxWidth = UINumber.Compute( region, UIStyleNumberProperty.Width );
|
|
}
|
|
|
|
if ( ! UINumber.IsNullOrNone( UIStyle.GetUINumberProperty( region, UIStyleNumberProperty.Height ) ) )
|
|
{
|
|
maxHeight = UINumber.Compute( region, UIStyleNumberProperty.Height );
|
|
maxVerticalPlacementOffset = maxHeight - maxLineY;
|
|
|
|
}
|
|
else if ( lines.Count > 0 )
|
|
{
|
|
maxHeight = maxLineY;
|
|
}
|
|
|
|
var margin = UINumber.Compute( region, UIStyleNumberProperty.Margin, 0 );
|
|
var marginLeft = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginLeft, 0 );
|
|
var marginTop = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginTop, 0 );
|
|
|
|
var marginRight = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginRight, 0 );
|
|
var marginBottom = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginBottom, 0 );
|
|
|
|
|
|
var verticalPlacementOffset = UINumber.Compute( region, UIStyleNumberProperty.VerticalPlacement, 0, maxVerticalPlacementOffset );
|
|
|
|
// if ( region.Name == "Audio" )
|
|
// {
|
|
// RJLog.Log( "Audio Placements",
|
|
// "maxHeight:", maxHeight,
|
|
// "maxLineY:", maxLineY,
|
|
// "maxVerticalPlacementOffset", maxVerticalPlacementOffset,
|
|
// "verticalPlacementOffset", verticalPlacementOffset
|
|
// );
|
|
// }
|
|
|
|
|
|
var marginOffset = new Vector2( marginLeft, marginTop + verticalPlacementOffset );
|
|
|
|
region.contentOffset = marginOffset;
|
|
|
|
PlaceControls( region, lines, marginOffset );
|
|
|
|
var alignmentWidth = maxWidth + marginLeft + marginRight;
|
|
var horizontalAlignment = UINumber.Compute( region, UIStyleNumberProperty.HorizontalAlignment, 0 );
|
|
region.contentOffset.X = Mathf.Lerp( 0, alignmentWidth - region.contentSize.X, horizontalAlignment / 100f );
|
|
|
|
var verticalMargins = marginTop + marginBottom;
|
|
var horizontalMargins = marginLeft + marginRight;
|
|
|
|
region.Size = new Vector2( maxWidth + horizontalMargins, maxHeight + verticalMargins );
|
|
|
|
if ( UIStyle.Position( region ) == UIPosition.Parent_Anchor )
|
|
{
|
|
UILayouting.SetPositionInParentAnchor( region );
|
|
}
|
|
|
|
Nodes.ForEachDirectChild<Control>( region,
|
|
child =>
|
|
{
|
|
|
|
var styleContainer = child as UIStylePropertyContainer;
|
|
|
|
if ( styleContainer == null || UIStyle.Position( styleContainer ) != UIPosition.Parent_Anchor )
|
|
{
|
|
return;
|
|
}
|
|
|
|
UILayouting.UpdateChild( child );
|
|
UILayouting.SetPositionInParentAnchor( styleContainer );
|
|
|
|
}
|
|
);
|
|
}
|
|
|
|
static List<Line> CreateLines( UIRegion region )
|
|
{
|
|
var x = 0f;
|
|
var width = UINumber.Compute( region, UIStyleNumberProperty.Width, 100000000f );
|
|
|
|
var lines = new List<Line>();
|
|
var currentLine = new Line();
|
|
|
|
var elementSpacing = UINumber.Compute( region, UIStyleNumberProperty.ElementSpacing, 0f );
|
|
var lineSpacing = UINumber.Compute( region, UIStyleNumberProperty.LineSpacing, 0f );
|
|
|
|
Nodes.ForEachDirectChild<Control>( region, c => UILayouting.UpdateChild( c ) );
|
|
|
|
|
|
Nodes.ForEachDirectChild<Control>( region,
|
|
child =>
|
|
{
|
|
if ( ! child.Visible )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var styleContainer = child as UIStylePropertyContainer;
|
|
|
|
if ( styleContainer != null && UIStyle.Position( styleContainer ) == UIPosition.Parent_Anchor )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cWidth = UILayouting.GetWidth( child );
|
|
var cHeight = UILayouting.GetHeight( child );
|
|
|
|
var nextEndX = x + cWidth + elementSpacing;
|
|
|
|
var lineWrap = UIStyle.LineWrap( styleContainer );
|
|
|
|
lineWrap = lineWrap == UILineWrap.___ ? UILineWrap.Wrap_On_Overflow : lineWrap;
|
|
|
|
if ( UILineWrap.Wrap_Never != lineWrap && ( UILineWrap.Wrap_Always == lineWrap || nextEndX > width ) )
|
|
{
|
|
lines.Add( currentLine );
|
|
currentLine = new Line();
|
|
x = 0;
|
|
currentLine.y = lines[ lines.Count - 1 ].maxY + lineSpacing;
|
|
nextEndX = cWidth + elementSpacing;
|
|
}
|
|
|
|
var placement = new ControlPlacement();
|
|
placement.offset = x;
|
|
placement.width = cWidth;
|
|
placement.height = cHeight;
|
|
placement.control = child;
|
|
|
|
currentLine.placements.Add( placement );
|
|
|
|
currentLine.size = Mathf.Max( currentLine.size, cHeight );
|
|
|
|
x = nextEndX;
|
|
}
|
|
);
|
|
|
|
if ( lines.Count > 0 )
|
|
{
|
|
currentLine.y = lines[ lines.Count - 1 ].maxY + lineSpacing;
|
|
}
|
|
|
|
lines.Add( currentLine );
|
|
|
|
return lines;
|
|
}
|
|
|
|
|
|
|
|
|
|
static void AdjustLines( UIRegion region, List<Line> lines )
|
|
{
|
|
var verticalAlignment = UINumber.Compute( region, UIStyleNumberProperty.VerticalAlignment, 0.5f, 1 );
|
|
|
|
lines.ForEach( line => AdjustVerticalAlignment( region, line, verticalAlignment ) );
|
|
|
|
if ( UINumber.IsNullOrNone( region, UIStyleNumberProperty.Width ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var horizontalAlignment = UINumber.Compute( region, UIStyleNumberProperty.HorizontalAlignment, 0.5f, 1 );
|
|
var maxWidth = UINumber.Compute( region, UIStyleNumberProperty.Width, 0 );
|
|
|
|
lines.ForEach( line => AdjustHorizontalAlignment( region, line, horizontalAlignment, maxWidth ) );
|
|
|
|
}
|
|
|
|
static void AdjustVerticalAlignment( UIRegion region, Line line, float verticalAlignment )
|
|
{
|
|
line.placements.ForEach( p => p.AlignVertically( line.size, verticalAlignment ) );
|
|
}
|
|
|
|
static void AdjustHorizontalAlignment( UIRegion region, Line line, float horizontalAlignment, float maxWidth )
|
|
{
|
|
var lineWidth = line.maxX;
|
|
var maxOffset = maxWidth - lineWidth;
|
|
|
|
line.xOffset = horizontalAlignment * maxOffset;
|
|
}
|
|
|
|
|
|
static void PlaceControls( UIRegion region, List<Line> lines, Vector2 marginOffset )
|
|
{
|
|
lines.ForEach(
|
|
line =>
|
|
{
|
|
var offset = new Vector2( line.xOffset, line.y ) + marginOffset;
|
|
line.placements.ForEach( p => p.Apply( offset ) );
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
} |