annotate LibKraken/LibKraken-1.0.lua @ 7:a2fc77fa4c73

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