annotate Init.lua @ 9:2698173edd40

ObjectiveUI & ObjectiveEvents - securehook to API calls for compatibility with addons that work with the objective tracking interface - let the API hooks invoke ObjectiveUI functions when possible - ObjectiveUI framescript handlers should use the corresponding API call if possible, so that addon space can be fully aware of our actions - Sanity check cached data when possible during 'Remove' hooks ObjectiveInfo - Add cheevID to criteria info ObjectiveCore - Index quest tracker blocks by their watch offset, and use that to verify whether the given block frame should be released into pool ObjectiveFrame - Differentiate between visible and non-visible unused buttons, and only release when their quest has been dropped - Reset 'actualBlocks' count during full updates - Reset scroll Position when the wrapper size shrinks
author Nenue
date Fri, 01 Apr 2016 14:54:01 -0400
parents 3397aae1f44d
children 9455693fc290
rev   line source
Nenue@0 1 --- Modulizer framework
Nenue@0 2 -- OnInitialize
Nenue@0 3 -- OnUpdate
Nenue@0 4 -- OnEnable -- run when GetSpecialization() returns true
Nenue@0 5
Nenue@0 6 local ADDON, A = ...
Nenue@0 7 Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent)
Nenue@0 8 local B = Veneer
Nenue@3 9 local wipe, min, max, random, tinsert, tremove = table.wipe, math.min, math.max, math.random, table.insert, table.remove
Nenue@0 10 local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G
Nenue@0 11 local type, tostring, format = type, tostring, string.format
Nenue@0 12 A.frame = B
Nenue@0 13
Nenue@0 14 --- Cache tables
Nenue@0 15 local initOnced
Nenue@0 16 local modules = {}
Nenue@0 17 local queuedModules = {}
Nenue@3 18 local checkForConfig = {}
Nenue@0 19 local moduleStack = {
Nenue@0 20 }
Nenue@0 21
Nenue@0 22 --- Various region categories
Nenue@0 23 B.displays = {}
Nenue@0 24 B.configLayers = {}
Nenue@0 25 B.configLayersRef = {}
Nenue@0 26
Nenue@0 27 --@debug@
Nenue@0 28 --- Generates a print handler pointing to a static channel signature
Nenue@0 29 -- @usage func = B.print(sig)
Nenue@0 30 -- @param sig channel name or number
Nenue@0 31 local printfuncs = {}
Nenue@0 32 B.print = function(pref, ...)
Nenue@0 33 if Devian and Devian.InWorkspace() then
Nenue@0 34 printfuncs[pref] = printfuncs[pref] or function(...) print(pref, ...) end
Nenue@0 35
Nenue@0 36 return printfuncs[pref]
Nenue@0 37 else
Nenue@0 38 return function () end
Nenue@0 39 end
Nenue@0 40 end
Nenue@0 41
Nenue@0 42 local rgb = {}
Nenue@0 43 local getcolor = function()
Nenue@0 44 local n, p = 0, 4
Nenue@0 45 for i = 1, 3 do
Nenue@0 46 rgb[i] = min(random(n,p) * 64, 255)
Nenue@0 47 if rgb[i] == 255 then
Nenue@0 48 p = 4
Nenue@0 49 elseif rgb[i] > 0 then
Nenue@0 50 n = 2
Nenue@0 51 end
Nenue@0 52 end
Nenue@0 53 return unpack(rgb)
Nenue@0 54 end
Nenue@0 55
Nenue@0 56 local color = {}
Nenue@0 57 local fprints = {}
Nenue@0 58 B.fprint = function()
Nenue@0 59 if not (Devian and Devian.InWorkspace()) then
Nenue@0 60 return function() end
Nenue@0 61 end
Nenue@0 62
Nenue@0 63
Nenue@0 64 local sig = debugstack(2,1)
Nenue@0 65 if fprints[sig] then
Nenue@0 66 return fprints[sig]
Nenue@0 67 end
Nenue@0 68
Nenue@0 69 local func = sig:match("%`(%a+)%'")
Nenue@0 70 if not func then
Nenue@0 71 func = sig:match("<(.-)>")
Nenue@0 72 end
Nenue@0 73 func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b end, 1)
Nenue@0 74 func = func:gsub('^.+%\\', '')
Nenue@0 75 if not func then
Nenue@0 76 func = 'noname'
Nenue@0 77 end
Nenue@0 78
Nenue@0 79 local r, g, b = getcolor()
Nenue@0 80 color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func)
Nenue@0 81
Nenue@0 82 --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' )
Nenue@0 83 func = B.print(func)
Nenue@0 84 fprints[sig] = func
Nenue@0 85 return func
Nenue@0 86 end
Nenue@0 87
Nenue@0 88 --@end-debug@
Nenue@0 89 --[=[@non-debug@
Nenue@0 90 B.print = function() end
Nenue@0 91 --@end-non-debug@]=]
Nenue@0 92
Nenue@0 93 -- for the Mikk script
Nenue@0 94 -- GLOBALS: NUM_LE_RAID_BUFF_TYPES
Nenue@0 95 -- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME
Nenue@0 96 -- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING
Nenue@0 97 -- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES
Nenue@0 98 -- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING
Nenue@0 99
Nenue@0 100 local print = B.print('Bfl')
Nenue@0 101
Nenue@0 102 --- Template for making perpendicular traversals of the displays structure; also makes sure the table is there
Nenue@0 103 B.Abstract = function(dest, key, table)
Nenue@0 104 if table then
Nenue@0 105 for _, v in pairs(dest) do
Nenue@0 106 v[key] = {}
Nenue@0 107 end
Nenue@0 108 end
Nenue@0 109 B[key] = setmetatable({}, {
Nenue@0 110 __index = function(t, k)
Nenue@0 111 return dest[k][key]
Nenue@0 112 end,
Nenue@0 113 __newindex = function(_, k, v)
Nenue@0 114 print('abstract write ('..key..'):', k)
Nenue@0 115 dest[k][key] = v
Nenue@0 116 end,
Nenue@0 117 __tostring = function() return 'Abstract:'..key..'' end
Nenue@0 118 })
Nenue@0 119
Nenue@0 120
Nenue@0 121 return B[key]
Nenue@0 122 end
Nenue@0 123
Nenue@0 124
Nenue@0 125 --- localize for speed
Nenue@0 126 local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays
Nenue@0 127
Nenue@0 128 local ModulesCall = function(func)
Nenue@0 129
Nenue@0 130 local n = 0
Nenue@0 131 for i = 1, #moduleStack do
Nenue@0 132 print('calling level '..i)
Nenue@0 133 local stackset = moduleStack[i]
Nenue@0 134
Nenue@0 135 for name, module in pairs(stackset) do
Nenue@0 136 n = n + 1
Nenue@0 137 print(n..' '..name..'.'..func..'()')
Nenue@0 138
Nenue@0 139
Nenue@0 140 if module[func] then
Nenue@0 141 module[func](module)
Nenue@0 142 end
Nenue@0 143 end
Nenue@0 144 end
Nenue@0 145 end
Nenue@0 146
Nenue@0 147
Nenue@0 148 local Enable = function()
Nenue@0 149 end
Nenue@0 150
Nenue@0 151 --- The things that happen repeatedly
Nenue@0 152 local Init = function ()
Nenue@0 153 end
Nenue@0 154
Nenue@0 155
Nenue@0 156 --- Things that happen immediately upon entering world
Nenue@0 157 local InitOnce = function()
Nenue@0 158 print('entering world first time')
Nenue@0 159 local defaults = B.ConfDefaults
Nenue@0 160 print('|cFFFFFF00Veneer|r')
Nenue@0 161 if not VeneerData then
Nenue@0 162 VeneerData = {}
Nenue@0 163 for k,v in pairs(defaults) do
Nenue@0 164 VeneerData[k] = v
Nenue@0 165 end
Nenue@0 166 print('Veneer defaults being used.')
Nenue@0 167 end
Nenue@0 168
Nenue@0 169 B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end})
Nenue@0 170
Nenue@0 171 -- suffix tables
Nenue@0 172 for name, display in pairs(displays) do
Nenue@0 173 display.conf = setmetatable({}, {
Nenue@0 174 __index = function(_, k)
Nenue@0 175 --print('config check '.. name .. k)
Nenue@0 176 return B.Conf[name .. k] or B.Conf['BuffButton' .. k]
Nenue@0 177 end,
Nenue@0 178 __newindex = function(_, k , v)
Nenue@0 179 B.Conf[name..k] = v
Nenue@0 180 end,
Nenue@0 181 })
Nenue@0 182 end
Nenue@0 183
Nenue@0 184 -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up
Nenue@0 185 -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next
Nenue@0 186 -- layer.
Nenue@0 187 local loaded = {}
Nenue@0 188 local stackLevels = #moduleStack
Nenue@0 189 local i = 1
Nenue@0 190 moduleStack[1] = modules
Nenue@0 191 repeat
Nenue@0 192 print('setting init level '.. i)
Nenue@0 193 local queue = moduleStack[i]
Nenue@0 194 for name, module in pairs(queue) do
Nenue@0 195
Nenue@0 196 if queuedModules[name] and #queuedModules[name] > 0 then
Nenue@0 197 local p = #queuedModules[name]
Nenue@0 198 for j = 1, p do
Nenue@0 199 local dep = queuedModules[name][j]
Nenue@0 200
Nenue@0 201 if loaded[dep] then
Nenue@0 202 print( ' ' .. dep .. ' OK')
Nenue@0 203 queuedModules[name][j] = nil
Nenue@0 204 for k = j, p do
Nenue@0 205 print(' shift ' .. (k+1) .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'')
Nenue@0 206 queuedModules[name][k] = queuedModules[name][k+1]
Nenue@0 207 end
Nenue@0 208 end
Nenue@0 209 end
Nenue@0 210
Nenue@0 211 if #queuedModules[name] == 0 then
Nenue@0 212 queuedModules[name] = nil
Nenue@0 213 print(' |cFF00FFFF'.. name ..'|r deps OK')
Nenue@0 214 loaded[name] = true
Nenue@0 215 else
Nenue@0 216
Nenue@0 217 print(' |cFFFF8800' .. name ..'|r pending')
Nenue@0 218 local next = i+1
Nenue@0 219 if not moduleStack[next] then
Nenue@0 220 moduleStack[next] = {}
Nenue@0 221 end
Nenue@0 222 stackLevels = next
Nenue@0 223 moduleStack[next][name] = module
Nenue@0 224 queue[name] = nil
Nenue@0 225 end
Nenue@0 226
Nenue@0 227 else
Nenue@0 228 print(' |cFF00FF00'.. name ..'|r no deps')
Nenue@0 229 loaded[name] = true
Nenue@0 230 end
Nenue@0 231 end
Nenue@0 232 i = i + 1
Nenue@0 233 until i > stackLevels
Nenue@0 234
Nenue@0 235
Nenue@0 236 for level, batch in ipairs(moduleStack) do
Nenue@0 237 print('config level', level)
Nenue@0 238 for name, module in pairs(batch) do
Nenue@0 239 print('integrity check', name)
Nenue@0 240
Nenue@0 241 --[===[@non-debug@
Nenue@0 242 if module.defaults and not VeneerData[name] then
Nenue@0 243 --@end-non-debug@]===]
Nenue@0 244 print('Adding defaults from module ', name)
Nenue@0 245 VeneerData[name] = module.default
Nenue@0 246 --[===[@non-debug@
Nenue@0 247 end
Nenue@0 248 --@end-non-debug@]===]
Nenue@0 249 end
Nenue@0 250 end
Nenue@3 251
Nenue@3 252
Nenue@3 253 if #checkForConfig >= 1 then
Nenue@3 254 local queuedFrame = tremove(checkForConfig)
Nenue@3 255 while queuedFrame do
Nenue@3 256 B.SetConfigLayers(queuedFrame)
Nenue@3 257 B.InitXMLFrame(queuedFrame)
Nenue@3 258 queuedFrame = tremove(checkForConfig)
Nenue@3 259 end
Nenue@3 260 end
Nenue@0 261 -- remove from existing
Nenue@0 262 end
Nenue@0 263
Nenue@0 264 --- Fires an update to all modules
Nenue@0 265 local lastUpdate
Nenue@0 266 function B.UpdateAll(...)
Nenue@0 267 lastUpdate = GetTime()
Nenue@0 268 ModulesCall('OnUpdate', lastUpdate)
Nenue@0 269 end
Nenue@0 270
Nenue@0 271 B:RegisterEvent('PLAYER_ENTERING_WORLD')
Nenue@0 272 B:SetScript('OnEvent', function(self, event)
Nenue@0 273 if event == 'PLAYER_ENTERING_WORLD' then
Nenue@0 274 if not initOnced then
Nenue@0 275 InitOnce()
Nenue@0 276 ModulesCall('OnInitialize')
Nenue@0 277 initOnced = true
Nenue@0 278 C_Timer.After(1, function()
Nenue@0 279 if GetSpecialization() then
Nenue@0 280 print(GetSpecialization(), 'enabling')
Nenue@0 281 ModulesCall('OnEnable')
Nenue@0 282 B:SetScript('OnUpdate', nil)
Nenue@0 283 end
Nenue@0 284
Nenue@0 285 end)
Nenue@0 286 end
Nenue@0 287
Nenue@0 288 end
Nenue@0 289
Nenue@0 290 B.UpdateAll()
Nenue@0 291 end)
Nenue@0 292
Nenue@0 293 --- Modulizer method
Nenue@0 294 --
Nenue@0 295 function B:RegisterModule (name, module, ...)
Nenue@0 296 if modules[name] then
Nenue@0 297 print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]')
Nenue@0 298 return modules[name]
Nenue@0 299 end
Nenue@0 300
Nenue@0 301 print('new module |cFF00BBFF'.. tostring(name) ..'|r')
Nenue@0 302 if module then
Nenue@0 303 if modules[name] then
Nenue@0 304 error("Module table for '"..tostring(name).."' already exists.")
Nenue@0 305 end
Nenue@0 306 else
Nenue@0 307 module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate')
Nenue@0 308 end
Nenue@0 309 modules[name] = module
Nenue@3 310 B[name] = module
Nenue@0 311 if select('#', ...) >= 1 then
Nenue@0 312 local numDeps = select('#', ...)
Nenue@0 313 print(' '..numDeps..' deps detected')
Nenue@0 314 for i = 1, numDeps do
Nenue@0 315 local dep = select(i, ...)
Nenue@0 316 -- means that init/enable funcs are ordered to run after deps do their things
Nenue@0 317 queuedModules[name] = queuedModules[name] or {}
Nenue@0 318 tinsert(queuedModules[name], dep)
Nenue@0 319 print(' needs '..dep)
Nenue@0 320 end
Nenue@0 321 end
Nenue@0 322 return module
Nenue@0 323 end
Nenue@0 324
Nenue@0 325
Nenue@0 326 B.SetConfigLayers = function(frame)
Nenue@0 327 local print = B.fprint()
Nenue@0 328 if not frame.config then
Nenue@0 329 print(frame:GetName(), 'has no config layers')
Nenue@0 330 return
Nenue@0 331 end
Nenue@0 332 print('Registering config layers from', frame:GetName())
Nenue@0 333
Nenue@0 334 for i, subframe in ipairs(frame.config) do
Nenue@0 335 -- make sure there are no duplicates
Nenue@0 336 if not refs[subframe] then
Nenue@0 337 local key = #layers+1
Nenue@0 338 layers[key] = subframe
Nenue@0 339 refs[subframe] = key
Nenue@0 340 end
Nenue@0 341 print(' ', i, subframe:GetName())
Nenue@0 342 end
Nenue@0 343 end
Nenue@0 344
Nenue@0 345 B.RemoveConfigLayers = function(frame)
Nenue@3 346
Nenue@0 347 local print = B.fprint()
Nenue@0 348 print('|cFFFF0000RemoveConfigLayers', frame:GetName())
Nenue@0 349 for i, subframe in pairs(layers) do
Nenue@0 350 if subframe:GetParent() == frame then
Nenue@0 351 print('|cFFFF8800 ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName())
Nenue@0 352 layers[i]:Hide()
Nenue@0 353 layers[i] = nil
Nenue@0 354 refs[subframe] = nil
Nenue@0 355 end
Nenue@0 356 end
Nenue@0 357 end
Nenue@0 358
Nenue@0 359 B.UpdateConfigLayers = function()
Nenue@0 360 local print = B.fprint()
Nenue@0 361 local func = B.Conf.GuidesMode and 'Show' or 'Hide'
Nenue@0 362 local numAnchors = 0
Nenue@0 363 for name, display in pairs(displays) do
Nenue@0 364 numAnchors = numAnchors + 1
Nenue@0 365 display.anchor:EnableMouse(B.Conf.GuidesMode)
Nenue@0 366 if B.Conf.GuidesMode then
Nenue@0 367 display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate)
Nenue@0 368 else
Nenue@0 369 display.anchor:SetScript('OnUpdate', nil)
Nenue@0 370
Nenue@0 371 for i, anchorButton in ipairs(display.anchor.anchorButton) do
Nenue@0 372 anchorButton:Hide()
Nenue@0 373 end
Nenue@0 374
Nenue@0 375 end
Nenue@0 376
Nenue@0 377 end
Nenue@0 378 for id, region in pairs(layers) do
Nenue@0 379 print(id, region:GetName(), func)
Nenue@0 380 region[func](region)
Nenue@0 381 end
Nenue@0 382
Nenue@0 383 print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames')
Nenue@3 384 end
Nenue@3 385
Nenue@3 386 --- Generic handlers for keeping track of XML-defined frames
Nenue@3 387 B.OnLoad = function(self)
Nenue@3 388 tinsert(checkForConfig, self)
Nenue@3 389 end
Nenue@3 390
Nenue@3 391 B.InitXMLFrame = function(self)
Nenue@3 392 print('|cFF00FF00hello from '..self:GetName())
Nenue@3 393
Nenue@3 394 self:RegisterForDrag('LeftButton')
Nenue@3 395 if not B.Conf.FramePosition then
Nenue@3 396 B.Conf.FramePosition = {}
Nenue@3 397 end
Nenue@3 398 if B.Conf.FramePosition[self:GetName()] then
Nenue@3 399 print('restoring frame position', unpack(B.Conf.FramePosition[self:GetName()]))
Nenue@3 400 self:ClearAllPoints()
Nenue@3 401 local anchorTo, relativePoint, x, y = unpack(B.Conf.FramePosition[self:GetName()])
Nenue@3 402 self:SetPoint(anchorTo, UIParent, relativePoint, x, y)
Nenue@3 403 end
Nenue@3 404 end
Nenue@3 405
Nenue@3 406 B.OnDragStart = function(self)
Nenue@3 407 self.xA = self:GetLeft()
Nenue@3 408 self.yA = self:GetBottom()
Nenue@3 409 self.anchorTo, self.relativeTo, self.relativePoint, self.x, self.y = self:GetPoint(1)
Nenue@3 410 print('acquire anchor', self:GetPoint(1))
Nenue@3 411 print(self:GetName(), 'start moving ('..self.x..', '..self.y..')')
Nenue@3 412 self:StartMoving()
Nenue@3 413 end
Nenue@3 414
Nenue@3 415 B.OnDragStop = function(self)
Nenue@3 416 print(self:GetName(), 'stop moving ('..self:GetLeft()..', '..self:GetBottom()..')')
Nenue@3 417 local xB = self:GetLeft() - self.xA
Nenue@3 418 local yB = self:GetBottom() - self.yA
Nenue@3 419 print('storing anchor point', self.anchorTo, self.relativePoint, self.x + xB, self.y + yB)
Nenue@3 420
Nenue@3 421 self:StopMovingOrSizing()
Nenue@3 422 B.Conf.FramePosition[self:GetName()] = {self.anchorTo, self.relativePoint, self.x + xB, self.y + yB}
Nenue@3 423 B.InitXMLFrame(self)
Nenue@3 424
Nenue@0 425 end