Guest User

LibQTip-1.0.lua for SL (17.08.2020)

a guest
Aug 17th, 2020
1,677
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local MAJOR = "LibQTip-1.0"
  2. local MINOR = 47 -- Should be manually increased
  3. local LibStub = _G.LibStub
  4.  
  5. assert(LibStub, MAJOR .. " requires LibStub")
  6.  
  7. local lib, oldMinor = LibStub:NewLibrary(MAJOR, MINOR)
  8.  
  9. if not lib then
  10. return
  11. end -- No upgrade needed
  12.  
  13. ------------------------------------------------------------------------------
  14. -- Upvalued globals
  15. ------------------------------------------------------------------------------
  16. local table = _G.table
  17. local tinsert = table.insert
  18. local tremove = table.remove
  19. local wipe = table.wipe
  20.  
  21. local error = error
  22. local math = math
  23. local min, max = math.min, math.max
  24. local next = next
  25. local pairs, ipairs = pairs, ipairs
  26. local select = select
  27. local setmetatable = setmetatable
  28. local tonumber, tostring = tonumber, tostring
  29. local type = type
  30.  
  31. local CreateFrame = _G.CreateFrame
  32. local GameTooltip = _G.GameTooltip
  33. local UIParent = _G.UIParent
  34.  
  35. local geterrorhandler = _G.geterrorhandler
  36.  
  37. ------------------------------------------------------------------------------
  38. -- Tables and locals
  39. ------------------------------------------------------------------------------
  40. lib.frameMetatable = lib.frameMetatable or {__index = CreateFrame("Frame")}
  41.  
  42. lib.tipPrototype = lib.tipPrototype or setmetatable({}, lib.frameMetatable)
  43. lib.tipMetatable = lib.tipMetatable or {__index = lib.tipPrototype}
  44.  
  45. lib.providerPrototype = lib.providerPrototype or {}
  46. lib.providerMetatable = lib.providerMetatable or {__index = lib.providerPrototype}
  47.  
  48. lib.cellPrototype = lib.cellPrototype or setmetatable({}, lib.frameMetatable)
  49. lib.cellMetatable = lib.cellMetatable or {__index = lib.cellPrototype}
  50.  
  51. lib.activeTooltips = lib.activeTooltips or {}
  52.  
  53. lib.tooltipHeap = lib.tooltipHeap or {}
  54. lib.frameHeap = lib.frameHeap or {}
  55. lib.tableHeap = lib.tableHeap or {}
  56.  
  57. lib.onReleaseHandlers = lib.onReleaseHandlers or {}
  58.  
  59. local tipPrototype = lib.tipPrototype
  60. local tipMetatable = lib.tipMetatable
  61.  
  62. local providerPrototype = lib.providerPrototype
  63. local providerMetatable = lib.providerMetatable
  64.  
  65. local cellPrototype = lib.cellPrototype
  66. local cellMetatable = lib.cellMetatable
  67.  
  68. local activeTooltips = lib.activeTooltips
  69.  
  70. local highlightFrame = CreateFrame("Frame", nil, UIParent)
  71. highlightFrame:SetFrameStrata("TOOLTIP")
  72. highlightFrame:Hide()
  73.  
  74. local DEFAULT_HIGHLIGHT_TEXTURE_PATH = [[Interface\QuestFrame\UI-QuestTitleHighlight]]
  75.  
  76. local highlightTexture = highlightFrame:CreateTexture(nil, "OVERLAY")
  77. highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
  78. highlightTexture:SetBlendMode("ADD")
  79. highlightTexture:SetAllPoints(highlightFrame)
  80.  
  81. ------------------------------------------------------------------------------
  82. -- Private methods for Caches and Tooltip
  83. ------------------------------------------------------------------------------
  84. local AcquireTooltip, ReleaseTooltip
  85. local AcquireCell, ReleaseCell
  86. local AcquireTable, ReleaseTable
  87.  
  88. local InitializeTooltip, SetTooltipSize, ResetTooltipSize, FixCellSizes
  89. local ClearTooltipScripts
  90. local SetFrameScript, ClearFrameScripts
  91.  
  92. ------------------------------------------------------------------------------
  93. -- Cache debugging.
  94. ------------------------------------------------------------------------------
  95. -- @debug @
  96. local usedTables, usedFrames, usedTooltips = 0, 0, 0
  97. --@end-debug@
  98.  
  99. ------------------------------------------------------------------------------
  100. -- Internal constants to tweak the layout
  101. ------------------------------------------------------------------------------
  102. local TOOLTIP_PADDING = 10
  103. local CELL_MARGIN_H = 6
  104. local CELL_MARGIN_V = 3
  105.  
  106. ------------------------------------------------------------------------------
  107. -- Public library API
  108. ------------------------------------------------------------------------------
  109. --- Create or retrieve the tooltip with the given key.
  110. -- If additional arguments are passed, they are passed to :SetColumnLayout for the acquired tooltip.
  111. -- @name LibQTip:Acquire(key[, numColumns, column1Justification, column2justification, ...])
  112. -- @param key string or table - the tooltip key. Any value that can be used as a table key is accepted though you should try to provide unique keys to avoid conflicts.
  113. -- Numbers and booleans should be avoided and strings should be carefully chosen to avoid namespace clashes - no "MyTooltip" - you have been warned!
  114. -- @return tooltip Frame object - the acquired tooltip.
  115. -- @usage Acquire a tooltip with at least 5 columns, justification : left, center, left, left, left
  116. -- <pre>local tip = LibStub('LibQTip-1.0'):Acquire('MyFooBarTooltip', 5, "LEFT", "CENTER")</pre>
  117. function lib:Acquire(key, ...)
  118. if key == nil then
  119. error("attempt to use a nil key", 2)
  120. end
  121.  
  122. local tooltip = activeTooltips[key]
  123.  
  124. if not tooltip then
  125. tooltip = AcquireTooltip()
  126. InitializeTooltip(tooltip, key)
  127. activeTooltips[key] = tooltip
  128. end
  129.  
  130. if select("#", ...) > 0 then
  131. -- Here we catch any error to properly report it for the calling code
  132. local ok, msg = pcall(tooltip.SetColumnLayout, tooltip, ...)
  133.  
  134. if not ok then
  135. error(msg, 2)
  136. end
  137. end
  138.  
  139. return tooltip
  140. end
  141.  
  142. function lib:Release(tooltip)
  143. local key = tooltip and tooltip.key
  144.  
  145. if not key or activeTooltips[key] ~= tooltip then
  146. return
  147. end
  148.  
  149. ReleaseTooltip(tooltip)
  150. activeTooltips[key] = nil
  151. end
  152.  
  153. function lib:IsAcquired(key)
  154. if key == nil then
  155. error("attempt to use a nil key", 2)
  156. end
  157.  
  158. return not (not activeTooltips[key])
  159. end
  160.  
  161. function lib:IterateTooltips()
  162. return pairs(activeTooltips)
  163. end
  164.  
  165. ------------------------------------------------------------------------------
  166. -- Frame cache
  167. ------------------------------------------------------------------------------
  168. local frameHeap = lib.frameHeap
  169.  
  170. local function AcquireFrame(parent)
  171. local frame = tremove(frameHeap) or CreateFrame("Frame")
  172. frame:SetParent(parent)
  173. --[===[@debug@
  174. usedFrames = usedFrames + 1
  175. --@end-debug@]===]
  176. return frame
  177. end
  178.  
  179. local function ReleaseFrame(frame)
  180. frame:Hide()
  181. frame:SetParent(nil)
  182. frame:ClearAllPoints()
  183.  
  184. if(frame.SetBackdrop) then --**
  185. frame:SetBackdrop(nil)
  186. end
  187.  
  188. ClearFrameScripts(frame)
  189.  
  190. tinsert(frameHeap, frame)
  191. --[===[@debug@
  192. usedFrames = usedFrames - 1
  193. --@end-debug@]===]
  194. end
  195.  
  196. ------------------------------------------------------------------------------
  197. -- Dirty layout handler
  198. ------------------------------------------------------------------------------
  199. lib.layoutCleaner = lib.layoutCleaner or CreateFrame("Frame")
  200.  
  201. local layoutCleaner = lib.layoutCleaner
  202. layoutCleaner.registry = layoutCleaner.registry or {}
  203.  
  204. function layoutCleaner:RegisterForCleanup(tooltip)
  205. self.registry[tooltip] = true
  206. self:Show()
  207. end
  208.  
  209. function layoutCleaner:CleanupLayouts()
  210. self:Hide()
  211.  
  212. for tooltip in pairs(self.registry) do
  213. FixCellSizes(tooltip)
  214. end
  215.  
  216. wipe(self.registry)
  217. end
  218.  
  219. layoutCleaner:SetScript("OnUpdate", layoutCleaner.CleanupLayouts)
  220.  
  221. ------------------------------------------------------------------------------
  222. -- CellProvider and Cell
  223. ------------------------------------------------------------------------------
  224. function providerPrototype:AcquireCell()
  225. local cell = tremove(self.heap)
  226.  
  227. if not cell then
  228. --** cell = setmetatable(CreateFrame("Frame", nil, UIParent), self.cellMetatable)
  229. cell = setmetatable(CreateFrame("Frame", nil, UIParent, "BackdropTemplate"), self.cellMetatable)
  230. if type(cell.InitializeCell) == "function" then
  231. cell:InitializeCell()
  232. end
  233. end
  234.  
  235. self.cells[cell] = true
  236.  
  237. return cell
  238. end
  239.  
  240. function providerPrototype:ReleaseCell(cell)
  241. if not self.cells[cell] then
  242. return
  243. end
  244.  
  245. if type(cell.ReleaseCell) == "function" then
  246. cell:ReleaseCell()
  247. end
  248.  
  249. self.cells[cell] = nil
  250. tinsert(self.heap, cell)
  251. end
  252.  
  253. function providerPrototype:GetCellPrototype()
  254. return self.cellPrototype, self.cellMetatable
  255. end
  256.  
  257. function providerPrototype:IterateCells()
  258. return pairs(self.cells)
  259. end
  260.  
  261. function lib:CreateCellProvider(baseProvider)
  262. local cellBaseMetatable, cellBasePrototype
  263.  
  264. if baseProvider and baseProvider.GetCellPrototype then
  265. cellBasePrototype, cellBaseMetatable = baseProvider:GetCellPrototype()
  266. else
  267. cellBaseMetatable = cellMetatable
  268. end
  269.  
  270. local newCellPrototype = setmetatable({}, cellBaseMetatable)
  271. local newCellProvider = setmetatable({}, providerMetatable)
  272.  
  273. newCellProvider.heap = {}
  274. newCellProvider.cells = {}
  275. newCellProvider.cellPrototype = newCellPrototype
  276. newCellProvider.cellMetatable = {__index = newCellPrototype}
  277.  
  278. return newCellProvider, newCellPrototype, cellBasePrototype
  279. end
  280.  
  281. ------------------------------------------------------------------------------
  282. -- Basic label provider
  283. ------------------------------------------------------------------------------
  284. if not lib.LabelProvider then
  285. lib.LabelProvider, lib.LabelPrototype = lib:CreateCellProvider()
  286. end
  287.  
  288. local labelProvider = lib.LabelProvider
  289. local labelPrototype = lib.LabelPrototype
  290.  
  291. function labelPrototype:InitializeCell()
  292. self.fontString = self:CreateFontString()
  293. self.fontString:SetFontObject(_G.GameTooltipText)
  294. end
  295.  
  296. function labelPrototype:SetupCell(tooltip, value, justification, font, leftPadding, rightPadding, maxWidth, minWidth, ...)
  297. local fontString = self.fontString
  298. local line = tooltip.lines[self._line]
  299.  
  300. -- detatch fs from cell for size calculations
  301. fontString:ClearAllPoints()
  302. fontString:SetFontObject(font or (line.is_header and tooltip:GetHeaderFont() or tooltip:GetFont()))
  303. fontString:SetJustifyH(justification)
  304. fontString:SetText(tostring(value))
  305.  
  306. leftPadding = leftPadding or 0
  307. rightPadding = rightPadding or 0
  308.  
  309. local width = fontString:GetStringWidth() + leftPadding + rightPadding
  310.  
  311. if maxWidth and minWidth and (maxWidth < minWidth) then
  312. error("maximum width cannot be lower than minimum width: " .. tostring(maxWidth) .. " < " .. tostring(minWidth), 2)
  313. end
  314.  
  315. if maxWidth and (maxWidth < (leftPadding + rightPadding)) then
  316. error("maximum width cannot be lower than the sum of paddings: " .. tostring(maxWidth) .. " < " .. tostring(leftPadding) .. " + " .. tostring(rightPadding), 2)
  317. end
  318.  
  319. if minWidth and width < minWidth then
  320. width = minWidth
  321. end
  322.  
  323. if maxWidth and maxWidth < width then
  324. width = maxWidth
  325. end
  326.  
  327. fontString:SetWidth(width - (leftPadding + rightPadding))
  328. -- Use GetHeight() instead of GetStringHeight() so lines which are longer than width will wrap.
  329. local height = fontString:GetHeight()
  330.  
  331. -- reanchor fs to cell
  332. fontString:SetWidth(0)
  333. fontString:SetPoint("TOPLEFT", self, "TOPLEFT", leftPadding, 0)
  334. fontString:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -rightPadding, 0)
  335. --~ fs:SetPoint("TOPRIGHT", self, "TOPRIGHT", -r_pad, 0)
  336.  
  337. self._paddingL = leftPadding
  338. self._paddingR = rightPadding
  339.  
  340. return width, height
  341. end
  342.  
  343. function labelPrototype:getContentHeight()
  344. local fontString = self.fontString
  345. fontString:SetWidth(self:GetWidth() - (self._paddingL + self._paddingR))
  346.  
  347. local height = self.fontString:GetHeight()
  348. fontString:SetWidth(0)
  349.  
  350. return height
  351. end
  352.  
  353. function labelPrototype:GetPosition()
  354. return self._line, self._column
  355. end
  356.  
  357. ------------------------------------------------------------------------------
  358. -- Tooltip cache
  359. ------------------------------------------------------------------------------
  360. local tooltipHeap = lib.tooltipHeap
  361.  
  362. -- Returns a tooltip
  363. function AcquireTooltip()
  364. local tooltip = tremove(tooltipHeap)
  365.  
  366. if not tooltip then
  367. --** tooltip = CreateFrame("Frame", nil, UIParent)
  368. tooltip = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
  369. local scrollFrame = CreateFrame("ScrollFrame", nil, tooltip)
  370. scrollFrame:SetPoint("TOP", tooltip, "TOP", 0, -TOOLTIP_PADDING)
  371. scrollFrame:SetPoint("BOTTOM", tooltip, "BOTTOM", 0, TOOLTIP_PADDING)
  372. scrollFrame:SetPoint("LEFT", tooltip, "LEFT", TOOLTIP_PADDING, 0)
  373. scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
  374. tooltip.scrollFrame = scrollFrame
  375.  
  376. local scrollChild = CreateFrame("Frame", nil, tooltip.scrollFrame)
  377. scrollFrame:SetScrollChild(scrollChild)
  378. tooltip.scrollChild = scrollChild
  379.  
  380. setmetatable(tooltip, tipMetatable)
  381. end
  382.  
  383. --[===[@debug@
  384. usedTooltips = usedTooltips + 1
  385. --@end-debug@]===]
  386. return tooltip
  387. end
  388.  
  389. -- Cleans the tooltip and stores it in the cache
  390. function ReleaseTooltip(tooltip)
  391. if tooltip.releasing then
  392. return
  393. end
  394.  
  395. tooltip.releasing = true
  396. tooltip:Hide()
  397.  
  398. local releaseHandler = lib.onReleaseHandlers[tooltip]
  399.  
  400. if releaseHandler then
  401. lib.onReleaseHandlers[tooltip] = nil
  402.  
  403. local success, errorMessage = pcall(releaseHandler, tooltip)
  404.  
  405. if not success then
  406. geterrorhandler()(errorMessage)
  407. end
  408. elseif tooltip.OnRelease then
  409. local success, errorMessage = pcall(tooltip.OnRelease, tooltip)
  410. if not success then
  411. geterrorhandler()(errorMessage)
  412. end
  413.  
  414. tooltip.OnRelease = nil
  415. end
  416.  
  417. tooltip.releasing = nil
  418. tooltip.key = nil
  419. tooltip.step = nil
  420.  
  421. ClearTooltipScripts(tooltip)
  422.  
  423. tooltip:SetAutoHideDelay(nil)
  424. tooltip:ClearAllPoints()
  425. tooltip:Clear()
  426.  
  427. if tooltip.slider then
  428. tooltip.slider:SetValue(0)
  429. tooltip.slider:Hide()
  430. tooltip.scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
  431. tooltip:EnableMouseWheel(false)
  432. end
  433.  
  434. for i, column in ipairs(tooltip.columns) do
  435. tooltip.columns[i] = ReleaseFrame(column)
  436. end
  437.  
  438. tooltip.columns = ReleaseTable(tooltip.columns)
  439. tooltip.lines = ReleaseTable(tooltip.lines)
  440. tooltip.colspans = ReleaseTable(tooltip.colspans)
  441.  
  442. layoutCleaner.registry[tooltip] = nil
  443. tinsert(tooltipHeap, tooltip)
  444.  
  445. highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
  446. highlightTexture:SetTexCoord(0, 1, 0, 1)
  447.  
  448. --[===[@debug@
  449. usedTooltips = usedTooltips - 1
  450. --@end-debug@]===]
  451. end
  452.  
  453. ------------------------------------------------------------------------------
  454. -- Cell 'cache' (just a wrapper to the provider's cache)
  455. ------------------------------------------------------------------------------
  456. -- Returns a cell for the given tooltip from the given provider
  457. function AcquireCell(tooltip, provider)
  458. local cell = provider:AcquireCell(tooltip)
  459.  
  460. cell:SetParent(tooltip.scrollChild)
  461. cell:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 3)
  462. cell._provider = provider
  463.  
  464. return cell
  465. end
  466.  
  467. -- Cleans the cell hands it to its provider for storing
  468. function ReleaseCell(cell)
  469. if cell.fontString and cell.r then
  470. cell.fontString:SetTextColor(cell.r, cell.g, cell.b, cell.a)
  471. end
  472.  
  473. cell._font = nil
  474. cell._justification = nil
  475. cell._colSpan = nil
  476. cell._line = nil
  477. cell._column = nil
  478.  
  479. cell:Hide()
  480. cell:ClearAllPoints()
  481. cell:SetParent(nil)
  482. cell:SetBackdrop(nil)
  483.  
  484. ClearFrameScripts(cell)
  485.  
  486. cell._provider:ReleaseCell(cell)
  487. cell._provider = nil
  488. end
  489.  
  490. ------------------------------------------------------------------------------
  491. -- Table cache
  492. ------------------------------------------------------------------------------
  493. local tableHeap = lib.tableHeap
  494.  
  495. -- Returns a table
  496. function AcquireTable()
  497. local tbl = tremove(tableHeap) or {}
  498. --[===[@debug@
  499. usedTables = usedTables + 1
  500. --@end-debug@]===]
  501. return tbl
  502. end
  503.  
  504. -- Cleans the table and stores it in the cache
  505. function ReleaseTable(tableInstance)
  506. wipe(tableInstance)
  507. tinsert(tableHeap, tableInstance)
  508. --[===[@debug@
  509. usedTables = usedTables - 1
  510. --@end-debug@]===]
  511. end
  512.  
  513. ------------------------------------------------------------------------------
  514. -- Tooltip prototype
  515. ------------------------------------------------------------------------------
  516. function InitializeTooltip(tooltip, key)
  517. ----------------------------------------------------------------------
  518. -- (Re)set frame settings
  519. ----------------------------------------------------------------------
  520. local backdrop = GameTooltip:GetBackdrop()
  521.  
  522. if not tooltip.SetBackdrop then --**
  523. Mixin(tooltip, BackdropTemplateMixin)
  524. end
  525.  
  526. tooltip:SetBackdrop(backdrop)
  527.  
  528. if backdrop then
  529. tooltip:SetBackdropColor(GameTooltip:GetBackdropColor())
  530. tooltip:SetBackdropBorderColor(GameTooltip:GetBackdropBorderColor())
  531. end
  532.  
  533. tooltip:SetScale(GameTooltip:GetScale())
  534. tooltip:SetAlpha(1)
  535. tooltip:SetFrameStrata("TOOLTIP")
  536. tooltip:SetClampedToScreen(false)
  537.  
  538. ----------------------------------------------------------------------
  539. -- Internal data. Since it's possible to Acquire twice without calling
  540. -- release, check for pre-existence.
  541. ----------------------------------------------------------------------
  542. tooltip.key = key
  543. tooltip.columns = tooltip.columns or AcquireTable()
  544. tooltip.lines = tooltip.lines or AcquireTable()
  545. tooltip.colspans = tooltip.colspans or AcquireTable()
  546. tooltip.regularFont = _G.GameTooltipText
  547. tooltip.headerFont = _G.GameTooltipHeaderText
  548. tooltip.labelProvider = labelProvider
  549. tooltip.cell_margin_h = tooltip.cell_margin_h or CELL_MARGIN_H
  550. tooltip.cell_margin_v = tooltip.cell_margin_v or CELL_MARGIN_V
  551.  
  552. ----------------------------------------------------------------------
  553. -- Finishing procedures
  554. ----------------------------------------------------------------------
  555. tooltip:SetAutoHideDelay(nil)
  556. tooltip:Hide()
  557. ResetTooltipSize(tooltip)
  558. end
  559.  
  560. function tipPrototype:SetDefaultProvider(myProvider)
  561. if not myProvider then
  562. return
  563. end
  564.  
  565. self.labelProvider = myProvider
  566. end
  567.  
  568. function tipPrototype:GetDefaultProvider()
  569. return self.labelProvider
  570. end
  571.  
  572. local function checkJustification(justification, level, silent)
  573. if justification ~= "LEFT" and justification ~= "CENTER" and justification ~= "RIGHT" then
  574. if silent then
  575. return false
  576. end
  577. error("invalid justification, must one of LEFT, CENTER or RIGHT, not: " .. tostring(justification), level + 1)
  578. end
  579.  
  580. return true
  581. end
  582.  
  583. function tipPrototype:SetColumnLayout(numColumns, ...)
  584. if type(numColumns) ~= "number" or numColumns < 1 then
  585. error("number of columns must be a positive number, not: " .. tostring(numColumns), 2)
  586. end
  587.  
  588. for i = 1, numColumns do
  589. local justification = select(i, ...) or "LEFT"
  590.  
  591. checkJustification(justification, 2)
  592.  
  593. if self.columns[i] then
  594. self.columns[i].justification = justification
  595. else
  596. self:AddColumn(justification)
  597. end
  598. end
  599. end
  600.  
  601. function tipPrototype:AddColumn(justification)
  602. justification = justification or "LEFT"
  603. checkJustification(justification, 2)
  604.  
  605. local colNum = #self.columns + 1
  606. local column = self.columns[colNum] or AcquireFrame(self.scrollChild)
  607.  
  608. column:SetFrameLevel(self.scrollChild:GetFrameLevel() + 1)
  609. column.justification = justification
  610. column.width = 0
  611. column:SetWidth(1)
  612. column:SetPoint("TOP", self.scrollChild)
  613. column:SetPoint("BOTTOM", self.scrollChild)
  614.  
  615. if colNum > 1 then
  616. local h_margin = self.cell_margin_h or CELL_MARGIN_H
  617.  
  618. column:SetPoint("LEFT", self.columns[colNum - 1], "RIGHT", h_margin, 0)
  619. SetTooltipSize(self, self.width + h_margin, self.height)
  620. else
  621. column:SetPoint("LEFT", self.scrollChild)
  622. end
  623.  
  624. column:Show()
  625. self.columns[colNum] = column
  626.  
  627. return colNum
  628. end
  629.  
  630. ------------------------------------------------------------------------------
  631. -- Convenient methods
  632. ------------------------------------------------------------------------------
  633. function tipPrototype:Release()
  634. lib:Release(self)
  635. end
  636.  
  637. function tipPrototype:IsAcquiredBy(key)
  638. return key ~= nil and self.key == key
  639. end
  640.  
  641. ------------------------------------------------------------------------------
  642. -- Script hooks
  643. ------------------------------------------------------------------------------
  644. local RawSetScript = lib.frameMetatable.__index.SetScript
  645.  
  646. function ClearTooltipScripts(tooltip)
  647. if tooltip.scripts then
  648. for scriptType in pairs(tooltip.scripts) do
  649. RawSetScript(tooltip, scriptType, nil)
  650. end
  651.  
  652. tooltip.scripts = ReleaseTable(tooltip.scripts)
  653. end
  654. end
  655.  
  656. function tipPrototype:SetScript(scriptType, handler)
  657. RawSetScript(self, scriptType, handler)
  658.  
  659. if handler then
  660. if not self.scripts then
  661. self.scripts = AcquireTable()
  662. end
  663.  
  664. self.scripts[scriptType] = true
  665. elseif self.scripts then
  666. self.scripts[scriptType] = nil
  667. end
  668. end
  669.  
  670. -- That might break some addons ; those addons were breaking other
  671. -- addons' tooltip though.
  672. function tipPrototype:HookScript()
  673. geterrorhandler()(":HookScript is not allowed on LibQTip tooltips")
  674. end
  675.  
  676. ------------------------------------------------------------------------------
  677. -- Scrollbar data and functions
  678. ------------------------------------------------------------------------------
  679. local sliderBackdrop = {
  680. bgFile = [[Interface\Buttons\UI-SliderBar-Background]],
  681. edgeFile = [[Interface\Buttons\UI-SliderBar-Border]],
  682. tile = true,
  683. edgeSize = 8,
  684. tileSize = 8,
  685. insets = {
  686. left = 3,
  687. right = 3,
  688. top = 3,
  689. bottom = 3
  690. }
  691. }
  692.  
  693. local function slider_OnValueChanged(self)
  694. self.scrollFrame:SetVerticalScroll(self:GetValue())
  695. end
  696.  
  697. local function tooltip_OnMouseWheel(self, delta)
  698. local slider = self.slider
  699. local currentValue = slider:GetValue()
  700. local minValue, maxValue = slider:GetMinMaxValues()
  701. local stepValue = self.step or 10
  702.  
  703. if delta < 0 and currentValue < maxValue then
  704. slider:SetValue(min(maxValue, currentValue + stepValue))
  705. elseif delta > 0 and currentValue > minValue then
  706. slider:SetValue(max(minValue, currentValue - stepValue))
  707. end
  708. end
  709.  
  710. -- Set the step size for the scroll bar
  711. function tipPrototype:SetScrollStep(step)
  712. self.step = step
  713. end
  714.  
  715. -- will resize the tooltip to fit the screen and show a scrollbar if needed
  716. function tipPrototype:UpdateScrolling(maxheight)
  717. self:SetClampedToScreen(false)
  718.  
  719. -- all data is in the tooltip; fix colspan width and prevent the layout cleaner from messing up the tooltip later
  720. FixCellSizes(self)
  721. layoutCleaner.registry[self] = nil
  722.  
  723. local scale = self:GetScale()
  724. local topside = self:GetTop()
  725. local bottomside = self:GetBottom()
  726. local screensize = UIParent:GetHeight() / scale
  727. local tipsize = (topside - bottomside)
  728.  
  729. -- if the tooltip would be too high, limit its height and show the slider
  730. if bottomside < 0 or topside > screensize or (maxheight and tipsize > maxheight) then
  731. local shrink = (bottomside < 0 and (5 - bottomside) or 0) + (topside > screensize and (topside - screensize + 5) or 0)
  732.  
  733. if maxheight and tipsize - shrink > maxheight then
  734. shrink = tipsize - maxheight
  735. end
  736.  
  737. self:SetHeight(2 * TOOLTIP_PADDING + self.height - shrink)
  738. self:SetWidth(2 * TOOLTIP_PADDING + self.width + 20)
  739. self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -(TOOLTIP_PADDING + 20), 0)
  740.  
  741. if not self.slider then
  742. local slider = CreateFrame("Slider", nil, self)
  743. slider.scrollFrame = self.scrollFrame
  744.  
  745. slider:SetOrientation("VERTICAL")
  746. slider:SetPoint("TOPRIGHT", self, "TOPRIGHT", -TOOLTIP_PADDING, -TOOLTIP_PADDING)
  747. slider:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -TOOLTIP_PADDING, TOOLTIP_PADDING)
  748. slider:SetBackdrop(sliderBackdrop)
  749. slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
  750. slider:SetMinMaxValues(0, 1)
  751. slider:SetValueStep(1)
  752. slider:SetWidth(12)
  753. slider:SetScript("OnValueChanged", slider_OnValueChanged)
  754. slider:SetValue(0)
  755.  
  756. self.slider = slider
  757. end
  758.  
  759. self.slider:SetMinMaxValues(0, shrink)
  760. self.slider:Show()
  761.  
  762. self:EnableMouseWheel(true)
  763. self:SetScript("OnMouseWheel", tooltip_OnMouseWheel)
  764. else
  765. self:SetHeight(2 * TOOLTIP_PADDING + self.height)
  766. self:SetWidth(2 * TOOLTIP_PADDING + self.width)
  767.  
  768. self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -TOOLTIP_PADDING, 0)
  769.  
  770. if self.slider then
  771. self.slider:SetValue(0)
  772. self.slider:Hide()
  773.  
  774. self:EnableMouseWheel(false)
  775. self:SetScript("OnMouseWheel", nil)
  776. end
  777. end
  778. end
  779.  
  780. ------------------------------------------------------------------------------
  781. -- Tooltip methods for changing its contents.
  782. ------------------------------------------------------------------------------
  783. function tipPrototype:Clear()
  784. for i, line in ipairs(self.lines) do
  785. for _, cell in pairs(line.cells) do
  786. if cell then
  787. ReleaseCell(cell)
  788. end
  789. end
  790.  
  791. ReleaseTable(line.cells)
  792.  
  793. line.cells = nil
  794. line.is_header = nil
  795.  
  796. ReleaseFrame(line)
  797.  
  798. self.lines[i] = nil
  799. end
  800.  
  801. for _, column in ipairs(self.columns) do
  802. column.width = 0
  803. column:SetWidth(1)
  804. end
  805.  
  806. wipe(self.colspans)
  807.  
  808. self.cell_margin_h = nil
  809. self.cell_margin_v = nil
  810.  
  811. ResetTooltipSize(self)
  812. end
  813.  
  814. function tipPrototype:SetCellMarginH(size)
  815. if #self.lines > 0 then
  816. error("Unable to set horizontal margin while the tooltip has lines.", 2)
  817. end
  818.  
  819. if not size or type(size) ~= "number" or size < 0 then
  820. error("Margin size must be a positive number or zero.", 2)
  821. end
  822.  
  823. self.cell_margin_h = size
  824. end
  825.  
  826. function tipPrototype:SetCellMarginV(size)
  827. if #self.lines > 0 then
  828. error("Unable to set vertical margin while the tooltip has lines.", 2)
  829. end
  830.  
  831. if not size or type(size) ~= "number" or size < 0 then
  832. error("Margin size must be a positive number or zero.", 2)
  833. end
  834.  
  835. self.cell_margin_v = size
  836. end
  837.  
  838. function SetTooltipSize(tooltip, width, height)
  839. tooltip.height = height
  840. tooltip.width = width
  841.  
  842. tooltip:SetHeight(2 * TOOLTIP_PADDING + height)
  843. tooltip:SetWidth(2 * TOOLTIP_PADDING + width)
  844.  
  845. tooltip.scrollChild:SetHeight(height)
  846. tooltip.scrollChild:SetWidth(width)
  847. end
  848.  
  849. -- Add 2 pixels to height so dangling letters (g, y, p, j, etc) are not clipped.
  850. function ResetTooltipSize(tooltip)
  851. local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
  852.  
  853. SetTooltipSize(tooltip, max(0, (h_margin * (#tooltip.columns - 1)) + (h_margin / 2)), 2)
  854. end
  855.  
  856. local function EnlargeColumn(tooltip, column, width)
  857. if width > column.width then
  858. SetTooltipSize(tooltip, tooltip.width + width - column.width, tooltip.height)
  859.  
  860. column.width = width
  861. column:SetWidth(width)
  862. end
  863. end
  864.  
  865. local function ResizeLine(tooltip, line, height)
  866. SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
  867.  
  868. line.height = height
  869. line:SetHeight(height)
  870. end
  871.  
  872. function FixCellSizes(tooltip)
  873. local columns = tooltip.columns
  874. local colspans = tooltip.colspans
  875. local lines = tooltip.lines
  876. local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
  877.  
  878. -- resize columns to make room for the colspans
  879. while next(colspans) do
  880. local maxNeedCols
  881. local maxNeedWidthPerCol = 0
  882.  
  883. -- calculate the colspan with the highest additional width need per column
  884. for colRange, width in pairs(colspans) do
  885. local left, right = colRange:match("^(%d+)%-(%d+)$")
  886.  
  887. left, right = tonumber(left), tonumber(right)
  888.  
  889. for col = left, right - 1 do
  890. width = width - columns[col].width - h_margin
  891. end
  892.  
  893. width = width - columns[right].width
  894.  
  895. if width <= 0 then
  896. colspans[colRange] = nil
  897. else
  898. width = width / (right - left + 1)
  899.  
  900. if width > maxNeedWidthPerCol then
  901. maxNeedCols = colRange
  902. maxNeedWidthPerCol = width
  903. end
  904. end
  905. end
  906.  
  907. -- resize all columns for that colspan
  908. if maxNeedCols then
  909. local left, right = maxNeedCols:match("^(%d+)%-(%d+)$")
  910.  
  911. for col = left, right do
  912. EnlargeColumn(tooltip, columns[col], columns[col].width + maxNeedWidthPerCol)
  913. end
  914.  
  915. colspans[maxNeedCols] = nil
  916. end
  917. end
  918.  
  919. --now that the cell width is set, recalculate the rows' height
  920. for _, line in ipairs(lines) do
  921. if #(line.cells) > 0 then
  922. local lineheight = 0
  923.  
  924. for _, cell in pairs(line.cells) do
  925. if cell then
  926. lineheight = max(lineheight, cell:getContentHeight())
  927. end
  928. end
  929.  
  930. if lineheight > 0 then
  931. ResizeLine(tooltip, line, lineheight)
  932. end
  933. end
  934. end
  935. end
  936.  
  937. local function _SetCell(tooltip, lineNum, colNum, value, font, justification, colSpan, provider, ...)
  938. local line = tooltip.lines[lineNum]
  939. local cells = line.cells
  940.  
  941. -- Unset: be quick
  942. if value == nil then
  943. local cell = cells[colNum]
  944.  
  945. if cell then
  946. for i = colNum, colNum + cell._colSpan - 1 do
  947. cells[i] = nil
  948. end
  949.  
  950. ReleaseCell(cell)
  951. end
  952.  
  953. return lineNum, colNum
  954. end
  955.  
  956. font = font or (line.is_header and tooltip.headerFont or tooltip.regularFont)
  957.  
  958. -- Check previous cell
  959. local cell
  960. local prevCell = cells[colNum]
  961.  
  962. if prevCell then
  963. -- There is a cell here
  964. justification = justification or prevCell._justification
  965. colSpan = colSpan or prevCell._colSpan
  966.  
  967. -- Clear the currently marked colspan
  968. for i = colNum + 1, colNum + prevCell._colSpan - 1 do
  969. cells[i] = nil
  970. end
  971.  
  972. if provider == nil or prevCell._provider == provider then
  973. -- Reuse existing cell
  974. cell = prevCell
  975. provider = cell._provider
  976. else
  977. -- A new cell is required
  978. cells[colNum] = ReleaseCell(prevCell)
  979. end
  980. elseif prevCell == nil then
  981. -- Creating a new cell, using meaningful defaults.
  982. provider = provider or tooltip.labelProvider
  983. justification = justification or tooltip.columns[colNum].justification or "LEFT"
  984. colSpan = colSpan or 1
  985. else
  986. error("overlapping cells at column " .. colNum, 3)
  987. end
  988.  
  989. local tooltipWidth = #tooltip.columns
  990. local rightColNum
  991.  
  992. if colSpan > 0 then
  993. rightColNum = colNum + colSpan - 1
  994.  
  995. if rightColNum > tooltipWidth then
  996. error("ColSpan too big, cell extends beyond right-most column", 3)
  997. end
  998. else
  999. -- Zero or negative: count back from right-most columns
  1000. rightColNum = max(colNum, tooltipWidth + colSpan)
  1001. -- Update colspan to its effective value
  1002. colSpan = 1 + rightColNum - colNum
  1003. end
  1004.  
  1005. -- Cleanup colspans
  1006. for i = colNum + 1, rightColNum do
  1007. local columnCell = cells[i]
  1008.  
  1009. if columnCell then
  1010. ReleaseCell(columnCell)
  1011. elseif columnCell == false then
  1012. error("overlapping cells at column " .. i, 3)
  1013. end
  1014.  
  1015. cells[i] = false
  1016. end
  1017.  
  1018. -- Create the cell
  1019. if not cell then
  1020. cell = AcquireCell(tooltip, provider)
  1021. cells[colNum] = cell
  1022. end
  1023.  
  1024. -- Anchor the cell
  1025. cell:SetPoint("LEFT", tooltip.columns[colNum])
  1026. cell:SetPoint("RIGHT", tooltip.columns[rightColNum])
  1027. cell:SetPoint("TOP", line)
  1028. cell:SetPoint("BOTTOM", line)
  1029.  
  1030. -- Store the cell settings directly into the cell
  1031. -- That's a bit risky but is really cheap compared to other ways to do it
  1032. cell._font, cell._justification, cell._colSpan, cell._line, cell._column = font, justification, colSpan, lineNum, colNum
  1033.  
  1034. -- Setup the cell content
  1035. local width, height = cell:SetupCell(tooltip, value, justification, font, ...)
  1036. cell:Show()
  1037.  
  1038. if colSpan > 1 then
  1039. -- Postpone width changes until the tooltip is shown
  1040. local colRange = colNum .. "-" .. rightColNum
  1041.  
  1042. tooltip.colspans[colRange] = max(tooltip.colspans[colRange] or 0, width)
  1043. layoutCleaner:RegisterForCleanup(tooltip)
  1044. else
  1045. -- Enlarge the column and tooltip if need be
  1046. EnlargeColumn(tooltip, tooltip.columns[colNum], width)
  1047. end
  1048.  
  1049. -- Enlarge the line and tooltip if need be
  1050. if height > line.height then
  1051. SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
  1052.  
  1053. line.height = height
  1054. line:SetHeight(height)
  1055. end
  1056.  
  1057. if rightColNum < tooltipWidth then
  1058. return lineNum, rightColNum + 1
  1059. else
  1060. return lineNum, nil
  1061. end
  1062. end
  1063.  
  1064. do
  1065. local function CreateLine(tooltip, font, ...)
  1066. if #tooltip.columns == 0 then
  1067. error("column layout should be defined before adding line", 3)
  1068. end
  1069.  
  1070. local lineNum = #tooltip.lines + 1
  1071. local line = tooltip.lines[lineNum] or AcquireFrame(tooltip.scrollChild)
  1072.  
  1073. line:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 2)
  1074. line:SetPoint("LEFT", tooltip.scrollChild)
  1075. line:SetPoint("RIGHT", tooltip.scrollChild)
  1076.  
  1077. if lineNum > 1 then
  1078. local v_margin = tooltip.cell_margin_v or CELL_MARGIN_V
  1079.  
  1080. line:SetPoint("TOP", tooltip.lines[lineNum - 1], "BOTTOM", 0, -v_margin)
  1081. SetTooltipSize(tooltip, tooltip.width, tooltip.height + v_margin)
  1082. else
  1083. line:SetPoint("TOP", tooltip.scrollChild)
  1084. end
  1085.  
  1086. tooltip.lines[lineNum] = line
  1087.  
  1088. line.cells = line.cells or AcquireTable()
  1089. line.height = 0
  1090. line:SetHeight(1)
  1091. line:Show()
  1092.  
  1093. local colNum = 1
  1094.  
  1095. for i = 1, #tooltip.columns do
  1096. local value = select(i, ...)
  1097.  
  1098. if value ~= nil then
  1099. lineNum, colNum = _SetCell(tooltip, lineNum, i, value, font, nil, 1, tooltip.labelProvider)
  1100. end
  1101. end
  1102.  
  1103. return lineNum, colNum
  1104. end
  1105.  
  1106. function tipPrototype:AddLine(...)
  1107. return CreateLine(self, self.regularFont, ...)
  1108. end
  1109.  
  1110. function tipPrototype:AddHeader(...)
  1111. local line, col = CreateLine(self, self.headerFont, ...)
  1112.  
  1113. self.lines[line].is_header = true
  1114.  
  1115. return line, col
  1116. end
  1117. end -- do-block
  1118.  
  1119. local GenericBackdrop = {
  1120. bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"
  1121. }
  1122.  
  1123. function tipPrototype:AddSeparator(height, r, g, b, a)
  1124. local lineNum, colNum = self:AddLine()
  1125. local line = self.lines[lineNum]
  1126. local color = _G.NORMAL_FONT_COLOR
  1127.  
  1128. height = height or 1
  1129.  
  1130. SetTooltipSize(self, self.width, self.height + height)
  1131.  
  1132. line.height = height
  1133. line:SetHeight(height)
  1134.  
  1135. if not line.SetBackdrop then --**
  1136. Mixin(line, BackdropTemplateMixin)
  1137. end
  1138.  
  1139. line:SetBackdrop(GenericBackdrop)
  1140. line:SetBackdropColor(r or color.r, g or color.g, b or color.b, a or 1)
  1141.  
  1142. return lineNum, colNum
  1143. end
  1144.  
  1145. function tipPrototype:SetCellColor(lineNum, colNum, r, g, b, a)
  1146. local cell = self.lines[lineNum].cells[colNum]
  1147.  
  1148. if not cell.SetBackdrop then --**
  1149. Mixin(cell, BackdropTemplateMixin)
  1150. end
  1151.  
  1152. if cell then
  1153. local sr, sg, sb, sa = self:GetBackdropColor()
  1154.  
  1155. cell:SetBackdrop(GenericBackdrop)
  1156. cell:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
  1157. end
  1158. end
  1159.  
  1160. function tipPrototype:SetColumnColor(colNum, r, g, b, a)
  1161. local column = self.columns[colNum]
  1162.  
  1163. if not colum.SetBackdrop then --**
  1164. Mixin(colum, BackdropTemplateMixin)
  1165. end
  1166.  
  1167. if column then
  1168. local sr, sg, sb, sa = self:GetBackdropColor()
  1169. column:SetBackdrop(GenericBackdrop)
  1170. column:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
  1171. end
  1172. end
  1173.  
  1174. function tipPrototype:SetLineColor(lineNum, r, g, b, a)
  1175. local line = self.lines[lineNum]
  1176.  
  1177. if not line.SetBackdrop then
  1178. Mixin(line, BackdropTemplateMixin)
  1179. end
  1180.  
  1181. if line then
  1182. local sr, sg, sb, sa = self:GetBackdropColor()
  1183. line:SetBackdrop(GenericBackdrop)
  1184. line:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
  1185. end
  1186. end
  1187.  
  1188. function tipPrototype:SetCellTextColor(lineNum, colNum, r, g, b, a)
  1189. local line = self.lines[lineNum]
  1190. local column = self.columns[colNum]
  1191.  
  1192. if not line or not column then
  1193. return
  1194. end
  1195.  
  1196. local cell = self.lines[lineNum].cells[colNum]
  1197.  
  1198. if cell then
  1199. if not cell.fontString then
  1200. error("cell's label provider did not assign a fontString field", 2)
  1201. end
  1202.  
  1203. if not cell.r then
  1204. cell.r, cell.g, cell.b, cell.a = cell.fontString:GetTextColor()
  1205. end
  1206.  
  1207. cell.fontString:SetTextColor(r or cell.r, g or cell.g, b or cell.b, a or cell.a)
  1208. end
  1209. end
  1210.  
  1211. function tipPrototype:SetColumnTextColor(colNum, r, g, b, a)
  1212. if not self.columns[colNum] then
  1213. return
  1214. end
  1215.  
  1216. for lineIndex = 1, #self.lines do
  1217. self:SetCellTextColor(lineIndex, colNum, r, g, b, a)
  1218. end
  1219. end
  1220.  
  1221. function tipPrototype:SetLineTextColor(lineNum, r, g, b, a)
  1222. local line = self.lines[lineNum]
  1223.  
  1224. if not line then
  1225. return
  1226. end
  1227.  
  1228. for cellIndex = 1, #line.cells do
  1229. self:SetCellTextColor(lineNum, line.cells[cellIndex]._column, r, g, b, a)
  1230. end
  1231. end
  1232.  
  1233. function tipPrototype:SetHighlightTexture(...)
  1234. return highlightTexture:SetTexture(...)
  1235. end
  1236.  
  1237. function tipPrototype:SetHighlightTexCoord(...)
  1238. highlightTexture:SetTexCoord(...)
  1239. end
  1240.  
  1241. do
  1242. local function checkFont(font, level, silent)
  1243. local bad = false
  1244.  
  1245. if not font then
  1246. bad = true
  1247. elseif type(font) == "string" then
  1248. local ref = _G[font]
  1249.  
  1250. if not ref or type(ref) ~= "table" or type(ref.IsObjectType) ~= "function" or not ref:IsObjectType("Font") then
  1251. bad = true
  1252. end
  1253. elseif type(font) ~= "table" or type(font.IsObjectType) ~= "function" or not font:IsObjectType("Font") then
  1254. bad = true
  1255. end
  1256.  
  1257. if bad then
  1258. if silent then
  1259. return false
  1260. end
  1261.  
  1262. error("font must be a Font instance or a string matching the name of a global Font instance, not: " .. tostring(font), level + 1)
  1263. end
  1264. return true
  1265. end
  1266.  
  1267. function tipPrototype:SetFont(font)
  1268. local is_string = type(font) == "string"
  1269.  
  1270. checkFont(font, 2)
  1271. self.regularFont = is_string and _G[font] or font
  1272. end
  1273.  
  1274. function tipPrototype:SetHeaderFont(font)
  1275. local is_string = type(font) == "string"
  1276.  
  1277. checkFont(font, 2)
  1278. self.headerFont = is_string and _G[font] or font
  1279. end
  1280.  
  1281. -- TODO: fixed argument positions / remove checks for performance?
  1282. function tipPrototype:SetCell(lineNum, colNum, value, ...)
  1283. -- Mandatory argument checking
  1284. if type(lineNum) ~= "number" then
  1285. error("line number must be a number, not: " .. tostring(lineNum), 2)
  1286. elseif lineNum < 1 or lineNum > #self.lines then
  1287. error("line number out of range: " .. tostring(lineNum), 2)
  1288. elseif type(colNum) ~= "number" then
  1289. error("column number must be a number, not: " .. tostring(colNum), 2)
  1290. elseif colNum < 1 or colNum > #self.columns then
  1291. error("column number out of range: " .. tostring(colNum), 2)
  1292. end
  1293.  
  1294. -- Variable argument checking
  1295. local font, justification, colSpan, provider
  1296. local i, arg = 1, ...
  1297.  
  1298. if arg == nil or checkFont(arg, 2, true) then
  1299. i, font, arg = 2, ...
  1300. end
  1301.  
  1302. if arg == nil or checkJustification(arg, 2, true) then
  1303. i, justification, arg = i + 1, select(i, ...)
  1304. end
  1305.  
  1306. if arg == nil or type(arg) == "number" then
  1307. i, colSpan, arg = i + 1, select(i, ...)
  1308. end
  1309.  
  1310. if arg == nil or type(arg) == "table" and type(arg.AcquireCell) == "function" then
  1311. i, provider = i + 1, arg
  1312. end
  1313.  
  1314. return _SetCell(self, lineNum, colNum, value, font, justification, colSpan, provider, select(i, ...))
  1315. end
  1316. end -- do-block
  1317.  
  1318. function tipPrototype:GetFont()
  1319. return self.regularFont
  1320. end
  1321.  
  1322. function tipPrototype:GetHeaderFont()
  1323. return self.headerFont
  1324. end
  1325.  
  1326. function tipPrototype:GetLineCount()
  1327. return #self.lines
  1328. end
  1329.  
  1330. function tipPrototype:GetColumnCount()
  1331. return #self.columns
  1332. end
  1333.  
  1334. ------------------------------------------------------------------------------
  1335. -- Frame Scripts
  1336. ------------------------------------------------------------------------------
  1337. local scripts = {
  1338. OnEnter = function(frame, ...)
  1339. highlightFrame:SetParent(frame)
  1340. highlightFrame:SetAllPoints(frame)
  1341. highlightFrame:Show()
  1342.  
  1343. if frame._OnEnter_func then
  1344. frame:_OnEnter_func(frame._OnEnter_arg, ...)
  1345. end
  1346. end,
  1347. OnLeave = function(frame, ...)
  1348. highlightFrame:Hide()
  1349. highlightFrame:ClearAllPoints()
  1350. highlightFrame:SetParent(nil)
  1351.  
  1352. if frame._OnLeave_func then
  1353. frame:_OnLeave_func(frame._OnLeave_arg, ...)
  1354. end
  1355. end,
  1356. OnMouseDown = function(frame, ...)
  1357. frame:_OnMouseDown_func(frame._OnMouseDown_arg, ...)
  1358. end,
  1359. OnMouseUp = function(frame, ...)
  1360. frame:_OnMouseUp_func(frame._OnMouseUp_arg, ...)
  1361. end,
  1362. OnReceiveDrag = function(frame, ...)
  1363. frame:_OnReceiveDrag_func(frame._OnReceiveDrag_arg, ...)
  1364. end
  1365. }
  1366.  
  1367. function SetFrameScript(frame, script, func, arg)
  1368. if not scripts[script] then
  1369. return
  1370. end
  1371.  
  1372. frame["_" .. script .. "_func"] = func
  1373. frame["_" .. script .. "_arg"] = arg
  1374.  
  1375. if script == "OnMouseDown" or script == "OnMouseUp" or script == "OnReceiveDrag" then
  1376. if func then
  1377. frame:SetScript(script, scripts[script])
  1378. else
  1379. frame:SetScript(script, nil)
  1380. end
  1381. end
  1382.  
  1383. -- if at least one script is set, set the OnEnter/OnLeave scripts for the highlight
  1384. if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
  1385. frame:EnableMouse(true)
  1386. frame:SetScript("OnEnter", scripts.OnEnter)
  1387. frame:SetScript("OnLeave", scripts.OnLeave)
  1388. else
  1389. frame:EnableMouse(false)
  1390. frame:SetScript("OnEnter", nil)
  1391. frame:SetScript("OnLeave", nil)
  1392. end
  1393. end
  1394.  
  1395. function ClearFrameScripts(frame)
  1396. if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
  1397. frame:EnableMouse(false)
  1398.  
  1399. frame:SetScript("OnEnter", nil)
  1400. frame._OnEnter_func = nil
  1401. frame._OnEnter_arg = nil
  1402.  
  1403. frame:SetScript("OnLeave", nil)
  1404. frame._OnLeave_func = nil
  1405. frame._OnLeave_arg = nil
  1406.  
  1407. frame:SetScript("OnReceiveDrag", nil)
  1408. frame._OnReceiveDrag_func = nil
  1409. frame._OnReceiveDrag_arg = nil
  1410.  
  1411. frame:SetScript("OnMouseDown", nil)
  1412. frame._OnMouseDown_func = nil
  1413. frame._OnMouseDown_arg = nil
  1414.  
  1415. frame:SetScript("OnMouseUp", nil)
  1416. frame._OnMouseUp_func = nil
  1417. frame._OnMouseUp_arg = nil
  1418. end
  1419. end
  1420.  
  1421. function tipPrototype:SetLineScript(lineNum, script, func, arg)
  1422. SetFrameScript(self.lines[lineNum], script, func, arg)
  1423. end
  1424.  
  1425. function tipPrototype:SetColumnScript(colNum, script, func, arg)
  1426. SetFrameScript(self.columns[colNum], script, func, arg)
  1427. end
  1428.  
  1429. function tipPrototype:SetCellScript(lineNum, colNum, script, func, arg)
  1430. local cell = self.lines[lineNum].cells[colNum]
  1431.  
  1432. if cell then
  1433. SetFrameScript(cell, script, func, arg)
  1434. end
  1435. end
  1436.  
  1437. ------------------------------------------------------------------------------
  1438. -- Auto-hiding feature
  1439. ------------------------------------------------------------------------------
  1440.  
  1441. -- Script of the auto-hiding child frame
  1442. local function AutoHideTimerFrame_OnUpdate(self, elapsed)
  1443. self.checkElapsed = self.checkElapsed + elapsed
  1444.  
  1445. if self.checkElapsed > 0.1 then
  1446. if self.parent:IsMouseOver() or (self.alternateFrame and self.alternateFrame:IsMouseOver()) then
  1447. self.elapsed = 0
  1448. else
  1449. self.elapsed = self.elapsed + self.checkElapsed
  1450.  
  1451. if self.elapsed >= self.delay then
  1452. lib:Release(self.parent)
  1453. end
  1454. end
  1455.  
  1456. self.checkElapsed = 0
  1457. end
  1458. end
  1459.  
  1460. -- Usage:
  1461. -- :SetAutoHideDelay(0.25) => hides after 0.25sec outside of the tooltip
  1462. -- :SetAutoHideDelay(0.25, someFrame) => hides after 0.25sec outside of both the tooltip and someFrame
  1463. -- :SetAutoHideDelay() => disable auto-hiding (default)
  1464. function tipPrototype:SetAutoHideDelay(delay, alternateFrame, releaseHandler)
  1465. local timerFrame = self.autoHideTimerFrame
  1466. delay = tonumber(delay) or 0
  1467.  
  1468. if releaseHandler then
  1469. if type(releaseHandler) ~= "function" then
  1470. error("releaseHandler must be a function", 2)
  1471. end
  1472.  
  1473. lib.onReleaseHandlers[self] = releaseHandler
  1474. end
  1475.  
  1476. if delay > 0 then
  1477. if not timerFrame then
  1478. timerFrame = AcquireFrame(self)
  1479. timerFrame:SetScript("OnUpdate", AutoHideTimerFrame_OnUpdate)
  1480.  
  1481. self.autoHideTimerFrame = timerFrame
  1482. end
  1483.  
  1484. timerFrame.parent = self
  1485. timerFrame.checkElapsed = 0
  1486. timerFrame.elapsed = 0
  1487. timerFrame.delay = delay
  1488. timerFrame.alternateFrame = alternateFrame
  1489. timerFrame:Show()
  1490. elseif timerFrame then
  1491. self.autoHideTimerFrame = nil
  1492.  
  1493. timerFrame.alternateFrame = nil
  1494. timerFrame:SetScript("OnUpdate", nil)
  1495.  
  1496. ReleaseFrame(timerFrame)
  1497. end
  1498. end
  1499.  
  1500. ------------------------------------------------------------------------------
  1501. -- "Smart" Anchoring
  1502. ------------------------------------------------------------------------------
  1503. local function GetTipAnchor(frame)
  1504. local x, y = frame:GetCenter()
  1505.  
  1506. if not x or not y then
  1507. return "TOPLEFT", "BOTTOMLEFT"
  1508. end
  1509.  
  1510. local hhalf = (x > UIParent:GetWidth() * 2 / 3) and "RIGHT" or (x < UIParent:GetWidth() / 3) and "LEFT" or ""
  1511. local vhalf = (y > UIParent:GetHeight() / 2) and "TOP" or "BOTTOM"
  1512.  
  1513. return vhalf .. hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP") .. hhalf
  1514. end
  1515.  
  1516. function tipPrototype:SmartAnchorTo(frame)
  1517. if not frame then
  1518. error("Invalid frame provided.", 2)
  1519. end
  1520.  
  1521. self:ClearAllPoints()
  1522. self:SetClampedToScreen(true)
  1523. self:SetPoint(GetTipAnchor(frame))
  1524. end
  1525.  
  1526. ------------------------------------------------------------------------------
  1527. -- Debug slashcmds
  1528. ------------------------------------------------------------------------------
  1529. -- @debug @
  1530. local print = print
  1531. local function PrintStats()
  1532. local tipCache = tostring(#tooltipHeap)
  1533. local frameCache = tostring(#frameHeap)
  1534. local tableCache = tostring(#tableHeap)
  1535. local header = false
  1536.  
  1537. print("Tooltips used: " .. usedTooltips .. ", Cached: " .. tipCache .. ", Total: " .. tipCache + usedTooltips)
  1538. print("Frames used: " .. usedFrames .. ", Cached: " .. frameCache .. ", Total: " .. frameCache + usedFrames)
  1539. print("Tables used: " .. usedTables .. ", Cached: " .. tableCache .. ", Total: " .. tableCache + usedTables)
  1540.  
  1541. for k in pairs(activeTooltips) do
  1542. if not header then
  1543. print("Active tooltips:")
  1544. header = true
  1545. end
  1546. print("- " .. k)
  1547. end
  1548. end
  1549.  
  1550. SLASH_LibQTip1 = "/qtip"
  1551. _G.SlashCmdList["LibQTip"] = PrintStats
  1552. --@end-debug@
  1553.  
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×