2024-08-09 13:52:49 +00:00
|
|
|
|
|
|
|
using Godot;
|
2025-06-19 17:22:25 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
namespace Rokojori
|
|
|
|
{
|
|
|
|
|
|
|
|
[Tool]
|
2025-02-12 16:48:15 +00:00
|
|
|
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UI.svg")]
|
2025-06-19 17:22:25 +00:00
|
|
|
public partial class UI : Control, IDisposable
|
|
|
|
{
|
2024-09-14 06:41:52 +00:00
|
|
|
|
2025-02-12 16:48:15 +00:00
|
|
|
[Export]
|
2025-06-19 17:22:25 +00:00
|
|
|
public UISettings settings;
|
2025-02-12 16:48:15 +00:00
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
[Export]
|
2025-06-19 17:22:25 +00:00
|
|
|
public float fontZoom = 1;
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
public enum UpdateMode
|
|
|
|
{
|
|
|
|
Always,
|
2025-06-23 11:16:01 +00:00
|
|
|
Optimized,
|
2025-06-19 17:22:25 +00:00
|
|
|
Only_Manual_Updates
|
|
|
|
}
|
2024-08-09 13:52:49 +00:00
|
|
|
[Export]
|
2025-06-19 17:22:25 +00:00
|
|
|
public UpdateMode updateMode = UpdateMode.Always;
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
[Export]
|
|
|
|
public bool useParentSize = false;
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
[ExportGroup("Functions")]
|
|
|
|
[ExportToolButton( "Mouse:Stop => Pass")]
|
|
|
|
public Callable StopToPassButton => Callable.From( ()=>{ MakeStopToPass(); } );
|
2024-08-09 13:52:49 +00:00
|
|
|
|
|
|
|
[Export]
|
2025-06-19 17:22:25 +00:00
|
|
|
public Node[] stopToPassRoots = [];
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-02-12 16:48:15 +00:00
|
|
|
[ExportGroup("Read Only")]
|
|
|
|
|
|
|
|
[Export]
|
2025-06-23 11:16:01 +00:00
|
|
|
public float X_computedFontSizePixels = 1;
|
2025-06-19 17:22:25 +00:00
|
|
|
|
|
|
|
List<ICustomDisposer> _customDisposers = [];
|
|
|
|
|
|
|
|
public void AddForDisposing( ICustomDisposer customDisposer )
|
|
|
|
{
|
|
|
|
_customDisposers.Add( customDisposer );
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose( bool disposing )
|
|
|
|
{
|
|
|
|
_customDisposers.ForEach( cd => cd.Dispose() );
|
|
|
|
_customDisposers = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public string[] customDisposerIDs = [];
|
2025-06-23 11:16:01 +00:00
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
|
|
|
|
public void MakeStopToPass()
|
|
|
|
{
|
|
|
|
var roots = stopToPassRoots;
|
|
|
|
|
|
|
|
if ( roots == null || roots.Length == 0 )
|
|
|
|
{
|
|
|
|
roots = [ this ];
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( var n in roots )
|
|
|
|
{
|
|
|
|
if ( n is Control c )
|
|
|
|
{
|
|
|
|
if ( c.MouseFilter == MouseFilterEnum.Stop )
|
|
|
|
{
|
|
|
|
c.MouseFilter = MouseFilterEnum.Pass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n.ForEach<Control>(
|
|
|
|
( c )=>
|
|
|
|
{
|
|
|
|
if ( c.MouseFilter == MouseFilterEnum.Stop )
|
|
|
|
{
|
|
|
|
c.MouseFilter = MouseFilterEnum.Pass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 cachedSize;
|
|
|
|
|
|
|
|
public static UI Get( Control c )
|
|
|
|
{
|
|
|
|
return UIHolder.GetUI( c );
|
|
|
|
}
|
|
|
|
|
2025-06-23 11:16:01 +00:00
|
|
|
|
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
public static UIStylePropertyContainer GetStylePropertyContainerParent( Control c )
|
|
|
|
{
|
|
|
|
var it = c as Node;
|
|
|
|
var walker = NodesWalker.Get();
|
|
|
|
|
|
|
|
it = walker.Parent( it );
|
|
|
|
|
|
|
|
if ( it is UI )
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( it != null )
|
|
|
|
{
|
|
|
|
if ( it is UIStylePropertyContainer )
|
|
|
|
{
|
|
|
|
return it as UIStylePropertyContainer;
|
|
|
|
}
|
|
|
|
|
|
|
|
it = walker.Parent( it );
|
|
|
|
|
|
|
|
if ( it is UI )
|
|
|
|
{
|
|
|
|
it = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static TimeLine GetTimeLine( Control c, TimeLine timeLine )
|
|
|
|
{
|
|
|
|
if ( timeLine != null )
|
|
|
|
{
|
|
|
|
return timeLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
var ui = Get( c );
|
|
|
|
|
|
|
|
if ( ui == null || ui.settings == null )
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ui.settings.defaultTimeline;
|
|
|
|
}
|
|
|
|
|
2025-06-23 11:16:01 +00:00
|
|
|
Vector2 windowSize = new Vector2();
|
|
|
|
|
|
|
|
bool _resizeFlag = false;
|
|
|
|
bool _fontSizeFlag = false;
|
|
|
|
|
|
|
|
public bool sizeChanged => _resizeFlag;
|
|
|
|
public bool fontSizeChanged => _fontSizeFlag;
|
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
public override void _Process( double delta )
|
|
|
|
{
|
2025-06-19 17:22:25 +00:00
|
|
|
if ( settings == null )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2025-06-23 11:16:01 +00:00
|
|
|
|
|
|
|
_resizeFlag = false;
|
|
|
|
_fontSizeFlag = false;
|
|
|
|
|
|
|
|
var newWindowSize = GetWindowSize();
|
|
|
|
|
|
|
|
if ( windowSize != newWindowSize )
|
|
|
|
{
|
|
|
|
_resizeFlag = true;
|
|
|
|
}
|
2025-06-19 17:22:25 +00:00
|
|
|
|
|
|
|
if ( useParentSize )
|
|
|
|
{
|
|
|
|
var parentSize = GetParent<Control>().Size;
|
|
|
|
|
|
|
|
if ( parentSize != cachedSize )
|
|
|
|
{
|
|
|
|
Size = parentSize;
|
|
|
|
cachedSize = parentSize;
|
2025-06-23 11:16:01 +00:00
|
|
|
_resizeFlag = true;
|
2025-06-19 17:22:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
onProcess.DispatchEvent( (float)delta );
|
2024-08-09 13:52:49 +00:00
|
|
|
UpdateFontSize();
|
|
|
|
UpdateUIElements();
|
2025-06-19 17:22:25 +00:00
|
|
|
|
|
|
|
// customDisposerIDs = _customDisposers.Map( c => c.GetUID() + ":" + c.GetInfo() ).ToArray();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void UpdateExternal( float delta)
|
|
|
|
{
|
|
|
|
onProcess.DispatchEvent( delta );
|
|
|
|
UpdateFontSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
public readonly EventSlot<InputEvent> onInputEvent = new EventSlot<InputEvent>();
|
|
|
|
public readonly EventSlot<float> onProcess = new EventSlot<float>();
|
|
|
|
|
|
|
|
public override void _Input( InputEvent ie )
|
|
|
|
{
|
|
|
|
onInputEvent.DispatchEvent( ie );
|
2025-06-23 11:16:01 +00:00
|
|
|
}
|
2025-06-19 17:22:25 +00:00
|
|
|
|
|
|
|
public void BindOwnChildren()
|
|
|
|
{
|
|
|
|
BindChildrenOf( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
public void BindChildrenOf( Node node )
|
|
|
|
{
|
|
|
|
node.ForEach<UIImage>( img => img.SetUI( this ) );
|
|
|
|
node.ForEach<UIInputInfo>( info => info.SetUI( this ) );
|
|
|
|
node.ForEach<UIText>( text => text.SetUI( this ) );
|
|
|
|
node.ForEach<UIRegion>( region => region.SetUI( this ) );
|
2024-08-09 13:52:49 +00:00
|
|
|
}
|
|
|
|
|
2025-02-12 16:48:15 +00:00
|
|
|
public override void _Ready()
|
|
|
|
{
|
|
|
|
var sm = Unique<SensorManager>.Get();
|
|
|
|
|
|
|
|
if ( sm != null )
|
|
|
|
{
|
|
|
|
sm._onActiveDeviceChange.AddAction( a => UpdateUIInputs() );
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateUIInputs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateUIInputs()
|
|
|
|
{
|
|
|
|
Nodes.ForEach<UIInputInfo>( this, uii => uii.updateInfo = true );
|
|
|
|
}
|
|
|
|
|
2024-08-11 17:38:06 +00:00
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
|
|
|
|
void UpdateFontSize()
|
|
|
|
{
|
2025-06-19 17:22:25 +00:00
|
|
|
if ( settings == null )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
X_computedFontSizePixels = UINumber.Compute( this, settings.fontSize ) * fontZoom;
|
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
|
|
|
|
if ( Theme != null )
|
|
|
|
{
|
|
|
|
Theme.DefaultFontSize = Mathf.RoundToInt( X_computedFontSizePixels );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-23 11:16:01 +00:00
|
|
|
HashSet<UIStylePropertyContainerNode> _dirty = new HashSet<UIStylePropertyContainerNode>();
|
|
|
|
HashSet<UIStylePropertyContainerNode> _updated = new HashSet<UIStylePropertyContainerNode>();
|
|
|
|
|
|
|
|
public void SetDirty( UIStylePropertyContainerNode control )
|
|
|
|
{
|
|
|
|
_dirty.Add( control );
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetUpdated( UIStylePropertyContainerNode control )
|
|
|
|
{
|
|
|
|
_updated.Add( control );
|
|
|
|
}
|
|
|
|
|
2024-08-09 13:52:49 +00:00
|
|
|
void UpdateUIElements()
|
|
|
|
{
|
2025-06-23 11:16:01 +00:00
|
|
|
if ( UpdateMode.Always == updateMode )
|
2024-08-09 13:52:49 +00:00
|
|
|
{
|
2025-06-23 11:16:01 +00:00
|
|
|
UpdateAllUIRegions();
|
|
|
|
}
|
|
|
|
else if ( UpdateMode.Optimized == updateMode )
|
|
|
|
{
|
|
|
|
if ( _fontSizeFlag || _resizeFlag )
|
|
|
|
{
|
|
|
|
_dirty.Clear();
|
|
|
|
UpdateAllUIRegions();
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
UpdateUIElementsOptimized();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float time = 0;
|
|
|
|
void UpdateUIElementsOptimized()
|
|
|
|
{
|
|
|
|
var timeNow = TimeLine.osTime;
|
|
|
|
var elapsed = timeNow - time;
|
|
|
|
time = timeNow;
|
|
|
|
// this.LogInfo( Mathf.RoundToInt( elapsed * 1000f ) );
|
|
|
|
|
|
|
|
var parent = GetParent();
|
|
|
|
|
|
|
|
var sorted = new List<UIStylePropertyContainerNode>( [ .. _dirty ]);
|
|
|
|
|
|
|
|
if ( sorted.Count > 0 )
|
|
|
|
{
|
|
|
|
// this.LogInfo( "Updating:", sorted.Count );
|
|
|
|
}
|
|
|
|
|
|
|
|
_updated.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
sorted.Sort(
|
|
|
|
( a, b ) =>
|
|
|
|
{
|
|
|
|
return Mathf.RoundToInt( Mathf.Sign( a.GetUIAncestorDepth() - b.GetUIAncestorDepth() ) );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sorted.ForEach(
|
|
|
|
( s )=>
|
|
|
|
{
|
|
|
|
if ( _updated.Contains( s ) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ( s as Control).LogInfo( "Updating:", s );
|
|
|
|
|
|
|
|
UpdateElement( s );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
_updated.Clear();
|
|
|
|
|
|
|
|
_dirty.RemoveWhere( d => ! d.IsDirty() );
|
|
|
|
|
|
|
|
foreach ( var d in _dirty )
|
|
|
|
{
|
|
|
|
d.ResetDirtyFlags();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateElement( UIStylePropertyContainerNode control )
|
|
|
|
{
|
|
|
|
if ( control is UIRegion region )
|
|
|
|
{
|
|
|
|
region.Layout();
|
2024-08-09 13:52:49 +00:00
|
|
|
}
|
2025-06-23 11:16:01 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
UILayouting.UpdateChild( control as Control );
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-06-23 11:16:01 +00:00
|
|
|
if ( UIStyle.Position( control ) == UIPosition.From_Layout )
|
|
|
|
{
|
|
|
|
UILayouting.SetPositionInParentAnchor( control );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
}
|
2024-08-09 13:52:49 +00:00
|
|
|
|
2025-06-19 17:22:25 +00:00
|
|
|
public void UpdateAllUIRegions()
|
|
|
|
{
|
2024-08-09 13:52:49 +00:00
|
|
|
Nodes.ForEachDirectChild<UIRegion>( this, r => r.Layout() );
|
|
|
|
}
|
|
|
|
|
2024-08-11 17:38:06 +00:00
|
|
|
public static float GetWindowWidth( Control control )
|
|
|
|
{
|
|
|
|
if ( Engine.IsEditorHint() )
|
|
|
|
{
|
|
|
|
return ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return control.GetWindow().Size.X;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static float GetWindowHeight( Control control )
|
|
|
|
{
|
|
|
|
if ( Engine.IsEditorHint() )
|
|
|
|
{
|
|
|
|
return ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return control.GetWindow().Size.Y;
|
|
|
|
}
|
|
|
|
}
|
2025-06-23 11:16:01 +00:00
|
|
|
|
|
|
|
public Vector2 GetWindowSize()
|
|
|
|
{
|
|
|
|
if ( Engine.IsEditorHint() )
|
|
|
|
{
|
|
|
|
var width = ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32();
|
|
|
|
var height = ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32();
|
|
|
|
|
|
|
|
return new Vector2( width, height );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return GetWindow().Size;
|
|
|
|
}
|
|
|
|
}
|
2024-08-09 13:52:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|