Skip to content

Commit 2cd0ed8

Browse files
Release v3.5.2
1 parent 3859155 commit 2cd0ed8

14 files changed

Lines changed: 3998 additions & 13 deletions

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Libraries are pulled by the packager via .pkgmeta externals
2-
Libs/
32
EllesmereUIUnitFrames/Libs/
43

54
# Kiro workspace files

.pkgmeta

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@ externals:
1313
EllesmereUIUnitFrames/Libs/oUF:
1414
url: https://github.com/oUF-wow/oUF
1515
tag: latest
16-
EllesmereUI/Libs/LibStub:
17-
url: https://repos.wowace.com/wow/libstub/trunk
18-
type: svn
19-
EllesmereUI/Libs/CallbackHandler-1.0:
20-
url: https://repos.wowace.com/wow/callbackhandler/trunk/CallbackHandler-1.0
21-
type: svn
22-
EllesmereUI/Libs/LibDeflate:
23-
url: https://github.com/SafeteeWoW/LibDeflate
24-
tag: latest
2516

2617
enable-nolib-creation: no
2718

EllesmereUI.toc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99
## X-Wago-ID: ZKbxbRN1
1010

1111
# Libraries
12-
Libs\LibStub\LibStub.lua
13-
Libs\CallbackHandler-1.0\CallbackHandler-1.0.lua
14-
Libs\LibDeflate\LibDeflate.lua
12+
Libs\LibDeflate.lua
1513

1614
# Lightweight addon framework (replaces Ace3)
1715
EllesmereUI_Lite.lua
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
--[[ $Id: CallbackHandler-1.0.lua 26 2022-12-12 15:09:39Z nevcairiel $ ]]
2+
local MAJOR, MINOR = "CallbackHandler-1.0", 8
3+
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
4+
5+
if not CallbackHandler then return end -- No upgrade needed
6+
7+
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
8+
9+
-- Lua APIs
10+
local securecallfunction, error = securecallfunction, error
11+
local setmetatable, rawget = setmetatable, rawget
12+
local next, select, pairs, type, tostring = next, select, pairs, type, tostring
13+
14+
15+
local function Dispatch(handlers, ...)
16+
local index, method = next(handlers)
17+
if not method then return end
18+
repeat
19+
securecallfunction(method, ...)
20+
index, method = next(handlers, index)
21+
until not method
22+
end
23+
24+
--------------------------------------------------------------------------
25+
-- CallbackHandler:New
26+
--
27+
-- target - target object to embed public APIs in
28+
-- RegisterName - name of the callback registration API, default "RegisterCallback"
29+
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
30+
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
31+
32+
function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName)
33+
34+
RegisterName = RegisterName or "RegisterCallback"
35+
UnregisterName = UnregisterName or "UnregisterCallback"
36+
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
37+
UnregisterAllName = "UnregisterAllCallbacks"
38+
end
39+
40+
-- we declare all objects and exported APIs inside this closure to quickly gain access
41+
-- to e.g. function names, the "target" parameter, etc
42+
43+
44+
-- Create the registry object
45+
local events = setmetatable({}, meta)
46+
local registry = { recurse=0, events=events }
47+
48+
-- registry:Fire() - fires the given event/message into the registry
49+
function registry:Fire(eventname, ...)
50+
if not rawget(events, eventname) or not next(events[eventname]) then return end
51+
local oldrecurse = registry.recurse
52+
registry.recurse = oldrecurse + 1
53+
54+
Dispatch(events[eventname], eventname, ...)
55+
56+
registry.recurse = oldrecurse
57+
58+
if registry.insertQueue and oldrecurse==0 then
59+
-- Something in one of our callbacks wanted to register more callbacks; they got queued
60+
for event,callbacks in pairs(registry.insertQueue) do
61+
local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten.
62+
for object,func in pairs(callbacks) do
63+
events[event][object] = func
64+
-- fire OnUsed callback?
65+
if first and registry.OnUsed then
66+
registry.OnUsed(registry, target, event)
67+
first = nil
68+
end
69+
end
70+
end
71+
registry.insertQueue = nil
72+
end
73+
end
74+
75+
-- Registration of a callback, handles:
76+
-- self["method"], leads to self["method"](self, ...)
77+
-- self with function ref, leads to functionref(...)
78+
-- "addonId" (instead of self) with function ref, leads to functionref(...)
79+
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
80+
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
81+
if type(eventname) ~= "string" then
82+
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
83+
end
84+
85+
method = method or eventname
86+
87+
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
88+
89+
if type(method) ~= "string" and type(method) ~= "function" then
90+
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
91+
end
92+
93+
local regfunc
94+
95+
if type(method) == "string" then
96+
-- self["method"] calling style
97+
if type(self) ~= "table" then
98+
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
99+
elseif self==target then
100+
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
101+
elseif type(self[method]) ~= "function" then
102+
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
103+
end
104+
105+
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
106+
local arg=select(1,...)
107+
regfunc = function(...) self[method](self,arg,...) end
108+
else
109+
regfunc = function(...) self[method](self,...) end
110+
end
111+
else
112+
-- function ref with self=object or self="addonId" or self=thread
113+
if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
114+
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
115+
end
116+
117+
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
118+
local arg=select(1,...)
119+
regfunc = function(...) method(arg,...) end
120+
else
121+
regfunc = method
122+
end
123+
end
124+
125+
126+
if events[eventname][self] or registry.recurse<1 then
127+
-- if registry.recurse<1 then
128+
-- we're overwriting an existing entry, or not currently recursing. just set it.
129+
events[eventname][self] = regfunc
130+
-- fire OnUsed callback?
131+
if registry.OnUsed and first then
132+
registry.OnUsed(registry, target, eventname)
133+
end
134+
else
135+
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
136+
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
137+
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
138+
registry.insertQueue[eventname][self] = regfunc
139+
end
140+
end
141+
142+
-- Unregister a callback
143+
target[UnregisterName] = function(self, eventname)
144+
if not self or self==target then
145+
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
146+
end
147+
if type(eventname) ~= "string" then
148+
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
149+
end
150+
if rawget(events, eventname) and events[eventname][self] then
151+
events[eventname][self] = nil
152+
-- Fire OnUnused callback?
153+
if registry.OnUnused and not next(events[eventname]) then
154+
registry.OnUnused(registry, target, eventname)
155+
end
156+
end
157+
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
158+
registry.insertQueue[eventname][self] = nil
159+
end
160+
end
161+
162+
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
163+
if UnregisterAllName then
164+
target[UnregisterAllName] = function(...)
165+
if select("#",...)<1 then
166+
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
167+
end
168+
if select("#",...)==1 and ...==target then
169+
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
170+
end
171+
172+
173+
for i=1,select("#",...) do
174+
local self = select(i,...)
175+
if registry.insertQueue then
176+
for eventname, callbacks in pairs(registry.insertQueue) do
177+
if callbacks[self] then
178+
callbacks[self] = nil
179+
end
180+
end
181+
end
182+
for eventname, callbacks in pairs(events) do
183+
if callbacks[self] then
184+
callbacks[self] = nil
185+
-- Fire OnUnused callback?
186+
if registry.OnUnused and not next(callbacks) then
187+
registry.OnUnused(registry, target, eventname)
188+
end
189+
end
190+
end
191+
end
192+
end
193+
end
194+
195+
return registry
196+
end
197+
198+
199+
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
200+
-- try to upgrade old implicit embeds since the system is selfcontained and
201+
-- relies on closures to work.
202+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
2+
..\FrameXML\UI.xsd">
3+
<Script file="CallbackHandler-1.0.lua"/>
4+
</Ui>

Libs/EllesmereUI_Libs.xml

Whitespace-only changes.

0 commit comments

Comments
 (0)