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