1
+ assert (LibStub , " LibStub not found." );
2
+
3
+ --- @alias LibFleeingButton-1.0 LibFleeingButton
4
+ local major , minor = " LibFleeingButton-1.0" , 1 ;
5
+
6
+ --- @class LibFleeingButton
7
+ local LibFleeingButton = LibStub :NewLibrary (major , minor );
8
+
9
+ if not LibFleeingButton then
10
+ return ;
11
+ end
12
+
13
+ local NUM_CURSOR_SAMPLES = 5 ;
14
+ local FLEEING_BUTTONS = {};
15
+
16
+ -- stolen from TRP3
17
+ local function Debounce (timeout , callback )
18
+ local calls = 0 ;
19
+
20
+ local function Decrement ()
21
+ calls = calls - 1 ;
22
+
23
+ if calls == 0 then
24
+ callback ();
25
+ end
26
+ end
27
+
28
+ return function ()
29
+ C_Timer .After (timeout , Decrement );
30
+ calls = calls + 1 ;
31
+ end
32
+ end
33
+
34
+ local function ShouldMoveButton (button )
35
+ if InCombatLockdown () then
36
+ return false ;
37
+ end
38
+
39
+ if not FLEEING_BUTTONS [button ] then
40
+ return false ;
41
+ end
42
+
43
+ if FLEEING_BUTTONS [button ].Disabled then
44
+ return false ;
45
+ end
46
+
47
+ return true ;
48
+ end
49
+
50
+ local function HandleOnUpdate (button , deltaTime )
51
+ if not ShouldMoveButton (button ) then
52
+ return ;
53
+ end
54
+
55
+ local data = FLEEING_BUTTONS [button ];
56
+ if not data then
57
+ return ;
58
+ end
59
+
60
+ local cursorX , cursorY = GetScaledCursorPosition ();
61
+ data .CursorSamples :PushFront ({
62
+ x = cursorX ,
63
+ y = cursorY ,
64
+ });
65
+
66
+ local numSamples = data .CursorSamples :GetNumElements ();
67
+
68
+ local sumX = 0 ;
69
+ local sumY = 0 ;
70
+ for _ , element in data .CursorSamples :EnumerateIndexedEntries () do
71
+ sumX = sumX + element .x ;
72
+ sumY = sumY + element .y ;
73
+ end
74
+ local avgX = sumX / numSamples ;
75
+ local avgY = sumY / numSamples ;
76
+
77
+ local buttonX , buttonY = button :GetCenter ();
78
+
79
+ local distX , distY = buttonX - avgX , buttonY - avgY ;
80
+ local totalDistanceSquared = distX ^ 2 + distY ^ 2 ;
81
+ if totalDistanceSquared < 0.1 then
82
+ totalDistanceSquared = 0.1 ;
83
+ end
84
+
85
+ local totalDistance = sqrt (totalDistanceSquared );
86
+
87
+ local force = 1000000000 / totalDistanceSquared ;
88
+ local offset = force * deltaTime ^ 2 ;
89
+ if offset > 10 then
90
+ offset = 10 ;
91
+ end
92
+
93
+ if totalDistance > 200 then
94
+ return ;
95
+ end
96
+
97
+ local offsetX = offset * (distX / totalDistance );
98
+ local offsetY = offset * (distY / totalDistance );
99
+
100
+ button :AdjustPointsOffset (offsetX , offsetY );
101
+ end
102
+
103
+ ---- --------
104
+
105
+ function LibFleeingButton .MakeButtonFlee (button )
106
+ if not FLEEING_BUTTONS [button ] then
107
+ button :HookScript (" OnUpdate" , HandleOnUpdate );
108
+ button :SetClampedToScreen (true );
109
+
110
+ FLEEING_BUTTONS [button ] = {
111
+ CursorSamples = CreateCircularBuffer (NUM_CURSOR_SAMPLES ),
112
+ Disabled = false ,
113
+ };
114
+ end
115
+ end
116
+
117
+ function LibFleeingButton .PauseButtonFleeing (button )
118
+ if FLEEING_BUTTONS [button ] then
119
+ FLEEING_BUTTONS [button ].Disabled = true ;
120
+ end
121
+ end
122
+
123
+ function LibFleeingButton .ResumeButtonFleeing (button )
124
+ if FLEEING_BUTTONS [button ] then
125
+ FLEEING_BUTTONS [button ].Disabled = false ;
126
+ end
127
+ end
128
+
129
+ function LibFleeingButton .ResetButton (button )
130
+ FLEEING_BUTTONS [button ] = nil ;
131
+ button :ClearPointsOffset ();
132
+ end
0 commit comments