diff --git a/Icons/AppSetting.svg b/Icons/AppSetting.svg
new file mode 100644
index 0000000..7d1236f
--- /dev/null
+++ b/Icons/AppSetting.svg
@@ -0,0 +1,256 @@
+
+
diff --git a/Icons/AppSetting.svg.import b/Icons/AppSetting.svg.import
new file mode 100644
index 0000000..90019e4
--- /dev/null
+++ b/Icons/AppSetting.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bmwow4y720y33"
+path="res://.godot/imported/AppSetting.svg-8d628f4fbcffee62d24cc3be49835a1b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/AppSetting.svg"
+dest_files=["res://.godot/imported/AppSetting.svg-8d628f4fbcffee62d24cc3be49835a1b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Icons/AppSettingsCategory.svg b/Icons/AppSettingsCategory.svg
new file mode 100644
index 0000000..a2deff2
--- /dev/null
+++ b/Icons/AppSettingsCategory.svg
@@ -0,0 +1,288 @@
+
+
diff --git a/Icons/AppSettingsCategory.svg.import b/Icons/AppSettingsCategory.svg.import
new file mode 100644
index 0000000..13dd68a
--- /dev/null
+++ b/Icons/AppSettingsCategory.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cxn0doccbmdkk"
+path="res://.godot/imported/AppSettingsCategory.svg-fc090dc93be0f63fc2716bd8b27285c6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/AppSettingsCategory.svg"
+dest_files=["res://.godot/imported/AppSettingsCategory.svg-fc090dc93be0f63fc2716bd8b27285c6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Icons/UIStyle.svg b/Icons/UIStyle.svg
new file mode 100644
index 0000000..2336448
--- /dev/null
+++ b/Icons/UIStyle.svg
@@ -0,0 +1,176 @@
+
+
diff --git a/Icons/UIStyle.svg.import b/Icons/UIStyle.svg.import
new file mode 100644
index 0000000..69356d9
--- /dev/null
+++ b/Icons/UIStyle.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bvypajorfxmwx"
+path="res://.godot/imported/UIStyle.svg-a608110861b4c944c77405733f78e151.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rokojori_action_library/Icons/UIStyle.svg"
+dest_files=["res://.godot/imported/UIStyle.svg-a608110861b4c944c77405733f78e151.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/Runtime/Actions/ActionSequence.cs b/Runtime/Actions/ActionSequence.cs
index ede7a37..c244722 100644
--- a/Runtime/Actions/ActionSequence.cs
+++ b/Runtime/Actions/ActionSequence.cs
@@ -16,6 +16,7 @@ namespace Rokojori
public int sequencablesIndex = 0;
bool cancelled = false;
bool cancelledSequence = false;
+
int _runID = -1;
@@ -213,6 +214,7 @@ namespace Rokojori
// this.LogInfo( "Running" );
+
var run = new ActionSequenceRunner();
run.sequence = this;
run.actions = new List( actions );
diff --git a/Runtime/Actions/Conditional/CoolDown.cs b/Runtime/Actions/Conditional/CoolDown.cs
index 3e92159..a8577e2 100644
--- a/Runtime/Actions/Conditional/CoolDown.cs
+++ b/Runtime/Actions/Conditional/CoolDown.cs
@@ -12,12 +12,25 @@ namespace Rokojori
[Export]
public Action action;
+ [Export]
+ public Action onCoolingDownAction;
+
[Export]
public Duration coolDownDuration;
+ [Export]
+ public bool retriggerCoolDown = false;
+
bool _isCoolingDown = false;
int _coolDownID = -1;
+ bool _canRelease = false;
+
+ public bool CanRelease()
+ {
+ return _canRelease;
+ }
+
public void RegisterCoolDown()
{
_isCoolingDown = coolDownDuration != null;
@@ -54,13 +67,23 @@ namespace Rokojori
{
if ( _isCoolingDown )
{
+ onCoolingDownAction?.Trigger();
+ _canRelease = false;
+
+ if ( retriggerCoolDown )
+ {
+ RegisterCoolDown();
+ }
return;
}
+ _canRelease = true;
Trigger( action );
RegisterCoolDown();
+
+
}
}
}
\ No newline at end of file
diff --git a/Runtime/Actions/Conditional/CoolDownRelease.cs b/Runtime/Actions/Conditional/CoolDownRelease.cs
new file mode 100644
index 0000000..52e6a19
--- /dev/null
+++ b/Runtime/Actions/Conditional/CoolDownRelease.cs
@@ -0,0 +1,28 @@
+
+using Godot;
+using System.Collections.Generic;
+
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/ConditionalAction.svg")]
+public partial class CoolDownRelease : Action
+{
+ [Export]
+ public CoolDown coolDown;
+
+ [Export]
+ public Action action;
+
+ protected override void _OnTrigger()
+ {
+ if ( ! ( coolDown?.CanRelease() ?? true ) )
+ {
+ return;
+ }
+
+ action?.Trigger();
+
+ }
+}
diff --git a/Runtime/Actions/Conditional/CoolDownRelease.cs.uid b/Runtime/Actions/Conditional/CoolDownRelease.cs.uid
new file mode 100644
index 0000000..7094f1a
--- /dev/null
+++ b/Runtime/Actions/Conditional/CoolDownRelease.cs.uid
@@ -0,0 +1 @@
+uid://b4ld8egl1pum
diff --git a/Runtime/Actions/LoadScene.cs b/Runtime/Actions/LoadScene.cs
index b34dfcd..1d01cbf 100644
--- a/Runtime/Actions/LoadScene.cs
+++ b/Runtime/Actions/LoadScene.cs
@@ -7,15 +7,32 @@ namespace Rokojori
[Tool][GlobalClass]
public partial class LoadScene : SequenceAction
{
- [Export]
+ [Export( PropertyHint.File )]
public string scenePath;
[Export]
public Node target;
+ [ExportGroup("Transforming")]
+ [Export]
+ public Node3D poseParent;
+
+ [Export]
+ public Vector3 offsetTranslation = Vector3.Zero;
+
+ [Export]
+ public Quaternion offsetRotation = Quaternion.Identity;
+
[Export]
public Action onLoaded;
+ Node _loadedNode;
+
+ public Node GetLoadedNode()
+ {
+ return _loadedNode;
+ }
+
bool _loading = false;
int _id = -1;
List _cached = new List();
@@ -40,6 +57,7 @@ namespace Rokojori
}
}
+
public override void _Process ( double delta )
{
if ( ! _loading )
@@ -58,8 +76,24 @@ namespace Rokojori
var packedScene = (PackedScene) ResourceLoader.LoadThreadedGet( scenePath );
var node = packedScene.Instantiate();
- target.AddChild( node );
+ _loadedNode = node;
+ target.AddChild( node );
+ node.Owner = target.Owner;
+
+ if ( node is Node3D n3D )
+ {
+ if ( poseParent != null )
+ {
+ Pose.From( poseParent ).Set( n3D );
+ }
+
+ n3D.GlobalPosition = n3D.GlobalPosition + offsetTranslation;
+ n3D.SetGlobalQuaternion( n3D.GlobalQuaternion() * offsetRotation );
+ }
+
Action.Trigger( onLoaded );
+
+ _loadedNode = null;
DispatchEnd( _id );
_id = -1;
diff --git a/Runtime/Actions/Node/SetNodeState.cs b/Runtime/Actions/Node/SetNodeState.cs
index 6e09371..9bb46f9 100644
--- a/Runtime/Actions/Node/SetNodeState.cs
+++ b/Runtime/Actions/Node/SetNodeState.cs
@@ -7,21 +7,60 @@ namespace Rokojori
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/SetNodeState.svg")]
public partial class SetNodeState : Action
{
- [Export]
- public Node[] enable = new Node[ 0 ];
+
[Export]
- public Node[] disable = new Node[ 0 ];
+ public Node[] enable = [];
+
+ [Export]
+ public Node[] disable = [];
+
+ [ExportGroup( "Reference")]
+ [Export]
+ public SetNodeState reference;
+
+ [Export]
+ public bool inverseReference = false;
+
protected override void _OnTrigger()
{
- CallDeferred( "SetStates" );
+ this.CallDeferred(
+ ()=>
+ {
+ var map = new System.Collections.Generic.HashSet();
+ SetStates( map, false, inverseReference );
+ }
+ );
}
- void SetStates()
+ public void SetStates( System.Collections.Generic.HashSet callMap, bool inverse, bool referenceInverse )
{
- Arrays.ForEach( enable, n => NodeState.Enable( n ) );
- Arrays.ForEach( disable, n => NodeState.Disable( n ) );
+ if ( callMap.Contains( this ) )
+ {
+ return;
+ }
+
+ callMap.Add( this );
+
+ if ( inverse )
+ {
+ Arrays.ForEach( enable, n => NodeState.Disable( n ) );
+ Arrays.ForEach( disable, n => NodeState.Enable( n ) );
+ }
+ else
+ {
+ Arrays.ForEach( enable, n => NodeState.Enable( n ) );
+ Arrays.ForEach( disable, n => NodeState.Disable( n ) );
+ }
+
+ if ( reference == null )
+ {
+ return;
+ }
+
+ reference.SetStates( callMap, referenceInverse, referenceInverse );
+
}
}
diff --git a/Runtime/Actions/Node3D/PlayParticles.cs b/Runtime/Actions/Node3D/PlayParticles.cs
index 8f7d85c..6104cb0 100644
--- a/Runtime/Actions/Node3D/PlayParticles.cs
+++ b/Runtime/Actions/Node3D/PlayParticles.cs
@@ -87,7 +87,7 @@ namespace Rokojori
return particles3D;
}
- return _pool.Find( p => ! p.Emitting );
+ return _pool.Find( p => ! IsEmitting( p ) );
}
GpuParticles3D DuplicateParticles()
diff --git a/Runtime/Actions/Sequence/CancelSequenceAction.cs b/Runtime/Actions/Sequence/CancelSequenceAction.cs
new file mode 100644
index 0000000..fe0718f
--- /dev/null
+++ b/Runtime/Actions/Sequence/CancelSequenceAction.cs
@@ -0,0 +1,18 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool][GlobalClass ]
+ public partial class CancelSequenceAction : Action
+ {
+ [Export]
+ public SequenceAction sequence;
+
+ protected override void _OnTrigger()
+ {
+ sequence?.CancelAllRunning();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Actions/Sequence/CancelSequenceAction.cs.uid b/Runtime/Actions/Sequence/CancelSequenceAction.cs.uid
new file mode 100644
index 0000000..da332b5
--- /dev/null
+++ b/Runtime/Actions/Sequence/CancelSequenceAction.cs.uid
@@ -0,0 +1 @@
+uid://cwbkharqngylr
diff --git a/Runtime/Actions/SequenceAction.cs b/Runtime/Actions/SequenceAction.cs
index 3427ae1..d594d08 100644
--- a/Runtime/Actions/SequenceAction.cs
+++ b/Runtime/Actions/SequenceAction.cs
@@ -1,6 +1,7 @@
using Godot;
using System.Collections.Generic;
+using System.Linq;
namespace Rokojori
{
@@ -30,7 +31,8 @@ namespace Rokojori
[Export]
public int[] runningSequences = [];
-
+
+ HashSet _running = new HashSet();
int _dispatchCounter = 0;
@@ -50,11 +52,15 @@ namespace Rokojori
runningSequences = runningSequences.Add( _dispatchCounter );
}
+ _running.Add( _dispatchCounter );
+
return _dispatchCounter;
}
public void DispatchEnd( int id )
{
+ _running.Remove( id );
+
var ev = new SequenceActionFinishedEvent{ id = id, success = true };
onSequenceDone.DispatchEvent( ev );
@@ -62,10 +68,14 @@ namespace Rokojori
{
runningSequences = runningSequences.Remove( _dispatchCounter );
}
+
+
}
public void DispatchCancelled( int id )
{
+ _running.Remove( id );
+
var ev = new SequenceActionFinishedEvent{ id = id, success = true };
onSequenceDone.DispatchEvent( ev );
@@ -73,6 +83,20 @@ namespace Rokojori
{
runningSequences = runningSequences.Remove( _dispatchCounter );
}
+
+
+ }
+
+ public virtual void CancelAllRunning()
+ {
+ var runningList = _running.ToArray();
+
+ runningList.ForEach(
+ ( id )=>
+ {
+ CancelAction( id );
+ }
+ );
}
public virtual void CancelAction( int id )
diff --git a/Runtime/Actions/SetPauseState.cs b/Runtime/Actions/SetPauseState.cs
index 8d71dc6..2b72d7c 100644
--- a/Runtime/Actions/SetPauseState.cs
+++ b/Runtime/Actions/SetPauseState.cs
@@ -29,22 +29,24 @@ namespace Rokojori
protected override void _OnTrigger()
{
- var currentState = GetTree().Paused;
+ var isCurrentlyPaused = GetTree().Paused;
- var nextState = Mode.Toggle == mode ? ! currentState : Mode.Pause == mode ? false : true;
+ var nextIsPaused = Mode.Toggle == mode ? ! isCurrentlyPaused :
+ Mode.Pause == mode ? true : false;
- this.LogInfo( "SetPauseState", currentState, ">>", nextState );
+ this.LogInfo( "SetPauseState: is paused", isCurrentlyPaused, ">> next is paused", nextIsPaused );
- if ( currentState == nextState && onlyTriggerOnChange )
+ if ( isCurrentlyPaused == nextIsPaused && onlyTriggerOnChange )
{
return;
}
- this.LogInfo( "Setting Pause State", nextState );
- GetTree().Paused = nextState;
+ this.LogInfo( "Setting Paused State", nextIsPaused );
+
+ GetTree().Paused = nextIsPaused;
- if ( nextState )
+ if ( nextIsPaused )
{
Action.Trigger( onPausing );
}
diff --git a/Runtime/Actions/Solo.cs b/Runtime/Actions/Solo.cs
index c7b2acf..35b45ce 100644
--- a/Runtime/Actions/Solo.cs
+++ b/Runtime/Actions/Solo.cs
@@ -1,4 +1,5 @@
+using System.Linq;
using Godot;
@@ -16,15 +17,27 @@ namespace Rokojori
[Export]
public NodeStateConfiguration muteConifiguration;
+ [Export]
+ public Node[] ignore = [];
+
protected override void _OnTrigger()
{
var parent = soloNode.GetParent();
+ var soloConfig = soloConfiguration ?? NodeStateConfiguration.AllOn();
+ var muteConfig = muteConifiguration ?? NodeStateConfiguration.AllOff();
+
+
parent.ForEachDirectChild(
n =>
{
- var configuration = soloNode == n ? soloConfiguration : muteConifiguration;
+ if ( ignore != null && ignore.Contains( n ) )
+ {
+ return;
+ }
+
+ var configuration = soloNode == n ? soloConfig : muteConfig;
NodeState.Configure( n, configuration );
}
);
diff --git a/Runtime/Actions/Time/Delay.cs b/Runtime/Actions/Time/Delay.cs
index 177a513..5f39401 100644
--- a/Runtime/Actions/Time/Delay.cs
+++ b/Runtime/Actions/Time/Delay.cs
@@ -28,7 +28,7 @@ namespace Rokojori
if ( type == TimeLineSpanUpdateType.End )
{
DispatchEnd( sequenceID );
- // this.LogInfo( "time:", Time.GetTicksMsec() / 1000f );
+ this.LogInfo( "time:", Time.GetTicksMsec() / 1000f );
}
},
this
diff --git a/Runtime/Actions/Time/DelayFrames.cs b/Runtime/Actions/Time/DelayFrames.cs
new file mode 100644
index 0000000..9b1ddbf
--- /dev/null
+++ b/Runtime/Actions/Time/DelayFrames.cs
@@ -0,0 +1,55 @@
+
+using Godot;
+using System.Threading.Tasks;
+
+namespace Rokojori
+{
+ [Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Delay.svg")]
+ public partial class DelayFrames : SequenceAction
+ {
+ [Export]
+ public int numFrames;
+
+ protected override void _OnTrigger()
+ {
+ var sequenceID = DispatchStart();
+
+ // this.LogInfo( "time:", Time.GetTicksMsec() / 1000f );
+
+ if ( Engine.IsEditorHint() )
+ {
+ var timeLine = TimeLineManager.Ensure( null );
+
+ TimeLineManager.ScheduleSpanIn( timeLine, 0, numFrames * 1f/60f ,
+ ( span, type )=>
+ {
+ if ( type == TimeLineSpanUpdateType.End )
+ {
+ DispatchEnd( sequenceID );
+ this.LogInfo( "time:", Time.GetTicksMsec() / 1000f );
+ }
+ },
+ this
+ );
+ }
+ else
+ {
+ runForFrames( numFrames, sequenceID );
+ }
+
+ }
+
+ protected async Task runForFrames( int frames, int sequenceID )
+ {
+ while ( frames > 0 )
+ {
+ await this.RequestNextFrame();
+ frames --;
+ }
+
+ DispatchEnd( sequenceID );
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Actions/Time/DelayFrames.cs.uid b/Runtime/Actions/Time/DelayFrames.cs.uid
new file mode 100644
index 0000000..267a7fd
--- /dev/null
+++ b/Runtime/Actions/Time/DelayFrames.cs.uid
@@ -0,0 +1 @@
+uid://cb4ji13qh1v3g
diff --git a/Runtime/Actions/Visual/TweenFloatShaderProperty.cs b/Runtime/Actions/Visual/TweenFloatShaderProperty.cs
index 667cb54..2b2f79b 100644
--- a/Runtime/Actions/Visual/TweenFloatShaderProperty.cs
+++ b/Runtime/Actions/Visual/TweenFloatShaderProperty.cs
@@ -24,6 +24,20 @@ namespace Rokojori
[Export]
public Curve curve;
+ [ExportGroup( "Stop")]
+ [Export]
+ public bool stopAnimation = false;
+
+ [Export]
+ public bool setStopValue = false;
+
+ [ExportGroup( "Animate")]
+ [Export]
+ public bool animateStartValue = false;
+
+ [Export]
+ public float animationStartValue = 0f;
+
[ExportGroup( "Editor Testing")]
[Export]
public bool forceStartValue = false;
@@ -55,15 +69,41 @@ namespace Rokojori
CancelAction( _actionID );
}
+ if ( stopAnimation )
+ {
+
+ AnimationManager.StartAnimation( this, material, propertyName );
+
+ if ( setStopValue )
+ {
+ propertyName.Set( material, endValue );
+ }
+
+ AnimationManager.EndAnimation( this, material, propertyName );
+
+
+ return;
+ }
+
+
_actionID = DispatchStart();
var startValue = propertyName.Get( material );
+
+
+
if ( forceStartValue && Engine.IsEditorHint() )
{
startValue = forcedStartValue;
}
+ if ( animateStartValue )
+ {
+ startValue = animationStartValue;
+ }
+
+
AnimationManager.StartAnimation( this, material, propertyName );
diff --git a/Runtime/Actions/Visual/TweenMaterial.cs b/Runtime/Actions/Visual/TweenMaterial.cs
index 932d89f..767a1bd 100644
--- a/Runtime/Actions/Visual/TweenMaterial.cs
+++ b/Runtime/Actions/Visual/TweenMaterial.cs
@@ -184,6 +184,18 @@ namespace Rokojori
_assignedMaterial = null;
var msc = MaterialSurfaceContainer.From( target, index );
msc.SetMaterialInSlot( slot, toMaterial );
+
+ var prop = new ColorPropertyName();
+ prop.propertyName = "albedo_color";
+
+ var info = new Color();
+
+ if ( toMaterial is BaseMaterial3D bm )
+ {
+ info = bm.AlbedoColor;
+ }
+
+ this.LogInfo( "Setting:", slot, toMaterial, info, prop.Get( toMaterial ) );
}
DispatchEnd( sequenceID );
diff --git a/Runtime/Actions/Visual/TweenScale.cs b/Runtime/Actions/Visual/TweenScale.cs
index 8caef13..58d19a2 100644
--- a/Runtime/Actions/Visual/TweenScale.cs
+++ b/Runtime/Actions/Visual/TweenScale.cs
@@ -12,6 +12,9 @@ namespace Rokojori
[Export]
public Node3D target;
+ [Export]
+ public float endScaleAll = 1f;
+
[Export]
public Vector3 endScale = Vector3.One;
@@ -37,7 +40,7 @@ namespace Rokojori
var start = tl.position;
var fromScale = target.Scale;
- var toScale = endScale;
+ var toScale = endScale * endScaleAll;
var sequenceID = DispatchStart();
@@ -64,7 +67,7 @@ namespace Rokojori
if ( ! cacheEndPositionOnStart )
{
- var toScale = endScale;
+ var toScale = endScale * endScaleAll;
}
var lerpedScale = fromScale.Lerp( toScale, state );
diff --git a/Runtime/Animation/Highlight/HighlightEffect.cs b/Runtime/Animation/Highlight/HighlightEffect.cs
index d26a4e6..45422f7 100644
--- a/Runtime/Animation/Highlight/HighlightEffect.cs
+++ b/Runtime/Animation/Highlight/HighlightEffect.cs
@@ -177,7 +177,7 @@ namespace Rokojori
RJLog.Log( "Removed animations", numRemoved );
- Lists.RemoveRange( animations, removals );
+ Lists.RemoveList( animations, removals );
}
diff --git a/Runtime/App/App.cs b/Runtime/App/App.cs
index 5816c31..0c59ad4 100644
--- a/Runtime/App/App.cs
+++ b/Runtime/App/App.cs
@@ -37,6 +37,31 @@ namespace Rokojori
[Export]
public AppLauncher launcher;
+ [Export]
+ public AppSettings settings;
+
+ [Export]
+ public Action onAppStart;
+
+ Dictionary _settingsData = new Dictionary();
+ public Dictionary GetAppSettingsData() =>_settingsData;
+
+ public string GetSetting( AppSetting appSetting )
+ {
+ return _settingsData.ContainsKey( appSetting.id ) ? _settingsData[ appSetting.id ] : appSetting.GetDefaultValue();
+ }
+
+ public string GetSetting( string id )
+ {
+ return _settingsData.ContainsKey( id ) ? _settingsData[ id ] : null;
+ }
+
+ public void SetSetting( string id, string value )
+ {
+ // this.LogInfo( "Set setting:", id, value );
+ _settingsData[ id ] = value;
+ }
+
int _fps = 60;
public int x = 0;
@@ -48,7 +73,16 @@ namespace Rokojori
set { _fps = value; Engine.MaxFps = _fps; }
}
-
-
+ public override void _Ready()
+ {
+ if ( Engine.IsEditorHint() )
+ {
+ return;
+ }
+
+ onAppStart?.Trigger();
+ }
+
+
}
}
\ No newline at end of file
diff --git a/Runtime/App/Settings/Actions/LoadAppSettings.cs b/Runtime/App/Settings/Actions/LoadAppSettings.cs
new file mode 100644
index 0000000..63abe86
--- /dev/null
+++ b/Runtime/App/Settings/Actions/LoadAppSettings.cs
@@ -0,0 +1,68 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class LoadAppSettings:Action
+ {
+ [Export]
+ public string savePath = "";
+
+ [Export]
+ public App app;
+
+ [Export]
+ public bool writeDefaults = true;
+
+ protected override void _OnTrigger()
+ {
+ this.LogInfo( "Loading App Settings" );
+
+ var data = GDFilesSync.LoadJSON>( savePath );
+
+ this.LogInfo( "App Settings", data );
+
+ foreach ( var vk in data )
+ {
+ app.settings.ApplySetting( app, vk.Key, vk.Value );
+ }
+
+ // var settings =
+ // this.LogInfo( JSON.StringifyObject( data ) );
+
+ // var resolvedApp = app ?? Unique.Get();
+
+ // var data = resolvedApp.GetAppSettingsData();
+
+ // var saveMap = new Dictionary();
+
+ // foreach ( var kv in data ){ saveMap[ kv.Key ] = kv.Value; }
+
+ // if ( writeDefaults )
+ // {
+ // app.settings.categories.ForEach(
+ // ( c )=>
+ // {
+ // c.settings.ForEach(
+ // ( appSetting )=>
+ // {
+ // if ( saveMap.ContainsKey( appSetting.id ) )
+ // {
+ // return;
+ // }
+
+ // saveMap[ appSetting.id ] = appSetting.GetDefaultValue();
+ // }
+ // );
+ // }
+ // );
+ // }
+
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/Actions/LoadAppSettings.cs.uid b/Runtime/App/Settings/Actions/LoadAppSettings.cs.uid
new file mode 100644
index 0000000..9939ad5
--- /dev/null
+++ b/Runtime/App/Settings/Actions/LoadAppSettings.cs.uid
@@ -0,0 +1 @@
+uid://bbm2x6as7wvc8
diff --git a/Runtime/App/Settings/Actions/SaveAppSettings.cs b/Runtime/App/Settings/Actions/SaveAppSettings.cs
new file mode 100644
index 0000000..ff123d8
--- /dev/null
+++ b/Runtime/App/Settings/Actions/SaveAppSettings.cs
@@ -0,0 +1,54 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class SaveAppSettings:Action
+ {
+ [Export]
+ public string savePath = "";
+
+ [Export]
+ public App app;
+
+ [Export]
+ public bool writeDefaults = true;
+
+ protected override void _OnTrigger()
+ {
+ var resolvedApp = app ?? Unique.Get();
+
+ var data = resolvedApp.GetAppSettingsData();
+
+ var saveMap = new Dictionary();
+
+ foreach ( var kv in data ){ saveMap[ kv.Key ] = kv.Value; }
+
+ if ( writeDefaults )
+ {
+ app.settings.categories.ForEach(
+ ( c )=>
+ {
+ c.settings.ForEach(
+ ( appSetting )=>
+ {
+ if ( saveMap.ContainsKey( appSetting.id ) )
+ {
+ return;
+ }
+
+ saveMap[ appSetting.id ] = appSetting.GetDefaultValue();
+ }
+ );
+ }
+ );
+ }
+
+ GDFilesSync.SaveJSON( savePath, saveMap );
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/Actions/SaveAppSettings.cs.uid b/Runtime/App/Settings/Actions/SaveAppSettings.cs.uid
new file mode 100644
index 0000000..ae56f40
--- /dev/null
+++ b/Runtime/App/Settings/Actions/SaveAppSettings.cs.uid
@@ -0,0 +1 @@
+uid://ctuyiqlpdd4m4
diff --git a/Runtime/App/Settings/AppSetting.cs b/Runtime/App/Settings/AppSetting.cs
index f550dec..3ea6cc1 100644
--- a/Runtime/App/Settings/AppSetting.cs
+++ b/Runtime/App/Settings/AppSetting.cs
@@ -5,13 +5,25 @@ using System.Collections.Generic;
namespace Rokojori
{
[Tool]
- [GlobalClass]
- public partial class AppSetting:Resource
+ [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/AppSetting.svg")]
+ public abstract partial class AppSetting:Resource
{
- public LocaleText GetName(){ return null; }
- public LocaleText GetInfo(){ return null; }
+ [Export]
+ public LocalizedString title;
+
+ [Export]
+ public LocalizedString info;
+
+ [Export]
+ public string id = "";
+
+ public abstract string GetDefaultValue();
+ public abstract void ApplyValue( App app );
+
+ public string GetValue( App app )
+ {
+ return app.GetSetting( id );
+ }
- public string Serialize(){ return null; }
- public void SetFromSerialized( string serializedValue ){}
}
}
\ No newline at end of file
diff --git a/Runtime/App/Settings/AppSettings.cs b/Runtime/App/Settings/AppSettings.cs
new file mode 100644
index 0000000..16aa652
--- /dev/null
+++ b/Runtime/App/Settings/AppSettings.cs
@@ -0,0 +1,35 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class AppSettings:Resource
+ {
+ [Export]
+ public AppSettingsCategory[] categories = [];
+
+ public void ApplySetting( App app, string key, string value )
+ {
+ app.SetSetting( key, value );
+ categories.ForEach(
+ ( c )=>
+ {
+ c.settings.ForEach(
+ ( s)=>
+ {
+ if ( s.id != key )
+ {
+ return;
+ }
+
+ s.ApplyValue( app );
+ }
+ );
+ }
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/AppSettings.cs.uid b/Runtime/App/Settings/AppSettings.cs.uid
new file mode 100644
index 0000000..7b35c9e
--- /dev/null
+++ b/Runtime/App/Settings/AppSettings.cs.uid
@@ -0,0 +1 @@
+uid://c5iowli8mkuoy
diff --git a/Runtime/App/Settings/AppSettingsCategory.cs b/Runtime/App/Settings/AppSettingsCategory.cs
new file mode 100644
index 0000000..823fe10
--- /dev/null
+++ b/Runtime/App/Settings/AppSettingsCategory.cs
@@ -0,0 +1,26 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/AppSettingsCategory.svg")]
+ public partial class AppSettingsCategory:Resource
+ {
+ [Export]
+ public LocalizedString title;
+
+ [Export]
+ public LocalizedString info;
+
+ [Export]
+ public Texture2D icon;
+
+ [Export]
+ public string id = "";
+
+ [Export]
+ public AppSetting[] settings;
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/AppSettingsCategory.cs.uid b/Runtime/App/Settings/AppSettingsCategory.cs.uid
new file mode 100644
index 0000000..f554b23
--- /dev/null
+++ b/Runtime/App/Settings/AppSettingsCategory.cs.uid
@@ -0,0 +1 @@
+uid://b3kfbhiwqt26o
diff --git a/Runtime/App/Settings/ListSetting/ListAppSetting.cs b/Runtime/App/Settings/ListSetting/ListAppSetting.cs
new file mode 100644
index 0000000..ade25d8
--- /dev/null
+++ b/Runtime/App/Settings/ListSetting/ListAppSetting.cs
@@ -0,0 +1,26 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public abstract partial class ListAppSetting:AppSetting
+ {
+ [Export]
+ public LocalizedString[] values = [];
+
+ [Export]
+ public int defaultValueIndex = 0;
+
+
+ public override string GetDefaultValue()
+ {
+ return JSON.StringifyObject( values[ defaultValueIndex ] );
+ }
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/ListSetting/ListAppSetting.cs.uid b/Runtime/App/Settings/ListSetting/ListAppSetting.cs.uid
new file mode 100644
index 0000000..870fcf0
--- /dev/null
+++ b/Runtime/App/Settings/ListSetting/ListAppSetting.cs.uid
@@ -0,0 +1 @@
+uid://cgo3gvs8q2oon
diff --git a/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs b/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs
new file mode 100644
index 0000000..f5564b8
--- /dev/null
+++ b/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs
@@ -0,0 +1,17 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class TestingListAppSetting:NumberAppSetting
+ {
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ RJLog.Log( "Test value is:", stringValue );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs.uid b/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs.uid
new file mode 100644
index 0000000..a7e9b3b
--- /dev/null
+++ b/Runtime/App/Settings/ListSetting/TestingListAppSettings.cs.uid
@@ -0,0 +1 @@
+uid://deyg247xjr2mu
diff --git a/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs b/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs
new file mode 100644
index 0000000..2f73a67
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs
@@ -0,0 +1,33 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class AudioBusSetting:NumberAppSetting
+ {
+ [Export]
+ public string busName = "";
+
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ var floatValue = RegexUtility.ParseFloat( stringValue );
+
+ var busIndex = AudioServer.GetBusIndex( busName );
+
+ if ( busIndex == -1 )
+ {
+ this.LogError( "Audio bus not found:", busName );
+ return;
+ }
+
+
+ AudioServer.SetBusVolumeLinear( busIndex, NormalizeValue( floatValue ) );
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs.uid b/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs.uid
new file mode 100644
index 0000000..63b9ef4
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs.uid
@@ -0,0 +1 @@
+uid://dji3qa0w7pbql
diff --git a/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs b/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs
new file mode 100644
index 0000000..202b2a7
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs
@@ -0,0 +1,48 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public abstract partial class NumberAppSetting:AppSetting
+ {
+ [Export]
+ public LocalizedString prefix;
+
+ [Export]
+ public float min = 0;
+
+ [Export]
+ public float max = 1;
+
+ [Export]
+ public float defaultValue = 0.5f;
+
+ [Export]
+ public int steps = -1;
+
+ [Export]
+ public float stepSize = -1;
+
+ [Export]
+ public UIFloatValueMode.DecimialPoints decimialPoints = UIFloatValueMode.DecimialPoints.Int;
+
+ [Export]
+ public LocalizedString suffix;
+
+ public float NormalizeValue( float v )
+ {
+ return MathX.Normalize( v, min, max );
+ }
+
+ public override string GetDefaultValue()
+ {
+ return JSON.StringifyObject( defaultValue );
+ }
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs.uid b/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs.uid
new file mode 100644
index 0000000..361fb3b
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/NumberAppSetting.cs.uid
@@ -0,0 +1 @@
+uid://bowpfiftk8xyq
diff --git a/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs b/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs
new file mode 100644
index 0000000..cb17349
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs
@@ -0,0 +1,25 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class ResolutionScalingSetting:NumberAppSetting
+ {
+ [Export]
+ public float userScaleToResolutionScale = 1f/100f;
+
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ var floatValue = RegexUtility.ParseFloat( stringValue );
+
+ var viewport = app.GetViewport();
+ viewport.Scaling3DScale = floatValue * userScaleToResolutionScale;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs.uid b/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs.uid
new file mode 100644
index 0000000..afa5600
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs.uid
@@ -0,0 +1 @@
+uid://ck1jjpy2gvkk4
diff --git a/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs b/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs
new file mode 100644
index 0000000..d0d943f
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs
@@ -0,0 +1,17 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class TestingNumberAppSetting:NumberAppSetting
+ {
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ RJLog.Log( "Test value is:", stringValue );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs.uid b/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs.uid
new file mode 100644
index 0000000..3ddf69f
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/TestingNumberAppSetting.cs.uid
@@ -0,0 +1 @@
+uid://en53sdt3fmlj
diff --git a/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs b/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs
new file mode 100644
index 0000000..c0561e1
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs
@@ -0,0 +1,30 @@
+
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class UIFontScaleSetting:NumberAppSetting
+ {
+ [Export]
+ public float userScaleToFontZoom = 1f/100f;
+
+ public override void ApplyValue( App app )
+ {
+ var stringValue = app.GetSetting( id );
+ var floatValue = RegexUtility.ParseFloat( stringValue );
+
+ var uis = Nodes.AllInScene();
+ uis.ForEach(
+ ( ui )=>
+ {
+ ui.fontZoom = userScaleToFontZoom * floatValue;
+ }
+ );
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs.uid b/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs.uid
new file mode 100644
index 0000000..4d945d0
--- /dev/null
+++ b/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs.uid
@@ -0,0 +1 @@
+uid://bj27trgy8poyy
diff --git a/Runtime/App/Settings/Presets/Audio/Audio Category.tres b/Runtime/App/Settings/Presets/Audio/Audio Category.tres
new file mode 100644
index 0000000..adc0c21
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Audio Category.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=7 format=3 uid="uid://cewutd6leekw6"]
+
+[ext_resource type="Script" uid="uid://b3kfbhiwqt26o" path="res://addons/rokojori_action_library/Runtime/App/Settings/AppSettingsCategory.cs" id="1_p3j14"]
+[ext_resource type="Resource" uid="uid://y3wia1vd1q68" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/Master AudioBus Setting.tres" id="2_1g5c8"]
+[ext_resource type="Resource" uid="uid://b24rm0ggveq8y" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/Music AudioBus Setting.tres" id="3_25bee"]
+[ext_resource type="Resource" uid="uid://da34tyk6d0l4b" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/SFX AudioBus Setting.tres" id="4_bgbml"]
+[ext_resource type="Resource" uid="uid://ckpuhu87npn2l" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/VOX AudioBus Setting.tres" id="5_pt3u0"]
+[ext_resource type="Resource" uid="uid://dn5qwc0t4llho" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/Audio Label.tres" id="6_imd2x"]
+
+[resource]
+script = ExtResource("1_p3j14")
+title = ExtResource("6_imd2x")
+id = "audio"
+settings = [ExtResource("2_1g5c8"), ExtResource("3_25bee"), ExtResource("4_bgbml"), ExtResource("5_pt3u0")]
+metadata/_custom_type_script = "uid://b3kfbhiwqt26o"
diff --git a/Runtime/App/Settings/Presets/Audio/Audio Label.tres b/Runtime/App/Settings/Presets/Audio/Audio Label.tres
new file mode 100644
index 0000000..8231638
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Audio Label.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=2 format=3 uid="uid://dn5qwc0t4llho"]
+
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="1_i1gki"]
+
+[resource]
+script = ExtResource("1_i1gki")
+en = "Audio"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Audio/Main Volume Label.tres b/Runtime/App/Settings/Presets/Audio/Main Volume Label.tres
new file mode 100644
index 0000000..0258f41
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Main Volume Label.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://ph4irn16ygj4"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_uqcpa"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_is7nr"]
+
+[sub_resource type="Resource" id="Resource_sjqn2"]
+script = ExtResource("1_uqcpa")
+code = 12
+content = "Gesamt Lautstärke"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_is7nr")
+en = "Main Volume"
+entries = [SubResource("Resource_sjqn2")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Audio/Master AudioBus Setting.tres b/Runtime/App/Settings/Presets/Audio/Master AudioBus Setting.tres
new file mode 100644
index 0000000..afc3b68
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Master AudioBus Setting.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="AudioBusSetting" load_steps=4 format=3 uid="uid://y3wia1vd1q68"]
+
+[ext_resource type="Script" uid="uid://dji3qa0w7pbql" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs" id="1_og01v"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="2_j708b"]
+[ext_resource type="Resource" uid="uid://ph4irn16ygj4" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/Main Volume Label.tres" id="3_fm56v"]
+
+[resource]
+script = ExtResource("1_og01v")
+busName = "Master"
+max = 100.0
+defaultValue = 50.0
+suffix = ExtResource("2_j708b")
+title = ExtResource("3_fm56v")
+id = "mainVolume"
+metadata/_custom_type_script = "uid://dji3qa0w7pbql"
diff --git a/Runtime/App/Settings/Presets/Audio/Music AudioBus Setting.tres b/Runtime/App/Settings/Presets/Audio/Music AudioBus Setting.tres
new file mode 100644
index 0000000..544229a
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Music AudioBus Setting.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="AudioBusSetting" load_steps=4 format=3 uid="uid://b24rm0ggveq8y"]
+
+[ext_resource type="Script" uid="uid://dji3qa0w7pbql" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs" id="1_clrqb"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="2_bhjsn"]
+[ext_resource type="Resource" uid="uid://dldn6o3wvxfdc" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/Music Label.tres" id="3_vjtyo"]
+
+[resource]
+script = ExtResource("1_clrqb")
+busName = "Music"
+max = 100.0
+defaultValue = 50.0
+suffix = ExtResource("2_bhjsn")
+title = ExtResource("3_vjtyo")
+id = "musicVolume"
+metadata/_custom_type_script = "uid://dji3qa0w7pbql"
diff --git a/Runtime/App/Settings/Presets/Audio/Music Label.tres b/Runtime/App/Settings/Presets/Audio/Music Label.tres
new file mode 100644
index 0000000..8329ff1
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/Music Label.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://dldn6o3wvxfdc"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_1ce4q"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_dqscy"]
+
+[sub_resource type="Resource" id="Resource_sjqn2"]
+script = ExtResource("1_1ce4q")
+code = 12
+content = "Musik Lautstärke"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_dqscy")
+en = "Music Volume"
+entries = [SubResource("Resource_sjqn2")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Audio/SFX AudioBus Setting.tres b/Runtime/App/Settings/Presets/Audio/SFX AudioBus Setting.tres
new file mode 100644
index 0000000..e42c2ac
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/SFX AudioBus Setting.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="AudioBusSetting" load_steps=4 format=3 uid="uid://da34tyk6d0l4b"]
+
+[ext_resource type="Script" uid="uid://dji3qa0w7pbql" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs" id="1_04sn2"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="2_37v0c"]
+[ext_resource type="Resource" uid="uid://ccrwni0het7rl" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/SFX Label.tres" id="3_6duf0"]
+
+[resource]
+script = ExtResource("1_04sn2")
+busName = "SFX"
+max = 100.0
+defaultValue = 50.0
+suffix = ExtResource("2_37v0c")
+title = ExtResource("3_6duf0")
+id = "sfxVolume"
+metadata/_custom_type_script = "uid://dji3qa0w7pbql"
diff --git a/Runtime/App/Settings/Presets/Audio/SFX Label.tres b/Runtime/App/Settings/Presets/Audio/SFX Label.tres
new file mode 100644
index 0000000..cd6a373
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/SFX Label.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://ccrwni0het7rl"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_3r5aw"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_voo1w"]
+
+[sub_resource type="Resource" id="Resource_sjqn2"]
+script = ExtResource("1_3r5aw")
+code = 12
+content = "SFX Lautstärke"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_voo1w")
+en = "SFX Volume"
+entries = [SubResource("Resource_sjqn2")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Audio/VOX AudioBus Setting.tres b/Runtime/App/Settings/Presets/Audio/VOX AudioBus Setting.tres
new file mode 100644
index 0000000..8573416
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/VOX AudioBus Setting.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="AudioBusSetting" load_steps=4 format=3 uid="uid://ckpuhu87npn2l"]
+
+[ext_resource type="Script" uid="uid://dji3qa0w7pbql" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/AudioBusSetting.cs" id="1_paelx"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="2_s0edn"]
+[ext_resource type="Resource" uid="uid://cg2e4yctcmhgy" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Audio/VOX Label.tres" id="3_e4vca"]
+
+[resource]
+script = ExtResource("1_paelx")
+busName = "Vox"
+max = 100.0
+defaultValue = 50.0
+suffix = ExtResource("2_s0edn")
+title = ExtResource("3_e4vca")
+id = "voxVolume"
+metadata/_custom_type_script = "uid://dji3qa0w7pbql"
diff --git a/Runtime/App/Settings/Presets/Audio/VOX Label.tres b/Runtime/App/Settings/Presets/Audio/VOX Label.tres
new file mode 100644
index 0000000..7c62a4a
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Audio/VOX Label.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://cg2e4yctcmhgy"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_jpt7d"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_xqj8d"]
+
+[sub_resource type="Resource" id="Resource_sjqn2"]
+script = ExtResource("1_jpt7d")
+code = 12
+content = "Sprach Lautstärke"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_xqj8d")
+en = "Voice Volume"
+entries = [SubResource("Resource_sjqn2")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres
new file mode 100644
index 0000000..a79fd9b
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Graphics/Graphics Category.tres
@@ -0,0 +1,13 @@
+[gd_resource type="Resource" script_class="AppSettingsCategory" load_steps=5 format=3 uid="uid://4iqfk01k81nc"]
+
+[ext_resource type="Script" uid="uid://b3kfbhiwqt26o" path="res://addons/rokojori_action_library/Runtime/App/Settings/AppSettingsCategory.cs" id="1_g7ii0"]
+[ext_resource type="Resource" uid="uid://0itt52s066qp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres" id="2_xi6qd"]
+[ext_resource type="Resource" uid="uid://bpfrw7y8jx2wp" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres" id="3_g7ii0"]
+[ext_resource type="Resource" uid="uid://cec7500hcn1e0" path="res://addons/rokojori_action_library/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres" id="3_xi6qd"]
+
+[resource]
+script = ExtResource("1_g7ii0")
+title = ExtResource("3_g7ii0")
+id = "graphics"
+settings = [ExtResource("3_xi6qd"), ExtResource("2_xi6qd")]
+metadata/_custom_type_script = "uid://b3kfbhiwqt26o"
diff --git a/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres b/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres
new file mode 100644
index 0000000..9ad5bda
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Graphics/Graphics Label.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://bpfrw7y8jx2wp"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_q1oe3"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_s1eae"]
+
+[sub_resource type="Resource" id="Resource_133rj"]
+script = ExtResource("1_q1oe3")
+content = "Grafik"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_s1eae")
+en = "Graphics"
+entries = [SubResource("Resource_133rj")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Graphics/Resolution Scale Label.tres b/Runtime/App/Settings/Presets/Graphics/Resolution Scale Label.tres
new file mode 100644
index 0000000..faa134c
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Graphics/Resolution Scale Label.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=4 format=3 uid="uid://ckevpvf37gsu0"]
+
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="1_jucsw"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_d7iky"]
+
+[sub_resource type="Resource" id="Resource_0xy14"]
+script = ExtResource("1_jucsw")
+code = 12
+content = "Auflösungs-Skalierung"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[resource]
+script = ExtResource("2_d7iky")
+en = "Resolution Scale"
+entries = [SubResource("Resource_0xy14")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres b/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres
new file mode 100644
index 0000000..65085d4
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Graphics/Resolution Scale Setting.tres
@@ -0,0 +1,33 @@
+[gd_resource type="Resource" script_class="ResolutionScalingSetting" load_steps=7 format=3 uid="uid://cec7500hcn1e0"]
+
+[ext_resource type="Script" uid="uid://ck1jjpy2gvkk4" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/ResolutionScalingSetting.cs" id="1_1x5jf"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="2_irwt0"]
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="3_831il"]
+
+[sub_resource type="Resource" id="Resource_4ajq1"]
+script = ExtResource("2_irwt0")
+en = "%"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="Resource" id="Resource_0xy14"]
+script = ExtResource("3_831il")
+code = 12
+content = "Auflösungs-Skalierung"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[sub_resource type="Resource" id="Resource_7auxo"]
+script = ExtResource("2_irwt0")
+en = "Resolution Scale"
+entries = [SubResource("Resource_0xy14")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[resource]
+script = ExtResource("1_1x5jf")
+min = 10.0
+max = 150.0
+defaultValue = 100.0
+stepSize = 5.0
+suffix = SubResource("Resource_4ajq1")
+title = SubResource("Resource_7auxo")
+id = "resolutionScale"
+metadata/_custom_type_script = "uid://ck1jjpy2gvkk4"
diff --git a/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres b/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres
new file mode 100644
index 0000000..cce2c7b
--- /dev/null
+++ b/Runtime/App/Settings/Presets/Graphics/UI Scale Setting.tres
@@ -0,0 +1,28 @@
+[gd_resource type="Resource" script_class="UIFontScaleSetting" load_steps=7 format=3 uid="uid://0itt52s066qp"]
+
+[ext_resource type="Script" uid="uid://bj27trgy8poyy" path="res://addons/rokojori_action_library/Runtime/App/Settings/NumberSetting/UIFontScaleSetting.cs" id="1_5l5ka"]
+[ext_resource type="Resource" uid="uid://osfjg5u2jb4f" path="res://addons/rokojori_action_library/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres" id="2_1r4kl"]
+[ext_resource type="Script" uid="uid://b584767duemqk" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleTextEntry.cs" id="3_ta5nt"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="4_mrecg"]
+
+[sub_resource type="Resource" id="Resource_cviq7"]
+script = ExtResource("3_ta5nt")
+code = 12
+content = "UI Skalierung"
+metadata/_custom_type_script = "uid://b584767duemqk"
+
+[sub_resource type="Resource" id="Resource_avygq"]
+script = ExtResource("4_mrecg")
+en = "UI Scale"
+entries = [SubResource("Resource_cviq7")]
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[resource]
+script = ExtResource("1_5l5ka")
+min = 75.0
+max = 150.0
+defaultValue = 100.0
+suffix = ExtResource("2_1r4kl")
+title = SubResource("Resource_avygq")
+id = "uiScale"
+metadata/_custom_type_script = "uid://bj27trgy8poyy"
diff --git a/Runtime/Audio/Presets/Default-Audio-Channel-Layout.tres b/Runtime/Audio/Presets/Default-Audio-Channel-Layout.tres
new file mode 100644
index 0000000..174186e
--- /dev/null
+++ b/Runtime/Audio/Presets/Default-Audio-Channel-Layout.tres
@@ -0,0 +1,21 @@
+[gd_resource type="AudioBusLayout" format=3 uid="uid://b588mdjuo56ut"]
+
+[resource]
+bus/1/name = &"Music"
+bus/1/solo = false
+bus/1/mute = false
+bus/1/bypass_fx = false
+bus/1/volume_db = 0.0
+bus/1/send = &"Master"
+bus/2/name = &"SFX"
+bus/2/solo = false
+bus/2/mute = false
+bus/2/bypass_fx = false
+bus/2/volume_db = 0.0
+bus/2/send = &"Master"
+bus/3/name = &"Vox"
+bus/3/solo = false
+bus/3/mute = false
+bus/3/bypass_fx = false
+bus/3/volume_db = 0.0
+bus/3/send = &"Master"
diff --git a/Runtime/Cameras/CameraTypes/FirstPersonCamera/FirstPersonCamera.cs b/Runtime/Cameras/CameraTypes/FirstPersonCamera/FirstPersonCamera.cs
index 6208a76..0ddd7cd 100644
--- a/Runtime/Cameras/CameraTypes/FirstPersonCamera/FirstPersonCamera.cs
+++ b/Runtime/Cameras/CameraTypes/FirstPersonCamera/FirstPersonCamera.cs
@@ -12,6 +12,12 @@ namespace Rokojori
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/1stPersonCamera.svg") ]
public partial class FirstPersonCamera:VirtualCamera
{
+ [Export]
+ public float fov = 60;
+ public override float GetCameraFOV()
+ {
+ return fov;
+ }
}
}
\ No newline at end of file
diff --git a/Runtime/Cameras/CameraTypes/FollowCamera/FollowCamera3D.cs b/Runtime/Cameras/CameraTypes/FollowCamera/FollowCamera3D.cs
index 758f24e..033dc0c 100644
--- a/Runtime/Cameras/CameraTypes/FollowCamera/FollowCamera3D.cs
+++ b/Runtime/Cameras/CameraTypes/FollowCamera/FollowCamera3D.cs
@@ -21,6 +21,14 @@ namespace Rokojori
[Export]
public float rotationSmoothingCoefficient = 0.1f;
+ [Export]
+ public float fov = 60;
+
+ public override float GetCameraFOV()
+ {
+ return fov;
+ }
+
Smoother smoother = new Smoother();
public override void _Process( double delta )
diff --git a/Runtime/Cameras/CameraTypes/LookAtCamera/LookAtCamera.cs b/Runtime/Cameras/CameraTypes/LookAtCamera/LookAtCamera.cs
index 9ffda99..2128658 100644
--- a/Runtime/Cameras/CameraTypes/LookAtCamera/LookAtCamera.cs
+++ b/Runtime/Cameras/CameraTypes/LookAtCamera/LookAtCamera.cs
@@ -15,12 +15,21 @@ namespace Rokojori
[Export]
public Node3D target;
+ [Export]
+ public float fov = 60;
+
+ public override float GetCameraFOV()
+ {
+ return fov;
+ }
+
[Export]
public Smoothing smoothing;
[Export]
public TimeLine timeLine;
+
[ExportToolButton( "Copy Camera Pose With Target")]
public Callable copyCameraPoseWithTargetButton => Callable.From(
()=>
diff --git a/Runtime/Cameras/CameraTypes/StrategyTopDownCamera/StrategyTopDownCamera.cs b/Runtime/Cameras/CameraTypes/StrategyTopDownCamera/StrategyTopDownCamera.cs
index 9446cf2..d034d68 100644
--- a/Runtime/Cameras/CameraTypes/StrategyTopDownCamera/StrategyTopDownCamera.cs
+++ b/Runtime/Cameras/CameraTypes/StrategyTopDownCamera/StrategyTopDownCamera.cs
@@ -122,7 +122,15 @@ namespace Rokojori
[Export]
public float zoomSmoothingCoefficient = 0.1f;
- Smoother smoother = new Smoother();
+ Smoother smoother = new Smoother();
+
+ [Export]
+ public float fov = 60;
+
+ public override float GetCameraFOV()
+ {
+ return fov;
+ }
public override void _Process( double delta )
{
diff --git a/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCamera.cs b/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCamera.cs
index a125aa1..15889d8 100644
--- a/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCamera.cs
+++ b/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCamera.cs
@@ -46,10 +46,10 @@ namespace Rokojori
void _ProcessCamera( double gameDelta )
{
- if ( Engine.IsEditorHint() )
- {
- return;
- }
+ // if ( Engine.IsEditorHint() )
+ // {
+ // return;
+ // }
if ( target == null )
{
@@ -93,14 +93,53 @@ namespace Rokojori
var smoothedPitch = Smoothing.Apply( settings.pitchSmoothing, pitch, delta );
- var distance = settings.distanceForPitch.Sample( MathX.NormalizeClamped( pitch, settings.minPitch, settings.maxPitch ) ) * settings.distanceScale;
+ var pitchState = MathX.NormalizeClamped( pitch, settings.minPitch, settings.maxPitch );
+ var distance = settings.distanceForPitch.Sample( pitchState ) * settings.distanceScale;
+ FOV = settings.fovOffset + ( settings.fovForPitch?.Sample( pitchState ) ?? 0f );
- GlobalPosition = targetPosition + Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward * distance;
+ cameraPosition = targetPosition + Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward * distance;
- LookAt( targetPosition, Vector3.Up, true );
+ cameraForward = ( targetPosition - cameraPosition ).Normalized();
+ // LookAt( targetPosition, Vector3.Up, true );
- GlobalPosition += this.GetOrientationBasedGlobalOffset( settings.offset );
+ var pitchOffset = settings.offset;
+
+ pitchOffset.X += settings.offsetXForPitch?.Sample( pitchState ) ?? 0f;
+ pitchOffset.Y += settings.offsetYForPitch?.Sample( pitchState ) ?? 0f;
+ pitchOffset.Z += settings.offsetZForPitch?.Sample( pitchState ) ?? 0f;
+ var basis = Basis.LookingAt( cameraForward, Vector3.Up, true );
+ cameraPosition += basis.ToGlobalDirection( pitchOffset );
+
+ cameraRotation = new Quaternion( basis );
+ }
+
+ [Export,ReadOnly]
+ public Vector3 cameraPosition;
+
+ public override Vector3 GetCameraPosition()
+ {
+ return cameraPosition;
+ }
+
+ [Export,ReadOnly]
+ public Vector3 cameraForward;
+
+ [Export,ReadOnly]
+ public Quaternion cameraRotation;
+
+ public override Quaternion GetCameraRotation()
+ {
+ return cameraRotation;
+ }
+
+
+ [Export,ReadOnly]
+ public float FOV;
+
+ public override float GetCameraFOV()
+ {
+ return FOV;
}
diff --git a/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCameraSettings.cs b/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCameraSettings.cs
index b3fcfa2..b41b1c7 100644
--- a/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCameraSettings.cs
+++ b/Runtime/Cameras/CameraTypes/ThirdPersonCamera/ThirdPersonCameraSettings.cs
@@ -11,8 +11,7 @@ namespace Rokojori
[Export]
public Smoothing targetFollowSmoothing = new FrameSmoothing();
- [Export]
- public Vector3 offset = Vector3.Zero;
+
[Export]
public Smoothing yawSmoothing = new FrameSmoothing();
@@ -39,12 +38,37 @@ namespace Rokojori
[ExportGroup("Distance")]
- [Export]
- public Curve distanceForPitch = MathX.Curve( 1, 1 );
[Export]
public float distanceScale = 1;
+ [Export]
+ public Curve distanceForPitch = MathX.Curve( 1, 1 );
+
+
+
+ [ExportGroup("Offset")]
+
+ [Export]
+ public Vector3 offset = Vector3.Zero;
+
+ [Export]
+ public Curve offsetXForPitch = MathX.Curve( 0, 0 ).WithValueRange( -10, 10 );
+
+ [Export]
+ public Curve offsetYForPitch = MathX.Curve( 0, 0 ).WithValueRange( -10, 10 );
+
+ [Export]
+ public Curve offsetZForPitch = MathX.Curve( 0, 0 ).WithValueRange( -10, 10 );
+
+ [ExportGroup("FOV")]
+
+ [Export]
+ public Curve fovForPitch = MathX.Curve( 0, 0 ).WithValueRange( -10, 10 );
+
+ [Export]
+ public float fovOffset = 60;
+
public float GetNormalizedPitch( float pitch )
{
@@ -53,10 +77,27 @@ namespace Rokojori
public ThirdPersonCameraData GetActiveDeviceData()
{
+ if ( deviceData == null )
+ {
+ return null;
+ }
+
var sm = Unique.Get();
+ if ( sm == null )
+ {
+ return deviceData[ 0 ];
+ }
+
+
var lastActive = sm.lastActiveDevice;
+ if ( lastActive == null )
+ {
+ return deviceData[ 0 ];
+ }
+
+
var lastActiveData = deviceData.FindNonNull( d => d.deviceSelector.Selects( lastActive ) );
return lastActiveData != null ? lastActiveData : deviceData[ 0 ];
diff --git a/Runtime/Cameras/EditorCamera/EditorCamera.cs b/Runtime/Cameras/EditorCamera/EditorCamera.cs
index 2ed23f7..b472a8e 100644
--- a/Runtime/Cameras/EditorCamera/EditorCamera.cs
+++ b/Runtime/Cameras/EditorCamera/EditorCamera.cs
@@ -38,6 +38,13 @@ namespace Rokojori
[Export]
public float maxDistance = 200f;
+ [Export]
+ public float fov = 60;
+
+ public override float GetCameraFOV()
+ {
+ return fov;
+ }
[Export( PropertyHint.Range, "0,600")]
public Smoothing zoomSmoothing;
diff --git a/Runtime/Cameras/VirtualCamera.cs b/Runtime/Cameras/VirtualCamera.cs
index f9daf57..11406b9 100644
--- a/Runtime/Cameras/VirtualCamera.cs
+++ b/Runtime/Cameras/VirtualCamera.cs
@@ -10,10 +10,8 @@ namespace Rokojori
{
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/VirtualCamera3D.svg") ]
- public partial class VirtualCamera:Node3D
+ public abstract partial class VirtualCamera:Node3D
{
- [Export]
- public float fov = 60;
[Export]
public bool inputEnabled = true;
@@ -31,20 +29,18 @@ namespace Rokojori
}
);
- public Vector3 GetCameraPosition()
+ public virtual Vector3 GetCameraPosition()
{
return GlobalPosition;
}
- public Quaternion GetCameraRotation()
+ public virtual Quaternion GetCameraRotation()
{
return GlobalBasis.GetRotationQuaternion();
}
- public float GetCameraFOV()
- {
- return fov;
- }
+ public abstract float GetCameraFOV();
+
}
}
\ No newline at end of file
diff --git a/Runtime/Events/EventSlot.cs b/Runtime/Events/EventSlot.cs
index c879ce0..71d8cda 100644
--- a/Runtime/Events/EventSlot.cs
+++ b/Runtime/Events/EventSlot.cs
@@ -96,7 +96,7 @@ namespace Rokojori
if ( _removals.Count > 0 )
{
- Lists.RemoveRange( _actions, _removals );
+ Lists.RemoveList( _actions, _removals );
// _removals.ForEach(
// r =>
diff --git a/Runtime/Files/GDFilesSync.cs b/Runtime/Files/GDFilesSync.cs
new file mode 100644
index 0000000..c3b37e0
--- /dev/null
+++ b/Runtime/Files/GDFilesSync.cs
@@ -0,0 +1,44 @@
+
+using System;
+using Godot;
+
+namespace Rokojori;
+
+public class GDFilesSync
+{
+ public static void SaveJSON( string path, object data )
+ {
+ SaveUTF8( path, JSON.StringifyObject( data ) );
+ }
+
+ public static T LoadJSON( string path ) where T:new()
+ {
+ return JSON.ParseObject( LoadUTF8( path ) );
+ }
+
+ public static void SaveUTF8( string path, string data )
+ {
+ using var fileAccess = FileAccess.Open( path, FileAccess.ModeFlags.Write );
+ fileAccess.StoreString( data );
+ fileAccess.Close();
+ }
+
+ public static string LoadUTF8( string path )
+ {
+ using var fileAccess = FileAccess.Open( path, FileAccess.ModeFlags.Read );
+ return fileAccess.GetAsText( );
+ }
+
+ public static void SaveBytes( string path, byte[] data )
+ {
+ using var fileAccess = FileAccess.Open( path, FileAccess.ModeFlags.Write );
+ fileAccess.StoreBuffer( data );
+ fileAccess.Close();
+ }
+
+ public static byte[] LoadBytes( string path )
+ {
+ using var fileAccess = FileAccess.Open( path, FileAccess.ModeFlags.Read );
+ return fileAccess.GetBuffer( (long) fileAccess.GetLength() );
+ }
+}
diff --git a/Runtime/Files/GDFilesSync.cs.uid b/Runtime/Files/GDFilesSync.cs.uid
new file mode 100644
index 0000000..088e6a1
--- /dev/null
+++ b/Runtime/Files/GDFilesSync.cs.uid
@@ -0,0 +1 @@
+uid://d08fev7gh8nfe
diff --git a/Runtime/Godot/Extensions/BasisExtensions.cs b/Runtime/Godot/Extensions/BasisExtensions.cs
index 5731967..f5779c9 100644
--- a/Runtime/Godot/Extensions/BasisExtensions.cs
+++ b/Runtime/Godot/Extensions/BasisExtensions.cs
@@ -7,6 +7,26 @@ namespace Rokojori
{
public static class BasisExtensions
{
+ public static Vector3 Forward( this Basis self )
+ {
+ return -self.Z;
+ }
+
+ public static Vector3 Right( this Basis self )
+ {
+ return self.X;
+ }
+
+ public static Vector3 Up( this Basis self )
+ {
+ return self.Y;
+ }
+
+ public static Vector3 ToGlobalDirection( this Basis self, Vector3 direction )
+ {
+ return self.Right() * direction.X + self.Up() * direction.Y + self.Forward() * direction;
+ }
+
public static bool IsValid( this Basis self )
{
return self.Row0.IsValid() && self.Row1.IsValid() && self.Row2.IsValid();
diff --git a/Runtime/Godot/Extensions/NodeExtensions.cs b/Runtime/Godot/Extensions/NodeExtensions.cs
index 470a79d..ed163db 100644
--- a/Runtime/Godot/Extensions/NodeExtensions.cs
+++ b/Runtime/Godot/Extensions/NodeExtensions.cs
@@ -4,12 +4,62 @@ using System.Collections.Generic;
using System;
using System.Threading.Tasks;
using System.Reflection;
-using Microsoft.VisualBasic;
namespace Rokojori
{
public static class NodeExtensions
{
+ public static void CallDeferred( this Node node, System.Action action )
+ {
+ Callable.From( action ).CallDeferred();
+ }
+
+
+ public static int GetChildCountOfType( this Node node )
+ {
+ var count = 0;
+
+ for ( int i = 0; i < node.GetChildCount(); i++ )
+ {
+ if ( node.GetChild( i ) is N )
+ {
+ count ++;
+ }
+ }
+
+ return count;
+ }
+
+ public static void EnsureChildCount( this Node node, int neededChildCount, Action callback = null ) where N:Node,new()
+ {
+ var segments = neededChildCount;
+ var ownCount = node.GetChildCount();
+
+ if ( ownCount == segments )
+ {
+ return;
+ }
+
+
+ if ( ownCount > segments )
+ {
+ node.DestroyChildrenRange( segments, ownCount - segments );
+
+ ownCount = segments;
+ }
+
+ for ( int i = ownCount; i < segments; i++ )
+ {
+ var n = node.CreateChild();
+
+ if ( callback != null )
+ {
+ callback( n );
+ }
+ }
+
+ }
+
public static T GetNextSiblingOrChild( this Node node ) where T:Node
{
var index = node.GetIndex();
diff --git a/Runtime/Godot/Extensions/QuaternionExtensions.cs b/Runtime/Godot/Extensions/QuaternionExtensions.cs
index 8c16b21..4c838c4 100644
--- a/Runtime/Godot/Extensions/QuaternionExtensions.cs
+++ b/Runtime/Godot/Extensions/QuaternionExtensions.cs
@@ -7,6 +7,9 @@ namespace Rokojori
{
public static class QuaternionExtensions
{
-
+ public static Quaternion From( Vector3 forward, Vector3 up )
+ {
+ return Math3D.LookRotation( forward, up );
+ }
}
}
\ No newline at end of file
diff --git a/Runtime/Godot/NodeStateConfiguration.cs b/Runtime/Godot/NodeStateConfiguration.cs
index 65af486..0e42da1 100644
--- a/Runtime/Godot/NodeStateConfiguration.cs
+++ b/Runtime/Godot/NodeStateConfiguration.cs
@@ -29,6 +29,36 @@ namespace Rokojori
[Export]
public Node.ProcessModeEnum processMode;
+
+
+ public static NodeStateConfiguration All( Trillean value )
+ {
+ var config = new NodeStateConfiguration();
+
+ config.processEnabled = value;
+ config.inputEnabled = value;
+ config.physicsEnabled = value;
+ config.signalsEnabled = value;
+ config.visible = value;
+
+ config.setProcessMode = true;
+
+ config.processMode = Trillean.True == value ? Node.ProcessModeEnum.Inherit : Node.ProcessModeEnum.Disabled;
+
+ return config;
+ }
+
+ public static NodeStateConfiguration AllOn()
+ {
+ return All( Trillean.True );
+ }
+
+ public static NodeStateConfiguration AllOff()
+ {
+ return All( Trillean.False );
+ }
+
+
}
}
\ No newline at end of file
diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs
index 876c14b..b2cdd0e 100644
--- a/Runtime/Godot/Nodes.cs
+++ b/Runtime/Godot/Nodes.cs
@@ -371,7 +371,7 @@ namespace Rokojori
}
- public static T CreateChild( this Node parent, PackedScene scene, string name = null ) where T:Node,new()
+ public static T CreateChild( this Node parent, PackedScene scene, string name = null, bool editable = true ) where T:Node,new()
{
var instance = scene.Instantiate();
@@ -383,6 +383,11 @@ namespace Rokojori
instance.Name = name;
}
+ if ( editable )
+ {
+ parent.SetEditableInstance( instance, true );
+ }
+
return instance;
}
@@ -673,6 +678,31 @@ namespace Rokojori
RemoveAndDeleteChildren( parent, includeInternal );
}
+ public static void DestroyChildAt( this Node parent, int index, bool includeInternal = false, bool queue = true )
+ {
+ var node = parent.GetChild( index, includeInternal );
+ parent.RemoveChild( node );
+
+ if ( ! queue )
+ {
+ node.Free();
+ }
+ else
+ {
+ node.QueueFree();
+ }
+ }
+
+ public static void DestroyChildrenRange( this Node parent, int startIndex, int range, bool includeInternal = false, bool queue = true )
+ {
+ parent.LogInfo( startIndex, range, parent.GetChildCount() );
+ for ( int i = 0; i < range; i++ )
+ {
+ var index = ( range - 1 ) - i;
+ parent.DestroyChildAt( index, includeInternal, queue );
+ }
+ }
+
public static void RemoveAndDeleteChildren( Node parent, bool includeInternal = false, bool queue = true )
{
if ( parent == null )
diff --git a/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres b/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres
new file mode 100644
index 0000000..2e46c70
--- /dev/null
+++ b/Runtime/Localization/DataBase/Numberic/Percantage-Suffix.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="LocaleText" load_steps=2 format=3 uid="uid://osfjg5u2jb4f"]
+
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="1_khv63"]
+
+[resource]
+script = ExtResource("1_khv63")
+en = "%"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
diff --git a/Runtime/Math/Geometry/Box3.cs b/Runtime/Math/Geometry/Box3.cs
index 08d3b67..8303b8b 100644
--- a/Runtime/Math/Geometry/Box3.cs
+++ b/Runtime/Math/Geometry/Box3.cs
@@ -31,6 +31,12 @@ namespace Rokojori
max += translation;
}
+ public void Extend( float size )
+ {
+ min -= Vector3.One * size / 2f;
+ max += Vector3.One * size / 2f;
+ }
+
public static Box3 FromPositionAndScale( Vector3 position, Vector3 scale )
{
var max = scale * 0.5f;
diff --git a/Runtime/Math/Geometry/Pose.cs b/Runtime/Math/Geometry/Pose.cs
index 31e4122..7252c67 100644
--- a/Runtime/Math/Geometry/Pose.cs
+++ b/Runtime/Math/Geometry/Pose.cs
@@ -177,6 +177,24 @@ namespace Rokojori
return p;
}
+ public static Pose From( Vector3 position, Vector3 forward )
+ {
+ var p = new Pose();
+ p.position = position;
+ p.LookAt( forward, Vector3.Up );
+
+ return p;
+ }
+
+ public static Pose From( Vector3 position, Vector3 forward, Vector3 up )
+ {
+ var p = new Pose();
+ p.position = position;
+ p.LookAt( forward, up );
+
+ return p;
+ }
+
public static Pose InverseFrom( Node3D node3D )
{
var p = new Pose();
diff --git a/Runtime/Math/Math2D.cs b/Runtime/Math/Math2D.cs
index 1c7129a..9bcbed0 100644
--- a/Runtime/Math/Math2D.cs
+++ b/Runtime/Math/Math2D.cs
@@ -108,6 +108,11 @@ namespace Rokojori
return new Vector2( x, y );
}
+ public static Vector2 CircleDegrees( float degrees, float size = 1 )
+ {
+ return Circle( MathX.DegreesToRadians * degrees, size );
+ }
+
public static Vector2 Fract( Vector2 a )
{
return new Vector2( MathX.Fract( a.X ), MathX.Fract( a.Y ) );
diff --git a/Runtime/Math/Math3D.cs b/Runtime/Math/Math3D.cs
index 77a5212..f68cf2c 100644
--- a/Runtime/Math/Math3D.cs
+++ b/Runtime/Math/Math3D.cs
@@ -595,14 +595,8 @@ namespace Rokojori
{
return Quaternion.Identity;
}
-
- var t = new Transform3D();
- t.Basis = Basis.Identity;
- t.Origin = Vector3.Zero;
- t = t.LookingAt( direction, up, useModelFront );
-
- return t.Basis.GetRotationQuaternion();
+ return Basis.LookingAt( direction, up, useModelFront ).GetRotationQuaternion();
}
public static Vector3 LerpComponents( Vector3 a, Vector3 b, Vector3 t )
diff --git a/Runtime/Math/MathX.cs b/Runtime/Math/MathX.cs
index 2f51c30..f12c662 100644
--- a/Runtime/Math/MathX.cs
+++ b/Runtime/Math/MathX.cs
@@ -79,6 +79,11 @@ namespace Rokojori
return Mathf.Lerp( bottom, top, uvw.Z );
}
+ public static float LerpClamped( float min, float max, float value )
+ {
+ return Mathf.Clamp( Mathf.Lerp( min, max, value ), min, max );
+ }
+
public static float Fract( float value )
{
return value - Mathf.Floor( value );
diff --git a/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs b/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs
new file mode 100644
index 0000000..0116e25
--- /dev/null
+++ b/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs
@@ -0,0 +1,30 @@
+using System.Collections;
+using System.Collections.Generic;
+using Godot;
+using System;
+
+
+
+namespace Rokojori
+{
+ [Tool]
+ [GlobalClass]
+ public partial class CylinderGenerator:MeshGeneratorType
+ {
+ [Export]
+ public int vertices = 16;
+
+ [Export]
+ public int subdivisions = 5;
+
+ protected override string GetCachePath()
+ {
+ return "CylinderGenerator-" + vertices + "-x-"+ subdivisions;
+ }
+
+ protected override MeshGeometry _GenerateMeshGeometry()
+ {
+ return MeshGeometry.Cylinder( vertices, subdivisions, 0f, 1f );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs.uid b/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs.uid
new file mode 100644
index 0000000..884a401
--- /dev/null
+++ b/Runtime/Procedural/Mesh/Generator/CylinderGenerator.cs.uid
@@ -0,0 +1 @@
+uid://8bb4srk0y7bi
diff --git a/Runtime/Procedural/Mesh/MeshGeometry.cs b/Runtime/Procedural/Mesh/MeshGeometry.cs
index 07e6ebd..ebb23bf 100644
--- a/Runtime/Procedural/Mesh/MeshGeometry.cs
+++ b/Runtime/Procedural/Mesh/MeshGeometry.cs
@@ -873,6 +873,65 @@ namespace Rokojori
return mg;
}
+ public static MeshGeometry Cylinder( int vertices, int divisions, float zMin, float zMax )
+ {
+ var mg = new MeshGeometry();
+ var normalizeDivisions = 1f / divisions;
+
+ for ( int d = 0; d < divisions; d++ )
+ {
+ var v0 = d * normalizeDivisions;
+ var v1 = ( d + 1f ) * normalizeDivisions;
+
+ var z0 = Mathf.Lerp( zMin, zMax, v0 );
+ var z1 = Mathf.Lerp( zMin, zMax, v1 );
+
+ var normalizeVertices = 1f / vertices;
+
+ for ( int i = 0; i < vertices; i++ )
+ {
+ var u0 = i * normalizeVertices;
+ var u1 = ( i + 1 ) * normalizeVertices;
+
+ var angle0 = u0 * 360f;
+ var angle1 = u1 * 360f;
+
+ var pos0 = Math2D.CircleDegrees( angle0 ).To3DXY();
+ var pos1 = Math2D.CircleDegrees( angle1 ).To3DXY();
+
+ var pos0z0 = pos0; pos0z0.Z = z0;
+ var pos0z1 = pos0; pos0z1.Z = z1;
+
+ var pos1z0 = pos1; pos1z0.Z = z0;
+ var pos1z1 = pos1; pos1z1.Z = z1;
+
+ // RJLog.Log(
+ // "\nPOSITIONS:",
+ // pos0z0, pos1z0, pos1z1, pos0z1,
+
+ // "\nNORMALS:",
+ // pos0, pos1, pos1, pos0,
+
+ // "\nUV:",
+ // new Vector2( u0, v0 ), new Vector2( u1, v0 ),
+ // new Vector2( u1, v1 ), new Vector2( u0, v1 )
+ // );
+
+ mg.AddQuad(
+ pos0z1, pos1z1, pos1z0, pos0z0,
+ pos0, pos1, pos1, pos0,
+ new Vector2( u0, v1 ), new Vector2( u1, v1 ), new Vector2( u1, v0 ), new Vector2( u0, v0 )
+ );
+
+
+ }
+ }
+
+ return mg;
+
+
+ }
+
public void Initialize( bool normals = true, bool uvs = true, bool colors = false, bool uvs2 = false )
{
this.normals = normals ? new List() : null;
diff --git a/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs b/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs
index 1cd2146..95bb675 100644
--- a/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs
+++ b/Runtime/Rendering/Compositor/CompositorEffects/AntiAliasing/FXAA/FXAAEffect.cs
@@ -87,7 +87,7 @@ namespace Rokojori
}
- if ( lastIterations != numIterations )
+ if ( lastIterations != numIterations || numIterations != graph.processOrderSize )
{
lastIterations = numIterations;
var list = new List();
diff --git a/Runtime/Rendering/RenderGraph/RDGraph.cs b/Runtime/Rendering/RenderGraph/RDGraph.cs
index 6a9d097..d0ff836 100644
--- a/Runtime/Rendering/RenderGraph/RDGraph.cs
+++ b/Runtime/Rendering/RenderGraph/RDGraph.cs
@@ -51,6 +51,8 @@ namespace Rokojori
_processOrder.AddRange( order );
}
+ public int processOrderSize => _processOrder.Count;
+
public void AddToProcessOrder( params RGGraphProcessor[] additional )
{
_processOrder.AddRange( additional );
diff --git a/Runtime/Sensors/CombineSensor.cs b/Runtime/Sensors/CombineSensor.cs
index 0dc3904..6c0a46a 100644
--- a/Runtime/Sensors/CombineSensor.cs
+++ b/Runtime/Sensors/CombineSensor.cs
@@ -18,6 +18,20 @@ namespace Rokojori
[Export]
public int numVisible = 0;
+ public override bool IsSensor( InputEvent ev )
+ {
+ foreach ( var s in sensors )
+ {
+ if ( s != null && s.IsSensor( ev ) )
+ {
+ // this.LogInfo( "Is from combined:", s, Sensor.GetInputEventInfo( ev ) );
+ return true;
+ }
+ }
+
+ return false;
+ }
+
protected override void UpdateValue()
{
var value = 0f;
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Cancel.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Cancel.tres
new file mode 100644
index 0000000..426a2b3
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Cancel.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=5 format=3 uid="uid://dfvs7wbygwmhk"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_3pq7c"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_87mft"]
+[ext_resource type="Resource" uid="uid://cvjlv07g2nkfw" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Button B, PS Circle, Nin A.tres" id="3_e1dcp"]
+
+[sub_resource type="Resource" id="Resource_hydin"]
+script = ExtResource("2_87mft")
+inputActionName = "ui_cancel"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_3pq7c")
+sensors = [SubResource("Resource_hydin"), ExtResource("3_e1dcp")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Confirm.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Confirm.tres
new file mode 100644
index 0000000..6737fa0
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Confirm.tres
@@ -0,0 +1,15 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=5 format=3 uid="uid://ciia3k58fa5w"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_5ww7h"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_qe2fd"]
+[ext_resource type="Resource" uid="uid://dffkdky8iowro" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Button A, PS Cross, Nin B.tres" id="3_wy52s"]
+
+[sub_resource type="Resource" id="Resource_1dc0j"]
+script = ExtResource("2_qe2fd")
+inputActionName = "ui_accept"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_5ww7h")
+sensors = [SubResource("Resource_1dc0j"), ExtResource("3_wy52s")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Down.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Down.tres
new file mode 100644
index 0000000..e444282
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Down.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://ckyf78p517ga1"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_uc4e8"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_l2qr3"]
+
+[sub_resource type="Resource" id="Resource_pb2so"]
+script = ExtResource("2_l2qr3")
+inputActionName = "ui_down"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_uc4e8")
+sensors = [SubResource("Resource_pb2so")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres
new file mode 100644
index 0000000..50899c0
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://cqatyb80rpor0"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_u5wou"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_ibucs"]
+
+[sub_resource type="Resource" id="Resource_n3xai"]
+script = ExtResource("2_ibucs")
+inputActionName = "ui_left"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_u5wou")
+sensors = [SubResource("Resource_n3xai")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Next Menu.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Next Menu.tres
new file mode 100644
index 0000000..607e4a9
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Next Menu.tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=3 format=3 uid="uid://ccff1bj35qcl0"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_8e2n5"]
+[ext_resource type="Resource" uid="uid://jbud1yjmxysm" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Shoulder Right, RB, R1.tres" id="2_m7ahn"]
+
+[resource]
+script = ExtResource("1_8e2n5")
+sensors = [ExtResource("2_m7ahn")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Previous Menu.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Previous Menu.tres
new file mode 100644
index 0000000..30f0a76
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Previous Menu.tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=3 format=3 uid="uid://dtykoghdisv37"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_r1ua5"]
+[ext_resource type="Resource" uid="uid://cituiuw6e1fho" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Shoulder Left, LB, L1.tres" id="2_in8jh"]
+
+[resource]
+script = ExtResource("1_r1ua5")
+sensors = [ExtResource("2_in8jh")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres
new file mode 100644
index 0000000..d9fd33f
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://dafu3alp6wr25"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_rqdfo"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_oj4wy"]
+
+[sub_resource type="Resource" id="Resource_tuqbj"]
+script = ExtResource("2_oj4wy")
+inputActionName = "ui_right"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_rqdfo")
+sensors = [SubResource("Resource_tuqbj")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Up.tres b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Up.tres
new file mode 100644
index 0000000..a8a5b9e
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Up.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Resource" script_class="CombineSensor" load_steps=4 format=3 uid="uid://r8bfiv34ghev"]
+
+[ext_resource type="Script" uid="uid://eid0qnlvq4n1" path="res://addons/rokojori_action_library/Runtime/Sensors/CombineSensor.cs" id="1_j2g18"]
+[ext_resource type="Script" uid="uid://e7fduwypgvwr" path="res://addons/rokojori_action_library/Runtime/Sensors/InputMapActionSensor.cs" id="2_5pcht"]
+
+[sub_resource type="Resource" id="Resource_esl73"]
+script = ExtResource("2_5pcht")
+inputActionName = "ui_up"
+metadata/_custom_type_script = "uid://e7fduwypgvwr"
+
+[resource]
+script = ExtResource("1_j2g18")
+sensors = [SubResource("Resource_esl73")]
+metadata/_custom_type_script = "uid://eid0qnlvq4n1"
diff --git a/Runtime/Sensors/Default-Sensors/UI/UI Inputs Group.tres b/Runtime/Sensors/Default-Sensors/UI/UI Inputs Group.tres
new file mode 100644
index 0000000..d6a43b4
--- /dev/null
+++ b/Runtime/Sensors/Default-Sensors/UI/UI Inputs Group.tres
@@ -0,0 +1,16 @@
+[gd_resource type="Resource" script_class="SensorGroup" load_steps=10 format=3 uid="uid://ca1e6qd423hg"]
+
+[ext_resource type="Script" uid="uid://da4bhmvkury2" path="res://addons/rokojori_action_library/Runtime/Sensors/SensorGroup.cs" id="1_n7t1q"]
+[ext_resource type="Resource" uid="uid://dfvs7wbygwmhk" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Cancel.tres" id="2_yi61e"]
+[ext_resource type="Resource" uid="uid://ciia3k58fa5w" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Confirm.tres" id="3_vqhth"]
+[ext_resource type="Resource" uid="uid://ckyf78p517ga1" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Down.tres" id="4_vjp62"]
+[ext_resource type="Resource" uid="uid://cqatyb80rpor0" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Left.tres" id="5_3twes"]
+[ext_resource type="Resource" uid="uid://ccff1bj35qcl0" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Next Menu.tres" id="6_rvbkj"]
+[ext_resource type="Resource" uid="uid://dtykoghdisv37" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Previous Menu.tres" id="7_jx650"]
+[ext_resource type="Resource" uid="uid://dafu3alp6wr25" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Right.tres" id="8_ttnbi"]
+[ext_resource type="Resource" uid="uid://r8bfiv34ghev" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/UI/Sensors/UI Up.tres" id="9_h04cc"]
+
+[resource]
+script = ExtResource("1_n7t1q")
+sensors = [ExtResource("2_yi61e"), ExtResource("3_vqhth"), ExtResource("9_h04cc"), ExtResource("4_vjp62"), ExtResource("5_3twes"), ExtResource("8_ttnbi"), ExtResource("6_rvbkj"), ExtResource("7_jx650")]
+metadata/_custom_type_script = "uid://da4bhmvkury2"
diff --git a/Runtime/Sensors/GamePadAxisSensor.cs b/Runtime/Sensors/GamePadAxisSensor.cs
index b08a057..81f0955 100644
--- a/Runtime/Sensors/GamePadAxisSensor.cs
+++ b/Runtime/Sensors/GamePadAxisSensor.cs
@@ -28,6 +28,37 @@ namespace Rokojori
SetFloatValue( _lastInput );
}
+
+ public override bool IsSensor( InputEvent ev )
+ {
+ // this.LogInfo( "Checking axis sensor:", Sensor.GetInputEventInfo( ev ) );
+
+ var joypadAxisEvent = ev as InputEventJoypadMotion;
+
+ if ( joypadAxisEvent == null )
+ {
+ return false;
+ }
+
+ if ( joypadAxisEvent.Axis != axis )
+ {
+ return false;
+ }
+
+ if ( type == GamePadAxisType.Positive )
+ {
+ // this.LogInfo( "Is positive axis sensor:", Sensor.GetInputEventInfo( ev ) );
+ return joypadAxisEvent.AxisValue > 0;
+ }
+ else if ( type == GamePadAxisType.Negative )
+ {
+ // this.LogInfo( "Is negative axis sensor:", Sensor.GetInputEventInfo( ev ) );
+ return joypadAxisEvent.AxisValue < 0;
+ }
+
+ return false;
+ }
+
public void _Input( InputEvent ev )
{
var joypadAxisEvent = ev as InputEventJoypadMotion;
diff --git a/Runtime/Sensors/GamePadButtonSensor.cs b/Runtime/Sensors/GamePadButtonSensor.cs
index 965cb86..abf08fe 100644
--- a/Runtime/Sensors/GamePadButtonSensor.cs
+++ b/Runtime/Sensors/GamePadButtonSensor.cs
@@ -24,7 +24,24 @@ namespace Rokojori
{
return RJLog.GetInfo( this, button );
}
-
+
+ public override bool IsSensor( InputEvent ev )
+ {
+ var joypadButtonEvent = ev as InputEventJoypadButton;
+
+ if ( joypadButtonEvent == null )
+ {
+ return false;
+ }
+
+ if ( joypadButtonEvent.ButtonIndex != button )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
public void _Input( InputEvent ev )
{
var joypadButtonEvent = ev as InputEventJoypadButton;
diff --git a/Runtime/Sensors/HoldSensor.cs b/Runtime/Sensors/HoldSensor.cs
index 92ce34f..0468162 100644
--- a/Runtime/Sensors/HoldSensor.cs
+++ b/Runtime/Sensors/HoldSensor.cs
@@ -17,6 +17,19 @@ namespace Rokojori
[Export]
public Sensor triggerButton;
+ public override bool IsSensor( InputEvent ie )
+ {
+ var holdButtonPressed = holdButton.isActive;
+ var needsToBePressed = ! negateHoldButton;
+
+ if ( holdButtonPressed == needsToBePressed )
+ {
+ return false;
+ }
+
+ return triggerButton.IsSensor( ie );
+ }
+
protected override void UpdateValue()
{
if ( holdButton == null || triggerButton == null )
@@ -41,7 +54,7 @@ namespace Rokojori
SetFloatValue( triggerButton.value );
}
- public override string ToString()
+ public override string ToString()
{
return RJLog.GetInfo( this, holdButton, triggerButton );
}
diff --git a/Runtime/Sensors/InputMapActionSensor.cs b/Runtime/Sensors/InputMapActionSensor.cs
index 1c3f238..a241c5b 100644
--- a/Runtime/Sensors/InputMapActionSensor.cs
+++ b/Runtime/Sensors/InputMapActionSensor.cs
@@ -26,6 +26,33 @@ namespace Rokojori
return RJLog.GetInfo( this, inputActionName, pollMode );
}
+ public override bool IsSensor( InputEvent ie )
+ {
+ // this.LogInfo( "Checking action input:", Sensor.GetInputEventInfo( ie ) );
+
+ if ( ie.IsActionPressed( inputActionName, true, true ) )
+ {
+ var strength = ie.GetActionStrength( inputActionName );
+ var isActive = strength > 0.01f;
+
+ if ( isActive )
+ {
+ // this.LogInfo( "Matching pressed action input:", Sensor.GetInputEventInfo( ie ) );
+ }
+
+ return isActive;
+ }
+
+ var released = ie.IsActionReleased( inputActionName, true );
+
+ if ( released )
+ {
+ // this.LogInfo( "Matching released action input:", Sensor.GetInputEventInfo( ie ) );
+ }
+
+ return released;
+ }
+
protected override void UpdateValue()
{
if ( PollMode.Button == pollMode )
diff --git a/Runtime/Sensors/KeySensor.cs b/Runtime/Sensors/KeySensor.cs
index 5dea8dd..3a06b9f 100644
--- a/Runtime/Sensors/KeySensor.cs
+++ b/Runtime/Sensors/KeySensor.cs
@@ -47,6 +47,56 @@ namespace Rokojori
SetFloatValue( _lastInput );
}
+ public override bool IsSensor( InputEvent ev )
+ {
+ var keyEvent = ev as InputEventKey;
+
+
+ if ( keyEvent == null )
+ {
+ return false;
+ }
+
+ if ( keyEvent.Keycode != key )
+ {
+ return false;
+ }
+
+ if ( keyLocation != KeyLocation.Unspecified && keyEvent.Location != KeyLocation.Unspecified )
+ {
+ if ( keyEvent.Location != keyLocation )
+ {
+ return false;
+ }
+ }
+
+ var checkModifiers = modifiersEnabled &&
+ (
+ ModifiersMode.Hold_Modifiers_All_The_Time == modifiersMode ||
+ _lastInput == 0 && ModifiersMode.Hold_Modifiers_Only_On_Down == modifiersMode
+ );
+
+ if ( checkModifiers )
+ {
+ if ( ! TrilleanLogic.Matches( ctrlHold, keyEvent.CtrlPressed ) )
+ {
+ return false;
+ }
+
+ if ( ! TrilleanLogic.Matches( altHold, keyEvent.AltPressed ) )
+ {
+ return false;
+ }
+
+ if ( ! TrilleanLogic.Matches( shiftHold, keyEvent.ShiftPressed ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public void _Input( InputEvent ev )
{
var keyEvent = ev as InputEventKey;
diff --git a/Runtime/Sensors/MouseButtonSensor.cs b/Runtime/Sensors/MouseButtonSensor.cs
index a14bbb9..1f97596 100644
--- a/Runtime/Sensors/MouseButtonSensor.cs
+++ b/Runtime/Sensors/MouseButtonSensor.cs
@@ -58,6 +58,56 @@ namespace Rokojori
}
+ public override bool IsSensor( InputEvent ev )
+ {
+ var mouseEvent = ev as InputEventMouseButton;
+
+ if ( mouseEvent == null )
+ {
+ return false;
+ }
+
+ if ( mouseEvent.ButtonIndex != button )
+ {
+ return false;
+ }
+
+ var checkModifiers = modifiersEnabled &&
+ (
+ ModifiersMode.Hold_Modifiers_All_The_Time == modifiersMode ||
+ _lastInput == 0 && ModifiersMode.Hold_Modifiers_Only_On_Down == modifiersMode
+ );
+
+ if ( checkModifiers )
+ {
+
+ if ( ! TrilleanLogic.Matches( ctrlHold, mouseEvent.CtrlPressed ) )
+ {
+ return false;
+ }
+
+ if ( ! TrilleanLogic.Matches( altHold, mouseEvent.AltPressed ) )
+ {
+ return false;
+ }
+
+ if ( ! TrilleanLogic.Matches( shiftHold, mouseEvent.ShiftPressed ) )
+ {
+ return false;
+ }
+ }
+
+ var isActive = mouseEvent.IsPressed();
+
+ if ( IsWheel() && ! isActive )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
public void _Input( InputEvent ev )
{
diff --git a/Runtime/Sensors/MouseMotionDelta.cs b/Runtime/Sensors/MouseMotionDelta.cs
index 405f024..30ade9e 100644
--- a/Runtime/Sensors/MouseMotionDelta.cs
+++ b/Runtime/Sensors/MouseMotionDelta.cs
@@ -35,6 +35,11 @@ namespace Rokojori
_lastInput = 0;
}
+ public override bool IsSensor( InputEvent ev )
+ {
+ return ev is InputEventMouseMotion;
+ }
+
public void _Input( InputEvent ev )
{
var mouseEvent = ev as InputEventMouseMotion ;
diff --git a/Runtime/Sensors/MouseScreenRelative.cs b/Runtime/Sensors/MouseScreenRelative.cs
index 17f2c55..2fc85fe 100644
--- a/Runtime/Sensors/MouseScreenRelative.cs
+++ b/Runtime/Sensors/MouseScreenRelative.cs
@@ -31,6 +31,11 @@ namespace Rokojori
return RJLog.GetInfo( this, motionType );
}
+ public override bool IsSensor( InputEvent ev )
+ {
+ return ev is InputEventMouseMotion;
+ }
+
public void _Input( InputEvent ev )
{
var mouseEvent = ev as InputEventMouseMotion ;
diff --git a/Runtime/Sensors/Sensor.cs b/Runtime/Sensors/Sensor.cs
index 03935d5..d461c50 100644
--- a/Runtime/Sensors/Sensor.cs
+++ b/Runtime/Sensors/Sensor.cs
@@ -6,7 +6,7 @@ namespace Rokojori
{
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Sensor.svg")]
- public partial class Sensor: Resource
+ public abstract partial class Sensor: Resource
{
[Export]
public LocaleText name;
@@ -52,6 +52,61 @@ namespace Rokojori
public virtual bool WasActive( int device ) => isUp;
public virtual bool IsActive( int device ) => isUp;
+ public virtual bool IsDown( InputEvent ie ){ return IsSensor( ie ) && ie.IsPressed(); }
+ public virtual bool IsUp( InputEvent ie ){ return IsSensor( ie ) && ie.IsReleased(); }
+ public abstract bool IsSensor( InputEvent ie );
+
+ public virtual bool IsRepeatDown( ref float lastActivation, float delay = 0.5f, float repeatDuration = 0.1f )
+ {
+ var now = TimeLine.osTime;
+
+ if ( isDown )
+ {
+ lastActivation = now + delay;
+ return true;
+ }
+
+ var value = isActive && ( now - lastActivation ) > repeatDuration;
+
+ if ( value )
+ {
+ lastActivation = now;
+ }
+
+ return value;
+ }
+
+ public static string GetInputEventInfo( InputEvent ie )
+ {
+ var type = ie.GetType().Name;
+ var isPressed = ie.IsPressed();
+ var isReleeased = ie.IsReleased();
+
+ var details = "";
+ if ( ie is InputEventKey k )
+ {
+ details = "key: " + k.Keycode + " " + k.KeyLabel;
+ }
+ else if ( ie is InputEventJoypadButton b )
+ {
+ details = "gamepad button: " + b.ButtonIndex;
+ }
+ else if ( ie is InputEventJoypadMotion a )
+ {
+ details = "gamepad axis: " + a.Axis + " " + a.AxisValue;
+ }
+ else if ( ie is InputEventMouseButton mb )
+ {
+ details = "mouse button: " + mb.ButtonIndex + " " + mb.ButtonMask;
+ }
+ else if ( ie is InputEventMouseMotion mm )
+ {
+ details = "mouse motion: " + mm.Position + " " + mm.Relative;
+ }
+
+ return type + " pressed:" + isPressed + " released: " + isReleeased + " " + details;
+ }
+
public bool consumed => _consumed;
diff --git a/Runtime/Sensors/SensorManager.cs b/Runtime/Sensors/SensorManager.cs
index 2c8b2b7..28d4d53 100644
--- a/Runtime/Sensors/SensorManager.cs
+++ b/Runtime/Sensors/SensorManager.cs
@@ -263,7 +263,8 @@ namespace Rokojori
{
return;
}
- //this.LogInfo( "Register", s );
+
+ this.LogInfo( "Register", s );
if ( ! sensorToRunner.ContainsKey( s ) )
{
@@ -410,6 +411,18 @@ namespace Rokojori
}
//this.LogInfo( "AddSensorsFrom", obj );
+
+ if ( obj is CombineSensor cs )
+ {
+
+ cs.sensors.ForEach( s =>
+ {
+ this.LogInfo( "Adding Combine Sensor:", s );
+ AddSensor( s );
+ }
+ );
+ return;
+ }
try
{
diff --git a/Runtime/Shading/Library/Bezier.gdshaderinc b/Runtime/Shading/Library/Bezier.gdshaderinc
new file mode 100644
index 0000000..2cff2e7
--- /dev/null
+++ b/Runtime/Shading/Library/Bezier.gdshaderinc
@@ -0,0 +1,65 @@
+// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/Bezier.gdshaderinc"
+
+
+float cubicBezier( float t, float p0, float p1, float p2, float p3 )
+{
+ float bp0 = ( 1.0 - t ) * ( 1.0 - t ) * ( 1.0 - t );
+ float bp1 = 3.0 * ( 1.0 - t ) * ( 1.0 - t ) * t;
+ float bp2 = 3.0 * ( 1.0 - t ) * t * t;
+ float bp3 = t * t * t;
+
+ return p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
+}
+
+vec2 cubicBezier( float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3 )
+{
+ float bp0 = ( 1.0 - t ) * ( 1.0 - t ) * ( 1.0 - t );
+ float bp1 = 3.0 * ( 1.0 - t ) * ( 1.0 - t ) * t;
+ float bp2 = 3.0 * ( 1.0 - t ) * t * t;
+ float bp3 = t * t * t;
+
+ return p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
+}
+
+
+vec3 cubicBezier( float t, vec3 p0, vec3 p1, vec3 p2, vec3 p3 )
+{
+ float bp0 = ( 1.0 - t ) * ( 1.0 - t ) * ( 1.0 - t );
+ float bp1 = 3.0 * ( 1.0 - t ) * ( 1.0 - t ) * t;
+ float bp2 = 3.0 * ( 1.0 - t ) * t * t;
+ float bp3 = t * t * t;
+
+ return p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
+}
+
+vec3 cubicBezierDerivative( float t, vec3 p0, vec3 p1, vec3 p2, vec3 p3 )
+{
+ vec3 d0 = ( p1 - p0 );
+ vec3 d1 = ( p2 - p1 );
+ vec3 d2 = ( p3 - p2 );
+
+ float bp0 = 3.0 * ( 1.0 - t ) * ( 1.0 - t );
+ float bp1 = 6.0 * ( 1.0 - t ) * t;
+ float bp2 = 3.0 * t * t;
+
+
+ return d0 * bp0 + d1 * bp1 + d2 * bp2;
+}
+
+
+vec3 rationalCubicBezier( float t,
+ vec3 p0, vec3 p1, vec3 p2, vec3 p3,
+ float w0, float w1, float w2, float w3
+ )
+{
+ float bp0 = ( 1.0 - t ) * ( 1.0 - t ) * ( 1.0 - t ) * w0;
+ float bp1 = 3.0 * ( 1.0 - t ) * ( 1.0 - t ) * t * w1;
+ float bp2 = 3.0 * ( 1.0 - t ) * t * t * w2;
+ float bp3 = t * t * t * w3;
+
+ vec3 weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
+
+ float projection = bp0 + bp1 + bp2 + bp3;
+
+ return weighted / projection;
+}
diff --git a/Runtime/Shading/Library/Bezier.gdshaderinc.uid b/Runtime/Shading/Library/Bezier.gdshaderinc.uid
new file mode 100644
index 0000000..763a737
--- /dev/null
+++ b/Runtime/Shading/Library/Bezier.gdshaderinc.uid
@@ -0,0 +1 @@
+uid://dmrr025l0bwyj
diff --git a/Runtime/Shading/Library/SDF.gdshaderinc b/Runtime/Shading/Library/SDF.gdshaderinc
index f3708c5..50b3b31 100644
--- a/Runtime/Shading/Library/SDF.gdshaderinc
+++ b/Runtime/Shading/Library/SDF.gdshaderinc
@@ -279,6 +279,45 @@ float sdRoundedX( in vec2 p, in float w, in float r )
return length(p-min(p.x+p.y,w)*0.5) - r;
}
+// float sdBezier( vec2 pos, vec2 pointA, vec2 pointB, vec2 pointC )
+// {
+// vec2 a = pointB - pointA;
+// vec2 b = pointA - 2.0*pointB + pointC;
+// vec2 c = a * 2.0;
+// vec2 d = pointA - pos;
+
+// float kk = 1.0/dot(b,b);
+// float kx = kk * dot(a,b);
+// float ky = kk * (2.0*dot(a,a)+dot(d,b)) / 3.0;
+// float kz = kk * dot(d,a);
+// float res = 0.0;
+// float p = ky - kx*kx;
+// float p3 = p*p*p;
+// float q = kx*(2.0*kx*kx-3.0*ky) + kz;
+// float h = q*q + 4.0*p3;
+
+// if( h >= 0.0 )
+// {
+// h = sqrt(h);
+// vec2 x = (vec2(h,-h)-q)/2.0;
+// vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));
+// float t = clamp( uv.x+uv.y-kx, 0.0, 1.0 );
+// res = dot2(d + (c + b*t)*t);
+// }
+// else
+// {
+// float z = sqrt(-p);
+// float v = acos( q/(p*z*2.0) ) / 3.0;
+// float m = cos(v);
+// float n = sin(v)*1.732050808;
+// vec3 t = clamp(vec3(m+m,-n-m,n-m)*z-kx,0.0,1.0);
+// res = min( dot2(d+(c+b*t.x)*t.x),
+// dot2(d+(c+b*t.y)*t.y) );
+// }
+
+// return sqrt( res );
+// }
+
// float sdPolygon( in vec2[N] v, in vec2 p )
// {
// float d = dot(p-v[0],p-v[0]);
diff --git a/Runtime/Shading/Library/Transform.gdshaderinc b/Runtime/Shading/Library/Transform.gdshaderinc
index 8998f0b..866e7cd 100644
--- a/Runtime/Shading/Library/Transform.gdshaderinc
+++ b/Runtime/Shading/Library/Transform.gdshaderinc
@@ -655,6 +655,41 @@ vec2 worldUVfromLocalXZ( vec3 localVertex, vec2 centerXZ, vec2 sizeXZ, mat4 _MOD
return worldUVfromWorldXZ( worldVertex, centerXZ, sizeXZ );
}
+mat3 createBasis( vec3 x, vec3 y, vec3 z )
+{
+ return mat3( x, y, z );
+}
+
+mat3 lookRotation( vec3 forward, vec3 up )
+{
+ vec3 z = normalize( forward );
+ vec3 x = normalize( cross( up, z ) );
+ vec3 y = cross( z, x );
+
+ return createBasis( x, y, z );
+}
+
+vec4 quaternionFromLookRotation( vec3 forward, vec3 up )
+{
+ mat3 rotationMatrix = lookRotation( forward, up );
+
+ return quaternionFromMatrix( rotationMatrix );
+}
+
+mat4 createMat4FromBasisAndOrigin( mat3 basis, vec3 origin )
+{
+ mat4 transform = mat4(
+
+ vec4( basis[0], 0.0 ),
+ vec4( basis[1], 0.0 ),
+ vec4( basis[2], 0.0 ),
+ vec4( origin, 1.0 )
+ );
+
+ return transform;
+}
+
+
mat3 createFromToRotation( vec3 from, vec3 to )
{
diff --git a/Runtime/Shading/Properties/FloatPropertyName.cs b/Runtime/Shading/Properties/FloatPropertyName.cs
index 8048013..035007f 100644
--- a/Runtime/Shading/Properties/FloatPropertyName.cs
+++ b/Runtime/Shading/Properties/FloatPropertyName.cs
@@ -59,7 +59,15 @@ namespace Rokojori
}
+ public void SetInstance( GeometryInstance3D gi, float value )
+ {
+ _SetInstance( gi, value );
+ }
+ public float GetInstance( GeometryInstance3D gi, float fallback = 0f)
+ {
+ return _GetInstance( gi, fallback );
+ }
public void Set( Material material, float value )
diff --git a/Runtime/Shading/Properties/ShaderPropertyName.cs b/Runtime/Shading/Properties/ShaderPropertyName.cs
index 07b6fca..26a28a1 100644
--- a/Runtime/Shading/Properties/ShaderPropertyName.cs
+++ b/Runtime/Shading/Properties/ShaderPropertyName.cs
@@ -31,6 +31,23 @@ namespace Rokojori
_SetStandardValue( m, value );
}
+ public void _SetInstance<[MustBeVariant] T>( GeometryInstance3D mi, T value )
+ {
+ var variant = Variant.From( value );
+ mi.SetInstanceShaderParameter( propertyName, variant );
+ return;
+ }
+
+ public T _GetInstance<[MustBeVariant] T>( GeometryInstance3D mi, T value )
+ {
+ if ( mi == null )
+ {
+ return value;
+ }
+
+ return mi.GetInstanceShaderParameter( propertyName ).As();
+ }
+
public T _Get<[MustBeVariant] T>( Material material, T fallback )
{
if ( material is ShaderMaterial shaderMaterial )
diff --git a/Runtime/Shading/Properties/Vector3PropertyName.cs b/Runtime/Shading/Properties/Vector3PropertyName.cs
index db45b16..96bfca2 100644
--- a/Runtime/Shading/Properties/Vector3PropertyName.cs
+++ b/Runtime/Shading/Properties/Vector3PropertyName.cs
@@ -27,6 +27,16 @@ namespace Rokojori
return _Get( material, Vector3.Zero );
}
+ public void SetInstance( GeometryInstance3D gi, Vector3 value )
+ {
+ _SetInstance( gi, value );
+ }
+
+ public Vector3 GetInstance( GeometryInstance3D gi )
+ {
+ return _GetInstance( gi, Vector3.Zero );
+ }
+
public static Vector3PropertyName Create( string name )
{
var p = new Vector3PropertyName();
diff --git a/Runtime/Structures/QueueList.cs b/Runtime/Structures/QueueList.cs
index 1f2eafd..97cd391 100644
--- a/Runtime/Structures/QueueList.cs
+++ b/Runtime/Structures/QueueList.cs
@@ -46,7 +46,7 @@ namespace Rokojori
return;
}
- Lists.RemoveRange( this, _queuedRemovals );
+ Lists.RemoveList( this, _queuedRemovals );
_queuedRemovals.Clear();
}
diff --git a/Runtime/Text/JSON/Serializers/JSONDeserializer.cs b/Runtime/Text/JSON/Serializers/JSONDeserializer.cs
index 4242ac9..1a51c7d 100644
--- a/Runtime/Text/JSON/Serializers/JSONDeserializer.cs
+++ b/Runtime/Text/JSON/Serializers/JSONDeserializer.cs
@@ -6,6 +6,7 @@ using System.Text;
using System;
+using System.Linq;
namespace Rokojori
@@ -74,13 +75,22 @@ namespace Rokojori
}
var type = parent.GetType();
+
+ if ( IsSerializableDictionary( type ) )
+ {
+ DeserializeDictionaryField( data, parent as IDictionary, name, -1 );
+ return;
+ }
+
var field = type.GetField( name );
if ( field == null )
{
- RJLog.Log( "Field not present: " + name );
+
+
+ RJLog.Log( "Field not present: " + name, "in", type.Name );
return;
}
diff --git a/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs b/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs
new file mode 100644
index 0000000..19e2261
--- /dev/null
+++ b/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs
@@ -0,0 +1,43 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace Rokojori
+{
+
+ public class UIExpressionLexer:Lexer
+ {
+ public static List Lex( string source )
+ {
+ var lexer = new UIExpressionLexer();
+ var events = lexer.LexToList( source );
+
+ if ( lexer.hasError )
+ {
+ return null;
+ }
+
+ events.ForEach( ev => { ev.GrabMatch( source ); } );
+ return events;
+ }
+
+ public UIExpressionLexer()
+ {
+ AddAllMatchers(
+ LexerMatcherLibrary.SingleLineCommentMatcher,
+ LexerMatcherLibrary.MultiLineCommentMatcher,
+ LexerMatcherLibrary.NumberMatcher,
+ LexerMatcherLibrary.NullMatcher,
+ LexerMatcherLibrary.BoolMatcher,
+ LexerMatcherLibrary.BreakMatcher,
+ LexerMatcherLibrary.WhiteSpaceMatcher,
+ LexerMatcherLibrary.LogicMatcher,
+ LexerMatcherLibrary.BracketMatcher,
+ LexerMatcherLibrary.OperatorMatcher,
+ LexerMatcherLibrary.CFunctionMatcher,
+ LexerMatcherLibrary.CwordMatcher,
+ LexerMatcherLibrary.AnySymbolMatcher
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs.uid b/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs.uid
new file mode 100644
index 0000000..b8e707a
--- /dev/null
+++ b/Runtime/Text/Lexing/LexerLibrary/UIExpressionLexer.cs.uid
@@ -0,0 +1 @@
+uid://p6e2rj7eba6x
diff --git a/Runtime/Text/Text.cs b/Runtime/Text/Text.cs
index b5c071c..c584cd3 100644
--- a/Runtime/Text/Text.cs
+++ b/Runtime/Text/Text.cs
@@ -135,6 +135,11 @@ namespace Rokojori
public static string ReplaceStart( this string source, string start, string replacement = "" )
{
+ if ( start == "" )
+ {
+ return source;
+ }
+
if ( source.StartsWith( start ) )
{
return replacement + source.Substring( start.Length );
@@ -145,6 +150,11 @@ namespace Rokojori
public static string ReplaceEnd( this string source, string ending, string replacement = "" )
{
+ if ( ending == "" )
+ {
+ return source;
+ }
+
if ( source.EndsWith( ending ) )
{
return source.Substring( 0, source.Length - ending.Length ) + replacement;
diff --git a/Runtime/Tools/Arrays.cs b/Runtime/Tools/Arrays.cs
index 0a54c4f..aa9e0e8 100644
--- a/Runtime/Tools/Arrays.cs
+++ b/Runtime/Tools/Arrays.cs
@@ -35,7 +35,7 @@ namespace Rokojori
}
- public static int FindIndex( T[] values, Func predicate )
+ public static int FindIndex( this T[] values, Func predicate )
{
if ( values == null )
{
diff --git a/Runtime/Tools/Lists.cs b/Runtime/Tools/Lists.cs
index 5ff2b4c..1a060e0 100644
--- a/Runtime/Tools/Lists.cs
+++ b/Runtime/Tools/Lists.cs
@@ -666,7 +666,7 @@ namespace Rokojori
}
}
- public static void RemoveRange( List list, List removals )
+ public static void RemoveList( this List list, List removals )
{
var removalSet = new HashSet();
removalSet.UnionWith( removals );
diff --git a/Runtime/UI/Actions/SetFocusedControl.cs b/Runtime/UI/Actions/SetFocusedControl.cs
new file mode 100644
index 0000000..2a9d743
--- /dev/null
+++ b/Runtime/UI/Actions/SetFocusedControl.cs
@@ -0,0 +1,27 @@
+
+using Godot;
+using System;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class SetFocusedControl: Action
+{
+ [Export]
+ public Control control;
+
+ protected override void _OnTrigger()
+ {
+ this.CallDeferred(
+ ()=>
+ {
+ control.GrabFocus();
+
+
+
+ control.LogInfo( "Grabbing Focus:", control.HasFocus() );
+ }
+ );
+
+ }
+}
diff --git a/Runtime/UI/Actions/SetFocusedControl.cs.uid b/Runtime/UI/Actions/SetFocusedControl.cs.uid
new file mode 100644
index 0000000..fa16911
--- /dev/null
+++ b/Runtime/UI/Actions/SetFocusedControl.cs.uid
@@ -0,0 +1 @@
+uid://dx7xkcqyf6vyf
diff --git a/Runtime/UI/Actions/SetUIElementActiveState.cs b/Runtime/UI/Actions/SetUIElementActiveState.cs
new file mode 100644
index 0000000..858b617
--- /dev/null
+++ b/Runtime/UI/Actions/SetUIElementActiveState.cs
@@ -0,0 +1,43 @@
+
+using Godot;
+using System;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class SetUIElementActiveState: Action
+{
+
+ [Export]
+ public Control uiNode;
+
+ public enum ActiveState
+ {
+ Set_Active,
+ Remove_Active
+ }
+
+ [Export]
+ public ActiveState activeState = ActiveState.Set_Active;
+
+ protected override void _OnTrigger()
+ {
+ var uiStyleable = uiNode as UIStylePropertyContainer;
+
+ if ( uiStyleable == null )
+ {
+ return;
+ }
+
+
+ if ( ActiveState.Set_Active == activeState )
+ {
+ uiStyleable.AddUISelectorFlag( UISelectorFlag.Active );
+ }
+ else
+ {
+ uiStyleable.RemoveUISelectorFlag( UISelectorFlag.Active );
+ }
+
+ }
+}
diff --git a/Runtime/UI/Actions/SetUIElementActiveState.cs.uid b/Runtime/UI/Actions/SetUIElementActiveState.cs.uid
new file mode 100644
index 0000000..fbf0646
--- /dev/null
+++ b/Runtime/UI/Actions/SetUIElementActiveState.cs.uid
@@ -0,0 +1 @@
+uid://di6haj23ecabu
diff --git a/Runtime/UI/Actions/SetUIStyle.cs b/Runtime/UI/Actions/SetUIStyle.cs
index 22cb760..0b73451 100644
--- a/Runtime/UI/Actions/SetUIStyle.cs
+++ b/Runtime/UI/Actions/SetUIStyle.cs
@@ -2,27 +2,26 @@
using Godot;
using System;
-namespace Rokojori
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class SetUIStyle: Action
{
- [Tool,GlobalClass]
- public partial class SetUIStyle: Action
- {
- [Export]
- public Control uiNode;
+ [Export]
+ public Control uiNode;
- [Export]
- public UIStyle style;
+ [Export]
+ public UIStyle style;
- protected override void _OnTrigger()
+ protected override void _OnTrigger()
+ {
+ var uiStyleable = uiNode as UIStylePropertyContainer;
+
+ if ( uiStyleable == null )
{
- var uiStyleable = uiNode as UIStylePropertyContainer;
-
- if ( uiStyleable == null )
- {
- return;
- }
-
- uiStyleable.SetUIStyleParent( style );
+ return;
}
+
+ uiStyleable.SetUIStyleParent( style );
}
-}
\ No newline at end of file
+}
diff --git a/Runtime/UI/Nodes/UIImage.cs b/Runtime/UI/Nodes/Image/UIImage.cs
similarity index 87%
rename from Runtime/UI/Nodes/UIImage.cs
rename to Runtime/UI/Nodes/Image/UIImage.cs
index 11d227a..3b08bf1 100644
--- a/Runtime/UI/Nodes/UIImage.cs
+++ b/Runtime/UI/Nodes/Image/UIImage.cs
@@ -88,6 +88,55 @@ namespace Rokojori
public override void _Ready()
{
+ FocusEntered += ()=>
+ {
+ this.LogInfo( "Focused", setActiveWhenFocused.Length );
+ AddUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusEntered );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ onFocusEntered?.Trigger();
+
+ setActiveWhenFocused?.ForEach(
+ ( c )=>
+ {
+ var uiStylable = c as UIStylePropertyContainerNode;
+
+ uiStylable?.AddUISelectorFlag( UISelectorFlag.Active );
+ }
+ );
+
+ };
+
+ FocusExited += ()=>
+ {
+ this.LogInfo( "Blurred" );
+ RemoveUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusExited );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ onFocusExited?.Trigger();
+
+ setActiveWhenFocused?.ForEach(
+ ( c )=>
+ {
+ var uiStylable = c as UIStylePropertyContainerNode;
+
+ uiStylable?.RemoveUISelectorFlag( UISelectorFlag.Active );
+ }
+ );
+ };
+
MouseEntered += ()=>
{
AddUISelectorFlag( UISelectorFlag.Hover, hoverID );
@@ -423,18 +472,62 @@ namespace Rokojori
public UILayout GetUILayout()
{
return UILayout.___;
- }
+ }
- [ExportGroup( "Pointer" )]
+
+ [ExportGroup( "Interactivity" )]
[Export]
public UICursor hoverCursor;
+ [Export]
+ public Action onFocusEntered;
+
+ [Export]
+ public Action onFocusExited;
+
+ [Export]
+ public Control[] setActiveWhenFocused = [];
+
public UICursor GetHoverCursor( UIStylePropertyContainer container )
{
return hoverCursor;
}
+ [ExportGroup( "Sound" )]
+ [Export]
+ public UISoundData onFocusSound;
+ [Export]
+ public UISoundData onBlurSound;
+
+ public UISoundData GetUISoundProperty( UISoundProperty property )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ return onFocusSound;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ return onFocusSound;
+ }
+
+ return null;
+ }
+
+ public void SetUISoundProperty( UISoundProperty property, UISoundData stream )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ onFocusSound = stream;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ onFocusSound = stream;
+ }
+ }
+
+
+
public ShaderUIColor[] GetShaderUIColors()
{
return colorProperties;
@@ -562,6 +655,9 @@ namespace Rokojori
}
+ [Export]
+ public bool debugOutput = false;
+
public void Update()
{
@@ -611,15 +707,17 @@ namespace Rokojori
var numberProperties = imageType != null ? imageType.GetNumberShaderProperties() : [];
var numberPropertyName = new FloatPropertyName();
+ var assignmentInfo = "";
+
foreach ( var n in numberProperties )
{
var relative = 100f;
- if ( n.EndsWith( ".x" ) )
+ if ( n.EndsWith( ".x" ) || n.EndsWith( "X" ) )
{
relative = w;
}
- else if ( n.EndsWith( ".y" ) )
+ else if ( n.EndsWith( ".y" ) || n.EndsWith( "Y" ) )
{
relative = h;
}
@@ -628,8 +726,18 @@ namespace Rokojori
var value = UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
numberPropertyName.propertyName = n;
numberPropertyName.Set( Material, value );
- }
+ if ( debugOutput )
+ {
+ assignmentInfo += "\n" + numberPropertyName.propertyName + "=" + value._FFF();
+ }
+
+ }
+
+ if ( debugOutput )
+ {
+ this.LogInfo( assignmentInfo );
+ }
}
diff --git a/Runtime/UI/Nodes/UIImage.cs.uid b/Runtime/UI/Nodes/Image/UIImage.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UIImage.cs.uid
rename to Runtime/UI/Nodes/Image/UIImage.cs.uid
diff --git a/Runtime/UI/Nodes/UIImageTypes/NinePatchUIImageType.cs b/Runtime/UI/Nodes/Image/UIImageTypes/NinePatchUIImageType.cs
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/NinePatchUIImageType.cs
rename to Runtime/UI/Nodes/Image/UIImageTypes/NinePatchUIImageType.cs
diff --git a/Runtime/UI/Nodes/UIImageTypes/NinePatchUIImageType.cs.uid b/Runtime/UI/Nodes/Image/UIImageTypes/NinePatchUIImageType.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/NinePatchUIImageType.cs.uid
rename to Runtime/UI/Nodes/Image/UIImageTypes/NinePatchUIImageType.cs.uid
diff --git a/Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs b/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs
rename to Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs
diff --git a/Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs.uid b/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs.uid
rename to Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs.uid
diff --git a/Runtime/UI/Nodes/UIImageTypes/SliderUIImageType.cs b/Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs
similarity index 79%
rename from Runtime/UI/Nodes/UIImageTypes/SliderUIImageType.cs
rename to Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs
index 29ec7f4..fed7316 100644
--- a/Runtime/UI/Nodes/UIImageTypes/SliderUIImageType.cs
+++ b/Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs
@@ -28,9 +28,11 @@ namespace Rokojori
SliderShader.strokeSize.propertyName,
SliderShader.offset.propertyName,
SliderShader.sliderStrokeSize.propertyName,
- SliderShader.sliderSize.propertyName + ".x",
- SliderShader.sliderSize.propertyName + ".y",
- SliderShader.sliderBorders.propertyName
+ SliderShader.sliderSizeX.propertyName,
+ SliderShader.sliderSizeY.propertyName,
+ SliderShader.sliderBorders.propertyName,
+ SliderShader.sliderSizeMarginX.propertyName,
+ SliderShader.sliderSizeMarginY.propertyName,
];
public override string[] GetNumberShaderProperties()
@@ -94,6 +96,22 @@ namespace Rokojori
set { _sliderSizeY = value; onChange.DispatchEvent( null ); }
}
+ UINumber _sliderSizeMarginX;
+ [Export]
+ public UINumber sliderSizeMarginX
+ {
+ get => _sliderSizeMarginX;
+ set { _sliderSizeMarginX = value; onChange.DispatchEvent( null ); }
+ }
+
+ UINumber _sliderSizeMarginY;
+ [Export]
+ public UINumber sliderSizeMarginY
+ {
+ get => _sliderSizeMarginY;
+ set { _sliderSizeMarginY = value; onChange.DispatchEvent( null ); }
+ }
+
UINumber _sliderBorderRadius;
[Export]
public UINumber sliderBorderRadius
@@ -163,16 +181,26 @@ namespace Rokojori
return offset;
}
- if ( SliderShader.sliderSize.propertyName + ".x" == shaderPropertyName )
+ if ( SliderShader.sliderSizeX.propertyName == shaderPropertyName )
{
return sliderSizeX;
}
- if ( SliderShader.sliderSize.propertyName + ".y" == shaderPropertyName )
+ if ( SliderShader.sliderSizeY.propertyName == shaderPropertyName )
{
return sliderSizeY;
}
+ if ( SliderShader.sliderSizeMarginX.propertyName == shaderPropertyName )
+ {
+ return sliderSizeMarginX;
+ }
+
+ if ( SliderShader.sliderSizeMarginY.propertyName == shaderPropertyName )
+ {
+ return sliderSizeMarginY;
+ }
+
if ( SliderShader.sliderStrokeSize.propertyName == shaderPropertyName )
{
return sliderStrokeSize;
@@ -188,27 +216,30 @@ namespace Rokojori
return null;
}
+ [Export]
+ public bool disableCaching = false;
+
protected override void _Assign( UIImage image )
{
- if ( _materials.ContainsKey( image ) )
+ if ( _materials.ContainsKey( image ) && ! disableCaching )
{
- this.LogInfo( "Has Image in cached materials", HierarchyName.Of( image ) );
+ // this.LogInfo( "Has Image in cached materials", HierarchyName.Of( image ) );
if ( image.Material == null )
{
- this.LogInfo( "Material was null, assigned Image from cached materials" );
+ // this.LogInfo( "Material was null, assigned Image from cached materials" );
image.Material = _materials[ image ];
}
else
{
- this.LogInfo( "Did not assigned material, already exists" );
+ // this.LogInfo( "Did not assigned material, already exists" );
}
return;
}
else
{
- this.LogInfo( "Image had no material and was not cached, caching & creating material", HierarchyName.Of( image ) );
+ // this.LogInfo( "Image had no material and was not cached, caching & creating material", HierarchyName.Of( image ) );
}
_materials[ image ] = new SliderMaterial();
diff --git a/Runtime/UI/Nodes/UIImageTypes/SliderUIImageType.cs.uid b/Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/SliderUIImageType.cs.uid
rename to Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs.uid
diff --git a/Runtime/UI/Nodes/UIImageTypes/UIImageType.cs b/Runtime/UI/Nodes/Image/UIImageTypes/UIImageType.cs
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/UIImageType.cs
rename to Runtime/UI/Nodes/Image/UIImageTypes/UIImageType.cs
diff --git a/Runtime/UI/Nodes/UIImageTypes/UIImageType.cs.uid b/Runtime/UI/Nodes/Image/UIImageTypes/UIImageType.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UIImageTypes/UIImageType.cs.uid
rename to Runtime/UI/Nodes/Image/UIImageTypes/UIImageType.cs.uid
diff --git a/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs b/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs
new file mode 100644
index 0000000..15ee4c1
--- /dev/null
+++ b/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs
@@ -0,0 +1,45 @@
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class ChangeUIListSelection:Action
+{
+
+ [Export]
+ public UIListSelection selection;
+
+ public enum Mode
+ {
+ Set,
+ Change
+ }
+
+ [Export]
+ public Mode mode;
+
+ [Export]
+ public int value;
+
+ protected override void _OnTrigger()
+ {
+
+ if ( selection == null )
+ {
+ return;
+ }
+
+ if ( Mode.Set == mode )
+ {
+ selection.selected = value;
+ }
+ else if ( Mode.Change == mode )
+ {
+ selection.selected = MathX.Repeat( selection.selected + value, selection.values.Length );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs.uid b/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs.uid
new file mode 100644
index 0000000..f989e90
--- /dev/null
+++ b/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs.uid
@@ -0,0 +1 @@
+uid://b50yldymrhply
diff --git a/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs b/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs
new file mode 100644
index 0000000..62eb714
--- /dev/null
+++ b/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs
@@ -0,0 +1,72 @@
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIListSelection:UIText, UIFocusProcessor
+{
+ int _selected = -1;
+ LocalizedString _selectedOption = null;
+
+ public string SerializeSelectedOption()
+ {
+ return _selectedOption.GetLocalizedString( LocaleCode.en );
+ }
+
+ public void SetSelectedBySerialized( string serializedEntry )
+ {
+ var index = values.ToList().FindIndex( v => v.GetLocalizedString( LocaleCode.en ) == serializedEntry );
+
+ selected = index;
+
+ }
+
+ public void OnFocusProcess( double delta )
+ {
+
+ }
+
+ [Export]
+ public Action onSelectionChange;
+ public EventSlot _onSelectionChange = new EventSlot();
+
+ [Export]
+ public int selected
+ {
+ get => _selected;
+ set
+ {
+ if ( values == null || values.Length <= 0 )
+ {
+ _selected = selected;
+ return;
+ }
+
+ var next = Mathf.Clamp( value, 0, values.Length - 1 );
+
+ if ( _selected == next )
+ {
+ return;
+ }
+
+ _selected = next;
+ SyncSelection();
+ onSelectionChange?.Trigger();
+ _onSelectionChange.DispatchEvent( _selected );
+ }
+ }
+
+ void SyncSelection()
+ {
+ locale = values[ _selected ];
+ }
+
+ [Export]
+ public LocalizedString[] values = [];
+
+
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs.uid b/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs.uid
new file mode 100644
index 0000000..c893bdf
--- /dev/null
+++ b/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs.uid
@@ -0,0 +1 @@
+uid://2ftd0bt6rrgo
diff --git a/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs
new file mode 100644
index 0000000..135b978
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs
@@ -0,0 +1,75 @@
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")]
+public partial class UIScrollSlider:UISlider
+{
+ [Export]
+ public Control scrollArea;
+
+ [Export]
+ public Control scrollContainer;
+
+ bool _hasEventListener = false;
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ if ( ! _hasEventListener )
+ {
+ _onSliderChange.AddAction( ( pos ) => { SyncScroll(); } );
+ _hasEventListener = true;
+ }
+
+ }
+
+ [Export]
+ public bool recreateMaterial = false;
+
+ public override void _Process( double delta )
+ {
+ if ( recreateMaterial )
+ {
+ UpdateImageType();
+ recreateMaterial = false;
+ }
+
+ base._Process( delta );
+ }
+
+ Vector2 _lastOffset = Vector2.Zero;
+
+ public void SyncScroll()
+ {
+ var containerSize = scrollContainer.Size;
+ var areaSize = scrollArea.Size;
+
+ var scroll = areaSize - containerSize;
+ scroll = scroll.Max( Vector2.Zero );
+
+ var stylable = scrollArea as UIStylePropertyContainerNode;
+
+ var scrollOffset = -scroll * sliderValue;
+
+ var diff = _lastOffset - scrollOffset;
+
+ this.LogInfo( scroll, sliderValue, scrollOffset );
+
+
+ if ( stylable == null )
+ {
+ scrollArea.Position = scroll * sliderValue;
+ }
+ else
+ {
+ stylable.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, UINumber.Create( scrollOffset.X, "px" ) );
+ stylable.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, UINumber.Create( scrollOffset.Y, "px" ) );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs.uid b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs.uid
new file mode 100644
index 0000000..2371658
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ScrollSlider/UIScrollSlider.cs.uid
@@ -0,0 +1 @@
+uid://ciqgpp82a2wr0
diff --git a/Runtime/UI/Nodes/Sliders/UISlider.cs b/Runtime/UI/Nodes/Sliders/UISlider.cs
new file mode 100644
index 0000000..d8de45f
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/UISlider.cs
@@ -0,0 +1,478 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")]
+public partial class UISlider:UIImage, UIFocusProcessor
+{
+ public enum Direction
+ {
+ Vertical,
+ Horizontal,
+ Both
+ }
+
+ [Export]
+ public Direction direction = Direction.Vertical;
+
+ [Export]
+ public float offsetPerInput = 1f / 20f;
+
+
+ [Export]
+ public Smoothing smoothing;
+
+
+ [Export]
+ public Action onSliderChange;
+ public readonly EventSlot _onSliderChange = new EventSlot();
+
+ [ExportGroup("Testing")]
+ // [Export( PropertyHint.Range, "0,1")]
+ // public Vector2 editorSliderValue = Vector2.Zero;
+
+ Vector2 _sliderValue;
+
+ [Export( PropertyHint.Range, "0,1")]
+ public Vector2 sliderValue
+ {
+ get { return _sliderValue; }
+ set
+ {
+ _sliderValue = value;
+ SyncSliderValue();
+ }
+ }
+
+ public float mainValue => direction == Direction.Vertical ? sliderValue.Y : sliderValue.X;
+
+ public Vector2 GetNextSliderMainValue( float value )
+ {
+ if ( Direction.Vertical == direction )
+ {
+ return new Vector2( 0.5f, value );
+ }
+ else
+ {
+ return new Vector2( value, 0.5f );
+ }
+ }
+
+ public void SetSliderMainValue( float value )
+ {
+ if ( Direction.Vertical == direction )
+ {
+ _sliderValue.Y = value;
+ }
+ else
+ {
+ _sliderValue.X = value;
+ }
+
+ SyncSliderValue();
+
+ _onSliderChange.DispatchEvent( _sliderValue );
+ onSliderChange?.Trigger();
+
+ }
+
+ void SyncSliderValue()
+ {
+ SliderShader.sliderValue.Set( Material, sliderValue );
+ // this.LogInfo( "Set slider value:", sliderValue, Material );
+
+ // var sm = Material as ShaderMaterial;
+ // sm.SetShaderParameter( "sliderValue", sliderValue );
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ if ( imageType == null )
+ {
+ imageType = new SliderUIImageType();
+ }
+
+ if ( Texture == null )
+ {
+ Texture = UI.whiteTexture.Get();
+ }
+
+ var uiSliderImageType = _imageType as SliderUIImageType;
+
+ if ( uiSliderImageType != null )
+ {
+ uiSliderImageType.Clear( this );
+ uiSliderImageType.Assign( this );
+
+ }
+
+ ComputeUIAncestorDepth();
+
+ SyncSliderValue();
+
+
+ AssignListener();
+ }
+
+ [Export]
+ public bool debugInfo = false;
+
+ [Export]
+ public string[] propertyInfos = [];
+
+
+ float lastLeft = 0f;
+ float lastRight = 0f;
+ float lastUp = 0f;
+ float lastDown = 0f;
+
+ public void OnFocusProcess( double delta )
+ {
+ var settings = GetUI().settings;
+
+ if ( settings == null )
+ {
+ return;
+ }
+
+ if ( Direction.Horizontal == direction )
+ {
+
+ var offset = 0;
+
+ if ( settings.uiLeft.IsRepeatDown( ref lastLeft ) )
+ {
+ offset --;
+ }
+
+ if ( settings.uiRight.IsRepeatDown( ref lastRight ) )
+ {
+ offset ++;
+ }
+
+ if ( offset != 0 )
+ {
+ var nextMainValue = MathX.Clamp01( mainValue + offset * offsetPerInput );
+ nextValue = NormalizedToButtonPosition( GetNextSliderMainValue( nextMainValue ) );
+
+ if ( ! _updatingPosition )
+ {
+ _updatingPosition = true;
+ GetUI().onProcess.AddAction( UpdatePosition );
+ }
+
+ }
+ }
+
+
+ // UpdatePosition( (float) delta );
+ }
+
+ // public override void _GuiInput( InputEvent inputEvent )
+ // {
+ // if ( ! processInputs )
+ // {
+ // return;
+ // }
+
+ // if ( ! HasFocus() )
+ // {
+ // return;
+ // }
+
+ // var settings = GetUI()?.settings;
+
+ // if ( settings == null )
+ // {
+ // return;
+ // }
+
+ // if ( Direction.Horizontal == direction )
+ // {
+ // var offset = 0;
+
+ // // this.LogInfo( Sensor.GetInputEventInfo( inputEvent ) );
+ // // this.LogInfo(
+ // // "Is Horizontal",
+ // // "Left:", settings.uiLeft.IsSensor( inputEvent ), "Left Down:", settings.uiLeft.IsDown( inputEvent ),
+ // // "Right:", settings.uiRight.IsSensor( inputEvent ), "Right Down:", settings.uiRight.IsDown( inputEvent )
+ // // );
+
+ // if ( settings.uiLeft.IsDown( inputEvent ) )
+ // {
+ // offset --;
+ // }
+
+ // if ( settings.uiRight.IsDown( inputEvent ) )
+ // {
+ // offset ++;
+ // }
+
+ // if ( offset != 0 )
+ // {
+ // // this.LogInfo( "Offset", offset );
+
+ // var nextValue = MathX.Clamp01( mainValue + offset * offsetPerInput );
+ // SetSliderMainValue( nextValue );
+ // }
+ // }
+
+ // if ( Direction.Vertical == direction )
+ // {
+ // var offset = 0;
+
+ // if ( settings.uiUp?.isActive ?? false )
+ // {
+ // offset --;
+ // }
+
+ // if ( settings.uiDown?.isActive ?? false )
+ // {
+ // offset ++;
+ // }
+
+ // var nextValue = MathX.Clamp01( mainValue + offset * offsetPerInput );
+ // SetSliderMainValue( nextValue );
+ // }
+ // }
+
+ public override void _Process( double delta )
+ {
+ // ProcessInputs();
+
+ if ( ! debugInfo )
+ {
+ return;
+ }
+
+
+
+
+ var it = imageType as SliderUIImageType;
+
+ if ( it == null )
+ {
+ return;
+ }
+
+ var propNames = it.GetNumberShaderProperties();
+
+ 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 );
+
+ var infos = new List();
+
+ for ( int i = 0; i < propNames.Length; i++ )
+ {
+ var n = propNames[ i ];
+ var p = it.GetUIStyleNumberProperty( UIStyleNumberProperty.FloatShaderProperty, n );
+
+ if ( p == null )
+ {
+ continue;
+ }
+
+ var relative = 100f;
+
+ if ( n.EndsWith( "X" ) )
+ {
+ relative = w;
+ }
+ else if ( n.EndsWith( "Y" ) )
+ {
+ relative = h;
+ }
+
+
+ var value = UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
+ infos.Add( "[" + n + "] (" + p.value._FFF() + " * " + p.unit +") :" + value._FFF() );
+ }
+
+ propertyInfos = infos.ToArray();
+
+ this.LogInfo( propertyInfos );
+
+
+ debugInfo = false;
+
+ }
+
+
+
+ UIDragging.UIDraggingCallbacks leftMouseCallbacks;
+ Vector2 cachedMouseOffset;
+ Vector2 cachedButtonPosition;
+
+ bool _dragging = false;
+ bool _updatingPosition = false;
+
+ string scrollID = IDGenerator.GenerateID();
+
+ float ComputeShaderProperty( string n, float relative = 100 )
+ {
+ return UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
+ }
+
+ Vector2 sliderSize
+ {
+ get
+ {
+ 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 );
+
+ var valueX = ComputeShaderProperty( SliderShader.sliderSizeX.propertyName, w );
+ var valueY = ComputeShaderProperty( SliderShader.sliderSizeY.propertyName, h );
+
+ return new Vector2( valueX, valueY );
+ }
+ }
+
+ Vector2 sliderSizeMargins
+ {
+ get
+ {
+ 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 );
+
+ var valueX = ComputeShaderProperty( SliderShader.sliderSizeMarginX.propertyName, w );
+ var valueY = ComputeShaderProperty( SliderShader.sliderSizeMarginY.propertyName, h );
+
+ return new Vector2( valueX, valueY );
+ }
+ }
+
+ Vector2 sliderRange => Size - ( sliderSize + sliderSizeMargins );
+ Vector2 sliderOffset => sliderSize;
+
+ Vector2 buttonPositionMin
+ {
+ get { return NormalizedToButtonPosition( Vector2.Zero ); }
+ }
+
+ Vector2 buttonPositionMax
+ {
+ get { return NormalizedToButtonPosition( Vector2.One ); }
+ }
+
+
+ Vector2 NormalizedToButtonPosition( Vector2 normalized )
+ {
+ return normalized * sliderRange + sliderOffset;
+ }
+
+ Vector2 ButtonPositionToNormalized( Vector2 buttonPosition )
+ {
+ return ( buttonPosition - sliderOffset ) / sliderRange;
+ }
+
+
+ bool _listenerAssigned = false;
+
+ void AssignListener()
+ {
+ if ( _listenerAssigned )
+ {
+ return;
+ }
+
+ leftMouseCallbacks = UIDragging.OnLeftMouseButton( this,
+ ( ev )=>
+ {
+ if ( ev.isStart )
+ {
+ if ( ! ( _updatingPosition || _dragging ) )
+ {
+ cachedButtonPosition = NormalizedToButtonPosition( sliderValue );
+ smoothing?.SetCurrent( cachedButtonPosition );
+
+ _dragging = true;
+ _updatingPosition = true;
+
+ ev.ui.onProcess.AddAction( UpdatePosition );
+ }
+
+ }
+ else if ( ev.isEnd )
+ {
+ _dragging = false;
+ }
+
+ var nextPosition = cachedButtonPosition + ev.distanceToStart;
+ nextValue = nextPosition.Clamp( buttonPositionMin, buttonPositionMax );
+
+ }
+ );
+
+ _listenerAssigned = true;
+ }
+
+ Vector2 nextValue;
+
+ Vector2 GetButtonScrollRange()
+ {
+ return Vector2.Zero;
+ // return ( Size - button.Size ).Max( Vector2.Zero );
+ }
+
+ Vector2 cachedOffset = Vector2.Zero;
+
+ void UpdatePosition( float delta )
+ {
+
+ var value = Smoothing.Apply( smoothing, nextValue, delta );
+
+ // this.LogInfo( "UpdatePosition:", value );
+
+ var uiStyleContainer = ( UIStylePropertyContainerNode ) this;
+
+ uiStyleContainer.SetLayoutDirtyFlag();
+
+ if ( ! _dragging && ( value - nextValue ).Length() < 1 )
+ {
+ var ui = UIHolder.GetUI( this );
+ ui.onProcess.RemoveAction( UpdatePosition );
+ _updatingPosition = false;
+ // this.LogInfo( "Removed Processing" );
+
+ value = nextValue;
+
+ uiStyleContainer.RemoveUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
+
+ }
+
+ var currentSliderValue = ButtonPositionToNormalized( value );
+
+ if ( Direction.Vertical == direction )
+ {
+ currentSliderValue.X = 0.5f;
+ }
+ else if ( Direction.Horizontal == direction )
+ {
+ currentSliderValue.Y = 0.5f;
+ }
+
+ _sliderValue = currentSliderValue;
+ SyncSliderValue();
+
+ onSliderChange?.Trigger();
+ _onSliderChange.DispatchEvent( _sliderValue );
+
+ }
+
+}
diff --git a/Runtime/UI/Nodes/UISlider.cs.uid b/Runtime/UI/Nodes/Sliders/UISlider.cs.uid
similarity index 100%
rename from Runtime/UI/Nodes/UISlider.cs.uid
rename to Runtime/UI/Nodes/Sliders/UISlider.cs.uid
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs b/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs
new file mode 100644
index 0000000..f4e1bd2
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs
@@ -0,0 +1,125 @@
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIFloatValueMode:UIValueSliderMode
+{
+ [Export]
+ public LocalizedString prefix;
+
+ [Export]
+ public float min = 0;
+
+ [Export]
+ public float max = 1;
+
+ [Export]
+ public int steps = -1;
+
+ [Export]
+ public float stepSize = -1;
+
+ public enum DecimialPoints
+ {
+ Int,
+ I_0,
+ I_00,
+ I_000
+ }
+
+ [Export]
+ public DecimialPoints decimialPoints = DecimialPoints.Int;
+
+ [Export]
+ public LocalizedString suffix;
+
+ public static UIFloatValueMode From( NumberAppSetting numberAppSetting )
+ {
+ var mode = new UIFloatValueMode();
+ mode.CopyFrom( numberAppSetting );
+ return mode;
+ }
+
+ public void CopyFrom( NumberAppSetting numberAppSetting )
+ {
+ prefix = numberAppSetting.prefix;
+ suffix = numberAppSetting.suffix;
+ steps = numberAppSetting.steps;
+ stepSize = numberAppSetting.stepSize;
+ min = numberAppSetting.min;
+ max = numberAppSetting.max;
+ decimialPoints = numberAppSetting.decimialPoints;
+ }
+
+ public int combinedSteps => steps > 0 ? steps :
+ stepSize > 0 ? Mathf.CeilToInt( ( max - min ) / stepSize ) :
+ -1;
+
+
+
+
+ public string prefixValue => prefix?.currentValue ?? "";
+ public string suffixValue => suffix?.currentValue ?? "";
+
+ public float quantize( float normalized )
+ {
+ var comSteps = combinedSteps;
+
+ if ( comSteps <= 0 )
+ {
+ return normalized;
+ }
+
+ return MathX.SnapRounded( normalized, 1f / comSteps );
+ }
+
+ public override string NormalizedToLabel( float normalized )
+ {
+ normalized = quantize( normalized );
+
+ var value = MathX.LerpClamped( min, max, normalized );
+
+ var stringValue = "";
+
+ if ( DecimialPoints.Int == decimialPoints )
+ {
+ stringValue = Mathf.RoundToInt( value ) + "";
+ }
+ else
+ {
+ stringValue = DecimialPoints.I_0 == decimialPoints ? value._F() :
+ DecimialPoints.I_00 == decimialPoints ? value._FF() :
+ value._FFF();
+ }
+
+
+ return prefixValue + stringValue + suffixValue;
+ }
+
+ public float GetValueFromNormalized( float normalized )
+ {
+ normalized = quantize( normalized );
+ return MathX.LerpClamped( min, max, normalized );
+ }
+
+ public override string GetSerializedValue( float normalized )
+ {
+ return GetValueFromNormalized( normalized )._G();
+ }
+
+ public override float FromSerializedToNormalized( string serialized )
+ {
+ var value = RegexUtility.ParseFloat( serialized );
+ return MathX.Normalize( value, min, max );
+ }
+
+ public override float LabelToNormalized( string label )
+ {
+ var value = RegexUtility.ParseFloat( label.ReplaceStart( prefixValue, "" ).ReplaceEnd( suffixValue, "" ) );
+
+ return MathX.Normalize( value, min, max );
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs.uid b/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs.uid
new file mode 100644
index 0000000..56710fc
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs.uid
@@ -0,0 +1 @@
+uid://bsonpc71ochpe
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs b/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs
new file mode 100644
index 0000000..3341eee
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs
@@ -0,0 +1,26 @@
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIResolutionScaleMode:UIFloatValueMode
+{
+ [Export]
+ public float userScaleToResolutionScale = 1f / 100f;
+ public Vector2 windowSize;
+
+
+
+ public override string NormalizedToLabel( float normalized )
+ {
+ var stringValue = base.NormalizedToLabel( normalized );
+ var scale = GetValueFromNormalized( normalized ) * userScaleToResolutionScale;
+
+ var win = windowSize * scale;
+ var winx = Mathf.RoundToInt( win.X );
+ var winy = Mathf.RoundToInt( win.Y );
+
+ return stringValue + "(" + winx + "x" + winy +")";
+ }
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs.uid b/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs.uid
new file mode 100644
index 0000000..1231c56
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIResolutionScaleMode.cs.uid
@@ -0,0 +1 @@
+uid://dtli3dnpem82l
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs
new file mode 100644
index 0000000..7a64586
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs
@@ -0,0 +1,51 @@
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")]
+public partial class UIValueSlider:UISlider
+{
+ [Export]
+ public UIText valueText;
+
+ [Export]
+ public UIValueSliderMode mode;
+
+ bool _hasEventListener = false;
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ if ( ! _hasEventListener )
+ {
+ _onSliderChange.AddAction( ( pos ) => { SyncScroll(); } );
+ _hasEventListener = true;
+ }
+
+ }
+
+ [Export]
+ public bool recreateMaterial = false;
+
+ public override void _Process( double delta )
+ {
+ if ( recreateMaterial )
+ {
+ UpdateImageType();
+ recreateMaterial = false;
+ }
+
+ base._Process( delta );
+ }
+
+ public void SyncScroll()
+ {
+ var label = mode.NormalizedToLabel( mainValue );
+ valueText.locale = LocaleText.Create( label );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs.uid b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs.uid
new file mode 100644
index 0000000..9619b94
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs.uid
@@ -0,0 +1 @@
+uid://cqi3jitprf7o0
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs
new file mode 100644
index 0000000..8613cf8
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs
@@ -0,0 +1,24 @@
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public abstract partial class UIValueSliderMode:Resource
+{
+ public abstract string NormalizedToLabel( float normalized );
+ public virtual string GetSerializedValue( float normalized )
+ {
+ return NormalizedToLabel( normalized );
+ }
+
+ public abstract float LabelToNormalized( string label );
+ public virtual float FromSerializedToNormalized( string serialized )
+ {
+ return LabelToNormalized( serialized );
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs.uid b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs.uid
new file mode 100644
index 0000000..27bce3d
--- /dev/null
+++ b/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSliderMode.cs.uid
@@ -0,0 +1 @@
+uid://srhht1qmu0jv
diff --git a/Runtime/UI/Nodes/UIFocusProcessor.cs b/Runtime/UI/Nodes/UIFocusProcessor.cs
new file mode 100644
index 0000000..dd8b79f
--- /dev/null
+++ b/Runtime/UI/Nodes/UIFocusProcessor.cs
@@ -0,0 +1,11 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public interface UIFocusProcessor
+{
+ public void OnFocusProcess( double delta );
+}
diff --git a/Runtime/UI/Nodes/UIFocusProcessor.cs.uid b/Runtime/UI/Nodes/UIFocusProcessor.cs.uid
new file mode 100644
index 0000000..c992adc
--- /dev/null
+++ b/Runtime/UI/Nodes/UIFocusProcessor.cs.uid
@@ -0,0 +1 @@
+uid://dx4fcgne8btqm
diff --git a/Runtime/UI/Nodes/UIRegion.cs b/Runtime/UI/Nodes/UIRegion.cs
index 00ef565..0eda2ed 100644
--- a/Runtime/UI/Nodes/UIRegion.cs
+++ b/Runtime/UI/Nodes/UIRegion.cs
@@ -136,7 +136,45 @@ namespace Rokojori
{
return activeColorTransitions;
}
-
+
+ [ExportGroup( "Sound" )]
+ [Export]
+ public UISoundData onFocusSound;
+ [Export]
+ public UISoundData onBlurSound;
+
+ public UISoundData GetUISoundProperty( UISoundProperty property )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ return onFocusSound;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ return onFocusSound;
+ }
+
+ return null;
+ }
+
+ public void SetUISoundProperty( UISoundProperty property, UISoundData stream )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ onFocusSound = stream;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ onFocusSound = stream;
+ }
+ }
+
+ [Export]
+ public Action onFocusEntered;
+
+ [Export]
+ public Action onFocusExited;
+
#if TOOLS
[ExportGroup("Editor SceneSetup")]
[Export]
@@ -327,6 +365,36 @@ namespace Rokojori
public override void _Ready()
{
+ FocusEntered += ()=>
+ {
+ AddUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusEntered );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ onFocusEntered?.Trigger();
+
+ };
+
+ FocusExited += ()=>
+ {
+ RemoveUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusExited );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ onFocusExited?.Trigger();
+ };
+
+
MouseEntered += ()=>
{
AddUISelectorFlag( UISelectorFlag.Hover, hoverID );
@@ -405,6 +473,15 @@ namespace Rokojori
UISelector.UpdateParentUISelectorFlags( this );
+ this.LogInfo(
+ "flag:", flag,
+ "reference:", reference,
+ "enable:", enable,
+ "changed:", changed,
+ "numFlagsBefore:", numFlagsBefore,
+ "_selectorFlags:", _selectorFlags.Map( sf => sf.ResourcePath + " " + sf.ResourceName ).Join( ", " )
+ );
+
if ( changed )
{
this.SetDirty();
diff --git a/Runtime/UI/Nodes/UIScrollContainer.cs b/Runtime/UI/Nodes/UIScrollContainer.cs
deleted file mode 100644
index 2da30f9..0000000
--- a/Runtime/UI/Nodes/UIScrollContainer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-
-using Godot;
-using Rokojori;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Rokojori
-{
- [Tool]
- [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRegion.svg")]
- public partial class UIScrollContainer:UIRegion
- {
- [Export]
- public Control horizontalSlider;
-
- [Export]
- public Control verticalSlider;
-
- [Export]
- public Control content;
-
- public override void _Ready()
- {
-
- }
-
- bool _initialized = false;
-
- void Initialize()
- {
- if ( _initialized )
- {
- return;
- }
-
-
- }
- }
-}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/UIScrollContainer.cs.uid b/Runtime/UI/Nodes/UIScrollContainer.cs.uid
deleted file mode 100644
index 32b5443..0000000
--- a/Runtime/UI/Nodes/UIScrollContainer.cs.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://btmqvwluvjwo0
diff --git a/Runtime/UI/Nodes/UISlider.cs b/Runtime/UI/Nodes/UISlider.cs
deleted file mode 100644
index 2e7269f..0000000
--- a/Runtime/UI/Nodes/UISlider.cs
+++ /dev/null
@@ -1,302 +0,0 @@
-
-
-
-
-using Godot;
-using Rokojori;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Rokojori
-{
- [Tool]
- [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")]
- public partial class UISlider:UIImage
- {
- public enum Direction
- {
- Vertical,
- Horizontal,
- Both
- }
-
- [Export]
- public Direction direction = Direction.Vertical;
-
- [Export]
- public Smoothing smoothing;
-
- Vector2 _sliderValue;
-
- [Export]
- public Vector2 sliderValue
- {
- get { return _sliderValue; }
- set
- {
- _sliderValue = value;
- SyncSliderValue();
- }
- }
-
- void SyncSliderValue()
- {
- SliderShader.sliderValue.Set( Material, sliderValue );
- }
-
- public override void _Ready()
- {
- base._Ready();
-
- if ( imageType == null )
- {
- imageType = new SliderUIImageType();
- }
-
- if ( Texture == null )
- {
- Texture = UI.whiteTexture.Get();
- }
-
- var uiSliderImageType = _imageType as SliderUIImageType;
-
- if ( uiSliderImageType != null )
- {
- uiSliderImageType.Clear( this );
- uiSliderImageType.Assign( this );
-
- }
-
- ComputeUIAncestorDepth();
-
- SyncSliderValue();
-
-
- AssignListener();
- }
-
- [Export]
- public bool debugInfo = false;
-
- [Export]
- public string[] propertyInfos = [];
-
- public override void _Process( double delta )
- {
- if ( ! debugInfo )
- {
- return;
- }
-
- var it = imageType as SliderUIImageType;
-
- if ( it == null )
- {
- return;
- }
-
- var propNames = it.GetNumberShaderProperties();
-
- 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 );
-
- var infos = new List();
- for ( int i = 0; i < propNames.Length; i++ )
- {
- var n = propNames[ i ];
- var p = it.GetUIStyleNumberProperty( UIStyleNumberProperty.FloatShaderProperty, n );
-
- if ( p == null )
- {
- continue;
- }
-
- var relative = 100f;
-
- if ( n.EndsWith( ".x" ) )
- {
- relative = w;
- }
- else if ( n.EndsWith( ".y" ) )
- {
- relative = h;
- }
-
-
- var value = UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
- infos.Add( "[" + n + "] (" + p.value._FFF() + " * " + p.unit +") :" + value._FFF() );
- }
-
- propertyInfos = infos.ToArray();
-
- this.LogInfo( propertyInfos );
-
-
- debugInfo = false;
-
- }
-
-
-
- UIDragging.UIDraggingCallbacks leftMouseCallbacks;
- Vector2 cachedMouseOffset;
- Vector2 cachedButtonPosition;
-
- bool _dragging = false;
- bool _updatingPosition = false;
-
- string scrollID = IDGenerator.GenerateID();
-
- float ComputeShaderProperty( string n, float relative = 100 )
- {
- return UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
- }
-
- Vector2 sliderSize
- {
- get
- {
- 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 );
-
- var valueX = ComputeShaderProperty( SliderShader.sliderSize.propertyNameX, w );
- var valueY = ComputeShaderProperty( SliderShader.sliderSize.propertyNameY, h );
-
- return new Vector2( valueX, valueY );
- }
- }
-
- Vector2 sliderSizeMargins
- {
- get
- {
- 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 );
-
- var valueX = ComputeShaderProperty( SliderShader.sliderSizeMargins.propertyNameX, w );
- var valueY = ComputeShaderProperty( SliderShader.sliderSizeMargins.propertyNameY, h );
-
- return new Vector2( valueX, valueY );
- }
- }
-
- Vector2 sliderRange => Size - ( sliderSize + sliderSizeMargins );
- Vector2 sliderOffset => sliderSize;
-
- Vector2 buttonPositionMin
- {
- get { return NormalizedToButtonPosition( Vector2.Zero ); }
- }
-
- Vector2 buttonPositionMax
- {
- get { return NormalizedToButtonPosition( Vector2.One ); }
- }
-
-
- Vector2 NormalizedToButtonPosition( Vector2 normalized )
- {
- return normalized * sliderRange + sliderOffset;
- }
-
- Vector2 ButtonPositionToNormalized( Vector2 buttonPosition )
- {
- return ( buttonPosition - sliderOffset ) / sliderRange;
- }
-
-
- bool _listenerAssigned = false;
-
- void AssignListener()
- {
- if ( _listenerAssigned )
- {
- return;
- }
-
- leftMouseCallbacks = UIDragging.OnLeftMouseButton( this,
- ( ev )=>
- {
- if ( ev.isStart )
- {
- cachedButtonPosition = NormalizedToButtonPosition( sliderValue );
- smoothing.SetCurrent( cachedButtonPosition );
-
- _dragging = true;
- _updatingPosition = true;
-
- ev.ui.onProcess.AddAction( UpdatePosition );
- }
- else if ( ev.isEnd )
- {
- _dragging = false;
- }
-
- var nextPosition = cachedButtonPosition + ev.distanceToStart;
- nextValue = nextPosition.Clamp( buttonPositionMin, buttonPositionMax );
-
- }
- );
-
- _listenerAssigned = true;
- }
-
- Vector2 nextValue;
-
- Vector2 GetButtonScrollRange()
- {
- return Vector2.Zero;
- // return ( Size - button.Size ).Max( Vector2.Zero );
- }
-
- Vector2 cachedOffset = Vector2.Zero;
-
- void UpdatePosition( float delta )
- {
- // this.LogInfo( "UpdatePosition" );
- var value = Smoothing.Apply( smoothing, nextValue, delta );
-
- var uiStyleContainer = ( UIStylePropertyContainerNode ) this;
-
- uiStyleContainer.SetLayoutDirtyFlag();
-
- if ( ! _dragging && ( value - nextValue ).Length() < 1 )
- {
- var ui = UIHolder.GetUI( this );
- ui.onProcess.RemoveAction( UpdatePosition );
- _updatingPosition = false;
- // this.LogInfo( "Removed Processing" );
-
- value = nextValue;
-
- uiStyleContainer.RemoveUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
-
- }
-
- var currentSliderValue = ButtonPositionToNormalized( value );
-
- if ( Direction.Vertical == direction )
- {
- currentSliderValue.X = 0.5f;
- }
- else if ( Direction.Vertical == direction )
- {
- currentSliderValue.Y = 0.5f;
- }
-
- _sliderValue = currentSliderValue;
- SyncSliderValue();
-
- }
-
- }
-}
\ No newline at end of file
diff --git a/Runtime/UI/Nodes/UIText.cs b/Runtime/UI/Nodes/UIText.cs
index 3ee8c49..2cac4fd 100644
--- a/Runtime/UI/Nodes/UIText.cs
+++ b/Runtime/UI/Nodes/UIText.cs
@@ -156,6 +156,8 @@ namespace Rokojori
[Export]
public UIColor selfModulationColor;
+
+
public Font GetFont()
{
return font;
@@ -180,9 +182,52 @@ namespace Rokojori
string hoverID = IDGenerator.GenerateID();
UICursor appliedCursor = null;
-
+
public override void _Ready()
{
+ FocusEntered += ()=>
+ {
+ AddUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusEntered );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ setActiveWhenFocused?.ForEach(
+ ( c )=>
+ {
+ var uiStylable = c as UIStylePropertyContainerNode;
+
+ uiStylable?.AddUISelectorFlag( UISelectorFlag.Active );
+ }
+ );
+
+ };
+
+ FocusExited += ()=>
+ {
+ RemoveUISelectorFlag( UISelectorFlag.Focus );
+
+ var sound = UIStyle.GetUISound( this, UISoundProperty.FocusExited );
+
+ if ( sound != null )
+ {
+ GetUI().PlaySound( sound );
+ }
+
+ setActiveWhenFocused?.ForEach(
+ ( c )=>
+ {
+ var uiStylable = c as UIStylePropertyContainerNode;
+
+ uiStylable?.RemoveUISelectorFlag( UISelectorFlag.Active );
+ }
+ );
+ };
+
MouseEntered += ()=>
{
AddUISelectorFlag( UISelectorFlag.Hover, hoverID );
@@ -300,16 +345,30 @@ namespace Rokojori
}
public override void _GuiInput( InputEvent inputEvent )
- {
+ {
+ var ui = GetUI();
+
+ // this.LogInfo( "InputEvent", inputEvent, ui.settings.uiConfirm.IsDown( inputEvent ) );
+
+ if ( ui.settings.uiConfirm.IsDown( inputEvent ) )
+ {
+ onUIConfirm?.Trigger();
+ // GD.Print("ui_accept pressed while focused");
+ // AcceptEvent(); // Optional: stop propagation
+ }
+
if ( ! handleMouseEvents )
{
return;
}
+
if ( inputEvent is InputEventMouseButton mb )
{
if ( mb.Pressed )
{
+ this.LogInfo( "Clicked" );
+
if ( mb.ButtonIndex == MouseButton.Left )
{
Action.Trigger( onLeftClick );
@@ -388,7 +447,7 @@ namespace Rokojori
}
}
- [ExportGroup("Pointer")]
+ [ExportGroup( "Interactivity" )]
[Export]
public UICursor hoverCursor;
@@ -399,6 +458,18 @@ namespace Rokojori
}
+ [Export]
+ public Action onUIConfirm;
+
+ [Export]
+ public Action onFocusEntered;
+
+ [Export]
+ public Action onFocusExited;
+
+ [Export]
+ public Control[] setActiveWhenFocused = [];
+
[Export]
public bool handleMouseEvents = false;
@@ -411,6 +482,39 @@ namespace Rokojori
[Export]
public Action onRightClick;
+ [ExportGroup( "Sound" )]
+ [Export]
+ public UISoundData onFocusSound;
+ [Export]
+ public UISoundData onBlurSound;
+
+ public UISoundData GetUISoundProperty( UISoundProperty property )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ return onFocusSound;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ return onFocusSound;
+ }
+
+ return null;
+ }
+
+ public void SetUISoundProperty( UISoundProperty property, UISoundData stream )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ onFocusSound = stream;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ onFocusSound = stream;
+ }
+ }
+
+
public UIStyle GetUIStyleParent()
{
return parentStyle;
@@ -447,6 +551,7 @@ namespace Rokojori
return null;
}
+
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source )
diff --git a/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader b/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader
index 3d5ddf4..b728cbf 100644
--- a/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader
+++ b/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader
@@ -12,17 +12,17 @@ uniform float strokeSize = 5;
uniform float offset;
uniform vec4 fillColor:source_color;
-uniform sampler2D fill;
+uniform sampler2D fill:source_color;
uniform vec4 fillUVTransform;
-uniform sampler2D screenFillMultiply;
+uniform sampler2D screenFillMultiply:source_color;
uniform vec4 screenfillMultiplyUVTransform;
uniform vec2 screenfillMultiplyUVMovement;
uniform vec4 strokeColor:source_color;
-uniform sampler2D stroke;
+uniform sampler2D stroke:source_color;
uniform vec4 strokeUVTransform;
-uniform sampler2D screenStrokeMultiply;
+uniform sampler2D screenStrokeMultiply:source_color;
uniform vec4 screenStrokeMultiplyUVTransform;
uniform vec2 screenStrokeMultiplyUVMovment;
@@ -60,10 +60,6 @@ float angleFill( vec2 uv, float angleDegrees, float offsetDegrees )
}
}
-void vertex()
-{
- // Called for every vertex the material is visible on.
-}
void fragment()
{
@@ -114,16 +110,12 @@ void fragment()
float mask = max ( fillMask , strokeMask );
mask = fillMask + strokeMask;
- vec4 tex = texture( TEXTURE, UV );
+ // vec4 tex = texture( TEXTURE, UV );
float anglefillState = angleFill( UV - vec2( 0.5 ), fillStateAngle, fillStateOffset );
+
+ float alpha = COLOR.a * outputColor.a * mask * opacity * anglefillState;
+ // alpha = clamp( alpha, 0.0, 1.0 ) * 5.0;
+ COLOR = vec4( COLOR.rgb * outputColor.rgb, alpha );
- COLOR *= vec4( outputColor.rgb * tex.rgb, outputColor.a * mask * opacity * tex.a * anglefillState);
-
- // Called for every pixel the material is visible on.
}
-
-//void light() {
- // Called for every pixel for every light affecting the CanvasItem.
- // Uncomment to replace the default light processing function with this one.
-//}
diff --git a/Runtime/UI/Shaders/Slider/Slider.gdshader b/Runtime/UI/Shaders/Slider/Slider.gdshader
index 6d5f972..bc155a3 100644
--- a/Runtime/UI/Shaders/Slider/Slider.gdshader
+++ b/Runtime/UI/Shaders/Slider/Slider.gdshader
@@ -35,9 +35,14 @@ uniform vec2 screenStrokeMultiplyUVMovment;
group_uniforms;
group_uniforms Slider;
-uniform vec2 sliderSize;
-uniform vec2 sliderSizeMargins;
-uniform float sliderBorders;
+// uniform vec2 sliderSize = vec2( 0.0 );
+// uniform vec2 sliderMinSize = vec2( 5.0, 5.0 );
+uniform float sliderSizeX = 0.0;
+uniform float sliderSizeY = 0.0;
+uniform float sliderSizeMarginX = 0.0;
+uniform float sliderSizeMarginY = 0.0;
+// uniform vec2 sliderSizeMargins = vec2( 0.0 );
+uniform float sliderBorders = 0.0;
uniform vec2 sliderValue;
group_uniforms;
@@ -63,15 +68,17 @@ vec4 createBorders( float borderSize, vec2 rectSize )
vec4 getSliderLayer( vec2 pixelPosition )
{
- vec2 sliderValueRange = size - ( sliderSize + sliderSizeMargins );
- vec2 sliderValueOffset = ( sliderSize + sliderSizeMargins ) / 2.0;
+ vec2 _sliderSize = vec2( sliderSizeX, sliderSizeY );
+ vec2 _sliderMargins = vec2( sliderSizeMarginX, sliderSizeMarginY );
+ vec2 sliderValueRange = size - ( _sliderSize + _sliderMargins );
+ vec2 sliderValueOffset = ( _sliderSize + _sliderMargins ) / 2.0;
vec2 sliderPosition = sliderValueOffset + sliderValueRange * sliderValue;
- vec4 borders = createBorders( sliderBorders, sliderSize );
+ vec4 borders = createBorders( sliderBorders, _sliderSize );
- float sd = sdRoundedBox( pixelPosition - sliderPosition, sliderSize / 2.0, borders );
+ float sd = sdRoundedBox( pixelPosition - sliderPosition, _sliderSize / 2.0, borders );
// vec4 sliderLayer = sdf_coloredShape( sd, sliderStrokeSize, sliderFillColor, sliderStrokeColor );
@@ -126,9 +133,9 @@ void fragment()
outputColor.rgb = LINEARtoSRGB( outputColor.rgb );
}
- vec4 tex = texture( TEXTURE, UV );
+ // vec4 tex = texture( TEXTURE, UV );
- COLOR = vec4( outputColor.rgb * tex.rgb, outputColor.a * opacity * tex.a);
+ COLOR = vec4( outputColor.rgb * COLOR.rgb, outputColor.a * opacity * COLOR.a);
}
diff --git a/Runtime/UI/Shaders/Slider/SliderMaterial.cs b/Runtime/UI/Shaders/Slider/SliderMaterial.cs
index 5b75755..5d39b8e 100644
--- a/Runtime/UI/Shaders/Slider/SliderMaterial.cs
+++ b/Runtime/UI/Shaders/Slider/SliderMaterial.cs
@@ -6,9 +6,11 @@ namespace Rokojori
public class SliderShader
{
+ ///*
public static readonly CachedResource shader = new CachedResource(
"res://addons/rokojori_action_library/Runtime/UI/Shaders/Slider/Slider.gdshader"
- );
+ );
+ //*/
public static readonly FloatPropertyName opacity = FloatPropertyName.Create( "opacity" );
public static readonly BoolPropertyName blendLinear = BoolPropertyName.Create( "blendLinear" );
@@ -29,8 +31,10 @@ namespace Rokojori
public static readonly Sampler2DPropertyName screenStrokeMultiply = Sampler2DPropertyName.Create( "screenStrokeMultiply" );
public static readonly Vector4PropertyName screenStrokeMultiplyUvTransform = Vector4PropertyName.Create( "screenStrokeMultiplyUVTransform" );
public static readonly Vector2PropertyName screenStrokeMultiplyUvMovment = Vector2PropertyName.Create( "screenStrokeMultiplyUVMovment" );
- public static readonly Vector2PropertyName sliderSize = Vector2PropertyName.Create( "sliderSize" );
- public static readonly Vector2PropertyName sliderSizeMargins = Vector2PropertyName.Create( "sliderSizeMargins" );
+ public static readonly FloatPropertyName sliderSizeX = FloatPropertyName.Create( "sliderSizeX" );
+ public static readonly FloatPropertyName sliderSizeY = FloatPropertyName.Create( "sliderSizeY" );
+ public static readonly FloatPropertyName sliderSizeMarginX = FloatPropertyName.Create( "sliderSizeMarginX" );
+ public static readonly FloatPropertyName sliderSizeMarginY = FloatPropertyName.Create( "sliderSizeMarginY" );
public static readonly FloatPropertyName sliderBorders = FloatPropertyName.Create( "sliderBorders" );
public static readonly Vector2PropertyName sliderValue = Vector2PropertyName.Create( "sliderValue" );
public static readonly ColorPropertyName sliderFillColor = ColorPropertyName.Create( "sliderFillColor" );
@@ -63,8 +67,10 @@ namespace Rokojori
public readonly CustomMaterialProperty screenStrokeMultiply;
public readonly CustomMaterialProperty screenStrokeMultiplyUvTransform;
public readonly CustomMaterialProperty screenStrokeMultiplyUvMovment;
- public readonly CustomMaterialProperty sliderSize;
- public readonly CustomMaterialProperty sliderSizeMargins;
+ public readonly CustomMaterialProperty sliderSizeX;
+ public readonly CustomMaterialProperty sliderSizeY;
+ public readonly CustomMaterialProperty sliderSizeMarginX;
+ public readonly CustomMaterialProperty sliderSizeMarginY;
public readonly CustomMaterialProperty sliderBorders;
public readonly CustomMaterialProperty sliderValue;
public readonly CustomMaterialProperty sliderFillColor;
@@ -73,7 +79,9 @@ namespace Rokojori
public SliderMaterial()
{
+ ///*
Shader = SliderShader.shader.Get();
+ //*/
opacity = new CustomMaterialProperty( this, SliderShader.opacity );
blendLinear = new CustomMaterialProperty( this, SliderShader.blendLinear );
@@ -94,8 +102,10 @@ namespace Rokojori
screenStrokeMultiply = new CustomMaterialProperty( this, SliderShader.screenStrokeMultiply );
screenStrokeMultiplyUvTransform = new CustomMaterialProperty( this, SliderShader.screenStrokeMultiplyUvTransform );
screenStrokeMultiplyUvMovment = new CustomMaterialProperty( this, SliderShader.screenStrokeMultiplyUvMovment );
- sliderSize = new CustomMaterialProperty( this, SliderShader.sliderSize );
- sliderSizeMargins = new CustomMaterialProperty( this, SliderShader.sliderSizeMargins );
+ sliderSizeX = new CustomMaterialProperty( this, SliderShader.sliderSizeX );
+ sliderSizeY = new CustomMaterialProperty( this, SliderShader.sliderSizeY );
+ sliderSizeMarginX = new CustomMaterialProperty( this, SliderShader.sliderSizeMarginX );
+ sliderSizeMarginY = new CustomMaterialProperty( this, SliderShader.sliderSizeMarginY );
sliderBorders = new CustomMaterialProperty( this, SliderShader.sliderBorders );
sliderValue = new CustomMaterialProperty( this, SliderShader.sliderValue );
sliderFillColor = new CustomMaterialProperty( this, SliderShader.sliderFillColor );
diff --git a/Runtime/UI/Sound/UISoundData.cs b/Runtime/UI/Sound/UISoundData.cs
new file mode 100644
index 0000000..9aee3f7
--- /dev/null
+++ b/Runtime/UI/Sound/UISoundData.cs
@@ -0,0 +1,20 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UISoundData: Resource
+{
+ [Export]
+ public Godot.AudioStream audio;
+
+ [Export( PropertyHint.Range, "0,1")]
+ public float volume = 1f;
+
+ [Export( PropertyHint.Range, "-36,36")]
+ public float pitchSemitonesOffset = 0f;
+
+}
+
diff --git a/Runtime/UI/Sound/UISoundData.cs.uid b/Runtime/UI/Sound/UISoundData.cs.uid
new file mode 100644
index 0000000..70289ee
--- /dev/null
+++ b/Runtime/UI/Sound/UISoundData.cs.uid
@@ -0,0 +1 @@
+uid://glochk7x1rvw
diff --git a/Runtime/UI/Styling/Presets/Numbers/0% (Left or Top).tres b/Runtime/UI/Styling/Presets/Numbers/0% (Left or Top).tres
new file mode 100644
index 0000000..a308586
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/0% (Left or Top).tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://cnbvpelp78wan"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_rgh8u"]
+
+[resource]
+script = ExtResource("1_rgh8u")
+unit = "%"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/0em (None).tres b/Runtime/UI/Styling/Presets/Numbers/0em (None).tres
new file mode 100644
index 0000000..74886a5
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/0em (None).tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://uarw3swsgl7"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_r2bdw"]
+
+[resource]
+script = ExtResource("1_r2bdw")
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/100ph (Parent Height).tres b/Runtime/UI/Styling/Presets/Numbers/100ph (Parent Height).tres
new file mode 100644
index 0000000..4b66a10
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/100ph (Parent Height).tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://did6kmvhnaxbd"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_6l6dl"]
+
+[resource]
+script = ExtResource("1_6l6dl")
+value = 100.0
+unit = "ph"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/100pw (Parent Width).tres b/Runtime/UI/Styling/Presets/Numbers/100pw (Parent Width).tres
new file mode 100644
index 0000000..687bddc
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/100pw (Parent Width).tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://dr68b4fprxige"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_qyj25"]
+
+[resource]
+script = ExtResource("1_qyj25")
+value = 100.0
+unit = "pw"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/100vh (Window Height).tres b/Runtime/UI/Styling/Presets/Numbers/100vh (Window Height).tres
new file mode 100644
index 0000000..a772416
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/100vh (Window Height).tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://deq3rcspgbfg7"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_77r26"]
+
+[resource]
+script = ExtResource("1_77r26")
+value = 100.0
+unit = "vh"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/100vw (Window Width).tres b/Runtime/UI/Styling/Presets/Numbers/100vw (Window Width).tres
new file mode 100644
index 0000000..c5ec0cc
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/100vw (Window Width).tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://fqdnpeq4oiq4"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_3a5q4"]
+
+[resource]
+script = ExtResource("1_3a5q4")
+value = 100.0
+unit = "vw"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/Presets/Numbers/50% (Centered).tres b/Runtime/UI/Styling/Presets/Numbers/50% (Centered).tres
new file mode 100644
index 0000000..8b5b65e
--- /dev/null
+++ b/Runtime/UI/Styling/Presets/Numbers/50% (Centered).tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="UINumber" load_steps=2 format=3 uid="uid://csgadj1kyjd7x"]
+
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_4kw5p"]
+
+[resource]
+script = ExtResource("1_4kw5p")
+value = 50.0
+unit = "%"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
diff --git a/Runtime/UI/Styling/UINumber.cs b/Runtime/UI/Styling/UINumber.cs
index cf5c434..b748582 100644
--- a/Runtime/UI/Styling/UINumber.cs
+++ b/Runtime/UI/Styling/UINumber.cs
@@ -391,10 +391,51 @@ namespace Rokojori
public string formula;
public Godot.Collections.Array inputs;
public float result;
+ public HashSet variables = null;
- public bool Matches( UINumber number, Godot.Collections.Array inputs )
+ public bool ContainsVariable( string varName )
{
- if ( number.unit != formula )
+ if ( variables == null )
+ {
+ ParseVariables();
+ }
+
+ return variables.Contains( varName );
+ }
+
+ public void ParseVariables()
+ {
+ variables = new HashSet();
+
+ var lexer = new UIExpressionLexer();
+ var events = lexer.LexToList( formula );
+
+ var list = new List();
+
+ events.ForEach(
+ ( tk )=>
+ {
+ if ( ! tk.Is( LexerMatcherLibrary.CwordMatcher ) )
+ {
+ return;
+ }
+
+ tk.GrabMatch( formula );
+ variables.Add( tk.match );
+
+ list.Add( tk.match );
+ }
+ );
+
+ // if ( variables.Count > 0 )
+ // {
+ // RJLog.Log( "Formula", formula, "Variables:", variables.ToList().Join() );
+ // }
+ }
+
+ public bool Matches( string cachedFormula, Godot.Collections.Array inputs )
+ {
+ if ( cachedFormula != formula )
{
return false;
}
@@ -414,9 +455,9 @@ namespace Rokojori
static List cachedExpressions = new List();
static int maxCachedExpressions = 50;
- static int GetCacheIndex( UINumber number, Godot.Collections.Array inputs )
+ static int GetCacheIndex( string formula, Godot.Collections.Array inputs )
{
- return cachedExpressions.FindIndex( c => c.Matches( number, inputs ) );
+ return cachedExpressions.FindIndex( c => c.Matches( formula, inputs ) );
}
static float ComputeBaseValue( Control control, UINumber number, float width, float height, float relative, string numberUnit = null )
@@ -538,11 +579,11 @@ namespace Rokojori
return number.value * ComputeBaseValue( control, number, width, height, relative );
}
- var parentControl = control.GetParent() as Control;;
+ var parentControl = control.GetParent() as Control;
var inputs = GetInputs( control, number, parentControl, width, height, relative );
- var cacheIndex = GetCacheIndex( number, inputs );
+ var cacheIndex = GetCacheIndex( number.unit, inputs );
if ( cacheIndex != -1 )
{
@@ -555,7 +596,13 @@ namespace Rokojori
var expression = new Expression();
- var expressionText = number.unit == null ? "" : RegexUtility.Replace( number.unit, "%", " * relative " );
+ var ui = UI.Get( control );
+
+ var hasVariables = false;
+ var expressionText = ui.InsertVariables( number.unit ?? "", ref hasVariables );
+
+ expressionText = RegexUtility.Replace( expressionText, "%", " * relative " );
+
expressionText = RegexUtility.Replace( expressionText, @"\b(\d+)\s*(em|v[wh]|p[wh]|c[wh]|c[xy]|ui[wh])\b", "$1*$2" );
@@ -577,12 +624,31 @@ namespace Rokojori
var result = (float) ( scale * expression.Execute( inputs ).AsDouble() );
+ // if ( ! hasVariables )
+ // {
Cache( number.unit, inputs, result );
+ // }
return result;
}
+ public static void ClearCacheFor( UINumberVariable variable )
+ {
+ var removals = new List();
+
+ foreach ( var exp in cachedExpressions )
+ {
+ if ( exp.ContainsVariable( variable.variableName ) )
+ {
+ // RJLog.Log( "Clearing cached expression:", "'" + exp.formula + "'");
+ removals.Add( exp );
+ }
+ }
+
+ cachedExpressions.RemoveList( removals );
+ }
+
static void Cache( string formula, Godot.Collections.Array inputs, float result )
{
CachedExpressionData data = null;
@@ -599,8 +665,7 @@ namespace Rokojori
data.formula = formula;
data.inputs = inputs;
- data.result = result;
-
+ data.result = result;
}
diff --git a/Runtime/UI/Styling/UINumberVariable.cs b/Runtime/UI/Styling/UINumberVariable.cs
new file mode 100644
index 0000000..f3d23eb
--- /dev/null
+++ b/Runtime/UI/Styling/UINumberVariable.cs
@@ -0,0 +1,59 @@
+
+using Godot;
+using Rokojori;
+using System.Globalization;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UINumberVariable:Resource
+{
+ [Export]
+ public string variableName = "";
+
+ [Export]
+ public string variableValue = "";
+
+ [Export]
+ public float variableScale = 1;
+
+
+ public string GetFormula()
+ {
+ return "( " + variableScale.ToString( CultureInfo.InvariantCulture ) + " * " + variableValue + " )";
+ }
+
+ public bool IsEqualTo( UINumberVariable other )
+ {
+ if ( other == null )
+ {
+ return false;
+ }
+
+ if ( other.variableName != variableName )
+ {
+ return false;
+ }
+
+ if ( other.variableScale != variableScale )
+ {
+ return false;
+ }
+
+ if ( other.variableValue != variableValue )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ [Export,ReadOnly]
+ public string compileResult = "";
+
+
+}
+
+
diff --git a/Runtime/UI/Styling/UINumberVariable.cs.uid b/Runtime/UI/Styling/UINumberVariable.cs.uid
new file mode 100644
index 0000000..15f7119
--- /dev/null
+++ b/Runtime/UI/Styling/UINumberVariable.cs.uid
@@ -0,0 +1 @@
+uid://b53p1cuq8hkcw
diff --git a/Runtime/UI/Styling/UIStyle.cs b/Runtime/UI/Styling/UIStyle.cs
index 46ca791..bf8e515 100644
--- a/Runtime/UI/Styling/UIStyle.cs
+++ b/Runtime/UI/Styling/UIStyle.cs
@@ -3,6 +3,7 @@ using Godot;
using Rokojori;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.ConstrainedExecution;
namespace Rokojori
{
@@ -113,7 +114,38 @@ namespace Rokojori
[Export]
public ShaderUINumber[] numberProperties = new ShaderUINumber[ 0 ];
-
+
+ [ExportGroup( "Sound" )]
+ [Export]
+ public UISoundData onFocusSound;
+ [Export]
+ public UISoundData onBlurSound;
+
+ public UISoundData GetUISoundProperty( UISoundProperty property )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ return onFocusSound;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ return onFocusSound;
+ }
+
+ return null;
+ }
+
+ public void SetUISoundProperty( UISoundProperty property, UISoundData stream )
+ {
+ if ( UISoundProperty.FocusEntered == property )
+ {
+ onFocusSound = stream;
+ }
+ else if ( UISoundProperty.FocusExited == property )
+ {
+ onFocusSound = stream;
+ }
+ }
public Font GetFont()
{
@@ -975,6 +1007,7 @@ namespace Rokojori
}
+
public static UIPosition Position( UIStylePropertyContainer container )
{
if ( container == null )
@@ -1155,6 +1188,26 @@ namespace Rokojori
return GetReferenceableColorProperty( container, property, shaderPropertyName, source );
}
+
+ public static UISoundData GetUISound( UIStylePropertyContainer container, UISoundProperty property )
+ {
+ var ownSound = container.GetUISoundProperty( property );
+
+ if ( ownSound != null )
+ {
+ return ownSound;
+ }
+
+ var parent = container.GetUIStyleParent();
+
+ if ( parent == null )
+ {
+ return null;
+ }
+
+ return GetUISound( parent, property );
+
+ }
}
}
\ No newline at end of file
diff --git a/Runtime/UI/Styling/UIStyleProperty.cs b/Runtime/UI/Styling/UIStyleProperty.cs
index 5fd5780..e449de0 100644
--- a/Runtime/UI/Styling/UIStyleProperty.cs
+++ b/Runtime/UI/Styling/UIStyleProperty.cs
@@ -44,6 +44,12 @@ namespace Rokojori
FloatShaderProperty
}
+ public enum UISoundProperty
+ {
+ FocusEntered,
+ FocusExited
+ }
+
public class UIStyleNumberPropertyAndName
{
public UIStyleNumberProperty styleProperty;
diff --git a/Runtime/UI/Styling/UIStylePropertyContainer.cs b/Runtime/UI/Styling/UIStylePropertyContainer.cs
index 88ed2d9..53541b0 100644
--- a/Runtime/UI/Styling/UIStylePropertyContainer.cs
+++ b/Runtime/UI/Styling/UIStylePropertyContainer.cs
@@ -20,6 +20,9 @@ namespace Rokojori
Font GetFont();
+ UISoundData GetUISoundProperty( UISoundProperty property );
+ void SetUISoundProperty( UISoundProperty property, UISoundData stream );
+
UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source );
void SetUIStyleNumberProperty( UIStyleNumberProperty property, UINumber number );
diff --git a/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres
new file mode 100644
index 0000000..7152b35
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Active 100% Selector Style.tres
@@ -0,0 +1,11 @@
+[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://cxq4cfdnk7c25"]
+
+[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_ytj2f"]
+[ext_resource type="Resource" uid="uid://do3q5tipotyn3" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Active Selector.tres" id="2_r7shh"]
+[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres" id="3_x1wpc"]
+
+[resource]
+script = ExtResource("1_ytj2f")
+selector = ExtResource("2_r7shh")
+style = ExtResource("3_x1wpc")
+metadata/_custom_type_script = "uid://bqypmtxqo5rnf"
diff --git a/Runtime/UI/UI-Selectors/Presets/Active Selector.tres b/Runtime/UI/UI-Selectors/Presets/Active Selector.tres
new file mode 100644
index 0000000..43b0bb5
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Active Selector.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="UISelector" load_steps=2 format=3 uid="uid://do3q5tipotyn3"]
+
+[ext_resource type="Script" uid="uid://brmxttyvbwoit" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelector.cs" id="1_u7tnw"]
+
+[resource]
+script = ExtResource("1_u7tnw")
+active = 1
+metadata/_custom_type_script = "uid://brmxttyvbwoit"
diff --git a/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres
new file mode 100644
index 0000000..5b42c62
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Focus 100% Selector Style.tres
@@ -0,0 +1,11 @@
+[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://cvc0wabrro18q"]
+
+[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_2joc3"]
+[ext_resource type="Resource" uid="uid://dgx4ue1pvvltj" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres" id="2_351ev"]
+[ext_resource type="Resource" uid="uid://brjq22uvnpxuv" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres" id="3_46vc8"]
+
+[resource]
+script = ExtResource("1_2joc3")
+selector = ExtResource("2_351ev")
+style = ExtResource("3_46vc8")
+metadata/_custom_type_script = "uid://bqypmtxqo5rnf"
diff --git a/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres b/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres
new file mode 100644
index 0000000..25910fd
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Focus Selector.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="UISelector" load_steps=2 format=3 uid="uid://dgx4ue1pvvltj"]
+
+[ext_resource type="Script" uid="uid://brmxttyvbwoit" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelector.cs" id="1_7xeoa"]
+
+[resource]
+script = ExtResource("1_7xeoa")
+focus = 1
+metadata/_custom_type_script = "uid://brmxttyvbwoit"
diff --git a/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres b/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres
new file mode 100644
index 0000000..ba36786
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Hover 80% Selector Style.tres
@@ -0,0 +1,11 @@
+[gd_resource type="Resource" script_class="UISelectorStyle" load_steps=4 format=3 uid="uid://d15wkkwgtlh0n"]
+
+[ext_resource type="Script" uid="uid://bqypmtxqo5rnf" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelectorStyle.cs" id="1_a0wuj"]
+[ext_resource type="Resource" uid="uid://cfctpa7mv11nj" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres" id="2_dm1hb"]
+[ext_resource type="Resource" uid="uid://cy7m6e0be3mqw" path="res://addons/rokojori_action_library/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres" id="3_e4mab"]
+
+[resource]
+script = ExtResource("1_a0wuj")
+selector = ExtResource("2_dm1hb")
+style = ExtResource("3_e4mab")
+metadata/_custom_type_script = "uid://bqypmtxqo5rnf"
diff --git a/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres b/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres
new file mode 100644
index 0000000..7869acf
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Hover Selector.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Resource" script_class="UISelector" load_steps=2 format=3 uid="uid://cfctpa7mv11nj"]
+
+[ext_resource type="Script" uid="uid://brmxttyvbwoit" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UISelector.cs" id="1_fyxpi"]
+
+[resource]
+script = ExtResource("1_fyxpi")
+hover = 1
+metadata/_custom_type_script = "uid://brmxttyvbwoit"
diff --git a/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres b/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres
new file mode 100644
index 0000000..012b433
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Mod 100% Style.tres
@@ -0,0 +1,13 @@
+[gd_resource type="Resource" script_class="UIStyle" load_steps=4 format=3 uid="uid://brjq22uvnpxuv"]
+
+[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_bdlk7"]
+[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_p68sf"]
+
+[sub_resource type="Resource" id="Resource_7s7su"]
+script = ExtResource("1_bdlk7")
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[resource]
+script = ExtResource("2_p68sf")
+modulationColor = SubResource("Resource_7s7su")
+metadata/_custom_type_script = "uid://chmcc71dvu4vj"
diff --git a/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres b/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres
new file mode 100644
index 0000000..0b03ac5
--- /dev/null
+++ b/Runtime/UI/UI-Selectors/Presets/Mod 80% Style.tres
@@ -0,0 +1,14 @@
+[gd_resource type="Resource" script_class="UIStyle" load_steps=4 format=3 uid="uid://cy7m6e0be3mqw"]
+
+[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="1_5k4i7"]
+[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="2_qkfun"]
+
+[sub_resource type="Resource" id="Resource_wxaam"]
+script = ExtResource("1_5k4i7")
+color = Color(1, 1, 1, 0.80784315)
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[resource]
+script = ExtResource("2_qkfun")
+modulationColor = SubResource("Resource_wxaam")
+metadata/_custom_type_script = "uid://chmcc71dvu4vj"
diff --git a/Runtime/UI/UI.cs b/Runtime/UI/UI.cs
index 1a7c4ab..ab3dad0 100644
--- a/Runtime/UI/UI.cs
+++ b/Runtime/UI/UI.cs
@@ -1,7 +1,9 @@
using Godot;
+using Godot.Collections;
using System;
using System.Collections.Generic;
+using System.Text;
namespace Rokojori
{
@@ -25,6 +27,102 @@ namespace Rokojori
[Export]
public float fontZoom = 1;
+ [Export]
+ public UINumberVariable[] variables = [];
+
+ [Export]
+ public int numUpdates = 0;
+
+ [Export]
+ public Control focusedControl;
+
+ [ExportToolButton("Update Variables")]
+ public Callable updateVariablesButton => Callable.From(
+ ()=>
+ {
+ CreateVariableValues();
+ }
+ );
+
+ [ExportToolButton("Clear UI Number Cache")]
+ public Callable clearUINumberCacheButton => Callable.From(
+ ()=>
+ {
+ CreateVariableValues();
+ }
+ );
+ System.Collections.Generic.Dictionary _variableValues = null;
+
+ void CreateVariableValues()
+ {
+ _variableValues = new System.Collections.Generic.Dictionary();
+ _cachedVariables = new List();
+
+ variables.ForEach(
+ ( v )=>
+ {
+ _variableValues[ v.variableName ] = v.GetFormula();
+ _cachedVariables.Add( (UINumberVariable)v.Duplicate() );
+ }
+ );
+
+ variables.ForEach(
+ ( v )=>
+ {
+ UINumber.ClearCacheFor( v );
+ }
+ );
+
+
+ }
+
+ public string InsertVariables( string value, ref bool hasVariables )
+ {
+ if ( variables == null || variables.Length == 0 )
+ {
+ hasVariables = false;
+ return value;
+ }
+
+ if ( _variableValues == null )
+ {
+ CreateVariableValues();
+ }
+
+ var tokens = UIExpressionLexer.Lex( value );
+
+ var output = new StringBuilder();
+
+ var tokensContainVariable = false;
+
+ tokens.ForEach(
+ ( tk )=>
+ {
+ if ( tk.isErrorOrDone )
+ {
+ return;
+ }
+
+ if ( tk.Is( LexerMatcherLibrary.CwordMatcher ) && _variableValues.ContainsKey( tk.match ) )
+ {
+ output.Append( _variableValues[ tk.match ] );
+ tokensContainVariable = true;
+ return;
+ }
+
+ output.Append( tk.match );
+
+ }
+ );
+
+ hasVariables = tokensContainVariable;
+
+ return output.ToString();
+
+
+
+ }
+
public enum UpdateMode
{
Always,
@@ -180,7 +278,12 @@ namespace Rokojori
public bool sizeChanged => _resizeFlag;
public bool fontSizeChanged => _fontSizeFlag;
-
+
+ // [Export]
+ // public UISlider focusedSlider = null;
+
+ // [Export]
+ // public UIListSelection focusedListSelection = null;
public override void _Process( double delta )
{
@@ -222,12 +325,24 @@ namespace Rokojori
}
+ focusedControl = GetViewport().GuiGetFocusOwner() as Control;
+
+ if ( focusedControl != null && focusedControl is UIHolderControl uih && focusedControl is UIFocusProcessor fp )
+ {
+ if ( uih.GetUI() == this )
+ {
+ fp.OnFocusProcess( delta );
+ }
+ }
+
onProcess.DispatchEvent( (float)delta );
UpdateFontSize();
+ UpdateVariables();
UpdateUIElements();
uiSize = Size;
+
// customDisposerIDs = _customDisposers.Map( c => c.GetUID() + ":" + c.GetInfo() ).ToArray();
}
@@ -238,6 +353,51 @@ namespace Rokojori
UpdateFontSize();
}
+ List _cachedVariables = [];
+
+ public void UpdateVariables()
+ {
+ if ( _cachedVariables.Count != variables.Length )
+ {
+ CreateVariableValues();
+ return;
+ }
+
+ var recreate = false;
+
+ for ( int i = 0; ! recreate && i < _cachedVariables.Count; i++ )
+ {
+ var v = variables[ i ];
+
+ if ( _cachedVariables[ i ] == null && v == null )
+ {
+ continue;
+ }
+
+ if ( _cachedVariables[ i ] == null || v == null )
+ {
+ recreate = true;
+ continue;
+ }
+
+ if ( _cachedVariables[ i ].IsEqualTo( v ) )
+ {
+ continue;
+ }
+
+ _cachedVariables[ i ] = (UINumberVariable) v.Duplicate();
+ UINumber.ClearCacheFor( v );
+ _variableValues[ v.variableName ] = v.GetFormula();
+ }
+
+ if ( recreate )
+ {
+ CreateVariableValues();
+ }
+
+
+ }
+
public readonly EventSlot onInputEvent = new EventSlot();
public readonly EventSlot onProcess = new EventSlot();
@@ -323,8 +483,7 @@ namespace Rokojori
if ( _fontSizeFlag || _resizeFlag )
{
_dirty.Clear();
- UpdateAllUIRegions();
-
+ UpdateAllUIRegions();
}
else
{
@@ -362,6 +521,7 @@ namespace Rokojori
);
+ var updated = 0;
sorted.ForEach(
( s )=>
@@ -374,9 +534,12 @@ namespace Rokojori
// ( s as Control).LogInfo( "Updating:", s );
UpdateElement( s );
+ updated ++;
}
);
+ numUpdates = updated;
+
_updated.Clear();
_dirty.RemoveWhere( d => ! d.IsDirty() );
@@ -451,7 +614,60 @@ namespace Rokojori
return GetWindow().Size;
}
}
+
+ System.Collections.Generic.Dictionary _audioPlayers = new System.Collections.Generic.Dictionary();
+
+ public AudioStreamPlayer _GetAudioPlayer( UISoundData data )
+ {
+ AudioStreamPlayer freePlayer = null;
+
+ foreach ( var p in _audioPlayers )
+ {
+ var player = p.Key;
+
+ if ( player.Playing )
+ {
+ continue;
+ }
+
+ if ( player.Stream != data.audio )
+ {
+ freePlayer = player;
+ continue;
+ }
+
+ return player;
+
+ }
+
+ if ( freePlayer != null )
+ {
+ return freePlayer;
+ }
+
+ var newPlayer = this.CreateChild();
+
+ _audioPlayers[ newPlayer ] = 0;
+ return newPlayer;
+ }
+
+ public void PlaySound( UISoundData soundData )
+ {
+ var player = _GetAudioPlayer( soundData );
+
+ player.Stream = soundData.audio;
+ player.VolumeLinear = soundData.volume;
+ player.PitchScale = MathAudio.SemitonesToFrequencyScaler( soundData.pitchSemitonesOffset );
+ player.Playing = true;
+
+ }
+ // public void Focus( Control control )
+ // {
+ // var focusParent =
+ // while ( control )
+ // }
+
}
}
\ No newline at end of file
diff --git a/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs b/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs
new file mode 100644
index 0000000..41d186d
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs
@@ -0,0 +1,28 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MinimalisticBackgroundGenerator:UIAppSettingsBackgroundGenerator
+{
+ [Export]
+ public UIStyle backgroundStyle;
+
+ [Export]
+ public UIImageType imageType;
+
+ public override UIStylePropertyContainerNode GenerateBackground( UIAppSettings uiAppSettings )
+ {
+ var background = uiAppSettings.CreateChild( "Background" );
+ background.imageType = imageType;
+ background.parentStyle = backgroundStyle;
+ background.Texture = UI.whiteTexture.Get();
+
+ return background;
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs.uid b/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs.uid
new file mode 100644
index 0000000..ab4ef4a
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Background/MinimalisticBackgroundGenerator.cs.uid
@@ -0,0 +1 @@
+uid://blysxpmf7v02p
diff --git a/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs b/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs
new file mode 100644
index 0000000..f92a6ef
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs
@@ -0,0 +1,14 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public abstract partial class UIAppSettingsBackgroundGenerator:Resource
+{
+ public abstract UIStylePropertyContainerNode GenerateBackground( UIAppSettings uiAppSettings );
+}
diff --git a/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs.uid b/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs.uid
new file mode 100644
index 0000000..1ebd977
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Background/UIAppSettingsBackgroundGenerator.cs.uid
@@ -0,0 +1 @@
+uid://b13ld5mt028g1
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs
new file mode 100644
index 0000000..9f4a7f6
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs
@@ -0,0 +1,130 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MinimalisticCategoryPagesGenerator:UIAppSettingsCategoryPageGenerator
+{
+ [Export]
+ public UIStyle pageStyle;
+
+ [Export]
+ public UIStyle pageBackgroundStyle;
+
+ [Export]
+ public UIImageType pageBackgroundImageType;
+
+ [Export]
+ public UIStyle sliderStyle;
+
+ [Export]
+ public SliderUIImageType sliderImageType;
+
+ [Export]
+ public UIStyle scrollAreaStyle;
+
+ [Export]
+ public UIStyle appSettingHandlerStyle;
+
+ [Export]
+ public UIStyle appSettingBackgroundStyle;
+
+ [Export]
+ public UIImageType appSettingBackgroundImage;
+
+ [Export]
+ public UIStyle appSettingLabelRegionStyle;
+
+ [Export]
+ public UIStyle appSettingLabelStyle;
+
+ [Export]
+ public PackedScene appSettingNumberController;
+
+ [Export]
+ public PackedScene appSettingListController;
+
+
+ public override UIAppSettingsCategoryPage GenerateCategoryPage(
+ UIAppSettings uiAppSettings, AppSettingsCategory category
+ )
+ {
+ var page = uiAppSettings.CreateChild( "[ " + category.title.currentValue + " ]");
+ page.category = category;
+ page.parentStyle = pageStyle;
+
+ var pageBG = page.CreateChild( "Background" );
+ pageBG.parentStyle = pageBackgroundStyle;
+ pageBG.imageType = pageBackgroundImageType;
+ pageBG.Texture = UI.whiteTexture.Get();
+
+ var scrollArea = page.CreateChild( "Scroll Area" );
+ scrollArea.parentStyle = scrollAreaStyle;
+
+ category.settings.ForEach(
+ ( setting )=>
+ {
+
+ var name = "- " + setting.title.currentValue;
+
+ UIAppSettingHandler handler = null;
+
+ if ( setting is NumberAppSetting )
+ {
+ handler = scrollArea.CreateChild( name );
+ }
+ else if ( setting is ListAppSetting )
+ {
+ handler = scrollArea.CreateChild( name );
+ }
+
+ handler.parentStyle = appSettingHandlerStyle;
+ handler.appSetting = setting;
+
+ var handlerBG = handler.CreateChild( name + " BG");
+ handlerBG.parentStyle = appSettingBackgroundStyle;
+ handlerBG.imageType = appSettingBackgroundImage;
+ handlerBG.Texture = UI.whiteTexture.Get();
+
+ var labelRegion = handler.CreateChild( name + " Label Container");
+ labelRegion.parentStyle = appSettingLabelRegionStyle;
+
+ var label = labelRegion.CreateChild( name + " Label" );
+ label.locale = setting.title;
+ label.parentStyle = appSettingLabelStyle;
+
+ if ( setting is NumberAppSetting )
+ {
+ var numberHandler = (UINumberAppSettingHandler) handler;
+ var numberController = handler.CreateChild( appSettingNumberController, "Number Handler" );
+ numberHandler.slider = numberController.Get();
+ numberHandler.slider.setActiveWhenFocused = [ handler ];
+
+ }
+
+ if ( setting is ListAppSetting )
+ {
+ var listHandler = (UIListAppSettingHandler) handler;
+ var listController = handler.CreateChild( appSettingNumberController, "List Handler" );
+ listHandler.list = listController.Get();
+ listHandler.list.setActiveWhenFocused = [ handler ];
+ }
+ }
+ );
+
+ var slider = page.CreateChild( "Scroll Area Slider" );
+ slider.scrollArea = scrollArea;
+ slider.scrollContainer = page;
+ slider.parentStyle = sliderStyle;
+ slider.imageType = sliderImageType;
+
+
+ return page;
+ }
+
+}
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs.uid b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs.uid
new file mode 100644
index 0000000..7765d4d
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/MinimalisticCategoryPagesGenerator.cs.uid
@@ -0,0 +1 @@
+uid://djagabirt3f6
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs
new file mode 100644
index 0000000..fae9fb4
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs
@@ -0,0 +1,51 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIAppSettingsCategoryPage:UIRegion
+{
+ [Export]
+ public AppSettingsCategory category;
+
+ [Export]
+ public Action onInitialize;
+
+ [Export]
+ public Action onActive;
+
+ public virtual void _OnInitialize()
+ {
+ LoadSettingsOfHandlers();
+ }
+
+ public virtual void _OnActivated()
+ {
+ LoadSettingsOfHandlers();
+ FocusHandler();
+ }
+
+
+
+ public void LoadSettingsOfHandlers()
+ {
+ var handlers = this.GetAll();
+ handlers.ForEach( h => h.LoadSetting() );
+
+
+ }
+
+ public void FocusHandler()
+ {
+ var handlers = this.GetAll();
+ var firstHandler = handlers[ 0 ];
+
+ firstHandler.FocusHandler();
+ }
+
+}
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs.uid b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs.uid
new file mode 100644
index 0000000..94aa9cf
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPage.cs.uid
@@ -0,0 +1 @@
+uid://c6gtpvaih4u5d
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs
new file mode 100644
index 0000000..f2c621f
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs
@@ -0,0 +1,14 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public abstract partial class UIAppSettingsCategoryPageGenerator:Resource
+{
+ public abstract UIAppSettingsCategoryPage GenerateCategoryPage( UIAppSettings uiAppSettings, AppSettingsCategory category );
+}
diff --git a/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs.uid b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs.uid
new file mode 100644
index 0000000..57d4a6c
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/CategoryPages/UIAppSettingsCategoryPageGenerator.cs.uid
@@ -0,0 +1 @@
+uid://b3qwyhgss87kp
diff --git a/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn b/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn
new file mode 100644
index 0000000..caca557
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/Presets/List Controller.tscn
@@ -0,0 +1,158 @@
+[gd_scene load_steps=19 format=3 uid="uid://blvco0pityhm1"]
+
+[ext_resource type="Script" uid="uid://c2hicupu28nbi" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIRegion.cs" id="1_1w55f"]
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="2_xupgh"]
+[ext_resource type="Script" uid="uid://rqs2m0u6yvvf" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIText.cs" id="3_emuhf"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="4_nso1f"]
+[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="5_v6jyw"]
+[ext_resource type="Script" uid="uid://b50yldymrhply" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Selections/ListSelection/ChangeUIListSelection.cs" id="6_28vtr"]
+[ext_resource type="Script" uid="uid://2ftd0bt6rrgo" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Selections/ListSelection/UIListSelection.cs" id="7_4f0b5"]
+[ext_resource type="Script" uid="uid://b4yjsis2fh64c" path="res://addons/rokojori_action_library/Runtime/Actions/ActionList.cs" id="8_001d7"]
+
+[sub_resource type="Resource" id="Resource_7e4fb"]
+script = ExtResource("2_xupgh")
+value = 2.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="LabelSettings" id="LabelSettings_qiba2"]
+
+[sub_resource type="Resource" id="Resource_o8r6f"]
+script = ExtResource("4_nso1f")
+en = "â—€"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="Resource" id="Resource_4wsps"]
+script = ExtResource("5_v6jyw")
+metadata/_custom_type_script = "uid://chmcc71dvu4vj"
+
+[sub_resource type="Resource" id="Resource_0schf"]
+script = ExtResource("2_xupgh")
+value = 25.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="LabelSettings" id="LabelSettings_eoac7"]
+
+[sub_resource type="Resource" id="Resource_ewl2f"]
+script = ExtResource("4_nso1f")
+en = "Value A"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="Resource" id="Resource_swro7"]
+script = ExtResource("4_nso1f")
+en = "Other Value"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="LabelSettings" id="LabelSettings_iajf2"]
+
+[sub_resource type="Resource" id="Resource_jgo2j"]
+script = ExtResource("4_nso1f")
+en = "â–¶"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[node name="List Handler" type="Control"]
+layout_mode = 3
+anchors_preset = 0
+offset_left = 115.200005
+offset_top = 4.17776
+offset_right = 426.24005
+offset_bottom = 21.177761
+pivot_offset = Vector2(155.52002, 8.5)
+script = ExtResource("1_1w55f")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="UIRegion2" type="Control" parent="."]
+anchors_preset = 0
+offset_right = 23.04
+offset_bottom = 17.0
+pivot_offset = Vector2(11.52, 8.5)
+mouse_filter = 1
+script = ExtResource("1_1w55f")
+width = SubResource("Resource_7e4fb")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="UIText3" type="Label" parent="UIRegion2"]
+layout_mode = 0
+offset_left = 6.0200005
+offset_right = 17.02
+offset_bottom = 17.0
+pivot_offset = Vector2(5.5, 8.5)
+mouse_filter = 1
+label_settings = SubResource("LabelSettings_qiba2")
+script = ExtResource("3_emuhf")
+locale = SubResource("Resource_o8r6f")
+parentStyle = SubResource("Resource_4wsps")
+handleMouseEvents = true
+
+[node name="ChangeUIListSelection" type="Node" parent="UIRegion2" node_paths=PackedStringArray("selection")]
+script = ExtResource("6_28vtr")
+selection = NodePath("../../UIRegion/UIListSelection")
+mode = 1
+value = -1
+metadata/_custom_type_script = "uid://b50yldymrhply"
+
+[node name="UIRegion" type="Control" parent="."]
+anchors_preset = 0
+offset_left = 23.04
+offset_right = 288.00003
+offset_bottom = 17.0
+pivot_offset = Vector2(132.48001, 8.5)
+mouse_filter = 1
+script = ExtResource("1_1w55f")
+width = SubResource("Resource_0schf")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="UIListSelection" type="Label" parent="UIRegion" node_paths=PackedStringArray("onFocusEntered", "onFocusExited")]
+layout_mode = 0
+offset_left = 97.48001
+offset_right = 167.48001
+offset_bottom = 17.0
+pivot_offset = Vector2(35, 8.5)
+label_settings = SubResource("LabelSettings_eoac7")
+script = ExtResource("7_4f0b5")
+values = [SubResource("Resource_ewl2f"), SubResource("Resource_swro7")]
+locale = SubResource("Resource_swro7")
+parentStyle = SubResource("Resource_4wsps")
+onFocusEntered = NodePath("../../On Focus Entered")
+onFocusExited = NodePath("../../On Focus Exited")
+metadata/_custom_type_script = "uid://2ftd0bt6rrgo"
+
+[node name="UIRegion4" type="Control" parent="."]
+anchors_preset = 0
+offset_left = 288.00003
+offset_right = 311.04004
+offset_bottom = 17.0
+pivot_offset = Vector2(11.520004, 8.5)
+mouse_filter = 1
+script = ExtResource("1_1w55f")
+width = SubResource("Resource_7e4fb")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="UIText2" type="Label" parent="UIRegion4"]
+layout_mode = 0
+offset_left = 6.0200005
+offset_right = 17.02
+offset_bottom = 17.0
+pivot_offset = Vector2(5.5, 8.5)
+mouse_filter = 1
+label_settings = SubResource("LabelSettings_iajf2")
+script = ExtResource("3_emuhf")
+locale = SubResource("Resource_jgo2j")
+parentStyle = SubResource("Resource_4wsps")
+handleMouseEvents = true
+
+[node name="ChangeUIListSelection2" type="Node" parent="UIRegion4" node_paths=PackedStringArray("selection")]
+script = ExtResource("6_28vtr")
+selection = NodePath("../../UIRegion/UIListSelection")
+mode = 1
+value = 1
+metadata/_custom_type_script = "uid://b50yldymrhply"
+
+[node name="On Focus Entered" type="Node" parent="."]
+script = ExtResource("8_001d7")
+metadata/_custom_type_script = "uid://b4yjsis2fh64c"
+
+[node name="On Focus Exited" type="Node" parent="."]
+script = ExtResource("8_001d7")
+metadata/_custom_type_script = "uid://b4yjsis2fh64c"
diff --git a/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn b/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn
new file mode 100644
index 0000000..3b67bda
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/Presets/Number Controller.tscn
@@ -0,0 +1,235 @@
+[gd_scene load_steps=39 format=3 uid="uid://58yaanrblnvj"]
+
+[ext_resource type="Script" uid="uid://c2hicupu28nbi" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIRegion.cs" id="1_ucjfr"]
+[ext_resource type="Script" uid="uid://1pymvcckklic" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/Slider/SliderMaterial.cs" id="2_rckb5"]
+[ext_resource type="Shader" uid="uid://drifsskg885sj" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/Slider/Slider.gdshader" id="3_ca53k"]
+[ext_resource type="Texture2D" uid="uid://coc7upm22lwcw" path="res://addons/rokojori_action_library/Assets/Textures/white.svg" id="4_vb488"]
+[ext_resource type="Script" uid="uid://cqi3jitprf7o0" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Sliders/ValueSlider/UIValueSlider.cs" id="5_p2b8g"]
+[ext_resource type="Script" uid="uid://bsonpc71ochpe" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Sliders/ValueSlider/UIFloatValueMode.cs" id="6_1gbfa"]
+[ext_resource type="Script" uid="uid://lhuuedx87rem" path="res://addons/rokojori_action_library/Runtime/Animation/Smoothing/FrameSmoothing.cs" id="7_pjx5d"]
+[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="7_sr7fn"]
+[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="8_74lu0"]
+[ext_resource type="Script" uid="uid://cwcm7eu486tr4" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImageTypes/SliderUIImageType.cs" id="9_jpqb0"]
+[ext_resource type="Script" uid="uid://rqs2m0u6yvvf" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIText.cs" id="10_58ifk"]
+[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="11_dmue3"]
+[ext_resource type="Script" uid="uid://cdsqunj017b7y" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UICursor.cs" id="11_gdfkg"]
+[ext_resource type="Script" uid="uid://chmcc71dvu4vj" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIStyle.cs" id="12_obxtq"]
+[ext_resource type="Script" uid="uid://b4yjsis2fh64c" path="res://addons/rokojori_action_library/Runtime/Actions/ActionList.cs" id="15_v3vxy"]
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_op7xn"]
+shader = ExtResource("3_ca53k")
+shader_parameter/opacity = 1.0
+shader_parameter/blendLinear = false
+shader_parameter/size = Vector2(0, 0)
+shader_parameter/sharpness = 5.0
+shader_parameter/borderRadius = 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/strokeSize = 5.0
+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)
+shader_parameter/sliderSizeX = 0.0
+shader_parameter/sliderSizeY = 0.0
+shader_parameter/sliderSizeMarginX = 0.0
+shader_parameter/sliderSizeMarginY = 0.0
+shader_parameter/sliderBorders = 0.0
+shader_parameter/sliderValue = Vector2(0.5, 0.5)
+shader_parameter/sliderFillColor = Color(0, 0, 0, 1)
+shader_parameter/sliderStrokeColor = Color(0, 0, 0, 1)
+shader_parameter/sliderStrokeSize = 2.0
+script = ExtResource("2_rckb5")
+
+[sub_resource type="Resource" id="Resource_ebf7l"]
+script = ExtResource("6_1gbfa")
+max = 100.0
+metadata/_custom_type_script = "uid://bsonpc71ochpe"
+
+[sub_resource type="Resource" id="Resource_gdfkg"]
+script = ExtResource("7_pjx5d")
+frames = 20.0
+metadata/_custom_type_script = "uid://lhuuedx87rem"
+
+[sub_resource type="Resource" id="Resource_pv02u"]
+script = ExtResource("7_sr7fn")
+value = 1.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_412gp"]
+script = ExtResource("8_74lu0")
+color = Color(0.3090081, 0.3473884, 0.40495878, 1)
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[sub_resource type="Resource" id="Resource_pp0bs"]
+script = ExtResource("7_sr7fn")
+value = 0.334
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_t2h31"]
+script = ExtResource("8_74lu0")
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[sub_resource type="Resource" id="Resource_ubijs"]
+script = ExtResource("7_sr7fn")
+value = 0.598
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_dq7d0"]
+script = ExtResource("7_sr7fn")
+value = 1.2525
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_tdk3c"]
+script = ExtResource("7_sr7fn")
+value = 0.6355
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_p7jqt"]
+script = ExtResource("8_74lu0")
+color = Color(1, 1, 1, 0)
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[sub_resource type="Resource" id="Resource_ioimv"]
+script = ExtResource("8_74lu0")
+color = Color(1, 1, 1, 0)
+metadata/_custom_type_script = "uid://drqb0pm5ub64g"
+
+[sub_resource type="Resource" id="Resource_q8n2a"]
+script = ExtResource("7_sr7fn")
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_loqre"]
+script = ExtResource("9_jpqb0")
+fillColor = SubResource("Resource_412gp")
+strokeColor = SubResource("Resource_ioimv")
+borderRadius = SubResource("Resource_pv02u")
+strokeSize = SubResource("Resource_q8n2a")
+sliderSizeX = SubResource("Resource_dq7d0")
+sliderSizeY = SubResource("Resource_tdk3c")
+sliderSizeMarginX = SubResource("Resource_ubijs")
+sliderBorderRadius = SubResource("Resource_pp0bs")
+sliderFillColor = SubResource("Resource_t2h31")
+sliderStrokeColor = SubResource("Resource_p7jqt")
+
+[sub_resource type="Resource" id="Resource_jhmds"]
+script = ExtResource("7_sr7fn")
+value = 20.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_mseeg"]
+script = ExtResource("7_sr7fn")
+value = 1.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_44lr4"]
+script = ExtResource("11_gdfkg")
+metadata/_custom_type_script = "uid://cdsqunj017b7y"
+
+[sub_resource type="Resource" id="Resource_drk6d"]
+script = ExtResource("7_sr7fn")
+value = 100.0
+unit = "%"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="Resource" id="Resource_jtfq4"]
+script = ExtResource("7_sr7fn")
+value = 10.0
+unit = "em"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[sub_resource type="LabelSettings" id="LabelSettings_to3ck"]
+
+[sub_resource type="Resource" id="Resource_r7l7h"]
+script = ExtResource("11_dmue3")
+en = "Test"
+metadata/_custom_type_script = "uid://bvj322mokkq63"
+
+[sub_resource type="Resource" id="Resource_4wsps"]
+script = ExtResource("12_obxtq")
+metadata/_custom_type_script = "uid://chmcc71dvu4vj"
+
+[sub_resource type="Resource" id="Resource_mk81p"]
+script = ExtResource("7_sr7fn")
+value = 10.0
+unit = "vw"
+metadata/_custom_type_script = "uid://cnkyynboxg1qg"
+
+[node name="Number Handler" type="Control"]
+layout_mode = 3
+anchors_preset = 0
+offset_left = 115.200005
+offset_top = 4.17776
+offset_right = 426.24002
+offset_bottom = 21.177761
+pivot_offset = Vector2(155.52, 8.5)
+script = ExtResource("1_ucjfr")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="UIValueSlider" type="TextureRect" parent="." node_paths=PackedStringArray("valueText", "onFocusEntered", "onFocusExited")]
+material = SubResource("ShaderMaterial_op7xn")
+layout_mode = 0
+offset_top = 2.7399998
+offset_right = 230.40001
+offset_bottom = 14.26
+pivot_offset = Vector2(115.200005, 5.76)
+focus_mode = 2
+texture = ExtResource("4_vb488")
+expand_mode = 1
+script = ExtResource("5_p2b8g")
+valueText = NodePath("../UIRegion2/Value")
+mode = SubResource("Resource_ebf7l")
+direction = 1
+smoothing = SubResource("Resource_gdfkg")
+sliderValue = Vector2(0.5, 0.5)
+imageType = SubResource("Resource_loqre")
+width = SubResource("Resource_jhmds")
+height = SubResource("Resource_mseeg")
+hoverCursor = SubResource("Resource_44lr4")
+onFocusEntered = NodePath("../On Focus Entered")
+onFocusExited = NodePath("../On Focus Exited")
+metadata/_custom_type_script = "uid://cqi3jitprf7o0"
+
+[node name="UIRegion2" type="Control" parent="."]
+anchors_preset = 0
+offset_left = 230.40001
+offset_right = 311.04
+offset_bottom = 17.0
+pivot_offset = Vector2(40.32, 8.5)
+mouse_filter = 1
+script = ExtResource("1_ucjfr")
+horizontalAlignment = SubResource("Resource_drk6d")
+width = SubResource("Resource_jtfq4")
+metadata/_custom_type_script = "uid://c2hicupu28nbi"
+
+[node name="Value" type="Label" parent="UIRegion2"]
+layout_mode = 0
+offset_left = 55.64
+offset_right = 80.64
+offset_bottom = 17.0
+pivot_offset = Vector2(12.5, 8.5)
+text = "Test"
+label_settings = SubResource("LabelSettings_to3ck")
+script = ExtResource("10_58ifk")
+locale = SubResource("Resource_r7l7h")
+parentStyle = SubResource("Resource_4wsps")
+width = SubResource("Resource_mk81p")
+
+[node name="On Focus Entered" type="Node" parent="."]
+script = ExtResource("15_v3vxy")
+metadata/_custom_type_script = "uid://b4yjsis2fh64c"
+
+[node name="On Focus Exited" type="Node" parent="."]
+script = ExtResource("15_v3vxy")
+metadata/_custom_type_script = "uid://b4yjsis2fh64c"
diff --git a/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs b/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs
new file mode 100644
index 0000000..3824a2f
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs
@@ -0,0 +1,21 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public abstract partial class UIAppSettingHandler:UIRegion
+{
+ [Export]
+ public AppSetting appSetting;
+
+ public abstract void LoadSetting();
+
+ public abstract void FocusHandler();
+
+
+}
diff --git a/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs.uid b/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs.uid
new file mode 100644
index 0000000..a5bd459
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UIAppSettingHandler.cs.uid
@@ -0,0 +1 @@
+uid://bcc7cyidhl6wm
diff --git a/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs b/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs
new file mode 100644
index 0000000..8a6bcc8
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs
@@ -0,0 +1,43 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIListAppSettingHandler:UIAppSettingHandler
+{
+ [Export]
+ public UIListSelection list;
+
+ public override void _Ready()
+ {
+ Initialize();
+ }
+
+ public override void FocusHandler()
+ {
+ list.CallDeferred( list.GrabFocus );
+ }
+
+ public override void LoadSetting()
+ {
+ var app = Unique.Get();
+ var value = app.GetSetting( appSetting );
+ list.SetSelectedBySerialized( value );
+ }
+
+ public void Initialize()
+ {
+ list.values = ( appSetting as ListAppSetting ).values;
+
+ list._onSelectionChange.AddAction(
+ ( v2 )=>
+ {
+ var app = Unique.Get();
+ app.SetSetting( appSetting.id, list.SerializeSelectedOption() );
+ appSetting.ApplyValue( app );
+ }
+ );
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs.uid b/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs.uid
new file mode 100644
index 0000000..26ebac2
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UIListAppSettingHandler.cs.uid
@@ -0,0 +1 @@
+uid://b1uumkpthbl76
diff --git a/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs b/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs
new file mode 100644
index 0000000..b85c483
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs
@@ -0,0 +1,71 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UINumberAppSettingHandler:UIAppSettingHandler
+{
+ [Export]
+ public UIValueSlider slider;
+
+ public override void _Ready()
+ {
+ Initialize();
+ }
+
+ public override void FocusHandler()
+ {
+ slider.CallDeferred( slider.GrabFocus );
+ }
+
+
+
+ public override void LoadSetting()
+ {
+ var app = Unique.Get();
+ var value = app.GetSetting( appSetting );
+ var normalized = slider.mode.FromSerializedToNormalized( value );
+ slider.SetSliderMainValue( normalized );
+
+ this.LogInfo( "Set setting", appSetting.title.currentValue, value, normalized );
+ }
+
+ public void Initialize()
+ {
+ UIValueSliderMode mode = null;
+
+ if ( appSetting is ResolutionScalingSetting rss )
+ {
+ var resFloatMode = new UIResolutionScaleMode();
+ resFloatMode.CopyFrom( appSetting as NumberAppSetting );
+ resFloatMode.userScaleToResolutionScale = rss.userScaleToResolutionScale;
+ mode = resFloatMode;
+ }
+ else
+ {
+ mode = UIFloatValueMode.From( appSetting as NumberAppSetting );
+ }
+
+ slider.mode = mode;
+
+ slider._onSliderChange.AddAction(
+ ( v2 )=>
+ {
+ if ( appSetting is ResolutionScalingSetting )
+ {
+ var resFloatMode = slider.mode as UIResolutionScaleMode;
+ resFloatMode.windowSize = GetWindow().Size;
+ }
+
+ var app = Unique.Get();
+ app.SetSetting( appSetting.id, slider.mode.GetSerializedValue( slider.mainValue ) );
+ appSetting.ApplyValue( app );
+ }
+ );
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs.uid b/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs.uid
new file mode 100644
index 0000000..3d59381
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Handlers/UINumberAppSettingHandler.cs.uid
@@ -0,0 +1 @@
+uid://yveix6mv8qko
diff --git a/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs
new file mode 100644
index 0000000..2cca47d
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs
@@ -0,0 +1,100 @@
+
+using System.Collections.Generic;
+using System.Linq;
+using Godot;
+using Rokojori;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class MinimalisticHeaderGenerator:UIAppSettingsHeaderGenerator
+{
+
+
+ [Export]
+ public UIStyle headerStyle;
+
+ [Export]
+ public UIStyle backgroundStyle;
+
+ [Export]
+ public UIImageType backgroundImageType;
+
+ [Export]
+ public SensorIcon leftIcon;
+
+ [Export]
+ public SensorIcon rightIcon;
+
+ [Export]
+ public UIStyle categoryContainerStyle;
+
+ [Export]
+ public UIStyle categoryIconStyle;
+
+ [Export]
+ public UIStyle categoryLabelStyle;
+
+
+ public override UIAppSettingsHeader GenerateHeader( UIAppSettings uiAppSettings, AppSettings appSettings )
+ {
+ var ignores = new List();
+ uiAppSettings.ForEachDirectChild( c => { ignores.Add( c ); } );
+
+ var header = uiAppSettings.CreateChild( "Header");
+ header.parentStyle = headerStyle;
+
+ ignores.Add( header );
+
+ var background = header.CreateChild( "Background" );
+ background.parentStyle = backgroundStyle;
+ background.imageType = backgroundImageType;
+ background.Texture = UI.whiteTexture.Get();
+
+ var leftInfo = header.CreateChild( "Left Input ");
+ leftInfo.inputIcons = [ leftIcon ];
+ leftInfo.deviceFilter = new LastActiveDeviceFilter();
+
+
+ var selectors = new List();
+
+ for ( int i = 0 ; i < appSettings.categories.Length; i++ )
+ {
+ var category = appSettings.categories[ i ];
+
+ var categoryRegion = header.CreateChild( "[ " + category.title.currentValue + " ]" );
+ categoryRegion.parentStyle = categoryContainerStyle;
+
+ var icon = categoryRegion.CreateChild();
+ icon.Texture = category.icon;
+ icon.parentStyle = categoryIconStyle;
+
+ var label = categoryRegion.CreateChild();
+ label.locale = category.title;
+ label.parentStyle = categoryLabelStyle;
+ label.MouseFilter = Control.MouseFilterEnum.Pass;
+
+ var selector = label.CreateChild( "Select Page" );
+ selector.uiStylable = categoryRegion;
+ selector.uiAppSettings = uiAppSettings;
+ selector.category = category;
+ label.handleMouseEvents = true;
+ label.onLeftClick = selector;
+
+ selectors.Add( selector );
+ }
+
+ header.pageSelectors = selectors.ToArray();
+
+
+
+ var rightInfo = header.CreateChild( "Right Input ");
+
+ rightInfo.inputIcons = [ rightIcon ];
+ rightInfo.deviceFilter = new LastActiveDeviceFilter();
+
+ return header;
+ }
+
+}
diff --git a/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs.uid b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs.uid
new file mode 100644
index 0000000..b7b0735
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/MinimalisticHeaderGenerator.cs.uid
@@ -0,0 +1 @@
+uid://dcc4hk82jju0b
diff --git a/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs b/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs
new file mode 100644
index 0000000..2cf9201
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs
@@ -0,0 +1,55 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class SelectSettingsPage:Action
+{
+ [Export]
+ public UIAppSettings uiAppSettings;
+
+ [Export]
+ public AppSettingsCategory category;
+
+ [Export]
+ public Node uiStylable;
+
+ protected override void _OnTrigger()
+ {
+ uiAppSettings.header.pageSelectors.ForEach(
+ ( ps )=>
+ {
+ var stylable = ps.uiStylable as UIStylePropertyContainerNode;
+ stylable.RemoveUISelectorFlag( UISelectorFlag.Active );
+ }
+ );
+
+ var ownStylable = uiStylable as UIStylePropertyContainerNode;
+ ownStylable.AddUISelectorFlag( UISelectorFlag.Active );
+
+ uiAppSettings.pages.ForEach(
+ ( p )=>
+ {
+ var isActive = p.category == category;
+ p.SetVisibility( isActive );
+
+
+ if ( ! isActive )
+ {
+ return;
+ }
+
+ p.onActive?.Trigger();
+ p._OnActivated();
+
+ }
+ );
+
+
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs.uid b/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs.uid
new file mode 100644
index 0000000..8880445
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/SelectSettingsPage.cs.uid
@@ -0,0 +1 @@
+uid://yhncbks70tby
diff --git a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs
new file mode 100644
index 0000000..ca632ca
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs
@@ -0,0 +1,15 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIAppSettingsHeader:UIRegion
+{
+ [Export]
+ public SelectSettingsPage[] pageSelectors = [];
+}
diff --git a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs.uid b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs.uid
new file mode 100644
index 0000000..4591ef1
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeader.cs.uid
@@ -0,0 +1 @@
+uid://bxkfi0jawg0gp
diff --git a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs
new file mode 100644
index 0000000..8cc39c1
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs
@@ -0,0 +1,14 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public abstract partial class UIAppSettingsHeaderGenerator:Resource
+{
+ public abstract UIAppSettingsHeader GenerateHeader( UIAppSettings uiAppSettings, AppSettings appSettings );
+}
diff --git a/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs.uid b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs.uid
new file mode 100644
index 0000000..836cd71
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/Headers/UIAppSettingsHeaderGenerator.cs.uid
@@ -0,0 +1 @@
+uid://bl54i76oblew4
diff --git a/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs b/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs
new file mode 100644
index 0000000..3223ab7
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs
@@ -0,0 +1,23 @@
+
+using Godot;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class InitializeUIAppSettings:Action
+{
+ [Export]
+ public UIAppSettings uiAppSettings;
+
+ protected override void _OnTrigger()
+ {
+ uiAppSettings.pages.ForEach(
+ p =>
+ {
+ p._OnInitialize();
+ p.onInitialize?.Trigger();
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs.uid b/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs.uid
new file mode 100644
index 0000000..f64c319
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/InitializeUIAppSettings.cs.uid
@@ -0,0 +1 @@
+uid://d22jpcisjv8bx
diff --git a/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs
new file mode 100644
index 0000000..3b0da67
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs
@@ -0,0 +1,26 @@
+
+using Godot;
+
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class SetUIAppSettingsReady : Action
+{
+ [Export]
+ public UIAppSettings uiAppSettings;
+
+ [Export]
+ public Action newReadyAction;
+
+ protected override void _OnTrigger()
+ {
+ if ( uiAppSettings == null )
+ {
+ return;
+ }
+
+ uiAppSettings.onReady = newReadyAction;
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs.uid b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs.uid
new file mode 100644
index 0000000..bf9413e
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/SetUIAppSettingsReady.cs.uid
@@ -0,0 +1 @@
+uid://bmqiq2x0pamja
diff --git a/Runtime/UI/UIAppSettings/UIAppSettings.cs b/Runtime/UI/UIAppSettings/UIAppSettings.cs
new file mode 100644
index 0000000..091ff1c
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/UIAppSettings.cs
@@ -0,0 +1,170 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIAppSettings:UIRegion
+{
+ [ExportToolButton( "Create App Settings UI")]
+ public Callable createAppSettingsUI => Callable.From(
+ ()=>
+ {
+ CreateAppSettingsUI();
+ }
+ );
+
+ [Export]
+ public AppSettings appSettings;
+
+ [Export]
+ public UIAppSettingsGenerator generator;
+
+ public enum MenuChangeMode
+ {
+ None,
+ Clamped,
+ Wrapped
+ }
+
+ [Export]
+ public MenuChangeMode menuChangeMode = MenuChangeMode.Wrapped;
+
+ [Export]
+ public Action onConfirm;
+
+ [Export]
+ public Action onCancel;
+
+ [Export]
+ public Action onReady;
+
+
+ [ExportGroup( "References")]
+
+ [Export]
+ public Node background = null;
+
+ [Export]
+ public UIAppSettingsHeader header = null;
+
+ [Export]
+ public UIAppSettingsCategoryPage[] pages = [];
+
+
+
+ public override void _Process( double delta )
+ {
+ ProcessMenuInputs();
+ ProcessMainInputs();
+ }
+
+ void ProcessMenuInputs()
+ {
+ if ( MenuChangeMode.None == menuChangeMode )
+ {
+ return;
+ }
+
+ var settings = GetUI().settings;
+ var wrapped = MenuChangeMode.Wrapped == menuChangeMode;
+
+ if ( settings == null )
+ {
+ return;
+ }
+
+ if ( settings.uiPreviousMenu?.isDown ?? false )
+ {
+ ChangeMenu( -1, wrapped );
+ }
+
+ if ( settings.uiNextMenu?.isDown ?? false )
+ {
+ ChangeMenu( 1, wrapped );
+ }
+
+ }
+
+ void ProcessMainInputs()
+ {
+ var settings = GetUI().settings;
+
+ if ( settings == null )
+ {
+ return;
+ }
+
+ if ( settings.uiConfirm?.isDown ?? false )
+ {
+ onConfirm?.Trigger();
+ onReady?.Trigger();
+ }
+
+ if ( settings.uiCancel?.isDown ?? false )
+ {
+ onCancel?.Trigger();
+ onReady?.Trigger();
+ }
+
+ }
+
+ void ChangeMenu( int offset, bool wrap )
+ {
+ var selectedPageIndex = pages.FindIndex( p => p.Visible );
+ var nextIndex = selectedPageIndex + offset;
+
+ nextIndex = wrap ? MathX.Repeat( nextIndex, pages.Length ) : Mathf.Clamp( nextIndex, 0, pages.Length -1 );
+
+
+ var nextSelectedPage = pages[ nextIndex ];
+ var category = nextSelectedPage.category;
+
+ var selector = header.GetAll().Find( selector => selector.category == category );
+ // var selector = nextSelectedPage.Get();
+
+ this.LogInfo(
+ "SelectedPageIndex:", selectedPageIndex, "nextIndex:", nextIndex,
+ HierarchyName.Of( nextSelectedPage ),
+ HierarchyName.Of( selector )
+ );
+
+ selector.Trigger();
+ }
+
+ void CreateAppSettingsUI()
+ {
+ this.DestroyChildren();
+
+ background = null;
+ header = null;
+ pages = [];
+
+ var resolvedSettings = appSettings ?? Unique.Get().settings;
+
+ background = generator.background.GenerateBackground( this ) as Node;
+
+ resolvedSettings.categories.ForEach( CreateCategory );
+
+ CreateHeader( resolvedSettings );
+
+
+
+ pages.ForEach( p => p.SetVisibility( p.category == appSettings.categories[ 0 ] ) );
+ }
+
+ void CreateHeader( AppSettings settings )
+ {
+ header = generator.header.GenerateHeader( this, settings );
+ }
+
+ void CreateCategory( AppSettingsCategory category )
+ {
+ var page = generator.catergoryPage.GenerateCategoryPage( this, category );
+ pages = pages.Add( page );
+ }
+}
diff --git a/Runtime/UI/UIAppSettings/UIAppSettings.cs.uid b/Runtime/UI/UIAppSettings/UIAppSettings.cs.uid
new file mode 100644
index 0000000..1eff144
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/UIAppSettings.cs.uid
@@ -0,0 +1 @@
+uid://dv2k1qbk8o5id
diff --git a/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs b/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs
new file mode 100644
index 0000000..4a7bfec
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs
@@ -0,0 +1,22 @@
+
+using Godot;
+using Rokojori;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass]
+public partial class UIAppSettingsGenerator:Resource
+{
+ [Export]
+ public UIAppSettingsBackgroundGenerator background;
+
+ [Export]
+ public UIAppSettingsHeaderGenerator header;
+
+ [Export]
+ public UIAppSettingsCategoryPageGenerator catergoryPage;
+
+}
diff --git a/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs.uid b/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs.uid
new file mode 100644
index 0000000..050d547
--- /dev/null
+++ b/Runtime/UI/UIAppSettings/UIAppSettingsGenerator.cs.uid
@@ -0,0 +1 @@
+uid://brw80tdgwgw4t
diff --git a/Runtime/UI/UISettings.cs b/Runtime/UI/UISettings.cs
index c270dee..4113078 100644
--- a/Runtime/UI/UISettings.cs
+++ b/Runtime/UI/UISettings.cs
@@ -6,24 +6,55 @@ namespace Rokojori
[Tool]
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UI.svg")]
public partial class UISettings : Resource
- {
+ {
[Export]
public InputIconsLibrary inputIconsLibrary;
+ [Export]
+ public TimeLine defaultTimeline;
+
+ [ExportGroup("Font")]
[Export]
public UINumber fontSize;
[Export]
public Font defaultFont;
+ [ExportGroup("Inputs")]
+ [Export]
+ public Sensor uiConfirm;
+
+ [Export]
+ public Sensor uiCancel;
+
+ [Export]
+ public Sensor uiLeft;
+
+ [Export]
+ public Sensor uiRight;
+
+ [Export]
+ public Sensor uiUp;
+
+ [Export]
+ public Sensor uiDown;
+
+ [Export]
+ public Sensor uiPreviousMenu;
+
+ [Export]
+ public Sensor uiNextMenu;
+
+
+ [ExportGroup("Shader Settings")]
+
[Export]
public Vector2PropertyName sizePropertyName;
[Export]
public Vector2PropertyName textureSizePropertyName;
- [Export]
- public TimeLine defaultTimeline;
+
}
diff --git a/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs
new file mode 100644
index 0000000..24d39c6
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs
@@ -0,0 +1,35 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class CustomLineMaterialPreset:LineMaterialPreset
+{
+ [Export]
+ public Material material;
+
+ [Export]
+ public GeometryInstance3D.ShadowCastingSetting shadows = GeometryInstance3D.ShadowCastingSetting.On;
+
+ [Export]
+ public LineVFXShaderSetup shaderSetup;
+
+ public override void CreateMaterial( LineVFX lineVFX, MeshInstance3D mi )
+ {
+ mi.SetSurfaceOverrideMaterial( 0, material );
+ mi.CastShadow = shadows;
+ }
+
+ public override void SetPointData( LineVFX lineVFX, MeshInstance3D mi, LinePointData data, bool start )
+ {
+ if ( start )
+ {
+ shaderSetup.start.Set( mi, data );
+ }
+ else
+ {
+ shaderSetup.end.Set( mi, data );
+ }
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs.uid b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs.uid
new file mode 100644
index 0000000..ab516c8
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/CustomLineMaterialPreset.cs.uid
@@ -0,0 +1 @@
+uid://d03apo8legu5r
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs
new file mode 100644
index 0000000..cefde77
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs
@@ -0,0 +1,11 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public abstract partial class LineMaterialPreset:Resource
+{
+ public abstract void CreateMaterial( LineVFX lineVFX, MeshInstance3D mi );
+ public abstract void SetPointData( LineVFX lineVFX, MeshInstance3D mi, LinePointData data, bool start );
+}
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs.uid b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs.uid
new file mode 100644
index 0000000..c1ab03d
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineMaterialPreset.cs.uid
@@ -0,0 +1 @@
+uid://ja1i66scdmqa
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs
new file mode 100644
index 0000000..7dbb15a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs
@@ -0,0 +1,34 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class LineVFXShaderPointProperties:Resource
+{
+ [Export]
+ public Vector3PropertyName positionName;
+
+ [Export]
+ public Vector3PropertyName forwardName;
+
+ [Export]
+ public Vector3PropertyName upName;
+
+ [Export]
+ public FloatPropertyName normalizedDistance;
+
+ public void Set( MeshInstance3D mi, LinePointData data )
+ {
+ positionName.SetInstance( mi, data.GetPosition() );
+ forwardName.SetInstance( mi, data.GetForward() );
+ upName.SetInstance( mi, data.GetUp() );
+
+ normalizedDistance.SetInstance( mi, data.GetNormalizedDistance() );
+ }
+
+
+}
+
+
\ No newline at end of file
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs.uid b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs.uid
new file mode 100644
index 0000000..a162510
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderPointProperties.cs.uid
@@ -0,0 +1 @@
+uid://cuo0gcxbb5wv1
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs
new file mode 100644
index 0000000..92dfb1a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs
@@ -0,0 +1,18 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class LineVFXShaderSetup:Resource
+{
+ [Export]
+ public LineVFXShaderPointProperties start;
+
+ [Export]
+ public LineVFXShaderPointProperties end;
+
+}
+
+
\ No newline at end of file
diff --git a/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs.uid b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs.uid
new file mode 100644
index 0000000..8d13d52
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMaterial/LineVFXShaderSetup.cs.uid
@@ -0,0 +1 @@
+uid://bxejx7wkhfpuj
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs b/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs
new file mode 100644
index 0000000..cf67251
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs
@@ -0,0 +1,17 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class CustomMeshGenerator:LineMeshGenerator
+{
+ [Export]
+ public Mesh customMesh;
+
+ public override Mesh GetMesh( LineVFX lineVFX, MeshInstance3D mi )
+ {
+ return customMesh;
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs.uid b/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs.uid
new file mode 100644
index 0000000..3eba442
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/CustomMeshGenerator.cs.uid
@@ -0,0 +1 @@
+uid://c16qq70lt434i
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs b/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs
new file mode 100644
index 0000000..2a85d8f
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs
@@ -0,0 +1,40 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class CylinderMeshGenerator:LineMeshGenerator
+{
+ [Export]
+ public int vertices = 16;
+
+ [Export]
+ public int divisions = 3;
+
+ Mesh segmentMesh;
+
+ public void CreateMesh()
+ {
+ var gen = new CylinderGenerator();
+ gen.vertices = vertices;
+ gen.subdivisions = divisions;
+ segmentMesh = gen.Generate();
+ }
+
+ int _v = -1;
+ int _d = -1;
+
+ public override Mesh GetMesh( LineVFX lineVFX, MeshInstance3D mi )
+ {
+ if ( segmentMesh == null || _v != vertices || _d != divisions)
+ {
+ CreateMesh();
+ _v = vertices;
+ _d = divisions;
+ }
+
+ return segmentMesh;
+ }
+
+}
\ No newline at end of file
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs.uid b/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs.uid
new file mode 100644
index 0000000..d59de91
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/CylinderMeshGenerator.cs.uid
@@ -0,0 +1 @@
+uid://dk5uf3xvja04c
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs b/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs
new file mode 100644
index 0000000..5ba8c4c
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs
@@ -0,0 +1,10 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public abstract partial class LineMeshGenerator:Resource
+{
+ public abstract Mesh GetMesh( LineVFX lineVFX, MeshInstance3D mi );
+}
\ No newline at end of file
diff --git a/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs.uid b/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs.uid
new file mode 100644
index 0000000..95287fc
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineMeshGenerator/LineMeshGenerator.cs.uid
@@ -0,0 +1 @@
+uid://cqjqt83vf62e5
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs
new file mode 100644
index 0000000..bd8eedf
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs
@@ -0,0 +1,25 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class AutoLinePointData:LinePointData
+{
+ [Export]
+ public Vector3 position;
+ public override Vector3 GetPosition(){ return position; }
+
+ public Vector3 forward;
+ public override Vector3 GetForward(){ return forward; }
+
+ public Vector3 up;
+ public override Vector3 GetUp(){ return up; }
+
+ public float normalizedDistance = 0f;
+ public override float GetNormalizedDistance()
+ {
+ return normalizedDistance;
+ }
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs.uid
new file mode 100644
index 0000000..270fad9
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointData.cs.uid
@@ -0,0 +1 @@
+uid://cvakxgn7tlup8
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs
new file mode 100644
index 0000000..0945d4d
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs
@@ -0,0 +1,191 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public abstract partial class AutoLinePointList:LinePointDataGenerator
+{
+
+
+ [Export]
+ public Vector3 up = Vector3.Up;
+
+ [Export( PropertyHint.Range, "0,1")]
+ public float symmetricTangents = 0;
+ float _symmetricTangents = 0;
+
+
+ [Export]
+ public bool splitLargeDistances = false;
+
+ [Export]
+ public float splitTreshold = 1.5f; // 0.75f - 1f
+
+ [Export]
+ public float splitLength = 1f;
+
+
+ [Export]
+ public float changeTreshold = 0.000001f;
+
+ List _cachedPoints = [];
+
+ protected abstract void _UpdatePoints( LineVFX lineVFX, double delta );
+
+ public override void Update( LineVFX lineVFX, double delta )
+ {
+ var data = lineVFX.GetData() as AutoLineVFXData;
+
+ if ( data == null )
+ {
+ data = new AutoLineVFXData();
+ lineVFX.SetData( data );
+ }
+
+ _UpdatePoints( lineVFX, delta );
+
+ // if ( Mode.Local_ChildPositions_From_Auto_Line_Parent == mode ||
+ // Mode.Global_ChildPositions_From_Auto_Line_Parent == mode
+ // )
+ // {
+ // UpdatePointsFromParent( lineVFX );
+ // }
+
+ if ( ! PointsChanged( lineVFX ) )
+ {
+ return;
+ }
+
+ if ( _cachedPoints == null )
+ {
+ _cachedPoints = [];
+ }
+
+ if ( data.points == null )
+ {
+ data.points = [];
+ }
+
+ if ( _cachedPoints.Count != data.points.Length )
+ {
+ _cachedPoints.Clear();
+ for ( int i = 0; i < data.points.Length; i++ )
+ {
+ _cachedPoints.Add( data.points[ i ].position );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < data.points.Length; i++ )
+ {
+ _cachedPoints[ i ] = data.points[ i ].position;
+ }
+ }
+
+ var cd = lineVFX.GetData() as AutoLineVFXData;
+
+ cd.customUpdateID ++;
+
+ var length = 0f;
+
+ for ( int i = 1; i < data.points.Length; i++ )
+ {
+ var d = ( data.points[ i ].position - data.points[ i - 1 ].position ).Length();
+ length += d;
+
+ data.points[ i ].normalizedDistance = length;
+
+ }
+
+ for ( int i = 1; i < data.points.Length; i++ )
+ {
+ data.points[ i ].normalizedDistance /= length;
+ }
+
+ for ( int i = 0; i < data.points.Length && data.points.Length > 1 ; i++ )
+ {
+ if ( i == data.points.Length - 1 )
+ {
+ data.points[ i ].forward = data.points[ i ].position - data.points[ i - 1 ].position;
+ }
+ else if ( i == 0 )
+ {
+ data.points[ i ].forward = data.points[ i + 1 ].position - data.points[ i ].position;
+ }
+ else
+ {
+ var before = data.points[ i ].position - data.points[ i - 1 ].position;
+ var after = data.points[ i + 1 ].position - data.points[ i ].position;
+
+ if ( symmetricTangents > 0 )
+ {
+ var bLength = before.Length();
+ var aLength = after.Length();
+
+ if ( bLength < aLength )
+ {
+ after = after.Lerp( after.Normalized() * bLength, symmetricTangents );
+ }
+ else
+ {
+ before = before.Lerp( before.Normalized() * aLength, symmetricTangents );
+ }
+ }
+
+ data.points[ i ].forward = ( before + after ) * 0.5f;
+ }
+
+ data.points[ i ].up = up;
+ }
+
+ _symmetricTangents = symmetricTangents;
+ cd.points = data.points;
+ }
+
+
+ bool PointsChanged( LineVFX lineVFX)
+ {
+ var data = lineVFX.GetData() as AutoLineVFXData;
+
+ if ( data.points == null || _cachedPoints == null )
+ {
+ return true;
+ }
+
+ if ( data.points.Length != _cachedPoints.Count )
+ {
+ return true;
+ }
+
+ if ( _symmetricTangents != symmetricTangents )
+ {
+ return true;
+ }
+
+
+ for ( int i = 0; i < data.points.Length; i++ )
+ {
+ var difference = data.points[ i ].position - _cachedPoints[ i ];
+
+ if ( Mathf.Abs( difference.X ) > 0.000001f )
+ {
+ return true;
+ }
+
+ if ( Mathf.Abs( difference.Y ) > 0.000001f )
+ {
+ return true;
+ }
+
+ if ( Mathf.Abs( difference.Z ) > 0.000001f )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs.uid b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs.uid
new file mode 100644
index 0000000..d19449a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLinePointList.cs.uid
@@ -0,0 +1 @@
+uid://60gdng6n54wb
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs
new file mode 100644
index 0000000..4a7b15b
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs
@@ -0,0 +1,29 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class AutoLineVFXData:LineVFXData
+{
+ public AutoLinePointData[] points;
+ public List pointsCacheList = [];
+
+ public int customUpdateID = -1;
+
+ public override int GetUpdateID(){ return customUpdateID; }
+ public override IEnumerable GetPointData(){ return points; }
+ public override int GetNumSegments()
+ {
+ return points == null ? 0 : points.Length - 1;
+ }
+
+ public override void SetSegmentData( MeshInstance3D mi, int segmentIndex )
+ {
+
+ }
+
+ public override Vector3 GetPositionAt( int i )
+ {
+ return points == null ? Vector3.Zero : points[ i ].position;
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs.uid
new file mode 100644
index 0000000..c94c463
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/AutoLine/AutoLineVFXData.cs.uid
@@ -0,0 +1 @@
+uid://8efughuiclqb
diff --git a/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs b/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs
new file mode 100644
index 0000000..ef5b018
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs
@@ -0,0 +1,114 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class ChildPositionsAutoLine:AutoLinePointList
+{
+ [Export]
+ public bool useGlobalPositions = true;
+
+ protected override void _UpdatePoints( LineVFX lineVFX, double delta )
+ {
+ UpdatePointsFromParent( lineVFX );
+ }
+
+ void UpdatePointsFromParent( LineVFX lineVFX )
+ {
+ if ( lineVFX.childPositionsParent == null )
+ {
+ return;
+ }
+
+ var data = lineVFX.GetData() as AutoLineVFXData;
+
+ var points = data.points;
+ var pointsCacheList = data.pointsCacheList;
+
+ if ( splitLargeDistances )
+ {
+ pointsCacheList.Clear();
+
+ var isGlobal = useGlobalPositions;
+
+ lineVFX.childPositionsParent.ForEachDirectChild(
+ n3D =>
+ {
+
+ if ( pointsCacheList.Count == 0 )
+ {
+ var p = new AutoLinePointData();
+ p.position = n3D.GetPosition( isGlobal );
+ pointsCacheList.Add( p );
+ }
+ else
+ {
+ var last = pointsCacheList[ pointsCacheList.Count - 1 ] .position;
+ var current = n3D.GetPosition( isGlobal );
+ var dir = current - last;
+ var length = dir.Length();
+
+ if ( length < splitTreshold )
+ {
+ var p = new AutoLinePointData();
+ p.position = n3D.GetPosition( isGlobal );
+ pointsCacheList.Add( p );
+
+ return;
+ }
+
+ var splits = Mathf.CeilToInt( length / splitLength );
+ var normalizeSplit = 1f / ( splits - 1 );
+ // 2 ns => 1 / ( 2 - 1 );
+ // 0 x, 1
+ // 4 ns => 1 / ( 4 - 1 );
+ // 0 x, 1/3, 2/3, 3/3
+
+ for ( int i = 1; i < splits; i++ )
+ {
+ var t = i * normalizeSplit;
+
+ var sp = new AutoLinePointData();
+ sp.position = last.Lerp( current, t );
+ pointsCacheList.Add( sp );
+ }
+ }
+
+ }
+ );
+
+ points = pointsCacheList.ToArray();
+
+ }
+ else
+ {
+ var childCount = lineVFX.childPositionsParent.GetChildCountOfType();
+
+ if ( points.Length != childCount )
+ {
+ points = new AutoLinePointData[ childCount ];
+
+ for ( int i = 0; i < points.Length; i++ )
+ {
+ points[ i ] = new AutoLinePointData();
+ }
+ }
+
+ var index = 0;
+ var isGlobal = useGlobalPositions;
+
+ lineVFX.childPositionsParent.ForEachDirectChild(
+ n3D =>
+ {
+ // this.LogInfo( "index:", index, points.Length, childCount );
+ points[ index ].position = n3D.GetPosition( isGlobal );
+ index ++;
+ }
+ );
+ }
+ }
+
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs.uid b/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs.uid
new file mode 100644
index 0000000..775974c
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/ChildPositionsAutoLine/ChildPositionsAutoLine.cs.uid
@@ -0,0 +1 @@
+uid://cr7hfwd1ki6yu
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs
new file mode 100644
index 0000000..8f1617b
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs
@@ -0,0 +1,25 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public partial class CustomLinePointData:LinePointData
+{
+ [Export]
+ public Vector3 position;
+ public override Vector3 GetPosition(){ return position; }
+
+ [Export]
+ public Vector3 forward;
+ public override Vector3 GetForward(){ return forward; }
+
+ [Export]
+ public Vector3 up;
+ public override Vector3 GetUp(){ return up; }
+
+ [Export]
+ public float normalizedDistance = 0f;
+ public override float GetNormalizedDistance(){ return normalizedDistance; }
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs.uid
new file mode 100644
index 0000000..e8eef6b
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointData.cs.uid
@@ -0,0 +1 @@
+uid://y615w3e7yj3o
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs
new file mode 100644
index 0000000..4902317
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs
@@ -0,0 +1,31 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class CustomLinePointList:LinePointDataGenerator
+{
+ [Export]
+ public CustomLinePointData[] points;
+
+ [Export]
+ public int customUpdateID = -1;
+
+ public override void Update( LineVFX lineVFX, double delta )
+ {
+ var data = lineVFX.GetData();
+
+ if ( data == null || ! ( data is CustomLineVFXData ) )
+ {
+ lineVFX.SetData( new CustomLineVFXData() );
+ }
+
+ var cd = lineVFX.GetData() as CustomLineVFXData;
+
+ cd.points = points;
+ cd.customUpdateID = customUpdateID;
+ }
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs.uid b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs.uid
new file mode 100644
index 0000000..8f27d49
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLinePointList.cs.uid
@@ -0,0 +1 @@
+uid://vt0juqpb0khg
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs
new file mode 100644
index 0000000..74a9e7d
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs
@@ -0,0 +1,28 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public class CustomLineVFXData:LineVFXData
+{
+ public CustomLinePointData[] points;
+
+ public int customUpdateID = -1;
+
+ public override int GetUpdateID(){ return customUpdateID; }
+ public override IEnumerable GetPointData(){ return points; }
+ public override int GetNumSegments()
+ {
+ return points.Length - 1;
+ }
+
+ public override void SetSegmentData( MeshInstance3D mi, int segmentIndex )
+ {
+
+ }
+
+ public override Vector3 GetPositionAt( int i )
+ {
+ return points == null ? Vector3.Zero : points[ i ].position;
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs.uid
new file mode 100644
index 0000000..b25ef20
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/CustomLine/CustomLineVFXData.cs.uid
@@ -0,0 +1 @@
+uid://4cvlhbo7vh62
diff --git a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs
new file mode 100644
index 0000000..89899c1
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs
@@ -0,0 +1,87 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class FollowAutoLine:AutoLinePointList
+{
+ [Export]
+ public float distanceTreshold = 1f;
+
+ [Export]
+ public int maxPoints = 100;
+
+ [Export]
+ public bool following = false;
+
+
+ protected override void _UpdatePoints( LineVFX lineVFX, double delta )
+ {
+ if ( ! following )
+ {
+ return;
+ }
+
+ var data = lineVFX.GetData() as AutoLineVFXData;
+
+ var points = data.points;
+
+
+ var newPosition = lineVFX.followSource.GlobalPosition;
+ var needsNewPoint = NotEnoughPoints( points ) || Moved( newPosition, points );
+
+ if ( ! needsNewPoint )
+ {
+
+ points[ points.Length -1 ].position = newPosition + Vector3.One * 0.00001f;
+ return;
+ }
+
+ if ( points == null || points.Length < 2)
+ {
+ var p1 = new AutoLinePointData();
+ var p2 = new AutoLinePointData();
+ p1.position = newPosition;
+ p2.position = newPosition + Vector3.One * 0.00001f;
+
+ data.points = [ p1, p2 ];
+
+ return;
+ }
+
+ var p = new AutoLinePointData();
+ p.position = newPosition;
+
+ var pos2 = points[ points.Length - 2 ].position;
+
+ var dir = newPosition - pos2;
+
+ points[ points.Length - 1 ].position = pos2 + dir.Normalized() * distanceTreshold;
+
+ if ( points.Length == maxPoints )
+ {
+ points = points.RemoveIndex( 0 );
+ }
+
+
+ data.points = points.Add( p );
+ }
+
+ bool NotEnoughPoints( AutoLinePointData[] _points )
+ {
+ return _points == null || _points.Length < 2;
+ }
+
+
+ bool Moved( Vector3 current, AutoLinePointData[] _points )
+ {
+ var lastPoint = _points[ _points.Length - 2 ].position;
+
+ var dir = current - lastPoint;
+ var length = dir.Length();
+
+ return length > distanceTreshold;
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs.uid b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs.uid
new file mode 100644
index 0000000..bc2b4b7
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/FollowAutoLine.cs.uid
@@ -0,0 +1 @@
+uid://cylph4wxm4xme
diff --git a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs
new file mode 100644
index 0000000..cab1f02
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs
@@ -0,0 +1,38 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class SetFollowAutoLine:Action
+{
+ [Export]
+ public LineVFX line;
+
+ [Export]
+ public bool following = true;
+
+ [Export]
+ public bool clearLine = false;
+
+ protected override void _OnTrigger()
+ {
+ var followAutoLine = line?.preset?.pointGenerator as FollowAutoLine;
+
+ if ( followAutoLine == null )
+ {
+ return;
+ }
+
+ followAutoLine.following = following;
+
+ if ( clearLine )
+ {
+ line.ClearLine();
+ }
+
+
+
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs.uid b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs.uid
new file mode 100644
index 0000000..59ff40a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/FollowAutoLine/SetFollowAutoLine.cs.uid
@@ -0,0 +1 @@
+uid://boxi854yskurg
diff --git a/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs b/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs
new file mode 100644
index 0000000..8ff24ba
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs
@@ -0,0 +1,16 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool,GlobalClass]
+public abstract partial class LinePointData:Resource
+{
+ public abstract Vector3 GetPosition();
+
+ public abstract Vector3 GetForward();
+
+ public abstract Vector3 GetUp();
+
+ public abstract float GetNormalizedDistance();
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs.uid
new file mode 100644
index 0000000..cacd5c4
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LinePointData.cs.uid
@@ -0,0 +1 @@
+uid://cd1xxx2nwnefa
diff --git a/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs b/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs
new file mode 100644
index 0000000..34435dd
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs
@@ -0,0 +1,12 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public abstract partial class LinePointDataGenerator:Resource
+{
+ public abstract void Update( LineVFX lineVFX, double delta );
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs.uid b/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs.uid
new file mode 100644
index 0000000..ad0c65f
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LinePointDataGenerator.cs.uid
@@ -0,0 +1 @@
+uid://633vouxuraxf
diff --git a/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs
new file mode 100644
index 0000000..04295de
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs
@@ -0,0 +1,50 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+public abstract class LineVFXData
+{
+ public abstract int GetUpdateID();
+ public abstract IEnumerable GetPointData();
+ public abstract int GetNumSegments();
+ public abstract void SetSegmentData( MeshInstance3D mi, int segmentIndex );
+ public virtual int GetNumPoints()
+ {
+ return GetNumSegments() + 1;
+ }
+
+ public abstract Vector3 GetPositionAt( int index );
+ public Vector3 LerpPositionAt( float normalizedIndex )
+ {
+ if ( GetNumPoints() == 0 )
+ {
+ return Vector3.Zero;
+ }
+
+ if ( GetNumPoints() == 1 )
+ {
+ return GetPositionAt( 0 );
+ }
+
+ var pointIndex = normalizedIndex * GetNumPoints();
+
+ if ( pointIndex <= 0 )
+ {
+ return GetPositionAt( 0 );
+ }
+
+ if ( pointIndex >= GetNumPoints() - 1 )
+ {
+ return GetPositionAt( GetNumPoints() - 1 );
+ }
+
+ var lowerIndex = Mathf.FloorToInt( pointIndex );
+ var higherIndex = Mathf.CeilToInt( pointIndex );
+
+ var p0 = GetPositionAt( lowerIndex );
+ var p1 = GetPositionAt( higherIndex );
+
+ return p0.Lerp( p1, pointIndex - lowerIndex );
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs.uid b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs.uid
new file mode 100644
index 0000000..54c2b5a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/LineVFXPointData.cs.uid
@@ -0,0 +1 @@
+uid://dsa3wvnj2ukom
diff --git a/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs b/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs
new file mode 100644
index 0000000..b6f590c
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs
@@ -0,0 +1,19 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class ManualAutoLine:AutoLinePointList
+{
+ [Export]
+ public AutoLinePointData[] points;
+
+ protected override void _UpdatePoints( LineVFX lineVFX, double delta )
+ {
+ var data = lineVFX.GetData() as AutoLineVFXData;
+
+ data.points = points;
+ }
+}
diff --git a/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs.uid b/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs.uid
new file mode 100644
index 0000000..0eedf3a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePoint/ManualAutoLine/ManualAutoLine.cs.uid
@@ -0,0 +1 @@
+uid://qu0grxbx4sda
diff --git a/Runtime/VFX/LineVFX/LinePreset.cs b/Runtime/VFX/LineVFX/LinePreset.cs
new file mode 100644
index 0000000..ddba66e
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePreset.cs
@@ -0,0 +1,29 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class LinePreset:Resource
+{
+ [Export]
+ public LinePointDataGenerator pointGenerator;
+
+ [Export]
+ public LineMeshGenerator meshGenerator;
+
+ [Export]
+ public LineMaterialPreset materialPreset;
+
+ public void Update( LineVFX lineVFX, double delta )
+ {
+ if ( pointGenerator == null )
+ {
+ return;
+ }
+
+ pointGenerator.Update( lineVFX, delta );
+ }
+
+}
diff --git a/Runtime/VFX/LineVFX/LinePreset.cs.uid b/Runtime/VFX/LineVFX/LinePreset.cs.uid
new file mode 100644
index 0000000..7a35173
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LinePreset.cs.uid
@@ -0,0 +1 @@
+uid://bt72ncr1j6ybq
diff --git a/Runtime/VFX/LineVFX/LineVFX.cs b/Runtime/VFX/LineVFX/LineVFX.cs
new file mode 100644
index 0000000..f1334d0
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineVFX.cs
@@ -0,0 +1,169 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class LineVFX:Node3D
+{
+ [ExportToolButton( "Force Update")]
+ public Callable forceUpdateButton => Callable.From(
+ () =>
+ {
+ ClearLine();
+ }
+ );
+
+ public void ClearLine()
+ {
+ _lastUpdateID = -1;
+ _data = null;
+ this.DestroyChildren();
+ }
+
+ [Export]
+ public LinePreset preset;
+
+ [ExportGroup("References")]
+ [Export]
+ public Node3D followSource;
+
+ [Export]
+ public Node3D childPositionsParent;
+
+ [ExportGroup("Shader Setup")]
+ [Export]
+ public Vector3PropertyName startPositionName;
+
+ [Export]
+ public Vector3PropertyName startForwardName;
+
+ [Export]
+ public Vector3PropertyName startUpName;
+
+ [Export]
+ public Vector3PropertyName endPositionName;
+
+ [Export]
+ public Vector3PropertyName endForwardName;
+
+ [Export]
+ public Vector3PropertyName endUpName;
+
+
+
+
+ LineVFXData _data;
+ int _lastUpdateID = -1;
+
+ public void SetData( LineVFXData data )
+ {
+ _data = data;
+ }
+
+ public LineVFXData GetData()
+ {
+ return _data;
+ }
+
+ public override void _Process( double delta )
+ {
+ if ( preset == null )
+ {
+ return;
+ }
+
+ preset.Update( this, delta );
+
+ if ( _data == null || _lastUpdateID == _data.GetUpdateID() )
+ {
+ return;
+ }
+
+ _lastUpdateID = _data.GetUpdateID();
+ UpdateSegments();
+
+
+ }
+
+ public Vector3 GetLerpedLinePositionAt( float t )
+ {
+ return _data == null ? Vector3.Zero : _data.LerpPositionAt( t );
+ }
+
+ void UpdateSegments()
+ {
+ var segments = Mathf.Max( 0, _data.GetNumSegments() );
+
+
+ this.EnsureChildCount( segments,
+ ( mi )=>
+ {
+ mi.Mesh = preset.meshGenerator.GetMesh( this, mi );
+ preset.materialPreset.CreateMaterial( this, mi );
+ }
+ );
+
+
+ var points = _data.GetPointData();
+
+ LinePointData start = null;
+ var segmentIndex = 0;
+
+ foreach ( var p in points )
+ {
+ if ( start == null )
+ {
+ start = p;
+
+ // if ( lineStart != null )
+ // {
+ // lineStart.GlobalPosition = start.GetPosition();
+ // lineStart.LookAt( start.GetPosition() + start.GetForward(), start.GetUp() );
+ // }
+
+ continue;
+ }
+
+ var end = p;
+ var mi = GetChild( segmentIndex ) as MeshInstance3D;
+ segmentIndex++;
+
+ preset.materialPreset.SetPointData( this, mi, start, true );
+ preset.materialPreset.SetPointData( this, mi, end, false );
+ // AssignPointData( mi, start, startPositionName, startForwardName, startUpName );
+ // AssignPointData( mi, end, endPositionName, endForwardName, endUpName );
+
+ var startPosition = start.GetPosition();
+ var endPosition = end.GetPosition();
+
+ var bounds = Box3.Create( startPosition, endPosition );
+ bounds.Extend( 1 + ( endPosition - startPosition ).Length() );
+ mi.CustomAabb = bounds;
+
+ start = end;
+ }
+
+
+ // if ( lineEnd != null )
+ // {
+ // lineEnd.GlobalPosition = start.GetPosition();
+ // lineEnd.LookAt( start.GetPosition() + start.GetForward(), start.GetUp() );
+ // }
+
+ // for ( int i = 0; i < segments; i++ )
+ // {
+ // var mi = GetChild( i ) as MeshInstance3D;
+
+ // }
+ }
+
+ // void AssignPointData( GeometryInstance3D gi, LinePointData lp,
+ // Vector3PropertyName p, Vector3PropertyName f, Vector3PropertyName u )
+ // {
+ // p.SetInstance( gi, lp.GetPosition() );
+ // f.SetInstance( gi, lp.GetForward() );
+ // u.SetInstance( gi, lp.GetUp() );
+ // }
+}
diff --git a/Runtime/VFX/LineVFX/LineVFX.cs.uid b/Runtime/VFX/LineVFX/LineVFX.cs.uid
new file mode 100644
index 0000000..37c5261
--- /dev/null
+++ b/Runtime/VFX/LineVFX/LineVFX.cs.uid
@@ -0,0 +1 @@
+uid://sf08iwoga2ba
diff --git a/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs b/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs
new file mode 100644
index 0000000..ecc033e
--- /dev/null
+++ b/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs
@@ -0,0 +1,38 @@
+using Godot;
+using System.Collections.Generic;
+
+namespace Rokojori;
+
+[Tool]
+[GlobalClass ]
+public partial class SetPositionOnLineVFX:Action
+{
+ [Export]
+ public Node3D target;
+
+ [Export]
+ public LineVFX lineVFX;
+
+ [Export( PropertyHint.Range, "0,1" ) ]
+ public float normalizedPosition = 0.5f;
+
+ [Export( PropertyHint.Range, "0,1" ) ]
+ public float normalizedRange = 0.5f;
+
+ protected override void _OnTrigger()
+ {
+ var random = GodotRandom.Get();
+
+ var min = normalizedPosition - normalizedRange;
+ var max = normalizedPosition + normalizedRange;
+
+ var t = random.Range( min, max );
+ t = MathX.Clamp01( t );
+
+ // this.LogInfo( t, normalizedPosition, normalizedRange, min, max );
+
+ var p = lineVFX.GetLerpedLinePositionAt( t );
+
+ target.GlobalPosition = p;
+ }
+}
diff --git a/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs.uid b/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs.uid
new file mode 100644
index 0000000..4c03b2a
--- /dev/null
+++ b/Runtime/VFX/LineVFX/SetPositionOnLineVFX.cs.uid
@@ -0,0 +1 @@
+uid://bsuqbg0trgspl
diff --git a/Tools/Messages/Message Background.tres b/Tools/Messages/Message Background.tres
index b87e9de..354cc48 100644
--- a/Tools/Messages/Message Background.tres
+++ b/Tools/Messages/Message Background.tres
@@ -2,7 +2,7 @@
[ext_resource type="Script" uid="uid://cnkyynboxg1qg" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UINumber.cs" id="1_4fcac"]
[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="2_m58tc"]
-[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs" id="3_uxf5k"]
+[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs" id="3_uxf5k"]
[sub_resource type="Resource" id="Resource_yp323"]
script = ExtResource("1_4fcac")
diff --git a/Tools/Messages/Message.tscn b/Tools/Messages/Message.tscn
index 21a8073..6a8e792 100644
--- a/Tools/Messages/Message.tscn
+++ b/Tools/Messages/Message.tscn
@@ -9,14 +9,14 @@
[ext_resource type="Script" uid="uid://dlu21piejg7w0" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangleMaterial.cs" id="6_wmt7q"]
[ext_resource type="Shader" uid="uid://x1a008jxt3ej" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader" id="7_aeebn"]
[ext_resource type="Script" uid="uid://bvaltw071whox" path="res://addons/rokojori_action_library/Tools/Messages/Message.cs" id="7_wmt7q"]
-[ext_resource type="Script" uid="uid://bx0bk663u3hj5" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImage.cs" id="8_gyhi8"]
+[ext_resource type="Script" uid="uid://bx0bk663u3hj5" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImage.cs" id="8_gyhi8"]
[ext_resource type="Resource" uid="uid://bliw5flmiq30c" path="res://addons/rokojori_action_library/Tools/Messages/Message Background.tres" id="9_wmt7q"]
[ext_resource type="Script" uid="uid://y2p0r8c5rs45" path="res://addons/rokojori_action_library/Runtime/Shading/Properties/ColorPropertyName.cs" id="10_btdid"]
[ext_resource type="Script" uid="uid://f7s137m6egkj" path="res://addons/rokojori_action_library/Runtime/UI/ShaderProperties/ShaderUIColor.cs" id="11_x3h2c"]
[ext_resource type="Script" uid="uid://jqgdm3r2u8xq" path="res://addons/rokojori_action_library/Runtime/Shading/Properties/FloatPropertyName.cs" id="12_xevu7"]
[ext_resource type="Script" uid="uid://j3mk8vwv56ui" path="res://addons/rokojori_action_library/Runtime/UI/ShaderProperties/ShaderUINumber.cs" id="13_1jemv"]
-[ext_resource type="Script" uid="uid://ce5eo6r5jqilt" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImageTypes/UIImageType.cs" id="14_1hp7s"]
-[ext_resource type="SystemFont" uid="uid://s1pi67tbxu24" path="res://3rdPerson/Inputs/Jost-Font.tres" id="15_nro64"]
+[ext_resource type="Script" uid="uid://ce5eo6r5jqilt" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImageTypes/UIImageType.cs" id="14_1hp7s"]
+[ext_resource type="SystemFont" path="res://3rdPerson/Inputs/Jost-Font.tres" id="15_nro64"]
[ext_resource type="Script" uid="uid://rqs2m0u6yvvf" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIText.cs" id="16_0e03u"]
[ext_resource type="Resource" uid="uid://c0hm8flp73453" path="res://addons/rokojori_action_library/Tools/Messages/Message Icon.tres" id="16_1tota"]
[ext_resource type="Script" uid="uid://bvj322mokkq63" path="res://addons/rokojori_action_library/Runtime/Localization/LocaleText.cs" id="17_illef"]
@@ -29,7 +29,7 @@
[ext_resource type="Resource" uid="uid://bilueedl68o8b" path="res://addons/rokojori_action_library/Tools/Messages/Message Time Stamp.tres" id="24_jm3cb"]
[ext_resource type="Resource" uid="uid://3l4054xmleyf" path="res://addons/rokojori_action_library/Tools/Messages/Message Resource Link.tres" id="27_gyhi8"]
[ext_resource type="Resource" uid="uid://c4x06404fxbq2" path="res://addons/rokojori_action_library/Tools/Messages/Message Web Link.tres" id="28_jm3cb"]
-[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs" id="30_btdid"]
+[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs" id="30_btdid"]
[sub_resource type="Resource" id="Resource_8aipl"]
script = ExtResource("2_3bqvc")
diff --git a/Tools/Messages/Messages.tscn b/Tools/Messages/Messages.tscn
index 33e2c54..9ae12b6 100644
--- a/Tools/Messages/Messages.tscn
+++ b/Tools/Messages/Messages.tscn
@@ -9,15 +9,15 @@
[ext_resource type="Script" uid="uid://drqb0pm5ub64g" path="res://addons/rokojori_action_library/Runtime/UI/Styling/UIColor.cs" id="6_j2i2l"]
[ext_resource type="Script" uid="uid://dlu21piejg7w0" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangleMaterial.cs" id="9_a81dy"]
[ext_resource type="Shader" uid="uid://x1a008jxt3ej" path="res://addons/rokojori_action_library/Runtime/UI/Shaders/RoundedRectangle/RoundedRectangle.gdshader" id="10_fbdhv"]
-[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImageTypes/RoundedRectangleUIImageType.cs" id="12_8waa8"]
-[ext_resource type="Script" uid="uid://bx0bk663u3hj5" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/UIImage.cs" id="12_kfok7"]
+[ext_resource type="Script" uid="uid://dwuimn03cvh3" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImageTypes/RoundedRectangleUIImageType.cs" id="12_8waa8"]
+[ext_resource type="Script" uid="uid://bx0bk663u3hj5" path="res://addons/rokojori_action_library/Runtime/UI/Nodes/Image/UIImage.cs" id="12_kfok7"]
[ext_resource type="Script" uid="uid://y2p0r8c5rs45" path="res://addons/rokojori_action_library/Runtime/Shading/Properties/ColorPropertyName.cs" id="14_pugir"]
[ext_resource type="Script" uid="uid://f7s137m6egkj" path="res://addons/rokojori_action_library/Runtime/UI/ShaderProperties/ShaderUIColor.cs" id="15_ojjyv"]
[ext_resource type="Script" uid="uid://jqgdm3r2u8xq" path="res://addons/rokojori_action_library/Runtime/Shading/Properties/FloatPropertyName.cs" id="16_bjurn"]
[ext_resource type="Script" uid="uid://j3mk8vwv56ui" path="res://addons/rokojori_action_library/Runtime/UI/ShaderProperties/ShaderUINumber.cs" id="17_pyi7r"]
[ext_resource type="Script" uid="uid://3bymmno3avag" path="res://addons/rokojori_action_library/Runtime/UI/Transitions/TransitionSettingsAll.cs" id="22_fbdhv"]
[ext_resource type="Resource" uid="uid://vbvri2ltruat" path="res://addons/rokojori_action_library/Tools/Messages/Vertical-Slider.tres" id="24_8aipl"]
-[ext_resource type="Script" uid="uid://btwjt483gljv7" path="res://addons/rokojori_action_library/Runtime/UI/Components/UISlider.cs" id="25_8waa8"]
+[ext_resource type="Script" uid="uid://btwjt483gljv7" path="res://addons/rokojori_action_library/Runtime/UI/Components/OldUISlider.cs" id="25_8waa8"]
[ext_resource type="Script" uid="uid://lhuuedx87rem" path="res://addons/rokojori_action_library/Runtime/Animation/Smoothing/FrameSmoothing.cs" id="26_pugir"]
[sub_resource type="Resource" id="Resource_bjurn"]