///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // D E R E L I C T // /// // (c) 2003..2024 using Godot; using Microsoft.Diagnostics.Tracing.Parsers.IIS_Trace; using System; /* T O D O: x) Add blinking cursor D O I N G: D O N E: */ [GlobalClass] public partial class TextAnimate : Control { public Action OnFinshed; [Export] public NodePath TargetPath = ".."; [Export] public int TrimStartCount = 0; [Export] public int TrimeEndCount = 0; [Export] public double InitialDelay = 0; [Export] public double MSPerChar = 100; [Export] public string OriginalText = "{ERR_BROKEN_TextAnimate}"; [Export] public string Cursor = ""; [ExportCategory( "Runtime" )] [Export] public Control TargetControl = null; [Export] public string TextSuffix = ""; [Export] public int CharCount = 0; [Export] public double TimeTillNextChar = 0; //Dont need prefix string since thats implicit in OriginalText [Export] public string SuffixStr = ""; Func GetNodeText; Action SetNodeText; // Called when the node enters the scene tree for the first time. public override void _Ready() { log.var( this.Name ); //log.info($"{this?.Name}"); if( TargetPath == null || TargetPath.IsEmpty ) { var parent = GetParent(); if( parent != null ) { log.info( $"{Name}: No TargetPath set, using parent {parent.Name}" ); TargetPath = parent.GetPath(); } else { log.warn( $"{Name}: No TargetPath set and no parent to use" ); ProcessMode = ProcessModeEnum.Disabled; return; } return; } TargetControl = GetNode( TargetPath ); if( TargetControl == null ) { log.warn( $"{Name}({this.NamePath()}): No node at {TargetPath}" ); return; } //* if( TargetControl is LineEdit tcLineEdit ) { log.info( $"{Name} Connect to {TargetControl.Name}'s TextChanged" ); tcLineEdit.TextChanged += ( text ) => Reset(); } else if( TargetControl is RichTextLabel richTextLabel ) { log.info( $"{Name} Connect to {TargetControl.Name}'s TextChanged" ); } else if( TargetControl is Button button ) { log.info( $"{Name} Connect to {TargetControl.Name}'s TextChanged" ); } else //*/ { log.high( $"{this?.Name} NOT CONNECTED {TargetControl?.Name}'s TextChanged" ); } //if( TargetControl is RichTextLabel rtLabel ) rtLabel.TextChanged += ( text ) => Reset(); log.info( $"{this.Name}: TargetControl is {TargetControl?.GetType().Name}" ); var propInfo = TargetControl?.GetType().GetProperty( "Text" ); var getMethod = propInfo?.GetGetMethod(); var setMethod = propInfo?.GetSetMethod(); if( getMethod == null || setMethod == null ) { log.warn( $"{Name}: No Text property on {TargetControl?.GetType().Name}" ); return; } GetNodeText = (Func)Delegate.CreateDelegate( typeof( Func ), TargetControl, getMethod ); SetNodeText = (Action)Delegate.CreateDelegate( typeof( Action ), TargetControl, setMethod ); OriginalText = GetNodeText(); SuffixStr = OriginalText.Substring( OriginalText.Length - TrimeEndCount ); Reset(); //log.debug( $"D O N E {GetType().Name}._Ready" ); } public void Reset( double delayMs = -1, string origText = "" ) { if( ProcessMode == ProcessModeEnum.Disabled ) return; if( GetNodeText == null || SetNodeText == null ) { log.warn( $"{Name}: No Text property on {TargetControl?.GetType().Name}" ); return; } if( string.IsNullOrWhiteSpace( origText ) ) origText = GetNodeText(); InitialDelay = delayMs / 1000.0; ProcessMode = ProcessModeEnum.Inherit; OriginalText = origText; if( delayMs < 0 ) { delayMs = MSPerChar; } //log.debug( $"TA.Text Reset {OriginalText}" ); CharCount = TrimStartCount; var text = OriginalText.Substring( 0, TrimStartCount ); TimeTillNextChar = delayMs / 1000.0; SetNodeText( $"{text}{Cursor}{SuffixStr}" ); ++CharCount; } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process( double delta ) { if( ProcessMode == ProcessModeEnum.Disabled ) return; if( GetNodeText == null || SetNodeText == null ) { return; } //log.info($"{this.Name}"); if( InitialDelay > 0 ) { InitialDelay -= delta; return; } TimeTillNextChar -= delta; if( TimeTillNextChar <= 0 ) { TimeTillNextChar += ( MSPerChar / 1000.0 ); if( CharCount < OriginalText.Length ) { //SetNodeText( TextPrefix + OriginalText.Substring( 0, CharCount ) + TextSuffix ); var newText = $"{OriginalText.Substring( 0, CharCount )}{Cursor}{SuffixStr}"; SetNodeText( newText ); ++CharCount; } else { SetNodeText( OriginalText ); OnFinshed?.Invoke( OriginalText ); //ProcessMode = ProcessModeEnum.Disabled; } } } }