rj-action-library/Runtime/UI/Components/UISlider.cs

376 lines
10 KiB
C#

using Godot;
using System;
using System.IO;
namespace Rokojori
{
[Tool][GlobalClass]
public partial class UISlider : Node, IAssemblyReload
{
[Export]
public Control button;
[Export]
public Control background;
[Export]
public Smoothing smoothing;
public enum Direction
{
Vertical,
Horizontal,
Both
}
[Export]
public Direction direction = Direction.Vertical;
[Export]
public Vector2 sliderValue;
[ExportGroup( "Scrolling")]
[Export]
public Control scrollTarget;
[Export]
public Control scrollContainer;
[Export]
public bool adjustButtonSizeToScrollContent;
[Export( PropertyHint.Range, "0,500, suffix:px")]
public float mouseWheelAbsoluteScroll = 10f;
[Export( PropertyHint.Range, "0,100, suffix:%")]
public float mouseWheelRelativeScroll = 10f;
Vector2 cachedMouseOffset;
Vector2 cachedButtonPosition;
public void OnAssemblyReloaded()
{
AddDraggingListener();
}
string scrollID = IDGenerator.GenerateID();
public override void _Ready()
{
// button.GuiInput += OnGUIInput;
// this.LogInfo( "S Adding new listeners" );
AddDraggingListener();
if ( scrollTarget != null && scrollContainer != null )
{
scrollContainer.Resized += SyncScroll;
scrollContainer.GuiInput += ( InputEvent ie )=>
{
if ( ie is InputEventMouseButton mb &&
( mb.ButtonIndex == MouseButton.WheelUp || mb.ButtonIndex == MouseButton.WheelDown ||
mb.ButtonIndex == MouseButton.WheelLeft || mb.ButtonIndex == MouseButton.WheelRight )
)
{
var range = GetScrollRange();
// var percentageAmount = 0.1f;
// var relativeToAbsolute = percentageAmount * range;
var absoluteAmount = mouseWheelAbsoluteScroll;
var absoluteToRelative = mouseWheelAbsoluteScroll * Vector2.One / range;
var buttonRange = absoluteToRelative * GetButtonScrollRange();
var scrollDelta = buttonRange;
// this.LogInfo( leftMouseCallback == null, leftMouseCallback?.GetUID(), leftMouseCallback?.GetInfo(), leftMouseCallback?.wasDisposed );
// scrollContainer.LogInfo( "Input", ie );
if ( mb.ButtonIndex == MouseButton.WheelUp )
{
scrollDelta.Y *= -1;
}
if ( mb.ButtonIndex == MouseButton.WheelLeft )
{
scrollDelta.X *= -1;
}
// sliderValue += scrollDelta;
// sliderValue = sliderValue.Clamp( 0, 1 );
// SyncScroll();
if ( Direction.Horizontal == direction )
{
scrollDelta.Y = 0;
}
else if ( Direction.Vertical == direction )
{
scrollDelta.X = 0;
}
nextValue = ( button.Position + scrollDelta ).Clamp( Vector2.Zero, GetButtonScrollRange() );
// this.LogInfo( scrollDelta );
var ui = this.FindParentThatIs<UI>();
ui.onProcess.AddAction( UpdatePosition );
( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
( button as UIStylePropertyContainerNode ).SetDirty();
}
};
}
if ( adjustButtonSizeToScrollContent )
{
scrollTarget.Resized += UpdateButtonSize;
scrollContainer.Resized += UpdateButtonSize;
UpdateButtonSize();
}
}
void UpdateButtonSize()
{
var value = new UINumber();
var target = button as UIStylePropertyContainer;
if ( Direction.Vertical == direction )
{
value.value = Mathf.Min( 10, background.Size.Y - Mathf.Max( 10, scrollTarget.Size.Y - scrollContainer.Size.Y ) );
target.SetUIStyleNumberProperty( UIStyleNumberProperty.Height, value );
}
if ( Direction.Horizontal == direction )
{
value.value = Mathf.Min( 10, background.Size.X - Mathf.Max( 10, scrollTarget.Size.X - scrollContainer.Size.X ) );
target.SetUIStyleNumberProperty( UIStyleNumberProperty.Width, value );
}
}
bool _dragging = false;
bool _updatingPosition = false;
UIDragging.UIDraggingCallbacks leftMouseCallbacks;
UIDragging.UIDraggingCallbacks middleMouseCallbacks;
public override void _Process( double delta )
{
if (
leftMouseCallbacks == null || leftMouseCallbacks.notValid ||
middleMouseCallbacks == null || middleMouseCallbacks.notValid
)
{
AddDraggingListener();
}
}
void AddDraggingListener()
{
leftMouseCallbacks = UIDragging.OnLeftMouseButton( button,
( ev )=>
{
if ( ev.isStart )
{
cachedButtonPosition = button.Position;
smoothing.SetCurrent( cachedButtonPosition );
_dragging = true;
_updatingPosition = true;
ev.ui.onProcess.AddAction( UpdatePosition );
( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
}
else if ( ev.isEnd )
{
_dragging = false;
}
var nextPosition = cachedButtonPosition + ev.distanceToStart;
nextValue = nextPosition.Clamp( Vector2.Zero, GetButtonScrollRange() );
}
);
middleMouseCallbacks = UIDragging.OnMiddleMouseButton( scrollContainer,
( ev )=>
{
if ( ev.isStart )
{
cachedButtonPosition = button.Position;
smoothing.SetCurrent( cachedButtonPosition );
_dragging = true;
_updatingPosition = true;
ev.ui.onProcess.AddAction( UpdatePosition );
( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
ev.customOffset = Vector2.Zero;
}
else if ( ev.isEnd )
{
_dragging = false;
}
ev.customOffset += ev.distanceToStart * 0.1f;
var nextPosition = cachedButtonPosition + ev.customOffset;
nextValue = nextPosition.Clamp( Vector2.Zero, GetButtonScrollRange() );
ev.customOffset = nextValue - cachedButtonPosition;
}
);
}
Vector2 cachedOffset = Vector2.Zero;
void UpdatePosition( float delta )
{
// this.LogInfo( "UpdatePosition" );
var value = Smoothing.Apply( smoothing, nextValue, delta );
var uiStyleContainer = ( UIStylePropertyContainerNode ) button;
uiStyleContainer.SetLayoutDirtyFlag();
if ( ! _dragging && ( value - nextValue ).Length() < 1 )
{
var ui = this.FindParentThatIs<UI>();
ui.onProcess.RemoveAction( UpdatePosition );
_updatingPosition = false;
// this.LogInfo( "Removed Processing" );
value = nextValue;
uiStyleContainer.RemoveUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
}
if ( Direction.Both == direction || Direction.Horizontal == direction )
{
var left = new UINumber();
left.value = value.X;
uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );
}
if ( Direction.Both == direction || Direction.Vertical == direction )
{
var top = new UINumber();
top.value = value.Y;
uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );
}
var range = background.Size - button.Size;
sliderValue = button.Position / range;
if ( scrollTarget != null && scrollContainer != null )
{
var scrollRange = scrollTarget.Size - scrollContainer.Size;
var scrollOffset = scrollRange * sliderValue;
var scrollTargetNode = scrollTarget as UIStylePropertyContainerNode;
if ( Direction.Both == direction || Direction.Horizontal == direction )
{
var left = new UINumber();
left.value = -scrollOffset.X;
scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );
}
if ( Direction.Both == direction || Direction.Vertical == direction )
{
var top = new UINumber();
top.value = -scrollOffset.Y;
scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );
}
}
}
Vector2 nextValue;
Vector2 GetButtonScrollRange()
{
return ( background.Size - button.Size ).Max( Vector2.Zero );
}
Vector2 GetScrollRange()
{
return ( scrollTarget.Size - scrollContainer.Size ).Max( Vector2.Zero );
}
void SyncScroll()
{
if ( _dragging || _updatingPosition )
{
// this.LogInfo( "SyncScroll blocked" );
return;
}
// this.LogInfo( "SyncScroll" );
var uiStyleContainer = ( UIStylePropertyContainerNode ) button;
var value = GetButtonScrollRange() * sliderValue;
uiStyleContainer.SetDirty();
if ( Direction.Both == direction || Direction.Horizontal == direction )
{
var left = new UINumber();
left.value = value.X;
uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );
}
if ( Direction.Both == direction || Direction.Vertical == direction )
{
var top = new UINumber();
top.value = value.Y;
uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );
}
if ( scrollTarget != null && scrollContainer != null )
{
var scrollRange = scrollTarget.Size - scrollContainer.Size;
var scrollOffset = scrollRange * sliderValue;
if ( Direction.Both == direction || Direction.Horizontal == direction )
{
var left = new UINumber();
left.value = -scrollOffset.X;
( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );
}
if ( Direction.Both == direction || Direction.Vertical == direction )
{
var top = new UINumber();
top.value = -scrollOffset.Y;
( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );
}
}
}
}
}