annotate Devian.lua @ 98:33bc8baba858

start of a lot of v3 groundwork based on better knowledge of the addon interface: - use of mixin as a lexical center for generated frames - removal of unfinished segments
author Nenue
date Wed, 26 Oct 2016 10:17:43 -0400
parents f6fae1a4c66c
children 7d94df3804a7
rev   line source
Nenue@50 1 --- Devian - Devian.lua
Nenue@32 2 -- @file-author@
Nenue@32 3 -- @project-revision@ @project-hash@
Nenue@32 4 -- @file-revision@ @file-hash@
Nenue@66 5
Nenue@91 6 --GLOBALS: Devian, DevianLoadMessage, DEVIAN_WORKSPACE, DEVIAN_PNAME, DEVIAN_PID
Nenue@91 7
Nenue@91 8 DEVIAN_WORKSPACE = false
Nenue@91 9 DEVIAN_PNAME = 'Dvn'
Nenue@91 10 DEVIAN_PID = 0
Nenue@79 11
Nenue@66 12 local ADDON, D = ...
Nenue@79 13 local MAJOR, MINOR = 'Devian-2.0', 'r@project-revision@'
Nenue@98 14 local D_INITIALIZED
Nenue@98 15 local next = next
Nenue@72 16 local sub, GetTime, print, _G = string.sub, GetTime, print, _G
Nenue@72 17 local format, setmetatable, getprinthandler, setprinthandler = string.format, setmetatable, getprinthandler, setprinthandler
Nenue@79 18 local tinsert, tremove, rawset = tinsert, tremove, rawset
Nenue@66 19 local currentProfile
Nenue@66 20 local playerName = UnitName("player")
Nenue@66 21 local playerRealm = playerName .. '-' .. GetRealmName()
Nenue@66 22 local num_dock_tabs = 0
Nenue@93 23 local charStates ={}
Nenue@79 24
Nenue@98 25 local registeredTags = {}
Nenue@98 26
Nenue@98 27
Nenue@98 28 DevianCore = {}
Nenue@98 29
Nenue@98 30 function DevianCore:OnLoad ()
Nenue@98 31 self:RegisterEvent('ADDON_LOADED')
Nenue@98 32 self:RegisterEvent('PLAYER_LOGIN')
Nenue@98 33 self:SetShown(true)
Nenue@98 34 end
Nenue@98 35
Nenue@98 36 function DevianCore:OnEvent(event, arg)
Nenue@98 37 if event == 'ADDON_LOADED' or event == 'PLAYER_LOGIN' then
Nenue@98 38 --print(event, arg, DevianDB)
Nenue@98 39 if (arg == 'Devian') and not D_INITIALIZED then
Nenue@98 40 D_INITIALIZED = true
Nenue@98 41 self:Initialize()
Nenue@98 42 self:UnregisterAllEvents()
Nenue@98 43 end
Nenue@98 44 end
Nenue@98 45 end
Nenue@98 46
Nenue@79 47 DevianLoadMessage = setmetatable({}, {
Nenue@79 48 __call = function(t, msg)
Nenue@79 49 rawset(t, #t+1, msg)
Nenue@79 50 end,
Nenue@79 51 __index = function(t)
Nenue@79 52 return #t
Nenue@79 53 end
Nenue@79 54 })
Nenue@79 55
Nenue@66 56 --@debug@
Nenue@66 57 D.debugmode = true
Nenue@66 58 --@end-debug@
Nenue@66 59 D.print = function(...)
Nenue@66 60 if currentProfile and not currentProfile.workspace then
Nenue@98 61 return nop
Nenue@66 62 end
Nenue@66 63
Nenue@66 64 if D.debugmode then
Nenue@66 65 return print('Dvn', ...)
Nenue@66 66 else
Nenue@93 67 return nop
Nenue@66 68 end
Nenue@0 69 end
Nenue@66 70 local print = D.print
Nenue@66 71
Nenue@66 72 D.L = setmetatable({}, {
Nenue@66 73 __index= function(t,k)
Nenue@98 74 return tostring(k)
Nenue@66 75 end,
Nenue@66 76 __call = function(t,k,...)
Nenue@98 77 return format((t[k]) , ...)
Nenue@66 78 end
Nenue@66 79 })
Nenue@66 80 D.oldprint = getprinthandler()
Nenue@66 81 if not _G.oldprint then _G.oldprint = D.oldprint end
Nenue@66 82
Nenue@47 83 local pairs, tostring, tonumber, ipairs, type = pairs, tostring, tonumber, ipairs, type
Nenue@66 84 local max, rand, format, print = max, math.random, string.format, print
Nenue@47 85 local insert, wipe, concat = table.insert, table.wipe, table.concat
Nenue@47 86 local select, unpack = select, unpack
Nenue@47 87 local GetNumAddOns, GetAddOnInfo, GetAddOnEnableState, EnableAddOn = GetNumAddOns, GetAddOnInfo, GetAddOnEnableState, EnableAddOn
Nenue@47 88 local UnitName, DisableAddOn = UnitName, DisableAddOn
Nenue@66 89
Nenue@98 90 local db, L
Nenue@13 91 local defaults = {
Nenue@66 92 global = {{}, {}},
Nenue@66 93 default_channel = {
Nenue@55 94 signature = 'Main',
Nenue@98 95 x = 100, y = -200,
Nenue@55 96 height = 500, width = 600,
Nenue@66 97 enabled = true},
Nenue@66 98 current_profile = 1,
Nenue@66 99 main_profile = 1,
Nenue@66 100 last_profile = 1,
Nenue@66 101 profilesName = {},
Nenue@66 102 profiles = {
Nenue@45 103 },
Nenue@33 104 font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]], -- font info
Nenue@13 105 fontsize = 13,
Nenue@13 106 fontoutline = 'NONE',
Nenue@45 107
Nenue@45 108 headergrad = {'VERTICAL', 0, 0, 0, 1,
Nenue@45 109 1, 0.1, 0.1, 1}, -- header info
Nenue@33 110 headerdrop = {1,1,1,1},
Nenue@45 111 headerblend = 'BLEND',
Nenue@33 112 headeralpha = 1,
Nenue@45 113 headerfontcolor = {1,1,1,1},
Nenue@45 114
Nenue@45 115 backdrop = {1,1,1,1}, -- background frame info
Nenue@56 116 backgrad = {'VERTICAL', 0, 0, 0, .75, 0,0,0, .65},
Nenue@55 117 backblend = 'BLEND',
Nenue@45 118 backalpha = 1,
Nenue@45 119 backborder = {.5,.5,.5,1},
Nenue@45 120 backheader = {.25,.25,.25,1},
Nenue@45 121
Nenue@45 122 frontdrop = {1,1,1,1}, -- foreground frame info
Nenue@56 123 frontgrad = {'VERTICAL', 0, 0, 0, 1, 0,0,0, 0.95},
Nenue@55 124 frontblend = 'BLEND',
Nenue@28 125 frontalpha = 1,
Nenue@45 126 frontborder = {.07,.47,1,1},
Nenue@45 127 frontheader = {1,1,1,1},
Nenue@33 128 tagcolor = {}, -- tag color repository
Nenue@36 129 workspace = 2, -- current profile
Nenue@47 130 last_workspace = 2, -- default workspace to alternate with when just "/dvn" is issued
Nenue@47 131
Nenue@47 132 dock_onshow_fade_time = 2.5,
Nenue@47 133 dock_onshow_fade_from = 1,
Nenue@47 134 dock_onshow_fade_to = 0.2,
Nenue@47 135
Nenue@47 136 dock_alpha_on = 1,
Nenue@47 137 dock_alpha_off = 0.2,
Nenue@47 138 dock_fade_in = 0.15,
Nenue@47 139 dock_fade_out = 0.45,
Nenue@47 140 dock_button_alpha_on = 1,
Nenue@47 141 dock_button_alpha_off = 0.2,
Nenue@50 142 dock_button_fade_in = 0.075,
Nenue@55 143 dock_button_fade_out = 0.075,
Nenue@47 144
Nenue@55 145 movement_fade = true,
Nenue@55 146 movement_fade_time = 0.15,
Nenue@60 147 movement_fade_from = 1,
Nenue@60 148 movement_fade_to = 0,
Nenue@60 149 movement_translation_x = 25,
Nenue@60 150 movement_translation_y = 25,
Nenue@13 151 }
Nenue@9 152
Nenue@66 153 D.console = {}
Nenue@66 154 D.max_channel = 0
Nenue@0 155
Nenue@67 156 D.InWorkspace = function ()
Nenue@67 157 return db.profiles[db.current_profile].workspace
Nenue@67 158 end
Nenue@67 159
Nenue@86 160 local profileTemplate = {
Nenue@86 161 name = function(id, name) return name end,
Nenue@86 162 workspace = function(id, name) return (id ~= 1) end,
Nenue@86 163 current_channel = 1,
Nenue@86 164 default_channel = 1,
Nenue@86 165 num_channels = 1,
Nenue@86 166 max_channel = 1, -- the highest created channel id
Nenue@86 167 enabled = true, -- allow enabled consoles to appear
Nenue@86 168 channels = {
Nenue@86 169 {
Nenue@86 170 index = 1,
Nenue@86 171 signature = 'Main',
Nenue@98 172 x = 100, y = -200,
Nenue@86 173 height = 500, width = 600,
Nenue@86 174 enabled = true
Nenue@86 175 }
Nenue@86 176 },
Nenue@86 177 loadouts = {},
Nenue@86 178 global = {},
Nenue@86 179 tags = {},
Nenue@86 180 char = {
Nenue@86 181 [playerRealm] = {}
Nenue@86 182 },
Nenue@86 183 unlisted = {}
Nenue@86 184 }
Nenue@86 185
Nenue@86 186 --- Applies complex template tables
Nenue@86 187 -- If he value is a function, then it will invoke f(...) and use whatever gets returned
Nenue@86 188 function D.DeepCopy(src, dest, ...)
Nenue@86 189
Nenue@86 190 for k,v in pairs(src) do
Nenue@86 191 if not dest[k] then
Nenue@93 192 --oldprint('Rebuilding conf value', k)
Nenue@86 193 if type(v) == 'table' then
Nenue@86 194 dest[k] = {}
Nenue@86 195 D.DeepCopy(v, dest[k], ...)
Nenue@86 196
Nenue@86 197 else
Nenue@86 198 if type(v) == 'function' then
Nenue@86 199 v = v(...)
Nenue@86 200 end
Nenue@86 201 dest[k] = v
Nenue@86 202 end
Nenue@86 203 end
Nenue@86 204 end
Nenue@86 205 end
Nenue@86 206
Nenue@98 207 D.FixProfile = function(forced)
Nenue@98 208
Nenue@98 209 local numChannels = 0
Nenue@98 210 local minChannel = 400
Nenue@98 211 local sortedChannels = {}
Nenue@98 212 local sortedTags = {}
Nenue@98 213 local maxChannel = 0
Nenue@98 214 for k,v in pairs(currentProfile.channels) do
Nenue@98 215 numChannels = numChannels + 1
Nenue@98 216 maxChannel = max(tonumber(k), maxChannel)
Nenue@98 217 minChannel = min(tonumber(k), minChannel)
Nenue@98 218 tinsert(sortedChannels, v)
Nenue@98 219 end
Nenue@98 220 if (maxChannel > numChannels) or forced then
Nenue@98 221 oldprint('fixing channels data')
Nenue@98 222 table.sort(sortedChannels, function(a,b)
Nenue@98 223 return (b.index > a.index)
Nenue@98 224 end)
Nenue@98 225 for i, info in ipairs(sortedChannels) do
Nenue@98 226 for tag, tagSet in pairs(currentProfile.tags) do
Nenue@98 227 for _, index in pairs(tagSet) do
Nenue@98 228 if index == info.index then
Nenue@98 229 sortedTags[tag] = sortedTags[tag] or {}
Nenue@98 230 sortedTags[tag][i] = i
Nenue@98 231 end
Nenue@98 232 end
Nenue@98 233 end
Nenue@98 234
Nenue@98 235 info.index = i
Nenue@98 236 end
Nenue@98 237 currentProfile.channels = sortedChannels
Nenue@98 238 currentProfile.tags = sortedTags
Nenue@98 239 else
Nenue@98 240 minChannel = 2
Nenue@98 241 end
Nenue@98 242 currentProfile.lastUpdateFix = MINOR
Nenue@98 243 end
Nenue@98 244
Nenue@66 245 D.Profile = function (id, name)
Nenue@66 246
Nenue@66 247 if name and not id and db.profilesName[name] then
Nenue@66 248 id = db.profilesName[name]
Nenue@66 249 print('ID located by name, |cFF00FF00'..name..'|r is |cFFFFFF00'.. id..'|r')
Nenue@66 250 end
Nenue@66 251
Nenue@66 252 if not id or not db.profiles[id] then
Nenue@66 253 if not id then
Nenue@66 254 id = #db.profiles+1
Nenue@66 255 print('Generated profile ID: |cFFFFFF00'.. id .. '|r')
Nenue@66 256 end
Nenue@66 257
Nenue@66 258 if not name or db.profilesName[name] then
Nenue@66 259 local newName = name or (id == 1 and 'Main' or 'Profile')
Nenue@66 260 local prefix = newName
Nenue@66 261 local i = 2
Nenue@66 262 while db.profilesName[newName] do
Nenue@66 263 i = i + 1
Nenue@66 264 newName = prefix .. i
Nenue@66 265 end
Nenue@66 266 name = newName
Nenue@66 267 print('Generated profile name: |cFF00FF00'..newName..'|r')
Nenue@66 268 end
Nenue@86 269
Nenue@86 270
Nenue@86 271
Nenue@66 272 print('Creating profile')
Nenue@66 273 db.profilesName[name] = id
Nenue@86 274 db.profiles[id] = {}
Nenue@66 275 end
Nenue@66 276
Nenue@86 277
Nenue@86 278
Nenue@66 279 D.currentProfile = db.profiles[id]
Nenue@66 280 currentProfile = D.currentProfile
Nenue@86 281
Nenue@86 282 D.DeepCopy(profileTemplate, currentProfile, id, name)
Nenue@86 283
Nenue@86 284
Nenue@66 285 currentProfile.char[playerRealm] = currentProfile.char[playerRealm] or {}
Nenue@66 286 if currentProfile.workspace then
Nenue@79 287 DEVIAN_WORKSPACE = true
Nenue@91 288 DEVIAN_PNAME = currentProfile.name
Nenue@89 289 DEVIAN_PID = id
Nenue@98 290 print('setting phandler')
Nenue@66 291 setprinthandler(D.Message)
Nenue@66 292 else
Nenue@79 293 DEVIAN_WORKSPACE = false
Nenue@93 294 DEVIAN_PNAME = nil
Nenue@93 295 print = nop
Nenue@66 296 end
Nenue@89 297 DEVIAN_PID =id
Nenue@66 298
Nenue@98 299
Nenue@98 300 -- Attempt to fix bad data
Nenue@98 301 --@debug@
Nenue@98 302 MINOR = 70100
Nenue@98 303 --@end-debug@
Nenue@98 304 if (currentProfile.lastUpdateFix or 0) < MINOR then
Nenue@98 305 D.FixProfile(true)
Nenue@98 306 end
Nenue@98 307
Nenue@98 308
Nenue@66 309 D.unlisted = currentProfile.unlisted
Nenue@66 310 D.channels = currentProfile.channels
Nenue@66 311 D.tags = currentProfile.tags
Nenue@66 312 D.channelinfo = currentProfile.channels
Nenue@66 313 D.char = currentProfile.char[playerRealm]
Nenue@66 314 D.global = currentProfile.global
Nenue@66 315 D.num_channels = currentProfile.num_channels
Nenue@66 316 D.enabled = currentProfile.enabled
Nenue@66 317 D.sig = {}
Nenue@66 318 D.sigID = {}
Nenue@66 319 D.IDsig = {}
Nenue@72 320 D.dock = _G.DevianDock
Nenue@66 321 D.dock.buttons = D.dock.buttons or {}
Nenue@66 322
Nenue@98 323
Nenue@98 324
Nenue@66 325 return id, name
Nenue@66 326 end
Nenue@66 327
Nenue@66 328 local targetGlobal, targetChar
Nenue@86 329 D.Command = function (cmd)
Nenue@66 330 local list_id, scan_func, reload
Nenue@86 331
Nenue@14 332 local args = {}
Nenue@86 333 if cmd then
Nenue@86 334 local i, j = 0, 0
Nenue@86 335 repeat
Nenue@86 336 i, j = cmd:find("%S+", j+1)
Nenue@86 337 if i and j then
Nenue@86 338 tinsert(args, cmd:sub(i, j))
Nenue@86 339 end
Nenue@86 340
Nenue@86 341 until not(i or j)
Nenue@14 342 end
Nenue@14 343 local mode, tag, dest = unpack(args)
Nenue@0 344
Nenue@86 345
Nenue@14 346 -- no args, toggle ui
Nenue@86 347 if mode == 'rc' then
Nenue@93 348 return D:ResetChannels(tag)
Nenue@86 349 elseif mode == 'stack' then
Nenue@14 350 return D:StackFrames()
Nenue@14 351 elseif mode == 'grid' then
Nenue@14 352 return D:DistributeFrames()
Nenue@14 353 elseif mode == 'tag' then -- tagging
Nenue@93 354 return D:Tag(tag, dest)
Nenue@73 355 elseif mode == 'new' then
Nenue@93 356 return D:New(tag)
Nenue@93 357 elseif mode == 'dock' then
Nenue@93 358 D.db.dockPoint = tag
Nenue@93 359 return D:UpdateDock()
Nenue@73 360 elseif mode == 'remove' then
Nenue@93 361 return D:Remove(tag)
Nenue@89 362 elseif mode ~= nil then
Nenue@89 363 -- profile selector or save command
Nenue@66 364 if mode == 'save' then
Nenue@66 365 list_id = tonumber(tag)
Nenue@89 366 else
Nenue@89 367 list_id = tonumber(mode)
Nenue@89 368 end
Nenue@89 369
Nenue@89 370 if not list_id then
Nenue@89 371 if db.profilesName[tostring(list_id)] then
Nenue@89 372 list_id = db.profilesName[tostring(list_id)]
Nenue@89 373 else
Nenue@89 374
Nenue@89 375 D:Print(L('Unable to resolve profile ID/name', list_id, dest))
Nenue@89 376 return
Nenue@66 377 end
Nenue@89 378 end
Nenue@89 379
Nenue@89 380
Nenue@89 381 if mode == 'save' then
Nenue@66 382 D.Profile(list_id, dest)
Nenue@66 383 scan_func = D.Save
Nenue@89 384
Nenue@89 385
Nenue@89 386 local name = currentProfile.name
Nenue@89 387 if dest then
Nenue@89 388 dest = dest:gsub("$%s+", ''):gsub("%s+^", '')
Nenue@89 389 if dest then
Nenue@89 390 if name then
Nenue@89 391 db.profilesName[name] = nil
Nenue@89 392 end
Nenue@89 393 db.profiles[list_id].name = dest
Nenue@89 394 db.profilesName[dest] = list_id
Nenue@92 395
Nenue@92 396 name = dest
Nenue@89 397 end
Nenue@89 398 end
Nenue@89 399
Nenue@89 400
Nenue@89 401 D:Print("Profile |cFFFFFF00".. list_id .."|r:|cFF00FFFF".. name .."|r saved.")
Nenue@66 402 else
Nenue@32 403
Nenue@89 404 if db.profiles[list_id] then
Nenue@89 405 D.LoadMessage ("Switched profiles.")
Nenue@89 406 if list_id ~= db.main_profile then
Nenue@89 407 db.last_profile = list_id
Nenue@89 408 end
Nenue@89 409 db.current_profile = list_id
Nenue@89 410 scan_func = D.Load
Nenue@89 411 else
Nenue@89 412 return D:PrintHelp()
Nenue@89 413 end
Nenue@36 414
Nenue@0 415 end
Nenue@32 416 elseif mode == nil then
Nenue@66 417 list_id = (db.current_profile ~= db.main_profile) and db.main_profile or db.last_profile
Nenue@77 418 D.LoadMessage ("Switched between main and recent profile ("..db.current_profile..' and '..list_id..')')
Nenue@66 419 db.current_profile = list_id
Nenue@66 420 scan_func = D.Load
Nenue@32 421 else
Nenue@89 422
Nenue@89 423
Nenue@32 424 return D:PrintHelp()
Nenue@0 425 end
Nenue@77 426
Nenue@77 427 if not db.profiles[list_id] then
Nenue@77 428 db.profiles[list_id] = {global = {}, char = {} }
Nenue@77 429 D.LoadMessage ("Starting profile #|cFF00FFFF".. list_id..'|r')
Nenue@77 430 end
Nenue@67 431 if not db.profiles[list_id].char[playerRealm] then
Nenue@67 432 db.profiles[list_id].char[playerRealm] = {}
Nenue@67 433 end
Nenue@67 434
Nenue@66 435 targetGlobal = db.profiles[list_id].global
Nenue@66 436 targetChar = db.profiles[list_id].char[playerRealm]
Nenue@32 437
Nenue@67 438
Nenue@66 439 if scan_func then
Nenue@93 440 wipe(charStates)
Nenue@66 441 for id, name, enableState, globalState in D.Addons() do
Nenue@66 442 scan_func(id, name, enableState, globalState)
Nenue@0 443 end
Nenue@0 444 end
Nenue@0 445
Nenue@66 446 if scan_func == D.Load then
Nenue@72 447 _G.ReloadUI()
Nenue@93 448 if AddonList_Update then
Nenue@93 449 AddonList_Update()
Nenue@93 450 end
Nenue@93 451 elseif (scan_func == D.Save) then
Nenue@93 452 print('reckoning')
Nenue@93 453 local updated = {}
Nenue@93 454 for addon, newState in pairs(charStates) do
Nenue@93 455 for character, addons in pairs(db.profiles[list_id].char) do
Nenue@93 456 if addons[addon] then
Nenue@93 457 print(addon, addons[addon], '::', newState)
Nenue@93 458 if (addons[addon] ~= newState) then
Nenue@93 459 addons[addon] = newState
Nenue@93 460 updated[character] = (updated[character] or 0) + 1
Nenue@93 461 end
Nenue@93 462
Nenue@93 463 end
Nenue@93 464
Nenue@93 465 end
Nenue@93 466 end
Nenue@93 467 for character, numAddons in pairs(updated) do
Nenue@93 468 print(character, numAddons, 'settings')
Nenue@93 469 end
Nenue@93 470
Nenue@66 471 end
Nenue@93 472
Nenue@93 473
Nenue@66 474 D.Profile(db.current_profile)
Nenue@66 475 end
Nenue@66 476
Nenue@66 477 D.Addons = function()
Nenue@66 478 local playername = UnitName("player")
Nenue@66 479 return function(n, i)
Nenue@66 480 if i >= n then
Nenue@66 481 return nil
Nenue@66 482 end
Nenue@66 483
Nenue@66 484 i = i + 1
Nenue@66 485 local name = GetAddOnInfo(i)
Nenue@66 486 local enableState, globalState = GetAddOnEnableState(playername, i), GetAddOnEnableState(nil, i)
Nenue@66 487 return i, name, enableState, globalState
Nenue@66 488 end, GetNumAddOns(), 0
Nenue@66 489 end
Nenue@66 490
Nenue@66 491 D.Load = function(id, name, charState, globalState)
Nenue@93 492 print('load', tostring(name), tostring(charState), tostring(globalState))
Nenue@93 493 if targetGlobal[name] == 2 then
Nenue@93 494 EnableAddOn(id, true)
Nenue@93 495 elseif targetChar[name] == 2 then
Nenue@93 496 EnableAddOn(id, playerName)
Nenue@93 497 elseif targetGlobal[name] == 0 then
Nenue@93 498 DisableAddOn(id, true)
Nenue@93 499 elseif targetChar[name] == 0 then
Nenue@93 500 DisableAddOn(id, playerName)
Nenue@93 501 end
Nenue@93 502
Nenue@93 503 if not (targetChar[name] or targetGlobal[name]) then
Nenue@66 504 tinsert(D.unlisted, name)
Nenue@66 505 end
Nenue@93 506
Nenue@66 507 end
Nenue@93 508
Nenue@93 509
Nenue@66 510 D.Save = function(id, name, charState, globalState)
Nenue@93 511 if (charState ~= 0) or (globalState ~= 0) then
Nenue@93 512 print('save', id, name, playerRealm .. ': '.. charState, 'All: '.. globalState)
Nenue@93 513 end
Nenue@93 514
Nenue@66 515 targetGlobal[name] = globalState
Nenue@66 516 targetChar[name] = charState
Nenue@93 517
Nenue@93 518 -- if enabling/disabling globally
Nenue@93 519 if globalState ~= 1 then
Nenue@93 520 charStates[name] = globalState
Nenue@93 521 end
Nenue@66 522 end
Nenue@57 523
Nenue@98 524 D.UpdateTags = function()
Nenue@98 525
Nenue@98 526 wipe(registeredTags)
Nenue@98 527 for tag, tagSet in pairs(currentProfile.tags) do
Nenue@98 528 registeredTags[tag] = registeredTags[tag] or {}
Nenue@98 529 for _, id in pairs(tagSet) do
Nenue@98 530 if D.console[id] then
Nenue@98 531 tinsert(registeredTags[tag], D.console[id])
Nenue@98 532 end
Nenue@98 533 end
Nenue@98 534 end
Nenue@98 535 end
Nenue@98 536
Nenue@66 537 D.Tag = function(self, tag, dest)
Nenue@66 538 local sig
Nenue@66 539 if tag ~= nil and dest ~= nil then
Nenue@66 540 --@debug@
Nenue@66 541 --print(tag, dest)
Nenue@66 542 --@end-debug@
Nenue@66 543
Nenue@66 544 -- convert to ID
Nenue@66 545 if tonumber(dest) == nil then
Nenue@66 546 if D.sigID[dest] then
Nenue@66 547 dest = currentProfile.channels[D.sigID[dest]].index
Nenue@66 548 else
Nenue@66 549 sig = dest
Nenue@66 550 end
Nenue@57 551 else
Nenue@66 552 dest = tonumber(dest)
Nenue@32 553 end
Nenue@66 554 --@debug@
Nenue@66 555 --print('2 tag,dest,sig', tag, dest, sig)--@end-debug@
Nenue@66 556
Nenue@66 557 -- make a new channel?
Nenue@66 558 local channel
Nenue@66 559 if not currentProfile.channels[dest] then
Nenue@98 560 dest = #D.channels + 1
Nenue@66 561 D:Print(L('New channel created', sig and (dest..':'..sig) or dest ))
Nenue@98 562 channel = D:GetOrCreateChannel(dest, tag)
Nenue@66 563 else
Nenue@98 564 channel = currentProfile.channels[dest]
Nenue@66 565 end
Nenue@66 566 --@debug@
Nenue@66 567 --print('3 tag,dest,channel.sig=',tag, dest, channel.signature)--@end-debug@
Nenue@66 568
Nenue@66 569 if not currentProfile.tags[tag] then -- no tag table?
Nenue@66 570 currentProfile.tags[tag] = {}
Nenue@66 571 end
Nenue@66 572
Nenue@66 573 if currentProfile.tags[tag][dest] then -- is tag set?
Nenue@98 574 currentProfile.tags[tag][dest] = nil
Nenue@98 575 D:Print(L('Tag removed from channel', tag, currentProfile.channels[dest].index, currentProfile.channels[dest].signature))
Nenue@66 576 else
Nenue@66 577 currentProfile.tags[tag][dest] = dest
Nenue@98 578 D:Print(L('Tag added to channel', tag, channel.index, channel.signature))
Nenue@66 579 end
Nenue@98 580 D.UpdateTags()
Nenue@98 581 DevianDock:Update()
Nenue@66 582 else
Nenue@66 583 D:Print(L['Command tag help'])
Nenue@0 584 end
Nenue@0 585 end
Nenue@0 586
Nenue@86 587 D.ResetChannels = function(self, profile)
Nenue@86 588 currentProfile.current_channel = 1
Nenue@86 589 currentProfile.primary_channel = 1
Nenue@86 590 currentProfile.channels = {}
Nenue@86 591 D.DeepCopy(profileTemplate.channels, currentProfile.channels)
Nenue@86 592 currentProfile.tags = {}
Nenue@86 593 D.LoadMessage('Profile reset.')
Nenue@86 594 ReloadUI()
Nenue@86 595 end
Nenue@86 596
Nenue@73 597 D.New = function(self, tag)
Nenue@73 598 if tag and not self.sigID[tag] then
Nenue@73 599 local id = D.max_channel + 1
Nenue@73 600 D.SetChannel(tag, id)
Nenue@73 601 end
Nenue@73 602 end
Nenue@0 603
Nenue@73 604 D.Remove = function(self, dest)
Nenue@73 605 dest = D.sigID[dest] or tonumber(dest)
Nenue@73 606 if D.console[dest] and D.channels[dest] then
Nenue@73 607 for tag, tagDest in pairs(D.tags) do
Nenue@73 608 for i = #tagDest, 0 do
Nenue@73 609 -- work downward so we aren't skipping entries
Nenue@73 610 if tagDest[i] == dest then
Nenue@73 611 tremove(tagDest, i)
Nenue@73 612 end
Nenue@73 613 end
Nenue@73 614 end
Nenue@73 615 D.console[dest]:Hide()
Nenue@73 616 D.channels[dest] = nil
Nenue@73 617 tremove(D.console, dest)
Nenue@93 618 D.dock.buttons[dest]:SetShown(false)
Nenue@73 619 D:UpdateDock()
Nenue@73 620 D:Print('Removed channel #'..dest)
Nenue@73 621 end
Nenue@73 622 end
Nenue@13 623
Nenue@77 624 --- Queue up a message to appear after UI reload
Nenue@77 625 function D.LoadMessage(msg)
Nenue@77 626
Nenue@77 627 tinsert(_G.DevianLoadMessage, msg)
Nenue@77 628 end
Nenue@77 629
Nenue@18 630 --- Creates a Devian-style output.
Nenue@18 631 -- The first argument describes the channel to output on, and the remaining arguments are concatenated in a manner similar to default print()
Nenue@18 632 -- This becomes the print handler when development mode is active. The original print() function is assigned to oldprint().
Nenue@18 633 -- @param Tag, signature, or numeric index of the channel to output on. Defaults to primary channel.
Nenue@18 634 -- @param ... Output contents.
Nenue@98 635 local default_sendq = {}
Nenue@66 636 function D.Message(prefix, ...)
Nenue@67 637 if not currentProfile.workspace then
Nenue@23 638 return D.oldprint(prefix, ...)
Nenue@23 639 end
Nenue@98 640 local print = D.oldprint
Nenue@57 641 prefix = tostring(prefix)
Nenue@57 642 if prefix == nil then
Nenue@55 643 prefix = 'nil*'
Nenue@1 644 end
Nenue@9 645
Nenue@98 646 local sendq = default_sendq
Nenue@30 647 local tag, id, tagged
Nenue@13 648 local byName = true
Nenue@98 649
Nenue@98 650 if registeredTags[prefix] then
Nenue@98 651 sendq = registeredTags[prefix]
Nenue@98 652 else
Nenue@98 653 if D.sig[prefix] then
Nenue@98 654 sendq[D.sig[prefix].index] = D.sig[prefix]
Nenue@98 655 elseif not tagged then
Nenue@98 656 sendq[1] = D.console[D.primary_channel]
Nenue@18 657 end
Nenue@18 658 end
Nenue@18 659
Nenue@98 660
Nenue@18 661
Nenue@9 662 -- color me timbers
Nenue@9 663 local pcolor
Nenue@18 664 if (not db.tagcolor[prefix]) and byName then
Nenue@86 665 -- numbers, use white
Nenue@86 666 if prefix:match('^%d+%.%d+') then
Nenue@73 667 pcolor = 'FFFFFF'
Nenue@73 668 else
Nenue@73 669 local c = {
Nenue@73 670 rand(64,255), rand(64,255), rand(64,255)
Nenue@73 671 }
Nenue@73 672 if c[1] > 223 and c[2] > 223 and c[3] > 223 then
Nenue@73 673 c[rand(1,3)] = rand(64,223)
Nenue@73 674 end
Nenue@73 675 db.tagcolor[prefix] = format('%02X%02X%02X', unpack(c))
Nenue@73 676 pcolor = db.tagcolor[prefix]
Nenue@0 677 end
Nenue@73 678 else
Nenue@73 679 pcolor = db.tagcolor[prefix]
Nenue@0 680 end
Nenue@0 681
Nenue@55 682 local buffer = {}
Nenue@0 683 for i = 1, select('#',...) do
Nenue@0 684 local var = select(i, ...)
Nenue@0 685
Nenue@0 686 if type(var) == 'table' then
Nenue@20 687 if type(var.GetName) == 'function' then
Nenue@72 688 var = '[table:'..tostring(var:GetName())..']'
Nenue@20 689 else
Nenue@32 690 var = '<'..tostring(var)..'>'
Nenue@20 691 end
Nenue@20 692
Nenue@0 693 elseif type(var) == 'boolean' then
Nenue@75 694 var = var and 'true' or 'false'
Nenue@0 695 elseif type(var) == 'function' then
Nenue@72 696 var = '['..tostring(var)..']'
Nenue@0 697 elseif type(var) == 'nil' then
Nenue@75 698 var = 'nil'
Nenue@60 699 else
Nenue@60 700 var = tostring(var)
Nenue@0 701 end
Nenue@0 702
Nenue@47 703 insert(buffer, var)
Nenue@0 704 end
Nenue@47 705 local message = concat(buffer, ' ')
Nenue@18 706 for id, channel in pairs(sendq) do
Nenue@55 707 if channel.width < 250 then
Nenue@72 708 prefix = sub(prefix, 0,2)
Nenue@55 709 end
Nenue@98 710 channel.out:AddMessage('|cFF'.. pcolor..prefix ..'|r ' .. message, 0.8, 0.8, 0.8)
Nenue@98 711 if channel.Dock and not channel.Dock.newMessage then
Nenue@98 712 channel.Dock.newMessage = true
Nenue@98 713 channel.Dock.caption.pulse:Play()
Nenue@98 714 channel.Dock:Update()
Nenue@58 715 end
Nenue@18 716 end
Nenue@47 717 wipe(buffer)
Nenue@0 718 end
Nenue@0 719
Nenue@14 720
Nenue@32 721
Nenue@14 722
Nenue@32 723 function D:PrintHelp()
Nenue@32 724 D:Print("|cFFFFFF00/dvn|r",
Nenue@32 725 "\n |cFFFFFF00<number>|r - Loads a saved addon list. List 1 is treated as a gameplay profile and consoles will be disabled by default.")
Nenue@47 726 D:Print("|cFFFFFF00/dvc|r [<key>, ...]", "- Hides and show consoles. A list of channel keys can be passed to specify which ones get toggled.")
Nenue@32 727
Nenue@32 728 D:Print("|cFFFFFF00/resetdvn|r", "- Resets all but profile data SavedVariables.")
Nenue@32 729 D:Print("|cFFFFFF00/cleandvn|r", "- Fully resets SavedVariables, profiles and all.")
Nenue@32 730 end
Nenue@32 731
Nenue@66 732 local blocked = {profiles = true, debugmode = true}
Nenue@66 733 D.SetDefaults = function()
Nenue@72 734 local DevianDB = _G.DevianDB
Nenue@66 735 for k,v in pairs(DevianDB) do
Nenue@66 736 if not blocked[k] then
Nenue@66 737 DevianDB[k] = nil
Nenue@60 738 end
Nenue@60 739 end
Nenue@66 740 for k,v in pairs(defaults) do
Nenue@66 741 if not blocked[k] then
Nenue@66 742 DevianDB[k] = v
Nenue@60 743 end
Nenue@60 744 end
Nenue@73 745
Nenue@77 746 D.LoadMessage "Non-user SavedVars have been reset."
Nenue@72 747 _G.ReloadUI()
Nenue@60 748 end
Nenue@66 749 D.SetDefaultsAll = function ()
Nenue@72 750 _G.DevianDB = nil
Nenue@77 751 D.LoadMessage "All SavedVars wiped."
Nenue@72 752 _G.ReloadUI()
Nenue@66 753 end
Nenue@73 754
Nenue@73 755 D.UnsetColors = function()
Nenue@73 756 db.tagcolor = {}
Nenue@73 757 D:Print('Tag color cache cleared.')
Nenue@73 758 end
Nenue@45 759
Nenue@33 760
Nenue@89 761 function D.ConsoleCommand (cmd)
Nenue@89 762 D:Console_Toggle(cmd)
Nenue@89 763 end
Nenue@87 764
Nenue@66 765
Nenue@98 766 function DevianCore:Initialize()
Nenue@81 767 L = D.L
Nenue@13 768
Nenue@33 769 -- pull defaults
Nenue@98 770 if not DevianDB then
Nenue@98 771 DevianDB = defaults
Nenue@9 772 end
Nenue@98 773 D.db = _G.DevianDB
Nenue@9 774 db = _G.DevianDB
Nenue@0 775
Nenue@66 776 ---
Nenue@77 777 if #_G.DevianLoadMessage >= 1 then
Nenue@77 778 for i, msg in ipairs(_G.DevianLoadMessage) do
Nenue@77 779 D:Print(msg)
Nenue@77 780 end
Nenue@77 781
Nenue@77 782 table.wipe(_G.DevianLoadMessage)
Nenue@0 783 end
Nenue@0 784
Nenue@66 785
Nenue@89 786 -- commands
Nenue@89 787 local cmdlist = {
Nenue@89 788 ['dvn'] = "Command",
Nenue@89 789 ['devian'] = "Command",
Nenue@89 790 ['dvc'] = "ConsoleCommand",
Nenue@89 791 ['dvncolors'] = "UnsetColors",
Nenue@89 792 ['cleandvn'] = "SetDefaultsAll",
Nenue@89 793 ['resetdvn'] = "SetDefaults",
Nenue@89 794 }
Nenue@89 795 for cmd, func in pairs(cmdlist) do
Nenue@89 796 local CMD = cmd:upper()
Nenue@89 797 _G['SLASH_' .. CMD .. '1'] = "/"..cmd
Nenue@89 798
Nenue@89 799 if type(func == 'string') then
Nenue@93 800 --print('SLASH_' .. CMD .. '1','/'.. cmd, func)
Nenue@89 801 SlashCmdList[CMD] = D[func]
Nenue@89 802 else
Nenue@93 803 --print('SLASH_' .. CMD .. '1','/'.. cmd, func)
Nenue@89 804 SlashCmdList[CMD] = func
Nenue@89 805 end
Nenue@89 806 end
Nenue@89 807
Nenue@66 808 --- initialize the current profile
Nenue@66 809 local id, name = D.Profile(db.current_profile or 1)
Nenue@66 810 D:Print('Using profile |cFFFFFF00'.. id ..'|r: |cFF00FF00'..currentProfile.name..'|r')
Nenue@66 811 if currentProfile.workspace then
Nenue@66 812 D:Print('Workspace: '.. (#currentProfile.channels) .. ' channels, ' .. #currentProfile.tags .. ' tags.')
Nenue@86 813 if D.channels[currentProfile.default_channel] then
Nenue@86 814 D:Print('Default channel: |cFFFFFF00'..currentProfile.default_channel..'|r: |cFF00FFFF'.. D.channels[currentProfile.default_channel].signature..'|r')
Nenue@86 815 end
Nenue@0 816 end
Nenue@13 817
Nenue@86 818
Nenue@98 819
Nenue@98 820 for index, cinfo in ipairs(D.channels) do
Nenue@98 821 --oldprint(index, cinfo.signature)
Nenue@66 822 if not D.primary_channel then
Nenue@98 823 D.primary_channel = index
Nenue@14 824 end
Nenue@98 825 D:GetOrCreateChannel(index)
Nenue@98 826 D.num_channels = #D.channels
Nenue@32 827 end
Nenue@86 828 D.primary_channel = D.primary_channel or 1
Nenue@66 829 D.max_channel = max(D.max_channel, currentProfile.max_channel)
Nenue@66 830 if currentProfile.max_channel < D.max_channel then
Nenue@66 831 for i = currentProfile.max_channel, D.max_channel do
Nenue@66 832 D.console[i]:Hide()
Nenue@47 833 end
Nenue@36 834 end
Nenue@36 835
Nenue@98 836 D.UpdateTags()
Nenue@98 837
Nenue@66 838 if currentProfile.workspace then
Nenue@66 839 if D.console[currentProfile.current_channel] then
Nenue@69 840 --print('bringing', D.console[currentProfile.current_channel].signature, 'to the front')
Nenue@66 841 D.console[currentProfile.current_channel]:ToFront()
Nenue@66 842 -- bring the current channel to the front
Nenue@47 843 end
Nenue@98 844 DevianDock:Update()
Nenue@36 845 end
Nenue@98 846
Nenue@98 847 print('devian')
Nenue@66 848 end
Nenue@89 849
Nenue@98 850 function D:Print (...)
Nenue@98 851 local msg = '|cFF00FF44Devian|r:'
Nenue@98 852 for i = 1, select('#', ...) do
Nenue@98 853 msg = msg .. ' ' .. tostring(select(i, ...))
Nenue@98 854 end
Nenue@98 855 DEFAULT_CHAT_FRAME:AddMessage(msg)
Nenue@98 856 end
Nenue@98 857
Nenue@98 858 function D:GetActiveChannel()
Nenue@98 859 return D.console[currentProfile.current_channel]
Nenue@98 860 end
Nenue@98 861
Nenue@98 862 function D:GetOrCreateChannel(id, name)
Nenue@98 863 local info = D.channels[id]
Nenue@98 864 local frame = D.console[id]
Nenue@98 865 if not frame then
Nenue@98 866
Nenue@98 867 --print('new frame')
Nenue@98 868 frame = CreateFrame('Frame', 'DevianConsole'..id, Devian, 'DevianConsoleTemplate')
Nenue@98 869 frame:SetID(id)
Nenue@98 870 D.console[id] = frame
Nenue@98 871 end
Nenue@98 872 if not info then
Nenue@98 873 --print('new channel')
Nenue@98 874 info = {
Nenue@98 875 }
Nenue@98 876 D.DeepCopy(defaults.default_channel, info)
Nenue@98 877 info.index = id
Nenue@98 878 info.signature = name
Nenue@98 879 D.channels[id] = info
Nenue@98 880 end
Nenue@98 881
Nenue@98 882
Nenue@98 883 frame:Setup(info)
Nenue@98 884 return frame
Nenue@98 885 end