view Devian.lua @ 35:3304455a3f45

code organizing; UI stuff is in the UI script, Devian prime just deals with config and print corner menu elements placed and hooked, still needs follow-up code
author Nenue
date Sun, 27 Dec 2015 03:51:17 -0500
parents 7441f3bce940
children bec37163b7fe
line wrap: on
line source
--- ${PACKAGE_NAME}
-- @file-author@
-- @project-revision@ @project-hash@
-- @file-revision@ @file-hash@
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 WORKSPACE_ON, WORKSPACE_OFF = 1, 2
local PLAYER_REALM = UnitName("player") .. '-' .. GetRealmName()
local print = _G.print
local db
local defaults = {
  ['global'] = {{}, {}},
  ['tags'] = {},
  ['channels'] = {[1] = {signature = 'Main', index = 1, x = 100, y = 800, height = 500, width = 600, enabled = true}},
  primary_channel = 1, -- the channel to which default output is sent
  current_channel = 1, -- the front channel
  max_channel = 1, -- the highest created channel id
  enable = true, -- allow enabled consoles to appear
  load_message = "Defaults loaded.", -- messages to be displayed after reload
  font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]], -- font info
  fontsize = 13,
  fontoutline = 'NONE',
  headergrad = {'VERTICAL', 0, 0, 0, 0.5, 0.1, 0.1, 0.1, 0.3}, -- header info
  headerdrop = {1,1,1,1},
  headeralpha = 1,
  backdrop = {0,0,0,1},                                        -- background frame info
  backgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.3, 0, 0, 0, 0.5},
  backblend = 'MOD',
  backalpha = 0.7,
  backborder = {0,0,1,0.75},
  frontdrop = {0,0,0,1},                                       -- foreground frame info
  frontgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.9, 0, 0, 0, 0.9},
  frontblend = 'MOD',
  frontalpha = 1,
  frontborder = {1,0,0,1},
  tagcolor = {},   -- tag color repository
  workspace = 1,   -- current profile
  last_workspace = 2 -- default workspace to alternate with when just "/dvn" is issued
}

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 == 'dock' then
    if db.workspace == 1 then
      D:Print('Must be in dev mode to use this.')
      return
    end
    if #args <= 2 then
      D:Print("Not enough arguments for dock command.")
      return
    end

    local target
    local worklist = {}
    for i = 2, #args do
      local ch
      local k = tostring(args[i])
      local j = tonumber(args[i])
      if db.channels[j] then
        ch = db.channels[j]
      elseif D.sig[k] then
        ch = D.sig[k]
      elseif D.sigID[k] then
        ch = db.channels[D.sigID[k]]
      elseif db.tags[k] and db.tags[k][1] then
        ch = db.channels[db.tags[j][1]]
        -- last resort
      else
        D:Print('No entry for argument #'..i..': '..tostring(args[i]))
        return
      end
      --@debug@
      --print(i, '->', ch.index, '-', ch.signature)--@end-debug@
      if i > 2 then
        table.insert(worklist, ch.index)
      else
        target = ch

        --@debug@
        --print('arg1', args[2], target)--@end-debug@
      end
    end
    D:Print("Docking |cFF88FFFF"..table.concat(worklist, "|r, |cFF88FFFF").."|r with |cFFFFFF00"..target.index..', '..target.signature.."|r.")
    return D:DockFrame(target.index, unpack(worklist))


  elseif mode == 'stack' then
    if db.workspace == 1 then
      return D:Print(MSG_NEED_DEV_MODE)
    end
    return D:StackFrames()
  elseif mode == 'grid' then
    if db.workspace == 1 then
      return D:Print(MSG_NEED_DEV_MODE)
    end
    return D:DistributeFrames()
  elseif mode == 'tag' then -- tagging
    if db.workspace == 1 then
      return D:Print(MSG_NEED_DEV_MODE)
    end

    if tag ~= nil and dest ~= nil then
      -- convert to ID
      if tonumber(dest) == nil and D.sigID[dest] then
        dest = db.channels[D.sigID[dest]].index
      end

      -- make a new channel?
      if not db.channels[dest] then
        dest = db.max_channel + 1
        D:Print('Creating a new channel for '.. tag)
        D:SetChannel(tag, dest)
      end

      if db.tags[tag] and db.tags[tag][dest] then
        db.tags[tag][dest] = nil
        D:Print('Hiding |cFF88FFFF'..tag..'|r messages in |cFFFFFF00'..db.channels[dest].index ..':'.. db.channels[dest].signature)
      else
        if not db.tags[tag] then
          db.tags[tag] = {}
        end
        db.tags[tag][dest] = dest
        D:Print('Showing |cFF88FFFF'..tag..'|r messages in |cFFFFFF00'..db.channels[dest].index ..':'.. db.channels[dest].signature)
      end
    else
      D:Print('Usage: /dvn tag <prefix> <console name or number>')
    end
    return
  elseif tonumber(mode) ~= nil or mode == 'save' then
    -- iterating for something
    if mode == 'save' then
      if tonumber(tag) == nil then
        T:Print('Save ID is invalid:', tag)
      end
      list_state = tonumber(tag)
    else
      list_state = tonumber(mode)
      db.workspace = list_state
      if list_state ~= 1 then
        db.last_workspace = list_state
      end

    end
  elseif mode == nil then
    list_state = (db.workspace == 1) and db.last_workspace or 1
    db.workspace = list_state
    db.load_message = "quick swapped workspace #"..list_state
  else
    return D:PrintHelp()
  end

  -- start the iterating
  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 == 'save' 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
      elseif mode ~= 'save' then
        if type(db.unlisted) ~= 'table' then
          db.unlisted = {}
        end
        table.insert(db.unlisted, name)
      end

    end
  end

  if mode ~= 'save' then
    --db.load_message = "AddOn profile ".. list_state .." was loaded."
    ReloadUI()
  else
      D:Print('Profile #'.. (list_state)..' saved.')
    if list_state == 1 then
      D:Print('This will be your main AddOn list.')
    elseif list_state == db.default_list then
      db.last_workspace = list_state
      D:Print('This will be your default workspace')
    end
  end
end



--- Creates a Devian-style output.
-- The first argument describes the channel to output on, and the remaining arguments are concatenated in a manner similar to default print()
-- This becomes the print handler when development mode is active. The original print() function is assigned to oldprint().
-- @param Tag, signature, or numeric index of the channel to output on. Defaults to primary channel.
-- @param ... Output contents.
local function Message(prefix, ...)
  if not db.enabled then
    return D.oldprint(prefix, ...)
  end

  if prefix == nil then
    prefix = 1
  end

  local sendq = {}
  local tag, id, tagged
  local byName = true
  if D.tags[prefix] then
    for _, id in pairs(D.tags[prefix]) do
      if D.console[id] then
        sendq[id] = D.console[id]
        tagged = true
      end
    end
  end

  if D.sig[prefix] then
    sendq[D.sig[prefix].index] = D.sig[prefix]
  elseif D.console[prefix] then
    sendq[D.console[prefix]] = D.console[prefix]
  elseif not tagged then
    sendq[D.primary_channel] = D.console[D.primary_channel]
  end

  -- color me timbers
  local pcolor
  if (not db.tagcolor[prefix]) and byName then
    local c = {
      math.random(64,255), math.random(64,255), math.random(64,255)
    }
    if c[1] > 223 and c[2] > 223 and c[3] > 223 then
      c[math.random(1,3)] = math.random(64,223)
    end

    db.tagcolor[prefix] = string.format('%02X%02X%02X', unpack(c))
  end
  pcolor = db.tagcolor[prefix]

  local buffer = {'|cFF'.. pcolor..prefix ..'|r'}
  for i = 1, select('#',...) do
    local var = select(i, ...)

    if type(var) == 'table' then
      if type(var.GetName) == 'function' then
        var = '<table:'..var:GetName()..'>'
      else
        var = '<'..tostring(var)..'>'
      end

    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
  local message = table.concat(buffer, ' ')
  for id, channel in pairs(sendq) do
    channel.out:AddMessage(message)
  end
  table.wipe(buffer)
end




function D:PrintHelp()
  D:Print("|cFFFFFF00/dvn|r",
    "\n |cFFFFFF00<number>|r - Loads a saved addon list. List 1 is treated as a gameplay profile and consoles will be disabled by default.")

  D:Print("|cFFFFFF00/resetdvn|r", "- Resets all but profile data SavedVariables.")
  D:Print("|cFFFFFF00/cleandvn|r", "- Fully resets SavedVariables, profiles and all.")
end

function D:OnEnable()
  print(MAJOR, MINOR)

  if db.unlisted and #db.unlisted > 0 then
    D:Print('New AddOns have been found since the last profile update: '.. table.concat(db.unlisted, ', '))
    table.wipe(db.unlisted)
  end

  if db.workspace == 1 then
    D:Print('Gameplay mode active (list #'..db.workspace..'). Print handling turned |cFFFFFF00OFF|r.')
  else
    D:Print('Development mode active (list #'..db.workspace..'). Print handling |cFF00FF00ON|r.')
  end

end

function D:OnInitialize()
  -- commands
  self:RegisterChatCommand("cleandvn", function(args)
    DevianDB = nil
    DevianDB = {
      load_message = "All SavedVars wiped."
    }
    ReloadUI()
    end)
  self:RegisterChatCommand("resetdvn", function(args)
    for k,v in pairs(DevianDB) do
      if k ~= 'global' then
        DevianDB[k] = nil
      end
    end

    DevianDB.load_message = "Non-user SavedVars have been reset."
    for k,v in pairs(defaults) do
      DevianDB[k] = v
    end
    ReloadUI()
  end)
  local cmdlist = {
    ['dvn'] = ScanAddOnList,
    ['devian'] = ScanAddOnList,
    ['dvc'] = Console_Toggle,
  }
  for cmd, func in pairs(cmdlist) do
    self:RegisterChatCommand(cmd, func, true)
  end

  -- pull defaults
  if not _G.DevianDB then
    _G.DevianDB = defaults
  end
  db = _G.DevianDB
  self.tags = db.tags
  self.channelinfo = db.channels

  if not db[PLAYER_REALM] then
    db[PLAYER_REALM] = {[WORKSPACE_ON] = {}, [WORKSPACE_OFF] = {}}
  end

  if db.load_message then
    D:Print(db.load_message)
    db.load_message = nil
  end
  D.oldprint = getprinthandler()
  if not _G.oldprint then
    _G.oldprint = D.oldprint
  end

  -- Stop here in game mode
  if db.workspace == 1 then
    return
  end
  -----------------------------------------------------------------------
  self.db = db
  self.channels = db.channels
  self.max_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)
    self.max_channel = math.max(i, self.max_channel)
    self.num_channels = self.num_channels + 1
  end

  for i, channel in pairs(db.channels) do
    if type(channel.docked) == 'table' then
      oldprint('docking',i, unpack(channel.docked))
      self.DockFrame(i, unpack(channel.docked))
    end
  end

  if self.console[db.current_channel] then
    self.console[db.current_channel]:ToFront()
    -- bring the current channel to the front
  end
  setprinthandler(Message)
  print = function(...)
    _G.print('Dvn', ...)
  end
end