Mercurial > wow > skeletonkey
comparison LibKraken/LibKraken-1.0.lua @ 5:9ac29fe77455
- dynamic profession spell mapping
- dynamic talent spell mapping
- protection of dynamic slots that aren't in use
- plugin abstractors for accessing state data
- a lot of fixes related to the 7.0.3 API
author | Nenue |
---|---|
date | Tue, 26 Jul 2016 19:29:44 -0400 |
parents | |
children | a2fc77fa4c73 |
comparison
equal
deleted
inserted
replaced
4:a30285f8191e | 5:9ac29fe77455 |
---|---|
1 --[[ | |
2 -- KrakynTools | |
3 -- AddOn prototyping library. | |
4 -- | |
5 -- Implements | |
6 -- KT.register(frame) to hook the following (all optional): | |
7 -- frame:init() run immediately after KT sets itself up | |
8 -- frame:profile("Name-TruncatedRealm") called the first time SavedVars data becomes available | |
9 -- frame:variables() called upon variables being available | |
10 -- frame:event(event, ...) replaces the event callback | |
11 -- frame:ui() called by /ui when activating | |
12 -- | |
13 -- frame:tab(name, tooltip, texture, coord) | |
14 -- produces a serial button that changes display tabs | |
15 -- | |
16 -- frame:button(name, text, tooltip, onClick) | |
17 -- produces a button with OnClick script | |
18 -- | |
19 -- frame:uibutton(name, text, tooltip, onClick, texture, coord) | |
20 -- produces a header button with desired onClick | |
21 -- | |
22 ]]-- | |
23 | |
24 local LIBKT_MAJOR, LIBKT_MINOR = "LibKraken", 1 | |
25 local KT = LibStub:NewLibrary(LIBKT_MAJOR, LIBKT_MINOR) | |
26 | |
27 --GLOBALS: LibKT, KrakTool, KTErrorFrame, LibKTError, SlashCmdList, SLASH_RL1, SLASH_UI1 | |
28 local CreateFrame, debugstack, tostring, select = CreateFrame, debugstack, tostring, select | |
29 local print, max, unpack, tinsert = print, max, unpack, tinsert | |
30 local ipairs, xpcall, next, safecall = ipairs, xpcall, next, safecall | |
31 local UI_TOGGLE = false | |
32 local db | |
33 | |
34 | |
35 KT.handler = CreateFrame('Frame', 'LibKTHostFrame', UIParent) | |
36 KT.addons = {} | |
37 KT.initStack = {} | |
38 KT.varsStack = {} | |
39 local print = DEVIAN_WORKSPACE and function(...) print('LKT', ...) end or function() end | |
40 local registeredHandles = {} | |
41 | |
42 --- /rl | |
43 -- ReloadUI shortcut | |
44 SLASH_RL1 = "/rl" | |
45 SlashCmdList.RL = function () | |
46 ReloadUI() | |
47 end | |
48 | |
49 --- /kv addon ... | |
50 -- Dumps table values from "addon", using the arguments as index values. | |
51 -- Numerics are converted, and names that end with "()" will be called as such | |
52 SLASH_KV1 = "/kv" | |
53 SlashCmdList.KV = function (editbox, input) | |
54 | |
55 end | |
56 | |
57 | |
58 --- /ui | |
59 -- Run any addon:ui() methods | |
60 SLASH_UI1 = "/ui" | |
61 SlashCmdList.UI = function () | |
62 if UI_TOGGLE then | |
63 UI_TOGGLE = false | |
64 else | |
65 UI_TOGGLE = true | |
66 end | |
67 for i, frame in pairs(KT.frames) do | |
68 if UI_TOGGLE then | |
69 if frame.close then | |
70 frame.close() | |
71 else | |
72 frame:Hide() | |
73 end | |
74 else | |
75 if frame.ui then | |
76 frame.ui() | |
77 end | |
78 frame:Show() | |
79 end | |
80 end | |
81 end | |
82 | |
83 LibKTError = function(msg) | |
84 local dstack = debugstack(2) | |
85 :gsub("Interface\\AddOns\\",'') | |
86 :gsub("<(.-)>", function(a) return '|cFF00FFFF<'.. a ..'>|r' end) | |
87 | |
88 | |
89 | |
90 KTErrorFrame.errmsg:SetText(msg) | |
91 KTErrorFrame.debugstack:SetText(dstack) | |
92 KTErrorFrame:SetHeight(KTErrorFrame.debugstack:GetStringHeight() + KTErrorFrame.errmsg:GetStringHeight() + 12) | |
93 KTErrorFrame:Show() | |
94 end | |
95 | |
96 | |
97 local pending = {} | |
98 local processing = false | |
99 local isHandled = false | |
100 local nodebug = false | |
101 function KT.OnEvent (addon, event, ...) | |
102 if processing then | |
103 local args = {...} | |
104 C_Timer.After(0, function() KT.OnEvent(addon, event, unpack(args)) end) | |
105 return | |
106 else | |
107 | |
108 end | |
109 --- reset state | |
110 processing = true | |
111 isHandled = false | |
112 nodebug = false | |
113 | |
114 | |
115 if addon.event then | |
116 nodebug = addon.event(addon, event, ...) | |
117 end | |
118 | |
119 if addon[event] then | |
120 nodebug = addon[event](addon, event, ...) or nodebug | |
121 addon.missed = 0 | |
122 addon.handled = addon.handled + 1 | |
123 isHandled = true | |
124 else | |
125 addon.firstEvent = false | |
126 addon.unhandled = addon.unhandled + 1 | |
127 addon.missed = addon.missed + 1 | |
128 end | |
129 | |
130 for i, module in ipairs(addon.modules) do | |
131 --print(i, module) | |
132 if module[event] then | |
133 nodebug = module[event](addon, event, ...) or nodebug | |
134 addon.missed = 0 | |
135 addon.handled = addon.handled + 1 | |
136 isHandled = true | |
137 else | |
138 addon.firstEvent = false | |
139 addon.unhandled = addon.unhandled + 1 | |
140 addon.missed = addon.missed + 1 | |
141 end | |
142 | |
143 end | |
144 if nodebug then | |
145 processing = false | |
146 return | |
147 else | |
148 KT.UpdateEventStatus(addon, event, ...) | |
149 processing = false | |
150 end | |
151 | |
152 end | |
153 | |
154 KT.UpdateEventStatus = function(addon, event, ...) | |
155 print(addon:GetName(), event, ...) | |
156 | |
157 -- debug outputs | |
158 if addon.status then | |
159 addon.status:SetText(event .. '\n|cFF00FF00' .. addon.handled .. '|r |cFFFF8800' .. addon.missed .. '|r |cFFFF4400' .. addon.unhandled .. '|r') | |
160 if isHandled then | |
161 addon.status:SetTextColor(0,1,0) | |
162 if addon.log then | |
163 local logtext = event | |
164 for i = 1, select('#',...) do | |
165 logtext = logtext .. '\n' .. i .. ':' .. tostring(select(i,...)) | |
166 end | |
167 addon.log:SetText('|cFFFFFF00last|r\n' .. logtext) | |
168 local newWidth = addon.log:GetStringWidth() | |
169 | |
170 if addon.logfirst then | |
171 if not addon.firstEvent then | |
172 addon.firstEvent = event | |
173 addon.logfirst:SetText('|cFF00FF88first|r\n' .. logtext) | |
174 end | |
175 | |
176 newWidth = newWidth + addon.logfirst:GetStringWidth() | |
177 end | |
178 if addon.logdiff then | |
179 if not event ~= addon.firstEvent then | |
180 addon.firstEvent = event | |
181 addon.logdiff:SetText('|cFF0088FFdiff|r\n' .. logtext) | |
182 end | |
183 newWidth = newWidth + addon.logdiff:GetStringWidth() | |
184 end | |
185 --addon:SetWidth(newWidth) | |
186 end | |
187 else | |
188 addon.status:SetTextColor(1,0,0) | |
189 end | |
190 end | |
191 end | |
192 | |
193 KT.register = function(addon, name, noGUI) | |
194 if registeredHandles[addon] then | |
195 name = name or debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "") | |
196 else | |
197 if not name then | |
198 assert(type(addon) == 'table', 'Need a valid table.') | |
199 if addon.GetName then | |
200 name = addon:GetName() | |
201 else | |
202 name = debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "") | |
203 end | |
204 assert(type(name) == 'string', 'Unable to resolve a valid stub name.') | |
205 end | |
206 -- if calling again, assume name is a file handle | |
207 | |
208 registeredHandles[addon] = name | |
209 KT.addons[name] = addon | |
210 if addon.SetScript then | |
211 addon:SetScript('OnEvent', KT.OnEvent) | |
212 end | |
213 addon.unhandled = 0 | |
214 addon.missed = 0 | |
215 addon.handled = 0 | |
216 addon.firstEvent = false | |
217 addon.modules = {} | |
218 tinsert(KT.initStack, addon) | |
219 tinsert(KT.varsStack, addon) | |
220 | |
221 if addon.GetName and (not noGUI) then | |
222 addon.UIPanelAnchor = {'TOPLEFT', addon, 'TOPLEFT', 12, -12 } | |
223 addon.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0} | |
224 addon.button = KT.button | |
225 addon.uibutton = KT.uibutton | |
226 addon.tab = KT.tab | |
227 addon.print = KT.print | |
228 end | |
229 end | |
230 | |
231 return addon, (DEVIAN_WORKSPACE and function(...) _G.print(name, ...) end or function() end) | |
232 end | |
233 | |
234 | |
235 | |
236 local onEvent = function(self, event, arg1) | |
237 if (event == 'ADDON_LOADED' and arg1 ~= 'Blizzard_DebugTools') or event == 'PLAYER_LOGIN' then | |
238 -- run any init blocks left in the queue | |
239 while #KT.initStack >= 1 do | |
240 local addon = tremove(KT.initStack, 1) | |
241 print('KT', addon:GetName(), 'init') | |
242 if addon.init then | |
243 xpcall(addon.init, LibKTError) | |
244 for i, module in ipairs(addon.modules) do | |
245 if module.init then | |
246 xpcall(module.init, LibKTError) | |
247 end | |
248 end | |
249 end | |
250 end | |
251 | |
252 -- run any variables blocks if player variables are ready | |
253 if IsLoggedIn() and #KT.varsStack >= 1 then | |
254 while #KT.varsStack >= 1 do | |
255 local addon = tremove(KT.varsStack, 1) | |
256 print(addon:GetName()) | |
257 if addon.variables then | |
258 xpcall(addon.variables, LibKTError) | |
259 for i, module in ipairs(addon.modules) do | |
260 if module.variables then | |
261 xpcall(module.variables, LibKTError) | |
262 end | |
263 end | |
264 end | |
265 end | |
266 end | |
267 end | |
268 end | |
269 | |
270 KT.print = function(module, ...) | |
271 local msg = '|cFF00FFFF'..module:GetName()..'|r:' | |
272 for i = 1, select('#', ...) do | |
273 msg = msg .. ' ' .. tostring(select(i, ...)) | |
274 end | |
275 DEFAULT_CHAT_FRAME:AddMessage(msg) | |
276 end | |
277 | |
278 --- Button generators | |
279 | |
280 local GetButtonTemplate = function(name, parent, template, onClick) | |
281 if _G[name] then | |
282 return _G[name] | |
283 end | |
284 | |
285 local button = CreateFrame('Button', name, parent, template) | |
286 button:RegisterForClicks('AnyUp') | |
287 button:SetScript('OnClick', onClick) | |
288 return button | |
289 end | |
290 | |
291 local SetButtonAnchor = function(self, collector, anchor, growth) | |
292 if self:GetID() == 0 then | |
293 self:SetID(#collector) | |
294 print('registered TabButton #', self:GetID()) | |
295 end | |
296 | |
297 if self:GetID() == 1 then | |
298 self:SetPoint(unpack(anchor)) | |
299 else | |
300 growth[2] = collector[self:GetID()-1] | |
301 self:SetPoint(unpack(growth)) | |
302 end | |
303 end | |
304 | |
305 KT.tab = function(self, name, tooltip, texture, coords) | |
306 local button = GetButtonTemplate(name, self, 'KTTabButton', self.SelectTab) | |
307 button.icon:SetTexture(texture) | |
308 button.tooltip = tooltip | |
309 button:SetSize(unpack(self.tabSize)) | |
310 if coords then | |
311 button.icon:SetTexCoord(unpack(coords)) | |
312 end | |
313 SetButtonAnchor(button, self.tabButtons, self.tabAnchor, self.tabGrowth) | |
314 return button | |
315 end | |
316 | |
317 KT.button = function(self, name, text, tooltip, onClick) | |
318 local button = GetButtonTemplate(name, self, 'KTButton', onClick) | |
319 | |
320 button.tooltip = tooltip | |
321 button:SetText(text) | |
322 button:SetWidth(max(button:GetWidth(), button:GetFontString():GetStringWidth() + 12)) | |
323 | |
324 SetButtonAnchor(button, self.controls, self.controlsAnchor, self.controlsGrowth) | |
325 return button | |
326 end | |
327 | |
328 KT.uibutton = function(self, name, text, tooltip, onClick, texture, coords) | |
329 local button = GetButtonTemplate(name, self, 'KTUIPanelButton', onClick) | |
330 | |
331 button.tooltip = tooltip | |
332 button:SetText(text) | |
333 | |
334 if self.UIPanelIcon then | |
335 local w, h, anchor, x, y = unpack(self.UIPanelIcon) | |
336 button.icon:SetTexture(texture) | |
337 button.icon:SetSize(w, h) | |
338 button.icon:ClearAllPoints() | |
339 button.icon:SetPoint(anchor, button, anchor, x, y) | |
340 end | |
341 | |
342 if not self.UIPanelSize then | |
343 button:SetWidth(button:GetFontString():GetStringWidth() + button.icon:GetWidth()/1.5) | |
344 else | |
345 button:SetSize(unpack(self.UIPanelSize)) | |
346 end | |
347 if coords then | |
348 button.icon:SetTexCoord(unpack(coords)) | |
349 end | |
350 SetButtonAnchor(button, self.UIPanels, self.UIPanelAnchor, self.UIPanelGrowth) | |
351 return button | |
352 end | |
353 | |
354 | |
355 KT.handler:RegisterEvent('ADDON_LOADED') | |
356 KT.handler:RegisterEvent('PLAYER_LOGIN') | |
357 KT.handler:SetScript('OnEvent', onEvent) |