Skip to content

Instantly share code, notes, and snippets.

@nswarm
Created October 14, 2020 03:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nswarm/04746aa900d89d981b5889e13b281c28 to your computer and use it in GitHub Desktop.
Save nswarm/04746aa900d89d981b5889e13b281c28 to your computer and use it in GitHub Desktop.
Shadowlands 9.0.1 TipTac FIX: Replace everything in "World of Warcraft\_retail_\Interface\AddOns\TipTac\ttCore.lua"
local _G = getfenv(0);
local unpack = unpack;
local UnitName = UnitName;
local UnitExists = UnitExists;
local GetMouseFocus = GetMouseFocus;
local gtt = GameTooltip;
local wipe = wipe;
local tconcat = table.concat;
-- Addon
local modName = ...;
local tt = CreateFrame("Frame",modName,UIParent, BackdropTemplateMixin and "BackdropTemplate");
-- Global Chat Message Function
function AzMsg(msg) DEFAULT_CHAT_FRAME:AddMessage(tostring(msg):gsub("|1","|cffffff80"):gsub("|2","|cffffffff"),0.5,0.75,1.0); end
-- Config Data Variables
local cfg;
local TT_DefaultConfig = {
showUnitTip = true,
showStatus = true,
showGuildRank = false,
showTargetedBy = true,
showPlayerGender = false,
nameType = "title",
showRealm = "show",
showTarget = "last",
targetYouText = "<<YOU>>",
showBattlePetTip = true,
gttScale = 1,
updateFreq = 0.5,
enableChatHoverTips = false,
hidePvpText = true,
hideFactionText = false,
hideRealmText = false,
colorGuildByReaction = true,
colGuild = "|cff0080cc",
colSameGuild = "|cffff32ff",
colRace = "|cffffffff",
colLevel = "|cffc0c0c0",
colorNameByClass = false,
classColoredBorder = false,
reactText = false,
colReactText1 = "|cffc0c0c0",
colReactText2 = "|cffff0000",
colReactText3 = "|cffff7f00",
colReactText4 = "|cffffff00",
colReactText5 = "|cff00ff00",
colReactText6 = "|cff25c1eb",
colReactText7 = "|cff808080",
reactColoredBackdrop = false,
reactColoredBorder = false,
colReactBack1 = { 0.2, 0.2, 0.2 },
colReactBack2 = { 0.3, 0, 0 },
colReactBack3 = { 0.3, 0.15, 0 },
colReactBack4 = { 0.3, 0.3, 0 },
colReactBack5 = { 0, 0.3, 0.1 },
colReactBack6 = { 0, 0, 0.5 },
colReactBack7 = { 0.05, 0.05, 0.05 },
tipBackdropBG = "Interface\\Buttons\\WHITE8X8",
tipBackdropEdge = "Interface\\Tooltips\\UI-Tooltip-Border",
backdropEdgeSize = 14,
backdropInsets = 2.5,
tipColor = { 0.1, 0.1, 0.2 }, -- UI Default: For most: (0.1,0.1,0.2), World Objects?: (0,0.2,0.35)
tipBorderColor = { 0.3, 0.3, 0.4 }, -- UI Default: (1,1,1,1)
gradientTip = true,
gradientHeight = 36,
gradientColor = { 0.8, 0.8, 0.8, 0.2 },
modifyFonts = false,
fontFace = "", -- Set during VARIABLES_LOADED
fontSize = 12,
fontFlags = "",
fontSizeDeltaHeader = 2,
fontSizeDeltaSmall = -2,
classification_minus = "-%s ", -- New classification in MoP; Unsure what it's used for, but apparently the units have no mana. Example of use: The "Sha Haunts" early in the Horde's quests in Thunder Hold.
classification_trivial = "~%s ",
classification_normal = "%s ",
classification_elite = "+%s ",
classification_worldboss = "%s|r (Boss) ",
classification_rare = "%s|r (Rare) ",
classification_rareelite = "+%s|r (Rare) ",
overrideFade = true,
preFadeTime = 0.1,
fadeTime = 0.1,
hideWorldTips = true,
barFontFace = "", -- Set during VARIABLES_LOADED
barFontSize = 12,
barFontFlags = "OUTLINE",
barHeight = 6,
barTexture = "Interface\\TargetingFrame\\UI-StatusBar",
hideDefaultBar = true,
barsCondenseValues = false,
healthBar = true,
healthBarClassColor = true,
healthBarText = "value",
healthBarColor = { 0.3, 0.9, 0.3 },
manaBar = false,
manaBarText = "value",
manaBarColor = { 0.3, 0.55, 0.9 },
powerBar = false,
powerBarText = "value",
aurasAtBottom = false,
showBuffs = true,
showDebuffs = true,
selfAurasOnly = false,
auraSize = 20,
auraMaxRows = 2,
showAuraCooldown = true,
noCooldownCount = false,
iconRaid = true,
iconFaction = false,
iconCombat = false,
iconClass = false,
iconAnchor = "TOPLEFT",
iconSize = 24,
anchorWorldUnitType = "normal",
anchorWorldUnitPoint = "BOTTOMRIGHT",
anchorWorldTipType = "normal",
anchorWorldTipPoint = "BOTTOMRIGHT",
anchorFrameUnitType = "normal",
anchorFrameUnitPoint = "BOTTOMRIGHT",
anchorFrameTipType = "normal",
anchorFrameTipPoint = "BOTTOMRIGHT",
mouseOffsetX = 0,
mouseOffsetY = 0,
hideUFTipsInCombat = false,
hideAllTipsInCombat = false,
showHiddenTipsOnShift = false,
-- Talents
showTalents = true,
talentOnlyInParty = false,
talentFormat = 1,
talentCacheSize = 25,
inspectDelay = 0.2, -- The time delay for the scheduled inspection
inspectFreq = 2, -- How soon after an inspection are we allowed to inspect again?
-- ItemRef
if_enable = true,
if_infoColor = { 0.2, 0.6, 1 },
if_itemQualityBorder = true,
if_showAuraCaster = true,
if_showItemLevelAndId = false, -- Used to be true, but changed due to the itemLevel issues
if_showQuestLevelAndId = true,
if_showSpellIdAndRank = false,
if_showCurrencyId = true, -- Az: no option for this added to TipTac/options yet!
if_showAchievementIdAndCategory = false, -- Az: no option for this added to TipTac/options yet!
if_modifyAchievementTips = true,
if_showIcon = true,
if_smartIcons = true,
if_borderlessIcons = false,
if_iconSize = 42,
};
-- Tips modified by TipTac in appearance and scale, you can add to this list if you want to modify more tips.
-- Other addons can use TipTac:AddModifiedTip(tip,noHooks) to register their own tooltips if desired.
local TT_TipsToModify = {
"GameTooltip",
"ShoppingTooltip1",
"ShoppingTooltip2",
"ItemRefTooltip",
"ItemRefShoppingTooltip1",
"ItemRefShoppingTooltip2",
-- 3rd party addon tooltips
"AtlasLootTooltip",
"QuestHelperTooltip",
"QuestGuru_QuestWatchTooltip",
};
tt.tipsToModify = TT_TipsToModify;
-- Colors
local CLASS_COLORS = CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS;
local TT_ClassColorMarkup = {};
for classID, color in next, CLASS_COLORS do
TT_ClassColorMarkup[classID] = ("|cff%.2x%.2x%.2x"):format(color.r*255,color.g*255,color.b*255);
end
tt.ClassColorMarkup = TT_ClassColorMarkup;
-- Mirror Anchors
local TT_MirrorAnchors = { -- MirrorAnchorsVertical
TOP = "BOTTOM",
TOPLEFT = "TOPRIGHT",
TOPRIGHT = "TOPLEFT",
BOTTOM = "TOP",
BOTTOMLEFT = "BOTTOMRIGHT",
BOTTOMRIGHT = "BOTTOMLEFT",
LEFT = "RIGHT",
RIGHT = "LEFT",
CENTER = "CENTER",
};
tt.MirrorAnchors = TT_MirrorAnchors;
local TT_MirrorAnchorsSmart = { -- MirrorAnchorsCentered
TOPLEFT = "BOTTOMRIGHT",
TOPRIGHT = "BOTTOMLEFT",
BOTTOMLEFT = "TOPRIGHT",
BOTTOMRIGHT = "TOPLEFT",
};
tt.MirrorAnchorsSmart = TT_MirrorAnchorsSmart;
-- GTT Control Variables
local gtt_lastUpdate = 0; -- time since last update
local gtt_numLines = 0; -- number of lines at last check, if this differs from gtt:NumLines() an update should be performed. Only used for unit tips with extra padding.
local gtt_anchorType; -- valid types: normal/mouse/parent
local gtt_anchorPoint; -- standard UI anchor point
tt.xPadding = 0; -- x/y variables used to set the padding (+width, +height) for the GTT, reset to zero in OnTooltipCleared
tt.yPadding = 0;
-- Data Variables
local u = {};
local targetedByList;
tt.u = u;
-- Hi-jack the GTT backdrop table for our own evil needs
local tipBackdrop = TOOLTIP_BACKDROP_STYLE_DEFAULT;
tipBackdrop.backdropColor = CreateColor(1,1,1);
tipBackdrop.backdropBorderColor = CreateColor(1,1,1);
-- To ensure that the alpha channel is applied to the backdrop color, we have to cheat a bit, by pointing the GetRGB() function to GetRGBA().
tipBackdrop.backdropColor.GetRGB = ColorMixin.GetRGBA;
tipBackdrop.backdropBorderColor.GetRGB = ColorMixin.GetRGBA;
--------------------------------------------------------------------------------------------------------
-- MetaClass for Pushing Values Into Table --
--------------------------------------------------------------------------------------------------------
-- this class keeps track of the array count internally to avoid the constant
-- use of the length operator (#) recounting the array over and over.
local PushArray = {
__index = {
count = 0,
Clear = function(t) wipe(t); end,
Concat = function(t) return tconcat(t) end,
},
__newindex = function(t,k,v)
if (k == "next") then
t.count = (t.count + 1);
t.last = v;
elseif (k == "last") then
rawset(t,t.count,v);
if (v == nil) then
t.count = (t.count - 1);
end
else
rawset(t,k,v);
end
end,
}
-- returns the given table, or a new table with te PushArray metamethods
function tt:CreatePushArray(optTable)
return setmetatable(optTable or {},PushArray);
end
--------------------------------------------------------------------------------------------------------
-- Elements Framework --
--------------------------------------------------------------------------------------------------------
--[[
Element Events:
- OnLoad Variables has been loaded
- OnCleared Tooltip has been cleared
- OnApplyConfig Config settings needs to be applied
- OnPreStyleTip Before tooltip is being styled
- OnPostStyleTip After tooltip has been styled and have the final size
--]]
local elements = {};
tt.elements = elements;
function tt:RegisterElement(element,name)
element.name = name;
elements[#elements + 1] = element;
return element;
end
function tt:SendElementEvent(event,...)
for _, element in ipairs(elements) do
if (not element.disabled) and (element[event]) then
element[event](element,...);
end
end
end
--------------------------------------------------------------------------------------------------------
-- Anchor Creation & Events --
--------------------------------------------------------------------------------------------------------
tt:SetSize(114,24);
tt:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 } });
tt:SetBackdropColor(0.1,0.1,0.2,1);
tt:SetBackdropBorderColor(0.1,0.1,0.1,1);
tt:SetMovable(true);
tt:EnableMouse(true);
tt:SetToplevel(true);
tt:SetClampedToScreen(true);
tt:SetPoint("CENTER");
tt:Hide();
tt.text = tt:CreateFontString(nil,"ARTWORK","GameFontHighlight");
tt.text:SetText("TipTacAnchor");
tt.text:SetPoint("LEFT",6,0);
tt.close = CreateFrame("Button",nil,tt,"UIPanelCloseButton");
tt.close:SetSize(24,24);
tt.close:SetPoint("RIGHT");
-- Cursor Update -- Event only registered when the "hideWorldTips" option is ENABLED.
function tt:CURSOR_UPDATE(event)
if (gtt:IsShown()) and (gtt:IsOwned(UIParent)) and (not u.token) then
-- Restoring the text of the first line, is a workaround so that gatherer addons can get the name of nodes
local backup = GameTooltipTextLeft1:GetText();
gtt:Hide();
GameTooltipTextLeft1:SetText(backup);
end
end
-- Login [One-Time-Event] -- Initialize Level for difficulty coloring
function tt:PLAYER_LOGIN(event)
self.playerLevel = UnitLevel("player");
self:UnregisterEvent(event);
self[event] = nil;
end
-- Level Up -- Update Level for difficulty coloring to avoid excessively calling UnitLevel()
function tt:PLAYER_LEVEL_UP(event,newLevel)
self.playerLevel = newLevel;
end
-- Variables Loaded [One-Time-Event]
function tt:VARIABLES_LOADED(event)
self.isColorBlind = (GetCVar("colorblindMode") == "1");
-- Default Fonts
TT_DefaultConfig.fontFace = GameFontNormal:GetFont();
TT_DefaultConfig.barFontFace = NumberFontNormal:GetFont();
-- Init Config
if (not TipTac_Config) then
TipTac_Config = {};
end
cfg = setmetatable(TipTac_Config,{ __index = TT_DefaultConfig });
-- Default the bar texture if it no longer exists
GameTooltipStatusBar:SetStatusBarTexture(cfg.barTexture);
if (not GameTooltipStatusBar:GetStatusBarTexture()) then
cfg.barTexture = nil;
end
-- Position
if (cfg.left and cfg.top) then
self:ClearAllPoints();
self:SetPoint("TOPLEFT",UIParent,"BOTTOMLEFT",cfg.left,cfg.top);
else
self:Show();
-- Just set left and top here, in case the player just closes the anchor without moving, so it doesn't keep showing up when they log in
cfg.left, cfg.top = self:GetLeft(), self:GetTop();
end
-- Notify elements that we've loaded
self:SendElementEvent("OnLoad",cfg);
-- Hook Tips & Apply Settings
self:HookTips();
self:ApplySettings();
if (not targetedByList) then
targetedByList = self:CreatePushArray();
end
-- Cleanup
self:UnregisterEvent(event);
self[event] = nil;
end
-- Console Var Change
function tt:CVAR_UPDATE(event,var,value)
if (var == "USE_COLORBLIND_MODE") then
self.isColorBlind = (value == "1");
end
end
tt:SetScript("OnMouseDown",tt.StartMoving);
tt:SetScript("OnMouseUp",function(self) self:StopMovingOrSizing(); cfg.left, cfg.top = self:GetLeft(), self:GetTop(); end);
tt:SetScript("OnEvent",function(self,event,...) self[event](self,event,...); end);
tt:RegisterEvent("PLAYER_LOGIN");
tt:RegisterEvent("PLAYER_LEVEL_UP");
tt:RegisterEvent("VARIABLES_LOADED");
tt:RegisterEvent("CVAR_UPDATE");
--------------------------------------------------------------------------------------------------------
-- Slash Handling --
--------------------------------------------------------------------------------------------------------
_G["SLASH_"..modName.."1"] = "/tip";
_G["SLASH_"..modName.."2"] = "/tiptac";
SlashCmdList[modName] = function(cmd)
-- Extract Parameters
local param1, param2 = cmd:match("^([^%s]+)%s*(.*)$");
param1 = (param1 and param1:lower() or cmd:lower());
-- Options
if (param1 == "") then
local loaded, reason = LoadAddOn("TipTacOptions");
if (loaded) then
TipTacOptions:SetShown(not TipTacOptions:IsShown());
else
AzMsg("Could not open TicTac Options: |1"..tostring(reason).."|r. Please make sure the addon is enabled from the character selection screen.");
end
-- Show Anchor
elseif (param1 == "anchor") then
tt:SetShown(not tt:IsShown());
-- Reset settings
elseif (param1 == "reset") then
wipe(cfg);
tt:ApplySettings();
AzMsg("All |2"..modName.."|r settings has been reset to their default values.");
-- Invalid or No Command
else
UpdateAddOnMemoryUsage();
AzMsg(format("----- |2%s|r |1%s|r ----- |1%.2f |2kb|r -----",modName,GetAddOnMetadata(modName,"Version"),GetAddOnMemoryUsage(modName)));
AzMsg("The following |2parameters|r are valid for this addon:");
AzMsg(" |2anchor|r = Shows the anchor where the tooltip appears");
AzMsg(" |2reset|r = Resets all settings back to their default values");
end
end
--------------------------------------------------------------------------------------------------------
-- Settings --
--------------------------------------------------------------------------------------------------------
-- Setup Gradient Tip
local function SetupGradientTip(tip)
local g = tip.ttGradient;
if (not cfg.gradientTip) then
if (g) then
g:Hide();
end
return;
elseif (not g) then
g = tip:CreateTexture();
g:SetColorTexture(1,1,1,1);
tip.ttGradient = g;
end
g:SetGradientAlpha("VERTICAL",0,0,0,0,unpack(cfg.gradientColor));
g:SetPoint("TOPLEFT",cfg.backdropInsets,cfg.backdropInsets * -1);
g:SetPoint("BOTTOMRIGHT",tip,"TOPRIGHT",cfg.backdropInsets * -1,-cfg.gradientHeight);
g:Show();
end
-- Apply Settings
function tt:ApplySettings()
-- Hide World Tips Instantly
if (cfg.hideWorldTips) then
self:RegisterEvent("CURSOR_UPDATE");
else
self:UnregisterEvent("CURSOR_UPDATE");
end
-- Set Backdrop -- not setting "tileSize" as we dont tile
tipBackdrop.bgFile = cfg.tipBackdropBG;
tipBackdrop.edgeFile = cfg.tipBackdropEdge;
tipBackdrop.tile = false;
tipBackdrop.tileEdge = false;
tipBackdrop.edgeSize = cfg.backdropEdgeSize;
tipBackdrop.insets.left = cfg.backdropInsets;
tipBackdrop.insets.right = cfg.backdropInsets;
tipBackdrop.insets.top = cfg.backdropInsets;
tipBackdrop.insets.bottom = cfg.backdropInsets;
tipBackdrop.backdropColor:SetRGBA(unpack(cfg.tipColor));
tipBackdrop.backdropBorderColor:SetRGBA(unpack(cfg.tipBorderColor));
-- Set Scale, Backdrop, Gradient
for _, tip in ipairs(TT_TipsToModify) do
if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
if (tip == WorldMapTooltip) and (WorldMapTooltip.BackdropFrame) then
tip:SetScale(cfg.gttScale);
tip = WorldMapTooltip.BackdropFrame; -- workaround for the worldmap faux tip
elseif (tip == QuestScrollFrame) and (QuestScrollFrame.StoryTooltip) then
tip = QuestScrollFrame.StoryTooltip;
end
SetupGradientTip(tip);
tip:SetScale(cfg.gttScale);
tt:ApplyBackdrop(tip);
end
end
-- GameTooltip Font Templates
if (cfg.modifyFonts) then
GameTooltipText:SetFont(cfg.fontFace,cfg.fontSize,cfg.fontFlags);
GameTooltipHeaderText:SetFont(cfg.fontFace,cfg.fontSize + cfg.fontSizeDeltaHeader,cfg.fontFlags);
GameTooltipTextSmall:SetFont(cfg.fontFace,cfg.fontSize + cfg.fontSizeDeltaSmall,cfg.fontFlags);
end
-- inform elements that settings has been applied
self:SendElementEvent("OnApplyConfig",cfg);
end
-- Applies the backdrop, color and border color. The GTT will often reset these internally.
function tt:ApplyBackdrop(tip)
SharedTooltip_SetBackdropStyle(tip, tipBackdrop);
end
--------------------------------------------------------------------------------------------------------
-- TipTac Functions --
--------------------------------------------------------------------------------------------------------
-- Anchor any given frame to mouse position
function tt:AnchorFrameToMouse(frame)
local x, y = GetCursorPosition();
local effScale = frame:GetEffectiveScale();
frame:ClearAllPoints();
frame:SetPoint(gtt_anchorPoint,UIParent,"BOTTOMLEFT",(x / effScale + cfg.mouseOffsetX),(y / effScale + cfg.mouseOffsetY));
end
-- Removes lines from the tooltip which are unwanted, such as "PvP", "Alliance", "Horde"
-- Also removes the coalesced realm line(s), which I am unsure is still in BfA?
function tt:RemoveUnwantedLines(tip)
for i = 2, tip:NumLines() do
local line = _G["GameTooltipTextLeft"..i];
local text = line:GetText();
if (cfg.hidePvpText) and (text == PVP_ENABLED) or (cfg.hideFactionText and (text == FACTION_ALLIANCE or text == FACTION_HORDE)) then
line:SetText(nil);
end
if (cfg.hideRealmText) and (text == " ") then
local nextLine = _G["GameTooltipTextLeft"..(i + 1)];
if (nextLine) then
local nextText = nextLine:GetText();
if (nextText == COALESCED_REALM_TOOLTIP) or (nextText == INTERACTIVE_REALM_TOOLTIP) then
line:SetText(nil);
nextLine:SetText(nil);
end
end
end
end
end
-- Get Reaction Index
--[[
1 = Tapped
2 = Hostile
3 = Caution
4 = Neutral
5 = Friendly NPC or PvP Player
6 = Friendly Player
7 = Dead
--]]
function tt:GetUnitReactionIndex(unit)
-- Deadies
if (UnitIsDead(unit)) then
return 7;
-- Players (Can't rely on UnitPlayerControlled() alone, since it always returns nil on units out of range)
elseif (UnitIsPlayer(unit) or UnitPlayerControlled(unit)) then
if (UnitCanAttack(unit,"player")) then
return (UnitCanAttack("player",unit) and 2 or 3);
elseif (UnitCanAttack("player",unit)) then
return 4;
elseif (UnitIsPVP(unit) and not UnitIsPVPSanctuary(unit) and not UnitIsPVPSanctuary("player")) then
return 5;
else
return 6;
end
-- Tapped -- The UNIT_FACTION event is fired when this changes (not for mouseover however) -- [7.0.3] API change: Tap functions has been condensed into a single function
elseif (UnitIsTapDenied(unit)) and not (UnitPlayerControlled(unit)) then
return 1;
-- Others
else
local reaction = (UnitReaction(unit,"player") or 3);
return (reaction > 5 and 5) or (reaction < 2 and 2) or (reaction);
end
end
-- Add "Targeted By" line
function tt:AddTargetedBy(u)
local numGroup = GetNumGroupMembers();
if (not numGroup) or (numGroup <= 1) then
return;
end
local inRaid = IsInRaid();
for i = 1, numGroup do
local unit = (inRaid and "raid"..i or "party"..i);
if (UnitIsUnit(unit.."target",u.token)) and (not UnitIsUnit(unit,"player")) then
local _, classID = UnitClass(unit);
targetedByList.next = TT_ClassColorMarkup[classID];
targetedByList.next = UnitName(unit);
targetedByList.next = "|r, ";
end
end
if (targetedByList.count > 0) then
targetedByList.last = nil; -- remove last comma
gtt:AddLine(" ",nil,nil,nil,1);
local line = _G["GameTooltipTextLeft"..gtt:NumLines()];
line:SetFormattedText("Targeted By (|cffffffff%d|r): %s",(targetedByList.count + 1) / 3,targetedByList:Concat());
targetedByList:Clear();
end
end
-- Apply Unit Appearance
-- Styling the unit tooltip happens in three stages, 1) pre-style 2) style 3) post-style
function tt:ApplyUnitAppearance(tip,u,first)
-- obtain unit properties
if (first) then
u.isPlayer = UnitIsPlayer(u.token);
u.class, u.classID = UnitClass(u.token);
end
u.reactionIndex = self:GetUnitReactionIndex(u.token);
--------------------------------------------------
-- [1] Send style event BEFORE tip has been styled
self:SendElementEvent("OnPreStyleTip",tip,u,first);
--------------------------------------------------
-- Backdrop Color: Reaction
if (cfg.reactColoredBackdrop) then
tip:SetBackdropColor(unpack(cfg["colReactBack"..u.reactionIndex]));
end
-- Backdrop Border Color: By Class or by Reaction
if (cfg.classColoredBorder) and (u.isPlayer) then
if (first) then
local color = CLASS_COLORS[u.classID] or CLASS_COLORS["PRIEST"];
tip:SetBackdropBorderColor(color.r,color.g,color.b);
end
elseif (cfg.reactColoredBorder) then -- Az: this will override the classColoredBorder config, perhaps have that option take priority instead?
tip:SetBackdropBorderColor(unpack(cfg["colReactBack"..u.reactionIndex]));
end
-- Remove Unwanted Lines
if (first) and (cfg.hidePvpText or cfg.hideFactionText or cfg.hideRealmText) then
self:RemoveUnwantedLines(tip);
end
--------------------------------------------------
-- [2] Send the actual TipTac Appearance Styling event
if (cfg.showUnitTip) then
self:SendElementEvent("OnStyleTip",tip,u,first);
end
--------------------------------------------------
if (first) and (cfg.showTargetedBy) then
self:AddTargetedBy(u);
end
-- Calling tip:Show() here ensures that the tooltip has the correct dimensions.
-- However, forcing it to show here could cause issues, and we should properly wait
-- until OnShow before we post the final OnPostStyleTip event.
--printf("[%.2f] %-24s %d x %d",GetTime(),"PreShow",tip:GetWidth(),tip:GetHeight())
tip:Show();
--printf("[%.2f] %-24s %d x %d",GetTime(),"PostShow",tip:GetWidth(),tip:GetHeight())
--------------------------------------------------
-- [3] Send style event AFTER tip has been styled
self:SendElementEvent("OnPostStyleTip",tip,u,first);
--------------------------------------------------
-- Apply tooltip padding, if any
if (tt.xPadding ~= 0) or (tt.yPadding ~= 0) then
tip:SetPadding(tt.xPadding,tt.yPadding);
gtt_numLines = gtt:NumLines();
end
end
--------------------------------------------------------------------------------------------------------
-- GameTooltip Script Hooks --
--------------------------------------------------------------------------------------------------------
--[[
GameTooltip Construction Call Order -- Tested for BfA (18.07.24)
This is apparently the order in which the GTT construsts unit tips
------------------------------------------------------------------
- GameTooltip_SetDefaultAnchor()
- GTT.OnTooltipSetUnit() -- GetUnit() becomes valid here
- GTT:Show() -- Will Resize the tip
- GTT.OnShow() -- Event triggered in response to the Show() function
- GTT.OnTooltipCleared() -- Tooltip has been cleared and is ready to show new information, doesn't mean it's hidden
--]]
-- table with GameTooltip scripts to hook into (k = scriptName, v = hookFunction)
local gttScriptHooks = {};
-- FadeOut constants
local FADE_ENABLE = 1;
local FADE_BLOCK = 2;
-- Get The Anchor Position Depending on the Tip Content and Parent Frame
-- Do not depend on "u.token" here, as it might not have been cleared yet!
-- Checking "mouseover" here isn't ideal due to actionbars, it will sometimes return true because of selfcast.
local function GetAnchorPosition()
local mouseFocus = GetMouseFocus();
local isUnit = UnitExists("mouseover") or (mouseFocus and mouseFocus.GetAttribute and mouseFocus:GetAttribute("unit")); -- Az: GetAttribute("unit") here is bad, as that will find things like buff frames too
local var = "anchor"..(mouseFocus == WorldFrame and "World" or "Frame")..(isUnit and "Unit" or "Tip");
return cfg[var.."Type"], cfg[var.."Point"];
end
-- EventHook: OnShow
function gttScriptHooks:OnShow()
-- Anchor GTT to Mouse -- Az: Initial mouse anchoring is now being done in GTT_SetDefaultAnchor (remove if there are no issues)
-- gtt_anchorType, gtt_anchorPoint = GetAnchorPosition();
-- if (gtt_anchorType == "mouse") and (self.default) then
-- local gttAnchor = self:GetAnchorType();
-- if (gttAnchor ~= "ANCHOR_CURSOR") and (gttAnchor ~= "ANCHOR_CURSOR_RIGHT") then
-- tt:AnchorFrameToMouse(self);
-- end
-- end
-- Ensures that default anchored world frame tips have the proper color, their internal function seems to set them to a dark blue color
-- Tooltips from world objects that change cursor seems to also require this. (Tested in 8.0/BfA)
if (self:IsOwned(UIParent)) and (not self:GetUnit()) then
self:SetBackdropColor(unpack(cfg.tipColor));
end
end
-- EventHook: OnUpdate
function gttScriptHooks:OnUpdate(elapsed)
-- This ensures that mouse anchored world frame tips have the proper color, their internal function seems to set them to a dark blue color
local gttAnchor = self:GetAnchorType();
if (gttAnchor == "ANCHOR_CURSOR") or (gttAnchor == "ANCHOR_CURSOR_RIGHT") then
self:SetBackdropColor(unpack(cfg.tipColor));
self:SetBackdropBorderColor(unpack(cfg.tipBorderColor));
return;
-- Anchor GTT to Mouse
elseif (gtt_anchorType == "mouse") and (self.default) then
tt:AnchorFrameToMouse(self);
end
-- WoD: This background color reset, from OnShow(), has been copied down here. It seems resetting the color in OnShow() wasn't enough, as the color changes after the tip is being shown
if (self:IsOwned(UIParent)) and (not self:GetUnit()) then
self:SetBackdropColor(unpack(cfg.tipColor));
end
-- Fadeout / Update Tip if Showing a Unit
-- Do not allow (fadeOut == FADE_BLOCK), as that is only for non overridden fadeouts
if (u.token) and (self.fadeOut ~= FADE_BLOCK) then
gtt_lastUpdate = (gtt_lastUpdate + elapsed);
if (self.fadeOut) then
self:Show(); -- Overrides self:FadeOut()
if (gtt_lastUpdate > cfg.fadeTime + cfg.preFadeTime) then
self.fadeOut = nil;
self:Hide();
elseif (gtt_lastUpdate > cfg.preFadeTime) then
self:SetAlpha(1 - (gtt_lastUpdate - cfg.preFadeTime) / cfg.fadeTime);
end
-- This is only really needed for worldframe unit tips, as when u.token == "mouseover", the GTT:FadeOut() function is not called
elseif (not UnitExists(u.token)) then
self:FadeOut();
elseif (cfg.updateFreq > 0) then
local gttCurrentLines = self:NumLines();
-- If number of lines differ from last time, force an update. This became an issue in 5.4 as the coalesced realm text is added after the initial Show(). This might also fix some incompatibilities with other addons.
if (gtt_lastUpdate > cfg.updateFreq) or (gttCurrentLines ~= gtt_numLines) then
gtt_numLines = gttCurrentLines;
gtt_lastUpdate = 0;
tt:ApplyUnitAppearance(gtt,u);
end
end
end
end
-- EventHook: OnTooltipSetUnit
function gttScriptHooks:OnTooltipSetUnit()
-- Hides the tip in combat if one of those options are set. Also checks if the Shift key is pressed, and cancels hiding of the tip (if that option is set, that is)
if (cfg.hideAllTipsInCombat or cfg.hideUFTipsInCombat and self:GetOwner() ~= UIParent) and (not cfg.showHiddenTipsOnShift or not IsShiftKeyDown()) and (UnitAffectingCombat("player")) then
self:Hide();
return;
end
local _, unit = self:GetUnit();
-- Concated unit tokens such as "targettarget" cannot be returned as the unit by GTT:GetUnit(),
-- and it will return as "mouseover", but the "mouseover" unit is still invalid at this point for those unitframes!
-- To overcome this problem, we look if the mouse is over a unitframe, and if that unitframe has a unit attribute set?
if (not unit) then
local mouseFocus = GetMouseFocus();
unit = mouseFocus and mouseFocus.GetAttribute and mouseFocus:GetAttribute("unit");
end
-- A mage's mirror images sometimes doesn't return a unit, this would fix it
if (not unit) and (UnitExists("mouseover")) then
unit = "mouseover";
end
-- Sometimes when you move your mouse quicky over units in the worldframe, we can get here without a unit
if (not unit) then
self:Hide();
return;
end
-- A "mouseover" unit is better to have as we can then safely say the tip should no longer show when it becomes invalid. Harder to say with a "party2" unit.
-- This also helps fix the problem that "mouseover" units aren't valid for group members out of range, a bug that has been in WoW since 3.0.2 I think.
if (UnitIsUnit(unit,"mouseover")) then
unit = "mouseover";
end
-- Workaround for OnTooltipCleared not having fired
self.fadeOut = nil; -- Az: Sometimes this wasn't getting reset, the fact a cleanup isn't performed at this point, now that it was moved to "OnTooltipCleared" is bad, so this is a fix [8.0/BfA/18.08.12 - Still not cleared 100% of the time]
-- We're done, apply appearance
u.token = unit;
tt:ApplyUnitAppearance(self,u,true); -- called with "first" arg to true
end
-- EventHook: OnTooltipCleared -- This will clean up auras, bars, raid icon and vars for the gtt when we aren't showing a unit
function gttScriptHooks:OnTooltipCleared()
-- WoD: resetting the back/border color seems to be a necessary action, otherwise colors may stick when showing the next tooltip thing (world object tips)
-- BfA: The tooltip now also clears the backdrop in adition to color and bordercolor, so set it again here
tt:ApplyBackdrop(self);
-- remove the padding that might have been set to fit health/power bars
tt.xPadding = 0;
tt.yPadding = 0;
--self:SetPadding(tt.xPadding,tt.yPadding); -- [8.1.5] disabled, as it causes issues -- Look into GTT.recalculatePadding & GameTooltip_CalculatePadding()
-- wipe the vars
wipe(u);
gtt_lastUpdate = 0;
gtt_numLines = 0;
self.fadeOut = nil;
-- post cleared event to elements
tt:SendElementEvent("OnCleared",self);
end
-- OnHide Script -- Used to default the background and border color
--function gttScriptHooks:OnHide()
-- tt:ApplyBackdrop(self);
--end
--------------------------------------------------------------------------------------------------------
-- GameTooltip Other Hooks --
--------------------------------------------------------------------------------------------------------
-- HOOK: GTT:FadeOut -- This allows us to check when the tip is fading out.
local gttFadeOut = gtt.FadeOut;
gtt.FadeOut = function(self,...)
if (not u.token) or (not cfg.overrideFade) then
self.fadeOut = FADE_BLOCK; -- Don't allow the OnUpdate handler to run the fadeout/update code
gttFadeOut(self,...);
elseif (cfg.preFadeTime == 0 and cfg.fadeTime == 0) then
self:Hide();
else
self.fadeOut = FADE_ENABLE;
gtt_lastUpdate = 0;
end
end
-- Resolves the given table array of string names into their global objects
local function ResolveGlobalNamedObjects(tipTable)
local resolved = {};
for index, tipName in ipairs(tipTable) do
-- lookup the global object from this name, assign false if nonexistent, to preserve the table entry
local tip = (_G[tipName] or false);
-- Check if this object has already been resolved. This can happen for thing like AtlasLoot, which sets AtlasLootTooltip = GameTooltip
if (resolved[tip]) then
tip = false;
elseif (tip) then
resolved[tip] = index;
end
-- Assign the resolved object or false back into the table array
tipTable[index] = tip;
end
end
-- HOOK: GameTooltip_SetDefaultAnchor
local function GTT_SetDefaultAnchor(tooltip,parent)
-- Return if no tooltip or parent
if (not tooltip or not parent) then
return;
end
-- Get the current anchoring type and point based on the frame under the mouse and anchor settings
gtt_anchorType, gtt_anchorPoint = GetAnchorPosition();
-- We only hook the GameTooltip, so if any other tips use the default anchor with mouse anchoring,
-- we have to just set it here statically, as we wont have the OnUpdate hooked for that tooltip
if (tooltip ~= gtt) and (gtt_anchorType == "mouse") then
tooltip:SetOwner(parent,"ANCHOR_CURSOR_RIGHT",cfg.mouseOffsetX,cfg.mouseOffsetY);
else
-- Since TipTac handles all the anchoring, we want to use "ANCHOR_NONE" here
tooltip:SetOwner(parent,"ANCHOR_NONE");
tooltip:ClearAllPoints();
if (gtt_anchorType == "mouse") then
-- Although we anchor the frame continuously in OnUpdate, we must anchor it initially here to avoid flicker on the first frame its being shown
tt:AnchorFrameToMouse(tooltip);
elseif (gtt_anchorType == "parent") and (parent ~= UIParent) then
-- anchor to the opposite edge of the parent frame
tooltip:SetPoint(TT_MirrorAnchorsSmart[gtt_anchorPoint] or TT_MirrorAnchors[gtt_anchorPoint],parent,gtt_anchorPoint);
else
-- "normal" anchor or fallback for "parent" in case its UIParent
tooltip:SetPoint(gtt_anchorPoint,tt);
end
end
-- "default" will flag the tooltip as having been anchored using the default anchor
tooltip.default = 1;
end
-- Function to loop through tips to modify and hook
function tt:HookTips()
-- Hooks needs to be applied as late as possible during load, as we want to try and be the
-- last addon to hook "OnTooltipSetUnit" so we always have a "completed" tip to work on
for scriptName, hookFunc in next, gttScriptHooks do
gtt:HookScript(scriptName,hookFunc);
end
-- Resolve the TipsToModify strings into actual objects
ResolveGlobalNamedObjects(TT_TipsToModify);
-- hook their OnHide script -- Az: OnHide hook disabled for now
-- for index, tipName in ipairs(TT_TipsToModify) do
-- if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
-- tip:HookScript("OnHide",gttScriptHooks.OnHide);
-- end
-- end
-- Replace GameTooltip_SetDefaultAnchor (For Re-Anchoring) -- Patch 3.2 made this function secure
hooksecurefunc("GameTooltip_SetDefaultAnchor",GTT_SetDefaultAnchor);
-- Clear this function as it's not needed anymore
self.HookTips = nil;
end
-- Allows other mods to "register" tooltips or frames to be modified by TipTac
function tt:AddModifiedTip(tip,noHooks)
if (type(tip) == "string") then
tip = _G[tip];
end
if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
-- if this tooltip is already modified, abort
if (tIndexOf(TT_TipsToModify,tip)) then
return;
end
TT_TipsToModify[#TT_TipsToModify + 1] = tip;
-- Az: Disabled the OnHide hook, unsure if it needs to be re-enabled,
-- if (not noHooks) then
-- tip:HookScript("OnHide",gttScriptHooks.OnHide);
-- end
-- Only apply settings if "cfg" has been initialised, meaning after VARIABLES_LOADED.
-- If AddModifiedTip() is called earlier, settings will be applied for all tips once VARIABLES_LOADED is fired anyway.
if (cfg) then
self:ApplySettings();
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment