Mercurial > wow > devian
view Devian.lua @ 14:5254d1ba6013 v1.2-r15
Multiple output windows can be created for different output prefixes, and prefixes can be designated to an existing or new "console" with /dvn <prefix> <console>
Frame objects are generated directly from XML data, and their state information is stored in the object itself to resolve issues with GetWidth() returning old info in some cases.
StackFrames and DistributeFrames methods can be invoked from /script to arrange the buffers.
author | Nenue |
---|---|
date | Sun, 20 Dec 2015 00:46:42 -0500 |
parents | 080dfa4990fb |
children | 48a1d9c14af5 |
line wrap: on
line source
-- User: Krakyn -- Created: 11/30/2015 7:46 AM if not LibStub then print('Something has happened...') end Devian = LibStub("AceAddon-3.0"):NewAddon("Devian", "AceConsole-3.0", "AceEvent-3.0") local MAJOR, MINOR = 'Devian-1.3', 'r@project-revision@' local D = _G.Devian local STATE_LOW, STATE_HIGH = 1, 2 local PLAYER_REALM = UnitName("player") .. '-' .. GetRealmName() local DEVIAN_FRAME = 'DevianConsole' local print = function(...) _G.print('Dvn', ...) end local db local defaults = { ['global'] = {[STATE_LOW] = {}, [STATE_HIGH] = {}}, ['tags'] = {}, ['channels'] = {[1] = {signature = 'Dvn', name = 'Main', header = "%n [%t]", x = 100, y = 800, height = 500, width = 600, enabled = true}}, primary_channel = 1, current_channel = 1, toggle = true, dnd_status = true, dnd_message = "Debugging. Your messages may get eaten.", font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]], fontsize = 13, fontoutline = 'NONE', backdrop = {1,1,1,0.2}, backgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.3, 0, 0, 0, 0.5}, backblend = 'BLEND', frontdrop = {1,1,1,1}, frontgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.9, 0, 0, 0, 0.9}, frontblend = 'BLEND' } local function ScanAddOnList(cmd, ...) local list_state local args = {} local arg, n = D:GetArgs(cmd, 1) while arg do table.insert(args, arg) arg, n = D:GetArgs(cmd,1,n) end local mode, tag, dest = unpack(args) -- no args, toggle ui if mode == nil then list_state = db.enabled and STATE_LOW or STATE_HIGH db.enabled = (db.enabled == false) and true or false print(list_state, db.enabled) if list_state == STATE_LOW then end elseif mode == 'stack' then return D:StackFrames() elseif mode == 'grid' then return D:DistributeFrames() elseif mode == 'tag' then -- tagging if tag ~= nil and dest ~= nil then if not D.console[dest] and not D.sig[dest] then local sig = dest:match('%a') local id = dest:match('%d') if not id then id = self.last_channel + 1 end if not sig then sig = tag end D:SetChannel(sig, id) end D:Print('Assigning |cFFFFFF00'..tag..'|r to |cFF00FFFF'.. dest .. '|r') else D:Print('Usage: /dvn tag <prefix> <console name or number>') end return elseif mode ~= nil then mode = tonumber(mode) if mode > 2 then print('Something has happened.') return end list_state = mode == STATE_LOW and STATE_LOW or STATE_HIGH end local char_list, global_list = db[PLAYER_REALM][list_state], db.global[list_state] local playername = UnitName("player") for i = 1, GetNumAddOns() do local name = GetAddOnInfo(i) local enableState, globalState = GetAddOnEnableState(playername, i), GetAddOnEnableState(nil, i) if mode == STATE_LOW or mode == STATE_HIGH then char_list[name] = enableState global_list[name] = globalState else if char_list[name] or global_list[name] then if char_list[name] ~= 0 and global_list[name] ~= 0 then local value = false if char_list[name] == 2 and global_list[name] == 1 then value = UnitName("player") elseif global_list[name] == 2 then value = true end print('EnableAddOn(', i, ',', value,')') EnableAddOn(i, value) else local value = true if char_list[name] == 2 and global_list[name] == 1 then value = UnitName("player") end print('DisableAddOn(', i, ',', value,')') DisableAddOn(i,value) end end end end if mode == nil then ReloadUI() end if mode == STATE_LOW then D:Print('Developement AddOn list saved.') else D:Print('Standard AddOn list saved.') end end local function Console_MinMax(self) if self.minimized then self:Maximize() else self:Minimize() end end local function Console_Minimize(self) self:SetHeight(20) self:SetMaxResize(GetScreenWidth(),20) self.minimized = true self.out:Hide() self:Save() end local function Console_Maximize(self) local db = db.channels[self.index] self:SetHeight(db.height) self:SetMaxResize(GetScreenWidth(),GetScreenHeight()) self.minimized = nil self.out:Show() self:Save() end local function Console_Save(self) local db = db.channels[self.index] if self.x then db.x = self.x else db.x = self:GetLeft() end if self.y then db.y = self.y else db.y = (self:GetTop() - GetScreenHeight()) end if self.width then db.width = self.width else db.width = self:GetWidth() end if not self.minimized then if self.height then db.height = self.height else db.height = self:GetHeight() end self:SetHeight(db.height) end db.minimized = self.minimized and true or nil db.enabled = self:IsVisible() and true or nil db.active = self.active and true or nil print('save:', db.signature, 'min=', db.minimized, ' enabled=', db.enabled, ' active = ', db.active, 'x=', db.x, 'y=', db.y, 'h=', db.height, 'w=', db.width) self:SetPoint('TOPLEFT', UIParent, 'TOPLEFT', db.x, db.y) self:SetWidth(db.width) end -- Console frame toggler -- @paramsig [...] -- @param ... one or more space-seperated channel keys local function Console_Toggle(input) local search = {} local key, n = D:GetArgs(input, 1) if key then repeat if D.sig[key] then table.insert(search, D.sig[key]) elseif D.console[key] then table.insert(search, D.console[key]) end key, n = D:GetArgs(input,1,n) until n == 1e9 else search = D.console end db.toggle = not db.toggle and true or nil for _, c in ipairs(search) do if db.toggle then c:Show() else c.enabled = nil c.minimized = nil c:Maximize() c:Hide() end end if db.toggle then D:Print('toggled on?') else D:Print('toggled off?') end end -- Bring console to the front local function Console_ToFront(c) --print(D.raise_ct, 'Raising', c.signature) --print(unpack(db.frontdrop)) --print(unpack(db.frontgrad)) --print(db.frontblend) D.raise_ct = D.raise_ct + 1 c:Raise() c.out.backdrop:SetTexture(unpack(db.frontdrop)) c.out.backdrop:SetGradientAlpha(unpack(db.frontgrad)) c.out.backdrop:SetBlendMode(db.frontblend) for id, bc in pairs(D.console) do if id ~= c.index then --print(D.raise_ct, 'Lowering', bc.signature) --print(unpack(db.backdrop)) --print(unpack(db.backgrad)) --print(db.backblend) bc.out.backdrop:SetTexture(unpack(db.backdrop)) bc.out.backdrop:SetGradientAlpha(unpack(db.backgrad)) bc.out.backdrop:SetBlendMode(db.backblend) end end end -- Generate a console frame -- @paramsig id, vars -- @param id channel number -- @param vars alternative config, else uses db.channels[id] local function CreateConsole(i, vars) if not vars then vars = db.channels[i] end print('make:', vars.signature, '(', vars.x, vars.y, ')', vars.width, 'x', vars.height) local f = CreateFrame('Frame', 'DevianChannelFrame' .. tostring(i), UIParent, DEVIAN_FRAME) f:SetPoint('TOPLEFT', UIParent, 'TOPLEFT', vars.x, vars.y) f:SetSize(vars.width, vars.height) f:Lower() f.out:SetFont(db.font, db.fontsize, db.fontoutline) f.Save = Console_Save f.Minimize = Console_Minimize f.Maximize = Console_Maximize f.MinMax = Console_MinMax f.ToFront = Console_ToFront f.Toggle = D.Console_Toggle f.name = vars.name f.index = i f.signature = vars.signature f.format = vars.header f.x = vars.x f.y = vars.y f.width = vars.width f.height = vars.height if vars.enabled then f.enabled = true if db.toggle then f:Show() end end if vars.minimized then f:Minimize() end return f end -- Print to Devian output -- @paramsig tag, ... -- @param tag channel signature or number used to select console -- @param ... print arguments local function Message(prefix, ...) if prefix == nil then prefix = 1 end local channel local byName = true if D.sig[prefix] then channel = D.sig[prefix] elseif D.console[prefix] then channel = D.console[prefix] byName = nil else channel = D.console[1] end -- color me timbers local pcolor if D.tags[prefix] then pcolor = db.tags[prefix] elseif byName then local c = {0, 0, 0 } local max = string.len(prefix) for i = 1, max, 3 do for k, v in ipairs(c) do local j = i + (k - 1) c[k] = c[k] + (j <= max and string.byte(prefix,j) or 0) end end for k,v in ipairs(c) do c[k] = c[k] % 255 if c[k] < 64 then c[k] = 0 elseif c[k] > 127 then c[k] = 255 end end D.tags[prefix] = string.format('%02X%02X%02X', unpack(c)) end local buffer = {'|cFF'.. D.tags[prefix]..prefix ..'|r'} for i = 1, select('#',...) do local var = select(i, ...) if type(var) == 'table' then var = '<table>' elseif type(var) == 'boolean' then var = var and 'true' or 'false' elseif type(var) == 'function' then var = '<funcref>' elseif type(var) == 'nil' then var = 'nil' end table.insert(buffer, var) end channel.out:AddMessage(table.concat(buffer, ' ')) table.wipe(buffer) end -- Spaces each frame evenly across the screen function D:DistributeFrames() -- print('frame grid:', max, num_side) local max = self.num_channels local num_side = math.ceil(math.sqrt(max)) local w = GetScreenWidth() / num_side local h = GetScreenHeight() / num_side for i, frame in pairs(D.console) do local dx = (i-1) % num_side local dy = math.floor((i-1) / num_side) print('move:', frame.signature, 'dx=', dx, 'dy=', dy) print('move:', frame.signature, ' x=', dx * w, 'y=', -(dy * h), 'h=', h, 'w=', w) frame.width = w frame.height = h frame.x = dx * w frame.y = -(dy * h) frame:Save() end end -- Place all frames stacked beneath the primary frame -- @paramsig function D:StackFrames() local last for i, frame in pairs(self.console) do if last then frame.x = last.x frame.y = last.y - 20 else frame.x = (GetScreenWidth()-frame:GetWidth())/2 frame.y = 0 end frame:Save() last = frame end end -- Creates or updates a console frame -- @paramsig cinfo [, i] -- @param cinfo an array from db.channels[x] or the desired string signature -- @param id when set, the console at that index will be assigned all parameters in cinfo function D:SetChannel(cinfo, i) print('join:', i , cinfo) local t_info = {} if type(cinfo) ~= 'table' then t_info.signature = tostring(cinfo) cinfo = {} end local srcdb = db.channels[self.primary_channel] if i ~= nil then i = tonumber(i) if db.channels[i] then print('pull vars from '..db.channels[i].signature) cinfo = db.channels[i] srcdb = cinfo end end for k,v in pairs(srcdb) do if not t_info[k] then if cinfo[k] then print('- pulling', k..':',v) t_info[k] = cinfo[k] end end end if not db.channels[i] then t_info.x = t_info.x + 20 t_info.y = t_info.y - 20 db.channels[i] = t_info end if not self.console[i] then self.console[i] = CreateConsole(i, t_info) end self.sig[cinfo.signature] = self.console[i] self.sigID[cinfo.signature] = i self.IDsig[i] = cinfo.signature end function D:OnEnable() -- commands local cmdlist = { ['dvn'] = ScanAddOnList, ['devian'] = ScanAddOnList, ['dvc'] = Console_Toggle, } for cmd, func in pairs(cmdlist) do self:RegisterChatCommand(cmd, func, true) end if db.enabled == true then D:Print('Standard AddOn list active. Type /dvn to switch to development mode.') else D:Print('Development AddOn list active. Type /dvn to revert to regular operation.') end end function D:OnInitialize() -- emergency button self:RegisterChatCommand("cleandvn", function(args) DevianDB = nil ReloadUI() end) -- savedvars local cherry = false if not _G.DevianDB then _G.DevianDB = defaults cherry = "Type /dvnsave to snapshot your current UI" end db = _G.DevianDB if not db[PLAYER_REALM] then db[PLAYER_REALM] = {[STATE_LOW] = {}, [STATE_HIGH] = {}} if not cherry then cherry = "This character didn't have an AddOn table." end end -- copy tags self.tags = {} for n, c in pairs(db.tags) do self.tags[n] = c end if cherry then D:Print(cherry) end D.oldprint = getprinthandler() if not _G.oldprint then _G.oldprint = D.oldprint end self.raise_ct = 0 self.last_channel = 0 self.num_channels = 0 self.console = {} self.sig = {} self.sigID = {} self.IDsig = {} for i, cinfo in pairs(db.channels) do i = tonumber(i) if not self.primary_channel then self.primary_channel = i end self:SetChannel(cinfo, i) if i > self.last_channel then self.last_channel = i end self.num_channels = self.num_channels + 1 end setprinthandler(Message) print(MAJOR, MINOR) end