forked from FPSMasterTeam/FPSMaster-Edge
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScrollContainer.java
More file actions
148 lines (128 loc) · 5.63 KB
/
ScrollContainer.java
File metadata and controls
148 lines (128 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package top.fpsmaster.ui.click.component;
import lombok.Getter;
import lombok.Setter;
import top.fpsmaster.utils.math.anim.AnimClock;
import top.fpsmaster.utils.math.anim.Animator;
import top.fpsmaster.utils.math.anim.Easings;
import top.fpsmaster.utils.render.draw.Hover;
import top.fpsmaster.utils.render.draw.Rects;
import top.fpsmaster.utils.render.gui.ScaledGuiScreen;
import java.awt.*;
public class ScrollContainer {
private static final float WHEEL_STEP = 50f;
private static final float MAX_OVERSCROLL = 45f;
private static final float OVERSCROLL_RESISTANCE = 0.38f;
private static final long SNAP_BACK_DELAY_NS = 50_000_000L;
private static final float TRACK_MIN_HEIGHT = 18f;
private static final float TRACK_SHRINK_FACTOR = 0.45f;
private float wheel = 0f;
private float wheelAnim = 0f;
@Getter
@Setter
private float height = 0f;
private final Animator wheelAnimator = new Animator();
private final AnimClock animClock = new AnimClock();
private float lastTarget = Float.NaN;
private double scrollExpand = 0.0;
private float scrollStart = 0f;
private boolean isScrolling = false;
private final String captureId = getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this));
private long wheelDelay = 0L;
public void draw(ScaledGuiScreen screen, float x, float y, float width, float height, int mouseX, int mouseY, Runnable runnable) {
double dt = animClock.tick();
runnable.run();
float maxUp = Math.max(0f, this.height - height);
float minScroll = -maxUp;
if (this.height > height) {
float percent = height / this.height;
float baseHeight = Math.max(TRACK_MIN_HEIGHT, percent * height);
float visibleScroll = clamp(wheel, minScroll, 0f);
float scrollPercent = maxUp <= 0f ? 0f : visibleScroll / maxUp;
float trackHeight = baseHeight;
float trackY = y - scrollPercent * (height - baseHeight);
float overscrollTop = Math.max(0f, wheel);
float overscrollBottom = Math.max(0f, minScroll - wheel);
if (overscrollTop > 0f) {
trackHeight = shrinkTrack(baseHeight, overscrollTop);
trackY = y;
} else if (overscrollBottom > 0f) {
trackHeight = shrinkTrack(baseHeight, overscrollBottom);
trackY = y + height - trackHeight;
}
float trackX = x + width + 1 - (float) scrollExpand;
Rects.rounded(
Math.round(trackX),
Math.round(trackY),
Math.round(1f + (float) scrollExpand),
Math.round(trackHeight),
1,
new Color(255, 255, 255, 100).getRGB()
);
if (Hover.is(trackX - 1, trackY, 2f + (float) scrollExpand, trackHeight, mouseX, mouseY)) {
scrollExpand = 1.0;
if (screen.beginPointerCapture(captureId, 0, trackX - 1, trackY, 2f + (float) scrollExpand, trackHeight)) {
isScrolling = true;
scrollStart = mouseY - trackY;
}
} else if (!isScrolling) {
scrollExpand = 0.0;
}
if (isScrolling) {
if (screen.isPointerCapturedBy(captureId, 0)) {
float dragScroll = -((mouseY - scrollStart - y) / height) * this.height;
wheelAnim = applyOverscrollResistance(dragScroll, minScroll, 0f);
wheelDelay = System.nanoTime();
} else {
isScrolling = false;
screen.releasePointerCapture(captureId);
}
}
} else {
wheelAnim = 0f;
}
if (Hover.is(x, y, width, height, mouseX, mouseY) && this.height > height) {
int mouseDWheel = screen.consumeWheelDelta(x, y, width, height);
if (mouseDWheel != 0) {
wheelDelay = System.nanoTime();
if (mouseDWheel > 0) {
wheelAnim = applyOverscrollResistance(wheelAnim + WHEEL_STEP, minScroll, 0f);
} else {
wheelAnim = applyOverscrollResistance(wheelAnim - WHEEL_STEP, minScroll, 0f);
}
}
}
if (Float.isNaN(lastTarget) || wheelAnim != lastTarget) {
wheelAnimator.animateTo(wheelAnim, 0.12f, Easings.CUBIC_OUT);
lastTarget = wheelAnim;
} else if (System.nanoTime() - wheelDelay > SNAP_BACK_DELAY_NS) {
float bounded = clamp(wheelAnim, minScroll, 0f);
if (bounded != wheelAnim) {
wheelAnim = bounded;
}
}
wheelAnimator.update(dt);
wheel = (float) wheelAnimator.get();
}
public int getScroll() {
return (int) wheel;
}
public float getRealScroll() {
return wheelAnim;
}
private float applyOverscrollResistance(float value, float min, float max) {
if (value > max) {
return Math.min(max + MAX_OVERSCROLL, max + (value - max) * OVERSCROLL_RESISTANCE);
}
if (value < min) {
return Math.max(min - MAX_OVERSCROLL, min + (value - min) * OVERSCROLL_RESISTANCE);
}
return value;
}
private float shrinkTrack(float baseHeight, float overscroll) {
float shrink = Math.min(baseHeight - TRACK_MIN_HEIGHT, overscroll * TRACK_SHRINK_FACTOR);
return Math.max(TRACK_MIN_HEIGHT, baseHeight - shrink);
}
private float clamp(float value, float min, float max) {
return Math.max(min, Math.min(max, value));
}
}