vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 ------------------------------------------------------
2 -- GFWTooltip.lua
3 -- Generic tooltip hooking
4 -- Credit where due: mostly based on GDI's Reagent Info (which in turn uses code from ItemsMatrix, LootLink, and Auctioneer)
5 -- Additional inspiration from Reagent Watch and EnhTooltip
6 ------------------------------------------------------
7 local GFWTOOLTIP_THIS_VERSION = 8;
8 ------------------------------------------------------
9  
10 ------------------------------------------------------
11 -- External API
12 ------------------------------------------------------
13  
14 --[[ GFWTooltip_AddCallback(modName, callbackFunction)
15  
16 Allows you to have a function called whenever a tooltip is displayed.
17 The function is called with arguments (frame, name, link, source):
18  
19 frame: the instance of GameTooltip being shown, which you can modify via its API
20 name: the first line of the tooltip, typically an item name.
21 link: a hyperlink to the item being shown in the tooltip
22 source: a non-localized string identifying why this tooltip is being shown
23 (e.g. "MERCHANT" for an item seen in the MerchantFrame)
24  
25 Your callback function should return true if it modifies the tooltip, so we know not to modify the same tooltip twice.
26  
27 Example:
28  
29 function MyTooltipCallback(frame, name, link, source)
30 frame:AddLine("some stuff");
31 return true;
32 end
33 function MyMod_OnLoad()
34 GFWTooltip_AddCallback("MyMod", MyTooltipCallback);
35 end
36 ]]
37  
38 local function addCallback(modName, callbackFunction)
39 GFWTooltip_Callbacks[modName] = callbackFunction;
40 end
41  
42 ------------------------------------------------------
43 -- Initial setup
44 ------------------------------------------------------
45  
46 if (GFWTooltip == nil) then
47 GFWTooltip = {};
48 end
49 if (GFWTooltip_Callbacks == nil) then
50 GFWTooltip_Callbacks = {};
51 end
52 if (GFWTooltip_OriginalFunctions == nil) then
53 GFWTooltip_OriginalFunctions = {};
54 end
55 local hookTableName = "GFWTooltip_"..GFWTOOLTIP_THIS_VERSION.."_HookFunctions";
56 if (getglobal(hookTableName) == nil) then
57 setglobal(hookTableName, {});
58 end
59 local G = GFWTooltip;
60 local Orig = GFWTooltip_OriginalFunctions;
61 local Hook = getglobal(hookTableName);
62  
63 ------------------------------------------------------
64 -- Internal functions
65 ------------------------------------------------------
66  
67 local checkTimer; -- Timer for frequency of tooltip checks
68 local gameToolTipOwner; -- The current owner of the GameTooltip
69 local currentTooltip; -- Current Tooltip frame
70 local itemsMatrixEnabled; -- Boolean to watch if ItemsMatrix is running
71  
72 local function hookFunction(functionName)
73 if (Orig[functionName] == nil) then
74 Orig[functionName] = getglobal(functionName);
75 end
76 setglobal(functionName, Hook[functionName]);
77 end
78  
79 local function hookMethod(objectName, functionName)
80 local signature = objectName.."_"..functionName;
81 local object = getglobal(objectName);
82 if (Orig[signature] == nil) then
83 Orig[signature] = object[functionName];
84 end
85 object[functionName] = Hook[signature];
86 end
87  
88 -- We call this at the bottom of this file to get things started.
89 local function setupHookFunctions()
90  
91 -- Hooks for Blizzard's GameTooltip functions
92 hookMethod("GameTooltip", "SetHyperlink");
93 hookMethod("GameTooltip", "SetLootItem");
94 hookMethod("GameTooltip", "SetQuestItem");
95 hookMethod("GameTooltip", "SetQuestLogItem");
96 hookMethod("GameTooltip", "SetInventoryItem");
97 hookMethod("GameTooltip", "SetMerchantItem");
98 hookMethod("GameTooltip", "SetCraftItem");
99 hookMethod("GameTooltip", "SetTradeSkillItem");
100 hookMethod("GameTooltip", "SetAuctionSellItem");
101 hookMethod("GameTooltip", "SetOwner");
102 hookFunction("GameTooltip_OnHide");
103  
104 -- Hooks for other Blizzard functions
105 hookFunction("ContainerFrameItemButton_OnEnter");
106 hookFunction("ContainerFrame_Update");
107 hookFunction("SetItemRef");
108  
109 -- Dynamic-load Blizzard functions
110 hookFunction("AuctionFrame_LoadUI");
111  
112 -- Hook ItemsMatrix's functions if they're available
113 if (type(ItemsMatrix_AddExtraTooltipInfo) == "function") then
114 itemsMatrixEnabled = true;
115 end
116  
117 -- Hook AIOI's stuff if it's available and we're not running ItemsMatrix
118 if(AllInOneInventory_Enabled and not itemsMatrixEnabled) then
119 hookFunction("AllInOneInventory_ModifyItemTooltip");
120 end
121  
122 -- Hook for MyInventory
123 if (MyInventoryProfile and not itemsMatrixEnabled) then
124 hookFunction("MyInventory_ContainerFrameItemButton_OnEnter");
125 hookFunction("MyInventoryFrame_Update");
126 end
127  
128 -- Hook for the LootLink window's tooltip (not using LL's tooltip hook because we already cover everything else it does)
129 if (LootLinkItemButton_OnEnter) then
130 hookFunction("LootLinkItemButton_OnEnter");
131 end
132 end
133  
134 local function addTooltipInfo(frame, name, link, source)
135 if (frame.gfwDone == 1) then return; end -- we've already been here
136  
137 local changedTooltip = false;
138 for modName, callback in GFWTooltip_Callbacks do
139 if (callback ~= nil and type(callback) == "function") then
140 local modifiedInCallback = callback(frame, name, link, source);
141 changedTooltip = changedTooltip or modifiedInCallback;
142 if (modifiedInCallback) then
143 --GFWUtils.DebugLog("Ran tooltip callback for ".. modName..", tooltip modified.");
144 else
145 --GFWUtils.DebugLog("Ran tooltip callback for ".. modName..", tooltip not modified.");
146 end
147 end
148 end
149 --GFWUtils.DebugLog("Done with tooltip callbacks.");
150 if (changedTooltip) then
151 frame.gfwDone = 1;
152 frame:Show();
153 end
154  
155 end
156  
157 -- Checks the tooltip info for an item name. If one is found and we haven't updated the tip already, process it.
158 local function checkTooltipInfo(frame, link, source)
159 if (link and link ~= GFWTooltip_LastLink) then
160 frame.gfwDone = nil;
161 end
162 if (link == nil) then
163 link = GFWTooltip_LastLink;
164 end
165  
166 -- If we've already added our information, no need to do it again
167 currentTooltip = frame;
168 if ( frame == nil ) then
169 return;
170 end
171 if (not frame:IsVisible()) then
172 frame.gfwDone = nil;
173 end
174 local _, _, itemLink = string.find(link, "(item:%d+:%d+:%d+:%d+)");
175 if (itemLink) then
176 local name = GetItemInfo(itemLink);
177 if (name and name ~= GFWTooltip_LastName) then
178 frame.gfwDone = nil;
179 end
180 if ( not frame.gfwDone) then
181 addTooltipInfo(frame, name, link, source);
182 GFWTooltip_LastLink = link;
183 GFWTooltip_LastName = name;
184 return;
185 end
186 end
187 end
188  
189 local function nameFromLink(link)
190 local name;
191 if ( not link ) then
192 return nil;
193 end
194 for name in string.gfind(link, "|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[(.-)%]|h|r") do
195 return name;
196 end
197 return nil;
198 end
199  
200 -- Calling this will allow us to automatically add information to tooltips when needed
201 local function autoInfoOn()
202 lSuppressInfoAdd = nil;
203 end
204  
205 -- Calling this will prevent us from automatically adding information to tooltips
206 local function autoInfoOff()
207 lSuppressInfoAdd = 1;
208 end
209  
210 local function findItemInBags(findName)
211 for bag = 0, 4, 1 do
212 size = GetContainerNumSlots(bag);
213 if (size) then
214 for slot = size, 1, -1 do
215 local link = GetContainerItemLink(bag, slot);
216 if (link) then
217 local itemName = nameFromLink(link);
218 if (itemName == findName) then
219 return bag, slot;
220 end
221 end
222 end
223 end
224 end
225 end
226  
227  
228 --------------------
229 -- Hook Functions --
230 --------------------
231  
232 function Hook.AuctionFrame_LoadUI()
233 Orig.AuctionFrame_LoadUI();
234  
235 if (Orig.AuctionFrameItem_OnEnter == nil) then
236 hookFunction("AuctionFrameItem_OnEnter");
237  
238 GFWUtils.DebugLog("GFWTooltip AuctionFrame hooks installed.");
239 end
240 end
241  
242 function Hook.GameTooltip_SetHyperlink(tooltip, link)
243 Orig.GameTooltip_SetHyperlink(tooltip, link);
244  
245 local name = GetItemInfo(link);
246 addTooltipInfo(tooltip, name, link, "LINK");
247 end
248  
249 function Hook.GameTooltip_SetLootItem(this, slot)
250 Orig.GameTooltip_SetLootItem(this, slot);
251  
252 local link = GetLootSlotLink(slot);
253 local name = nameFromLink(link);
254 addTooltipInfo(this, name, link, "LOOT");
255 end
256  
257 function Hook.GameTooltip_SetQuestItem(this, qtype, slot)
258 Orig.GameTooltip_SetQuestItem(this, qtype, slot);
259  
260 local link = GetQuestItemLink(qtype, slot);
261 local name = nameFromLink(link);
262 addTooltipInfo(this, name, link, "QUEST");
263 end
264  
265 function Hook.GameTooltip_SetQuestLogItem(this, qtype, slot)
266 Orig.GameTooltip_SetQuestLogItem(this, qtype, slot);
267  
268 local link = GetQuestLogItemLink(qtype, slot);
269 local name = nameFromLink(link);
270 addTooltipInfo(this, name, link, "QUESTLOG");
271 end
272  
273 function Hook.GameTooltip_SetMerchantItem(this, slot)
274 Orig.GameTooltip_SetMerchantItem(this, slot);
275  
276 local link = GetMerchantItemLink(slot);
277 local name = nameFromLink(link);
278 addTooltipInfo(this, name, link, "MERCHANT");
279 end
280  
281 function Hook.AuctionFrameItem_OnEnter(type, index)
282 Orig.AuctionFrameItem_OnEnter(type, index);
283  
284 local link = GetAuctionItemLink(type, index);
285 local name = nameFromLink(link);
286 addTooltipInfo(GameTooltip, name, link, "AUCTION");
287 end
288  
289 function Hook.GameTooltip_SetInventoryItem(this, unit, slot)
290 local hasItem, hasCooldown, repairCost = Orig.GameTooltip_SetInventoryItem(this, unit, slot);
291 local link = GetInventoryItemLink(unit, slot);
292 local name = nameFromLink(link);
293 addTooltipInfo(this, name, link, "INVENTORY");
294  
295 return hasItem, hasCooldown, repairCost;
296 end
297  
298 function Hook.GameTooltip_SetCraftItem(this, skill, slot)
299 Orig.GameTooltip_SetCraftItem(this, skill, slot);
300 local link;
301 if (slot) then
302 link = GetCraftReagentItemLink(skill, slot);
303 local name = nameFromLink(link);
304 addTooltipInfo(this, name, link, "CRAFT_REAGENT");
305 else
306 link = GetCraftItemLink(skill);
307 local name = nameFromLink(link);
308 addTooltipInfo(this, name, link, "CRAFT_ITEM");
309 end
310 end
311  
312 function Hook.GameTooltip_SetTradeSkillItem(this, skill, slot)
313 Orig.GameTooltip_SetTradeSkillItem(this, skill, slot);
314 local link;
315 if (slot) then
316 link = GetTradeSkillReagentItemLink(skill, slot);
317 local name = nameFromLink(link);
318 addTooltipInfo(this, name, link, "TRADESKILL_REAGENT");
319 else
320 link = GetTradeSkillItemLink(skill);
321 local name = nameFromLink(link);
322 addTooltipInfo(this, name, link, "TRADESKILL_ITEM");
323 end
324 end
325  
326 function Hook.GameTooltip_SetAuctionSellItem(this)
327 Orig.GameTooltip_SetAuctionSellItem(this);
328 local name, texture, quantity, quality, canUse, price = GetAuctionSellItemInfo();
329 if (name) then
330 local bag, slot = findItemInBags(name);
331 if (bag) then
332 local link = GetContainerItemLink(bag, slot);
333 addTooltipInfo(this, name, link, "AUCTION_SELL");
334 end
335 end
336 end
337  
338 function Hook.ContainerFrameItemButton_OnEnter()
339 Orig.ContainerFrameItemButton_OnEnter();
340 autoInfoOff();
341  
342 if (itemsMatrixEnabled) then
343 autoInfoOn();
344 return;
345 end
346  
347 if (not InRepairMode()) then
348 local frameID = this:GetParent():GetID();
349 local buttonID = this:GetID();
350 local link = GetContainerItemLink(frameID, buttonID);
351 local name = nameFromLink(link);
352  
353 if( name ) then
354 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(frameID, buttonID);
355 checkTooltipInfo(GameTooltip, link, "CONTAINER");
356 GameTooltip:Show();
357 end
358 end
359 autoInfoOn();
360 end
361  
362 function Hook.ContainerFrame_Update(frame)
363 Orig.ContainerFrame_Update(frame);
364 autoInfoOff();
365  
366 if (itemsMatrixEnabled) then
367 autoInfoOn();
368 return;
369 end
370  
371 if( not InRepairMode() and GameTooltip:IsVisible() ) then
372 local frameID = frame:GetID();
373 local frameName = frame:GetName();
374 local iButton;
375 for iButton = 1, frame.size do
376 local button = getglobal(frameName.."Item"..iButton);
377 if( GameTooltip:IsOwned(button) ) then
378 local buttonID = button:GetID();
379 local link = GetContainerItemLink(frameID, buttonID);
380 local name = nameFromLink(link);
381  
382 if( name ) then
383 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(frameID, buttonID);
384 checkTooltipInfo(GameTooltip, link, "CONTAINER");
385 GameTooltip:Show();
386 end
387 end
388 end
389 end
390 autoInfoOn();
391 end
392  
393 function Hook.GameTooltip_OnHide()
394 Orig.GameTooltip_OnHide();
395 GFWTooltip_LastLink = nil;
396 GFWTooltip_LastName = nil;
397 GameTooltip.gfwDone = nil;
398 if ( currentTooltip ) then
399 currentTooltip.gfwDone = nil;
400 currentTooltip = nil;
401 end
402 end
403  
404 function Hook.GameTooltip_SetOwner(this, owner, anchor)
405 Orig.GameTooltip_SetOwner(this, owner, anchor);
406 gameToolTipOwner = owner;
407 end
408  
409 function Hook.SetItemRef(link, text, button)
410 if (not ItemRefTooltip:IsVisible()) then
411 ItemRefTooltip.gfwDone = nil;
412 end
413 Orig.SetItemRef(link, text, button);
414 checkTooltipInfo(ItemRefTooltip, link, "ITEMREF");
415 end
416  
417 -- AIOI Hooks
418 function Hook.AllInOneInventory_ModifyItemTooltip(bag, slot, tooltipName)
419 Orig.AllInOneInventory_ModifyItemTooltip(bag, slot, tooltipName);
420  
421 -- Verify AIOI is installed and running
422 if(not AllInOneInventory_Enabled or itemsMatrixEnabled) then
423 return;
424 end
425  
426 local tooltip = getglobal(tooltipName);
427 if ( not tooltip ) then
428 tooltip = getglobal("GameTooltip");
429 tooltipName = "GameTooltip";
430 end
431 if ( not tooltip ) then
432 return false;
433 end
434  
435 if ( not InRepairMode() ) then
436 local link = GetContainerItemLink(bag, slot);
437 local name = nameFromLink(link);
438  
439 addTooltipInfo(GameTooltip, name, link, "AIOI");
440 end
441 end
442  
443 -- MyInventory Hooks
444 function Hook.MyInventory_ContainerFrameItemButton_OnEnter()
445 Orig.MyInventory_ContainerFrameItemButton_OnEnter();
446  
447 if (GameTooltip:IsVisible() and not InRepairMode()) then
448 local bag, slot = MyInventory_GetIdAsBagSlot(this:GetID());
449 local _, stack = GetContainerItemInfo(bag, slot);
450  
451 local link = GetContainerItemLink(bag, slot);
452 local name = nameFromLink(link);
453  
454 if(link and name) then
455 addTooltipInfo(GameTooltip, name, link, "MYINV");
456 end
457 end
458 end
459  
460 function Hook.MyInventoryFrame_Update(frame)
461 Orig.MyInventoryFrame_Update(frame);
462  
463 local name = frame:GetName();
464 for j=1, frame.size, 1 do
465 local itemButton = getglobal(name.."Item"..j);
466  
467 if (GameTooltip:IsVisible() and GameTooltip:IsOwned(itemButton)) then
468 tooltip = getglobal("GameTooltip");
469 tooltipName = "GameTooltip";
470  
471 if ( not tooltip ) then
472 return false;
473 end
474  
475 local bag, slot = MyInventory_GetIdAsBagSlot(itemButton:GetID());
476 local link = GetContainerItemLink(bag, slot);
477 local name = nameFromLink(link);
478  
479 if (name ~= nil) then
480 addTooltipInfo(GameTooltip, name, link, "MYINV");
481 end
482 end
483 end
484 end
485  
486 function Hook.LootLinkItemButton_OnEnter()
487 Orig.LootLinkItemButton_OnEnter();
488 local name = this:GetText();
489 local itemLink = ItemLinks[name];
490 local link;
491 if (itemLink and itemLink.c and itemLink.i and LootLink_CheckItemServer(itemLink, LootLinkState.ServerNamesToIndices[GetCVar("realmName")])) then
492 local item = string.gsub(itemLink.i, "(%d+):(%d+):(%d+):(%d+)", "%1:0:%3:%4");
493 link = "|c"..itemLink.c.."|Hitem:"..item.."|h["..name.."]|h|r";
494 end
495 if (link) then
496 addTooltipInfo(LootLinkTooltip, name, link, "LOOTLINK");
497 end
498 end
499  
500 ------------------------------------------------------
501 -- load only if not already loaded
502 ------------------------------------------------------
503  
504 if (G.Version == nil or (tonumber(G.Version) and G.Version < GFWTOOLTIP_THIS_VERSION)) then
505  
506 -- Initialize state variables
507 checkTimer = 0; -- Timer for frequency of tooltip checks
508 itemsMatrixEnabled = false; -- Boolean to watch if ItemsMatrix is running
509  
510 -- Export functions
511 setupHookFunctions();
512 G.AddCallback = addCallback;
513 GFWTooltip_AddCallback = addCallback;
514 GFWTooltip.FindItemInBags = findItemInBags;
515 GFWTooltip.NameFromLink = nameFromLink;
516  
517 -- Set version number
518 G.Version = GFWTOOLTIP_THIS_VERSION;
519  
520 GFWUtils.Print("GFWTooltip v"..GFWTOOLTIP_THIS_VERSION.." loaded.");
521  
522 end
523  
524