Files
AetherBags/KamiToolKit/Nodes/Component/ScrollBarNode.cs
T
KnackAtNite 8db4ce6094
Debug Build and Test / Build against Latest Dalamud (push) Has been cancelled
Debug Build and Test / Build against Staging Dalamud (push) Has been cancelled
Initial commit: AetherBags + KamiToolKit for FC Gitea
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 14:46:31 -05:00

129 lines
3.8 KiB
C#

using System;
using System.Numerics;
using FFXIVClientStructs.FFXIV.Component.GUI;
namespace KamiToolKit.Nodes;
public unsafe class ScrollBarNode : ComponentNode<AtkComponentScrollBar, AtkUldComponentDataScrollBar> {
public readonly ScrollBarBackgroundButtonNode BackgroundButtonNode;
public readonly ScrollBarForegroundButtonNode ForegroundButtonNode;
public ScrollBarNode() {
SetInternalComponentType(ComponentType.ScrollBar);
BackgroundButtonNode = new ScrollBarBackgroundButtonNode {
Size = new Vector2(8.0f, 306.0f),
};
BackgroundButtonNode.AttachNode(this);
ForegroundButtonNode = new ScrollBarForegroundButtonNode {
Size = new Vector2(8.0f, 306.0f),
};
ForegroundButtonNode.AttachNode(this);
Data->Nodes[0] = ForegroundButtonNode.NodeId;
Data->Nodes[1] = 0; // Arrow Up Button
Data->Nodes[2] = 0; // Arrow Down Button
Data->Nodes[3] = BackgroundButtonNode.NodeId;
Data->Vertical = 1;
Data->Margin = 0;
InitializeComponentEvents();
Component->MouseDownScreenPos = 0;
Component->MouseWheelSpeed = 24;
AddEvent(AtkEventType.ValueUpdate, UpdateHandler);
}
public Action<int>? OnValueChanged { get; set; }
public NodeBase? ContentNode {
get;
set {
field = value;
if (value is not null) {
Component->ContentNode = value;
UpdateScrollParams();
}
}
}
public CollisionNode? ContentCollisionNode {
get;
set {
field = value;
Component->ContentCollisionNode = value is null ? null : value.Node;
UpdateScrollParams();
}
}
public int ScrollPosition {
get => Component->ScrollPosition;
set => Component->SetScrollPosition(value);
}
public int ScrollSpeed {
get => Component->MouseWheelSpeed;
set => Component->MouseWheelSpeed = (short)value;
}
public bool HideWhenDisabled { get; set; }
private void UpdateHandler() {
OnValueChanged?.Invoke(Component->PendingScrollPosition);
}
protected override void OnSizeChanged() {
base.OnSizeChanged();
BackgroundButtonNode.Size = Size;
ForegroundButtonNode.Size = Size;
}
/// <summary>
/// Updates from attached Content and Collision nodes
/// </summary>
public void UpdateScrollParams() {
if (Component->ContentNode is null) return;
if (Component->ContentCollisionNode is null) return;
var content = Component->ContentNode;
var collision = Component->ContentCollisionNode;
UpdateScrollParams(collision->Height, content->Height);
}
public void UpdateScrollParams(int barHeight, int offScreenHeight) {
var distance = offScreenHeight - barHeight;
Component->ScrollbarLength = (short)barHeight;
Component->ScrollMaxPosition = Math.Max(distance, 0);
Component->ContentNodeOffScreenLength = Math.Max((short)distance, (short)0);
Component->EmptyLength = Math.Max(barHeight - (int)((float)barHeight / offScreenHeight * barHeight), 0);
ForegroundButtonNode.Height = barHeight - Component->EmptyLength;
if (Component->ScrollPosition > Component->ScrollMaxPosition) {
Component->SetScrollPosition(Component->ScrollMaxPosition);
}
if (Component->EmptyLength is 0) {
ForegroundButtonNode.Y = 0.0f;
ContentNode?.Y = 0;
}
var enabledState = Component->EmptyLength is not 0;
Component->SetEnabledState(enabledState);
if (HideWhenDisabled) {
BackgroundButtonNode.IsVisible = enabledState;
ForegroundButtonNode.IsVisible = enabledState;
}
}
}