Quantcast

-- rTooltip: core
-- zork, 2018

-----------------------------
-- Variables
-----------------------------

local A, L = ...

local unpack, type = unpack, type
local RAID_CLASS_COLORS, FACTION_BAR_COLORS, ICON_LIST = RAID_CLASS_COLORS, FACTION_BAR_COLORS, ICON_LIST
local GameTooltip, GameTooltipStatusBar = GameTooltip, GameTooltipStatusBar
local GameTooltipTextRight1, GameTooltipTextRight2, GameTooltipTextRight3, GameTooltipTextRight4, GameTooltipTextRight5, GameTooltipTextRight6, GameTooltipTextRight7, GameTooltipTextRight8 = GameTooltipTextRight1, GameTooltipTextRight2, GameTooltipTextRight3, GameTooltipTextRight4, GameTooltipTextRight5, GameTooltipTextRight6, GameTooltipTextRight7, GameTooltipTextRight8
local GameTooltipTextLeft1, GameTooltipTextLeft2, GameTooltipTextLeft3, GameTooltipTextLeft4, GameTooltipTextLeft5, GameTooltipTextLeft6, GameTooltipTextLeft7, GameTooltipTextLeft8 = GameTooltipTextLeft1, GameTooltipTextLeft2, GameTooltipTextLeft3, GameTooltipTextLeft4, GameTooltipTextLeft5, GameTooltipTextLeft6, GameTooltipTextLeft7, GameTooltipTextLeft8
local classColorHex, factionColorHex = {}, {}
local Hider = CreateFrame("Frame", nil, UIParent) Hider:Hide()

-----------------------------
-- Config
-----------------------------

local cfg = {}
cfg.textColor = {0.4,0.4,0.4}
cfg.bossColor = {1,0,0}
cfg.eliteColor = {1,0,0.5}
cfg.rareeliteColor = {1,0.5,0}
cfg.rareColor = {1,0.5,0}
cfg.levelColor = {0.8,0.8,0.5}
cfg.deadColor = {0.5,0.5,0.5}
cfg.targetColor = {1,0.5,0.5}
cfg.guildColor = {1,0,1}
cfg.afkColor = {0,1,1}
cfg.scale = 0.95
cfg.fontFamily = STANDARD_TEXT_FONT
cfg.alwaysCompare = true
cfg.backdrop = {
  bgFile = "Interface\\Buttons\\WHITE8x8",
  bgColor = {0.08,0.08,0.1,0.92},
  edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  borderColor = {0.1,0.1,0.1,0.6},
  itemBorderColorAlpha = 0.9,
  azeriteBorderColor = {1,0.3,0,0.9},
  tile = false,
  tileEdge = false,
  tileSize = 16,
  edgeSize = 16,
  insets = {left=3, right=3, top=3, bottom=3}
}

--pos can be either a point table or a anchor string
--cfg.pos = { "BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -10, 180 }
cfg.pos = "ANCHOR_NONE" --"ANCHOR_CURSOR"

-----------------------------
-- Functions
-----------------------------

-- Tooltip skin
local fakeBg = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
fakeBg:SetBackdrop({ bgFile = cfg.backdrop.bgFile, edgeFile = cfg.backdrop.bgFile, edgeSize = 1 })
local function __GetBackdrop() return fakeBg:GetBackdrop() end
local function __GetBackdropColor() return 0, 0, 0, .7 end
local function __GetBackdropBorderColor() return 0, 0, 0 end

local function GetHexColor(color)
  if color.r then
    return ("%.2x%.2x%.2x"):format(color.r*255, color.g*255, color.b*255)
  else
    local r,g,b,a = unpack(color)
    return ("%.2x%.2x%.2x"):format(r*255, g*255, b*255)
  end
end

local function GetTarget(unit)
  if UnitIsUnit(unit, "player") then
    return ("|cffff0000%s|r"):format("<YOU>")
  elseif UnitIsPlayer(unit, "player") then
    local _, class = UnitClass(unit)
    return ("|cff%s%s|r"):format(classColorHex[class], UnitName(unit))
  elseif UnitReaction(unit, "player") then
    return ("|cff%s%s|r"):format(factionColorHex[UnitReaction(unit, "player")], UnitName(unit))
  else
    return ("|cffffffff%s|r"):format(UnitName(unit))
  end
end

local function OnTooltipSetUnit(self)
  local unitName, unit = self:GetUnit()
  if not unit then return end
  --color tooltip textleft2..8
  GameTooltipTextLeft2:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft3:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft4:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft5:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft6:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft7:SetTextColor(unpack(cfg.textColor))
  GameTooltipTextLeft8:SetTextColor(unpack(cfg.textColor))
  --position raidicon
  local raidIconIndex = GetRaidTargetIndex(unit)
  if raidIconIndex then
   GameTooltipTextLeft1:SetText(("%s %s"):format(ICON_LIST[raidIconIndex].."14|t", unitName))
  end
  if not UnitIsPlayer(unit) then
    --unit is not a player
    --color textleft1 and statusbar by faction color
    local reaction = UnitReaction(unit, "player")
    if reaction then
      local color = FACTION_BAR_COLORS[reaction]
      if color then
        cfg.barColor = color
        GameTooltipStatusBar:SetStatusBarColor(color.r,color.g,color.b)
        GameTooltipTextLeft1:SetTextColor(color.r,color.g,color.b)
      end
    end
    --color textleft2 by classificationcolor
    local unitClassification = UnitClassification(unit)
    local levelLine
    if string.find(GameTooltipTextLeft2:GetText() or "empty", "%a%s%d") then
      levelLine = GameTooltipTextLeft2
    elseif string.find(GameTooltipTextLeft3:GetText() or "empty", "%a%s%d") then
      GameTooltipTextLeft2:SetTextColor(unpack(cfg.guildColor)) --seems like the npc has a description, use the guild color for this
      levelLine = GameTooltipTextLeft3
    end
    if levelLine then
      local l = UnitLevel(unit)
      local color = GetCreatureDifficultyColor((l > 0) and l or 999)
      levelLine:SetTextColor(color.r,color.g,color.b)
    end
    if unitClassification == "worldboss" or UnitLevel(unit) == -1 then
      self:AppendText(" |cffff0000{B}|r")
      GameTooltipTextLeft2:SetTextColor(unpack(cfg.bossColor))
    elseif unitClassification == "rare" then
      self:AppendText(" |cffff9900{R}|r")
    elseif unitClassification == "rareelite" then
      self:AppendText(" |cffff0000{R+}|r")
    elseif unitClassification == "elite" then
      self:AppendText(" |cffff6666{E}|r")
    end
  else
    --unit is any player
    local _, unitClass = UnitClass(unit)
    --color textleft1 and statusbar by class color
    local color = RAID_CLASS_COLORS[unitClass]
    cfg.barColor = color
    GameTooltipStatusBar:SetStatusBarColor(color.r,color.g,color.b)
    GameTooltipTextLeft1:SetTextColor(color.r,color.g,color.b)
    --color textleft2 by guildcolor
    local unitGuild = GetGuildInfo(unit)
    if unitGuild then
      GameTooltipTextLeft2:SetText("<"..unitGuild..">")
      GameTooltipTextLeft2:SetTextColor(unpack(cfg.guildColor))
    end
    local levelLine = unitGuild and GameTooltipTextLeft3 or GameTooltipTextLeft2
    local l = UnitLevel(unit)
    local color = GetCreatureDifficultyColor((l > 0) and l or 999)
    levelLine:SetTextColor(color.r,color.g,color.b)
    --afk?
    if UnitIsAFK(unit) then
      self:AppendText((" |cff%s<AFK>|r"):format(cfg.afkColorHex))
    end
  end
  --dead?
  if UnitIsDeadOrGhost(unit) then
    GameTooltipTextLeft1:SetTextColor(unpack(cfg.deadColor))
  end
  --target line
  if (UnitExists(unit.."target")) then
    GameTooltip:AddDoubleLine(("|cff%s%s|r"):format(cfg.targetColorHex, "Target"),GetTarget(unit.."target") or "Unknown")
  end
end

local function SetItemBorderColor(tooltip)
	local link = select(2, tooltip:GetItem())
	local r, g, b
	local backdrop = tooltip.Backdrop

	if backdrop then
		if link then
			local quality = select(3, GetItemInfo(link))

			if quality then
				r, g, b = GetItemQualityColor(quality)
			else
				r, g, b = unpack(cfg.backdrop.borderColor)
			end

			backdrop:SetBackdropBorderColor(r, g, b)
		else
			backdrop:SetBackdropBorderColor(unpack(cfg.backdrop.borderColor))
		end
	end
end

local function OnTooltipSetItem(self)
  local _, link = self:GetItem()

  if link then
    local id = "|cFFCA3C3CID|r "..link:match(":(%w+)")
    local level = GetDetailedItemLevelInfo(link) or 1
    local text = "|cFFCA3C3C"..ITEM_LEVEL_ABBR.."|r "..level

    self:AddLine(" ")
    self:AddDoubleLine(id, text)
  end

  SetItemBorderColor(self)
end

local function Kill(self)
	if (self.UnregisterAllEvents) then
		self:UnregisterAllEvents()
		self:SetParent(Hider)
	else
		self.Show = self.Hide
	end

	self:Hide()
end

local function StripTextures(self, Kill)
	for i = 1, self:GetNumRegions() do
		local Region = select(i, self:GetRegions())
		if (Region and Region:GetObjectType() == "Texture") then
			if (Kill and type(Kill) == "boolean") then
				Region:Kill()
			elseif (Region:GetDrawLayer() == Kill) then
				Region:SetTexture(nil)
			elseif (Kill and type(Kill) == "string" and Region:GetTexture() ~= Kill) then
				Region:SetTexture(nil)
			else
				Region:SetTexture(nil)
			end
		end
	end
end

local function SetBackdropStyle(self, style)
  if self.TopOverlay then self.TopOverlay:Hide() end
  if self.BottomOverlay then self.BottomOverlay:Hide() end
  StripTextures(self)
  self:SetBackdrop(cfg.backdrop)
  self:SetBackdropColor(unpack(cfg.backdrop.bgColor))
  local _, itemLink = self:GetItem()
  if itemLink then
    local azerite = false--C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(itemLink) or C_AzeriteItem.IsAzeriteItemByID(itemLink) or false
    local _, _, itemRarity = GetItemInfo(itemLink)
    local r,g,b = 1,1,1
    if itemRarity then r,g,b = GetItemQualityColor(itemRarity) end
    --use azerite coloring or item rarity
    if azerite and cfg.backdrop.azeriteBorderColor then
      self:SetBackdropBorderColor(unpack(cfg.backdrop.azeriteBorderColor))
    else
      self:SetBackdropBorderColor(r,g,b,cfg.backdrop.itemBorderColorAlpha)
    end
  else
    --no item, use default border
    self:SetBackdropBorderColor(unpack(cfg.backdrop.borderColor))
  end
end

local function CreateBackdrop(self)
	if self.Backdrop then return end

	self.Backdrop = CreateFrame("Frame", nil, self, "BackdropTemplate")
	self.Backdrop:SetAllPoints()
	self.Backdrop:SetFrameLevel(self:GetFrameLevel())

	self.Backdrop:SetBackdrop(cfg.backdrop)
	self.Backdrop:SetBackdropColor(unpack(cfg.backdrop.bgColor))
	self.Backdrop:SetBackdropBorderColor(unpack(cfg.backdrop.borderColor))
end

local function SetStatusBarColor(self,r,g,b)
  if not cfg.barColor then return end
  if r == cfg.barColor.r and g == cfg.barColor.g and b == cfg.barColor.b then return end
  self:SetStatusBarColor(cfg.barColor.r,cfg.barColor.g,cfg.barColor.b)
end

local function SetDefaultAnchor(self,parent)
  if not cfg.pos then return end
  if type(cfg.pos) == "string" then
    self:SetOwner(parent, cfg.pos)
  else
    self:SetOwner(parent, "ANCHOR_NONE")
    self:ClearAllPoints()
    self:SetPoint(unpack(cfg.pos))
  end
end

local function ResetBorderColor(self)
	if self ~= GameTooltip then
		return
	end

	if self.Backdrop then
		self.Backdrop:SetBackdropBorderColor(unpack(cfg.backdrop.borderColor))
	end
end

local function SetUnitBorderColor(self)
	local unit = self
	local r, g, b
	local GameTooltip = GameTooltip

	local reaction = unit and UnitReaction(unit, "player")
	local player = unit and UnitIsPlayer(unit)
	local friend = unit and UnitIsFriend("player", unit)

	if player and friend then
		local class = select(2, UnitClass(unit))
		local color = RAID_CLASS_COLORS[class]

		r, g, b = color.r, color.g, color.b

		GameTooltip.Backdrop:SetBackdropBorderColor(r, g, b)
	elseif reaction then
		local color = FACTION_BAR_COLORS[reaction]

		r, g, b = color.r, color.g, color.b

		GameTooltip.Backdrop:SetBackdropBorderColor(r, g, b)
	end
end

local function SetCompareItemBorderColor(anchorFrame)
	for i = 1, 2 do
		local shoptip = _G["ShoppingTooltip"..i]

		if shoptip:IsShown() then
			local frameLevel = GameTooltip:GetFrameLevel()
			local item = shoptip:GetItem()

			if frameLevel == shoptip:GetFrameLevel() then
				shoptip:SetFrameLevel(i + 1)
			end

			if item then
				local quality = select(3, GetItemInfo(item))

				if quality then
					local r, g, b = GetItemQualityColor(quality)

					shoptip.Backdrop:SetBackdropBorderColor(r, g, b, cfg.backdrop.itemBorderColorAlpha)
				else
					shoptip.Backdrop:SetBackdropBorderColor(unpack(cfg.backdrop.borderColor))
				end
			end
		end
	end
end

local function HideBackdrop(frame)
  if frame.NineSlice then frame.NineSlice:SetAlpha(0) end
  if frame.SetBackdrop then frame:SetBackdrop(nil) end
end

local function SkinTooltip(self)
	if self:IsForbidden() then
		return
	end

	if (not self.isSkinned) then
    HideBackdrop(self)
    self:DisableDrawLayer("BACKGROUND")
		StripTextures(self)
		CreateBackdrop(self)

    if self.GetBackdrop then
			self.GetBackdrop = __GetBackdrop
			self.GetBackdropColor = __GetBackdropColor
			self.GetBackdropBorderColor = __GetBackdropBorderColor
		end

		self.isSkinned = true
	end
end

local function OnTooltipCleared(self)
	if self:IsForbidden() then return end

	GameTooltip_ClearMoney(self)
	GameTooltip_ClearStatusBars(self)
	GameTooltip_ClearProgressBars(self)
	GameTooltip_ClearWidgetSet(self)
end

-----------------------------
-- Init
-----------------------------

--hex class colors
for class, color in next, RAID_CLASS_COLORS do
  classColorHex[class] = GetHexColor(color)
  --if (class == 'SHAMAN') then
  --  classColorHex[class] = '0070de'
  --end
end
--hex reaction colors
--for idx, color in next, FACTION_BAR_COLORS do
for i = 1, #FACTION_BAR_COLORS do
  factionColorHex[i] = GetHexColor(FACTION_BAR_COLORS[i])
end

cfg.targetColorHex = GetHexColor(cfg.targetColor)
cfg.afkColorHex = GetHexColor(cfg.afkColor)

GameTooltipHeaderText:SetFont(cfg.fontFamily, 14, "NONE")
GameTooltipHeaderText:SetShadowOffset(1,-2)
GameTooltipHeaderText:SetShadowColor(0,0,0,0.75)
GameTooltipText:SetFont(cfg.fontFamily, 12, "NONE")
GameTooltipText:SetShadowOffset(1,-2)
GameTooltipText:SetShadowColor(0,0,0,0.75)
Tooltip_Small:SetFont(cfg.fontFamily, 11, "NONE")
Tooltip_Small:SetShadowOffset(1,-2)
Tooltip_Small:SetShadowColor(0,0,0,0.75)

--gametooltip statusbar
GameTooltipStatusBar:ClearAllPoints()
GameTooltipStatusBar:SetPoint("LEFT",5,0)
GameTooltipStatusBar:SetPoint("RIGHT",-5, 0)
GameTooltipStatusBar:SetPoint("TOP",0,-2.5)
GameTooltipStatusBar:SetHeight(4)
--gametooltip statusbar bg
GameTooltipStatusBar.bg = GameTooltipStatusBar:CreateTexture(nil,"BACKGROUND",nil,-8)
GameTooltipStatusBar.bg:SetAllPoints()
GameTooltipStatusBar.bg:SetColorTexture(1,1,1)
GameTooltipStatusBar.bg:SetVertexColor(0,0,0,0.5)

--GameTooltipStatusBar:SetStatusBarColor()
hooksecurefunc(GameTooltipStatusBar, "SetStatusBarColor", SetStatusBarColor)
--GameTooltip_SetDefaultAnchor()
if cfg.pos then hooksecurefunc("GameTooltip_SetDefaultAnchor", SetDefaultAnchor) end
--GameTooltip_SetBackdropStyle
-- hooksecurefunc("GameTooltip_SetBackdropStyle", SetBackdropStyle)
--SharedTooltip_SetBackdropStyle
-- hooksecurefunc("SharedTooltip_SetBackdropStyle", SetBackdropStyle)

-- hooksecurefunc("GameTooltip_UnitColor", SetUnitBorderColor)
hooksecurefunc("GameTooltip_ShowCompareItem", SetCompareItemBorderColor)
hooksecurefunc("GameTooltip_ClearMoney", ResetBorderColor)

--OnTooltipSetUnit
GameTooltip:HookScript("OnTooltipSetUnit", OnTooltipSetUnit)
--OnTooltipSetItem
GameTooltip:HookScript("OnTooltipSetItem", OnTooltipSetItem)

-- loop over tooltips
local tooltips = { GameTooltip,ShoppingTooltip1,ShoppingTooltip2,ItemRefTooltip,ItemRefShoppingTooltip1,ItemRefShoppingTooltip2,WorldMapTooltip,
WorldMapCompareTooltip1,WorldMapCompareTooltip2,SmallTextTooltip,EmbeddedItemTooltip }
for i, tooltip in next, tooltips do
  tooltip:SetScale(cfg.scale)
  SkinTooltip(tooltip)
  if tooltip:HasScript("OnTooltipCleared") then
    -- tooltip:HookScript("OnTooltipCleared", SetBackdropStyle)
    tooltip:HookScript("OnTooltipCleared", OnTooltipCleared)
  end
end

-- SkinTooltip(GameTooltip)
-- SkinTooltip(ItemRefTooltip)
-- SkinTooltip(EmbeddedItemTooltip)
-- SkinTooltip(ShoppingTooltip1)
-- SkinTooltip(ShoppingTooltip2)

--loop over menues
local menues = {
  DropDownList1MenuBackdrop,
  DropDownList2MenuBackdrop,
}
for i, menu in next, menues do
  menu:SetScale(cfg.scale)
end

-- compare items
if cfg.alwaysCompare then
  SetCVar("alwaysCompareItems", 1)
else
  SetCVar("alwaysCompareItems", 0)
end

--spellid line

--func TooltipAddSpellID
local function TooltipAddSpellID(self,spellid)
  if not spellid then return end
  self:AddDoubleLine("|cff0099ffspellid|r",spellid)
  self:Show()
end

--hooksecurefunc GameTooltip SetUnitBuff
hooksecurefunc(GameTooltip, "SetUnitBuff", function(self,...)
  TooltipAddSpellID(self,select(10,UnitBuff(...)))
end)

--hooksecurefunc GameTooltip SetUnitDebuff
hooksecurefunc(GameTooltip, "SetUnitDebuff", function(self,...)
  TooltipAddSpellID(self,select(10,UnitDebuff(...)))
end)

--hooksecurefunc GameTooltip SetUnitAura
hooksecurefunc(GameTooltip, "SetUnitAura", function(self,...)
  TooltipAddSpellID(self,select(10,UnitAura(...)))
end)

--hooksecurefunc SetItemRef
hooksecurefunc("SetItemRef", function(link)
  local type, value = link:match("(%a+):(.+)")
  if type == "spell" then
    TooltipAddSpellID(ItemRefTooltip,value:match("([^:]+)"))
  end
end)

--HookScript GameTooltip OnTooltipSetSpell
GameTooltip:HookScript("OnTooltipSetSpell", function(self)
  TooltipAddSpellID(self,select(2,self:GetSpell()))
end)