using Godot; using Rokojori; using System.Collections.Generic; using System.Linq; namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIText.svg")] public partial class UIText:Label,UIStylePropertyContainerNode, iLocalizable, UIHolderControl, IAssemblyReload { LocalizedString _locale; [Export] public LocalizedString locale { get => _locale; set { _locale = value; UpdateLocalization(); } } [Export] public bool refreshText { get => false; set { if ( value ) UpdateLocalization(); UpdateFont(); } } [Export] public bool disableLocalization = false; public void UpdateLocalization() { if ( disableLocalization ) { return; } Text = LocalizedString.Get( _locale ); _textDirty = true; } public void OnAssemblyReloaded() { UpdateLocalization(); UpdateFont(); } [Export] public bool alwaysMinimumSize = true; UIStyle _parentStyle; [Export] public UIStyle parentStyle { get => _parentStyle; set { _parentStyle = value; UpdateFont(); } } Font _font; [ExportGroup( "Font" )] [Export] public Font font { get => _font; set { _font = value; UpdateFont(); } } [Export] public UINumber fontSize; [Export] public UIColor fontColor; [Export] public UINumber outlineSize; [Export] public UIColor outlineColor; [Export] public UINumber shadowSize; [Export] public UIColor shadowColor; [Export] public UINumber shadowOffsetX; [Export] public UINumber shadowOffsetY; [ExportGroup("Size & Margins")] [Export] public UINumber width; [Export] public UINumber height; [Export] public UINumber margin; [Export] public UINumber marginLeft; [Export] public UINumber marginTop; [Export] public UINumber marginRight; [Export] public UINumber marginBottom; [ExportGroup( "Position" )] [Export] public UIPosition position; [Export] public UILineWrap lineWrap; [Export] public UINumber left; [Export] public UINumber top; [Export] public UINumber right; [Export] public UINumber bottom; [ExportGroup("Rotation & Scale")] [Export] public UINumber pivotX; [Export] public UINumber pivotY; [Export] public UINumber rotation; [Export] public UINumber scale; [Export] public UINumber scaleX; [Export] public UINumber scaleY; public Font GetFont() { return font; } void UpdateFont() { var resolvedFont = UIStyle.Font( this ); if ( resolvedFont != null ) { RemoveThemeFontOverride( "font" ); AddThemeFontOverride( "font", resolvedFont ); _textDirty = true; } } string hoverID = IDGenerator.GenerateID(); public override void _Ready() { MouseEntered += ()=> { AddUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); }; MouseExited += ()=> { RemoveUISelectorFlag( UISelectorFlag.Hover, hoverID ); this.SetDirty(); }; } int _uiAncestorDepth; public void ComputeUIAncestorDepth() { SetUIAncestorDepth( NodesWalker.Get().GetAncestorDistance( this, GetUI( false ) ) ); } public void SetUIAncestorDepth( int depth ) { _uiAncestorDepth = depth; } public int GetUIAncestorDepth() { return _uiAncestorDepth; } public override void _EnterTree() { ComputeUIAncestorDepth(); } public override void _ExitTree() { _uiAncestorDepth = -1; } protected override void Dispose( bool disposing) { _selectorFlagReferenceCounter.Clear(); } MapList _selectorFlagReferenceCounter = new MapList(); public void AddUISelectorFlag( UISelectorFlag flag, string reference = "" ) { SetSelectorFlagReference( flag, reference, true ); } public void RemoveUISelectorFlag( UISelectorFlag flag, string reference = "" ) { SetSelectorFlagReference( flag, reference, false ); } void SetSelectorFlagReference( UISelectorFlag flag, string reference, bool enable ) { if ( enable ) { _selectorFlagReferenceCounter.AddIfNotPresent( flag, reference ); } else { _selectorFlagReferenceCounter.Remove( flag, reference );; } var numFlagsBefore = _selectorFlags.Count; _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList(); var changed = numFlagsBefore != _selectorFlags.Count; UISelector.UpdateParentUISelectorFlags( this ); if ( changed ) { this.SetDirty(); } } List _selectorFlags = []; List _parentSelectorFlags = []; public List GetUISelectorFlags() { return _selectorFlags; } public List GetParentUISelectorFlags() { return _parentSelectorFlags; } public override void _GuiInput( InputEvent inputEvent ) { if ( ! handleMouseEvents ) { return; } if ( inputEvent is InputEventMouseButton mb ) { if ( mb.Pressed ) { if ( mb.ButtonIndex == MouseButton.Left ) { Action.Trigger( onLeftClick ); } if ( mb.ButtonIndex == MouseButton.Middle ) { Action.Trigger( onMiddleClick ); } if ( mb.ButtonIndex == MouseButton.Right ) { Action.Trigger( onRightClick ); } } } } [ExportGroup("Transitions")] [Export] public TransitionSettingsAll transitionSettings; public TransitionSettingsAll GetTransitionSettingsAll() { return transitionSettings; } [Export] public UINumberTransition[] numberTransitions = new UINumberTransition[ 0 ]; public UINumberTransition[] GetNumberTransitions() { return numberTransitions; } public List> activeNumberTransitions = new List>(); public List> GetActiveUINumberTransitions() { return activeNumberTransitions; } [Export] public UIColorTransition[] colorTransitions = new UIColorTransition[ 0 ]; public UIColorTransition[] GetColorTransitions() { return colorTransitions; } public List> activeColorTransitions = new List>(); public List> GetActiveUIColorTransitions() { return activeColorTransitions; } LabelSettings _labelSettings; public LabelSettings uiTextLabelSettings { get { if ( _labelSettings == null ) { _labelSettings = new LabelSettings(); } LabelSettings = _labelSettings; return _labelSettings; } set { _labelSettings = value.Duplicate() as LabelSettings; LabelSettings = _labelSettings; } } [ExportGroup("Events")] [Export] public bool handleMouseEvents = false; [Export] public Action onLeftClick; [Export] public Action onMiddleClick; [Export] public Action onRightClick; public UIStyle GetUIStyleParent() { return parentStyle; } public UIPosition GetUIPosition() { return position; } public UILineWrap GetUILineWrap() { return lineWrap; } public UILayout GetUILayout() { return UILayout.___; } public ShaderUIColor[] GetShaderUIColors() { return null; } public ShaderUINumber[] GetShaderUINumbers() { return null; } public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source ) { switch ( property ) { case UIStyleNumberProperty.Width: return width; case UIStyleNumberProperty.Height: return height; case UIStyleNumberProperty.Margin: return margin; case UIStyleNumberProperty.MarginLeft: return marginLeft; case UIStyleNumberProperty.MarginRight: return marginRight; case UIStyleNumberProperty.MarginTop: return marginTop; case UIStyleNumberProperty.MarginBottom: return marginBottom; case UIStyleNumberProperty.Left: return left; case UIStyleNumberProperty.Right: return right; case UIStyleNumberProperty.Top: return top; case UIStyleNumberProperty.Bottom: return bottom; case UIStyleNumberProperty.PivotX: return pivotX; case UIStyleNumberProperty.PivotY: return pivotY; case UIStyleNumberProperty.Rotation: return rotation; case UIStyleNumberProperty.Scale: return scale; case UIStyleNumberProperty.ScaleX: return scaleX; case UIStyleNumberProperty.ScaleY: return scaleY; case UIStyleNumberProperty.FontSize: return fontSize; case UIStyleNumberProperty.FontOutlineSize: return outlineSize; case UIStyleNumberProperty.FontShadowSize: return shadowSize; case UIStyleNumberProperty.FontShadowOffsetX: return shadowOffsetX; case UIStyleNumberProperty.FontShadowOffsetY: return shadowOffsetY; } return null; } public void SetUIStyleNumberProperty( UIStyleNumberProperty property, UINumber number ) { switch ( property ) { case UIStyleNumberProperty.Left: { left = number; } break; case UIStyleNumberProperty.Right: { right = number; } break; case UIStyleNumberProperty.Top: { top = number; } break; case UIStyleNumberProperty.Bottom: { bottom = number; } break; case UIStyleNumberProperty.Width: { width = number; } break; case UIStyleNumberProperty.Height: { height = number; } break; case UIStyleNumberProperty.Margin: { margin = number; } break; case UIStyleNumberProperty.MarginLeft: { marginLeft = number; } break; case UIStyleNumberProperty.MarginRight: { marginRight = number; } break; case UIStyleNumberProperty.MarginTop: { marginTop = number; } break; case UIStyleNumberProperty.MarginBottom: { marginBottom = number; } break; case UIStyleNumberProperty.FontSize: { fontSize = number; _textDirty = true; } break; case UIStyleNumberProperty.FontOutlineSize: { outlineSize = number; _styleDirty = true; } break; case UIStyleNumberProperty.FontShadowSize: { shadowSize = number; _styleDirty = true; } break; case UIStyleNumberProperty.FontShadowOffsetX: { shadowOffsetX = number; _styleDirty = true; } break; case UIStyleNumberProperty.FontShadowOffsetY: { shadowOffsetY = number; _styleDirty = true; } break; case UIStyleNumberProperty.PivotX: { pivotX = number; } break; case UIStyleNumberProperty.PivotY: { pivotY = number; } break; case UIStyleNumberProperty.Rotation: { rotation = number; } break; case UIStyleNumberProperty.Scale: { scale = number; } break; case UIStyleNumberProperty.ScaleX: { scaleX = number; } break; case UIStyleNumberProperty.ScaleY: { scaleY = number; } break; } this.SetLayoutDirtyFlag(); } public Vector2 GetUISize() { return GetSize(); } bool _isAnimated = false; int _isLayoutDirty = 3; public void ResetDirtyFlags() { _isAnimated = false; _isLayoutDirty = Mathf.Max( 0, _isLayoutDirty - 1 ); } public void SetAnimatedFlag() { _isAnimated = true; this.SetDirty(); } public void SetLayoutDirtyFlag() { _isLayoutDirty = 3; this.SetDirty(); } public bool IsDirty() { return _isAnimated || _isLayoutDirty != 0 || this.HasActiveTransitions(); } bool _styleDirty = false; bool _textDirty = false; public class CachedLabelSettings { public CachedUINumber fontSize = CachedUINumber.AsInt( UIStyleNumberProperty.FontSize ).SetMin( 1 ); public CachedUINumber outlineSize = CachedUINumber.AsInt( UIStyleNumberProperty.FontOutlineSize ); public CachedUINumber shadowSize = CachedUINumber.AsInt( UIStyleNumberProperty.FontShadowSize ); public CachedUINumber shadowOffsetX = CachedUINumber.AsFloat( UIStyleNumberProperty.FontShadowOffsetX ); public CachedUINumber shadowOffsetY = CachedUINumber.AsFloat( UIStyleNumberProperty.FontShadowOffsetY ); public CachedUIColor fontColor = CachedUIColor.Create( UIStyleColorProperty.FontColor ); public CachedUIColor outlineColor = CachedUIColor.Create( UIStyleColorProperty.FontOutlineColor ); public CachedUIColor shadowColor = CachedUIColor.Create( UIStyleColorProperty.FontShadowColor ); public bool HasChanged() { if ( fontSize.changed || outlineSize.changed || shadowSize.changed || fontColor.changed ) { return true; } if ( outlineSize.valueInt > 0 && outlineColor.changed ) { return true; } if ( shadowSize.valueInt > 0 && ( shadowOffsetX.changed || shadowOffsetY.changed || shadowColor.changed ) ) { return true; } return false; } bool _wasCreated = false; public bool wasCreated => _wasCreated; public LabelSettings CreateLabelSettings() { _wasCreated = true; var l = new LabelSettings(); l.FontSize = fontSize.valueInt; l.OutlineSize = outlineSize.valueInt; l.ShadowSize = shadowSize.valueInt; l.FontColor = fontColor.color; if ( outlineSize.valueInt > 0 ) { l.OutlineColor = outlineColor.color; } if ( shadowSize.valueInt > 0 ) { l.ShadowColor = shadowColor.color; l.ShadowOffset = new Vector2( shadowOffsetX.value, shadowOffsetY.value ); } return l; } } CachedLabelSettings cachedLabelSettings = new CachedLabelSettings(); public void Update() { // FONT SIZE // VIEW WIDTH/HEIGHT // PARENT WIDTH/HEIGHT // PARENT STYLE // PROP var ui = GetUI(); var updateTextField = _textDirty || ui.fontSizeChanged || ui.sizeChanged; if ( ui.fontSizeChanged || ! cachedLabelSettings.wasCreated ) { cachedLabelSettings.fontSize.alternative = UINumber.em( this ); cachedLabelSettings.fontSize.relative = UINumber.em( this ) / 100f ; } cachedLabelSettings.fontSize.Compute( this ); cachedLabelSettings.outlineSize.Compute( this ); cachedLabelSettings.shadowSize.Compute( this ); cachedLabelSettings.fontColor.Compute( this ); if ( cachedLabelSettings.outlineSize.valueInt > 0 ) { cachedLabelSettings.outlineColor.Compute( this ); } if ( cachedLabelSettings.shadowSize.valueInt > 0 ) { cachedLabelSettings.shadowOffsetX.Compute( this ); cachedLabelSettings.shadowOffsetY.Compute( this ); cachedLabelSettings.shadowColor.Compute( this ); } updateTextField = updateTextField || cachedLabelSettings.fontSize.changed; if ( cachedLabelSettings.HasChanged() || ! cachedLabelSettings.wasCreated ) { uiTextLabelSettings = cachedLabelSettings.CreateLabelSettings(); } // uiTextLabelSettings.FontSize = Mathf.Max( 1, // UINumber.ComputeInt( this, UIStyleNumberProperty.FontSize, UINumber.em( this ), UINumber.em( this ) / 100f ) ); // uiTextLabelSettings.OutlineSize = // UINumber.ComputeInt( this, UIStyleNumberProperty.FontOutlineSize, 0 ); // uiTextLabelSettings.ShadowSize = // UINumber.ComputeInt( this, UIStyleNumberProperty.FontShadowSize, 0 ); // uiTextLabelSettings.ShadowOffset = new Vector2( // UINumber.Compute( this, UIStyleNumberProperty.FontShadowOffsetX, 0 ), // UINumber.Compute( this, UIStyleNumberProperty.FontShadowOffsetY, 0 ) // ); // uiTextLabelSettings.FontColor = // UIColor.Compute( this, UIStyleColorProperty.FontColor, "", Colors.White ); // uiTextLabelSettings.OutlineColor = // UIColor.Compute( this, UIStyleColorProperty.FontOutlineColor, "", Colors.Transparent ); // uiTextLabelSettings.ShadowColor = // UIColor.Compute( this, UIStyleColorProperty.FontShadowColor, "", Colors.Black ); if ( ! updateTextField ) { return; } UpdateMinimumSize(); if ( alwaysMinimumSize ) { if ( AutowrapMode == TextServer.AutowrapMode.Word ) { AutowrapMode = TextServer.AutowrapMode.Off; var minSize = GetMinimumSize(); AutowrapMode = TextServer.AutowrapMode.Word; var w = UINumber.Compute( this, UIStyleNumberProperty.Width, minSize.X, minSize.X / 100f ); var h = UINumber.Compute( this, UIStyleNumberProperty.Height, minSize.Y, minSize.Y / 100f ); CustomMinimumSize = new Vector2( Mathf.Min( minSize.X, w ), 0 ); } Size = GetMinimumSize(); } else { var minSize = GetMinimumSize(); var w = UINumber.Compute( this, UIStyleNumberProperty.Width, minSize.X, minSize.X / 100f ); var h = UINumber.Compute( this, UIStyleNumberProperty.Height, minSize.Y, minSize.Y / 100f ); // RJLog.Log( "Set Image Size", w, h ); Size = new Vector2( w, h ); } } public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source ) { switch ( property ) { case UIStyleColorProperty.FontColor: return fontColor; case UIStyleColorProperty.FontOutlineColor: return outlineColor; case UIStyleColorProperty.FontShadowColor: return shadowColor; } return null; } UI ui; public void SetUI( UI ui,bool computeDepth = true ) { this.ui = ui; if ( computeDepth ) { ComputeUIAncestorDepth(); } } public UI GetUI( bool computeDepth = true ) { if ( this.ui != null ) { return this.ui; } var ui = this.FindParentThatIs(); if ( ui == null ) { _uiAncestorDepth = -1; // this.LogInfo( "No UI in parents >", HierarchyName.Of( this ) ); return null; } if ( computeDepth ) { ComputeUIAncestorDepth(); } return ui; } } }