--[[ Name: Tablet-2.0 Revision: $Rev: 16145 $ Author(s): ckknight (ckknight@gmail.com) Website: http://ckknight.wowinterface.com/ Documentation: http://wiki.wowace.com/index.php/Tablet-2.0 SVN: http://svn.wowace.com/root/trunk/TabletLib/Tablet-2.0 Description: A library to provide an efficient, featureful tooltip-style display. Dependencies: AceLibrary, (optional) Dewdrop-2.0 ]] local MAJOR_VERSION = "Tablet-2.0" local MINOR_VERSION = "$Revision: 16145 $" if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end local DEBUG = false local SCROLL_UP = "Scroll up" local SCROLL_DOWN = "Scroll down" local HINT = "Hint" local DETACH = "Detach" local DETACH_DESC = "Detach the tablet from its source." local SIZE = "Size" local SIZE_DESC = "Scale the tablet." local CLOSE_MENU = "Close menu" local CLOSE_MENU_DESC = "Close the menu." local COLOR = "Background color" local COLOR_DESC = "Set the background color." local LOCK = "Lock" local LOCK_DESC = "Lock the tablet in its current position. Alt+Right-click for menu or Alt+drag to drag it when locked." if GetLocale() == "deDE" then SCROLL_UP = "Hochscrollen" SCROLL_DOWN = "Runterscrollen" HINT = "Hinweis" DETACH = "L\195\182sen" DETACH_DESC = "L\195\182st den Tooltip aus seiner Verankerung." SIZE = "Gr\195\182\195\159e" SIZE_DESC = "Gr\195\182\195\159e des Tooltips \195\164ndern." CLOSE_MENU = "Menu schlie\195\159en" CLOSE_MENU_DESC = "Schlie\195\159t das Menu." COLOR = "Hintergrundfarbe" COLOR_DESC = "Hintergrundfarbe setzen." LOCK = "Sperren" LOCK_DESC = "Sperrt die aktuelle Position vom Tooltip. Alt+Rechts-klick f\195\188rs Men\195\188 oder Alt+Verschieben f\195\188rs verschieben wenn es gesperrt ist." elseif GetLocale() == "koKR" then SCROLL_UP = "위로 스크롤" SCROLL_DOWN = "아래로 스크롤" HINT = "힌트" DETACH = "분리" DETACH_DESC = "테이블을 분리합니다." SIZE = "크기" SIZE_DESC = "테이블의 크기입니다." CLOSE_MENU = "메뉴 닫기" CLOSE_MENU_DESC = "메뉴를 닫습니다." COLOR = "배경 색상" COLOR_DESC = "배경 색상을 설정합니다." LOCK = "고정" LOCK_DESC = "현재 위치에 테이블을 고정합니다. 알트+우클릭 : 메뉴열기, 알트+드래그 : 고정된것을 드래그합니다." elseif GetLocale() == "zhCN" then SCROLL_UP = "向上翻转" SCROLL_DOWN = "向上翻转" HINT = "提示" DETACH = "分离" DETACH_DESC = "分离菜单为独立提示." SIZE = "尺寸" SIZE_DESC = "缩放菜单显示尺寸." CLOSE_MENU = "关闭菜单" CLOSE_MENU_DESC = "关闭菜单" COLOR = "背景颜色" COLOR_DESC = "设置菜单背景颜色." LOCK = "锁定" LOCK_DESC = "锁定菜单当前位置. alt+右键 将显示选项, alt+拖动 可以移动已锁定的菜单." elseif GetLocale() == "zhTW" then SCROLL_UP = "向上翻轉" SCROLL_DOWN = "向上翻轉" HINT = "提示" DETACH = "分離" DETACH_DESC = "分離選單為獨立提示。" SIZE = "尺寸" SIZE_DESC = "縮放選單顯示尺寸。" CLOSE_MENU = "關閉選單" CLOSE_MENU_DESC = "關閉選單" COLOR = "背景顏色" COLOR_DESC = "設置選單背景顏色。" LOCK = "鎖定" LOCK_DESC = "鎖定選單目前位置. Alt+右鍵 將顯示選項,Alt+拖動 可以移動已鎖定的選單。" elseif GetLocale() == "frFR" then SCROLL_UP = "Parcourir vers le haut" SCROLL_DOWN = "Parcourir vers le bas" HINT = "Astuce" DETACH = "D\195\169tacher" DETACH_DESC = "Permet de d\195\169tacher le tableau de sa source." SIZE = "Taille" SIZE_DESC = "Permet de changer l'\195\169chelle du tableau." CLOSE_MENU = "Fermer le menu" CLOSE_MENU_DESC = "Ferme ce menu." COLOR = "Couleur du fond" COLOR_DESC = "Permet de d\195\169finir la couleur du fond." LOCK = "Bloquer" LOCK_DESC = "Bloque le tableau \195\160 sa position actuelle. Alt+clic-droit pour le menu ou Alt+glisser pour le d\195\169placer quand il est bloqu\195\169." 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 TESTSTRING_EXTRA_WIDTH = 5 local Tablet = {} local function getsecond(_, value) return value end local Dewdrop local sekeys local CleanCategoryPool local pool = {} local table_setn do local version = GetBuildInfo() if string.find(version, "^2%.") then -- 2.0.0 table_setn = function() end else table_setn = table.setn end end local function del(t) if t then 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}) local headerSize, normalSize if GameTooltipHeaderText then _,headerSize = GameTooltipHeaderText:GetFont() else headerSize = 14 end if GameTooltipText then _,normalSize = GameTooltipText:GetFont() else normalSize = 12 end 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:Display() if self.tablet == tooltip or self.tablet.registration.showTitleWhenDetached then local info = new( 'hideBlankLine', true, 'text', self.title, 'justify', "CENTER", 'font', GameTooltipHeaderText, 'isTitle', true ) self:AddCategory(info, 1) del(info) end if self.tablet == tooltip or self.tablet.registration.showHintWhenDetached then 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.x5 + v.x6 + (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 if self.tablet == tooltip or not self.tablet.registration.hideWhenEmpty 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) else self.tablet:__Hide() self.tablet.tmpHidden = true end else self.tablet:__Show() self.tablet.tmpHidden = nil 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 self.x5 = 0 self.x6 = 0 setmetatable(self, Category_mt) self.lastWasTitle = nil if self.text or self.text2 or self.text3 or self.text4 or self.text5 or self.text6 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, 'justify5', self.justify5, 'justify6', self.justify6 ) 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.text5 = self.text5 x.text6 = self.text6 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.text5R = self.text5R or self.textR5 or 1 x.text5G = self.text5G or self.textG5 or 1 x.text5B = self.text5B or self.textB5 or 1 x.text6R = self.text6R or self.textR6 or 1 x.text6G = self.text6G or self.textG6 or 1 x.text6B = self.text6B or self.textB6 or 1 x.font2 = self.font2 x.font3 = self.font3 x.font4 = self.font4 x.font5 = self.font5 x.font6 = self.font6 x.size2 = self.size2 x.size3 = self.size3 x.size4 = self.size4 x.size5 = self.size5 x.size6 = self.size6 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 elseif columns == 5 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 = "CENTER" end if not self.justify5 then self.justify5 = "RIGHT" end if self.wrap then self.wrap2 = false self.wrap3 = false self.wrap4 = false self.wrap5 = false elseif self.wrap2 then self.wrap3 = false self.wrap4 = false self.wrap5 = false elseif self.wrap3 then self.wrap4 = false self.wrap5 = false elseif self.wrap4 then self.wrap5 = false end elseif columns == 6 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 = "CENTER" end if not self.justify5 then self.justify5 = "CENTER" end if not self.justify6 then self.justify6 = "RIGHT" end if self.wrap then self.wrap2 = false self.wrap3 = false self.wrap4 = false self.wrap5 = false self.wrap6 = false elseif self.wrap2 then self.wrap3 = false self.wrap4 = false self.wrap5 = false self.wrap6 = false elseif self.wrap3 then self.wrap4 = false self.wrap5 = false self.wrap6 = false elseif self.wrap4 then self.wrap5 = false self.wrap6 = false elseif self.wrap5 then self.wrap6 = 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 if self.textR5 then self.text5R, self.textR5 = self.text5R or self.textR5 self.text5G, self.textG5 = self.text5G or self.textG5 self.text5B, self.textB5 = self.text5B or self.textB5 if self.textR5 then self.text6R, self.textR6 = self.text6R or self.textR6 self.text6G, self.textG6 = self.text6G or self.textG6 self.text6B, self.textB6 = self.text6B or self.textB6 end end 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.font5 then self.font5 = self.font end if not self.font6 then self.font6 = 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 if not self.size5 then _,self.size5 = self.font5:GetFont() end if not self.size6 then _,self.size6 = self.font6:GetFont() end local fontSizePercent = category.tabletData.tablet.fontSizePercent local w = 0 self.checkWidth = 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 self.checkWidth = checkWidth w = testString:GetWidth() + self.indentation * fontSizePercent + checkWidth + TESTSTRING_EXTRA_WIDTH 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 self.checkWidth = checkWidth w = testString:GetWidth() + self.indentation * fontSizePercent + checkWidth + TESTSTRING_EXTRA_WIDTH 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() + TESTSTRING_EXTRA_WIDTH 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() + TESTSTRING_EXTRA_WIDTH 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() + TESTSTRING_EXTRA_WIDTH 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() + TESTSTRING_EXTRA_WIDTH 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 if columns >= 5 then if self.text5 then if not self.wrap5 then testString:SetWidth(0) testString:SetFontObject(self.font5) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size5 * fontSizePercent, flags) testString:SetText(self.text5) w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH if category.superCategory.x5 < w then category.superCategory.x5 = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory.x5 < w then category.superCategory.x5 = w end end end if columns >= 6 then if self.text6 then if not self.wrap6 then testString:SetWidth(0) testString:SetFontObject(self.font6) local font,_,flags = testString:GetFont() testString:SetFont(font, self.size6 * fontSizePercent, flags) testString:SetText(self.text6) w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH if category.superCategory.x6 < w then category.superCategory.x6 = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory.x6 < w then category.superCategory.x6 = w end end 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 type(this.self:GetScript("OnEnter")) == "function" then this.self:GetScript("OnEnter")() end this.highlight:Show() end local function button_OnLeave() if type(this.self:GetScript("OnLeave")) == "function" 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 fifth = button:CreateFontString(nil, "ARTWORK") local sixth = 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) table.insert(self.fifths, fifth) table.insert(self.sixths, sixth) left:SetWidth(0) if self.maxLines == 1 then left:SetFontObject(GameTooltipHeaderText) right:SetFontObject(GameTooltipHeaderText) third:SetFontObject(GameTooltipHeaderText) fourth:SetFontObject(GameTooltipHeaderText) fifth:SetFontObject(GameTooltipHeaderText) sixth: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) fifth:SetFontObject(GameTooltipText) sixth: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) fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", 20 * self.fontSizePercent, 0) sixth:SetPoint("TOPLEFT", fifth, "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() third:Hide() fourth:Hide() fifth:Hide() sixth: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", "Tablet20Frame", UIParent) self.tooltip = tooltip 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.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.fifths = {} tooltip.sixths = {} 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 self.numLines = 0 end tooltip.ClearLines = wrap(tooltip.ClearLines, "tooltip:ClearLines") function tooltip:NumLines() return self.numLines end local lastWidth local old_tooltip_Hide = tooltip.Hide tooltip.__Hide = old_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 self.tmpHidden = nil end tooltip.Hide = wrap(tooltip.Hide, "tooltip:Hide") local old_tooltip_Show = tooltip.Show tooltip.__Show = old_tooltip_Show function tooltip:Show(tabletData) if self.owner == nil or self.notInUse then return end if not self.tmpHidden then old_tooltip_Show(self) end 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 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 or (i == scrollMax and i ~= self.numLines) then self.buttons[i]:ClearAllPoints() self.buttons[i]:Hide() else local button = self.buttons[i] local left = self.lefts[i] local right = self.rights[i] local check = self.checks[i] button:SetWidth(maxWidth) button:SetHeight(math.max(left:GetHeight(), right: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 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 type(this.self:GetScript("OnClick")) == "function" then this.self:GetScript("OnClick")() end if arg1 == "RightButton" then if this.self:HasScript("OnClick") and type(this.self:GetScript("OnClick")) == "function" 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) if this.self then this.self.preventRefresh = false this.self:children() this.self.updating = false end end end end local function button_OnMouseUp() if this.self:HasScript("OnMouseUp") and type(this.self:GetScript("OnMouseUp")) == "function" 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 type(this.self:GetScript("OnMouseDown")) == "function" 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.superCategory 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, x5, x6 if category then x1, x2, x3, x4, x5, x6 = category.x1, category.x2, category.x3, category.x4, category.x5, category.x6 else x1, x2, x3, x4, x5, x6 = 0, 0, 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 local button = self.buttons[num] button.indentation = info.indentation local left = self.lefts[num] local right = self.rights[num] local third = self.thirds[num] local fourth = self.fourths[num] local fifth = self.fifths[num] local sixth = self.sixths[num] local check = self.checks[num] do -- 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) if columns < 2 then right:SetText(nil) right:Hide() right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * fontSizePercent, 0) right:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) third:SetText(nil) third:Hide() fourth:SetText(nil) fourth:Hide() fifth:SetText(nil) fifth:Hide() sixth:SetText(nil) sixth:Hide() else 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) if columns < 3 then right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * fontSizePercent, 0) right:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) third:SetText(nil) third:Hide() fourth:SetText(nil) fourth:Hide() fifth:SetText(nil) fifth:Hide() sixth:SetText(nil) sixth:Hide() else 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) if columns < 4 then fourth:SetText(nil) fourth:Hide() fifth:SetText(nil) fifth:Hide() sixth:SetText(nil) sixth:Hide() else 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) if columns < 5 then fifth:SetText(nil) fifth:Hide() sixth:SetText(nil) sixth:Hide() else fifth:SetFontObject(info.font5) fifth:SetText(info.text5) fifth:Show() if info.text5R and info.text5G and info.text5B then fifth:SetTextColor(info.text5R, info.text5G, info.text5B) else fifth:SetTextColor(1, 0.823529, 0) end local a,_,b = fourth:GetFont() fifth:SetFont(a, info.size5 * fontSizePercent, b) fifth:SetJustifyH(info.justify5) if columns < 6 then sixth:SetText(nil) sixth:Hide() else sixth:SetFontObject(info.font6) sixth:SetText(info.text6) sixth:Show() if info.text5R and info.text6G and info.text6B then sixth:SetTextColor(info.text6R, info.text6G, info.text6B) else sixth:SetTextColor(1, 0.823529, 0) end local a,_,b = fourth:GetFont() sixth:SetFont(a, info.size6 * fontSizePercent, b) sixth:SetJustifyH(info.justify6) end end end end end 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) if string.sub(info.checkIcon, 1, 16) == "Interface\\Icons\\" then check:SetTexCoord(0.05, 0.95, 0.05, 0.95) else check:SetTexCoord(0, 1, 0, 1) end 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 check:SetTexCoord(0, 1, 0, 1) end 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 - info.checkWidth) 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 - info.checkWidth) 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) elseif columns == 5 then left:SetWidth(x1 - info.checkWidth) right:SetWidth(x2) third:SetWidth(x3) fourth:SetWidth(x4) fifth:SetWidth(x5) local num = (category.tabletData.width - x1 - x2 - x3 - x4 - x5) / 4 right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", num, 0) elseif columns == 6 then left:SetWidth(x1 - info.checkWidth) right:SetWidth(x2) third:SetWidth(x3) fourth:SetWidth(x4) fifth:SetWidth(x5) sixth:SetWidth(x6) local num = (category.tabletData.width - x1 - x2 - x3 - x4 - x5 - x6) / 5 right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", num, 0) sixth:SetPoint("TOPLEFT", fifth, "TOPRIGHT", num, 0) end if not self.locked or IsAltKeyDown() then local func = info.func if func then if type(func) == "string" then Tablet:assert(type(info.arg1) == "table", "Cannot call method " .. info.func .. " on a non-table") func = info.arg1[func] Tablet:assert(type(func) == "function", "Method " .. info.func .. " nonexistant") end Tablet: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 fifth = self.fifths[i] local sixth = self.sixths[i] local check = self.checks[i] local font, size, flags = left:GetFont() left:SetFont(font, size * ratio, flags) font, size, flags = right:GetFont() right:SetFont(font, size * ratio, flags) font, size, flags = third:GetFont() third:SetFont(font, size * ratio, flags) font, size, flags = fourth:GetFont() fourth:SetFont(font, size * ratio, flags) font, size, flags = fifth:GetFont() fifth:SetFont(font, size * ratio, flags) font, size, flags = sixth:GetFont() sixth: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() self: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") local StartCheckingAlt, StopCheckingAlt do local frame function StartCheckingAlt(func) if not frame then frame = CreateFrame("Frame") end local last = IsAltKeyDown() frame:SetScript("OnUpdate", function() local now = IsAltKeyDown() if last ~= now then last = now func() end end) end function StopCheckingAlt() if frame then frame:SetScript("OnUpdate", nil) end end end 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 AceLibrary:HasInstance("Dewdrop-2.0") then Dewdrop = AceLibrary("Dewdrop-2.0") end StartCheckingAlt(function() for _, detached in ipairs(detachedTooltips) do if detached:IsShown() and detached.locked then detached:EnableMouse(IsAltKeyDown()) detached:children() if detached.moving then local a1 = arg1 arg1 = "LeftButton" if type(detached:GetScript("OnMouseUp")) == "function" then detached:GetScript("OnMouseUp")() end arg1 = a1 end end end end) if not tooltip then AcquireFrame(self, {}) end local detached = CreateFrame("Frame", "Tablet20DetachedFrame" .. (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.owner = nil detached.fontSizePercent = 1 detached.maxLines = 0 detached.buttons = {} detached.checks = {} detached.lefts = {} detached.rights = {} detached.thirds = {} detached.fourths = {} detached.fifths = {} detached.sixths = {} 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 = detachedData.locked detached.scroll = 0 detached:EnableMouse(not detached.locked) local width = GetScreenWidth() local height = GetScreenHeight() detached:SetScript("OnMouseDown", function() if arg1 == "LeftButton" then detached:StartMoving() detached.moving = true end end) detached:SetScript("OnMouseUp", function() if arg1 == "LeftButton" then detached:StopMovingOrSizing() detached.moving = nil 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) Dewdrop:Register(detached, 'children', function(level, value) if not detached.registration then return end 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, 'tooltipTitle', DETACH, 'tooltipText', DETACH_DESC, 'checked', true, 'arg1', detached, 'func', "Attach", 'closeWhenClicked', true ) end Dewdrop:AddLine( 'text', LOCK, 'tooltipTitle', LOCK, 'tooltipText', LOCK_DESC, 'checked', detached:IsLocked(), 'arg1', detached, 'func', "Lock", 'closeWhenClicked', not detached:IsLocked() ) Dewdrop:AddLine( 'text', COLOR, 'tooltipTitle', COLOR, 'tooltipText', COLOR_DESC, 'hasColorSwatch', true, 'r', detached.r, 'g', detached.g, 'b', detached.b, 'hasOpacity', true, 'opacity', detached.transparency, 'colorFunc', function(r, g, b, a) detached:SetColor(r, g, b) detached:SetTransparency(a) end ) Dewdrop:AddLine( 'text', SIZE, 'tooltipTitle', SIZE, 'tooltipText', SIZE_DESC, 'hasArrow', true, 'hasSlider', true, 'sliderFunc', function(value) detached:SetFontSizePercent(value) end, 'sliderMax', 2, 'sliderMin', 0.5, 'sliderStep', 0.05, 'sliderIsPercent', true, 'sliderValue', detached:GetFontSizePercent() ) Dewdrop:AddLine( 'text', CLOSE_MENU, 'tooltipTitle', CLOSE_MENU, 'tooltipText', CLOSE_MENU_DESC, '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 = detached.Hide detached.__Show = detached.Show detached.Hide = tooltip.Hide detached.Show = tooltip.Show local old_IsShown = detached.IsShown function detached:IsShown() if self.tmpHidden then return true else return old_IsShown(self) end end 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) self:assert(detached, "Detached tooltip not given.") self:assert(detached.AddLine, "detached argument not a Tooltip.") self:assert(detached.owner, "Detached tooltip has no owner.") self: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 Tablet:Close(parent) if not parent then if tooltip and tooltip:IsShown() then tooltip:Hide() tooltip.registration.tooltip = nil tooltip.registration = nil end return else self:argCheck(parent, 2, "table", "string") end local info = self.registry[parent] self: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 Tablet.Close = wrap(Tablet.Close, "Tablet:Close") local currentFrame local currentTabletData function Tablet:Open(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self: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() if type(parent) ~= "string" then frame:SetPoint(point, parent, relativePoint) end 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 MainMenuBar:IsVisible() and frame:GetBottom() < MainMenuBar:GetTop() 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() and 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() and 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 if type(parent) ~= "string" then frame:SetPoint(point, parent, relativePoint, -offsetx, -offsety) end if detachedData and (info.cantAttach or detachedData.detached) and frame == tooltip then detachedData.detached = false frame:Detach() end end Tablet.Open = wrap(Tablet.Open, "Tablet:Open") function Tablet: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) self:argCheck(parent, 2, "table", "string") if self.registry[parent] then self:Unregister(parent) end local info if type(k1) == "table" and k1[0] then self: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 or {} info.detachedData = info.detachedData or info.data local data = info.data local detachedData = info.detachedData if not self.onceRegistered[parent] and type(parent) == "table" and type(parent.SetScript) == "function" and not info.dontHook then if not Dewdrop then Dewdrop = AceLibrary("Dewdrop-2.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) self.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 self.tooltip and (not data or not detachedData or not detachedData.detached) then self.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 == self.tooltip then self.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 Tablet.Register = wrap(Tablet.Register, "Tablet:Register") function Tablet:Unregister(parent) self:argCheck(parent, 2, "table", "string") self:assert(self.registry[parent], "You cannot unregister a parent frame if it has not been registered already.") self.registry[parent] = nil end Tablet.Unregister = wrap(Tablet.Unregister, "Tablet:Unregister") function Tablet:IsRegistered(parent) self:argCheck(parent, 2, "table", "string") return self.registry[parent] and true end Tablet.IsRegistered = wrap(Tablet.IsRegistered, "Tablet: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 Tablet: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) self: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 Tablet.AddCategory = wrap(Tablet.AddCategory, "Tablet:AddCategory") function Tablet:SetHint(text) self:assert(currentFrame, "You must set hint within a registration.") self:assert(not currentCategoryInfo, "You cannot set hint in a category.") currentTabletData:SetHint(text) end Tablet.SetHint = wrap(Tablet.SetHint, "Tablet:SetHint") function Tablet:SetTitle(text) self:assert(currentFrame, "You must set title within a registration") self:assert(not currentCategoryInfo, "You cannot set title in a category.") currentTabletData:SetTitle(text) end Tablet.SetTitle = wrap(Tablet.SetTitle, "Tablet:SetTitle") function Tablet:GetNormalFontSize() return normalSize end function Tablet:GetHeaderFontSize() return headerSize end function Tablet:GetNormalFontObject() return GameTooltipText end function Tablet:GetHeaderFontObject() return GameTooltipHeaderText end function Tablet:SetFontSizePercent(parent, percent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then if info.tooltip then info.tooltip:SetFontSizePercent(percent) else local data = info.data local detachedData = info.detachedData if detachedData.detached then detachedData.fontSizePercent = percent else data.fontSizePercent = percent end end elseif type(parent) == "table" then parent.fontSizePercent = percent else self:assert(false, "You cannot change font size with an unregistered parent frame.") end end Tablet.SetFontSizePercent = wrap(Tablet.SetFontSizePercent, "Tablet:SetFontSizePercent") function Tablet:GetFontSizePercent(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then local data = info.data local detachedData = info.detachedData if detachedData.detached then return detachedData.fontSizePercent or 1 else return data.fontSizePercent or 1 end elseif type(parent) == "table" then return parent.fontSizePercent or 1 else self:assert(false, "You cannot check font size with an unregistered parent frame.") end end Tablet.GetFontSizePercent = wrap(Tablet.GetFontSizePercent, "Tablet:GetFontSizePercent") function Tablet:SetTransparency(parent, percent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then local data = info.data local detachedData = info.detachedData if info.tooltip then info.tooltip:SetTransparency(percent) else if detachedData.detached then detachedData.transparency = percent elseif data then data.transparency = percent end end elseif type(parent) == "table" then parent.transparency = percent else self:assert(false, "You cannot change transparency with an unregistered parent frame.") end end Tablet.SetTransparency = wrap(Tablet.SetTransparency, "Tablet:SetTransparency") function Tablet:GetTransparency(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then 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 elseif type(parent) == "table" then return parent.transparency or 0.75 else self:assert(parent, "You must provide a parent frame to check transparency") end end Tablet.GetTransparency = wrap(Tablet.GetTransparency, "Tablet:GetTransparency") function Tablet:SetColor(parent, r, g, b) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then if info.tooltip then info.tooltip:SetColor(r, g, b) else local data = info.data local detachedData = info.detachedData 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 elseif type(parent) == "table" then parent.r = r parent.g = g parent.b = b else self:assert(false, "You cannot change color with an unregistered parent frame.") end end Tablet.SetColor = wrap(Tablet.SetColor, "Tablet:SetColor") function Tablet:GetColor(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] if info then 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 elseif type(parent) == "table" then return parent.r or 0, parent.g or 0, parent.b or 0 else self:assert(parent, "You must provide a parent frame to check color") end end Tablet.GetColor = wrap(Tablet.GetColor, "Tablet:GetColor") function Tablet:Detach(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self:assert(info, "You cannot detach tablet with an unregistered parent frame.") self: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 Tablet.Detach = wrap(Tablet.Detach, "Tablet:Detach") function Tablet:Attach(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self:assert(info, "You cannot detach tablet with an unregistered parent frame.") self: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 Tablet.Attach = wrap(Tablet.Attach, "Tablet:Attach") function Tablet:IsAttached(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self:assert(info, "You cannot check tablet with an unregistered parent frame.") return not info.detachedData or not info.detachedData.detached end Tablet.IsAttached = wrap(Tablet.IsAttached, "Tablet:IsAttached") function Tablet:Refresh(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self: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 Tablet.Refresh = wrap(Tablet.Refresh, "Tablet:Refresh") function Tablet:IsLocked(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self:assert(info, "You cannot detach tablet with an unregistered parent frame.") return info.detachedData and info.detachedData.locked end Tablet.IsLocked = wrap(Tablet.IsLocked, "Tablet:IsLocked") function Tablet:ToggleLocked(parent) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self: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 Tablet.ToggleLocked = wrap(Tablet.ToggleLocked, "Tablet:ToggleLocked") function Tablet:UpdateDetachedData(parent, detachedData) self:argCheck(parent, 2, "table", "string") local info = self.registry[parent] self:assert(info, "You cannot detach tablet with an unregistered parent frame.") self:argCheck(detachedData, 3, "table") if info.data == info.detachedData then info.data = detachedData end info.detachedData = detachedData if info.detachedData.detached then self:Detach(parent) elseif info.tooltip and info.tooltip.owner then self:Attach(parent) end end Tablet.UpdateDetachedData = wrap(Tablet.UpdateDetachedData, "Tablet:UpdateDetachedData") if DEBUG then function Tablet:ListProfileInfo() local duration, times, memories = GetProfileInfo() self: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 local function activate(self, oldLib, oldDeactivate) Tablet = self if oldLib then self.registry = oldLib.registry self.onceRegistered = oldLib.onceRegistered self.tooltip = oldLib.tooltip else self.registry = {} self.onceRegistered = {} end tooltip = self.tooltip if oldDeactivate then oldDeactivate(oldLib) end end local function deactivate(self) StopCheckingAlt() end AceLibrary:Register(Tablet, MAJOR_VERSION, MINOR_VERSION, activate, deactivate)