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 ); } }