local MAJOR_VERSION = "1.0" local MINOR_VERSION = tonumber(string.sub("$Revision: 1867 $", 12, -3)) local DEBUG = false if TabletLib and TabletLib.versions[MAJOR_VERSION] and TabletLib.versions[MAJOR_VERSION].minor >= MINOR_VERSION then return end local SCROLL_UP, SCROLL_DOWN, HINT, DETACH, SIZE, CLOSE_MENU if GetLocale() == "deDE" then SCROLL_UP = "Hochscrolle" SCROLL_DOWN = "Herunterscrolle" HINT = "Hinweis" DETACH = "L\195\182sen" SIZE = "Größe" CLOSE_MENU = "Menü schließen" else SCROLL_UP = "Scroll up" SCROLL_DOWN = "Scroll down" HINT = "Hint" DETACH = "Detach" SIZE = "Size" CLOSE_MENU = "Close menu" end -------------IRIEL'S-STUB-CODE-------------- local stub = {}; -- Instance replacement method, replace contents of old with that of new function stub:ReplaceInstance(old, new) for k,v in pairs(old) do old[k]=nil; end for k,v in pairs(new) do old[k]=v; end end -- Get a new copy of the stub function stub:NewStub() local newStub = {}; self:ReplaceInstance(newStub, self); newStub.lastVersion = ''; newStub.versions = {}; return newStub; end -- Get instance version function stub:GetInstance(version) if (not version) then version = self.lastVersion; end local versionData = self.versions[version]; if (not versionData) then message("Cannot find library instance with version '" .. version .. "'"); return; end return versionData.instance; end -- Register new instance function stub:Register(newInstance) local version,minor = newInstance:GetLibraryVersion(); self.lastVersion = version; local versionData = self.versions[version]; if (not versionData) then -- This one is new! versionData = { instance = newInstance, minor = minor, old = {} }; self.versions[version] = versionData; newInstance:LibActivate(self); return newInstance; end if (minor <= versionData.minor) then -- This one is already obsolete if (newInstance.LibDiscard) then newInstance:LibDiscard(); end return versionData.instance; end -- This is an update local oldInstance = versionData.instance; local oldList = versionData.old; versionData.instance = newInstance; versionData.minor = minor; local skipCopy = newInstance:LibActivate(self, oldInstance, oldList); table.insert(oldList, oldInstance); if (not skipCopy) then for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance); end end return newInstance; end -- Bind stub to global scope if it's not already there if (not TabletLib) then TabletLib = stub:NewStub(); end -- Nil stub for garbage collection stub = nil; -----------END-IRIEL'S-STUB-CODE------------ local function assert(condition, message) if not condition then local stack = debugstack() local first = string.gsub(stack, "\n.*", "") local file = string.gsub(first, "^(.*\\.*)%.lua:%d+: .*", "%1") if not message then local _,_,second = string.find(stack, "\n(.-)\n") message = "assertion failed! " .. second end message = "TabletLib: " .. message local i = 1 for s in string.gfind(stack, "\n(.-)\n") do i = i + 1 if not string.find(s, file .. "%.lua:%d+:") then error(message, i) return end end error(message, 2) return end return condition end local start = GetTime() local wrap local GetProfileInfo if DEBUG then local tree = {} local treeMemories = {} local treeTimes = {} local memories = {} local times = {} function wrap(value, name) if type(value) == "function" then local oldFunction = value memories[name] = 0 times[name] = 0 return function(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60) local pos = table.getn(tree) table.insert(tree, name) table.insert(treeMemories, 0) table.insert(treeTimes, 0) local t, mem = GetTime(), gcinfo() local r1, r2, r3, r4, r5, r6, r7, r8 = oldFunction(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60) mem, t = gcinfo() - mem, GetTime() - t if pos > 0 then treeMemories[pos] = treeMemories[pos] + mem treeTimes[pos] = treeTimes[pos] + t end local otherMem = table.remove(treeMemories) if mem - otherMem > 0 then memories[name] = memories[name] + mem - otherMem end times[name] = times[name] + t - table.remove(treeTimes) table.remove(tree) return r1, r2, r3, r4, r5, r6, r7, r8 end end end function GetProfileInfo() return GetTime() - start, times, memories end else function wrap(value) return value end end local MIN_TOOLTIP_SIZE = 200 local lib = {} local ipairs = ipairs local tinsert = table.insert local tremove = table.remove local tgetn = table.getn local function getsecond(_, value) return value end local dewdrop local sekeys local CleanCategoryPool local pool = {} local function del(t) if t then if DEBUG and t[".poolprint"] then print(t[".poolprint"]) end for k in pairs(t) do t[k] = nil end setmetatable(t, nil) table.setn(t, 0) table.insert(pool, t) end end local new local function copy(parent) local t if table.getn(pool) > 0 then t = table.remove(pool) else t = {} end if parent then for k,v in pairs(parent) do t[k] = v end table.setn(t, table.getn(parent)) setmetatable(t, getmetatable(parent)) end return t end function new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) local t if table.getn(pool) > 0 then t = table.remove(pool) else t = {} end if k1 then t[k1] = v1 if k2 then t[k2] = v2 if k3 then t[k3] = v3 if k4 then t[k4] = v4 if k5 then t[k5] = v5 if k6 then t[k6] = v6 if k7 then t[k7] = v7 if k8 then t[k8] = v8 if k9 then t[k9] = v9 if k10 then t[k10] = v10 if k11 then t[k11] = v11 if k12 then t[k12] = v12 if k13 then t[k13] = v13 if k14 then t[k14] = v14 if k15 then t[k15] = v15 if k16 then t[k16] = v16 if k17 then t[k17] = v17 if k18 then t[k18] = v18 if k19 then t[k19] = v19 if k20 then t[k20] = v20 if k21 then t[k21] = v21 if k22 then t[k22] = v22 if k23 then t[k23] = v23 if k24 then t[k24] = v24 if k25 then t[k25] = v25 if k26 then t[k26] = v26 if k27 then t[k27] = v27 if k28 then t[k28] = v28 if k29 then t[k29] = v29 if k30 then t[k30] = v30 end end end end end end end end end end end end end end end end end end end end end end end end end end end end end end return t end local tmp tmp = setmetatable({}, {__index = function(self, key) local t = {} tmp[key] = function(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) for k in pairs(t) do t[k] = nil end if k1 then t[k1] = v1 if k2 then t[k2] = v2 if k3 then t[k3] = v3 if k4 then t[k4] = v4 if k5 then t[k5] = v5 if k6 then t[k6] = v6 if k7 then t[k7] = v7 if k8 then t[k8] = v8 if k9 then t[k9] = v9 if k10 then t[k10] = v10 if k11 then t[k11] = v11 if k12 then t[k12] = v12 if k13 then t[k13] = v13 if k14 then t[k14] = v14 if k15 then t[k15] = v15 if k16 then t[k16] = v16 if k17 then t[k17] = v17 if k18 then t[k18] = v18 if k19 then t[k19] = v19 if k20 then t[k20] = v20 if k21 then t[k21] = v21 if k22 then t[k22] = v22 if k23 then t[k23] = v23 if k24 then t[k24] = v24 if k25 then t[k25] = v25 if k26 then t[k26] = v26 if k27 then t[k27] = v27 if k28 then t[k28] = v28 if k29 then t[k29] = v29 if k30 then t[k30] = v30 end end end end end end end end end end end end end end end end end end end end end end end end end end end end end end return t end return tmp[key] end}) function lib:GetLibraryVersion() return MAJOR_VERSION, MINOR_VERSION end function lib:LibActivate(stub, oldLib, oldList) if oldLib then self.registry = oldLib.registry self.onceRegistered = oldLib.onceRegistered else self.registry = {} self.onceRegistered = {} end end function lib:LibDeactivate(stub) end local _,headerSize = GameTooltipHeaderText:GetFont() local _,normalSize = GameTooltipText:GetFont() local tooltip local testString local TabletData = {} local Category = {} local Line = {} do local TabletData_mt = { __index = TabletData } function TabletData:new(tablet) if not testString then testString = UIParent:CreateFontString() testString:Hide() end local self = new() self.categories = new() self.id = 0 self.width = 0--(MIN_TOOLTIP_SIZE - 20)*tablet.fontSizePercent self.tablet = tablet self.title = "Title" setmetatable(self, TabletData_mt) return self end function TabletData:del() for k, v in ipairs(self.categories) do v:del() end del(self.categories) del(self) end function TabletData:print(id) printFull(id, self) end function TabletData:Display() if self.tablet == tooltip then local info = new( 'hideBlankLine', true, 'text', self.title, 'justify', "CENTER", 'font', GameTooltipHeaderText, 'isTitle', true ) self:AddCategory(info, 1) del(info) if self.hint then self:AddCategory(nil):AddLine( 'text', HINT .. ": " .. self.hint, 'textR', 0, 'textG', 1, 'textB', 0, 'wrap', true ) end end local tabletData = self.tabletData local width for k, v in ipairs(self.categories) do if v.columns <= 2 then width = v.x1 else width = v.x1 + v.x2 + v.x3 + v.x4 + (v.columns - 1) * 20 end if self.width < width then self.width = width end end local good = false local lastTitle = true for k, v in ipairs(self.categories) do if lastTitle then v.hideBlankLine = true lastTitle = false end if v:Display(self.tablet) then good = true end if v.isTitle then lastTitle = true end end if not good then local width local info = new( 'hideBlankLine', true, 'text', self.title, 'justify', "CENTER", 'font', GameTooltipHeaderText, 'isTitle', true ) local cat = self:AddCategory(info) del(info) self.width = self.categories[table.getn(self.categories)].x1 cat:Display(self.tablet) end end function TabletData:AddCategory(info, index) local made = false if not info then made = true info = new() end local cat = Category:new(self, info) if index then table.insert(self.categories, index, cat) else table.insert(self.categories, cat) end if made then del(info) end return cat end function TabletData:SetHint(hint) self.hint = hint end function TabletData:SetTitle(title) self.title = title or "Title" end end do local Category_mt = { __index = Category } function Category:new(tabletData, info, superCategory) local self = copy(info) if superCategory and not self.noInherit then self.superCategory = superCategory.superCategory for k, v in pairs(superCategory) do if string.find(k, "^child_") then local k = strsub(k, 7) if self[k] == nil then self[k] = v end end end self.columns = superCategory.columns else self.superCategory = self end self.tabletData = tabletData self.lines = new() if not self.columns then self.columns = 1 end self.x1 = 0 self.x2 = 0 self.x3 = 0 self.x4 = 0 setmetatable(self, Category_mt) self.lastWasTitle = nil if self.text or self.text2 or self.text3 or self.text4 then local x = new( 'category', category, 'text', self.text, 'textR', self.textR or 1, 'textG', self.textG or 1, 'textB', self.textB or 1, 'fakeChild', true, 'func', self.func, 'arg1', info.arg1, 'arg2', self.arg2, 'arg3', self.arg3, 'hasCheck', self.hasCheck, 'checked', self.checked, 'checkIcon', self.checkIcon, 'isRadio', self.isRadio, 'font', self.font, 'size', self.size, 'wrap', self.wrap, 'catStart', true, 'indentation', self.indentation, 'noInherit', true, 'justify', self.justify, 'justify2', self.justify2, 'justify3', self.justify3, 'justify4', self.justify4 ) if self.isTitle then x.textR = self.textR or 1 x.textG = self.textG or 0.823529 x.textB = self.textB or 0 else x.textR = self.textR or 1 x.textG = self.textG or 1 x.textB = self.textB or 1 end x.text2 = self.text2 x.text3 = self.text3 x.text4 = self.text4 x.text2R = self.text2R or self.textR2 or 1 x.text2G = self.text2G or self.textG2 or 1 x.text2B = self.text2B or self.textB2 or 1 x.text3R = self.text3R or self.textR3 or 1 x.text3G = self.text3G or self.textG3 or 1 x.text3B = self.text3B or self.textB3 or 1 x.text4R = self.text4R or self.textR4 or 1 x.text4G = self.text4G or self.textG4 or 1 x.text4B = self.text4B or self.textB4 or 1 x.font2 = self.font2 x.font3 = self.font3 x.font4 = self.font4 x.size2 = self.size2 x.size3 = self.size3 x.size4 = self.size4 self:AddLine(x) del(x) self.lastWasTitle = true end return self end function Category:del() local prev = garbageLine for k, v in pairs(self.lines) do v:del() end del(self.lines) del(self) end function Category:AddLine(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) self.lastWasTitle = nil local line if type(k1) == "table" then Line:new(self, k1, v1) else local info = new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) Line:new(self, info) del(info) end end function Category:AddCategory(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) local lastWasTitle = self.lastWasTitle self.lastWasTitle = nil local info if type(k1) == "table" then info = k1 else info = new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) end if lastWasTitle or table.getn(self.lines) == 0 then info.hideBlankLine = true end local cat = Category:new(self.tabletData, info, self) table.insert(self.lines, cat) return cat end function Category:HasChildren() local hasChildren = false for k, v in ipairs(self.lines) do if v.HasChildren then if v:HasChildren() then return true end end if not v.fakeChild then return true end end return false end local lastWasTitle = false function Category:Display(tablet) if not self.isTitle and not self.showWithoutChildren and not self:HasChildren() then return false end if not self.hideBlankLine and not lastWasTitle then local info = new( 'blank', true, 'fakeChild', true ) self:AddLine(info, 1) del(info) end local good = false if table.getn(self.lines) > 0 then self.tabletData.id = self.tabletData.id + 1 self.id = self.tabletData.id for k, v in ipairs(self.lines) do if v:Display(tablet) then good = true end end end lastWasTitle = self.isTitle return good end end do local Line_mt = { __index = Line } function Line:new(category, info, position) local self = copy(info) if not info.noInherit then for k, v in pairs(category) do if string.find(k, "^child_") then local k = strsub(k, 7) if self[k] == nil then self[k] = v end end end end self.category = category if position then table.insert(category.lines, position, self) else table.insert(category.lines, self) end setmetatable(self, Line_mt) local columns = category.columns if columns == 1 then if not self.justify then self.justify = "LEFT" end elseif columns == 2 then self.justify = "LEFT" self.justify2 = "RIGHT" if self.wrap then self.wrap2 = false end elseif columns == 3 then if not self.justify then self.justify = "LEFT" end if not self.justify2 then self.justify2 = "CENTER" end if not self.justify3 then self.justify3 = "RIGHT" end if self.wrap then self.wrap2 = false self.wrap3 = false elseif self.wrap2 then self.wrap3 = false end elseif columns == 4 then if not self.justify then self.justify = "LEFT" end if not self.justify2 then self.justify2 = "CENTER" end if not self.justify3 then self.justify3 = "CENTER" end if not self.justify4 then self.justify4 = "RIGHT" end if self.wrap then self.wrap2 = false self.wrap3 = false self.wrap4 = false elseif self.wrap2 then self.wrap3 = false self.wrap4 = false elseif self.wrap3 then self.wrap4 = false end end if self.textR2 then self.text2R, self.textR2 = self.text2R or self.textR2 self.text2G, self.textG2 = self.text2G or self.textG2 self.text2B, self.textB2 = self.text2B or self.textB2 if self.textR3 then self.text3R, self.textR3 = self.text3R or self.textR3 self.text3G, self.textG3 = self.text3G or self.textG3 self.text3B, self.textB3 = self.text3B or self.textB3 if self.textR4 then self.text4R, self.textR4 = self.text4R or self.textR4 self.text4G, self.textG4 = self.text4G or self.textG4 self.text4B, self.textB4 = self.text4B or self.textB4 end end end if not self.indentation or self.indentation < 0 then self.indentation = 0 end if not self.font then self.font = GameTooltipText end if not self.font2 then self.font2 = self.font end if not self.font3 then self.font3 = self.font end if not self.font4 then self.font4 = self.font end if not self.size then _,self.size = self.font:GetFont() end if not self.size2 then _,self.size2 = self.font2:GetFont() end if not self.size3 then _,self.size3 = self.font3:GetFont() end if not self.size4 then _,self.size4 = self.font4:GetFont() end local fontSizePercent = category.tabletData.tablet.fontSizePercent local w = 0 if self.text then if not self.wrap then testString:SetWidth(0) testString:SetFontObject(self.font) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size * fontSizePercent, flags) testString:SetText(self.text) local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 w = testString:GetWidth() + self.indentation * fontSizePercent if self.hasCheck then w = w + self.size end if category.superCategory.x1 < w then category.superCategory.x1 = w end else if columns == 1 then testString:SetWidth(0) testString:SetFontObject(self.font) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size * fontSizePercent, flags) testString:SetText(self.text) local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 w = testString:GetWidth() + self.indentation * fontSizePercent if self.hasCheck then w = w + self.size end if w > (MIN_TOOLTIP_SIZE - 20) * fontSizePercent then w = (MIN_TOOLTIP_SIZE - 20) * fontSizePercent end else w = MIN_TOOLTIP_SIZE * fontSizePercent / 2 end if category.superCategory.x1 < w then category.superCategory.x1 = w end end end if columns == 2 and self.text2 then if not self.wrap2 then testString:SetWidth(0) testString:SetFontObject(self.font2) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size2 * fontSizePercent, flags) testString:SetText(self.text2) w = w + 40 * fontSizePercent + testString:GetWidth() if category.superCategory.x1 < w then category.superCategory.x1 = w end else w = w + 40 * fontSizePercent + MIN_TOOLTIP_SIZE * fontSizePercent / 2 if category.superCategory.x1 < w then category.superCategory.x1 = w end end elseif columns >= 3 then if self.text2 then if not self.wrap2 then testString:SetWidth(0) testString:SetFontObject(self.font2) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size2 * fontSizePercent, flags) testString:SetText(self.text2) local w = testString:GetWidth() if category.superCategory.x2 < w then category.superCategory.x2 = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory.x2 < w then category.superCategory.x2 = w end end end if self.text3 then if not self.wrap3 then testString:SetWidth(0) testString:SetFontObject(self.font3) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size3 * fontSizePercent, flags) testString:SetText(self.text3) local w = testString:GetWidth() if category.superCategory.x3 < w then category.superCategory.x3 = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory.x3 < w then category.superCategory.x3 = w end end end if columns >= 4 then if self.text4 then if not self.wrap4 then testString:SetWidth(0) testString:SetFontObject(self.font4) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size4 * fontSizePercent, flags) testString:SetText(self.text4) w = testString:GetWidth() if category.superCategory.x4 < w then category.superCategory.x4 = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory.x4 < w then category.superCategory.x4 = w end end end end end return self end function Line:del() del(self) end function Line:Display(tablet) tablet:AddLine(self) return true end end local function button_OnEnter() if this.self:GetScript("OnEnter") then this.self:GetScript("OnEnter")() end this.highlight:Show() end local function button_OnLeave() if this.self:GetScript("OnLeave") then this.self:GetScript("OnLeave")() end this.highlight:Hide() end local function NewLine(self) if self.maxLines <= self.numLines then self.maxLines = self.maxLines + 1 local button = CreateFrame("Button", nil, self) button.indentation = 0 local check = button:CreateTexture(nil, "ARTWORK") local left = button:CreateFontString(nil, "ARTWORK") local right = button:CreateFontString(nil, "ARTWORK") local third = button:CreateFontString(nil, "ARTWORK") local fourth = button:CreateFontString(nil, "ARTWORK") local highlight = button:CreateTexture(nil, "BACKGROUND") highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") button.highlight = highlight highlight:SetBlendMode("ADD") highlight:SetAllPoints(button) highlight:Hide() table.insert(self.buttons, button) table.insert(self.checks, check) table.insert(self.lefts, left) table.insert(self.rights, right) table.insert(self.thirds, third) table.insert(self.fourths, fourth) left:SetWidth(0) if self.maxLines == 1 then left:SetFontObject(GameTooltipHeaderText) right:SetFontObject(GameTooltipHeaderText) third:SetFontObject(GameTooltipHeaderText) fourth:SetFontObject(GameTooltipHeaderText) left:SetJustifyH("CENTER") button:SetPoint("TOPLEFT", self, "TOPLEFT", 8, -10) else left:SetFontObject(GameTooltipText) right:SetFontObject(GameTooltipText) third:SetFontObject(GameTooltipText) fourth:SetFontObject(GameTooltipText) button:SetPoint("TOPLEFT", self.buttons[self.maxLines - 1], "BOTTOMLEFT", 0, -2) end button:SetScript("OnEnter", button_OnEnter) button:SetScript("OnLeave", button_OnLeave) button.check = check button.self = self button:SetPoint("RIGHT", self, "RIGHT", -12, 0) check.shown = false check:SetPoint("TOPLEFT", button, "TOPLEFT") left:SetPoint("TOPLEFT", check, "TOPLEFT") right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * self.fontSizePercent, 0) third:SetPoint("TOPLEFT", right, "TOPRIGHT", 20 * self.fontSizePercent, 0) fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", 20 * self.fontSizePercent, 0) right:SetJustifyH("RIGHT") local _,size = GameTooltipText:GetFont() check:SetHeight(size * 1.5) check:SetWidth(size * 1.5) check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") check:SetAlpha(0) if not button.clicked then button:SetScript("OnMouseWheel", self:GetScript("OnMouseWheel")) button:EnableMouseWheel(true) button:Hide() end check:Show() left:Hide() right:Hide() end end NewLine = wrap(NewLine, "NewLine") local function GetMaxLinesPerScreen(self) if self == tooltip then return floor(50 / self.fontSizePercent) else return floor(30 / self.fontSizePercent) end end GetMaxLinesPerScreen = wrap(GetMaxLinesPerScreen, "GetMaxLinesPerScreen") local detachedTooltips = {} local AcquireDetachedFrame, ReleaseDetachedFrame local function AcquireFrame(self, registration, data, detachedData) if not detachedData then detachedData = data end if tooltip then tooltip.data = data tooltip.detachedData = detachedData local fontSizePercent = tooltip.data and tooltip.data.fontSizePercent or 1 local transparency = tooltip.data and tooltip.data.transparency or 0.75 local r = tooltip.data and tooltip.data.r or 0 local g = tooltip.data and tooltip.data.g or 0 local b = tooltip.data and tooltip.data.b or 0 tooltip:SetFontSizePercent(fontSizePercent) tooltip:SetTransparency(transparency) tooltip:SetColor(r, g, b) else tooltip = CreateFrame("Frame", "TabletLibFrame", UIParent) tooltip.data = data tooltip.detachedData = detachedData tooltip:EnableMouse(true) tooltip:EnableMouseWheel(true) tooltip:SetFrameStrata("TOOLTIP") tooltip:SetFrameLevel(10) local backdrop = new( 'bgFile', "Interface\\Buttons\\WHITE8X8", 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", 'tile', true, 'tileSize', 16, 'edgeSize', 16, 'insets', new( 'left', 5, 'right', 5, 'top', 5, 'bottom', 5 ) ) tooltip:SetBackdrop(backdrop) del(backdrop.insets) del(backdrop) tooltip:SetBackdropColor(0, 0, 0, 1) tooltip.numLines = 0 --tooltip.categoryLines = {} tooltip.idLines = {} tooltip.categories = 0 tooltip.owner = nil tooltip.fontSizePercent = tooltip.data and tooltip.data.fontSizePercent or 1 tooltip.maxLines = 0 tooltip.buttons = {} tooltip.checks = {} tooltip.lefts = {} tooltip.rights = {} tooltip.thirds = {} tooltip.fourths = {} tooltip.transparency = tooltip.data and tooltip.data.transparency or 0.75 tooltip:SetBackdropColor(0, 0, 0, tooltip.transparency) tooltip:SetBackdropBorderColor(1, 1, 1, tooltip.transparency) tooltip.scroll = 0 tooltip:SetScript("OnUpdate", function() if not tooltip.updating and not tooltip.enteredFrame then tooltip.scroll = 0 tooltip:Hide() tooltip.registration.tooltip = nil tooltip.registration = nil end end) tooltip:SetScript("OnEnter", function() if tooltip.clickable then tooltip.enteredFrame = true end end) tooltip:SetScript("OnLeave", function() if not tooltip.updating then tooltip.enteredFrame = false end end) tooltip:SetScript("OnMouseWheel", function() tooltip.updating = true tooltip:Scroll(arg1 < 0) tooltip.updating = false end) NewLine(tooltip) tooltip.scrollUp = tooltip:CreateFontString(nil, "ARTWORK") tooltip.scrollUp:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2) tooltip.scrollUp:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10) tooltip.scrollUp:SetFontObject(GameTooltipText) tooltip.scrollUp:Hide() local font,_,flags = tooltip.scrollUp:GetFont() tooltip.scrollUp:SetFont(font, normalSize * tooltip.fontSizePercent, flags) tooltip.scrollUp:SetJustifyH("CENTER") tooltip.scrollUp:SetTextColor(1, 0.823529, 0) tooltip.scrollUp:SetText(" ") tooltip.scrollDown = tooltip:CreateFontString(nil, "ARTWORK") tooltip.scrollDown:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2) tooltip.scrollDown:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10) tooltip.scrollDown:SetFontObject(GameTooltipText) tooltip.scrollDown:Hide() local font,_,flags = tooltip.scrollUp:GetFont() tooltip.scrollDown:SetFont(font, normalSize * tooltip.fontSizePercent, flags) tooltip.scrollDown:SetJustifyH("CENTER") tooltip.scrollDown:SetTextColor(1, 0.823529, 0) tooltip.scrollDown:SetText(" ") function tooltip:SetOwner(o) self:Hide(o) self.owner = o end tooltip.SetOwner = wrap(tooltip.SetOwner, "tooltip:SetOwner") function tooltip:IsOwned(o) return self.owner == o end tooltip.IsOwned = wrap(tooltip.IsOwned, "tooltip:IsOwned") function tooltip:ClearLines(hide) CleanCategoryPool(self) for i = 1, self.numLines do local button = self.buttons[i] local check = self.checks[i] if not button.clicked or hide then button:Hide() end check.shown = false check:SetAlpha(0) end for key,_ in pairs(self.idLines) do local i = self.idLines[key] if i then local check = self.checks[i] if check and check.shown then check.shown = false check:SetAlpha(0) end end self.idLines[key] = nil end self.numLines = 0 self.categories = 0 end tooltip.ClearLines = wrap(tooltip.ClearLines, "tooltip:ClearLines") function tooltip:NumLines() return self.numLines end local lastWidth local old_tooltip_Hide = tooltip.Hide function tooltip:Hide(newOwner) if self == tooltip or newOwner == nil then old_tooltip_Hide(self) end self:ClearLines(true) self.owner = nil self.lastWidth = nil end tooltip.Hide = wrap(tooltip.Hide, "tooltip:Hide") local old_tooltip_Show = tooltip.Show function tooltip:Show(tabletData) if self.owner == nil or self.notInUse then return end old_tooltip_Show(self) local maxWidth = tabletData and tabletData.width or self:GetWidth() - 20 local hasWrap = false local screenWidth = GetScreenWidth() local scrollMax = self.numLines if scrollMax > GetMaxLinesPerScreen(self) + self.scroll then scrollMax = GetMaxLinesPerScreen(self) + self.scroll end local numColumns local x1, x2, x3, x4 = 0, 0, 0, 0 local height = 20 if scrollMax ~= self.numLines then self.scrollDown:SetWidth(maxWidth) height = height + self.scrollDown:GetHeight() + 2 end if self.scroll ~= 0 then self.scrollUp:SetWidth(maxWidth) height = height + self.scrollUp:GetHeight() + 2 end self:SetWidth(maxWidth + 20) local tmp = self.scroll + 1 if tmp ~= 1 then tmp = tmp + 1 end for i = 1, self.numLines do if i < tmp or i > scrollMax then self.buttons[i]:ClearAllPoints() self.buttons[i]:Hide() else if i ~= scrollMax or i == self.numLines then local button = self.buttons[i] local left = self.lefts[i] local right = self.rights[i] local third = self.thirds[i] local fourth = self.fourths[i] local check = self.checks[i] button:SetWidth(maxWidth) button:SetHeight(math.max(left:GetHeight(), right:GetHeight(), third:GetHeight(), fourth:GetHeight())) height = height + button:GetHeight() + 2 if i == self.scroll + 1 then button:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10) else button:SetPoint("TOPLEFT", self.buttons[i - 1], "BOTTOMLEFT", 0, -2) end if button.clicked then check:SetPoint("TOPLEFT", button, "TOPLEFT", button.indentation * self.fontSizePercent + (check.width - check:GetWidth()) / 2 + 1, -1) else check:SetPoint("TOPLEFT", button, "TOPLEFT", button.indentation * self.fontSizePercent + (check.width - check:GetWidth()) / 2, 0) end button:Show() end end end if self.scroll ~= 0 then self.scrollUp:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10) self.buttons[self.scroll + 2]:SetPoint("TOPLEFT", self.scrollUp, "BOTTOMLEFT", 0, -2) self.scrollUp:SetText(SCROLL_UP .. " (" .. self.scroll + 2 .. " / " .. self.numLines .. ")") self.scrollUp:Show() else self.scrollUp:Hide() end if scrollMax ~= self.numLines and self.buttons[scrollMax - 1] then self.scrollDown:SetPoint("TOPLEFT", self.buttons[scrollMax - 1], "BOTTOMLEFT", 0, -2) self.scrollDown:SetText(SCROLL_DOWN .. " (" .. scrollMax - 1 .. " / " .. self.numLines .. ")") self.scrollDown:Show() else self.scrollDown:Hide() end self:SetHeight(height) end tooltip.Show = wrap(tooltip.Show, "tooltip:Show") local lastMouseDown local function button_OnClick() if this.self:HasScript("OnClick") and this.self:GetScript("OnClick") then this.self:GetScript("OnClick")() end if arg1 == "RightButton" then if this.self:HasScript("OnClick") and this.self:GetScript("OnClick") then this.self:GetScript("OnClick")() end elseif arg1 == "LeftButton" then if this.self.preventClick == nil or GetTime() > this.self.preventClick and GetTime() < lastMouseDown + 0.5 then this.self.preventClick = nil this.self.updating = true this.self.preventRefresh = true this.func(this.a1, this.a2, this.a3) this.self.preventRefresh = false this.self:children() this.self.updating = false end end end local function button_OnMouseUp() if this.self:HasScript("OnMouseUp") and this.self:GetScript("OnMouseUp") then this.self:GetScript("OnMouseUp")() end if arg1 ~= "RightButton" then if this.clicked then local a,b,c,d,e = this.check:GetPoint(1) this.check:SetPoint(a,b,c,d-1,e+1) this.clicked = false end end end local function button_OnMouseDown() if this.self:HasScript("OnMouseDown") and this.self:GetScript("OnMouseDown") then this.self:GetScript("OnMouseDown")() end lastMouseDown = GetTime() if arg1 ~= "RightButton" then local a,b,c,d,e = this.check:GetPoint(1) this.check:SetPoint(a,b,c,d+1,e-1) this.clicked = true end end function tooltip:AddLine(info) local category = info.category local maxWidth = category.tabletData.width local text = info.blank and "\n" or info.text local id = info.id local func = info.func local checked = info.checked local isRadio = info.isRadio local checkTexture = info.checkTexture local fontSizePercent = self.fontSizePercent if not info.font then info.font = GameTooltipText end if not info.size then _,info.size = info.font:GetFont() end local catStart = false local columns = category and category.columns or 1 local x1, x2, x3, x4 if category then x1, x2, x3, x4 = category.x1, category.x2, category.x3, category.x4 else x1, x2, x3, x4 = 0, 0, 0, 0 end if info.isTitle then justAddedTitle = true end self.numLines = self.numLines + 1 NewLine(self) self.lefts[self.numLines]:Show() self.buttons[self.numLines]:Show() num = self.numLines if id ~= nil and self.idLines[id] == nil then self.idLines[id] = num end local button = self.buttons[num] button.indentation = info.indentation-- or 0 local left = self.lefts[num] local right = self.rights[num] local third = self.thirds[num] local fourth = self.fourths[num] local check = self.checks[num] if columns >= 1 then left:SetFontObject(info.font) left:SetText(text) left:Show() if info.textR and info.textG and info.textB then left:SetTextColor(info.textR, info.textG, info.textB) else left:SetTextColor(1, 0.823529, 0) end local a,_,b = left:GetFont() left:SetFont(a, info.size * fontSizePercent, b) left:SetJustifyH(info.justify) end if columns >= 2 then right:SetFontObject(info.font2) right:SetText(info.text2) right:Show() if info.text2R and info.text2G and info.text2B then right:SetTextColor(info.text2R, info.text2G, info.text2B) else right:SetTextColor(1, 0.823529, 0) end local a,_,b = right:GetFont() right:SetFont(a, info.size2 * fontSizePercent, b) right:SetJustifyH(info.justify2) else right:SetText(nil) right:Hide() end if columns >= 3 then third:SetFontObject(info.font3) third:SetText(info.text3) third:Show() if info.text3R and info.text3G and info.text3B then third:SetTextColor(info.text3R, info.text3G, info.text3B) else third:SetTextColor(1, 0.823529, 0) end local a,_,b = third:GetFont() third:SetFont(a, info.size3 * fontSizePercent, b) right:ClearAllPoints() right:SetPoint("TOPLEFT", left, "TOPRIGHT", 20 * fontSizePercent, 0) third:SetJustifyH(info.justify3) else third:SetText(nil) third:Hide() right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * fontSizePercent, 0) right:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) end if columns >= 4 then fourth:SetFontObject(info.font4) fourth:SetText(info.text4) fourth:Show() if info.text4R and info.text4G and info.text4B then fourth:SetTextColor(info.text4R, info.text4G, info.text4B) else fourth:SetTextColor(1, 0.823529, 0) end local a,_,b = fourth:GetFont() fourth:SetFont(a, info.size4 * fontSizePercent, b) fourth:SetJustifyH(info.justify4) else fourth:SetText(nil) fourth:Hide() end check:SetWidth(info.size) check:SetHeight(info.size) check.width = info.size if info.hasCheck then check.shown = true check:Show() if isRadio then check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") if info.checked then check:SetAlpha(1) check:SetTexCoord(0.25, 0.5, 0, 1) else check:SetAlpha(self.transparency) check:SetTexCoord(0, 0.25, 0, 1) end else if info.checkIcon then check:SetTexture(info.checkIcon) else check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") check:SetWidth(info.size * 1.5) check:SetHeight(info.size * 1.5) check.width = info.size * 1.2 end check:SetTexCoord(0, 1, 0, 1) check:SetAlpha(info.checked and 1 or 0) end left:SetPoint("TOPLEFT", check, "TOPLEFT", check.width, 0) else left:SetPoint("TOPLEFT", check, "TOPLEFT") end if columns == 1 then left:SetWidth(maxWidth) elseif columns == 2 then left:SetWidth(0) right:SetWidth(0) if info.wrap then left:SetWidth(maxWidth - right:GetWidth() - 40 * fontSizePercent) elseif info.wrap2 then right:SetWidth(maxWidth - left:GetWidth() - 40 * fontSizePercent) end right:ClearAllPoints() right:SetPoint("TOPRIGHT", button, "TOPRIGHT", 0, 0) if not info.text2 then left:SetJustifyH(info.justify or "LEFT") end elseif columns == 3 then left:SetWidth(x1) right:SetWidth(x2) third:SetWidth(x3) right:ClearAllPoints() local num = (category.tabletData.width - x1 - x2 - x3) / 2 right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) elseif columns == 4 then left:SetWidth(x1) right:SetWidth(x2) third:SetWidth(x3) fourth:SetWidth(x4) local num = (category.tabletData.width - x1 - x2 - x3 - x4) / 3 right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) end if not self.locked or IsAltKeyDown() then local func = info.func if func then if type(func) == "string" then assert(type(info.arg1) == "table", "Cannot call method " .. info.func .. " on a non-table") func = info.arg1[func] assert(type(func) == "function", "Method " .. info.func .. " nonexistant") end assert(type(func) == "function", "func must be a function or method") button.func = func button.a1 = info.arg1 button.a2 = info.arg2 button.a3 = info.arg3 button.self = self button:SetScript("OnMouseUp", button_OnMouseUp) button:SetScript("OnMouseDown", button_OnMouseDown) button:SetScript("OnClick", button_OnClick) if button.clicked then button:SetButtonState("PUSHED") end button:EnableMouse(true) else button:SetScript("OnMouseDown", nil) button:SetScript("OnMouseUp", nil) button:SetScript("OnClick", nil) button:EnableMouse(false) end else button:SetScript("OnMouseDown", nil) button:SetScript("OnMouseUp", nil) button:SetScript("OnClick", nil) button:EnableMouse(false) end end tooltip.AddLine = wrap(tooltip.AddLine, "tooltip:AddLine") function tooltip:SetFontSizePercent(percent) local data, detachedData = self.data, self.detachedData if detachedData and detachedData.detached then data = detachedData end local lastSize = self.fontSizePercent percent = tonumber(percent) or 1 if percent < 0.25 then percent = 0.25 elseif percent > 4 then percent = 4 end self.fontSizePercent = percent if data then data.fontSizePercent = percent ~= 1 and percent or nil end self.scrollUp:SetFont(font, normalSize * self.fontSizePercent, flags) self.scrollDown:SetFont(font, normalSize * self.fontSizePercent, flags) local ratio = self.fontSizePercent / lastSize for i = 1, self.numLines do local left = self.lefts[i] local right = self.rights[i] local third = self.thirds[i] local fourth = self.fourths[i] local check = self.checks[i] local font, size, flags = left:GetFont() left:SetFont(font, size * ratio, flags) local font, size, flags = right:GetFont() right:SetFont(font, size * ratio, flags) local font, size, flags = third:GetFont() third:SetFont(font, size * ratio, flags) local font, size, flags = fourth:GetFont() fourth:SetFont(font, size * ratio, flags) check.width = check.width * ratio check:SetWidth(check:GetWidth() * ratio) check:SetHeight(check:GetHeight() * ratio) end self:SetWidth((self:GetWidth() - 51) * ratio + 51) self:SetHeight((self:GetHeight() - 51) * ratio + 51) if self:IsShown() and self.children then self:Show() end end tooltip.SetFontSizePercent = wrap(tooltip.SetFontSizePercent, "tooltip:SetFontSizePercent") function tooltip:GetFontSizePercent() return self.fontSizePercent end function tooltip:SetTransparency(alpha) local data, detachedData = self.data, self.detachedData if detachedData and detachedData.detached then data = detachedData end self.transparency = alpha if data then data.transparency = alpha ~= 0.75 and alpha or nil end self:SetBackdropColor(self.r or 0, self.g or 0, self.b or 0, alpha) self:SetBackdropBorderColor(1, 1, 1, alpha) end tooltip.SetTransparency = wrap(tooltip.SetTransparency, "tooltip:SetTransparency") function tooltip:GetTransparency() return self.transparency end function tooltip:SetColor(r, g, b) local data, detachedData = self.data, self.detachedData if detachedData and detachedData.detached then data = detachedData end self.r = r self.g = g self.b = b if data then data.r = r ~= 0 and r or nil data.g = g ~= 0 and g or nil data.b = b ~= 0 and b or nil end self:SetBackdropColor(r or 0, g or 0, b or 0, self.transparency) self:SetBackdropBorderColor(1, 1, 1, self.transparency) end tooltip.SetColor = wrap(tooltip.SetColor, "tooltip:SetColor") function tooltip:GetColor() return self.r, self.g, self.b end function tooltip:Scroll(down) if down then if IsShiftKeyDown() then self.scroll = self.numLines - GetMaxLinesPerScreen(self) else self.scroll = self.scroll + 3 end else if IsShiftKeyDown() then self.scroll = 0 else self.scroll = self.scroll - 3 end end if self.scroll > self.numLines - GetMaxLinesPerScreen(self) then self.scroll = self.numLines - GetMaxLinesPerScreen(self) end if self.scroll < 0 then self.scroll = 0 end if self:IsShown() then self:Show() end end tooltip.Scroll = wrap(tooltip.Scroll, "tooltip:Scroll") function tooltip.Detach(tooltip) local owner = tooltip.owner tooltip:Hide() assert(tooltip.detachedData, "You cannot detach if detachedData is not present") tooltip.detachedData.detached = true local detached = AcquireDetachedFrame(self, tooltip.registration, tooltip.data, tooltip.detachedData) detached.menu, tooltip.menu = tooltip.menu, nil detached.children = tooltip.children tooltip.children = nil detached:SetOwner(owner) detached:children() detached:Show() end tooltip.Detach = wrap(tooltip.Detach, "tooltip:Detach") end tooltip.registration = registration registration.tooltip = tooltip return tooltip end AcquireFrame = wrap(AcquireFrame, "AcquireFrame") function ReleaseDetachedFrame(self, data, detachedData) if not detachedData then detachedData = data end for _, detached in ipairs(detachedTooltips) do if detached.detachedData == detachedData then detached.notInUse = true detached:Hide() detached.registration.tooltip = nil detached.registration = nil end end end ReleaseDetachedFrame = wrap(ReleaseDetachedFrame, "ReleaseDetachedFrame") function AcquireDetachedFrame(self, registration, data, detachedData) if not detachedData then detachedData = data end for _, detached in ipairs(detachedTooltips) do if detached.notInUse then detached.data = data detached.detachedData = detachedData detached.notInUse = nil local fontSizePercent = detachedData.fontSizePercent or 1 local transparency = detachedData.transparency or 0.75 local r = detachedData.r or 0 local g = detachedData.g or 0 local b = detachedData.b or 0 detached:SetFontSizePercent(fontSizePercent) detached:SetTransparency(transparency) detached:SetColor(r, g, b) detached:ClearAllPoints() detached:SetPoint(detachedData.anchor or "CENTER", UIParent, detachedData.anchor or "CENTER", detachedData.offsetx or 0, detachedData.offsety or 0) detached.registration = registration registration.tooltip = detached return detached end end if not dewdrop and DewdropLib then dewdrop = DewdropLib:GetInstance('1.0') end if not sekeys and SpecialEventsEmbed and SpecialEventsEmbed.versions["Keys 1"] then sekeys = SpecialEventsEmbed:GetInstance("Keys 1") sekeys:RegisterEvent(self, "SPECIAL_ALTKEY_DOWN") sekeys:RegisterEvent(self, "SPECIAL_ALTKEY_UP") function self:SPECIAL_ALTKEY_DOWN() for _, detached in ipairs(detachedTooltips) do if detached:IsShown() and detached.locked then detached:EnableMouse(IsAltKeyDown()) detached:children() end end end self.SPECIAL_ALTKEY_UP = self.SPECIAL_ALTKEY_DOWN end if not tooltip then AcquireFrame(self, {}) end local detached = CreateFrame("Frame", "TabletLibDetachedFrame" .. (table.getn(detachedTooltips) + 1), UIParent) table.insert(detachedTooltips, detached) detached.notInUse = true detached:EnableMouse(not data.locked) detached:EnableMouseWheel(true) detached:SetMovable(true) detached:SetPoint(data.anchor or "CENTER", UIParent, data.anchor or "CENTER", data.offsetx or 0, data.offsety or 0) detached.numLines = 0 --detached.categoryLines = {} detached.idLines = {} detached.categories = 0 detached.owner = nil detached.fontSizePercent = 1 detached.maxLines = 0 detached.buttons = {} detached.checks = {} detached.lefts = {} detached.rights = {} detached.thirds = {} detached.fourths = {} detached.transparency = 0.75 detached.r = 0 detached.g = 0 detached.b = 0 detached:SetFrameStrata("BACKGROUND") detached:SetBackdrop(tmp.a( 'bgFile', "Interface\\Buttons\\WHITE8X8", 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", 'tile', true, 'tileSize', 16, 'edgeSize', 16, 'insets', tmp.b( 'left', 5, 'right', 5, 'top', 5, 'bottom', 5 ) )) detached.locked = data.locked detached.scroll = 0 local width = GetScreenWidth() local height = GetScreenHeight() detached:SetScript("OnMouseDown", function() if arg1 == "LeftButton" then if not detached.locked then detached:StartMoving() end end end) detached:SetScript("OnMouseUp", function() if arg1 == "LeftButton" then if not detached.locked then detached:StopMovingOrSizing() local anchor local offsetx local offsety if detached:GetTop() + detached:GetBottom() < height then anchor = "BOTTOM" offsety = detached:GetBottom() if offsety < 0 then offsety = 0 end if offsety < MainMenuBar:GetTop() and MainMenuBar:IsVisible() then offsety = MainMenuBar:GetTop() end local top = 0 if FuBar then for i = 1, FuBar:GetNumPanels() do local panel = FuBar:GetPanel(i) if panel:GetAttachPoint() == "BOTTOM" then if panel.frame:GetTop() > top then top = panel.frame:GetTop() break end end end end if offsety < top then offsety = top end else anchor = "TOP" offsety = detached:GetTop() - height if offsety > 0 then offsety = 0 end local bottom = GetScreenHeight() if FuBar then for i = 1, FuBar:GetNumPanels() do local panel = FuBar:GetPanel(i) if panel:GetAttachPoint() == "TOP" then if panel.frame:GetBottom() < bottom then bottom = panel.frame:GetBottom() break end end end end bottom = bottom - GetScreenHeight() if offsety > bottom then offsety = bottom end end if detached:GetLeft() + detached:GetRight() < width * 2 / 3 then anchor = anchor .. "LEFT" offsetx = detached:GetLeft() if offsetx < 0 then offsetx = 0 end elseif detached:GetLeft() + detached:GetRight() < width * 4 / 3 then if anchor == "" then anchor = "CENTER" end offsetx = (detached:GetLeft() + detached:GetRight() - GetScreenWidth()) / 2 else anchor = anchor .. "RIGHT" offsetx = detached:GetRight() - width if offsetx > 0 then offsetx = 0 end end detached:ClearAllPoints() detached:SetPoint(anchor, UIParent, anchor, offsetx, offsety) local t = detached.detachedData if t.anchor ~= anchor or math.abs(t.offsetx - offsetx) > 8 or math.abs(t.offsety - offsety) > 8 then detached.preventClick = GetTime() + 0.05 end t.anchor = anchor t.offsetx = offsetx t.offsety = offsety detached:Show() end end end) dewdrop:Register(detached, 'children', function(level, value) if detached.menu then detached.menu(level, value) if level == 1 then dewdrop:AddLine() end end if level == 1 then if not detached.registration.cantAttach then dewdrop:AddLine( 'text', DETACH, 'checked', true, 'arg1', detached, 'func', "Attach", 'closeWhenClicked', true ) end dewdrop:AddLine( 'text', LOCK, 'checked', detached:IsLocked(), 'arg1', detached, 'func', "Lock", 'closeWhenClicked', not detached:IsLocked() ) dewdrop:AddLine( 'text', COLOR, 'hasColorSwatch', true, 'r', detached.r, 'g', detached.g, 'b', detached.b, 'swatchFunc', function(r, g, b) detached:SetColor(r, g, b) end, 'hasOpacity', true, 'opacity', detached.transparency, 'opacityFunc', function(alpha) detached:SetTransparency(alpha) end, 'cancelFunc', function(r, g, b, a) detached:SetColor(r, g, b) detached:SetTransparency(a) end ) local value = detached:GetFontSizePercent() if value < 1 then value = value - 0.5 else value = value / 2 end dewdrop:AddLine( 'text', SIZE, 'hasArrow', true, 'hasSlider', true, 'sliderFunc', function(value) if value > 0.5 then value = value * 2 else value = value + 0.5 end detached:SetFontSizePercent(value) return format("%d%%", value * 100) end, 'sliderTop', "200%", 'sliderBottom', "50%", 'sliderValue', value ) dewdrop:AddLine() dewdrop:AddLine( 'text', CLOSE_MENU, 'func', function() dewdrop:Close() end ) end end, 'point', function() local x, y = detached:GetCenter() if x < GetScreenWidth() / 2 then if y < GetScreenHeight() / 2 then return "BOTTOMLEFT", "BOTTOMRIGHT" else return "TOPLEFT", "TOPRIGHT" end else if y < GetScreenHeight() / 2 then return "BOTTOMRIGHT", "BOTTOMLEFT" else return "TOPRIGHT", "TOPLEFT" end end end ) NewLine(detached) detached.scrollUp = detached:CreateFontString(nil, "ARTWORK") detached.scrollUp:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2) detached.scrollUp:SetPoint("RIGHT", detached, "RIGHT", 0, -10) detached.scrollUp:SetFontObject(GameTooltipText) detached.scrollUp:Hide() local font,_,flags = detached.scrollUp:GetFont() detached.scrollUp:SetFont(font, normalSize * detached.fontSizePercent, flags) detached.scrollUp:SetJustifyH("CENTER") detached.scrollUp:SetTextColor(1, 0.823529, 0) detached.scrollUp:SetText(" ") detached.scrollDown = detached:CreateFontString(nil, "ARTWORK") detached.scrollDown:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2) detached.scrollDown:SetPoint("RIGHT", detached, "RIGHT", 0, -10) detached.scrollDown:SetFontObject(GameTooltipText) detached.scrollDown:Hide() local font,_,flags = detached.scrollUp:GetFont() detached.scrollDown:SetFont(font, normalSize * detached.fontSizePercent, flags) detached.scrollDown:SetJustifyH("CENTER") detached.scrollDown:SetTextColor(1, 0.823529, 0) detached.scrollDown:SetText(" ") detached:SetScript("OnMouseWheel", function() detached:Scroll(arg1 < 0) end) detached.SetTransparency = tooltip.SetTransparency detached.GetTransparency = tooltip.GetTransparency detached.SetColor = tooltip.SetColor detached.GetColor = tooltip.GetColor detached.SetFontSizePercent = tooltip.SetFontSizePercent detached.GetFontSizePercent = tooltip.GetFontSizePercent detached.SetOwner = tooltip.SetOwner detached.IsOwned = tooltip.IsOwned detached.ClearLines = tooltip.ClearLines detached.NumLines = tooltip.NumLines detached.Hide = tooltip.Hide detached.Show = tooltip.Show detached.AddLine = tooltip.AddLine detached.Scroll = tooltip.Scroll function detached:IsLocked() return self.locked end function detached:Lock() self:EnableMouse(self.locked) self.locked = not self.locked self.detachedData.locked = self.locked or nil self:children() end function detached.Attach(detached) assert(detached, "Detached tooltip not given.") assert(detached.AddLine, "detached argument not a Tooltip.") assert(detached.owner, "Detached tooltip has no owner.") assert(not detached.notInUse, "Detached tooltip not in use.") detached.menu = nil detached.detachedData.detached = nil detached:SetOwner(nil) detached.notInUse = TRUE end return AcquireDetachedFrame(self, registration, data, detachedData) end AcquireDetachedFrame = wrap(AcquireDetachedFrame, "AcquireDetachedFrame") function lib:Close(parent) if not parent then if tooltip and tooltip:IsShown() then tooltip:Hide() tooltip.registration.tooltip = nil tooltip.registration = nil end return end local info = self.registry[parent] assert(info, "You cannot close a tablet with an unregistered parent frame.") local data = info.data local detachedData = info.detachedData if detachedData and detachedData.detached then ReleaseDetachedFrame(self, data, detachedData) elseif tooltip.data == data then tooltip:Hide() tooltip.registration.tooltip = nil tooltip.registration = nil end end lib.Close = wrap(lib.Close, "lib:Close") local currentFrame local currentTabletData function lib:Open(parent) assert(parent, "You must provide a parent frame whose tablet you mean to open.") local info = self.registry[parent] assert(info, "You cannot open a tablet with an unregistered parent frame.") self:Close() local data = info.data local detachedData = info.detachedData local children = info.children if not children then return end local frame = AcquireFrame(self, info, data, detachedData) frame.clickable = info.clickable frame.menu = info.menu local children = info.children function frame:children() if not self.preventRefresh then currentFrame = self currentTabletData = TabletData:new(self) self:ClearLines() if children then children() end currentTabletData:Display(currentFrame) self:Show(currentTabletData) currentTabletData:del() currentTabletData = nil currentFrame = nil end end frame:SetOwner(parent) frame:children() local point = info.point local relativePoint = info.point if type(point) == "function" then local b point, b = point(parent) if b then relativePoint = b end end if type(relativePoint) == "function" then relativePoint = relativePoint(parent) end if not point then point = "CENTER" end if not relativePoint then relativePoint = point end frame:ClearAllPoints() frame:SetPoint(point, parent, relativePoint) local offsetx = 0 local offsety = 0 if frame:GetBottom() and frame:GetLeft() then if frame:GetRight() > GetScreenWidth() then offsetx = frame:GetRight() - GetScreenWidth() elseif frame:GetLeft() < 0 then offsetx = -frame:GetLeft() end local ratio = GetScreenWidth() / GetScreenHeight() if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then if frame:GetCenter() < GetScreenWidth() / 2 then offsetx = frame:GetRight() - GetScreenWidth() / 2 else offsetx = frame:GetLeft() - GetScreenWidth() / 2 end end if frame:GetBottom() < 0 then offsety = frame:GetBottom() elseif frame:GetTop() and frame:GetTop() > GetScreenHeight() then offsety = frame:GetTop() - GetScreenHeight() end if frame:GetBottom() < MainMenuBar:GetTop() and MainMenuBar:IsVisible() and offsety < frame:GetBottom() - MainMenuBar:GetTop() then offsety = frame:GetBottom() - MainMenuBar:GetTop() end if FuBar then local top = 0 if FuBar then for i = 1, FuBar:GetNumPanels() do local panel = FuBar:GetPanel(i) if panel:GetAttachPoint() == "BOTTOM" then if panel.frame:GetTop() > top then top = panel.frame:GetTop() break end end end end if frame:GetBottom() < top and offsety < frame:GetBottom() - top then offsety = frame:GetBottom() - top end local bottom = GetScreenHeight() if FuBar then for i = 1, FuBar:GetNumPanels() do local panel = FuBar:GetPanel(i) if panel:GetAttachPoint() == "TOP" then if panel.frame:GetBottom() < bottom then bottom = panel.frame:GetBottom() break end end end end if frame:GetTop() > bottom and offsety < frame:GetTop() - bottom then offsety = frame:GetTop() - bottom end end end frame:SetPoint(point, parent, relativePoint, -offsetx, -offsety) if detachedData and (info.cantAttach or detachedData.detached) and frame == tooltip then detachedData.detached = false frame:Detach() end end lib.Open = wrap(lib.Open, "lib:Open") function lib:Register(parent, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) assert(parent, "You must provide a parent frame to register with") if self.registry[parent] then self:Unregister(parent) end local info if type(k1) == "table" and k1[0] then assert(type(self.registry[k1]) == "table", "Other parent not registered") info = copy(self.registry[k1]) if type(v1) == "function" then info.point = v1 info.relativePoint = nil end else info = new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) end self.registry[parent] = info info.data = info.data or info.detachedData info.detachedData = info.detachedData or info.data local data = info.data local detachedData = info.detachedData if not self.onceRegistered[parent] then if not dewdrop then dewdrop = DewdropLib:GetInstance('1.0') end local script = parent:GetScript("OnEnter") parent:SetScript("OnEnter", function() if script then script() end if self.registry[parent] then if (not data or not detachedData.detached) and not dewdrop:IsOpen(parent) then self:Open(parent) tooltip.enteredFrame = true end end end) local script = parent:GetScript("OnLeave") parent:SetScript("OnLeave", function() if script then script() end if self.registry[parent] then if tooltip and (not data or not detachedData or not detachedData.detached) then tooltip.enteredFrame = false end end end) if parent:HasScript("OnMouseDown") then local script = parent:GetScript("OnMouseDown") parent:SetScript("OnMouseDown", function() if script then script() end if self.registry[parent] and self.registry[parent].tooltip and self.registry[parent].tooltip == tooltip then tooltip:Hide() end end) end if parent:HasScript("OnMouseWheel") then local script = parent:GetScript("OnMouseWheel") parent:SetScript("OnMouseWheel", function() if script then script() end if self.registry[parent] and self.registry[parent].tooltip then self.registry[parent].tooltip:Scroll(arg1 < 0) end end) end end self.onceRegistered[parent] = true if GetMouseFocus() == parent then self:Open(parent) end end lib.Register = wrap(lib.Register, "lib:Register") function lib:Unregister(parent) assert(self.registry[parent], "You cannot unregister a parent frame if it has not been registered already.") self.registry[parent] = nil end lib.Unregister = wrap(lib.Unregister, "lib:Unregister") function lib:IsRegistered(parent) return self.registry[parent] and true end lib.IsRegistered = wrap(lib.IsRegistered, "lib:IsRegistered") local _id = 0 local addedCategory local currentCategoryInfo local depth = 0 local categoryPool = {} function CleanCategoryPool(self) for k,v in pairs(categoryPool) do del(v) categoryPool[k] = nil end _id = 0 end function lib:AddCategory(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) assert(currentFrame, "You must add categories in within a registration.") local info = new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20, k21, v21, k22, v22, k23, v23, k24, v24, k25, v25, k26, v26, k27, v27, k28, v28, k29, v29, k30, v30) local cat = currentTabletData:AddCategory(info) del(info) return cat end lib.AddCategory = wrap(lib.AddCategory, "lib:AddCategory") function lib:SetHint(text) assert(currentFrame, "You must set hint within a registration.") assert(not currentCategoryInfo, "You cannot set hint in a category.") currentTabletData:SetHint(text) end lib.SetHint = wrap(lib.SetHint, "lib:SetHint") function lib:SetTitle(text) assert(currentFrame, "You must set title within a registration") assert(not currentCategoryInfo, "You cannot set title in a category.") currentTabletData:SetTitle(text) end lib.SetTitle = wrap(lib.SetTitle, "lib:SetTitle") function lib:GetNormalFontSize() return normalSize end function lib:GetHeaderFontSize() return headerSize end function lib:GetNormalFontObject() return GameTooltipText end function lib:GetHeaderFontObject() return GameTooltipHeaderText end function lib:SetFontSizePercent(parent, percent) assert(parent, "You must provide a parent frame to change font size.") if parent[0] then local info = self.registry[parent] assert(info, "You cannot change font size with an unregistered parent frame.") if info.tooltip then info.tooltip:SetFontSizePercent(percent) else if detachedData.detached then detachedData.fontSizePercent = percent else data.fontSizePercent = percent end end else parent.fontSizePercent = percent end end lib.SetFontSizePercent = wrap(lib.SetFontSizePercent, "lib:SetFontSizePercent") function lib:GetFontSizePercent(parent) assert(parent, "You must provide a parent frame to check font size.") if parent[0] then local info = self.registry[parent] assert(info, "You cannot check font size with an unregistered parent frame.") local data = info.data local detachedData = info.detachedData if detachedData.detached then return detachedData.fontSizePercent or 1 else return data.fontSizePercent or 1 end else return parent.fontSizePercent or 1 end end lib.GetFontSizePercent = wrap(lib.GetFontSizePercent, "lib:GetFontSizePercent") function lib:SetTransparency(parent, percent) assert(parent, "You must provide a parent frame to change transparency") if parent[0] then local info = self.registry[parent] assert(info, "You cannot change transparency with an unregistered parent frame.") if info.tooltip then info.tooltip:SetTransparency(percent) else if detachedData.detached then detachedData.transparency = percent else data.transparency = percent end end else parent.transparency = percent end end lib.SetTransparency = wrap(lib.SetTransparency, "lib:SetTransparency") function lib:GetTransparency(parent) assert(parent, "You must provide a parent frame to check transparency") if parent[0] then local info = self.registry[parent] assert(info, "You cannot check transparency with an unregistered parent frame.") local data = info.data local detachedData = info.detachedData if detachedData.detached then return detachedData.transparency or 0.75 else return data.transparency or 0.75 end else return parent.transparency or 0.75 end end lib.GetTransparency = wrap(lib.GetTransparency, "lib:GetTransparency") function lib:SetColor(parent, r, g, b) assert(parent, "You must provide a parent frame to change color") if parent[0] then local info = self.registry[parent] assert(info, "You cannot change color with an unregistered parent frame.") if info.tooltip then info.tooltip:SetColor(r, g, b) else if detachedData.detached then detachedData.r = r detachedData.g = g detachedData.b = b else data.r = r data.g = g data.b = b end end else parent.r = r parent.g = g parent.b = b end end lib.SetColor = wrap(lib.SetColor, "lib:SetColor") function lib:GetColor(parent) assert(parent, "You must provide a parent frame to check color") if parent[0] then local info = self.registry[parent] assert(info, "You cannot check color with an unregistered parent frame.") local data = info.data local detachedData = info.detachedData if detachedData.detached then return detachedData.r or 0, detachedData.g or 0, detachedData.b or 0 else return data.r or 0, data.g or 0, data.b or 0 end else return parent.r or 0, parent.g or 0, parent.b or 0 end end lib.GetColor = wrap(lib.GetColor, "lib:GetColor") function lib:Detach(parent) assert(parent, "You must provide a parent frame to detach tablet") local info = self.registry[parent] assert(info, "You cannot detach tablet with an unregistered parent frame.") assert(info.detachedData, "You cannot detach tablet without a data field.") if info.tooltip and info.tooltip == tooltip then tooltip:Detach() else info.detachedData.detached = true local detached = AcquireDetachedFrame(self, info, info.data, info.detachedData) detached.menu = info.menu local children = info.children function detached:children() if not self.preventRefresh then currentFrame = self currentTabletData = TabletData:new(self) self:ClearLines() if children then children() end currentTabletData:Display(currentFrame) self:Show(currentTabletData) currentTabletData:del() currentTabletData = nil currentFrame = nil end end detached:SetOwner(parent) detached:children() end end lib.Detach = wrap(lib.Detach, "lib:Detach") function lib:Attach(parent) assert(parent, "You must provide a parent frame to detach tablet") local info = self.registry[parent] assert(info, "You cannot detach tablet with an unregistered parent frame.") assert(info.detachedData, "You cannot attach tablet without a data field.") if info.tooltip and info.tooltip ~= tooltip then info.tooltip:Attach() else info.detachedData.detached = false end end lib.Attach = wrap(lib.Attach, "lib:Attach") function lib:IsAttached(parent) assert(parent, "You must provide a parent frame to check tablet") local info = self.registry[parent] assert(info, "You cannot check tablet with an unregistered parent frame.") return not info.detachedData or not info.detachedData.detached end lib.IsAttached = wrap(lib.IsAttached, "lib:IsAttached") function lib:Refresh(parent) assert(parent, "You must provide a parent frame to refresh tablet") local info = self.registry[parent] assert(info, "You cannot refresh tablet with an unregistered parent frame.") local tt = info.tooltip if tt and not tt.preventRefresh and tt:IsShown() then tt.updating = true tt:children() tt.updating = false end end lib.Refresh = wrap(lib.Refresh, "lib:Refresh") function lib:IsLocked(parent) assert(parent, "You must provide a parent frame to detach tablet") local info = self.registry[parent] assert(info, "You cannot detach tablet with an unregistered parent frame.") return info.detachedData and info.detachedData.locked end lib.IsLocked = wrap(lib.IsLocked, "lib:IsLocked") function lib:ToggleLocked(parent) assert(parent, "You must provide a parent frame to detach tablet") local info = self.registry[parent] assert(info, "You cannot detach tablet with an unregistered parent frame.") if info.tooltip and info.tooltip ~= tooltip then info.tooltip:Lock() elseif info.detachedData then info.detachedData.locked = info.detachedData.locked end end lib.ToggleLocked = wrap(lib.ToggleLocked, "lib:ToggleLocked") if DEBUG then function lib:ListProfileInfo() local duration, times, memories = GetProfileInfo() assert(duration and times and memories) local t = new() for method in pairs(memories) do table.insert(t, method) end table.sort(t, function(alpha, bravo) if memories[alpha] ~= memories[bravo] then return memories[alpha] < memories[bravo] elseif times[alpha] ~= times[bravo] then return times[alpha] < times[bravo] else return alpha < bravo end end) local memory = 0 local time = 0 for _,method in ipairs(t) do DEFAULT_CHAT_FRAME:AddMessage(format("%s || %.3f s || %.3f%% || %d KiB", method, times[method], times[method] / duration * 100, memories[method])) memory = memory + memories[method] time = time + times[method] end DEFAULT_CHAT_FRAME:AddMessage(format("%s || %.3f s || %.3f%% || %d KiB", "Total", time, time / duration * 100, memory)) table.setn(t, 0) del(t) end SLASH_TABLET1 = "/tablet" SLASH_TABLET2 = "/tabletlib" SlashCmdList["TABLET"] = function(msg) TabletLib:GetInstance(MAJOR_VERSION):ListProfileInfo() end end TabletLib:Register(lib) lib = nil