using Godot; using System.Collections.Generic; namespace Rokojori { public class FontFXGroup { public FontDefinition fontDefinition; public float scale = 1; public string characters; float _width = 0; public float width { get { if ( _width == 0 ) { _width = fontDefinition.GetWidth( characters ) * scale; } return _width; } } public List relativeOffsets => fontDefinition.GetOffsets( characters ).Map( o => o * scale ); public List absoluteOffsets; } public class FontFXLine { public List groups = new List(); public void ComptuteOffsets() { var offset = 0f; for ( int i = 0; i < groups.Count; i++ ) { var width = groups[ i ].width; groups[ i ].absoluteOffsets = groups[ i ].relativeOffsets.Map( o => o + offset ); offset += width; } } public List LayoutLineWrapped( float width ) { var lines = new List(); var line = new FontFXLine(); var lineWidth = 0f; groups.ForEach( ( g )=> { var groupWidth = g.width; var nextEnd = lineWidth + groupWidth; if ( nextEnd > width ) { lines.Add( line ); line = new FontFXLine(); lineWidth = 0; } line.groups.Add( g ); lineWidth += groupWidth; } ); lines.Add( line ); return lines; } } public class FontFXLayouter { public List Layout( string text, FontDefinition font, float maxWidth = 10000000 ) { var lines = new List(); var lexed = WordLexer.Lex( text ); if ( lexed == null ) { return null; } var line = new FontFXLine(); lexed.ForEach( ( l )=> { if ( l.isDone ) { return; } if ( l.Is( WordLexer.LineBreak ) ) { lines.Add( line ); line = new FontFXLine(); return; } var group = new FontFXGroup(); group.fontDefinition = font; group.characters = l.match; line.groups.Add( group ); } ); lines.Add( line ); lines = lines.MultiMap( ( line, index ) => line.LayoutLineWrapped( maxWidth ) ); return lines; } } }