diff --git a/Runtime/Actions/Node3D/CopyPose.cs b/Runtime/Actions/Node3D/CopyPose.cs index 0e560a4..ac21706 100644 --- a/Runtime/Actions/Node3D/CopyPose.cs +++ b/Runtime/Actions/Node3D/CopyPose.cs @@ -13,11 +13,13 @@ namespace Rokojori [Export] public Node3D target; + [Export] + public bool global = true; - public override void _Process( double delta ) - { - _OnTrigger(); - } + // public override void _Process( double delta ) + // { + // _OnTrigger(); + // } protected override void _OnTrigger() @@ -27,8 +29,17 @@ namespace Rokojori return; } - target.GlobalPosition = source.GlobalPosition; - target.GlobalRotation = source.GlobalRotation; + if ( global ) + { + target.GlobalPosition = source.GlobalPosition; + target.GlobalRotation = source.GlobalRotation; + } + else + { + target.Position = source.Position; + target.Rotation = source.Rotation; + } + } } } \ No newline at end of file diff --git a/Runtime/Actions/Node3D/CopyPosition.cs b/Runtime/Actions/Node3D/CopyPosition.cs index af6757c..677ce2e 100644 --- a/Runtime/Actions/Node3D/CopyPosition.cs +++ b/Runtime/Actions/Node3D/CopyPosition.cs @@ -13,11 +13,14 @@ namespace Rokojori [Export] public Node3D target; + [Export] + public bool global = true; - public override void _Process( double delta ) - { - _OnTrigger(); - } + + // public override void _Process( double delta ) + // { + // _OnTrigger(); + // } protected override void _OnTrigger() { @@ -26,7 +29,14 @@ namespace Rokojori return; } - target.GlobalPosition = source.GlobalPosition; + if ( global ) + { + target.GlobalPosition = source.GlobalPosition; + } + else + { + target.Position = source.Position; + } } } } \ No newline at end of file diff --git a/Runtime/Actions/Node3D/CopyRotation.cs b/Runtime/Actions/Node3D/CopyRotation.cs new file mode 100644 index 0000000..c8a9068 --- /dev/null +++ b/Runtime/Actions/Node3D/CopyRotation.cs @@ -0,0 +1,39 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Tool ] + public partial class CopyRotation : Action + { + [Export] + public Node3D source; + + [Export] + public Node3D target; + + [Export] + public bool global = true; + + + protected override void _OnTrigger() + { + if ( source == null || target == null ) + { + return; + } + + + if ( global ) + { + target.GlobalRotation = source.GlobalRotation; + } + else + { + target.Rotation = source.Rotation; + } + + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/CopyRotation.cs.uid b/Runtime/Actions/Node3D/CopyRotation.cs.uid new file mode 100644 index 0000000..c3cc9db --- /dev/null +++ b/Runtime/Actions/Node3D/CopyRotation.cs.uid @@ -0,0 +1 @@ +uid://b721xxo48pogv diff --git a/Runtime/Graphs/Trees/TreeWalker.cs b/Runtime/Graphs/Trees/TreeWalker.cs index 3d214cf..5e66a57 100644 --- a/Runtime/Graphs/Trees/TreeWalker.cs +++ b/Runtime/Graphs/Trees/TreeWalker.cs @@ -354,6 +354,35 @@ namespace Rokojori return null; } + public int GetAncestorDistance( N child, N ancestor ) + { + if ( ancestor == null ) + { + return -1; + } + + if ( child == ancestor ) + { + return 0; + } + + + var p = Parent( child ); + var distance = 1; + + while ( p != null ) + { + if ( p == ancestor ) + { + return distance; + } + + p = Parent( p ); + distance ++; + } + + return -1; + } public int GetDepth( N node, Dictionary depthMap = null ) { diff --git a/Runtime/Interactions/CharacterController/CharacterController.cs b/Runtime/Interactions/CharacterController/CharacterController.cs index f359865..1d0737b 100644 --- a/Runtime/Interactions/CharacterController/CharacterController.cs +++ b/Runtime/Interactions/CharacterController/CharacterController.cs @@ -39,7 +39,7 @@ namespace Rokojori public override void _Process( double delta ) { - if ( graphics == null || body == null ) + if ( Engine.IsEditorHint() || graphics == null || body == null ) { return; } diff --git a/Runtime/Interactions/MultiRayCaster.cs b/Runtime/Interactions/MultiRayCaster.cs index 038c662..3f6cd91 100644 --- a/Runtime/Interactions/MultiRayCaster.cs +++ b/Runtime/Interactions/MultiRayCaster.cs @@ -9,6 +9,12 @@ namespace Rokojori [GlobalClass] public partial class MultiRayCaster:Caster { + public enum UpdateMode + { + Process, + Physics_Process + } + [Export] public float rayLength = 10; @@ -27,6 +33,9 @@ namespace Rokojori [Export] public Node collider; + [Export] + public UpdateMode updateMode = UpdateMode.Physics_Process; + public override int NumColliders() { return numCollisions; @@ -55,8 +64,35 @@ namespace Rokojori PhysicsRayQueryParameters3D rayParameters = new PhysicsRayQueryParameters3D(); + public override void _PhysicsProcess (double delta ) + { + if ( UpdateMode.Physics_Process != updateMode ) + { + return; + } + + Update( delta ); + } + public override void _Process( double delta ) { + if ( UpdateMode.Process != updateMode ) + { + return; + } + + Update( delta ); + + } + + void Update( double delta ) + { + if ( Engine.IsEditorHint() ) + { + return; + + } + Action.Trigger( beforeProcess ); ResolveCollisions(); @@ -72,8 +108,7 @@ namespace Rokojori } Action.Trigger( afterProcess ); - - } + } ValueSorter singleSorter; MultiValueSorter multiSorter; diff --git a/Runtime/Procedural/Mesh/MassRenderer.cs b/Runtime/Procedural/Mesh/MassRenderer.cs index 33bccb3..2a2fb10 100644 --- a/Runtime/Procedural/Mesh/MassRenderer.cs +++ b/Runtime/Procedural/Mesh/MassRenderer.cs @@ -29,6 +29,9 @@ namespace Rokojori [Export] public Mesh mesh; + [Export] + public GeometryInstance3D.ShadowCastingSetting castShadows = GeometryInstance3D.ShadowCastingSetting.On; + [Export] public Material materialOveride; @@ -50,10 +53,16 @@ namespace Rokojori public float multiMeshSplitSize = 25; [Export] - public Vector3 multiMeshSplitScatterRelative = new Vector3( 2, 0, 2 ); + public float cullDistance = 100; [Export] - public Vector3 multiMeshSplitScatterScale = new Vector3( 10, 10, 10 ); + public float cullRange = 50; + + [Export] + public Vector3 multiMeshSplitNoiseAmount = new Vector3( 2, 0, 2 ); + + [Export] + public Vector3 multiMeshSplitNoiseFrequency = new Vector3( 10, 10, 10 ); Dictionary multiMeshMapping = new Dictionary(); @@ -160,10 +169,12 @@ namespace Rokojori var instancesSorted = new MapList(); + + for ( int i = 0; i < positions.Length; i++ ) { var floatIndex = ( positions[ i ] / multiMeshSplitSize ); - floatIndex += Noise.Perlin3( positions[ i ] * multiMeshSplitScatterScale ) * multiMeshSplitScatterRelative; + floatIndex += Noise.Perlin3( positions[ i ] * multiMeshSplitNoiseFrequency ) * multiMeshSplitNoiseAmount; var index = floatIndex.RoundToInt(); instancesSorted.Add( index, i ); @@ -177,6 +188,10 @@ namespace Rokojori for ( int i = 0; i < numMultiMeshes; i++ ) { var multiMeshNode = this.CreateChild(); + var center = new Vector3( keys[ i ].X, keys[ i ].Y, keys[ i ].Z ) * multiMeshSplitSize; + multiMeshNode.GlobalPosition = center; + multiMeshNode.cullDistance = cullDistance; + multiMeshNode.cullRange = cullRange; multiMeshNode.Multimesh = new MultiMesh(); multiMeshNode.Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D; @@ -186,6 +201,7 @@ namespace Rokojori var meshIndices = instancesSorted[ keys[ i ] ]; mm.Mesh = mesh; + multiMeshNode.CastShadow = castShadows; mm.InstanceCount = meshIndices.Count; if ( materialOveride != null ) @@ -193,12 +209,12 @@ namespace Rokojori multiMeshNode.MaterialOverride = materialOveride; } - this.LogInfo( i, ">>", keys[ i ], ">>", meshIndices.Count ); + // this.LogInfo( i, ">>", keys[ i ], ">>", meshIndices.Count ); for ( int j = 0; j < meshIndices.Count; j++ ) { var index = meshIndices[ j ]; - var trsf = Math3D.TRS( positions[ index ], rotations[ index ], scales[ index ] ); + var trsf = Math3D.TRS( positions[ index ] - center, rotations[ index ], scales[ index ] ); mm.SetInstanceTransform( j, trsf ); } diff --git a/Runtime/Procedural/Mesh/MaterialType.cs b/Runtime/Procedural/Mesh/MaterialType.cs index e5a9be8..d66d4d7 100644 --- a/Runtime/Procedural/Mesh/MaterialType.cs +++ b/Runtime/Procedural/Mesh/MaterialType.cs @@ -10,6 +10,7 @@ namespace Rokojori public class MaterialType { public Trillean isStandard = Trillean.Any; + public Shader shader = null; public BaseMaterial3D.TransparencyEnum transparency; public BaseMaterial3D.BlendModeEnum blendMode; public BaseMaterial3D.CullModeEnum cullMode; @@ -24,12 +25,18 @@ namespace Rokojori public bool Equals( MaterialType materialType ) - { + { + if ( isStandard != materialType.isStandard ) { return false; } + if ( Trillean.False == isStandard ) + { + return shader == materialType.shader; + } + if ( transparency != materialType.transparency ) { return false; @@ -161,6 +168,8 @@ namespace Rokojori { isStandard = materialType.isStandard; + shader = materialType.shader; + transparency = materialType.transparency; blendMode = materialType.blendMode; cullMode = materialType.cullMode; @@ -186,7 +195,33 @@ namespace Rokojori return From( sm ); } - return null; + + return From( material as ShaderMaterial ); + } + + public static MaterialType From( ShaderMaterial shaderMaterial ) + { + var mt = new MaterialType(); + + mt.isStandard = Trillean.False; + mt.shader = shaderMaterial.Shader; + + // public (?:\w+\.)?\w+ (\w+).*?; + // mt.$1 = standardMaterial3D.$1; + + // mt.transparency = standardMaterial3D.; + // mt.blendMode = standardMaterial3D.BlendMode; + // mt.cullMode = standardMaterial3D.CullMode; + // mt.depthDrawMode = standardMaterial3D.DepthDrawMode; + // mt.noDepthTest = standardMaterial3D.NoDepthTest; + + // mt.shadingMode = standardMaterial3D.ShadingMode; + // mt.diffuseMode = standardMaterial3D.DiffuseMode; + // mt.specularMode = standardMaterial3D.SpecularMode; + // mt.disableAmbientLight = standardMaterial3D.DisableAmbientLight; + // mt.disableFog = standardMaterial3D.DisableFog; + + return mt; } public static MaterialType From( StandardMaterial3D standardMaterial3D ) diff --git a/Runtime/Procedural/Mesh/MeshCombiner.cs b/Runtime/Procedural/Mesh/MeshCombiner.cs index d3a720f..99d7def 100644 --- a/Runtime/Procedural/Mesh/MeshCombiner.cs +++ b/Runtime/Procedural/Mesh/MeshCombiner.cs @@ -34,6 +34,22 @@ namespace Rokojori [Export] public Node3D pivot; + public enum SortMode + { + No_Sorting, + Sort_By_Pivot_Distance, + Randomize + } + + [Export] + public SortMode sortMode = SortMode.No_Sorting; + + [Export] + public bool reverseSortOrder = false; + + [Export] + public int randomSortSeed = 1234; + [ExportGroup( "Material")] [Export] public bool combineMaterials = true; @@ -72,7 +88,18 @@ namespace Rokojori { if ( ! _meshGeometryCache.Has( surface.mesh, surface.index ) ) { - var mg = MeshGeometry.From( surface.mesh as ArrayMesh, null, surface.index ); + // var arrayMesh = surface.mesh as ArrayMesh; + + // if ( arrayMesh == null ) + // { + // arrayMesh = new ArrayMesh(); + // var st = new SurfaceTool(); + // st.Begin( Mesh.PrimitiveType.Triangles ); + // st.CreateFrom( surface.mesh, surface.index ); + // st.Commit( arrayMesh ); + // } + + var mg = MeshGeometry.From( surface.mesh, null, surface.index ); _meshGeometryCache.Set( surface.mesh, surface.index, mg ); this.LogInfo( "Created mesh with triangles:", mg.numTriangles ); @@ -132,6 +159,8 @@ namespace Rokojori { MeshExtractor.ExtractSurfacesInHierarchy( n, _surfaces ); } + + this.LogInfo( "Surfaces found:", _surfaces.Count ); } async Task GrabMaterials() @@ -369,6 +398,42 @@ namespace Rokojori var surfaces = _materiaList[ m ]; + if ( SortMode.Sort_By_Pivot_Distance == sortMode ) + { + var center = pivot == null ? Vector3.Zero : pivot.GlobalPosition; + surfaces.Sort( + ( a, b )=> + { + var distanceA = ( a.transform.Origin - center ).LengthSquared(); + var distanceB = ( b.transform.Origin - center ).LengthSquared(); + + return Mathf.Sign( distanceA - distanceB ); + } + ); + } + + if ( SortMode.Randomize == sortMode ) + { + var random = LCG.WithSeed( randomSortSeed ); + var randomValues = new Dictionary,float>(); + surfaces.ForEach( s => randomValues[ s ] = random.Next() ); + + surfaces.Sort( + ( a, b )=> + { + var distanceA = randomValues[ a ]; + var distanceB = randomValues[ b ]; + + return Mathf.Sign( distanceA - distanceB ); + } + ); + } + + if ( reverseSortOrder ) + { + surfaces.Reverse(); + } + this.LogInfo( "Combining for Material", "combined?:",isCombinedMaterial,"material:", usedMaterial, surfaces.Count, "meshes" ); var meshGeometry = new MeshGeometry(); @@ -466,12 +531,10 @@ namespace Rokojori if ( combineMeshes ) { - if ( outputMesh == null ) - { - this.LogInfo( "Created outputMesh"); - outputMesh = this.CreateChild(); - } + outputMesh = null; + this.DestroyChildren(); + outputMesh = this.CreateChild(); outputMesh.Mesh = arrayMesh; } diff --git a/Runtime/Procedural/Mesh/MeshGeometry.cs b/Runtime/Procedural/Mesh/MeshGeometry.cs index 2f679d0..c6c98fa 100644 --- a/Runtime/Procedural/Mesh/MeshGeometry.cs +++ b/Runtime/Procedural/Mesh/MeshGeometry.cs @@ -285,10 +285,32 @@ namespace Rokojori return From( (ArrayMesh)meshInstance3D.Mesh, meshInstance3D.GlobalTransform ); } + public static MeshGeometry From( Mesh mesh, Transform3D? trsf = null, int index = 0 ) + { + var arrayMesh = mesh as ArrayMesh; + + if ( arrayMesh == null ) + { + arrayMesh = new ArrayMesh(); + var st = new SurfaceTool(); + st.Begin( Mesh.PrimitiveType.Triangles ); + st.CreateFrom( mesh, index ); + st.Commit( arrayMesh ); + } + + return From( arrayMesh, trsf, 0 ); + } + public static MeshGeometry From( ArrayMesh mesh, Transform3D? trsf = null, int index = 0 ) { + var mg = new MeshGeometry(); + if ( mesh == null ) + { + return mg; + } + var arrays = mesh.SurfaceGetArrays( index ); var vertices = arrays[ (int) Mesh.ArrayType.Vertex ]; diff --git a/Runtime/Procedural/Scatter/Generators/GeneratorEntry.cs b/Runtime/Procedural/Scatter/Generators/GeneratorEntry.cs index 6027d2d..2a67ed2 100644 --- a/Runtime/Procedural/Scatter/Generators/GeneratorEntry.cs +++ b/Runtime/Procedural/Scatter/Generators/GeneratorEntry.cs @@ -23,12 +23,30 @@ namespace Rokojori [Export] public bool getMeshInstanceChild = false; + [ExportGroup("Instancing")] [Export] public bool useInstancing = false; + [Export] + public float instancingCullDistance = 1000; + + [Export] + public float instancingCullRange = 500; + [Export] public float instancingSplitSize = 25; + [Export] + public Vector3 instancingSplitScatterNoiseAmount = Vector3.Zero; + + [Export] + public Vector3 instancingSplitScatterNoiseFrequency = Vector3.Zero; + + + + + [ExportGroup("")] + protected PackedScene _cachedNode3DScene; public PackedScene GetPackedScene() diff --git a/Runtime/Procedural/Scatter/Generators/GeneratorScatterer.cs b/Runtime/Procedural/Scatter/Generators/GeneratorScatterer.cs index 43bae04..efb8083 100644 --- a/Runtime/Procedural/Scatter/Generators/GeneratorScatterer.cs +++ b/Runtime/Procedural/Scatter/Generators/GeneratorScatterer.cs @@ -64,6 +64,17 @@ namespace Rokojori p.parent = gs.container != null ? gs.container : container; p.instanced = gs.useInstancing; p.instanceSplitSize = gs.instancingSplitSize; + p.instancingSplitScatterNoiseAmount = gs.instancingSplitScatterNoiseAmount; + p.instancingSplitScatterNoiseFrequency = gs.instancingSplitScatterNoiseFrequency; + p.instanceCullDistance = gs.instancingCullDistance; + p.instanceCullRange = gs.instancingCullRange; + + if ( gs.node3D != null && gs.node3D is MeshInstance3D mi ) + { + p.shadowCasting = mi.CastShadow; + } + + } } diff --git a/Runtime/Procedural/Scatter/ScatterPoint.cs b/Runtime/Procedural/Scatter/ScatterPoint.cs index 796a9da..203cdd4 100644 --- a/Runtime/Procedural/Scatter/ScatterPoint.cs +++ b/Runtime/Procedural/Scatter/ScatterPoint.cs @@ -10,7 +10,15 @@ namespace Rokojori public class ScatterPoint:PointData { public bool instanced = false; + + public float instanceCullDistance = 200; + public float instanceCullRange = 100; + public float instanceSplitSize = 25; + public Vector3 instancingSplitScatterNoiseAmount = Vector3.Zero; + public Vector3 instancingSplitScatterNoiseFrequency = Vector3.Zero; + + public GeometryInstance3D.ShadowCastingSetting shadowCasting = GeometryInstance3D.ShadowCastingSetting.On; protected Scatterer _creator; public Scatterer creator => _creator; protected int _creatorID; diff --git a/Runtime/Procedural/Scatter/Scatterer.cs b/Runtime/Procedural/Scatter/Scatterer.cs index b43a80e..4954c40 100644 --- a/Runtime/Procedural/Scatter/Scatterer.cs +++ b/Runtime/Procedural/Scatter/Scatterer.cs @@ -344,6 +344,11 @@ namespace Rokojori c.materialOveride = mwm.material; c.mesh = mwm.mesh; c.multiMeshSplitSize = sp.instanceSplitSize; + c.multiMeshSplitNoiseAmount = sp.instancingSplitScatterNoiseAmount; + c.multiMeshSplitNoiseFrequency = sp.instancingSplitScatterNoiseFrequency; + c.cullDistance = sp.instanceCullDistance; + c.cullRange = sp.instanceCullRange; + c.castShadows = sp.shadowCasting; _instancedMassRenderers.Add( mwm.mesh, c ); diff --git a/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs b/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs index c6727c3..90bfb63 100644 --- a/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs +++ b/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs @@ -27,6 +27,10 @@ namespace Rokojori [Export] public Vector3 positionNoiseOffset = Vector3.Zero; + [Export] + public Vector3 staticOffset = Vector3.Zero; + + [ExportGroup( "Rotation" )] [Export] public Vector3 rotationOffset = Vector3.Zero; @@ -75,7 +79,7 @@ namespace Rokojori var scaleRandom = Noise.Perlin3( scalePerlin ); var uniformScaleRandom = Noise.Perlin( scalePerlin + new Vector3( 100002, -10002, 1000 ) ); - p.position += positionOffset * positionRandom * positionOffsetScale; + p.position += positionOffset * positionRandom * positionOffsetScale + staticOffset; p.rotation *= Quaternion.FromEuler( rotationOffset * MathX.DegreesToRadians * rotationRandom * rotationOffsetScale ); diff --git a/Runtime/Random/RandomEngine.cs b/Runtime/Random/RandomEngine.cs index ad1db3f..a2deca0 100644 --- a/Runtime/Random/RandomEngine.cs +++ b/Runtime/Random/RandomEngine.cs @@ -252,6 +252,18 @@ namespace Rokojori return list[ index ]; } + public T From( List list, int start, int end ) + { + if ( list.Count == 0 ) + { + return default ( T ); + } + + var index = this.IntegerInclusive( start, end ); + + return list[ index ]; + } + public T RemoveFrom( List list ) { if ( list.Count == 0 ) diff --git a/Runtime/Sensors/SensorManager.cs b/Runtime/Sensors/SensorManager.cs index 3c7d9cc..c33cadf 100644 --- a/Runtime/Sensors/SensorManager.cs +++ b/Runtime/Sensors/SensorManager.cs @@ -229,6 +229,11 @@ namespace Rokojori } //this.LogInfo( "Register", s ); + if ( ! sensorToRunner.ContainsKey( s ) ) + { + return; + } + var sensorRunner = sensorToRunner[ s ]; if ( sensorRunner.listeners.Contains( sih ) ) @@ -337,6 +342,28 @@ namespace Rokojori HashSet _scannedObjects = new HashSet(); + + bool IsIgnoreType( object obj ) + { + var ignoreTypes = new List() + { + typeof( GpuParticles3D ), + typeof( MeshInstance3D ), + typeof( Node3D ), + typeof( CollisionShape3D ), + typeof( OmniLight3D ), + typeof( DirectionalLight3D ), + typeof( WorldEnvironment ), + typeof( Area3D ), + typeof( CharacterBody3D ), + typeof( AudioStreamPlayer3D ), + typeof( ReflectionProbe ) + }; + + + return ignoreTypes.IndexOf( obj.GetType() ) != -1; + } + void AddSensorsFrom( object obj ) { if ( Engine.IsEditorHint() ) @@ -345,52 +372,68 @@ namespace Rokojori } //this.LogInfo( "AddSensorsFrom", obj ); - - if ( obj == null || _scannedObjects.Contains( obj ) ) - { - return; - } - - _scannedObjects.Add( obj ); - - - var sensors = ReflectionHelper.GetDataMemberValues( obj ); - - if ( sensors.Count > 0 ) - { - if ( obj is Node n ) - { - n.LogInfo( sensors ); - } - else if ( obj is Resource r ) - { - r.LogInfo( sensors ); - } - } + try + { - sensors.ForEach( - s => + if ( obj == null || _scannedObjects.Contains( obj ) ) { - AddSensor( s ); + return; } - ); - var sensorArrays = ReflectionHelper.GetDataMemberValues( obj ); + + _scannedObjects.Add( obj ); - sensorArrays.ForEach( - s => + if ( IsIgnoreType( obj ) ) { - for ( int i = 0; i < s.Length; i++ ) + return; + } + + + + var sensors = ReflectionHelper.GetDataMemberValues( obj ); + + if ( sensors.Count > 0 ) + { + if ( obj is Node n ) { - AddSensor( s[ i ] ); + n.LogInfo( sensors ); + } + else if ( obj is Resource r ) + { + r.LogInfo( sensors ); } } - ); + - var resources = ReflectionHelper.GetDataMemberValues( obj ); + sensors.ForEach( + s => + { + AddSensor( s ); + } + ); - resources.ForEach( r => AddSensorsFrom( r ) ); + var sensorArrays = ReflectionHelper.GetDataMemberValues( obj ); + + sensorArrays.ForEach( + s => + { + for ( int i = 0; i < s.Length; i++ ) + { + AddSensor( s[ i ] ); + } + } + ); + + var resources = ReflectionHelper.GetDataMemberValues( obj ); + + resources.ForEach( r => AddSensorsFrom( r ) ); + + } + catch( System.Exception e ) + { + this.LogError( e ); + } } void CreateRunners() diff --git a/Runtime/Testing/CheckWarnings.cs b/Runtime/Testing/CheckWarnings.cs index f7811c9..f21579e 100644 --- a/Runtime/Testing/CheckWarnings.cs +++ b/Runtime/Testing/CheckWarnings.cs @@ -30,7 +30,7 @@ namespace Rokojori roots.ForEach( ( r )=> { - Nodes.ForEach( r, n => CheckWarningsOf( n ) ); + Nodes.ForEach( r, n => CheckWarningsOf( n ) ); } ); diff --git a/Runtime/Time/DateTime/DateMath.cs b/Runtime/Time/DateTime/DateMath.cs index e187b1b..2eab84c 100644 --- a/Runtime/Time/DateTime/DateMath.cs +++ b/Runtime/Time/DateTime/DateMath.cs @@ -10,6 +10,8 @@ namespace Rokojori { public static class DateMath { + + public static float GetDifference( this DateTime a, DateTime b ) { return (float) ( ( a - b ).TotalSeconds ); diff --git a/Runtime/Time/TimeLine.cs b/Runtime/Time/TimeLine.cs index 8aca404..b1225cd 100644 --- a/Runtime/Time/TimeLine.cs +++ b/Runtime/Time/TimeLine.cs @@ -27,6 +27,7 @@ namespace Rokojori [Export] public bool autoStart = true; + public static float osTime => (float)( Time.GetTicksMsec() / 1000.0 ); public TimeLineRunner runner { diff --git a/Runtime/Tools/Lists.cs b/Runtime/Tools/Lists.cs index 5753d85..3841a15 100644 --- a/Runtime/Tools/Lists.cs +++ b/Runtime/Tools/Lists.cs @@ -605,6 +605,42 @@ namespace Rokojori return copy; } + public static bool Has( this List list, Func evaluater ) + { + foreach ( var t in list ) + { + if ( evaluater( t ) ) + { + return true; + } + } + + return false; + } + + public static void SwapTowardsBegin( this List list, int index, int steps = 1 ) + { + list.Swap( index, index - steps ); + } + + public static void SwapTowardsEnd( this List list, int index, int steps = 1 ) + { + list.Swap( index, index + steps ); + } + + public static void Swap( this List list, int indexA, int indexB ) + { + if ( list == null || indexA == indexB || indexA < 0 || indexB < 0 || indexA >= list.Count || indexA >= list.Count ) + { + return; + } + + var buffer = list[ indexA ]; + list[ indexA ] = list[ indexB ]; + list[ indexB ] = buffer; + + } + public static List FilterAndMap( List list, Func filter, Func map) { var mapped = new List(); diff --git a/Runtime/UI/Components/UIDragging.cs b/Runtime/UI/Components/UIDragging.cs index f12a23f..6bc0d40 100644 --- a/Runtime/UI/Components/UIDragging.cs +++ b/Runtime/UI/Components/UIDragging.cs @@ -8,6 +8,18 @@ namespace Rokojori { public class UIDragging { + public class MappedEvent + { + public MouseButton mouseButton; + public EditableUIDraggingEvent uiEvent; + } + + public class ButtonState + { + public MouseButton mouseButton; + public bool dragging; + } + public class UIDraggingCallbacks: ICustomDisposer { public UI ui; @@ -15,13 +27,23 @@ namespace Rokojori public bool wasDisposed = false; + public bool notValid => + wasDisposed || + onMouseClick == null || + onDragging == null || + onProcess == null || + mouseEvents == null || mouseEvents.FilterNulls().Count == 0 || + mouseEventsDragging == null || mouseEventsDragging.FilterNulls().Count == 0; + public Action onMouseClick; public Callable callable; public Action onDragging; public Action onProcess; - public Dictionary mouseEvents = new Dictionary(); - - public Dictionary mouseEventsDragging = new Dictionary(); + // public Dictionary mouseEvents = new Dictionary(); + + public List mouseEvents = new List(); + public List mouseEventsDragging = new List(); + // public Dictionary mouseEventsDragging = new Dictionary(); public string uid = IDGenerator.GenerateID(); public string GetUID(){ return uid; } @@ -42,10 +64,16 @@ namespace Rokojori callbacks.onProcess = (float delta )=> { - foreach ( var m in callbacks.mouseEvents ) - { - callback( callbacks.mouseEvents[ m.Key ] ); - } + callbacks.mouseEvents.ForEach( + ( m )=> + { + callback( m.uiEvent ); + } + ); + // foreach ( var m in callbacks.mouseEvents ) + // { + // callback( callbacks.mouseEvents[ m.Key ] ); + // } }; callbacks.onDragging = ( InputEvent ie ) => @@ -53,11 +81,13 @@ namespace Rokojori if ( ie is InputEventMouseButton mb && ! mb.Pressed ) { - callbacks.mouseEventsDragging[ mb.ButtonIndex ] = false; + var mdIndex = callbacks.mouseEventsDragging.FindIndex( me => me.mouseButton == mb.ButtonIndex ); + var meIndex = callbacks.mouseEvents.FindIndex( md => md.mouseButton == mb.ButtonIndex ); + callbacks.mouseEventsDragging[ mdIndex ].dragging = false; - callbacks.mouseEvents[ mb.ButtonIndex ].UpdatePosition( mb.GlobalPosition, true ); + callbacks.mouseEvents[ meIndex ].uiEvent.UpdatePosition( mb.GlobalPosition, true ); - callback( callbacks.mouseEvents[ mb.ButtonIndex ] ); + callback( callbacks.mouseEvents[ meIndex ].uiEvent ); if ( ! callbacks.hasAnyMouseDragging ) { @@ -76,11 +106,18 @@ namespace Rokojori { var globalPosition = mo.GlobalPosition; - foreach ( var m in callbacks.mouseEvents ) + // foreach ( var m in callbacks.mouseEvents ) + // { + // callbacks.mouseEvents[ m.Key ].UpdatePosition( globalPosition ); + // // callback( callbacks.mouseEvents[ m.Key ] ); + // } + + callbacks.mouseEvents.ForEach( + ( m )=> { - callbacks.mouseEvents[ m.Key ].UpdatePosition( globalPosition ); - // callback( callbacks.mouseEvents[ m.Key ] ); + m.uiEvent.UpdatePosition( globalPosition ); } + ); } @@ -111,7 +148,19 @@ namespace Rokojori { sc.GetUISelectorFlags().AddIfNotPresent( UISelectorFlag.Dragging ); } - callbacks.mouseEventsDragging[ button ] = true; + + var buttonIndex = callbacks.mouseEventsDragging.FindIndex( bs => bs.mouseButton == button ); + + if ( buttonIndex == -1 ) + { + var bs = new ButtonState(); + bs.mouseButton = button; + callbacks.mouseEventsDragging.Add( bs ); + buttonIndex = callbacks.mouseEventsDragging.Count - 1; + + } + + callbacks.mouseEventsDragging[ buttonIndex ].dragging = true; if ( ! callbacks.hasDraggingCallback ) { @@ -162,7 +211,7 @@ namespace Rokojori { foreach ( var mb in mouseEventsDragging ) { - if ( mb.Value ) + if ( mb.dragging ) { return true; } @@ -177,14 +226,20 @@ namespace Rokojori public EditableUIDraggingEvent GetMouseEvent( MouseButton mb ) { - if ( ! mouseEvents.ContainsKey( mb ) ) + var index = mouseEvents.FindIndex( m => m.mouseButton == mb ); + + if ( index == -1) { - mouseEvents[ mb ] = new EditableUIDraggingEvent( mb ); + var mappedEvent = new MappedEvent(); + mappedEvent.mouseButton = mb; + mappedEvent.uiEvent = new EditableUIDraggingEvent( mb ); + mouseEvents.Add( mappedEvent ); + index = mouseEvents.Count - 1; } - mouseEvents[ mb ].SetUI( ui ); + mouseEvents[ index ].uiEvent.SetUI( ui ); - return mouseEvents[ mb ]; + return mouseEvents[ index ].uiEvent; } public void Clear() diff --git a/Runtime/UI/Components/UISlider.cs b/Runtime/UI/Components/UISlider.cs index 4460363..a225ddd 100644 --- a/Runtime/UI/Components/UISlider.cs +++ b/Runtime/UI/Components/UISlider.cs @@ -121,7 +121,7 @@ namespace Rokojori ui.onProcess.AddAction( UpdatePosition ); ( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID ); - + ( button as UIStylePropertyContainerNode ).SetDirty(); } }; @@ -159,12 +159,25 @@ namespace Rokojori bool _dragging = false; bool _updatingPosition = false; - UIDragging.UIDraggingCallbacks leftMouseCallback; + UIDragging.UIDraggingCallbacks leftMouseCallbacks; + UIDragging.UIDraggingCallbacks middleMouseCallbacks; + + + public override void _Process( double delta ) + { + if ( + leftMouseCallbacks == null || leftMouseCallbacks.notValid || + middleMouseCallbacks == null || middleMouseCallbacks.notValid + ) + { + AddDraggingListener(); + } + } void AddDraggingListener() { - leftMouseCallback = UIDragging.OnLeftMouseButton( button, + leftMouseCallbacks = UIDragging.OnLeftMouseButton( button, ( ev )=> { if ( ev.isStart ) @@ -189,7 +202,7 @@ namespace Rokojori } ); - UIDragging.OnMiddleMouseButton( scrollContainer, + middleMouseCallbacks = UIDragging.OnMiddleMouseButton( scrollContainer, ( ev )=> { if ( ev.isStart ) @@ -223,10 +236,12 @@ namespace Rokojori Vector2 cachedOffset = Vector2.Zero; void UpdatePosition( float delta ) { - + // this.LogInfo( "UpdatePosition" ); var value = Smoothing.Apply( smoothing, nextValue, delta ); - var uiStyleContainer = ( UIStylePropertyContainer ) button; + var uiStyleContainer = ( UIStylePropertyContainerNode ) button; + + uiStyleContainer.SetLayoutDirtyFlag(); if ( ! _dragging && ( value - nextValue ).Length() < 1 ) { @@ -249,14 +264,15 @@ namespace Rokojori { var left = new UINumber(); left.value = value.X; - uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left ); + uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left ); + } if ( Direction.Both == direction || Direction.Vertical == direction ) { var top = new UINumber(); top.value = value.Y; - uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top ); + uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top ); } var range = background.Size - button.Size; @@ -268,18 +284,21 @@ namespace Rokojori var scrollOffset = scrollRange * sliderValue; + var scrollTargetNode = scrollTarget as UIStylePropertyContainerNode; + if ( Direction.Both == direction || Direction.Horizontal == direction ) { var left = new UINumber(); left.value = -scrollOffset.X; - ( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left ); + scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left ); } if ( Direction.Both == direction || Direction.Vertical == direction ) { var top = new UINumber(); top.value = -scrollOffset.Y; - ( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top ); + scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top ); + } } @@ -299,6 +318,7 @@ namespace Rokojori void SyncScroll() { + if ( _dragging || _updatingPosition ) { // this.LogInfo( "SyncScroll blocked" ); @@ -307,9 +327,11 @@ namespace Rokojori // this.LogInfo( "SyncScroll" ); - var uiStyleContainer = ( UIStylePropertyContainer ) button; + var uiStyleContainer = ( UIStylePropertyContainerNode ) button; var value = GetButtonScrollRange() * sliderValue; + uiStyleContainer.SetDirty(); + if ( Direction.Both == direction || Direction.Horizontal == direction ) { var left = new UINumber(); diff --git a/Runtime/UI/Layouts/UIFlowLayout.cs b/Runtime/UI/Layouts/UIFlowLayout.cs index 85b982c..1b4e1d1 100644 --- a/Runtime/UI/Layouts/UIFlowLayout.cs +++ b/Runtime/UI/Layouts/UIFlowLayout.cs @@ -135,6 +135,8 @@ namespace Rokojori UILayouting.SetPositionInParentAnchor( region ); } + region.CommitUpdateInfo(); + Nodes.ForEachDirectChild( region, child => { @@ -151,6 +153,8 @@ namespace Rokojori } ); + + region.CommitUpdateInfo(); } static List CreateLines( UIRegion region ) diff --git a/Runtime/UI/Layouts/UILayouting.cs b/Runtime/UI/Layouts/UILayouting.cs index 0c0c667..b925d15 100644 --- a/Runtime/UI/Layouts/UILayouting.cs +++ b/Runtime/UI/Layouts/UILayouting.cs @@ -34,164 +34,28 @@ namespace Rokojori return; } - if ( control is UIRegion ) + if ( control is UIRegion region ) { - var childUIRegion = (UIRegion) control; - childUIRegion.Layout(); + region.Layout(); } - else if ( control is UIImage ) + else if ( control is UIImage uiImage ) { - var tw = 0; - var th = 0; - - if ( control is UIImage ) - { - var uiImage = (UIImage) control; - - if ( uiImage.Texture == null ) - { - uiImage.Size = new Vector2( 0, 0 ); - return; - } - - tw = uiImage.Texture.GetWidth(); - th = uiImage.Texture.GetHeight(); - } - - var container = (UIStylePropertyContainer) control; - - var w = UINumber.Compute( control, UIStyleNumberProperty.Width, tw, tw / 100f ); - var h = UINumber.Compute( control, UIStyleNumberProperty.Height, th, th / 100f ); - - // RJLog.Log( "Set Image Size", w, h ); - control.Size = new Vector2( w, h ); - - if ( control is UIImage ) - { - var uiImage = (UIImage) control; - - if ( uiImage.Material != null ) - { - var ui = uiImage.GetUI(); - - if ( ui == null ) - { - RJLog.Log( "No UI Found", HierarchyName.Of( uiImage ) ); - return; - } - - if ( ui.settings == null ) - { - RJLog.Log( "No UI settings Found", HierarchyName.Of( uiImage ) ); - return; - } - - if ( ui.settings.sizePropertyName == null ) - { - // RJLog.Log( "No UI.settings.sizePropertyName Found" ); - return; - } - - //RJLog.Log( "Setting Size", ui.settings.sizePropertyName.propertyName, HierarchyName.Of( uiImage ) ); - ui.settings.sizePropertyName.Set( uiImage.Material, uiImage.Size ); - - // UIShaderProperties.UpdatePropertiesInHierarchy( uiImage, uiImage.Material ); - - var colorProperties = uiImage.imageType != null ? uiImage.imageType.GetColorShaderProperties() : []; - var colorPropertyName = new ColorPropertyName(); - foreach ( var c in colorProperties ) - { - // uiImage.LogInfo( c ); - var color = UIColor.Compute( control, UIStyleColorProperty.ColorShaderProperty, c, Colors.White ); - colorPropertyName.propertyName = c; - colorPropertyName.Set( uiImage.Material, color ); - } - - var numberProperties = uiImage.imageType != null ? uiImage.imageType.GetNumberShaderProperties() : []; - var numberPropertyName = new FloatPropertyName(); - foreach ( var n in numberProperties ) - { - // uiImage.LogInfo( c ); - var value = UINumber.Compute( control, UIStyleNumberProperty.FloatShaderProperty, n ); - numberPropertyName.propertyName = n; - numberPropertyName.Set( uiImage.Material, value ); - } - - - return; - } - - } + uiImage.Update(); + uiImage.CommitUpdateInfo(); } - else if ( control is UIText ) + else if ( control is UIText uiText ) { - var text = (UIText) control; - - var container = (UIStylePropertyContainer) control; - - text.uiTextLabelSettings.FontSize = Mathf.Max( 1, - UINumber.ComputeInt( control, UIStyleNumberProperty.FontSize, UINumber.em( control ), UINumber.em( control ) / 100f ) ); - - text.uiTextLabelSettings.FontColor = - UIColor.Compute( control, UIStyleColorProperty.FontColor, "", Colors.White ); - - text.uiTextLabelSettings.OutlineSize = - UINumber.ComputeInt( control, UIStyleNumberProperty.FontOutlineSize, 0 ); - - text.uiTextLabelSettings.OutlineColor = - UIColor.Compute( control, UIStyleColorProperty.FontOutlineColor, "", Colors.Transparent ); - - text.uiTextLabelSettings.ShadowSize = - UINumber.ComputeInt( control, UIStyleNumberProperty.FontShadowSize, 0 ); - - text.uiTextLabelSettings.ShadowColor = - UIColor.Compute( control, UIStyleColorProperty.FontShadowColor, "", Colors.Black ); - - text.uiTextLabelSettings.ShadowOffset = new Vector2( - UINumber.Compute( control, UIStyleNumberProperty.FontShadowOffsetX, 0 ), - UINumber.Compute( control, UIStyleNumberProperty.FontShadowOffsetY, 0 ) - ); - - - control.UpdateMinimumSize(); - - if ( text.alwaysMinimumSize ) - { - if ( text.AutowrapMode == TextServer.AutowrapMode.Word ) - { - text.AutowrapMode = TextServer.AutowrapMode.Off; - var minSize = text.GetMinimumSize(); - text.AutowrapMode = TextServer.AutowrapMode.Word; - - var w = UINumber.Compute( control, UIStyleNumberProperty.Width, minSize.X, minSize.X / 100f ); - var h = UINumber.Compute( control, UIStyleNumberProperty.Height, minSize.Y, minSize.Y / 100f ); - - control.CustomMinimumSize = new Vector2( Mathf.Min( minSize.X, w ), 0 ); - } - - control.Size = control.GetMinimumSize(); - } - else - { - var minSize = control.GetMinimumSize(); - - var w = UINumber.Compute( control, UIStyleNumberProperty.Width, minSize.X, minSize.X / 100f ); - var h = UINumber.Compute( control, UIStyleNumberProperty.Height, minSize.Y, minSize.Y / 100f ); - - // RJLog.Log( "Set Image Size", w, h ); - control.Size = new Vector2( w, h ); - } - + uiText.Update(); + uiText.CommitUpdateInfo(); } else { - // control.UpdateMinimumSize(); - // control.Size = control.GetMinimumSize(); + } - UILayouting.UpdatePivot( control ); + UpdatePivot( control ); } - + public static void SetPositionInParentAnchor( UIStylePropertyContainer container ) { var control = (Control) container; diff --git a/Runtime/UI/Nodes/UIHolder.cs b/Runtime/UI/Nodes/UIHolder.cs index 3a29292..8b9b0fe 100644 --- a/Runtime/UI/Nodes/UIHolder.cs +++ b/Runtime/UI/Nodes/UIHolder.cs @@ -7,8 +7,8 @@ namespace Rokojori { public interface UIHolderControl { - public void SetUI( UI ui); - public UI GetUI(); + public void SetUI( UI ui, bool computeDepth = true ); + public UI GetUI( bool computeDepth = true ); } public class UIHolder diff --git a/Runtime/UI/Nodes/UIImage.cs b/Runtime/UI/Nodes/UIImage.cs index 907cef9..6e83ec6 100644 --- a/Runtime/UI/Nodes/UIImage.cs +++ b/Runtime/UI/Nodes/UIImage.cs @@ -8,7 +8,7 @@ namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")] - public partial class UIImage:TextureRect, UIStylePropertyContainer, UIHolderControl, IAssemblyReload + public partial class UIImage:TextureRect, UIStylePropertyContainerNode, UIHolderControl, IAssemblyReload { UIImageType _imageType; [Export] @@ -33,28 +33,43 @@ namespace Rokojori UI ui; - public void SetUI( UI ui ) + public void SetUI( UI ui, bool computeDepth = true ) { this.ui = ui; + + if ( computeDepth ) + { + ComputeUIAncestorDepth(); + } + } - public UI GetUI() + public UI GetUI( bool computeDepth = true ) { - var ui = this.ui != null ? this.ui : Unique.Get(); + if ( this.ui != null ) + { + return this.ui; + } + + var ui = this.FindParentThatIs(); if ( ui == null ) { - ui = this.FindParentThatIs(); + + this._uiAncestorDepth = -1; + this.LogInfo( "No UI in parents >", ui ); - if ( ui == null ) - { - this.LogInfo( "No UI in parents >", ui ); - - return null; - } + return null; + } + if ( computeDepth ) + { + ComputeUIAncestorDepth(); + } + + return ui; } @@ -64,7 +79,7 @@ namespace Rokojori if ( _imageType != null ) { - this.LogInfo( "Assigning Image Type:", _imageType ); + // this.LogInfo( "Assigning Image Type:", _imageType ); _imageType.Assign( this ); } } @@ -76,26 +91,52 @@ namespace Rokojori MouseEntered += ()=> { AddUISelectorFlag( UISelectorFlag.Hover, hoverID ); + this.SetDirty(); }; MouseExited += ()=> { RemoveUISelectorFlag( UISelectorFlag.Hover, hoverID ); + this.SetDirty(); }; UpdateImageType(); + ComputeUIAncestorDepth(); } public override void _EnterTree() { UpdateImageType(); + ComputeUIAncestorDepth(); + } + + public override void _ExitTree() + { + _uiAncestorDepth = -1; } public void OnAssemblyReloaded() { UpdateImageType(); } + + int _uiAncestorDepth; + + public void ComputeUIAncestorDepth() + { + SetUIAncestorDepth( NodesWalker.Get().GetAncestorDistance( this, GetUI( false ) ) ); + } + + public void SetUIAncestorDepth( int depth ) + { + _uiAncestorDepth = depth; + } + + public int GetUIAncestorDepth() + { + return _uiAncestorDepth; + } void ResetImageType() { @@ -129,12 +170,23 @@ namespace Rokojori } else { - _selectorFlagReferenceCounter.Remove( flag ); + _selectorFlagReferenceCounter.Remove( flag, reference ); } + var numFlagsBefore = _selectorFlags.Count; _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList(); + + var changed = numFlagsBefore != _selectorFlags.Count; UISelector.UpdateParentUISelectorFlags( this ); + + if ( changed ) + { + // this.LogInfo( "Changed flag:", flag, reference ); + this.SetDirty(); + } + + } List _selectorFlags = []; @@ -444,6 +496,90 @@ namespace Rokojori case UIStyleNumberProperty.ScaleY: { scaleY = number; } break; } + this.SetLayoutDirtyFlag(); + + } + + 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(); + } + + + public void Update() + { + + if ( Texture == null ) + { + Size = new Vector2( 0, 0 ); + return; + } + + var tw = Texture.GetWidth(); + var th = Texture.GetHeight(); + + + var w = UINumber.Compute( this, UIStyleNumberProperty.Width, tw, tw / 100f ); + var h = UINumber.Compute( this, UIStyleNumberProperty.Height, th, th / 100f ); + + Size = new Vector2( w, h ); + + if ( Material == null ) + { + return; + } + + var ui = GetUI(); + + if ( ui == null || ui.settings == null || ui.settings.sizePropertyName == null ) + { + return; + } + + ui.settings.sizePropertyName.Set( Material, Size ); + + var colorProperties = imageType != null ? imageType.GetColorShaderProperties() : []; + var colorPropertyName = new ColorPropertyName(); + + foreach ( var c in colorProperties ) + { + var color = UIColor.Compute( this, UIStyleColorProperty.ColorShaderProperty, c, Colors.White ); + colorPropertyName.propertyName = c; + colorPropertyName.Set( Material, color ); + } + + var numberProperties = imageType != null ? imageType.GetNumberShaderProperties() : []; + var numberPropertyName = new FloatPropertyName(); + + foreach ( var n in numberProperties ) + { + var value = UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n ); + numberPropertyName.propertyName = n; + numberPropertyName.Set( Material, value ); + } + } public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source ) diff --git a/Runtime/UI/Nodes/UIRegion.cs b/Runtime/UI/Nodes/UIRegion.cs index 60116c6..132e7bb 100644 --- a/Runtime/UI/Nodes/UIRegion.cs +++ b/Runtime/UI/Nodes/UIRegion.cs @@ -7,7 +7,7 @@ namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRegion.svg")] - public partial class UIRegion : Control, UIStylePropertyContainer, UIHolderControl + public partial class UIRegion : Control, UIStylePropertyContainerNode, UIHolderControl { [Export] public UIStyle parentStyle; @@ -256,8 +256,37 @@ namespace Rokojori } + this.SetLayoutDirtyFlag(); } + 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(); + } + + public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source ) { switch ( property ) @@ -277,15 +306,44 @@ namespace Rokojori 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; + } + MapList _selectorFlagReferenceCounter = new MapList(); public void AddUISelectorFlag( UISelectorFlag flag, string reference = "" ) @@ -311,12 +369,20 @@ namespace Rokojori } else { - _selectorFlagReferenceCounter.Remove( flag ); + _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 = []; @@ -352,25 +418,37 @@ namespace Rokojori UI ui; - public void SetUI( UI ui ) + public void SetUI( UI ui, bool computeDepth = true ) { this.ui = ui; + + if ( computeDepth ) + { + ComputeUIAncestorDepth(); + } } - public UI GetUI() + public UI GetUI( bool computeDepth = true ) { - var ui = this.ui != null ? this.ui : Unique.Get(); + if ( this.ui != null ) + { + return this.ui; + } + + var ui = this.FindParentThatIs(); if ( ui == null ) { - ui = this.FindParentThatIs(); + + _uiAncestorDepth =-1; + this.LogInfo( "No UI in parents >", ui ); - if ( ui == null ) - { - this.LogInfo( "No UI in parents >", ui ); + return null; + } - return null; - } + if ( computeDepth ) + { + ComputeUIAncestorDepth(); } return ui; diff --git a/Runtime/UI/Nodes/UIText.cs b/Runtime/UI/Nodes/UIText.cs index f86bd7c..bee5d2f 100644 --- a/Runtime/UI/Nodes/UIText.cs +++ b/Runtime/UI/Nodes/UIText.cs @@ -8,7 +8,7 @@ namespace Rokojori { [Tool] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIText.svg")] - public partial class UIText:Label,UIStylePropertyContainer, iLocalizable, UIHolderControl, IAssemblyReload + public partial class UIText:Label,UIStylePropertyContainerNode, iLocalizable, UIHolderControl, IAssemblyReload { LocalizedString _locale; @@ -40,6 +40,8 @@ namespace Rokojori Text = LocalizedString.Get( _locale ); + _textDirty = true; + } public void OnAssemblyReloaded() @@ -69,6 +71,7 @@ namespace Rokojori set { _font = value; UpdateFont(); } } + [Export] public UINumber fontSize; [Export] @@ -155,6 +158,8 @@ namespace Rokojori { RemoveThemeFontOverride( "font" ); AddThemeFontOverride( "font", resolvedFont ); + + _textDirty = true; } } @@ -168,15 +173,44 @@ namespace Rokojori 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(); @@ -196,18 +230,28 @@ namespace Rokojori void SetSelectorFlagReference( UISelectorFlag flag, string reference, bool enable ) { + if ( enable ) { _selectorFlagReferenceCounter.AddIfNotPresent( flag, reference ); } else { - _selectorFlagReferenceCounter.Remove( flag ); + _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 = []; @@ -254,16 +298,6 @@ namespace Rokojori } - // public List> GetActiveShaderUIColorTransitions() - // { - // return null; - // } - - // public List> GetActiveShaderUINumberTransitions() - // { - // return null; - // } - [ExportGroup("Transitions")] [Export] public TransitionSettingsAll transitionSettings; @@ -427,11 +461,11 @@ namespace Rokojori case UIStyleNumberProperty.MarginTop: { marginTop = number; } break; case UIStyleNumberProperty.MarginBottom: { marginBottom = number; } break; - case UIStyleNumberProperty.FontSize: { fontSize = number; } break; - case UIStyleNumberProperty.FontOutlineSize: { outlineSize = number; } break; - case UIStyleNumberProperty.FontShadowSize: { shadowSize = number; } break; - case UIStyleNumberProperty.FontShadowOffsetX: { shadowOffsetX = number; } break; - case UIStyleNumberProperty.FontShadowOffsetY: { shadowOffsetY = 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; @@ -441,6 +475,9 @@ namespace Rokojori case UIStyleNumberProperty.ScaleX: { scaleX = number; } break; case UIStyleNumberProperty.ScaleY: { scaleY = number; } break; } + + + this.SetLayoutDirtyFlag(); } public Vector2 GetUISize() @@ -448,6 +485,207 @@ namespace Rokojori 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 ) @@ -462,25 +700,36 @@ namespace Rokojori UI ui; - public void SetUI( UI ui ) + public void SetUI( UI ui,bool computeDepth = true ) { this.ui = ui; + + if ( computeDepth ) + { + ComputeUIAncestorDepth(); + } } - public UI GetUI() + public UI GetUI( bool computeDepth = true ) { - var ui = this.ui != null ? this.ui : Unique.Get(); + if ( this.ui != null ) + { + return this.ui; + } + + var ui = this.FindParentThatIs(); if ( ui == null ) - { - ui = this.FindParentThatIs(); + { + _uiAncestorDepth = -1; + // this.LogInfo( "No UI in parents >", HierarchyName.Of( this ) ); - if ( ui == null ) - { - // this.LogInfo( "No UI in parents >", HierarchyName.Of( this ) ); + return null; + } - return null; - } + if ( computeDepth ) + { + ComputeUIAncestorDepth(); } return ui; diff --git a/Runtime/UI/Optimization/CachedUIColor.cs b/Runtime/UI/Optimization/CachedUIColor.cs new file mode 100644 index 0000000..d280d24 --- /dev/null +++ b/Runtime/UI/Optimization/CachedUIColor.cs @@ -0,0 +1,38 @@ + +using Godot; +using System; + +namespace Rokojori +{ + public class CachedUIColor + { + public UIStyleColorProperty property; + public string shaderPropertyName; + + public bool changed; + public Color defaultColor = Colors.White; + public Color color; + + + public static CachedUIColor Create( UIStyleColorProperty colorProperty, string shaderPropertyName = "" ) + { + var c = new CachedUIColor(); + c.property = colorProperty; + c.shaderPropertyName = shaderPropertyName; + c.defaultColor = Colors.White; + return c; + } + + public void Compute( Control control ) + { + var nextValue = UIColor.Compute( control, property, shaderPropertyName, defaultColor ); + + changed = color != nextValue; + + if ( changed ) + { + color = nextValue; + } + } + } +} \ No newline at end of file diff --git a/Runtime/UI/Optimization/CachedUIColor.cs.uid b/Runtime/UI/Optimization/CachedUIColor.cs.uid new file mode 100644 index 0000000..6e6c659 --- /dev/null +++ b/Runtime/UI/Optimization/CachedUIColor.cs.uid @@ -0,0 +1 @@ +uid://ch0mxgji41tru diff --git a/Runtime/UI/Optimization/CachedUINumber.cs b/Runtime/UI/Optimization/CachedUINumber.cs new file mode 100644 index 0000000..92c4ab2 --- /dev/null +++ b/Runtime/UI/Optimization/CachedUINumber.cs @@ -0,0 +1,85 @@ + +using Godot; +using System; + +namespace Rokojori +{ + public class CachedUINumber + { + public UIStyleNumberProperty property; + public string shaderPropertyName; + + public bool isInt = false; + public float value = 0; + public int valueInt = 0; + public bool changed = false; + public int minInt = -1000000; + public int maxInt = 1000000; + + public CachedUINumber SetMin( int min ) + { + minInt = min; + return this; + } + + + + public float alternative; + public float relative; + + public static CachedUINumber AsFloat( UIStyleNumberProperty numberProperty, string shaderPropertyName = "" ) + { + var n = new CachedUINumber(); + n.property = numberProperty; + n.shaderPropertyName = shaderPropertyName; + n.alternative = 0; + return n; + } + + public static CachedUINumber AsInt( UIStyleNumberProperty numberProperty, string shaderPropertyName = "" ) + { + var n = new CachedUINumber(); + n.property = numberProperty; + n.shaderPropertyName = shaderPropertyName; + n.alternative = 0; + n.isInt = true; + + return n; + } + + public static CachedUINumber AsInt( string shaderPropertyName ) + { + return AsInt( UIStyleNumberProperty.FloatShaderProperty, shaderPropertyName ); + } + + public void Compute( Control control ) + { + var nextValue = UINumber.Compute( control, property, shaderPropertyName, alternative, relative ); + + if ( isInt ) + { + var nextInt = Mathf.Max( minInt, Mathf.RoundToInt( nextValue ) ); + changed = nextInt != valueInt; + + if ( changed ) + { + valueInt = nextInt; + } + + } + else + { + changed = value != nextValue; + + if ( changed ) + { + value = nextValue; + } + } + + + + } + + } +} \ No newline at end of file diff --git a/Runtime/UI/Optimization/CachedUINumber.cs.uid b/Runtime/UI/Optimization/CachedUINumber.cs.uid new file mode 100644 index 0000000..b905867 --- /dev/null +++ b/Runtime/UI/Optimization/CachedUINumber.cs.uid @@ -0,0 +1 @@ +uid://cj7ufttupy0io diff --git a/Runtime/UI/Styling/UIColor.cs b/Runtime/UI/Styling/UIColor.cs index eb94643..0f28c3a 100644 --- a/Runtime/UI/Styling/UIColor.cs +++ b/Runtime/UI/Styling/UIColor.cs @@ -39,10 +39,16 @@ namespace Rokojori public static Color Compute( Control control, UIStyleColorProperty property, string shaderPropertyName, Color defaultColor ) { - var container = control as UIStylePropertyContainer; + var container = control as UIStylePropertyContainerNode; // Get selected ui color var uiColor = UIStyle.GetUIColorProperty( container, property, shaderPropertyName, container ); + + if ( uiColor != null && uiColor.isAnimated ) + { + container.SetAnimatedFlag(); + } + var computedColor = Compute( control, uiColor, defaultColor ); var transition = UIStyle.GetTransition( container, property, shaderPropertyName ); diff --git a/Runtime/UI/Styling/UINumber.cs b/Runtime/UI/Styling/UINumber.cs index c046fe6..209ad72 100644 --- a/Runtime/UI/Styling/UINumber.cs +++ b/Runtime/UI/Styling/UINumber.cs @@ -1,7 +1,9 @@ using Godot; using Rokojori; - +using System.Collections.Generic; +using System.Linq; + namespace Rokojori { @@ -179,12 +181,17 @@ namespace Rokojori public static float Compute( Control control, UIStyleNumberProperty property, string shaderPropertyName = "", float alternative = 0, float relative = 100 ) { - var container = control as UIStylePropertyContainer; + var container = control as UIStylePropertyContainerNode; // Get selected ui number - var uiNumber = UIStyle.GetUINumberProperty( control as UIStylePropertyContainer, property, shaderPropertyName, container ); + var uiNumber = UIStyle.GetUINumberProperty( container, property, shaderPropertyName, container ); var computedNumber = Compute( control, uiNumber, alternative, relative ); + if ( uiNumber != null && uiNumber.isAnimated ) + { + container.SetAnimatedFlag(); + } + var transition = UIStyle.GetTransition( container, property, shaderPropertyName ); var transitionAll = UIStyle.GetTransitionSettingsAll( container ); @@ -345,7 +352,7 @@ namespace Rokojori public static float Compute( Control control, UINumber number, float width, float height, float relative ) { - var value = ComputeWithoutAnimation( control, number, width, height, relative ); + var value = ComputeFormulaValue( control, number, width, height, relative ); if ( ! number.isAnimated || number.animationCurve == null ) { @@ -375,7 +382,42 @@ namespace Rokojori "value" }; - static float ComputeWithoutAnimation( Control control, UINumber number, float width, float height, float relative ) + static MapList cached = new MapList(); + + class CachedExpressionData + { + public string formula; + public Godot.Collections.Array inputs; + public float result; + + public bool Matches( UINumber number, Godot.Collections.Array inputs ) + { + if ( number.unit != formula ) + { + return false; + } + + for ( int i = 0; i < inputs.Count; i++ ) + { + if ( (float)inputs.ElementAt( i ) != (float)this.inputs.ElementAt( i ) ) + { + return false; + } + } + + return true; + } + } + + static List cachedExpressions = new List(); + static int maxCachedExpressions = 50; + + static int GetCacheIndex( UINumber number, Godot.Collections.Array inputs ) + { + return cachedExpressions.FindIndex( c => c.Matches( number, inputs ) ); + } + + static float ComputeFormulaValue( Control control, UINumber number, float width, float height, float relative ) { if ( number == null ) { @@ -387,9 +429,7 @@ namespace Rokojori case "em": { return number.value * em( control ); - } - - + } case "vw": { @@ -407,6 +447,12 @@ namespace Rokojori return number.value / 100f * ( parent == null ? width : parent.Size.X ); } + case "ph": + { + var parent = control.GetParent() as Control; + return number.value / 100f * ( parent == null ? height : parent.Size.Y ); + } + case "cw": { var parent = control.GetParent() as Control; @@ -442,11 +488,7 @@ namespace Rokojori } - case "ph": - { - var parent = control.GetParent() as Control; - return number.value / 100f * ( parent == null ? height : parent.Size.Y ); - } + case "": { @@ -459,10 +501,29 @@ namespace Rokojori } } + + var parentControl = control.GetParent() as Control;; + + var inputs = GetInputs( control, number, parentControl, width, height, relative ); + + var cacheIndex = GetCacheIndex( number, inputs ); + + if ( cacheIndex != -1 ) + { + var cachedResult = cachedExpressions[ cacheIndex ].result; + cachedExpressions.SwapTowardsBegin( cacheIndex ); + + // control.LogInfo( "Using cached value", cachedExpressions[ cacheIndex ].formula, ">", cachedResult ); + return cachedResult; + } + var expression = new Expression(); var expressionText = number.unit == null ? "" : RegexUtility.Replace( number.unit, "%", " * relative " ); + expressionText = RegexUtility.Replace( expressionText, @"\b(\d+)\s*(em|v[wh]|p[wh]|c[wh]|c[xy]|ui[wh])\b", "$1*$2" ); + + if ( ! IsValid( expressionText ) ) { return 0; @@ -475,9 +536,41 @@ namespace Rokojori return 0; } - var parentControl = control.GetParent() as Control;; + + var scale = number.unit.IndexOf( "value" ) == -1 ? number.value : 1; - var inputs = new Godot.Collections.Array(); + var result = (float) ( scale * expression.Execute( inputs ).AsDouble() ); + + Cache( number.unit, inputs, result ); + + + return result; + } + + static void Cache( string formula, Godot.Collections.Array inputs, float result ) + { + CachedExpressionData data = null; + + if ( cachedExpressions.Count < maxCachedExpressions ) + { + data = new CachedExpressionData(); + cachedExpressions.Add( data ); + } + else + { + data = GodotRandom.Get().From( cachedExpressions, 4 * maxCachedExpressions / 5, maxCachedExpressions - 1 ); + } + + data.formula = formula; + data.inputs = inputs; + data.result = result; + + } + + + static Godot.Collections.Array GetInputs( Control control, UINumber number, Control parentControl, float width, float height, float relative ) + { + var inputs = new Godot.Collections.Array(); // em inputs.Add( em( control ) ); @@ -491,7 +584,7 @@ namespace Rokojori // cw, ch inputs.Add( ( parentControl == null ? width : UILayouting.GetContentSize( parentControl ).X ) / 100f ); - inputs.Add( ( parentControl == null ? width : UILayouting.GetContentSize( parentControl ).Y ) / 100f ); + inputs.Add( ( parentControl == null ? height : UILayouting.GetContentSize( parentControl ).Y ) / 100f ); // cx, cy inputs.Add( ( parentControl == null ? 0 : UILayouting.GetContentOffset( parentControl ).X ) / 100f ); @@ -504,16 +597,10 @@ namespace Rokojori // "relative" inputs.Add( relative / 100f ); - // value - if ( number.unit.IndexOf( "value" ) == -1 ) - { - inputs.Add( 0 ); - return number.value * (float) expression.Execute( inputs ).AsDouble() ; - } - + // value inputs.Add( number.value ); - return (float) expression.Execute( inputs ).AsDouble() ; + return inputs; } static bool IsValid( string expressionText ) diff --git a/Runtime/UI/Styling/UISelector.cs b/Runtime/UI/Styling/UISelector.cs index 434d778..c4803de 100644 --- a/Runtime/UI/Styling/UISelector.cs +++ b/Runtime/UI/Styling/UISelector.cs @@ -15,9 +15,9 @@ namespace Rokojori { ___, True, - False, - True_For_Any_Parent, - False_For_All_Parents + False + // True_For_Any_Parent, + // False_For_All_Parents } [Export] @@ -51,10 +51,10 @@ namespace Rokojori return container.GetUISelectorFlags().Contains( flag ) == ( Value.True == value ); } - if ( Value.True_For_Any_Parent == value || Value.False_For_All_Parents == value ) - { - return container.GetParentUISelectorFlags().Contains( flag ) == ( Value.True_For_Any_Parent == value ); - } + // if ( Value.True_For_Any_Parent == value || Value.False_For_All_Parents == value ) + // { + // return container.GetParentUISelectorFlags().Contains( flag ) == ( Value.True_For_Any_Parent == value ); + // } return true; @@ -101,8 +101,13 @@ namespace Rokojori } - public static void UpdateParentUISelectorFlags( UIStylePropertyContainer target ) + public static void UpdateParentUISelectorFlags( UIStylePropertyContainerNode target ) { + if ( target != null ) + { + return; + } + var node = target as Node; var walker = NodesWalker.Get(); @@ -111,7 +116,7 @@ namespace Rokojori walker.PruneChildTraversal( node, ( Node n ) => { - if ( n != node && n is UIStylePropertyContainer c ) + if ( n != node && n is UIStylePropertyContainerNode c ) { UpdateParentUISelectorFlags( c ); return false; @@ -125,7 +130,7 @@ namespace Rokojori } - static void CombineParentFlags( UIStylePropertyContainer target ) + static void CombineParentFlags( UIStylePropertyContainerNode target ) { var parentFlags = target.GetParentUISelectorFlags(); parentFlags.Clear(); @@ -137,6 +142,9 @@ namespace Rokojori { parentFlags.Union( parent.GetParentUISelectorFlags() ); } + + target.SetDirty(); + } diff --git a/Runtime/UI/Styling/UIStylePropertyContainer.cs b/Runtime/UI/Styling/UIStylePropertyContainer.cs index f83d978..c0eafda 100644 --- a/Runtime/UI/Styling/UIStylePropertyContainer.cs +++ b/Runtime/UI/Styling/UIStylePropertyContainer.cs @@ -40,6 +40,76 @@ namespace Rokojori void AddUISelectorFlag( UISelectorFlag flag, string reference = "" ); void RemoveUISelectorFlag( UISelectorFlag flag, string reference = "" ); - } + + public interface UIStylePropertyContainerNode:UIStylePropertyContainer + { + public int GetUIAncestorDepth(); + public void ResetDirtyFlags(); + public void SetAnimatedFlag(); + public void SetLayoutDirtyFlag(); + public bool IsDirty(); + } + + public static class UIStylePropertyContainers + { + public static void SetDirty( this UIStylePropertyContainerNode container ) + { + if ( ! ( container is UIHolderControl ) ) + { + return; + } + + var control = container as UIHolderControl; + + var ui = control.GetUI(); + + if ( ui == null ) + { + return; + } + + ui.SetDirty( container ); + } + + public static void CommitUpdateInfo( this UIStylePropertyContainerNode container ) + { + if ( ! ( container is UIHolderControl ) ) + { + return; + } + + var control = container as UIHolderControl; + + var ui = control.GetUI(); + + if ( ui == null ) + { + return; + } + + ui.SetUpdated( container ); + + } + + public static bool HasActiveTransitions( this UIStylePropertyContainer container ) + { + var animatedNumber = container.GetActiveUINumberTransitions().Find( n => n != null && n.transitioning ); + + if ( animatedNumber != null ) + { + return true; + } + + var animatedColor = container.GetActiveUIColorTransitions().Find( n => n != null && n.transitioning ); + + if ( animatedColor != null ) + { + return true; + } + + return false; + } + } + } \ No newline at end of file diff --git a/Runtime/UI/UI.cs b/Runtime/UI/UI.cs index a0cc1d6..6f690ce 100644 --- a/Runtime/UI/UI.cs +++ b/Runtime/UI/UI.cs @@ -20,6 +20,7 @@ namespace Rokojori public enum UpdateMode { Always, + Optimized, Only_Manual_Updates } [Export] @@ -38,9 +39,7 @@ namespace Rokojori [ExportGroup("Read Only")] [Export] - public float X_computedFontSizePixels = 1; - - + public float X_computedFontSizePixels = 1; List _customDisposers = []; @@ -57,6 +56,7 @@ namespace Rokojori [Export] public string[] customDisposerIDs = []; + public void MakeStopToPass() { @@ -96,6 +96,8 @@ namespace Rokojori return UIHolder.GetUI( c ); } + + public static UIStylePropertyContainer GetStylePropertyContainerParent( Control c ) { var it = c as Node; @@ -144,12 +146,30 @@ namespace Rokojori return ui.settings.defaultTimeline; } + Vector2 windowSize = new Vector2(); + + bool _resizeFlag = false; + bool _fontSizeFlag = false; + + public bool sizeChanged => _resizeFlag; + public bool fontSizeChanged => _fontSizeFlag; + public override void _Process( double delta ) { if ( settings == null ) { return; } + + _resizeFlag = false; + _fontSizeFlag = false; + + var newWindowSize = GetWindowSize(); + + if ( windowSize != newWindowSize ) + { + _resizeFlag = true; + } if ( useParentSize ) { @@ -158,12 +178,9 @@ namespace Rokojori if ( parentSize != cachedSize ) { Size = parentSize; - cachedSize = parentSize; - - // this.LogInfo( "Size Changed" ); + _resizeFlag = true; } - } @@ -187,14 +204,7 @@ namespace Rokojori public override void _Input( InputEvent ie ) { onInputEvent.DispatchEvent( ie ); - } - - List hoveredControls = new List(); - - public void SetHovered( UIHoverable control ) - { - hoveredControls.Add( control ); - } + } public void BindOwnChildren() { @@ -244,14 +254,113 @@ namespace Rokojori } } + HashSet _dirty = new HashSet(); + HashSet _updated = new HashSet(); + + public void SetDirty( UIStylePropertyContainerNode control ) + { + _dirty.Add( control ); + } + + public void SetUpdated( UIStylePropertyContainerNode control ) + { + _updated.Add( control ); + } + void UpdateUIElements() { - if ( UpdateMode.Always != updateMode ) + if ( UpdateMode.Always == updateMode ) { - return; + 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( [ .. _dirty ]); + + if ( sorted.Count > 0 ) + { + // this.LogInfo( "Updating:", sorted.Count ); } - UpdateAllUIRegions(); + _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(); + } + else + { + UILayouting.UpdateChild( control as Control ); + + if ( UIStyle.Position( control ) == UIPosition.From_Layout ) + { + UILayouting.SetPositionInParentAnchor( control ); + } + + } + } public void UpdateAllUIRegions() @@ -282,6 +391,21 @@ namespace Rokojori return control.GetWindow().Size.Y; } } + + 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; + } + } } diff --git a/Tools/Git/Git.cs b/Tools/Git/Git.cs new file mode 100644 index 0000000..8600bb4 --- /dev/null +++ b/Tools/Git/Git.cs @@ -0,0 +1,61 @@ +#if TOOLS +using Godot; +using Rokojori; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Rokojori.Tools +{ + public class GitResponse + { + public string rawResponse; + public int exitCode; + } + + public class Git + { + public static async Task GetStatus( string path ) + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "git", + Arguments = "status", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = path + } + }; + + process.Start(); + + var outputTask = process.StandardOutput.ReadToEndAsync(); + var errorTask = process.StandardError.ReadToEndAsync(); + + await Task.WhenAll( outputTask, errorTask ); + + await process.WaitForExitAsync(); + + var response = new GitResponse(); + response.exitCode = process.ExitCode; + + if ( process.ExitCode == 0 ) + { + response.rawResponse = outputTask.Result; + } + else + { + response.rawResponse = errorTask.Result; + } + + return response; + } + } + +} + +#endif \ No newline at end of file diff --git a/Tools/Git/Git.cs.uid b/Tools/Git/Git.cs.uid new file mode 100644 index 0000000..c866e67 --- /dev/null +++ b/Tools/Git/Git.cs.uid @@ -0,0 +1 @@ +uid://b2m8er8ijkqhy diff --git a/Tools/Git/GitTest.cs b/Tools/Git/GitTest.cs new file mode 100644 index 0000000..d63aa79 --- /dev/null +++ b/Tools/Git/GitTest.cs @@ -0,0 +1,30 @@ +#if TOOLS +using Godot; +using Rokojori; +using System.Diagnostics; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Rokojori.Tools +{ + [Tool] + [GlobalClass] + public partial class GitTest:Node + { + [ExportToolButton("Status")] + public Callable StatusButton => Callable.From( + ()=> + { + GetStatus(); + } + ); + + async void GetStatus() + { + var response = await Git.GetStatus( ProjectSettings.GlobalizePath( "res://") ); + this.LogInfo( response.exitCode, ">>", response.rawResponse ); + + } + } +} +#endif \ No newline at end of file diff --git a/Tools/Git/GitTest.cs.uid b/Tools/Git/GitTest.cs.uid new file mode 100644 index 0000000..056781b --- /dev/null +++ b/Tools/Git/GitTest.cs.uid @@ -0,0 +1 @@ +uid://d2ieh3rd71cdk diff --git a/Tools/Messages/Message.tscn b/Tools/Messages/Message.tscn index 1eaaa38..21a8073 100644 --- a/Tools/Messages/Message.tscn +++ b/Tools/Messages/Message.tscn @@ -83,7 +83,7 @@ metadata/_custom_type_script = "uid://cnkyynboxg1qg" [sub_resource type="ShaderMaterial" id="ShaderMaterial_btdid"] shader = ExtResource("7_aeebn") -shader_parameter/size = Vector2(1156.56, 137.56) +shader_parameter/size = Vector2(1134.72, 137.56) shader_parameter/sharpness = 5.0 shader_parameter/borderRadius = 6.048 shader_parameter/strokeSize = 0.0 @@ -111,7 +111,7 @@ fill_to = Vector2(0.0811966, 0.0811966) [sub_resource type="Resource" id="Resource_pyi7r"] script = ExtResource("5_1tota") value = 1.0 -unit = "100 * pw - 2*1.5em" +unit = "100 pw - 2*1.5em" isAnimated = false animationDuration = 0.0 animationOffset = 0.0 @@ -566,10 +566,7 @@ number = SubResource("Resource_fcuvy") [sub_resource type="LabelSettings" id="LabelSettings_x3h2c"] font_size = 9 font_color = Color(1, 0.467117, 0.467117, 1) -outline_color = Color(1, 1, 1, 0) shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) [sub_resource type="Resource" id="Resource_uulg6"] script = ExtResource("17_illef") @@ -607,7 +604,7 @@ fill = 1 fill_from = Vector2(0.5, 0.5) fill_to = Vector2(0.5, 0) -[sub_resource type="LabelSettings" id="LabelSettings_qjby8"] +[sub_resource type="LabelSettings" id="LabelSettings_1jemv"] [sub_resource type="Resource" id="Resource_jm3cb"] script = ExtResource("17_illef") @@ -616,21 +613,15 @@ entries = [] context = "" metadata/_custom_type_script = "uid://bvj322mokkq63" -[sub_resource type="LabelSettings" id="LabelSettings_1jemv"] +[sub_resource type="LabelSettings" id="LabelSettings_1hp7s"] font_size = 9 font_color = Color(0.75201, 0.831706, 0.90732, 1) -outline_color = Color(1, 1, 1, 0) shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) -[sub_resource type="LabelSettings" id="LabelSettings_1hp7s"] +[sub_resource type="LabelSettings" id="LabelSettings_nro64"] font_size = 17 font_color = Color(1, 1, 1, 0.843137) -outline_color = Color(1, 1, 1, 0) shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) [sub_resource type="Resource" id="Resource_jn787"] script = ExtResource("17_illef") @@ -639,13 +630,10 @@ entries = [] context = "" metadata/_custom_type_script = "uid://bvj322mokkq63" -[sub_resource type="LabelSettings" id="LabelSettings_nro64"] +[sub_resource type="LabelSettings" id="LabelSettings_0e03u"] font_size = 14 font_color = Color(0.2226, 0.710943, 0.914108, 1) -outline_color = Color(1, 1, 1, 0) shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) [sub_resource type="Resource" id="Resource_7rt2a"] script = ExtResource("17_illef") @@ -654,21 +642,15 @@ entries = [] context = "" metadata/_custom_type_script = "uid://bvj322mokkq63" -[sub_resource type="LabelSettings" id="LabelSettings_0e03u"] -font_size = 14 -font_color = Color(0.289366, 0.771546, 0.496309, 1) -outline_color = Color(1, 1, 1, 0) -shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) - [sub_resource type="LabelSettings" id="LabelSettings_illef"] font_size = 14 -font_color = Color(0.914108, 0.8403, 0.2226, 1) -outline_color = Color(1, 1, 1, 0) +font_color = Color(0.289366, 0.771546, 0.496309, 1) +shadow_size = 0 + +[sub_resource type="LabelSettings" id="LabelSettings_qjby8"] +font_size = 14 +font_color = Color(0.914108, 0.8403, 0.2226, 1) shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) [sub_resource type="Resource" id="Resource_qjby8"] script = ExtResource("5_1tota") @@ -706,18 +688,18 @@ animationDuration = 0.0 animationOffset = 0.0 metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="ShaderMaterial" id="ShaderMaterial_qjby8"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ul0js"] shader = ExtResource("7_aeebn") -shader_parameter/size = Vector2(34.5601, 34.56) +shader_parameter/size = Vector2(0, 0) shader_parameter/sharpness = 5.0 -shader_parameter/borderRadius = 3.46464 -shader_parameter/strokeSize = 8.44128 -shader_parameter/offset = 3.51648 -shader_parameter/fillColor = Color(1, 1, 1, 1) +shader_parameter/borderRadius = 5.0 +shader_parameter/strokeSize = 5.0 +shader_parameter/offset = 0.0 +shader_parameter/fillColor = Color(0, 0, 0, 1) shader_parameter/fillUVTransform = Vector4(0, 0, 0, 0) shader_parameter/screenfillMultiplyUVTransform = Vector4(0, 0, 0, 0) shader_parameter/screenfillMultiplyUVMovement = Vector2(0, 0) -shader_parameter/strokeColor = Color(1, 1, 1, 1) +shader_parameter/strokeColor = Color(0, 0, 0, 1) shader_parameter/strokeUVTransform = Vector4(0, 0, 0, 0) shader_parameter/screenStrokeMultiplyUVTransform = Vector4(0, 0, 0, 0) shader_parameter/screenStrokeMultiplyUVMovment = Vector2(0, 0) @@ -794,12 +776,7 @@ animationDuration = 0.0 animationOffset = 0.0 metadata/_custom_type_script = "uid://cnkyynboxg1qg" -[sub_resource type="LabelSettings" id="LabelSettings_ul0js"] -font_size = 26 -outline_color = Color(1, 1, 1, 0) -shadow_size = 0 -shadow_color = Color(0, 0, 0, 1) -shadow_offset = Vector2(0, 0) +[sub_resource type="LabelSettings" id="LabelSettings_hj653"] [sub_resource type="Resource" id="Resource_btdid"] script = ExtResource("5_1tota") @@ -882,9 +859,9 @@ nodeLink = NodePath("../Node Link") [node name="Background" type="TextureRect" parent="."] material = SubResource("ShaderMaterial_btdid") layout_mode = 0 -offset_right = 1156.56 +offset_right = 1134.72 offset_bottom = 137.56 -pivot_offset = Vector2(593.28, 68.78) +pivot_offset = Vector2(567.36, 68.78) texture = SubResource("GradientTexture2D_dmcan") expand_mode = 1 script = ExtResource("8_gyhi8") @@ -994,7 +971,7 @@ pivot_offset = Vector2(11, 7) mouse_filter = 1 theme_override_fonts/font = ExtResource("15_nro64") text = "INFO" -label_settings = SubResource("LabelSettings_qjby8") +label_settings = SubResource("LabelSettings_1jemv") autowrap_mode = 2 script = ExtResource("16_0e03u") locale = SubResource("Resource_jm3cb") @@ -1002,16 +979,17 @@ parentStyle = ExtResource("22_aeebn") metadata/_custom_type_script = "uid://rqs2m0u6yvvf" [node name="Time Stamp" type="Label" parent="."] -custom_minimum_size = Vector2(1, 0) +custom_minimum_size = Vector2(24, 0) layout_mode = 0 offset_left = 69.0896 offset_top = 17.28 -offset_right = 70.0896 +offset_right = 93.0896 offset_bottom = 31.28 -pivot_offset = Vector2(0.5, 7) +pivot_offset = Vector2(12, 7) mouse_filter = 1 theme_override_fonts/font = ExtResource("15_nro64") -label_settings = SubResource("LabelSettings_1jemv") +text = "19:00" +label_settings = SubResource("LabelSettings_1hp7s") autowrap_mode = 2 script = ExtResource("16_0e03u") disableLocalization = true @@ -1029,7 +1007,7 @@ pivot_offset = Vector2(220.5, 13) mouse_filter = 1 theme_override_fonts/font = ExtResource("15_nro64") text = "Ein etwas anderer Text! Hello das ist eine Nachricht! Huhe!" -label_settings = SubResource("LabelSettings_1hp7s") +label_settings = SubResource("LabelSettings_nro64") autowrap_mode = 2 script = ExtResource("16_0e03u") locale = SubResource("Resource_jn787") @@ -1048,7 +1026,7 @@ mouse_filter = 1 mouse_default_cursor_shape = 2 theme_override_fonts/font = ExtResource("15_nro64") text = "Node3D > Static Environment > SomeThing > MyNodes > SomeNode" -label_settings = SubResource("LabelSettings_nro64") +label_settings = SubResource("LabelSettings_0e03u") autowrap_mode = 2 script = ExtResource("16_0e03u") locale = SubResource("Resource_7rt2a") @@ -1074,7 +1052,7 @@ mouse_filter = 1 mouse_default_cursor_shape = 2 theme_override_fonts/font = ExtResource("15_nro64") text = "Node3D > Static Environment > SomeThing > MyNodes > SomeNode" -label_settings = SubResource("LabelSettings_0e03u") +label_settings = SubResource("LabelSettings_illef") autowrap_mode = 2 script = ExtResource("16_0e03u") locale = SubResource("Resource_7rt2a") @@ -1100,7 +1078,7 @@ mouse_filter = 1 mouse_default_cursor_shape = 2 theme_override_fonts/font = ExtResource("15_nro64") text = "Node3D > Static Environment > SomeThing > MyNodes > SomeNode" -label_settings = SubResource("LabelSettings_illef") +label_settings = SubResource("LabelSettings_qjby8") autowrap_mode = 2 script = ExtResource("16_0e03u") locale = SubResource("Resource_7rt2a") @@ -1131,7 +1109,7 @@ right = SubResource("Resource_v6jx4") metadata/_custom_type_script = "uid://c2hicupu28nbi" [node name="Info Icon2" type="TextureRect" parent="Close Button"] -material = SubResource("ShaderMaterial_qjby8") +material = SubResource("ShaderMaterial_ul0js") layout_mode = 0 offset_right = 34.5601 offset_bottom = 34.56 @@ -1157,8 +1135,7 @@ offset_right = 34.5601 offset_bottom = 32.721 mouse_filter = 1 theme_override_fonts/font = ExtResource("15_nro64") -text = "x" -label_settings = SubResource("LabelSettings_ul0js") +label_settings = SubResource("LabelSettings_hj653") horizontal_alignment = 1 vertical_alignment = 1 autowrap_mode = 2 diff --git a/Tools/Messages/Messages.tscn b/Tools/Messages/Messages.tscn index 93743e2..33e2c54 100644 --- a/Tools/Messages/Messages.tscn +++ b/Tools/Messages/Messages.tscn @@ -320,6 +320,7 @@ offset_bottom = 584.0 mouse_filter = 1 script = ExtResource("1_op0b4") settings = ExtResource("2_iufyf") +updateMode = 1 useParentSize = true X_computedFontSizePixels = 17.28 customDisposerIDs = PackedStringArray("ciOsgmckohhN3Ejw:Messages ▸ UI ▸ Scroller ▸ Vertical Scroller ▸ Button", "9ak1UYtRMpBsDldi:Messages ▸ UI ▸ Scroller")