PageRenderTime 38ms CodeModel.GetById 21ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Tukui/modules/tooltip/tooltip.lua

http://github.com/Asphyxia/Tukui
Lua | 442 lines | 367 code | 55 blank | 20 comment | 78 complexity | 2049b1d97a60a672eb2bafe232c6125f MD5 | raw file
  1local T, C, L = unpack(select(2, ...)) -- Import: T - functions, constants, variables; C - config; L - locales
  2-- credits : Aezay (TipTac) and Caellian for some parts of code.
  3
  4if not C["tooltip"].enable then return end
  5
  6local TukuiTooltip = CreateFrame("Frame", "TukuiTooltip", UIParent)
  7
  8local _G = getfenv(0)
  9
 10local GameTooltip, GameTooltipStatusBar = _G["GameTooltip"], _G["GameTooltipStatusBar"]
 11
 12local gsub, find, format = string.gsub, string.find, string.format
 13
 14local Tooltips = {GameTooltip,ShoppingTooltip1,ShoppingTooltip2,ShoppingTooltip3,WorldMapTooltip,WorldMapCompareTooltip1,WorldMapCompareTooltip2,WorldMapCompareTooltip3}
 15local ItemRefTooltip = ItemRefTooltip
 16
 17local linkTypes = {item = true, enchant = true, spell = true, quest = true, unit = true, talent = true, achievement = true, glyph = true}
 18
 19local classification = {
 20	worldboss = "|cffAF5050Boss|r",
 21	rareelite = "|cffAF5050+ Rare|r",
 22	elite = "|cffAF5050+|r",
 23	rare = "|cffAF5050Rare|r",
 24}
 25
 26local NeedBackdropBorderRefresh = true
 27
 28local anchor = CreateFrame("Frame", "TukuiTooltipAnchor", UIParent)
 29anchor:SetSize(200, TukuiInfoRight:GetHeight())
 30anchor:SetFrameStrata("TOOLTIP")
 31anchor:SetFrameLevel(20)
 32anchor:SetClampedToScreen(true)
 33anchor:SetAlpha(0)
 34if C.chat.background and TukuiChatBackgroundRight then
 35	anchor:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 5)
 36else
 37	anchor:SetPoint("BOTTOMRIGHT", TukuiInfoRight)
 38end
 39anchor:SetTemplate("Default")
 40anchor:SetBackdropBorderColor(C.media.backdropcolor)
 41anchor:SetMovable(true)
 42anchor.text = T.SetFontString(anchor, C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 43anchor.text:SetPoint("CENTER")
 44anchor.text:SetText(L.move_tooltip)
 45
 46-- Update Tukui Tooltip Position on some specifics Tooltip
 47-- Also used because on Eyefinity, SetClampedToScreen doesn't work on left and right side of screen #1
 48local function UpdateTooltip(self)
 49	local owner = self:GetOwner()
 50	if not owner then return end	
 51	local name = owner:GetName()
 52	
 53	-- fix X-offset or Y-offset
 54	local x = T.Scale(5)
 55	
 56	-- mouseover
 57	if self:GetAnchorType() == "ANCHOR_CURSOR" then
 58		-- h4x for world object tooltip border showing last border color 
 59		-- or showing background sometime ~blue :x		
 60		if NeedBackdropBorderRefresh then
 61		 self:ClearAllPoints()
 62			NeedBackdropBorderRefresh = false			
 63			self:SetBackdropColor(unpack(C.media.backdropcolor))
 64			if not C["tooltip"].cursor then
 65				self:SetBackdropBorderColor(unpack(C.media.bordercolor))
 66			end
 67		end
 68	elseif self:GetAnchorType() == "ANCHOR_NONE" and InCombatLockdown() and C["tooltip"].hidecombat == true then
 69		self:Hide()
 70	end
 71	
 72	if name and (TukuiPlayerBuffs or TukuiPlayerDebuffs) then
 73		if (TukuiPlayerBuffs:GetPoint():match("LEFT") or TukuiPlayerDebuffs:GetPoint():match("LEFT")) and (name:match("TukuiPlayerBuffs") or name:match("TukuiPlayerDebuffs")) then
 74			self:SetAnchorType("ANCHOR_BOTTOMRIGHT", x, -x)
 75		end
 76	end
 77		
 78	if (owner == MiniMapBattlefieldFrame or owner == MiniMapMailFrame) and TukuiMinimap then
 79		if TukuiMinimap:GetPoint():match("LEFT") then 
 80			self:SetAnchorType("ANCHOR_TOPRIGHT", x, -x)
 81		end
 82	end
 83	
 84	if self:GetAnchorType() == "ANCHOR_NONE" and TukuiTooltipAnchor then
 85		local point = TukuiTooltipAnchor:GetPoint()
 86		if point == "TOPLEFT" then
 87			self:ClearAllPoints()
 88			self:SetPoint("TOPLEFT", TukuiTooltipAnchor, "BOTTOMLEFT", 0, -x)			
 89		elseif point == "TOP" then
 90			self:ClearAllPoints()
 91			self:SetPoint("TOP", TukuiTooltipAnchor, "BOTTOM", 0, -x)			
 92		elseif point == "TOPRIGHT" then
 93			self:ClearAllPoints()
 94			self:SetPoint("TOPRIGHT", TukuiTooltipAnchor, "BOTTOMRIGHT", 0, -x)			
 95		elseif point == "BOTTOMLEFT" or point == "LEFT" then
 96			self:ClearAllPoints()
 97			self:SetPoint("BOTTOMLEFT", TukuiTooltipAnchor, "TOPLEFT", 0, x)		
 98		elseif point == "BOTTOMRIGHT" or point == "RIGHT" then
 99			if TukuiBags and TukuiBags:IsShown() then
100				self:ClearAllPoints()
101				self:SetPoint("BOTTOMRIGHT", TukuiBags, "TOPRIGHT", 0, x)
102			else
103				if not C["actionbar"].enable then
104					if not C["chat"].background then
105						self:ClearAllPoints()
106						self:SetPoint("BOTTOMRIGHT", TukuiInfoRight, "TOPRIGHT", 0, x)
107					else
108						self:ClearAllPoints()
109						self:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, x)
110					end
111				else
112					if not C["chat"].background then
113						self:ClearAllPoints()
114						self:SetPoint("BOTTOMRIGHT", TukuiInfoRight, "TOPRIGHT", 0, x)
115					elseif HasPetUI() then
116						if C["actionbar"].vertical_rightbars then
117							self:ClearAllPoints()
118							self:SetPoint("BOTTOMRIGHT", TukuiPetBar, "BOTTOMLEFT", -x, 0)
119						else
120							self:ClearAllPoints()
121							self:SetPoint("BOTTOMRIGHT", TukuiPetBar, "TOPRIGHT", 0, x)
122						end
123					else
124						if C["actionbar"].vertical_rightbars and TukuiSaved.rightbars > 0 then
125							self:ClearAllPoints()
126							self:SetPoint("BOTTOMRIGHT", TukuiRightBar, "BOTTOMLEFT", -x, 0)
127						elseif not C["actionbar"].vertical_rightbars and TukuiSaved.rightbars > 0 then
128							self:ClearAllPoints()
129							self:SetPoint("BOTTOMRIGHT", TukuiRightBar, "TOPRIGHT", 0, x)
130						else
131							self:ClearAllPoints()
132							self:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, x)
133						end
134					end
135				end
136			end
137		else
138			self:ClearAllPoints()
139			self:SetPoint("BOTTOM", TukuiTooltipAnchor, "TOP", 0, x)		
140		end
141	end
142end
143
144hooksecurefunc("GameTooltip_SetDefaultAnchor", function(self, parent)
145	if C["tooltip"].cursor == true then
146		if IsAddOnLoaded("Tukui_Raid_Healing") and parent ~= UIParent then
147			self:SetOwner(parent, "ANCHOR_NONE")
148		else
149			self:SetOwner(parent, "ANCHOR_CURSOR")
150		end
151	else
152		self:SetOwner(parent, "ANCHOR_NONE")
153	end
154	
155	self:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -111111, -111111) -- hack to update GameStatusBar instantly.
156end)
157
158GameTooltip:HookScript("OnUpdate", function(self, ...) UpdateTooltip(self) end)
159
160local function Hex(color)
161	return string.format('|cff%02x%02x%02x', color.r * 255, color.g * 255, color.b * 255)
162end
163
164local function GetColor(unit)
165	if(UnitIsPlayer(unit) and not UnitHasVehicleUI(unit)) then
166		local _, class = UnitClass(unit)
167		local color = RAID_CLASS_COLORS[class]
168		if not color then return end -- sometime unit too far away return nil for color :(
169		local r,g,b = color.r, color.g, color.b
170		return Hex(color), r, g, b	
171	else
172		local color = FACTION_BAR_COLORS[UnitReaction(unit, "player")]
173		if not color then return end -- sometime unit too far away return nil for color :(
174		local r,g,b = color.r, color.g, color.b		
175		return Hex(color), r, g, b		
176	end
177end
178
179-- function to short-display HP value on StatusBar
180local function ShortValue(value)
181	if value >= 1e7 then
182		return ('%.1fm'):format(value / 1e6):gsub('%.?0+([km])$', '%1')
183	elseif value >= 1e6 then
184		return ('%.2fm'):format(value / 1e6):gsub('%.?0+([km])$', '%1')
185	elseif value >= 1e5 then
186		return ('%.0fk'):format(value / 1e3)
187	elseif value >= 1e3 then
188		return ('%.1fk'):format(value / 1e3):gsub('%.?0+([km])$', '%1')
189	else
190		return value
191	end
192end
193
194-- update HP value on status bar
195GameTooltipStatusBar:SetScript("OnValueChanged", function(self, value)
196	if not value then
197		return
198	end
199	local min, max = self:GetMinMaxValues()
200	
201	if (value < min) or (value > max) then
202		return
203	end
204	local _, unit = GameTooltip:GetUnit()
205	
206	-- fix target of target returning nil
207	if (not unit) then
208		local GMF = GetMouseFocus()
209		unit = GMF and GMF:GetAttribute("unit")
210	end
211
212	if not self.text then
213		self.text = self:CreateFontString(nil, "OVERLAY")
214		local position = TukuiTooltipAnchor:GetPoint()
215		if position:match("TOP") then
216			self.text:Point("CENTER", GameTooltipStatusBar, 2, 2)
217		else
218			self.text:Point("CENTER", GameTooltipStatusBar, 2, 2)
219		end
220		
221		self.text:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
222		self.text:Show()
223		if unit then
224			min, max = UnitHealth(unit), UnitHealthMax(unit)
225			local hp = ShortValue(min).." / "..ShortValue(max)
226			if UnitIsGhost(unit) then
227				self.text:SetText(L.unitframes_ouf_ghost)
228			elseif min == 0 or UnitIsDead(unit) or UnitIsGhost(unit) then
229				self.text:SetText(L.unitframes_ouf_dead)
230			else
231				self.text:SetText(hp)
232			end
233		end
234	else
235		if unit then
236			min, max = UnitHealth(unit), UnitHealthMax(unit)
237			self.text:Show()
238			local hp = ShortValue(min).." / "..ShortValue(max)
239			if UnitIsGhost(unit) then
240				self.text:SetText(L.unitframes_ouf_ghost)
241			elseif min == 0 or UnitIsDead(unit) or UnitIsGhost(unit) then
242				self.text:SetText(L.unitframes_ouf_dead)
243			else
244				self.text:SetText(hp)
245			end
246		else
247			self.text:Hide()
248		end
249	end
250end)
251
252local healthBar = GameTooltipStatusBar
253healthBar:ClearAllPoints()
254healthBar:Height(11)
255healthBar:Point("BOTTOMLEFT", healthBar:GetParent(), "TOPLEFT", 2, 5)
256healthBar:Point("BOTTOMRIGHT", healthBar:GetParent(), "TOPRIGHT", -2, 5)
257healthBar:SetStatusBarTexture(C.media.normTex)
258
259local healthBarBG = CreateFrame("Frame", "StatusBarBG", healthBar)
260healthBarBG:SetFrameLevel(healthBar:GetFrameLevel() - 1)
261healthBarBG:Point("TOPLEFT", -2, 2)
262healthBarBG:Point("BOTTOMRIGHT", 2, -2)
263healthBarBG:SetTemplate("Default")
264
265-- Add "Targeted By" line
266local targetedList = {}
267local ClassColors = {};
268local token
269for class, color in next, RAID_CLASS_COLORS do
270	ClassColors[class] = ("|cff%.2x%.2x%.2x"):format(color.r*255,color.g*255,color.b*255);
271end
272
273GameTooltip:HookScript("OnTooltipSetUnit", function(self)
274	local lines = self:NumLines()
275	local GMF = GetMouseFocus()
276	local unit = (select(2, self:GetUnit())) or (GMF and GMF:GetAttribute("unit"))
277	
278	-- A mage's mirror images sometimes doesn't return a unit, this would fix it
279	if (not unit) and (UnitExists("mouseover")) then
280		unit = "mouseover"
281	end
282	
283	-- Sometimes when you move your mouse quicky over units in the worldframe, we can get here without a unit
284	if not unit then self:Hide() return end
285	
286	-- for hiding tooltip on unitframes
287	if (self:GetOwner() ~= UIParent and C["tooltip"].hideuf) then self:Hide() return end
288	
289	-- A "mouseover" unit is better to have as we can then safely say the tip should no longer show when it becomes invalid.
290	if (UnitIsUnit(unit,"mouseover")) then
291		unit = "mouseover"
292	end
293
294	local race = UnitRace(unit)
295	local class = UnitClass(unit)
296	local level = UnitLevel(unit)
297	local guildName, guildRankName, guildRankIndex = GetGuildInfo(unit)
298	local name, realm = UnitName(unit)
299	local crtype = UnitCreatureType(unit)
300	local classif = UnitClassification(unit)
301	local title = UnitPVPName(unit)
302	local r, g, b = GetQuestDifficultyColor(level).r, GetQuestDifficultyColor(level).g, GetQuestDifficultyColor(level).b
303
304	local color = GetColor(unit)	
305	if not color then color = "|CFFFFFFFF" end -- just safe mode for when GetColor(unit) return nil for unit too far away
306
307	_G["GameTooltipTextLeft1"]:SetFormattedText("%s%s%s", color, title or name, realm and realm ~= "" and " - "..realm.."|r" or "|r")
308
309	if(UnitIsPlayer(unit)) then
310		if UnitIsAFK(unit) then
311			self:AppendText((" %s"):format(CHAT_FLAG_AFK))
312		elseif UnitIsDND(unit) then 
313			self:AppendText((" %s"):format(CHAT_FLAG_DND))
314		end
315
316		local offset = 2
317		if guildName then
318		    if UnitIsInMyGuild(unit) then
319				_G["GameTooltipTextLeft2"]:SetText("<".."|cff0090ff"..guildName.."|r> [".."|cff00ff10"..guildRankName.."|r]") -- setting guildranks here
320			else
321			    _G["GameTooltipTextLeft2"]:SetText("<|cff00ff10"..guildName.."|r> [|cff00ff10"..guildRankName.."|r]")
322			end	
323			offset = offset + 1
324		end
325
326		for i= offset, lines do
327			if(_G["GameTooltipTextLeft"..i]:GetText():find("^"..LEVEL)) then
328				_G["GameTooltipTextLeft"..i]:SetFormattedText("|cff%02x%02x%02x%s|r %s %s%s", r*255, g*255, b*255, level > 0 and level or "??", race, color, class.."|r")
329				break
330			end
331		end
332	else
333		for i = 2, lines do
334			if((_G["GameTooltipTextLeft"..i]:GetText():find("^"..LEVEL)) or (crtype and _G["GameTooltipTextLeft"..i]:GetText():find("^"..crtype))) then
335				if level == -1 and classif == "elite" then classif = "worldboss" end
336				_G["GameTooltipTextLeft"..i]:SetFormattedText("|cff%02x%02x%02x%s|r%s %s", r*255, g*255, b*255, classif ~= "worldboss" and level ~= 0 and level or "", classification[classif] or "", crtype or "")
337				break
338			end
339		end
340	end
341
342	local pvpLine
343	for i = 1, lines do
344		local text = _G["GameTooltipTextLeft"..i]:GetText()
345		if text and text == PVP_ENABLED then
346			pvpLine = _G["GameTooltipTextLeft"..i]
347			pvpLine:SetText()
348			break
349		end
350	end
351
352	-- ToT line
353	if UnitExists(unit.."target") and unit~="player" then
354		local hex, r, g, b = GetColor(unit.."target")
355		if not r and not g and not b then r, g, b = 1, 1, 1 end
356		GameTooltip:AddLine(UnitName(unit.."target"), r, g, b)
357	end
358	
359	-- Sometimes this wasn't getting reset, the fact a cleanup isn't performed at this point, now that it was moved to "OnTooltipCleared" is very bad, so this is a fix
360	self.fadeOut = nil
361end)
362
363local BorderColor = function(self)
364	local GMF = GetMouseFocus()
365	local unit = (select(2, self:GetUnit())) or (GMF and GMF:GetAttribute("unit"))
366		
367	local reaction = unit and UnitReaction(unit, "player")
368	local player = unit and UnitIsPlayer(unit)
369	local tapped = unit and UnitIsTapped(unit)
370	local tappedbyme = unit and UnitIsTappedByPlayer(unit)
371	local connected = unit and UnitIsConnected(unit)
372	local dead = unit and UnitIsDead(unit)
373
374	if player then
375		local class = select(2, UnitClass(unit))
376		local c = T.oUF_colors.class[class]
377		r, g, b = c[1], c[2], c[3]
378		self:SetBackdropBorderColor(r, g, b)
379		healthBarBG:SetBackdropBorderColor(r, g, b)
380		healthBar:SetStatusBarColor(r, g, b)
381	elseif reaction then
382		local c = T.oUF_colors.reaction[reaction]
383		r, g, b = c[1], c[2], c[3]
384		self:SetBackdropBorderColor(r, g, b)
385		healthBarBG:SetBackdropBorderColor(r, g, b)
386		healthBar:SetStatusBarColor(r, g, b)
387	else
388		local _, link = self:GetItem()
389		local quality = link and select(3, GetItemInfo(link))
390		if quality and quality >= 2 then
391			local r, g, b = GetItemQualityColor(quality)
392			self:SetBackdropBorderColor(r, g, b)
393		else
394			self:SetBackdropBorderColor(unpack(C["media"].bordercolor))
395			healthBarBG:SetBackdropBorderColor(unpack(C["media"].bordercolor))
396			healthBar:SetStatusBarColor(unpack(C["media"].bordercolor))
397		end
398	end
399	
400	-- need this
401	NeedBackdropBorderRefresh = true
402end
403
404local SetStyle = function(self)
405	self:SetTemplate("Default", true)
406	BorderColor(self)
407end
408
409TukuiTooltip:RegisterEvent("PLAYER_ENTERING_WORLD")
410TukuiTooltip:SetScript("OnEvent", function(self)
411	for _, tt in pairs(Tooltips) do
412		tt:HookScript("OnShow", SetStyle)
413	end
414	
415	ItemRefTooltip:HookScript("OnTooltipSetItem", SetStyle)
416	ItemRefTooltip:HookScript("OnShow", SetStyle)	
417	FriendsTooltip:SetTemplate("Default", true)
418		
419	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
420	self:SetScript("OnEvent", nil)
421	
422	-- move health status bar if anchor is found at top
423	local position = TukuiTooltipAnchor:GetPoint()
424	if position:match("TOP") then
425		healthBar:ClearAllPoints()
426		healthBar:Point("TOPLEFT", healthBar:GetParent(), "BOTTOMLEFT", 2, -5)
427		healthBar:Point("TOPRIGHT", healthBar:GetParent(), "BOTTOMRIGHT", -2, -5)
428	end
429	
430	-- Hide tooltips in combat for actions, pet actions and shapeshift
431	if C["tooltip"].hidebuttons == true then
432		local CombatHideActionButtonsTooltip = function(self)
433			if not IsShiftKeyDown() then
434				self:Hide()
435			end
436		end
437	 
438		hooksecurefunc(GameTooltip, "SetAction", CombatHideActionButtonsTooltip)
439		hooksecurefunc(GameTooltip, "SetPetAction", CombatHideActionButtonsTooltip)
440		hooksecurefunc(GameTooltip, "SetShapeshift", CombatHideActionButtonsTooltip)
441	end
442end)