Repository navigation
Expand file tree
/
Copy pathframes.lua
More file actions
222 lines (187 loc) · 6.71 KB
/
Copy pathframes.lua
File metadata and controls
222 lines (187 loc) · 6.71 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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
--[[--------------------------------------------------------------------------
Clickcast - frames.lua
Finds unit frames to hook: the default Blizzard frames, the Blizzard raid UI,
and - when auto-detection is on - any other frame in the UI hierarchy that
resolves to a valid unit (pfUI, HoryUI, Turtle group frames, ...).
----------------------------------------------------------------------------]]
local CC = Clickcast
-- default Blizzard unit frames, name -> unit
local blizzard_frames = {
{ "PlayerFrame", "player" },
{ "PetFrame", "pet" },
{ "TargetFrame", "target" },
{ "TargetofTargetFrame", "targettarget" },
}
for i = 1, 4 do
table.insert(blizzard_frames, { "PartyMemberFrame" .. i, "party" .. i })
table.insert(blizzard_frames, { "PartyMemberFrame" .. i .. "PetFrame", "partypet" .. i })
end
-- frames that must never be hooked, matched against the frame name
local excluded = {
"Nameplate",
"^pfNameplate",
"DropDown",
"^ClickcastConfig",
}
local function IsExcluded(frame)
if not frame.GetName then return nil end
local name = frame:GetName()
if not name then return nil end
for i = 1, table.getn(excluded) do
if string.find(name, excluded[i]) then return true end
end
return nil
end
-- ---------------------------------------------------------------------------
-- explicit hooks
-- ---------------------------------------------------------------------------
function CC:HookBlizzardFrames()
for i = 1, table.getn(blizzard_frames) do
local frame = getglobal(blizzard_frames[i][1])
if frame then CC:Register(frame, blizzard_frames[i][2]) end
end
end
-- The Blizzard raid UI buttons carry no usable unit id, so they are hooked by
-- name and resolved from the displayed player name at click time.
function CC:HookBlizzardRaidFrames()
for i = 1, 40 do
local button = getglobal("RaidGroupButton" .. i)
if button then CC:Register(button) end
end
for pullout = 1, 8 do
for i = 1, 40 do
local button = getglobal("RaidPullout" .. pullout .. "Button" .. i)
if button then CC:Register(button) end
end
end
end
-- ---------------------------------------------------------------------------
-- auto-detection
-- ---------------------------------------------------------------------------
local MAX_DEPTH = 4
local function ScanChildren(parent, depth)
if depth > MAX_DEPTH then return end
if not parent.GetChildren then return end
local children = { parent:GetChildren() }
for i = 1, table.getn(children) do
local frame = children[i]
if frame and not CC.hooked[frame] and not IsExcluded(frame) then
if frame.RegisterForClicks and CC:GetUnit(frame) then
CC:Register(frame)
end
end
if frame then ScanChildren(frame, depth + 1) end
end
end
local lastscan = 0
function CC:ScanFrames(force)
if not CC.db then return end
-- roster events arrive in bursts; one scan per second is plenty
if not force and GetTime() - lastscan < 1 then
CC:ScheduleScan(1)
return
end
lastscan = GetTime()
CC:HookBlizzardFrames()
CC:HookBlizzardRaidFrames()
-- pick up anything registered the Clique way
if type(ClickCastFrames) == "table" then
for frame, value in pairs(ClickCastFrames) do
if value then CC:Register(frame) end
end
end
-- keep pfUI from re-arming its own click casting after a config reload
if CC.db.takeover_pfui == "1" and pfUI and pfUI.uf then
for frame in pairs(CC.hooked) do
if frame.clickactions then frame.clickactions = nil end
end
end
if CC.db.autodetect == "1" or force then
ScanChildren(UIParent, 1)
end
end
-- ---------------------------------------------------------------------------
-- scheduling: a throttled rescan, so frames created later still get picked up
-- ---------------------------------------------------------------------------
local scheduler = CreateFrame("Frame", nil, UIParent)
local pending = {}
local pending_count = 0
function CC:ScheduleScan(delay)
pending_count = pending_count + 1
pending[pending_count] = GetTime() + (delay or 0.5)
end
scheduler:SetScript("OnUpdate", function()
if pending_count == 0 then return end
local now = GetTime()
local due = nil
local remaining = {}
local count = 0
for i = 1, pending_count do
if pending[i] <= now then
due = true
else
count = count + 1
remaining[count] = pending[i]
end
end
pending = remaining
pending_count = count
if due then CC:ScanFrames() end
end)
-- ---------------------------------------------------------------------------
-- events
-- ---------------------------------------------------------------------------
local events = CreateFrame("Frame", nil, UIParent)
events:RegisterEvent("ADDON_LOADED")
events:RegisterEvent("VARIABLES_LOADED")
events:RegisterEvent("PLAYER_ENTERING_WORLD")
events:RegisterEvent("PLAYER_LOGIN")
events:RegisterEvent("PARTY_MEMBERS_CHANGED")
events:RegisterEvent("RAID_ROSTER_UPDATE")
events:RegisterEvent("UNIT_PET")
events:SetScript("OnEvent", function()
-- Saved variables are in place by the time our own ADDON_LOADED arrives.
-- The folder may have been renamed (a GitHub zip unpacks as "Clickcast-main"),
-- so a populated ClickcastDB counts as proof our variables have landed too.
if event == "ADDON_LOADED" then
if not CC.db and (arg1 == "Clickcast" or type(ClickcastDB) == "table") then
CC:LoadConfig()
end
if arg1 == "Blizzard_RaidUI" then CC:ScheduleScan(0.5) end
return
end
if not CC.db then CC:LoadConfig() end
if event == "VARIABLES_LOADED" then
CC:ScheduleScan(0.5)
return
end
if event == "PLAYER_LOGIN" then
CC:ScheduleScan(0.5)
return
end
if event == "PLAYER_ENTERING_WORLD" then
-- unit frame addons build their frames on this event too, so scan a few
-- times over the first seconds to be sure we see all of them
CC:ScheduleScan(0.5)
CC:ScheduleScan(3)
CC:ScheduleScan(8)
if not CC.welcomed then
CC.welcomed = true
CC:Print("v" .. CC.version .. " loaded."
.. (CC:HasSuperWoW() and " |cff33ff99SuperWoW detected.|r" or ""))
-- Settings are per character and every slot starts empty, so a fresh
-- install does nothing at all until something is bound. Say so plainly
-- rather than letting it look broken.
if CC:CountBindings() == 0 then
DEFAULT_CHAT_FRAME:AddMessage(" |cffffaa55Nothing is bound yet.|r Type "
.. "|cffffff88/cc|r, pick a mouse button, and enter a spell name.")
else
DEFAULT_CHAT_FRAME:AddMessage(" " .. CC:CountBindings()
.. " click action(s) bound. |cffffff88/cc status|r for details.")
end
end
return
end
-- roster changes can create new frames (raid subgroups, party pets, ...)
CC:ScheduleScan(1)
end)