You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1281 lines
46 KiB

local _, addon = ...
local TOOLTIP_NAME = "NarciGameTooltip";
local floor = math.floor;
local gsub = string.gsub;
local format = string.format;
local match = string.match;
local strtrim = strtrim;
local _G = _G;
local NarciAPI = NarciAPI;
local FadeFrame = NarciFadeUI.Fade;
local GetItemStats = GetItemStats;
local GetItemSpell = GetItemSpell;
local GetItemInfo = GetItemInfo;
local GetItemInfoInstant = GetItemInfoInstant;
local GetDetailedItemLevelInfo = GetDetailedItemLevelInfo;
local GetInventoryItemLink = GetInventoryItemLink;
local GetInventoryItemDurability = GetInventoryItemDurability;
local Model_ApplyUICamera = Model_ApplyUICamera;
local C_TransmogCollection = C_TransmogCollection;
local C_Item = C_Item;
local GetSlotVisualInfo = C_Transmog.GetSlotVisualInfo;
local EJ_SetSearch = EJ_SetSearch;
local GetItemQualityColor = NarciAPI.GetItemQualityColor;
local GetSlotVisualID = NarciAPI.GetSlotVisualID;
local SharedTooltipDelay = addon.SharedTooltipDelay;
local TransmogDataProvider = addon.TransmogDataProvider;
local SetModelByUnit = addon.TransitionAPI.SetModelByUnit;
local ItemCacheUtil = addon.ItemCacheUtil;
local PT_EQUIPMENT_SETS = gsub(EQUIPMENT_SETS, ".cFF.+", "");
local PT_ITEM_SOULBOUND = ITEM_SOULBOUND;
local PT_DURABILITY = "|TInterface\\AddOns\\Narcissus\\Art\\GameTooltip\\ExclamationMark:14:14:2:-2:32:32:0:32:0:32:255:109:15|t "..(DURABILITY_TEMPLATE or "Durability %d / % d");
local PT_DPS_TEMPLATE = gsub(DPS_TEMPLATE, "%%s", "%%.1f");
local ENCHANTED_TOOLTIP_LINE = ENCHANTED_TOOLTIP_LINE or "Enchanted: %s";
local GenericTooltip, EquipmentTooltip;
local function IsColorRelevant(r, g, b)
return not (r == 1 and g == 0.5 and b == 1)
end
local function IsTextRelevant(text)
return not (strtrim(text) == "" or match(text, "<", 1) or match(text, PT_EQUIPMENT_SETS, 1) or match(text, PT_ITEM_SOULBOUND, 1) )
end
--[[
1, 0.13, 0.13 --red
0, 1, 0 --green
1, 1, 1 --white
1, 0.5, 1 --pink transmog
GetSpellBaseCooldown
GetItemSpell
C_TradeSkillUI.GetItemCraftedQualityByItemInfo(itemLink)
--]]
local function Round(a)
return tonumber(format("%.2f", floor(a*100+0.5)*0.01 ))
end
local function RoundColor(r, g, b)
return Round(r), Round(g), Round(b)
end
local function VoidFunc(self)
end
local function AppendItemIDToGameTooltip(self)
if not self.GetItem then return end;
local name, itemLink = self:GetItem();
if itemLink then
local itemID = match(itemLink, "item:(%d+)");
local spellID;
name, spellID = GetItemSpell(itemLink);
if spellID then
self:AddDoubleLine(format("|cff545454ItemID|r |cff808080%s|r", itemID), format("|cff545454SpellID|r |cff808080%s|r", spellID));
else
self:AddLine(format("|cff545454ID|r |cff808080%s|r", itemID));
end
end
end
local GENERIC_SETUP_FUNC = VoidFunc;
local GameTooltip_ClearMoney = GameTooltip_ClearMoney or VoidFunc;
if addon.IsDragonflight() and TooltipDataHandlerMixin then
NarciGameTooltipMixin = CreateFromMixins(TooltipDataHandlerMixin);
else
NarciGameTooltipMixin = {};
end
function NarciGameTooltipMixin:OnLoad()
GenericTooltip = self;
NarciAPI.NineSliceUtil.SetUpBackdrop(self, "phantom", 0, 20/255, 24/255, 28/255);
NarciAPI.NineSliceUtil.SetUpBorder(self, "shadowHugeR0", 0);
local p = 8;
self:SetPadding(p, p, p, p);
self.leftTexts = {};
self.rightTexts = {};
self:SetFrameStrata("TOOLTIP");
self:SetFixedFrameStrata(true);
end
function NarciGameTooltipMixin:OnShow()
end
function NarciGameTooltipMixin:OnHide()
SharedTooltipDelay:Kill();
self:SetScript("OnUpdate", nil);
end
function NarciGameTooltipMixin:OnTooltipCleared()
GameTooltip_ClearMoney(self);
SharedTooltip_ClearInsertedFrames(self);
end
function NarciGameTooltipMixin:OnSizeChanged(w, h)
end
function NarciGameTooltipMixin:UpdateTextColor()
local r, g, b;
local text, count;
local numLines = self:NumLines();
for i = 1, numLines do
if not self.leftTexts[i] then
self.leftTexts[i] = _G[TOOLTIP_NAME.."TextLeft"..i];
end
if self.leftTexts[i] then
r, g, b = RoundColor(self.leftTexts[i]:GetTextColor());
if r == 1 and g == 1 and b == 1 then
self.leftTexts[i]:SetTextColor(0.8863, 0.8863, 0.8863);
elseif r == 0 and g == 1 and b == 0 then --green
self.leftTexts[i]:SetTextColor(0.4353, 0.8039, 0.4784);
elseif r == 1 and g == 0.13 and b == 0.13 then
self.leftTexts[i]:SetTextColor(119/255, 119/255, 119/255);
elseif r == 1 and g == 0.82 and b == 0 then --yellow
self.leftTexts[i]:SetTextColor(222/255, 179/255, 0/255);
text = self.leftTexts[i]:GetText();
if text then
text, count = gsub(text, "|cffffffff", "|cffe2e2e2");
text, count = gsub(text, "|cFFFFFFFF", "|cffe2e2e2");
--if count > 0 then
self.leftTexts[i]:SetText(text);
--end
end
end
end
if not self.rightTexts[i] then
self.rightTexts[i] = _G[TOOLTIP_NAME.."TextRight"..i];
end
if self.rightTexts[i] then
r, g, b = RoundColor(self.rightTexts[i]:GetTextColor());
if r == 1 and g == 1 and b == 1 then
self.rightTexts[i]:SetTextColor(0.8863, 0.8863, 0.8863);
end
end
end
end
function NarciGameTooltipMixin:AnchorToSlotButton(slotButton, offsetX, offsetY)
self:ClearAllPoints();
self:SetOwner(slotButton, "ANCHOR_NONE");
offsetX = offsetX or 0;
offsetY = offsetY or 0;
if slotButton.isRight then
self:SetPoint("TOPRIGHT", slotButton, "TOPLEFT", -offsetX, offsetY);
else
self:SetPoint("TOPLEFT", slotButton, "TOPRIGHT", offsetX, offsetY);
end
end
function NarciGameTooltipMixin:SetFromSlotButton(slotButton, offsetX, offsetY, delay)
if delay then
SharedTooltipDelay:Setup(slotButton, delay, self.SetFromSlotButton, self, slotButton, offsetX, offsetY);
else
self:AnchorToSlotButton(slotButton, offsetX, offsetY);
self:SetInventoryItem("player", slotButton.slotID, nil, true);
GENERIC_SETUP_FUNC(self);
self:Show();
self:FadeIn();
end
end
function NarciGameTooltipMixin:SetTransmogFromSlotButton(slotButton, offsetX, offsetY)
self:AnchorToSlotButton(slotButton, offsetX, offsetY);
if slotButton.hyperlink then
self:SetHyperlink(slotButton.hyperlink);
self:Show();
self:FadeIn();
end
end
function NarciGameTooltipMixin:SetItemLinkAndAnchor(itemLink, anchorTo, offsetX, offsetY)
if itemLink and anchorTo then
self:AnchorToSlotButton(anchorTo, offsetX, offsetY);
self:SetHyperlink(itemLink);
GENERIC_SETUP_FUNC(self);
self:Show();
self:FadeIn();
end
end
function NarciGameTooltipMixin:HideTooltip()
self:Hide();
SharedTooltipDelay:Kill();
end
function NarciGameTooltipMixin:FadeIn()
self:StopFading();
self.AnimIn:Play();
end
local function TooltipFadeOut_OnUpdate(self, elapsed)
self.alpha = self.alpha - 4 * elapsed;
if self.alpha <= 0 then
self:StopFading();
self:Hide();
else
self:SetAlpha(self.alpha);
end
end
function NarciGameTooltipMixin:FadeOut()
if self:IsVisible() then
self.AnimIn:Stop();
self.alpha = 1;
self:SetScript("OnUpdate", TooltipFadeOut_OnUpdate);
end
end
function NarciGameTooltipMixin:StopFading()
self.AnimIn:Stop();
self:SetScript("OnUpdate", nil);
self.alpha = nil;
end
---- Equipment Tooltip (for displaying gears/mogs in character frame) ----
local function OnModelLoaded(self)
if self.cameraID then
Model_ApplyUICamera(self, self.cameraID);
end
end
local STATS_COLOR = {
[0] = {0.5, 0.5, 0.5},
[1] = {0.8863, 0.8863, 0.8863}, --white
[2] = {0.4353, 0.8039, 0.4784}, --green
[3] = {1, 0.82, 0}, --bliz yellow
[4] = {0.9412, 0.3490, 0.3490}, --red
[5] = {0.8275, 0.7804, 0.5529}, --flavor text
[6] = {1, 0.4275, 0.0588}, --Low durability
[7] = {0.8610, 0.8610, 0.4549}, --Light Yellow: For equipped set items 1, 1, 0.6
};
local TOOLTIP_PADDING = 24;
local MIN_TEXT_WIDTH = 240 - 2 * TOOLTIP_PADDING;
local SEG_INSETS = 12;
local DIVIDER_HEIGHT = 0;
local MODEL_SIZE_RATIO = 0.7647;
local function GetColorByIndex(index)
return unpack(STATS_COLOR[index]);
end
local function CompareWidth(fontString, lastMax)
local width = fontString:GetWrappedWidth();
return ((width > lastMax) and width) or lastMax
end
local STATS_ORDER = {
{"RESISTANCE0_NAME", "%d ", 1}, --Armor
{"ITEM_MOD_BLOCK_RATING_SHORT", "%d ", 1}, --Block not in the itemstats payload but will be inserted later
{"ITEM_MOD_AGILITY_SHORT", "+%d ", 1},
{"ITEM_MOD_STRENGTH_SHORT", "+%d ", 1},
{"ITEM_MOD_INTELLECT_SHORT", "+%d ", 1},
{"ITEM_MOD_STAMINA_SHORT", "+%d ", 1},
{"ITEM_MOD_CRIT_RATING_SHORT", "+%d ", 2, "crit"},
{"ITEM_MOD_HASTE_RATING_SHORT", "+%d ", 2, "haste"},
{"ITEM_MOD_MASTERY_RATING_SHORT", "+%d ", 2, "mastery"},
{"ITEM_MOD_VERSATILITY", "+%d ", 2, "versatility"},
{"ITEM_MOD_CR_STURDINESS_SHORT", "", 2},
{"ITEM_MOD_CR_SPEED_SHORT", "+%d ", 2},
{"ITEM_MOD_CR_LIFESTEAL_SHORT", "+%d ", 2},
{"ITEM_MOD_CR_AVOIDANCE_SHORT", "+%d ", 2},
};
local function AppendItemID(tooltip)
local spellID = tooltip:GetItemSpellID();
if spellID then
tooltip:AddDoubleLine(format("|cff545454ItemID|r |cff808080%s|r", tooltip.itemID), format("|cff545454SpellID|r |cff808080%s|r", spellID), 1, 1, 1, (tooltip.numLines > 0 and - SEG_INSETS));
else
tooltip:AddLine(format("|cff545454ID|r |cff808080%s|r", tooltip.itemID), 1, 1, 1, (tooltip.numLines > 0 and - SEG_INSETS));
end
end
local ADDTIONAL_SETUP_FUNC = VoidFunc;
local ItemDropLocation = {};
function ItemDropLocation:SetDropLocation(itemID, locationText)
if not self.items then
self.items = {};
end
self.items[itemID] = locationText or "";
end
function ItemDropLocation:GetItemDropLocation(itemID)
if itemID and self.items then
return self.items[itemID];
end
end
function ItemDropLocation:IsItemCached(itemID)
return itemID and self.items and self.items[itemID];
end
function ItemDropLocation:DoesItemHaveDropLocation(itemID)
return self:IsItemCached(itemID) and self.items[itemID] ~= ""
end
local ItemLoader = CreateFrame("Frame");
local function ItemLoader_OnUpdate(self, elapased)
self.t = self.t + elapased;
if self.t >= 0 then
self:SetScript("OnUpdate", nil);
self.t = nil;
EquipmentTooltip:OnDataLoaded();
end
end
function ItemLoader:QueryData(itemLink, itemID)
self.t = -0.2;
self.pendingItemID = itemID;
self:SetScript("OnUpdate", ItemLoader_OnUpdate);
C_Item.RequestLoadItemDataByID(itemLink);
end
function ItemLoader:LoadItemData(link, itemID, forceUpdateItemData)
if forceUpdateItemData or (not ItemCacheUtil:IsItemDataCached(itemID)) then
if C_Item.DoesItemExistByID(link) then
self:QueryData(link, itemID);
end
else
if self.pendingItemID then
self.pendingItemID = nil;
self:SetScript("OnUpdate", nil);
end
end
end
NarciEquipmentTooltipMixin = {};
function NarciEquipmentTooltipMixin:OnLoad()
EquipmentTooltip = self;
local FRAME_WIDTH = 320;
local padding = TOOLTIP_PADDING;
local textWidth = FRAME_WIDTH - 2 * padding;
self.textWidthDefault = textWidth;
self.textWidthNoModel = FRAME_WIDTH - 40 - 2 * padding;
self.textWidth = self.textWidthNoModel;
self:SetEmbededFrameWidth(self.textWidth);
self.SpellFrame.isActive = true;
self.SpellFrame.InactiveAlert:SetTextColor(GetColorByIndex(4));
self.SpellFrame:SetCooldownTextColor(GetColorByIndex(1));
NarciAPI.NineSliceUtil.SetUpBorder(self, "shadowHugeR0", 0);
NarciAPI.NineSliceUtil.SetUpBackdrop(self, "phantom", 0, 20/255, 24/255, 28/255);
self.leftTexts = {};
self.rightTexts = {};
self:ClearLines();
self.transmogLocation = CreateFromMixins(TransmogLocationMixin);
self.padding = padding;
self.headerPadding = padding + SEG_INSETS;
self.HeaderFrame.ItemName:ClearAllPoints();
self.HeaderFrame.ItemLevel:ClearAllPoints();
self.HeaderFrame.ItemType:ClearAllPoints();
self.HeaderFrame.LevelSubText:ClearAllPoints();
self.HeaderFrame.ItemName:SetPoint("TOPLEFT", self.HeaderFrame, "TOPLEFT", padding, -padding);
self.HeaderFrame.ItemLevel:SetPoint("TOPLEFT", self.HeaderFrame.ItemName, "BOTTOMLEFT", 0, -2);
self.HeaderFrame.ItemType:SetPoint("TOPLEFT", self.HeaderFrame.ItemLevel, "BOTTOMLEFT", 0, -2);
self.HeaderFrame.ItemType:SetTextColor(GetColorByIndex(1));
self.HeaderFrame.LevelSubText:SetPoint("TOPLEFT", self.HeaderFrame.ItemLevel, "TOPRIGHT", 3, -2);
self.HeaderFrame.LevelSubText:SetTextColor(GetColorByIndex(1));
self.HeaderFrame.ItemName:SetWidth(self.textWidthDefault - 78);
self.HeaderFrame.ItemName:SetShadowOffset(2, -2);
self.HeaderFrame.ItemLevel:SetShadowOffset(4, -4);
self.AttributeFrame:SetPoint("TOPLEFT", self.HeaderFrame, "BOTTOMLEFT", padding, -SEG_INSETS - DIVIDER_HEIGHT);
self.AttributeFrame:SetPoint("TOPRIGHT", self.HeaderFrame, "BOTTOMRIGHT", -padding, -SEG_INSETS - DIVIDER_HEIGHT);
self.ItemModel:SetUseTransmogSkin(true); --not self.usePlayerSkin
self.ItemModel:SetAutoDress(false);
self.ItemModel:SetKeepModelOnHide(true);
self.ItemModel:SetDoBlend(false);
self.ItemModel:Undress();
self.ItemModel:FreezeAnimation(0, 0, 0);
self.ItemModel:SetUseTransmogChoices(true);
self.ItemModel:SetObeyHideInTransmogFlag(true);
self.ItemModel:SetScript("OnModelLoaded", OnModelLoaded);
self.ItemModel:SetModelDrawLayer("BACKGROUND", 1);
self:SetFrameStrata("TOOLTIP");
self:SetFixedFrameStrata(true);
local alwaysShown = true;
self.HotkeyFrame = CreateFrame("Frame", nil, self, "NarciHotkeyNotificationTemplate");
self.HotkeyFrame:SetPoint("BOTTOM", self, "TOP", 0, 8);
self.HotkeyFrame:SetKey(NARCI_MODIFIER_ALT, "LeftButton", Narci.L["Swap items"], alwaysShown);
self.HotkeyFrame:SetIgnoreParentScale(true);
self.HotkeyFrame:Show();
addon.ModuleManager:AddGamePadCallbackWidget(self);
NarciAPI.InitializeModelLight(self.ItemModel);
end
function NarciEquipmentTooltipMixin:OnShow()
end
function NarciEquipmentTooltipMixin:OnHide()
SharedTooltipDelay:Kill();
end
function NarciEquipmentTooltipMixin:EvaluateMaxWidth(width)
if width > self.maxWidth then
self.maxWidth = width;
end
end
function NarciEquipmentTooltipMixin:SetEmbededFrameWidth(width)
self.SpellFrame:SetFrameWidth(width);
self.GemFrame:SetFrameWidth(width);
end
function NarciEquipmentTooltipMixin:AddLine(text, r, g, b, offsetY)
if not text then return end
local n = self.numLines + 1;
self.numLines = n;
offsetY = offsetY or -4;
if not self.leftTexts[n] then
self.leftTexts[n] = self.AttributeFrame:CreateFontString(nil, "ARTWORK", self.textFont);
self.leftTexts[n]:SetSpacing(2);
self.leftTexts[n]:SetJustifyH("LEFT");
end
self.leftTexts[n]:ClearAllPoints();
if self.bottomObject then
self.leftTexts[n]:SetPoint("TOPLEFT", self.bottomObject, "BOTTOMLEFT", 0, offsetY);
else
self.leftTexts[n]:SetPoint("TOPLEFT", self.AttributeFrame, "TOPLEFT", 0, offsetY);
end
self.leftTexts[n]:SetWidth(self.textWidth);
self.leftTexts[n]:SetText(text);
self.leftTexts[n]:SetTextColor(r or 0.8863, g or 0.8863, b or 0.8863, 1);
self.leftTexts[n]:Show();
self.maxWidth = CompareWidth(self.leftTexts[n], self.maxWidth);
self.bottomObject = self.leftTexts[n];
end
function NarciEquipmentTooltipMixin:IsBottomObjectFontString()
return self.bottomObject and self.bottomObject:IsObjectType("FontString")
end
function NarciEquipmentTooltipMixin:AddDoubleLine(text1, text2, r, g, b, offsetY)
if not text1 then return end
local n = self.numLines + 1;
local p = self.numRightLines + 1;
self.numLines = n;
self.numRightLines = p;
offsetY = offsetY or -4;
if not self.leftTexts[n] then
self.leftTexts[n] = self.AttributeFrame:CreateFontString(nil, "ARTWORK", self.textFont);
self.leftTexts[n]:SetSpacing(2);
self.leftTexts[n]:SetJustifyH("LEFT");
end
self.leftTexts[n]:ClearAllPoints();
if self.bottomObject then
self.leftTexts[n]:SetPoint("TOPLEFT", self.bottomObject, "BOTTOMLEFT", 0, offsetY);
else
self.leftTexts[n]:SetPoint("TOPLEFT", self.AttributeFrame, "TOPLEFT", 0, offsetY);
end
self.leftTexts[n]:SetWidth(self.textWidth);
self.leftTexts[n]:SetText(text1);
self.leftTexts[n]:SetTextColor(r or 0.8863, g or 0.8863, b or 0.8863);
self.leftTexts[n]:Show();
self.bottomObject = self.leftTexts[n];
if not self.rightTexts[p] then
self.rightTexts[p] = self.AttributeFrame:CreateFontString(nil, "ARTWORK", self.textFont);
self.rightTexts[p]:SetSpacing(2);
self.rightTexts[p]:SetJustifyH("RIGHT");
end
self.rightTexts[p]:ClearAllPoints();
self.rightTexts[p]:SetWidth(self.textWidth);
self.rightTexts[p]:SetPoint("RIGHT", self.AttributeFrame, "RIGHT", 0, 0);
self.rightTexts[p]:SetPoint("TOP", self.leftTexts[n], "TOP", 0, 0);
self.rightTexts[p]:SetText(text2);
self.rightTexts[p]:SetTextColor(r or 0.8863, g or 0.8863, b or 0.8863);
self.rightTexts[p]:Show();
local width = self.leftTexts[n]:GetWrappedWidth() + self.rightTexts[p]:GetWrappedWidth() + 20;
if width > self.maxWidth then
self.maxWidth = width
end
end
function NarciEquipmentTooltipMixin:ClearLines()
self.numLines = 0;
self.numRightLines = 0;
self.maxWidth = 0;
self.bottomObject = nil;
self.baseSourceID = nil;
self.baseVisualID = nil;
self.itemID = nil;
self.itemIcon = nil;
self.itemName = nil;
self.itemLink = nil;
for i = 1, #self.leftTexts do
self.leftTexts[i]:Hide();
self.leftTexts[i]:SetText(nil);
end
for i = 1, #self.rightTexts do
self.rightTexts[i]:Hide();
self.rightTexts[i]:SetText(nil);
end
self.HeaderFrame.ItemLevel:SetText(nil);
self.HeaderFrame.LevelSubText:SetText(nil);
self.GemFrame:Clear();
self.SpellFrame:Clear();
end
function NarciEquipmentTooltipMixin:InsertFrame(embededFrame)
embededFrame:ClearAllPoints();
if self.bottomObject then
embededFrame:SetPoint("TOPLEFT", self.bottomObject, "BOTTOMLEFT", 0, -SEG_INSETS);
else
embededFrame:SetPoint("TOPLEFT", self.AttributeFrame, "TOPLEFT", 0, 0);
end
self.bottomObject = embededFrame;
end
function NarciEquipmentTooltipMixin:AddBlankLine()
self:AddLine(" ");
end
function NarciEquipmentTooltipMixin:AddRows(rows, colorIndex, prefix, padFirstLine)
colorIndex = colorIndex or 1;
local r, g, b;
if prefix then
for i = 1, #rows do
r, g, b = GetColorByIndex( (rows[i][2] and colorIndex) or 0 );
if i == 1 then
self:AddLine(prefix.. rows[i][1], r, g, b, (padFirstLine and -SEG_INSETS));
else
self:AddLine(prefix.. rows[i][1], r, g, b);
end
end
else
for i = 1, #rows do
r, g, b = GetColorByIndex( (rows[i][2] and colorIndex) or 0 );
if i == 1 then
self:AddLine(rows[i][1], r, g, b, (padFirstLine and -SEG_INSETS));
else
self:AddLine(rows[i][1], r, g, b);
end
end
end
end
function NarciEquipmentTooltipMixin:SetInventoryItem(slotID)
self.transmogLocation:Set(slotID, 0, 0);
self.slotID = slotID;
self:ClearLines();
self:SetUseTransmogLayout(false);
local link = GetInventoryItemLink("player", slotID);
if link then
local itemData, requestEmbededData = NarciAPI.GetCompleteItemDataFromSlot(slotID);
self:DisplayItemData(link, itemData, slotID, nil, nil, requestEmbededData);
itemData = nil;
else
self:Hide();
end
end
function NarciEquipmentTooltipMixin:DisplayItemData(link, itemData, slotID, visualID, sourceID, forceUpdateItemData)
--link: the itemlink, itemData: data obatined by scanning tooltip, slotID: if the item is an inventory item (equipped)
link = string.match(link, "(item:[%-?%d:]+)");
local itemID, itemType, itemSubType, itemEquipLoc, icon, classID, subclassID = GetItemInfoInstant(link);
ItemLoader:LoadItemData(link, itemID, forceUpdateItemData);
local quality = link and C_Item.GetItemQualityByID(link);
if quality then
self.HeaderFrame.ItemName:SetTextColor( GetItemQualityColor(quality) );
end
local itemName = GetItemInfo(link);
local itemLevel = GetDetailedItemLevelInfo(link);
self.HeaderFrame.ItemName:SetText(itemName);
self.HeaderFrame.ItemLevel:SetText(itemLevel);
self.HeaderFrame.ItemIcon:SetTexture(icon);
self.HeaderFrame.ItemIcon:SetVertexColor(0.6, 0.6, 0.6);
self.itemID = itemID;
self.itemName = itemName;
self.itemIcon = icon;
self.isWeapon = classID == 2;
local validForTransmog = visualID or NarciAPI.IsSlotValidForTransmog(slotID);
if validForTransmog ~= self.showItemModel then
if validForTransmog then
self.textWidth = self.textWidthDefault;
else
self.textWidth = self.textWidthNoModel;
end
self.showItemModel = validForTransmog
self:SetEmbededFrameWidth(self.textWidth);
end
if itemData and itemData.itemType then
itemSubType = itemData.itemType; --the original itemSubType is plural, so use the item type displayed on the GameTooltip instead
end
if itemEquipLoc then
if classID == 4 and subclassID == 0 then
--Neck, rings, etc.
self.HeaderFrame.ItemType:SetText(_G[itemEquipLoc]);
else
self.HeaderFrame.ItemType:SetText(_G[itemEquipLoc] .." · ".. itemSubType);
end
else
self.HeaderFrame.ItemType:SetText(itemSubType);
end
if itemData then
local levelSubtext;
if itemData.context then
levelSubtext = itemData.context;
end
if itemData.upgradeString then
levelSubtext = itemData.upgradeString;
elseif itemData.upgradeLevel then
levelSubtext = format("%s/%s", itemData.upgradeLevel[1], itemData.upgradeLevel[2]);
end
if levelSubtext and itemData.fullyUpgradedItemLevel then
local level1, level2 = match(levelSubtext, "(%d)/(%d)");
if level1 and level2 and level1 ~= level2 then
levelSubtext = levelSubtext.." |cff808080("..itemData.fullyUpgradedItemLevel..")|r";
end
end
self.HeaderFrame.LevelSubText:SetText(levelSubtext);
if itemData.craftingQuality then
local qualityTexture = self.HeaderFrame.CraftingQualityIcon;
local craftingQuality = itemData.craftingQuality;
local qualityAtlas = format("Professions-Icon-Quality-Tier%d-Small", craftingQuality);
qualityTexture:ClearAllPoints();
local offsetY;
if craftingQuality == 2 then
qualityTexture:SetSize(18, 18);
offsetY = 2;
elseif craftingQuality == 3 then
qualityTexture:SetSize(16, 16);
offsetY = -1;
else
qualityTexture:SetSize(12, 12);
offsetY = -1;
end
qualityTexture:SetAtlas(qualityAtlas, false);
qualityTexture:Show();
if levelSubtext ~= nil and levelSubtext ~= "" then
qualityTexture:SetPoint("LEFT", self.HeaderFrame.LevelSubText, "RIGHT", 4, 0);
else
qualityTexture:SetPoint("TOPLEFT", self.HeaderFrame.ItemLevel, "TOPRIGHT", 4, offsetY);
end
else
self.HeaderFrame.CraftingQualityIcon:Hide();
end
if itemData.weaponInfo then
self:AddDoubleLine(itemData.weaponInfo[1], itemData.weaponInfo[2], GetColorByIndex(1));
end
end
local statsTable = GetItemStats(link);
if statsTable then
if self.isWeapon then
local dps = statsTable["ITEM_MOD_DAMAGE_PER_SECOND_SHORT"]; --this value might be different for artifact
if dps then
self:AddLine(format(PT_DPS_TEMPLATE, dps), GetColorByIndex(1)); --DPS_TEMPLATE
statsTable["ITEM_MOD_DAMAGE_PER_SECOND_SHORT"] = nil;
end
elseif classID == 4 and subclassID == 6 then
local block = GetShieldBlock();
if block and block > 0 then
statsTable["ITEM_MOD_BLOCK_RATING_SHORT"] = block;
end
end
local key;
local statText;
for i = 1, #STATS_ORDER do
key = STATS_ORDER[i][1];
if statsTable[key] then
statText = format(STATS_ORDER[i][2], statsTable[key]) .. _G[key];
if STATS_ORDER[i][4] then
statText = statText .. "|cff729a7c" .. NarciAPI.ConvertRatingToPercentage(STATS_ORDER[i][4], statsTable[key]) .. "|r";
end
self:AddLine(statText, GetColorByIndex(STATS_ORDER[i][3]));
statsTable[key] = nil;
end
end
for k, v in pairs(statsTable) do
if _G[k] and not match(k, "^EMPTY_SOCKET") then
statText = format("+%d %s", v, _G[k]);
self:AddLine(statText, GetColorByIndex(2));
--print(k) --special stats
end
end
end
if itemData then
if itemData.enchant then
local r, g, b = GetColorByIndex(2);
self:AddLine(format(ENCHANTED_TOOLTIP_LINE, itemData.enchant), r, g, b, -SEG_INSETS);
end
local anySocket, frameHeight, lineWidth = self.GemFrame:SetSocketInfo(itemData.socketInfo);
if anySocket then
self:InsertFrame(self.GemFrame);
self:EvaluateMaxWidth(lineWidth);
end
if itemData.effects then
local splitLines, lineText;
for i = 1, #itemData.effects do
if itemData.effects[i][1] == "use" then
self.SpellFrame:SetSpellEffect(link, itemData.effects[i][2], itemData.effects[i][3], itemData.effects[i][4]);
--self:InsertFrame(self.SpellFrame);
else
local r, g, b = GetColorByIndex((itemData.effects[i][3] and 2) or 4);
splitLines = {string.split("\n", itemData.effects[i][2])}; --adjust multiline spacing
for j = 1, #splitLines do
lineText = strtrim(splitLines[j]);
if lineText ~= "" then
self:AddLine(lineText, r, g, b, (self.bottomObject) and -SEG_INSETS);
end
end
--print(itemData.effects[i][2])
end
end
end
if itemData.itemSet then
local r, g, b = GetColorByIndex(3);
self:AddLine(itemData.itemSet.rawName, r, g, b, -SEG_INSETS);
self:AddRows(itemData.itemSet.itemNames, 7, " ");
--self:AddBlankLine();
self:AddRows(itemData.itemSet.bonuses, 2, nil, true);
end
if itemData.classesAllowed then
local r, g, b = GetColorByIndex( (itemData.classesAllowed[2] and 1) or 4);
self:AddLine(itemData.classesAllowed[1], r, g, b, -SEG_INSETS);
end
if itemData.flavorText then
local r, g, b = GetColorByIndex(5);
self:AddLine(itemData.flavorText, r, g, b, -SEG_INSETS);
end
end
--Show durability under certain threshhold <50%
if slotID then
local currentDura, maxDura = GetInventoryItemDurability(slotID);
if currentDura and maxDura and maxDura > 0 then
if currentDura / maxDura <= 0.5 then
self:AddLine(format(PT_DURABILITY, currentDura, maxDura), 1, 0.4275, 0.0588, -SEG_INSETS);
end
end
end
if validForTransmog and not visualID then
self.baseSourceID, self.baseVisualID = GetSlotVisualInfo(self.transmogLocation);
else
self.baseSourceID, self.baseVisualID = sourceID, visualID;
end
self:SearchDropLocation(itemName, itemID, self.baseSourceID);
ADDTIONAL_SETUP_FUNC(self);
self:UpdateSize();
self:SetItemModel();
self:Show();
end
function NarciEquipmentTooltipMixin:SetTransmogSource(appliedSourceID)
self:ClearLines();
self:SetUseTransmogLayout(true);
--local appliedSourceID, appliedVisualID, hasSecondaryAppearance = GetSlotVisualID(slotID);
if appliedSourceID and appliedSourceID > 0 then
local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID);
local itemName = sourceInfo and sourceInfo.name;
if not itemName or itemName == "" then
return
end
local appliedVisualID = sourceInfo.visualID;
local itemID, itemType, itemSubType, itemEquipLoc, icon, classID, subclassID = GetItemInfoInstant(sourceInfo.itemID);
local quality = sourceInfo.quality;
if quality then
self.HeaderFrame.ItemName:SetTextColor( GetItemQualityColor(quality) );
end
self.HeaderFrame.ItemName:SetText(itemName);
self.HeaderFrame.ItemIcon:SetTexture(icon);
self.HeaderFrame.ItemIcon:SetVertexColor(0.6, 0.6, 0.6);
self.isWeapon = classID == 2;
if not self.showItemModel then
self.showItemModel = true;
self.textWidth = self.textWidthDefault;
self:SetEmbededFrameWidth(self.textWidth);
end
if itemEquipLoc then
if classID == 4 and subclassID == 0 then
--Neck, rings, etc.
self.HeaderFrame.ItemType:SetText(_G[itemEquipLoc]);
else
self.HeaderFrame.ItemType:SetText(_G[itemEquipLoc] .." · ".. itemSubType);
end
else
self.HeaderFrame.ItemType:SetText(itemSubType);
end
local sourceText;
if sourceInfo.sourceType == 1 then --TRANSMOG_SOURCE_BOSS_DROP
local location;
local drops = C_TransmogCollection.GetAppearanceSourceDrops(appliedSourceID);
if drops and drops[1] then
local drop = drops[1];
location = format(WARDROBE_TOOLTIP_ENCOUNTER_SOURCE, drop.encounter, drop.instance);
local difficulty = drop.difficulties and drop.difficulties[1];
if difficulty then
sourceText = format(WARDROBE_TOOLTIP_BOSS_DROP_FORMAT_WITH_DIFFICULTIES, location, difficulty)
else
sourceText = format(WARDROBE_TOOLTIP_BOSS_DROP_FORMAT, location);
end
else
sourceText = _G["TRANSMOG_SOURCE_1"];
end
else
if sourceInfo.sourceType then
sourceText = _G["TRANSMOG_SOURCE_".. sourceInfo.sourceType];
end
end
if sourceText then
self:AddLine(sourceText, GetColorByIndex(1));
end
local specialSourceText = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, sourceInfo.itemID, sourceInfo.itemModID);
if specialSourceText then
if TransmogDataProvider:IsLegionArtifactBySourceID(appliedSourceID) then
specialSourceText = (ARTIFACTS_APPEARANCE_TAB_TITLE or "Artifact Appearance") .. ": "..specialSourceText;
end
self:AddLine(specialSourceText, GetColorByIndex(1));
end
--Model
self.ItemModel.FadeIn:Stop();
local cameraID = C_TransmogCollection.GetAppearanceCameraIDBySource(appliedSourceID);
self.ItemModel.cameraID = cameraID;
self.ItemModel:RefreshCamera();
Model_ApplyUICamera(self.ItemModel, cameraID);
--self.ItemModel.FadeIn.Hold:SetDuration(1);
--self.ItemModel.FadeIn:Play();
if not self.isWeapon then
if appliedSourceID ~= self.ItemModel.id then
self.ItemModel.id = appliedSourceID;
SetModelByUnit(self.ItemModel, "player");
self.ItemModel:TryOn(appliedSourceID);
end
else
if appliedVisualID ~= self.ItemModel.id then
self.ItemModel.id = appliedVisualID;
self.ItemModel:SetItemAppearance(appliedVisualID);
end
end
self.ItemModel:Show();
self.HeaderFrame.ItemIcon:Hide();
self.HeaderFrame.ItemIconMask:Hide();
self:UpdateSize();
self:Show();
else
self:Hide();
end
end
local function Search_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t > 0.5 then
self.t = 0;
if EJ_IsSearchFinished() then
self:SetScript("OnUpdate", nil);
self:InsertDropLocation();
end
end
end
local function PauseSearching_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t > 0 then
if self.searchName then
EJ_SetSearch(self.searchName);
self:SetScript("OnUpdate", Search_OnUpdate);
self.searchName = nil;
else
self.t = nil;
self:SetScript("OnUpdate", nil);
end
end
end
function NarciEquipmentTooltipMixin:SearchDropLocation(itemName, itemID, baseSourceID)
if ItemDropLocation:IsItemCached(itemID) then
self:InsertDropLocation(itemID);
self:SetScript("OnUpdate", nil);
self.t = nil;
else
if not itemName then return end
if baseSourceID then
--for transmogable items
self:SetScript("OnUpdate", nil);
self.t = nil;
local sourceText;
local sourceInfo = C_TransmogCollection.GetSourceInfo(baseSourceID);
if sourceInfo.sourceType == 1 then --TRANSMOG_SOURCE_BOSS_DROP
local location;
local drops = C_TransmogCollection.GetAppearanceSourceDrops(baseSourceID);
if drops and drops[1] then
local drop = drops[1];
sourceText = drop.instance;
if sourceText then
sourceText = sourceText.." > "..drop.encounter;
else
sourceText = drop.encounter;
end
end
if not sourceText then
sourceText = _G["TRANSMOG_SOURCE_1"];
end
else
--Only displays the boss-dropped
--[[
if sourceInfo.sourceType then
sourceText = _G["TRANSMOG_SOURCE_"..sourceInfo.sourceType];
end
--]]
end
ItemDropLocation:SetDropLocation(itemID, sourceText);
self:InsertDropLocation(itemID);
else
--for trinket/ring/necklace
self.searchName = itemName;
self.t = -0.2; --start searching after the delay to minimize stuttering
self:SetScript("OnUpdate", PauseSearching_OnUpdate);
end
end
end
function NarciEquipmentTooltipMixin:InsertDropLocation(itemID, locationText)
if itemID then
if locationText then
self:AddLine(locationText, 0.5, 0.5, 0.5, -SEG_INSETS);
elseif ItemDropLocation:DoesItemHaveDropLocation(itemID) then
locationText = ItemDropLocation:GetItemDropLocation(itemID);
self:AddLine(locationText, 0.5, 0.5, 0.5, -SEG_INSETS);
end
return
end
local numResults = EJ_GetNumSearchResults();
if numResults > 0 then
local id, stype, difficultyID, instanceID, encounterID, itemLink = EJ_GetSearchResult(1);
if stype == 0 then --loot
local creatureName, _;
local instanceName = instanceID and EJ_GetInstanceInfo(instanceID);
if encounterID then
local resultItemID = itemLink and tonumber( match(itemLink, "item:(%d+)") or "" ) or 0;
if resultItemID == self.itemID then
creatureName, _, _, _, _, _, _, instanceID = EJ_GetEncounterInfo(encounterID);
if creatureName and instanceName then
local locationText = instanceName.." > "..creatureName;
self:AddLine(locationText, 0.5, 0.5, 0.5, -SEG_INSETS);
local fontString = self.bottomObject;
if fontString then
FadeFrame(fontString, 0.25, 1, 0);
end
self:UpdateSize();
ItemDropLocation:SetDropLocation(self.itemID, locationText)
return
end
end
end
end
end
ItemDropLocation:SetDropLocation(self.itemID, nil);
end
function NarciEquipmentTooltipMixin:CalculateHeightAbove()
if self.numLines > 0 then
return self.HeaderFrame:GetBottom() - self.leftTexts[self.numLines]:GetBottom();
else
return 0
end
end
function NarciEquipmentTooltipMixin:GetItemSpellID()
return self.SpellFrame.spellID;
end
function NarciEquipmentTooltipMixin:SetItemModel()
self.ItemModel.FadeIn:Stop();
if not self.showItemModel then
self.HeaderFrame.ItemIcon:Show();
self.HeaderFrame.ItemIconMask:Show();
self.ItemModel:Hide();
return
end
if self.baseSourceID and self.baseVisualID then
self.ItemModel:Show();
self.ItemModel:SetUseTransmogSkin(true);
--local baseSourceID, baseVisualID = GetSlotVisualInfo(self.transmogLocation);
--local sourceID = transmogInfo.appearanceID;
local cameraID = C_TransmogCollection.GetAppearanceCameraIDBySource(self.baseSourceID);
if cameraID == 0 then
cameraID = 238; --Use the Sword camera if the weapon is not transmoggable
end
self.ItemModel.cameraID = cameraID;
self.ItemModel:RefreshCamera();
Model_ApplyUICamera(self.ItemModel, cameraID);
--self.ItemModel.FadeIn.Hold:SetDuration(1);
--self.ItemModel.FadeIn:Play();
if self.isWeapon then
if self.ItemModel.id ~= self.baseVisualID then
self.ItemModel.id = self.baseVisualID;
self.ItemModel:SetItemAppearance(self.baseVisualID);
end
else
if self.ItemModel.id ~= self.baseSourceID then
self.ItemModel.id = self.baseSourceID;
SetModelByUnit(self.ItemModel, "player");
self.ItemModel:TryOn(self.baseSourceID);
end
end
self.HeaderFrame.ItemIcon:Hide();
self.HeaderFrame.ItemIconMask:Hide();
else
self.HeaderFrame.ItemIcon:Show();
self.HeaderFrame.ItemIconMask:Show();
self.ItemModel:Hide();
end
end
function NarciEquipmentTooltipMixin:SetUseTransmogLayout(state)
if state ~= self.transmogLayout then
self.transmogLayout = state;
self.HeaderFrame.ItemName:ClearAllPoints();
self.HeaderFrame.ItemType:ClearAllPoints();
if state then
--hide item level, upgrade level
self.HeaderFrame.ItemName:SetPoint("TOPLEFT", self.HeaderFrame, "TOPLEFT", TOOLTIP_PADDING, -36);
self.HeaderFrame.ItemType:SetPoint("TOPLEFT", self.HeaderFrame.ItemName, "BOTTOMLEFT", 0, -4);
self.headerPadding = 48 + SEG_INSETS;
self.HeaderFrame.CraftingQualityIcon:Hide();
else
self.HeaderFrame.ItemName:SetPoint("TOPLEFT", self.HeaderFrame, "TOPLEFT", TOOLTIP_PADDING, -TOOLTIP_PADDING);
self.HeaderFrame.ItemType:SetPoint("TOPLEFT", self.HeaderFrame.ItemLevel, "BOTTOMLEFT", 0, -2);
self.headerPadding = TOOLTIP_PADDING + SEG_INSETS + 2;
end
self:ShowHotkey(not state);
end
end
function NarciEquipmentTooltipMixin:ShowHotkey(state)
self.HotkeyFrame:SetShown(state and not self.isGamepad);
end
function NarciEquipmentTooltipMixin:OnGamePadActiveChanged(isActive)
self.isGamepad = isActive;
if isActive then
self:ShowHotkey(false);
else
self:ShowHotkey(not self.transmogLayout);
end
end
function NarciEquipmentTooltipMixin:IsTransmogLayout()
return self.transmogLayout
end
function NarciEquipmentTooltipMixin:UpdateSize()
local padding = self.padding;
local headerTextHeight = self.HeaderFrame.ItemName:GetTop() - self.HeaderFrame.ItemType:GetBottom();
local headerHeight = headerTextHeight + self.headerPadding;
self.HeaderFrame:SetHeight(headerHeight);
self.HeaderFrame.ItemIcon:SetSize(headerHeight, headerHeight);
local modelHeight = headerHeight - 10;
local modelWidth = MODEL_SIZE_RATIO * modelHeight;
self.ItemModel:SetSize(modelWidth, modelHeight);
local headerWidth = math.max(self.HeaderFrame.ItemName:GetWrappedWidth() + (self.showItemModel and 0 or 52), self.HeaderFrame.ItemType:GetWrappedWidth()) + ((self.showItemModel and (modelWidth + 16) or 0));
local maxWidth = self.maxWidth;
if headerWidth > maxWidth then
maxWidth = headerWidth;
end
maxWidth = math.max(maxWidth, MIN_TEXT_WIDTH);
if self:GetItemSpellID() then
self.SpellFrame:SetFrameWidth(maxWidth);
end
local fullHeight;
if self.bottomObject then
self.AttributeFrame:Show();
fullHeight = self.HeaderFrame:GetTop() - self.bottomObject:GetBottom() + padding;
self.ItemModel:SetPoint("BOTTOMRIGHT", self.HeaderFrame, "BOTTOMRIGHT", -padding, 1);
else
if self.transmogLayout then
headerHeight = headerTextHeight + 72;
else
headerHeight = headerTextHeight + 2* padding;
end
fullHeight = headerHeight;
self.HeaderFrame:SetHeight(headerHeight);
self.AttributeFrame:Hide();
self.ItemModel:SetPoint("BOTTOMRIGHT", self.HeaderFrame, "BOTTOMRIGHT", -padding, SEG_INSETS - 2);
end
local fullWidth = maxWidth + 2 * padding;
self:SetSize(fullWidth, fullHeight);
end
function NarciEquipmentTooltipMixin:AnchorToSlotButton(slotButton, offsetX, offsetY)
self:ClearAllPoints();
offsetX = offsetX or 0;
offsetY = offsetY or 0;
if slotButton.isRight then
self:SetPoint("TOPRIGHT", slotButton, "TOPLEFT", -offsetX, offsetY);
else
self:SetPoint("TOPLEFT", slotButton, "TOPRIGHT", offsetX, offsetY);
end
self.anchorTo = slotButton;
self.offsetX, self.offsetY = offsetX, offsetY;
end
function NarciEquipmentTooltipMixin:SetFromSlotButton(slotButton, offsetX, offsetY, delay, noFadeIn)
if delay then
SharedTooltipDelay:Setup(slotButton, delay, self.SetFromSlotButton, self, slotButton, offsetX, offsetY);
else
self:AnchorToSlotButton(slotButton, offsetX, offsetY);
self:SetInventoryItem(slotButton.slotID);
if not noFadeIn then
self:FadeIn();
end
end
end
function NarciEquipmentTooltipMixin:SetTransmogFromSlotButton(slotButton, offsetX, offsetY, noFadeIn)
self:AnchorToSlotButton(slotButton, offsetX, offsetY);
self:SetTransmogSource(slotButton.sourceID);
if not noFadeIn then
self:FadeIn();
end
end
function NarciEquipmentTooltipMixin:SetItemLinkAndAnchor(link, anchorTo, offsetX, offsetY, noFadeIn)
self:ClearLines();
self.slotID = nil;
self.itemLink = link;
self:SetUseTransmogLayout(false);
if link and anchorTo then
self:AnchorToSlotButton(anchorTo, offsetX, offsetY);
local itemData = NarciAPI.GetCompleteItemDataByItemLink(link);
local visualID, sourceID = C_TransmogCollection.GetItemInfo(link);
self:DisplayItemData(link, itemData, nil, visualID, sourceID);
itemData = nil;
if not noFadeIn then
self:FadeIn();
end
else
self:Hide();
end
end
function NarciEquipmentTooltipMixin:OnDataLoaded()
if self:IsShown() and self.anchorTo then
if self.transmogLayout then
self:SetTransmogFromSlotButton(self.anchorTo, self.offsetX, self.offsetY, true)
else
if self.slotID then
self:SetFromSlotButton(self.anchorTo, self.offsetX, self.offsetY, nil, true);
else
self:SetItemLinkAndAnchor(self.itemLink, self.anchorTo, self.offsetX, self.offsetY, true);
end
end
end
end
local function ItemDataLoadedResult_OnEvent(self, event, itemID, success)
if itemID == self.pendingItemID then
self:SetScript("OnEvent", nil);
self:OnDataLoaded();
self.pendingItemID = nil;
self.t = -0.2;
print(event, itemID);
end
end
function NarciEquipmentTooltipMixin:HideTooltip()
self:Hide();
self:ClearAllPoints();
self:ClearLines();
self:SetScript("OnUpdate", nil);
SharedTooltipDelay:Kill();
end
function NarciEquipmentTooltipMixin:OnPixelChanged(pixel)
end
function NarciEquipmentTooltipMixin:FadeIn()
self.AnimIn:Stop();
self.AnimIn:Play();
self.ItemModel.FadeIn:Stop();
self.ItemModel.FadeIn:Play();
end
do
local SettingFunctions = addon.SettingFunctions;
function SettingFunctions.ShowItemIDOnTooltip(state, db)
if state == nil then
state = db["ShowItemID"];
end
if state then
ADDTIONAL_SETUP_FUNC = AppendItemID;
GENERIC_SETUP_FUNC = AppendItemIDToGameTooltip;
else
ADDTIONAL_SETUP_FUNC = VoidFunc;
GENERIC_SETUP_FUNC = VoidFunc;
end
end
end