--[[ Name: Tablet-2.0 Revision: $Rev: 216 $ Author(s): ckknight (ckknight@gmail.com) Website: http://ckknight.wowinterface.com/ Documentation: http://www.wowace.com/index.php/Tablet-2.0 SVN: http://svn.wowace.com/wowace/trunk/TabletLib/Tablet-2.0 Description: A library to provide an efficient, featureful tooltip-style display. Dependencies: AceLibrary, (optional) Dewdrop-2.0 License: LGPL v2.1 ]] local MAJOR_VERSION = "Tablet-2.0" local MINOR_VERSION = 90000 + tonumber(("$Revision: 216 $"):match("(%d+)")) 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." elseif GetLocale() == "esES" then SCROLL_UP = "Desplazar hacia arriba" SCROLL_DOWN = "Desplazar hacia abajo" HINT = "Consejo" DETACH = "Separar" DETACH_DESC = "Separa el tooltip de su fuente." SIZE = "Tama\195\177o" SIZE_DESC = "Escala el tooltip" CLOSE_MENU = "Cerrar men\195\186" CLOSE_MENU_DESC = "Cierra el men\195\186" COLOR = "Color de fondo" COLOR_DESC = "Establece el color de fondo" LOCK = "Bloquear" LOCK_DESC = "Bloquea el tooltip en su posici\195\179n actual. Clic+Alt para el men\195\186 y arrastra+Alt para arrastrarlo cuando est\195\161 bloqueado" elseif GetLocale() == "ruRU" 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+перетаскивание для перетаскивания когда планшет зафиксирован." 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, ...) local pos = #tree tree[#tree+1] = name treeMemories[#treeMemories+1] = 0 treeTimes[#treeTimes+1] = 0 local t, mem = GetTime(), gcinfo() local r1, r2, r3, r4, r5, r6, r7, r8 = oldFunction(self, ...) 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 function GetMainFrame() if UIParent:IsShown() then return UIParent end local f = GetUIPanel("fullscreen") if f and f:IsShown() then return f end return nil end GetMainFrame = wrap(GetMainFrame, "GetMainFrame") local MIN_TOOLTIP_SIZE = 200 local TESTSTRING_EXTRA_WIDTH = 8 local Tablet = {} local Dewdrop = nil local CleanCategoryPool local pool = {} local function del(t) setmetatable(t, nil) for k in pairs(t) do t[k] = nil end t[''] = true t[''] = nil pool[t] = true return nil end local function copy(parent) local t = next(pool) if not t then t = {} else pool[t] = nil end if parent then for k,v in pairs(parent) do t[k] = v end setmetatable(t, getmetatable(parent)) end return t end local function new(...) local t = next(pool) if not t then t = {} else pool[t] = nil end for i = 1, select('#', ...), 2 do local k = select(i, ...) if k then t[k] = select(i+1, ...) else break end end return t end local tmp tmp = setmetatable({}, {__index = function(self, key) local t = {} tmp[key] = function(...) for k in pairs(t) do t[k] = nil end for i = 1, select('#', ...), 2 do local k = select(i, ...) if k then t[k] = select(i+1, ...) else break end end return t end return tmp[key] end}) local headerSize, normalSize if GameTooltipHeaderText then headerSize = select(2,GameTooltipHeaderText:GetFont()) else headerSize = 14 end if GameTooltipText then normalSize = select(2,GameTooltipText:GetFont()) else normalSize = 12 end local tooltip local testString local TabletData = {} local Category = {} local Line = {} local function getTestWidth(font, size, text) if not testString then return MIN_TOOLTIP_SIZE + 40 end testString:SetWidth(0) testString:SetFontObject(font) local a,_,b = font:GetFont() testString:SetFont(a, size, b) testString:SetText(text) return testString:GetStringWidth()-- + TESTSTRING_EXTRA_WIDTH end getTestWidth = wrap(getTestWidth, "getTestWidth") do local TabletData_mt = { __index = TabletData } function TabletData:new(tablet) local self = new() self.categories = new() self.id = 0 self.width = 0 -- (MIN_TOOLTIP_SIZE - 20)*tablet.fontSizePercent self.tablet = tablet self.title = nil self.titleR, self.titleG, self.titleB = nil, nil, nil self.num_lines = 0 setmetatable(self, TabletData_mt) return self end TabletData.new = wrap(TabletData.new, "TabletData:new") function TabletData:checkMinWidth() local min = self.minWidth or MIN_TOOLTIP_SIZE local width = (min - 20)*self.tablet.fontSizePercent if self.width < width then self.width = width end end TabletData.checkMinWidth = wrap(TabletData.checkMinWidth, "TabletData:checkMinWidth") function TabletData:del() for k, v in ipairs(self.categories) do v:del() end del(self.categories) del(self) end TabletData.del = wrap(TabletData.del, "TabletData:del") function TabletData:Display() if self.title and (self.tablet == tooltip or self.tablet.registration.showTitleWhenDetached) then local info = new( 'hideBlankLine', true, 'text', self.title, 'justify', "CENTER", 'font', GameTooltipHeaderText, 'isTitle', true ) if self.titleR then info.textR = self.titleR info.textG = self.titleG info.textB = self.titleB end 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 for k, v in ipairs(self.categories) do local width if v.columns <= 2 then width = v.x1 else width = (v.columns - 1)*20 for i = 1, v.columns do width = width + v['x' .. i] end 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) and (not v.isTitle or not self.tablet.registration.hideWhenEmpty or next(self.categories, k)) 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[#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 TabletData.Display = wrap(TabletData.Display, "TabletData:Display") 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 self.categories[#self.categories+1] = cat end if made then del(info) end return cat end TabletData.AddCategory = wrap(TabletData.AddCategory, "TabletData:AddCategory") function TabletData:SetHint(hint) self.hint = hint end TabletData.SetHint = wrap(TabletData.SetHint, "TabletData:SetHint") function TabletData:SetTitle(title) self.title = title or "Title" end TabletData.SetTitle = wrap(TabletData.SetTitle, "TabletData:SetTitle") function TabletData:SetTitleColor(r, g, b) self.titleR = r self.titleG = g self.titleB = b end TabletData.SetTitleColor = wrap(TabletData.SetTitleColor, "TabletData:SetTitleColor") 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 k:find("^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 for i = 1, self.columns do self['x' .. i] = 0 end setmetatable(self, Category_mt) self.lastWasTitle = nil local good = self.text if not good then for i = 2, self.columns do if self['text' .. i] then good = true break end end end if good then local x = new( 'category', category, 'text', self.text, 'fakeChild', true, 'func', self.func, 'onEnterFunc', self.onEnterFunc, 'onLeaveFunc', self.onLeaveFunc, '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, 'isTitle', self.isTitle ) local i = 1 while true do local k = 'arg' .. i local v = self[k] if v == nil then break end x[k] = v i = i + 1 end i = 1 while true do local k = 'onEnterArg' .. i local v = self[k] if v == nil then break end x[k] = v i = i + 1 end i = 1 while true do local k = 'onLeaveArg' .. i local v = self[k] if v == nil then break end x[k] = v i = i + 1 end 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 for i = 2, self.columns do x['text' .. i] = self['text' .. i] x['text' .. i .. 'R'] = self['text' .. i .. 'R'] or self['textR' .. i] or 1 x['text' .. i .. 'G'] = self['text' .. i .. 'G'] or self['textG' .. i] or 1 x['text' .. i .. 'B'] = self['text' .. i .. 'B'] or self['textB' .. i] or 1 x['font' .. i] = self['font' .. i] x['size' .. i] = self['size' .. i] x['justify' .. i] = self['justify' .. i] end if self.checkIcon and self.checkIcon:find("^Interface\\Icons\\") then x.checkCoordLeft = self.checkCoordLeft or 0.05 x.checkCoordRight = self.checkCoordRight or 0.95 x.checkCoordTop = self.checkCoordTop or 0.05 x.checkCoordBottom = self.checkCoordBottom or 0.95 else x.checkCoordLeft = self.checkCoordLeft or 0 x.checkCoordRight = self.checkCoordRight or 1 x.checkCoordTop = self.checkCoordTop or 0 x.checkCoordBottom = self.checkCoordBottom or 1 end x.checkColorR = self.checkColorR or 1 x.checkColorG = self.checkColorG or 1 x.checkColorB = self.checkColorB or 1 self:AddLine(x) del(x) self.lastWasTitle = true end return self end Category.new = wrap(Category.new, "Category:new") function Category:del() local prev = garbageLine for k, v in pairs(self.lines) do v:del() end del(self.lines) del(self) end Category.del = wrap(Category.del, "Category:del") function Category:AddLine(...) self.lastWasTitle = nil local line local k1 = ... if type(k1) == "table" then local k2 = select(2, ...) Line:new(self, k1, k2) else local info = new(...) Line:new(self, info) info = del(info) end end Category.AddLine = wrap(Category.AddLine, "Category:AddLine") function Category:AddCategory(...) local lastWasTitle = self.lastWasTitle self.lastWasTitle = nil local info local k1 = ... if type(k1) == "table" then info = k1 else info = new(...) end if lastWasTitle or #self.lines == 0 then info.hideBlankLine = true end local cat = Category:new(self.tabletData, info, self) self.lines[#self.lines+1] = cat if info ~= k1 then info = del(info) end return cat end Category.AddCategory = wrap(Category.AddCategory, "Category:AddCategory") 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 Category.HasChildren = wrap(Category.HasChildren, "Category:HasChildren") 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, 'noInherit', true ) self:AddLine(info, 1) del(info) end local good = false if #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 Category.Display = wrap(Category.Display, "Category:Display") 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 k:find("^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 category.lines[#category.lines+1] = self end setmetatable(self, Line_mt) local n = category.tabletData.num_lines + 1 category.tabletData.num_lines = n if n == 10 then category.tabletData:checkMinWidth() end 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 else for i = 2, columns-1 do if not self['justify' .. i] then self['justify' .. i] = "CENTER" end end if not self.justify then self.justify = "LEFT" end if not self['justify' .. columns] then self['justify' .. columns] = "RIGHT" end if self.wrap then for i = 2, columns do self['wrap' .. i] = false end else for i = 2, columns do if self['wrap' .. i] then for j = i+1, columns do self['wrap' .. i] = false end break 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 for i = 2, columns do if not self['font' .. i] then self['font' .. i] = self.font end end if not self.size then self.size = select(2,self.font:GetFont()) end for i = 2, columns do if not self['size' .. i] then self['size' .. i] = select(2,self['font' .. i]:GetFont()) end end if self.checkIcon and self.checkIcon:find("^Interface\\Icons\\") then if not self.checkCoordLeft then self.checkCoordLeft = 0.05 end if not self.checkCoordRight then self.checkCoordRight = 0.95 end if not self.checkCoordTop then self.checkCoordTop = 0.05 end if not self.checkCoordBottom then self.checkCoordBottom = 0.95 end else if not self.checkCoordLeft then self.checkCoordLeft = 0 end if not self.checkCoordRight then self.checkCoordRight = 1 end if not self.checkCoordTop then self.checkCoordTop = 0 end if not self.checkCoordBottom then self.checkCoordBottom = 1 end end if not self.checkColorR then self.checkColorR = 1 end if not self.checkColorG then self.checkColorG = 1 end if not self.checkColorB then self.checkColorB = 1 end local fontSizePercent = category.tabletData.tablet.fontSizePercent local w = 0 self.checkWidth = 0 testString = category.tabletData.tablet.buttons[1].col1 if self.text then if not self.wrap then local testWidth = getTestWidth(self.font, self.size * fontSizePercent, self.text) local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 self.checkWidth = checkWidth w = testWidth + self.indentation * fontSizePercent + checkWidth if category.superCategory.x1 < w then category.superCategory.x1 = w end else if columns == 1 then local testWidth = getTestWidth(self.font, self.size * fontSizePercent, self.text) local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 self.checkWidth = checkWidth w = testWidth + self.indentation * fontSizePercent + checkWidth 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 local testWidth = getTestWidth(self.font2, self.size2 * fontSizePercent, self.text2) w = w + 40 * fontSizePercent + testWidth 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 local testWidth = getTestWidth(self.font2, self.size2 * fontSizePercent, self.text2) local w = testWidth 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 for i = 3, columns do local text = self['text' .. i] if text then local x_i = 'x' .. i if not self['wrap' .. i] then local testWidth = getTestWidth(self['font' .. i], self['size' .. i] * fontSizePercent, text) local w = testWidth if category.superCategory[x_i] < w then category.superCategory[x_i] = w end else local w = MIN_TOOLTIP_SIZE / 2 if category.superCategory[x_i] < w then category.superCategory[x_i] = w end end end end end return self end Line.new = wrap(Line.new, "Line:new") function Line:del() del(self) end Line.del = wrap(Line.del, "Line:del") function Line:Display(tablet) tablet:AddLine(self) return true end Line.Display = wrap(Line.Display, "Line:Display") end local fake_ipairs do local function iter(tmp, i) i = i + 1 local x = tmp[i] tmp[i] = nil if x then return i, x end end local tmp = {} function fake_ipairs(...) for i = 1, select('#', ...) do tmp[i] = select(i, ...) end return iter, tmp, 0 end fake_ipairs = wrap(fake_ipairs, "fake_ipairs") end local function argunpack(t, key, i) if not i then i = 1 end local k = key .. i local v = t[k] if v then return v, argunpack(t, key, i+1) end end argunpack = wrap(argunpack, "argunpack") local delstring, newstring do local cache = {} function delstring(t) cache[#cache+1] = t t:SetText(nil) t:ClearAllPoints() t:Hide() t:SetParent(UIParent) return nil end delstring = wrap(delstring, "delstring") function newstring(parent) if #cache ~= 0 then local t = cache[#cache] cache[#cache] = nil t:Show() t:SetParent(parent) return t end local t = parent:CreateFontString(nil, "ARTWORK") return t end newstring = wrap(newstring, "newstring") end local function button_OnEnter(this, ...) if type(this.self:GetScript("OnEnter")) == "function" then this.self:GetScript("OnEnter")(this.self, ...) end this.highlight:Show() if this.onEnterFunc then local success, ret = pcall(this.onEnterFunc, argunpack(this, 'onEnterArg')) if not success then geterrorhandler()(ret) end end end button_OnEnter = wrap(button_OnEnter, "button_OnEnter") local function button_OnLeave(this, ...) if type(this.self:GetScript("OnLeave")) == "function" then this.self:GetScript("OnLeave")(this.self, ...) end this.highlight:Hide() if this.onLeaveFunc then local success, ret = pcall(this.onLeaveFunc, argunpack(this, 'onLeaveArg')) if not success then geterrorhandler()(ret) end end end button_OnLeave = wrap(button_OnLeave, "button_OnLeave") local lastMouseDown local function button_OnClick(this, arg1, ...) if this.self:HasScript("OnClick") and type(this.self:GetScript("OnClick")) == "function" then this.self:GetScript("OnClick")(this.self, arg1, ...) end if arg1 == "RightButton" then if this.self:HasScript("OnClick") and type(this.self:GetScript("OnClick")) == "function" then this.self:GetScript("OnClick")(this.self, arg1, ...) 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 local success, ret = pcall(this.func, argunpack(this, 'arg')) if not success then geterrorhandler()(ret) end if this.self and this.self.registration then this.self.preventRefresh = false this.self:children() this.self.updating = false end end end end button_OnClick = wrap(button_OnClick, "button_OnClick") local function button_OnMouseUp(this, arg1, ...) if this.self:HasScript("OnMouseUp") and type(this.self:GetScript("OnMouseUp")) == "function" then this.self:GetScript("OnMouseUp")(this.self, arg1, ...) 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 button_OnMouseUp = wrap(button_OnMouseUp, "button_OnMouseUp") local function button_OnMouseDown(this, arg1, ...) if this.self:HasScript("OnMouseDown") and type(this.self:GetScript("OnMouseDown")) == "function" then this.self:GetScript("OnMouseDown")(this.self, arg1, ...) 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 button_OnMouseDown = wrap(button_OnMouseDown, "button_OnMouseDown") local function button_OnDragStart(this, ...) local parent = this:GetParent() and this:GetParent().tablet if parent:GetScript("OnDragStart") then return parent:GetScript("OnDragStart")(parent, ...) end end button_OnDragStart = wrap(button_OnDragStart, "button_OnDragStart") local function button_OnDragStop(this, ...) local parent = this:GetParent() and this:GetParent().tablet if parent:GetScript("OnDragStop") then return parent:GetScript("OnDragStop")(parent, ...) end end button_OnDragStop = wrap(button_OnDragStop, "button_OnDragStop") local num_buttons = 0 local function NewLine(self) if self.maxLines <= self.numLines then self.maxLines = self.maxLines + 1 num_buttons = num_buttons + 1 local button = CreateFrame("Button", "Tablet20Button" .. num_buttons, self.scrollChild) button:SetFrameLevel(12) button.indentation = 0 local check = button:CreateTexture(nil, "ARTWORK") local col1 = newstring(button) testString = col1 local highlight = button:CreateTexture(nil, "BACKGROUND") highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") button.highlight = highlight highlight:SetBlendMode("ADD") highlight:SetAllPoints(button) highlight:Hide() self.buttons[#self.buttons+1] = button button.check = check button.col1 = col1 col1:SetWidth(0) if self.maxLines == 1 then col1:SetFontObject(GameTooltipHeaderText) col1:SetJustifyH("CENTER") button:SetPoint("TOPLEFT", self.scrollFrame, "TOPLEFT", 3, -5) else col1: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.scrollFrame, "RIGHT", -7, 0) check.shown = false check:SetPoint("TOPLEFT", button, "TOPLEFT") col1:SetPoint("TOPLEFT", check, "TOPLEFT") local size = select(2,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() col1:Hide() end end NewLine = wrap(NewLine, "NewLine") local function RecalculateTabletHeight(detached) detached.height_ = nil if detached.registration and detached.registration.positionFunc then local height = detached:GetHeight() if height > 0 then detached.height_ = height else local top, bottom for i = 1, detached:GetNumPoints() do local a,b,c,d,e = detached:GetPoint(i) if a:find("^TOP") then if c:find("^TOP") then top = b:GetTop() elseif c:find("^BOTTOM") then top = b:GetBottom() else top = select(2,b:GetCenter()) end if top then top = top + e end elseif a:find("^BOTTOM") then if c:find("^TOP") then bottom = b:GetTop() elseif c:find("^BOTTOM") then bottom = b:GetBottom() else bottom = select(2,b:GetCenter()) end if bottom then bottom = bottom + e end end end if top and bottom then detached.height_ = top - bottom end end end end RecalculateTabletHeight = wrap(RecalculateTabletHeight, "RecalculateTabletHeight") local function GetTooltipHeight(self) RecalculateTabletHeight(self) if self.height_ then local height = self:GetTop() and self:GetBottom() and self:GetTop() - self:GetBottom() or self:GetHeight() if height == 0 then height = self.height_ end return height end if self.registration.maxHeight then return self.registration.maxHeight end if self == tooltip then return GetScreenHeight()*3/4 else return GetScreenHeight()*2/3 end end GetTooltipHeight = wrap(GetTooltipHeight, "GetTooltipHeight") local overFrame = nil 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) tooltip:SetParent(GetMainFrame()) tooltip:SetFrameStrata(registration.strata or "TOOLTIP") tooltip:SetFrameLevel(10) for _,frame in fake_ipairs(tooltip:GetChildren()) do frame:SetFrameLevel(12) end else tooltip = CreateFrame("Frame", "Tablet20Frame", UIParent) tooltip:SetParent(GetMainFrame()) self.tooltip = tooltip tooltip.data = data tooltip.detachedData = detachedData tooltip:EnableMouse(true) tooltip:EnableMouseWheel(true) tooltip:SetFrameStrata(registration.strata or "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.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:SetScript("OnUpdate", function(this, elapsed) if not tooltip.updating and (not tooltip.enteredFrame or (overFrame and not MouseIsOver(overFrame))) then tooltip.scrollFrame:SetVerticalScroll(0) tooltip.slider:SetValue(0) tooltip:Hide() tooltip.registration.tooltip = nil tooltip.registration = nil overFrame = nil end end) tooltip:SetScript("OnEnter", function(this) if tooltip.clickable then tooltip.enteredFrame = true overFrame = nil end end) tooltip:SetScript("OnLeave", function(this) if not tooltip.updating then tooltip.enteredFrame = false end end) tooltip:SetScript("OnMouseWheel", function(this, arg1) tooltip.updating = true tooltip:Scroll(arg1 < 0) tooltip.updating = false end) local scrollFrame = CreateFrame("ScrollFrame", "Tablet20FrameScrollFrame", tooltip) scrollFrame:SetFrameLevel(11) local scrollChild = CreateFrame("Frame", "Tablet20FrameScrollChild", scrollFrame) scrollChild.tablet = tooltip scrollFrame:SetScrollChild(scrollChild) tooltip.scrollFrame = scrollFrame tooltip.scrollChild = scrollChild scrollFrame:SetPoint("TOPLEFT", 5, -5) scrollFrame:SetPoint("TOPRIGHT", -5, -5) scrollFrame:SetPoint("BOTTOMLEFT", 5, 5) scrollFrame:SetPoint("BOTTOMRIGHT", -5, 5) scrollChild:SetWidth(1) scrollChild:SetHeight(1) local slider = CreateFrame("Slider", "Tablet20FrameSlider", scrollFrame) tooltip.slider = slider slider:SetOrientation("VERTICAL") slider:SetMinMaxValues(0, 1) slider:SetValueStep(0.001) slider:SetValue(0) slider:SetWidth(8) slider:SetPoint("TOPRIGHT", 0, 0) slider:SetPoint("BOTTOMRIGHT", 0, 0) slider:SetBackdrop(new( 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", 'tile', true, 'edgeSize', 8, 'tileSize', 8, 'insets', new( 'left', 3, 'right', 3, 'top', 3, 'bottom', 3 ) )) slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") slider:SetScript("OnEnter", tooltip:GetScript("OnEnter")) slider:SetScript("OnLeave", tooltip:GetScript("OnLeave")) slider.tablet = tooltip slider:SetScript("OnValueChanged", function(this) local max = this.tablet.scrollChild:GetHeight() - this.tablet:GetHeight() local val = this:GetValue() * max if math.abs(this.tablet.scrollFrame:GetVerticalScroll() - val) < 1 then return end this.tablet.scrollFrame:SetVerticalScroll(val) end) NewLine(tooltip) 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 = button.check 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 testString = self.buttons[1].col1 local maxWidth = tabletData and tabletData.width or self:GetWidth() - 20 local hasWrap = false local numColumns local height = 20 self:SetWidth(maxWidth + 20) for i = 1, self.numLines do local button = self.buttons[i] local col1 = button.col1 local col2 = button.col2 local check = button.check button:SetWidth(maxWidth) button:SetHeight(col2 and math.max(col1:GetHeight(), col2:GetHeight()) or col1:GetHeight()) height = height + button:GetHeight() + 2 if i == 1 then button:SetPoint("TOPLEFT", self.scrollChild, "TOPLEFT", 5, -5) 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 self.scrollFrame:SetFrameLevel(11) self.scrollChild:SetWidth(maxWidth) self.scrollChild:SetHeight(height) local maxHeight = GetTooltipHeight(self) if height > maxHeight then height = maxHeight self.slider:Show() else self.slider:Hide() end self:SetHeight(height) self.scrollFrame:SetScrollChild(self.scrollChild) local val = self.scrollFrame:GetVerticalScroll() local max = self.scrollChild:GetHeight() - self:GetHeight() if val > max then val = max end if val < 0 then val = 0 end self.scrollFrame:SetVerticalScroll(val) self.slider:SetValue(val/max) end tooltip.Show = wrap(tooltip.Show, "tooltip:Show") 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 = select(2,info.font:GetFont()) end local catStart = false local columns = category and category.columns or 1 local x_total = 0 local x1, x2 if category then for i = 1, category.columns do x_total = x_total + category['x' .. i] end x1, x2 = category.x1, category.x2 else x1, x2 = 0, 0 end self.numLines = self.numLines + 1 NewLine(self) local num = self.numLines local button = self.buttons[num] button:Show() button.col1:Show() button.indentation = info.indentation local col1 = button.col1 local check = button.check do -- if columns >= 1 then col1:SetWidth(0) col1:SetFontObject(info.font) local font,_,flags = info.font:GetFont() col1:SetFont(font, info.size * fontSizePercent, flags) col1:SetText(text) col1:SetJustifyH(info.justify) col1:Show() if info.textR and info.textG and info.textB then col1:SetTextColor(info.textR, info.textG, info.textB) else col1:SetTextColor(1, 0.823529, 0) end if columns < 2 then local i = 2 while true do local col = button['col' .. i] if col then button['col' .. i] = delstring(col) else break end i = i + 1 end else local i = 2 while true do local col = button['col' .. i] if not col then button['col' .. i] = newstring(button) col = button['col' .. i] end col:SetFontObject(info['font' .. i]) col:SetText(info['text' .. i]) col:Show() local r,g,b = info['text' .. i .. 'R'] if r then g = info['text' .. i .. 'G'] if g then b = info['text' .. i .. 'B'] end end if b then col:SetTextColor(r, g, b) else col:SetTextColor(1, 0.823529, 0) end local a,_,b = info.font2:GetFont() col:SetFont(a, info['size' .. i] * fontSizePercent, b) col:SetJustifyH(info['justify' .. i]) if columns == i then if i == 2 then col:SetPoint("TOPLEFT", col1, "TOPRIGHT", 40 * fontSizePercent, 0) col:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) else local col2 = button.col2 col2:ClearAllPoints() col2:SetPoint("TOPLEFT", col1, "TOPRIGHT", (20 - info.indentation) * fontSizePercent, 0) end i = i + 1 while true do local col = button['col' .. i] if col then button['col' .. i] = delstring(col) else break end i = i + 1 end break end i = i + 1 end end end check:SetWidth(info.size * fontSizePercent) check:SetHeight(info.size * fontSizePercent) check.width = info.size * fontSizePercent 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 check:SetVertexColor(1, 1, 1) else if info.checkIcon then check:SetTexture(info.checkIcon) check:SetTexCoord(info.checkCoordLeft, info.checkCoordRight, info.checkCoordTop, info.checkCoordBottom) check:SetVertexColor(info.checkColorR, info.checkColorG, info.checkColorB) else check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") check:SetWidth(info.size * fontSizePercent * 1.5) check:SetHeight(info.size * fontSizePercent * 1.5) check.width = info.size * fontSizePercent * 1.2 check:SetTexCoord(0, 1, 0, 1) check:SetVertexColor(1, 1, 1) end check:SetAlpha(info.checked and 1 or 0) end col1:SetPoint("TOPLEFT", check, "TOPLEFT", check.width, 0) else col1:SetPoint("TOPLEFT", check, "TOPLEFT") end local col2 = button.col2 if columns == 1 then col1:SetWidth(maxWidth) elseif columns == 2 then if info.wrap then col1:SetWidth(maxWidth - col2:GetWidth() - 40 * fontSizePercent) col2:SetWidth(0) elseif info.wrap2 then col1:SetWidth(0) col2:SetWidth(maxWidth - col1:GetWidth() - 40 * fontSizePercent) else col1:SetWidth(0) col2:SetWidth(0) end col2:ClearAllPoints() col2:SetPoint("TOPRIGHT", button, "TOPRIGHT", 0, 0) if not info.text2 then col1:SetJustifyH(info.justify or "LEFT") end else col1:SetWidth(x1 - info.checkWidth) col2:SetWidth(x2) local num = (category.tabletData.width - x_total) / (columns - 1) col2:SetPoint("TOPLEFT", col1, "TOPRIGHT", num - info.indentation * fontSizePercent, 0) local last = col2 for i = 3, category.columns do local col = button['col' .. i] col:SetWidth(category['x' .. i]) col:SetPoint("TOPLEFT", last, "TOPRIGHT", num, 0) last = col end end button.func = nil button.onEnterFunc = nil button.onLeaveFunc = nil button:SetFrameLevel(12) -- hack suggested on forum. Added 06/17/2007. (hC) if not self.locked or IsAltKeyDown() then local func = info.func if func then if type(func) == "string" then if type(info.arg1) ~= "table" then Tablet:error("Cannot call method " .. info.func .. " on a non-table") end func = info.arg1[func] if type(func) ~= "function" then Tablet:error("Method " .. info.func .. " nonexistant") end else if type(func) ~= "function" then Tablet:error("func must be a function or method") end end button.func = func local i = 1 while true do local k = 'arg' .. i if button[k] ~= nil then button[k] = nil else break end i = i + 1 end i = 1 while true do local k = 'arg' .. i local v = info[k] if v == nil then break end button[k] = v i = i + 1 end local onEnterFunc = info.onEnterFunc if onEnterFunc then if type(onEnterFunc) == "string" then if type(info.onEnterArg1) ~= "table" then Tablet:error("Cannot call method " .. info.onEnterFunc .. " on a non-table") end onEventFunc = info.onEnterArg1[onEnterFunc] if type(onEnterFunc) ~= "function" then Tablet:error("Method " .. info.onEnterFunc .. " nonexistant") end else if type(onEnterFunc) ~= "function" then Tablet:error("func must be a function or method") end end button.onEnterFunc = onEnterFunc local i = 1 while true do local k = 'onEnterArg' .. i if button[k] ~= nil then button[k] = nil else break end i = i + 1 end i = 1 while true do local k = 'onEnterArg' .. i local v = info[k] if v == nil then break end button[k] = v i = i + 1 end end local onLeaveFunc = info.onLeaveFunc if onLeaveFunc then if type(onLeaveFunc) == "string" then if type(info.onLeaveArg1) ~= "table" then Tablet:error("Cannot call method " .. info.onLeaveFunc .. " on a non-table") end onLeaveFunc = info.onLeaveArg1[onLeaveFunc] if type(onLeaveFunc) ~= "function" then Tablet:error("Method " .. info.onLeaveFunc .. " nonexistant") end else if type(onLeaveFunc) ~= "function" then Tablet:error("func must be a function or method") end end button.onLeaveFunc = onLeaveFunc local i = 1 while true do local k = 'onLeaveArg' .. i if button[k] ~= nil then button[k] = nil else break end i = i + 1 end i = 1 while true do local k = 'onLeaveArg' .. i local v = info[k] if v == nil then break end button[k] = v i = i + 1 end end button.self = self button:SetScript("OnMouseUp", button_OnMouseUp) button:SetScript("OnMouseDown", button_OnMouseDown) button:RegisterForDrag("LeftButton") button:SetScript("OnDragStart", button_OnDragStart) button:SetScript("OnDragStop", button_OnDragStop) 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:RegisterForDrag() button:SetScript("OnDragStart", nil) button:SetScript("OnDragStop", nil) button:SetScript("OnClick", nil) button:EnableMouse(false) end else button:SetScript("OnMouseDown", nil) button:SetScript("OnMouseUp", nil) button:RegisterForDrag() button:SetScript("OnDragStart", nil) button:SetScript("OnDragStop", 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 end local ratio = self.fontSizePercent / lastSize for i = 1, self.numLines do local button = self.buttons[i] local j = 1 while true do local col = button['col' .. j] if not col then break end local font, size, flags = col:GetFont() col:SetFont(font, size * ratio, flags) j = j + 1 end local check = button.check 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:children() 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) self.slider:SetBackdropColor(self.r or 0, self.g or 0, self.b or 0, alpha) self.slider: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) local val local max = self.scrollChild:GetHeight() - self:GetHeight() if down then if IsShiftKeyDown() then val = max else val = self.scrollFrame:GetVerticalScroll() + 36 if val > max then val = max end end else if IsShiftKeyDown() then val = 0 else val = self.scrollFrame:GetVerticalScroll() - 36 if val < 0 then val = 0 end end end self.scrollFrame:SetVerticalScroll(val) self.slider:SetValue(val/max) end tooltip.Scroll = wrap(tooltip.Scroll, "tooltip:Scroll") function tooltip.Detach(tooltip) local owner = tooltip.owner tooltip:Hide() if not tooltip.detachedData then self:error("You cannot detach if detachedData is not present") end tooltip.detachedData.detached = true local detached = AcquireDetachedFrame(self, tooltip.registration, tooltip.data, tooltip.detachedData) detached.menu, tooltip.menu = tooltip.menu, nil detached.runChildren = tooltip.runChildren detached.children = tooltip.children detached.minWidth = tooltip.minWidth tooltip.runChildren = nil tooltip.children = nil tooltip.minWidth = 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 detached.detachedData = nil end end end ReleaseDetachedFrame = wrap(ReleaseDetachedFrame, "ReleaseDetachedFrame") local StartCheckingAlt, StopCheckingAlt do local frame function StartCheckingAlt(func) if not frame then frame = CreateFrame("Frame") frame:SetScript("OnEvent", function(this, _, modifier) if modifier == "LALT" or modifier == "RALT" then this.func() end end) end frame:RegisterEvent("MODIFIER_STATE_CHANGED") frame.func = func end StartCheckingAlt = wrap(StartCheckingAlt, "StartCheckingAlt") function StopCheckingAlt() if frame then frame:UnregisterEvent("MODIFIER_STATE_CHANGED") end end StopCheckingAlt = wrap(StopCheckingAlt, "StopCheckingAlt") 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:SetWidth(0) detached:SetHeight(0) if not registration.strata then detached:SetFrameStrata("BACKGROUND") end if not registration.frameLevel then detached:SetFrameLevel(10) for _,frame in fake_ipairs(detached:GetChildren()) do frame:SetFrameLevel(12) end end detached:SetParent(registration.parent or GetMainFrame()) if registration.strata then detached:SetFrameStrata(registration.strata) end if registration.frameLevel then detached:SetFrameLevel(registration.frameLevel) for _,frame in fake_ipairs(detached:GetChildren()) do frame:SetFrameLevel(registration.frameLevel+2) end end detached.height_ = nil if registration.positionFunc then registration.positionFunc(detached) RecalculateTabletHeight(detached) else detached:SetPoint(detachedData.anchor or "CENTER", GetMainFrame(), detachedData.anchor or "CENTER", detachedData.offsetx or 0, detachedData.offsety or 0) end detached.registration = registration registration.tooltip = detached if registration.movable == false then detached:RegisterForDrag() else detached:RegisterForDrag("LeftButton") end 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")(detached, arg1) end arg1 = a1 end end end end) if not tooltip then AcquireFrame(self, {}) end local detached = CreateFrame("Frame", "Tablet20DetachedFrame" .. (#detachedTooltips + 1), GetMainFrame()) detachedTooltips[#detachedTooltips+1] = detached detached.notInUse = true detached:EnableMouse(not data.locked) detached:EnableMouseWheel(true) detached:SetMovable(true) detached:SetPoint(data.anchor or "CENTER", GetMainFrame(), 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.transparency = 0.75 detached.r = 0 detached.g = 0 detached.b = 0 detached:SetFrameStrata(registration and registration.strata or "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:EnableMouse(not detached.locked) local width = GetScreenWidth() local height = GetScreenHeight() if registration and registration.movable == false then detached:RegisterForDrag() else detached:RegisterForDrag("LeftButton") end detached:SetScript("OnDragStart", function(this) detached:StartMoving() detached.moving = true end) detached:SetScript("OnDragStop", function(this) detached:StopMovingOrSizing() detached.moving = nil detached:SetClampedToScreen(1) detached:SetClampedToScreen(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, GetMainFrame(), 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) if Dewdrop then Dewdrop:Register(detached, 'children', function(level, value) if not detached.registration then return end if detached.menu then if type(detached.menu) == "function" then detached.menu(level, value) else Dewdrop:FeedAceOptionsTable(detached.menu) end 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 if not detached.registration.positionFunc then Dewdrop:AddLine( 'text', LOCK, 'tooltipTitle', LOCK, 'tooltipText', LOCK_DESC, 'checked', detached:IsLocked(), 'arg1', detached, 'func', "Lock", 'closeWhenClicked', not detached:IsLocked() ) end 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 ) end local scrollFrame = CreateFrame("ScrollFrame", detached:GetName() .. "ScrollFrame", detached) local scrollChild = CreateFrame("Frame", detached:GetName() .. "ScrollChild", scrollFrame) scrollFrame:SetFrameLevel(11) scrollFrame:SetScrollChild(scrollChild) scrollChild.tablet = detached detached.scrollFrame = scrollFrame detached.scrollChild = scrollChild scrollFrame:SetPoint("TOPLEFT", 5, -5) scrollFrame:SetPoint("BOTTOMRIGHT", -5, 5) scrollChild:SetWidth(1) scrollChild:SetHeight(1) local slider = CreateFrame("Slider", detached:GetName() .. "Slider", scrollFrame) detached.slider = slider slider:SetOrientation("VERTICAL") slider:SetMinMaxValues(0, 1) slider:SetValueStep(0.001) slider:SetValue(0) slider:SetWidth(8) slider:SetPoint("TOPRIGHT", 0, 0) slider:SetPoint("BOTTOMRIGHT", 0, 0) slider:SetBackdrop(new( 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", 'tile', true, 'edgeSize', 8, 'tileSize', 8, 'insets', new( 'left', 3, 'right', 3, 'top', 3, 'bottom', 3 ) )) slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") slider:SetScript("OnEnter", detached:GetScript("OnEnter")) slider:SetScript("OnLeave", detached:GetScript("OnLeave")) slider.tablet = detached slider:SetScript("OnValueChanged", Tablet20FrameSlider:GetScript("OnValueChanged")) NewLine(detached) detached:SetScript("OnMouseWheel", function(this, arg1) 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 if self.detachedData then self.detachedData.locked = self.locked or nil end self:children() end function detached.Attach(detached) if not detached then self:error("Detached tooltip not given.") end if not detached.AddLine then self:error("detached argument not a Tooltip.") end if not detached.owner then self:error("Detached tooltip has no owner.") end if detached.notInUse then self:error("Detached tooltip not in use.") end 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 tooltip.enteredFrame = false end return else self:argCheck(parent, 2, "table", "string") end local info = self.registry[parent] if not info then self:error("You cannot close a tablet with an unregistered parent frame.") end local data = info.data local detachedData = info.detachedData if detachedData and detachedData.detached then ReleaseDetachedFrame(self, data, detachedData) elseif tooltip and tooltip.data == data then tooltip:Hide() if tooltip.registration then tooltip.registration.tooltip = nil tooltip.registration = nil end end if tooltip then tooltip.enteredFrame = false end end Tablet.Close = wrap(Tablet.Close, "Tablet:Close") local function frame_children(self) if not self.preventRefresh and self:GetParent() and self:GetParent():IsShown() then Tablet.currentFrame = self Tablet.currentTabletData = TabletData:new(self) Tablet.currentTabletData.minWidth = self.minWidth self:ClearLines() if self.runChildren then self.runChildren() end Tablet.currentTabletData:Display(Tablet.currentFrame) self:Show(Tablet.currentTabletData) Tablet.currentTabletData:del() Tablet.currentTabletData = nil Tablet.currentFrame = nil end end frame_children = wrap(frame_children, "frame_children") function Tablet:Open(fakeParent, parent) self:argCheck(fakeParent, 2, "table", "string") self:argCheck(parent, 3, "nil", "table", "string") if not parent then parent = fakeParent end local info = self.registry[parent] if not info then self:error("You cannot open a tablet with an unregistered parent frame.") end local detachedData = info.detachedData if detachedData then for _, detached in ipairs(detachedTooltips) do if not detached.notInUse and detached.detachedData == detachedData then return end end end local data = info.data 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 frame.runChildren = info.children frame.minWidth = info.minWidth if not frame.children or not frame.childrenVer or frame.childrenVer < MINOR_VERSION then frame.childrenVer = MINOR_VERSION frame.children = frame_children end frame:SetOwner(fakeParent) frame:children() local point = info.point local relativePoint = info.relativePoint if type(point) == "function" then local b point, b = point(fakeParent) if b then relativePoint = b end end if type(relativePoint) == "function" then relativePoint = relativePoint(fakeParent) 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, fakeParent, relativePoint) end local offsetx = 0 local offsety = 0 frame:SetClampedToScreen(1) frame:SetClampedToScreen(nil) 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(fakeParent) ~= "string" then frame:SetPoint(point, fakeParent, relativePoint, -offsetx, -offsety) end if detachedData and (info.cantAttach or detachedData.detached) and frame == tooltip then detachedData.detached = false frame:Detach() end if (not detachedData or not detachedData.detached) and GetMouseFocus() == fakeParent then self.tooltip.enteredFrame = true end overFrame = type(fakeParent) == "table" and MouseIsOver(fakeParent) and fakeParent end Tablet.Open = wrap(Tablet.Open, "Tablet:Open") function Tablet:Register(parent, ...) self:argCheck(parent, 2, "table", "string") if self.registry[parent] then self:Unregister(parent) end local info local k1 = ... if type(k1) == "table" and k1[0] then if type(self.registry[k1]) ~= "table" then self:error("Other parent not registered") end info = copy(self.registry[k1]) local v1 = select(2, ...) if type(v1) == "function" then info.point = v1 info.relativePoint = nil end else info = new(...) end self.registry[parent] = info info.data = info.data or info.detachedData or new() 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 and AceLibrary:HasInstance("Dewdrop-2.0") 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 (Dewdrop and not Dewdrop:IsOpen(parent)) then self:Open(parent) 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") if not self.registry[parent] then self:error("You cannot unregister a parent frame if it has not been registered already.") end 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 depth = 0 local categoryPool = {} function CleanCategoryPool(self) for k,v in pairs(categoryPool) do del(v) categoryPool[k] = nil end _id = 0 end CleanCategoryPool = wrap(CleanCategoryPool, "CleanCategoryPool") function Tablet:AddCategory(...) if not self.currentFrame then self:error("You must add categories in within a registration.") end local info = new(...) local cat = self.currentTabletData:AddCategory(info) info = del(info) return cat end Tablet.AddCategory = wrap(Tablet.AddCategory, "Tablet:AddCategory") function Tablet:SetHint(text) if not self.currentFrame then self:error("You must set hint within a registration.") end self.currentTabletData:SetHint(text) end Tablet.SetHint = wrap(Tablet.SetHint, "Tablet:SetHint") function Tablet:SetTitle(text) if not self.currentFrame then self:error("You must set title within a registration.") end self.currentTabletData:SetTitle(text) end Tablet.SetTitle = wrap(Tablet.SetTitle, "Tablet:SetTitle") function Tablet:SetTitleColor(r, g, b) if not self.currentFrame then self:error("You must set title color within a registration.") end self:argCheck(r, 2, "number") self:argCheck(g, 3, "number") self:argCheck(b, 4, "number") self.currentTabletData:SetTitleColor(r, g, b) end Tablet.SetTitleColor = wrap(Tablet.SetTitleColor, "Tablet:SetTitleColor") function Tablet:GetNormalFontSize() return normalSize end Tablet.GetNormalFontSize = wrap(Tablet.GetNormalFontSize, "Tablet:GetNormalFontSize") function Tablet:GetHeaderFontSize() return headerSize end Tablet.GetHeaderFontSize = wrap(Tablet.GetHeaderFontSize, "Tablet:GetHeaderFontSize") function Tablet:GetNormalFontObject() return GameTooltipText end Tablet.GetNormalFontObject = wrap(Tablet.GetNormalFontObject, "Tablet:GetNormalFontObject") function Tablet:GetHeaderFontObject() return GameTooltipHeaderText end Tablet.GetHeaderFontObject = wrap(Tablet.GetHeaderFontObject, "Tablet:GetHeaderFontObject") 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:error("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:error("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 if info.tooltip then info.tooltip:SetTransparency(percent) else local data = info.data local detachedData = info.detachedData 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:error("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:error("You cannot get transparency with an unregistered parent frame.") 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:error("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:error("You must provide a registered 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] if not info then self:error("You cannot detach tablet with an unregistered parent frame.") end if not info.detachedData then self:error("You cannot detach tablet without a data field.") end if info.tooltip and info.tooltip == tooltip and tooltip.registration then tooltip:Detach() else info.detachedData.detached = true local detached = AcquireDetachedFrame(self, info, info.data, info.detachedData) detached.menu = info.menu detached.runChildren = info.children detached.minWidth = info.minWidth if not detached.children or not detached.childrenVer or detached.childrenVer < MINOR_VERSION then detached.childrenVer = MINOR_VERSION detached.children = frame_children 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] if not info then self:error("You cannot detach tablet with an unregistered parent frame.") end if not info.detachedData then self:error("You cannot attach tablet without a data field.") end 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] if not info then self:error("You cannot check tablet with an unregistered parent frame.") end 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] if not info then self:error("You cannot refresh tablet with an unregistered parent frame.") end 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] if not info then self:error("You cannot check tablet with an unregistered parent frame.") end 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] if not info then self:error("You cannot lock tablet with an unregistered parent frame.") end 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] if not info then self:error("You cannot update tablet with an unregistered parent frame.") end 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() if not duration or not time or not memories then self:error("Problems") end local t = new() for method in pairs(memories) do t[#t+1] = 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)) del(t) end SLASH_TABLET1 = "/tablet" SLASH_TABLET2 = "/tabletlib" SlashCmdList["TABLET"] = function(msg) AceLibrary(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 self.currentFrame = oldLib.currentFrame self.currentTabletData = oldLib.currentTabletData 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)