Mercurial > wow > reaction
view classes/ReBar.lua @ 7:f920db5fc6b1
version 0.3
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Tue, 20 Mar 2007 21:25:29 +0000 |
parents | dfd829db3ad0 |
children | c05fd3e18b4f |
line wrap: on
line source
-- private constants local anchoredLabelColor = { r = 1.0, g = 0.82, b = 0.0 } local nonAnchoredLabelColor = { r = 1.0, g = 1.0, b = 1.0 } local DRAG_UPDATE_RATE = 0.125 -- cap at 8 Hz local nStancePages = { WARRIOR = 3, ROGUE = 0, HUNTER = 0, DRUID = 3, -- updated to 4 if talented PALADIN = 0, SHAMAN = 0, -- As far as I know, ghost wolf is not a proper shapeshift form, it's just a buff MAGE = 0, PRIEST = 0, -- updated to 1 if talented WARLOCK = 0, } local stanceMaps = { WARRIOR = { -- note: warriors are never in shapeshift form 0. [1] = "*:1", -- battle stance. All states go to state (page) 1. [2] = "*:2", -- defensive stance. All states go to state (page) 2. [3] = "*:3", -- berserker stance. All states go to state (page) 3. }, ROGUE = {}, HUNTER = {}, DRUID = { [0] = "*:1", -- humanoid form. All states go to state (page) 1. [1] = "*:2", -- bear/dire bear form. All states go to state (page) 2. [2] = "*:1", -- aquatic form. All states to go state (page) 1 (same as humanoid) [3] = "*:3", -- cat form. All states go to state (page) 3 [4] = "*:1", -- travel form. All states go to state (page) 1 (same as humanoid) [5] = "*:4", -- oomkin/tree form [talent only]. All states go to state (page) 4 [6] = "*:1", -- flight form. All states go to state (page) 1 (same as humanoid) (??? How does this work with oomkin/tree?) }, PALADIN = {}, SHAMAN = {}, MAGE = {}, PRIEST = { [0] = "*:1", -- normal form. All states go to page 1. [1] = "*:2", -- shadowform (talent only). All states go to page 2. }, WARLOCK = {}, } local stealthMaps = { WARRIOR = "", ROGUE = "1:2", -- go to page 2 for rogues HUNTER = "", DRUID = "3:5", -- we'll replace with 1:2 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree PALADIN = "", SHAMAN = "", MAGE = "", PRIEST = "", } local unstealthMaps = { WARRIOR = "", ROGUE = "2:1", -- go to page 1 for rogues HUNTER = "", DRUID = "5:3", -- we'll replace with 2:1 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree PALADIN = "", SHAMAN = "", MAGE = "", PRIEST = "", } -- Immediately fix if a druid with oomkin or tree (note: can't have both) local _, playerClass = UnitClass("player") if playerClass == "DRUID" and GetNumShapeshiftForms() > 4 then nStancePages.DRUID = 4 stanceMaps.DRUID[5] = "*:4" stealthMaps.DRUID = "3:6" unstealthMaps.DRUID ="6:3" end -- Immediately fix if a priest with shadowform if playerClass == "PRIEST" and GetNumShapeshiftForms() > 1 then nStancePages.PRIEST = 2 end local AceOO = AceLibrary("AceOO-2.0") -- ReBar is an Ace 2 class prototype object. ReBar = AceOO.Class("AceEvent-2.0", ReAnchor, ReAnchor.IAnchorable) ---------------------- -- Static members ---------------------- -- IButtonClass is an interface required of any button class type (not the class objects themselves) to be used with the bar ReBar.IButtonClass = AceOO.Interface { Acquire = "function", -- btn = Acquire(config, barIdx, pages, buttonsPerPage) -- analogous to new(), this should re-use recycled frames for memory efficiency Release = "function", -- Release(btn) should hide and dispose of the button (and recycle it) } -- IButton is an interface required of any button objects to be used with the bar ReBar.IButton = AceOO.Interface { GetActionFrame = "function", -- obtains the action frame, presumably inherited from SecureActionButtonTemplate or similar. BarLocked = "function", -- BarLocked() called when the bar is locked. BarUnlocked = "function", -- BarUnlocked() called when the bar is unlocked. PlaceButton = "function", -- PlaceButton(parent, anchorPoint, offsetX, offsetY, squareSz), one-stop position and size setting SetPages = "function", -- SetPages(n): sets number of pages for multi-paging. Can error if paging not supported. } -- wrap UIParent and WorldFrame in objects which implement the ReAnchor.IAnchorable interface local UIParentPlaceable = { GetFrame = function() return UIParent end, GetAnchorage = function() return ReAnchor.anchorInside end, } local WorldFramePlaceable = { GetFrame = function() return WorldFrame end, GetAnchorage = function() return ReAnchor.anchorInside end, } ReBar.anchorTargets = { UIParentPlaceable, WorldFramePlaceable } ReBar.UIParentAnchorTarget = { UIParentPlaceable } -------------------- -- instance methods -------------------- -- construction and destruction function ReBar.prototype:init( config, id ) ReBar.super.prototype.init(self) self.config = config self.barID = id self.buttons = { } self.locked = true self.buttonClass = config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) if not AceOO.inherits(self.buttonClass, ReBar.IButton) then error("ReBar: Supplied Button type does not meet required interface.") end -- create the bar and control widgets self.barFrame = CreateFrame("Frame", "ReBar"..id, config.parent and getglobal(config.parent) or UIParent, "ReBarTemplate") self.controlFrame = getglobal(self.barFrame:GetName().."Controls") self.controlFrame.reBar = self self.barFrame:SetClampedToScreen(true) -- set the text label on the control widget self.labelString = getglobal(self.controlFrame:GetName().."LabelString") self.labelString:SetText(id) -- initial stateheader state self.barFrame.StateChanged = function() self:StateChanged() end self.barFrame:SetAttribute("state",config.pages and config.pages.currentPage or 1) -- initial state -- initialize the bar layout self:ApplySize() self:ApplyAnchor() self:AcquireButtons() self:LayoutButtons() self:ApplyVisibility() if self.config.pages then self:SetPages(self.config.pages.n) self:ApplyAutoStanceSwitch() self:ApplyAutoStealthSwitch() self:RefreshPageControls() end -- register page up/down buttons with ReBound for keybinding if ReBound then ReBound:AddKeybindTarget(getglobal(self.barFrame:GetName().."PageUp")) ReBound:AddKeybindTarget(getglobal(self.barFrame:GetName().."PageDown")) end -- add bar to anchorTargets list table.insert(ReBar.anchorTargets, self) end function ReBar.prototype:Destroy() local f = self.barFrame self:HideControls() f:Hide() f:ClearAllPoints() f:SetParent(nil) f:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0) while #self.buttons > 0 do self.buttonClass:Release(table.remove(self.buttons)) end -- remove from anchorTargets table for idx, b in ipairs(ReBar.anchorTargets) do if b == self then table.remove(ReBar.anchorTargets, idx) break end end -- remove from globals local n = f:GetName() setglobal(n, nil) setglobal(n.."Control", nil) setglobal(n.."Controls", nil) setglobal(n.."ControlsLabelString", nil) setglobal(n.."PageUp", nil) setglobal(n.."PageDown", nil) setglobal(n.."Page", nil) setglobal(n.."PageNumber", nil) setglobal(n.."PageNumberLabel", nil) setglobal(n.."PageNumberLabelText", nil) end -- ReAnchor.IAnchorable interface implementation function ReBar.prototype:GetFrame() return self.barFrame end function ReBar.prototype:GetAnchorage() return ReAnchor.anchorOutside end -- show/hide the control frame function ReBar.prototype:ShowControls() self.locked = false self.controlFrame:Show() for _, b in ipairs(self.buttons) do b:BarUnlocked() b:DisplayVisibility() end self:ApplyVisibility() end function ReBar.prototype:HideControls() self.locked = true local b = self.barFrame if b.isMoving or b.resizing then b:StopMovingOrSizing() b:SetScript("OnUpdate",nil) end for _, b in ipairs(self.buttons) do b:BarLocked() b:DisplayVisibility() end self.controlFrame:Hide() self:ApplyVisibility() end function ReBar.prototype:GetControlFrame() return self.controlFrame end -- accessors function ReBar.prototype:GetVisibility() return self.config.visible end function ReBar.prototype:ToggleVisibility() self:SetVisibility( not self:GetVisibility() ) end function ReBar.prototype:SetVisibility(v) self.config.visible = v and true or false -- force data integrity self:ApplyVisibility() end function ReBar.prototype:GetOpacity() return tonumber(self.config.opacity) or 100 end function ReBar.prototype:SetOpacity( o ) o = tonumber(o) if o then self.config.opacity = o self:ApplyVisibility() return self.config.opacity end end function ReBar.prototype:GetButtonList() return self.buttons end function ReBar.prototype:GetGrowLeft() return self.config.growLeft end function ReBar.prototype:SetGrowLeft(g) self.config.growLeft = g and true or false self:LayoutButtons() end function ReBar.prototype:GetGrowUp() return self.config.growUp end function ReBar.prototype:SetGrowUp(g) self.config.growUp = g and true or false self:LayoutButtons() end function ReBar.prototype:GetColumnMajor() return self.config.columnMajor end function ReBar.prototype:SetColumnMajor(m) self.config.columnMajor = m and true or false self:LayoutButtons() end -- paging methods function ReBar.prototype:IsPagingDisabled() return not (self.config.pages and self.config.pages.n > 1) end function ReBar.prototype:GetPages() return self.config.pages and self.config.pages.n or 1 end function ReBar.prototype:SetPages(n) n = tonumber(n) if n and n >= 1 then self.config.pages = self.config.pages or { } self.config.pages.n = n for _, btn in pairs(self.buttons) do btn:SetPages(n) end if n > 1 then local statebutton = "0:page1;" -- map states 1-n to 'page1'-'pagen' -- page 0 is the same as page 1. for i = 1, n do statebutton = statebutton..i..":page"..i..";" end self.barFrame:SetAttribute("statebutton",statebutton) else self.barFrame:SetAttribute("statebutton",ATTRIBUTE_NOOP) end self.barFrame:SetAttribute("statemap-anchor-next","1-"..n) self.barFrame:SetAttribute("statemap-anchor-prev",tostring(n).."-1") self:RefreshPageControls() end end function ReBar.prototype:GetAutoStanceSwitch() return self.config.pages and self.config.pages.autoStanceSwitch end function ReBar.prototype:SetAutoStanceSwitch( s ) if not self.config.pages then self.config.pages = { n = 1 } end self.config.pages.autoStanceSwitch = s and true or false self:ApplyAutoStanceSwitch() end function ReBar.prototype:ToggleAutoStanceSwitch() self:SetAutoStanceSwitch( not self:GetAutoStanceSwitch() ) end function ReBar.prototype:ApplyAutoStanceSwitch() local switch = self:GetAutoStanceSwitch() local _, class = UnitClass("player") if switch then -- check that the number of pages available is sufficient local totalPages = nStancePages[class] + (self:GetAutoStealthSwitch() and 1 or 0) if self:GetPages() < totalPages then self:SetPages(totalPages) end for form, spec in pairs(stanceMaps[class]) do self.barFrame:SetAttribute("statemap-stance-"..form,spec) end -- set initial value self.barFrame:SetAttribute("state-stance",GetShapeshiftForm(true)) else for form, _ in pairs(stanceMaps[class]) do self.barFrame:SetAttribute("statemap-stance-"..form, ATTRIBUTE_NOOP) end end end function ReBar.prototype:GetAutoStealthSwitch() return self.config.pages and self.config.pages.autoStealthSwitch end function ReBar.prototype:SetAutoStealthSwitch( s ) if not self.config.pages then self.config.pages = { n = 1 } end self.config.pages.autoStealthSwitch = s and true or false self:ApplyAutoStealthSwitch() end function ReBar.prototype:ToggleAutoStealthSwitch() self:SetAutoStealthSwitch( not self:GetAutoStealthSwitch() ) end function ReBar.prototype:ApplyAutoStealthSwitch() local switch = self:GetAutoStealthSwitch() local _, class = UnitClass("player") if switch then -- check that the number of pages available is sufficient local totalPages = (self:GetAutoStanceSwitch() and nStancePages[class] > 0 and nStancePages[class] or 1) + 1 if self:GetPages() < totalPages then self:SetPages(totalPages) end local s, s2 if class == "DRUID" and not self:GetAutoStanceSwitch() then -- change mapping for cat->prowl and prowl->cat to 1:2 and 2:1 since no stance mapping s = "1:2" s2 = "2:1" end self.barFrame:SetAttribute("statemap-stealth-1",s or stealthMaps[class]) self.barFrame:SetAttribute("statemap-stealth-0",s2 or unstealthMaps[class]) -- set initial value self.barFrame:SetAttribute("state-stealth",IsStealthed() or 0) else self.barFrame:SetAttribute("statemap-stealth-1",ATTRIBUTE_NOOP) self.barFrame:SetAttribute("statemap-stealth-0",ATTRIBUTE_NOOP) end end function ReBar.prototype:ArePageControlsHidden() return not ( self.config.pages and self.config.pages.showControls ) end function ReBar.prototype:TogglePageControlsHidden() if self.config.pages then self.config.pages.showControls = not self.config.pages.showControls self:RefreshPageControls() end end function ReBar.prototype:GetPageControlsLoc() return self.config.pages and self.config.pages.controlsLoc end function ReBar.prototype:SetPageControlsLoc(loc) if self.config.pages then self.config.pages.controlsLoc = loc self:RefreshPageControls() end end function ReBar.prototype:RefreshPageControls() local b = self.barFrame; local upArrow = getglobal(b:GetName().."PageUp") local downArrow = getglobal(b:GetName().."PageDown") local pageNum = getglobal(b:GetName().."PageNumber") if self:GetPages() > 1 and self.config.pages.showControls then local loc = self.config.pages.controlsLoc pageNum:ClearAllPoints() upArrow:ClearAllPoints() downArrow:ClearAllPoints() local vertical = { 0,0,0,1,1,0,1,1 } local horizontal = { 0,1,1,1,0,0,1,0 } local textures = { upArrow:GetNormalTexture(), upArrow:GetPushedTexture(), upArrow:GetDisabledTexture(), upArrow:GetHighlightTexture(), downArrow:GetNormalTexture(), downArrow:GetPushedTexture(), downArrow:GetDisabledTexture(), downArrow:GetHighlightTexture(), } local offset = 10 local mult = (loc == "RIGHT" or loc == "TOP") and 1 or -1 local pageNumOffset = mult * (self.config.spacing/2 - offset) local arrowOffset = mult * offset if loc == "Blizzard" or loc == nil then pageNum:SetPoint("LEFT", b, "RIGHT", 28, 0) upArrow:SetPoint("LEFT", b, "RIGHT", -2, 9) downArrow:SetPoint("LEFT", b, "RIGHT", -2, -10) for _, tex in ipairs(textures) do tex:SetTexCoord(unpack(vertical)) end elseif loc == "RIGHT" or loc == "LEFT" then local relPoint = loc == "RIGHT" and "LEFT" or "RIGHT" pageNum:SetPoint(relPoint, b, loc, pageNumOffset, 0) upArrow:SetPoint("BOTTOM",pageNum,"TOP",arrowOffset, -12) downArrow:SetPoint("TOP",pageNum,"BOTTOM",arrowOffset, 12) for _, tex in ipairs(textures) do tex:SetTexCoord(unpack(vertical)) end else pageNum:SetPoint(loc == "BOTTOM" and "TOP" or "BOTTOM", b, loc, 0, pageNumOffset) upArrow:SetPoint("LEFT",pageNum,"RIGHT",-12,arrowOffset) downArrow:SetPoint("RIGHT",pageNum,"LEFT",12,arrowOffset) for _, tex in ipairs(textures) do tex:SetTexCoord(unpack(horizontal)) end end self:StateChanged() upArrow:Show() downArrow:Show() pageNum:Show() else upArrow:Hide() downArrow:Hide() pageNum:Hide() end end function ReBar.prototype:StateChanged() local page = self.barFrame:GetAttribute("state") or 1 getglobal(self.barFrame:GetName().."PageNumberLabelText"):SetText(page) if self.config.pages then self.config.pages.currentPage = page end end -- layout methods function ReBar.prototype:ApplySize() local buttonSz = self.config.size or 36 local spacing = self.config.spacing or 4 local rows = self.config.rows or 1 local columns = self.config.columns or 12 local w = buttonSz * columns + spacing * columns local h = buttonSz * rows + spacing * rows local f = self.barFrame -- + 0.1: avoid issues with UI scaling f:SetMinResize(buttonSz + spacing + 0.1, buttonSz + spacing + 0.1) f:SetWidth(w + 0.1) f:SetHeight(h + 0.1) end function ReBar.prototype:ApplyAnchor() local a = self.config.anchor local f = self.barFrame if a then f:ClearAllPoints() f:SetPoint(a.point,getglobal(a.frame),a.relPoint,a.x,a.y) local color = anchoredLabelColor if a.frame == "UIParent" or a.frame == "WorldFrame" then color = nonAnchoredLabelColor end self.labelString:SetTextColor(color.r, color.g, color.b) end end function ReBar.prototype:ApplyVisibility() local v = self.config.visible or not self.locked if tonumber(self.config.opacity) then self.barFrame:SetAlpha(self.config.opacity / 100) end if v then self.barFrame:Show() else self.barFrame:Hide() end end function ReBar.prototype:LayoutButtons() local r = self.config.rows local c = self.config.columns local sp = self.config.spacing local sz = self.config.size local gSize = sp + sz local point = (self.config.growUp and "BOTTOM" or "TOP")..(self.config.growLeft and "RIGHT" or "LEFT") local major = self.config.columnMajor and r or c for i, b in ipairs(self.buttons) do local x = sp/2 + gSize * math.fmod(i-1,major) local y = sp/2 + gSize * math.floor((i-1)/major) if self.config.columnMajor then x,y = y,x end if self.config.growLeft then x = -x end if not self.config.growUp then y = -y end b:PlaceButton(self.barFrame, point, x, y, sz) end end function ReBar.prototype:FlipRowsColumns() self.config.rows, self.config.columns = self.config.columns, self.config.rows self.config.columnMajor = not self.config.columnMajor self:ApplySize() self:LayoutButtons() end function ReBar.prototype:AcquireButtons() local n = self.config.rows * self.config.columns for i = 1, n do if self.buttons[i] == nil then local b = self.buttonClass:Acquire(self.config.btnConfig, i, self.config.pages and self.config.pages.n, n) if b then if not AceOO.inherits(b, ReBar.IButton) then error("ReBar: specified Button class object did not meet required interface") end if self.locked == false then b:BarUnlocked() -- buttons assume they are created in a barlocked state end self.buttons[i] = b self.barFrame:SetAttribute("addchild",b:GetActionFrame()) end end end local maxn = table.maxn(self.buttons) for i = n+1, table.maxn(self.buttons) do local b = self.buttons[i] self.buttons[i] = nil if b then self.buttonClass:Release(b) end end end function ReBar.prototype:StoreAnchor(f, p, rp, x, y) local name = f:GetName() -- no point if we can't store the name or the offsets are incomplete if name and x and y then self.config.anchor = { frame = name, point = p, relPoint = rp or p, x = x, y = y } end end function ReBar.prototype:StickyIndicatorUpdate() if IsShiftKeyDown() then local snapRange = self.config.size + self.config.spacing self:DisplaySnapIndicator(ReBar.anchorTargets, snapRange, 0, 0) else self:HideSnapIndicator() end end -- mouse event handlers (clicking/dragging/resizing the bar) function ReBar.prototype:BeginDrag() local f = self.barFrame f:StartMoving() f.isMoving = true self.updateTime = DRAG_UPDATE_RATE f:SetScript("OnUpdate", function(frame, elapsed) self:StickyIndicatorUpdate(elapsed) end) end function ReBar.prototype:FinishDrag() local o, p, rp, x, y local bf = self.barFrame local snapRange = self.config.size + self.config.spacing bf:StopMovingOrSizing() bf.isMoving = false bf:SetScript("OnUpdate",nil) if IsShiftKeyDown() then o, p, rp, x, y = self:GetClosestPointSnapped(ReBar.anchorTargets, snapRange, 0, 0) end if o == nil then o, p, rp, x, y = self:GetClosestVisiblePoint(ReBar.UIParentAnchorTarget, snapRange, 0, 0) end self:HideSnapIndicator() self:StoreAnchor(o:GetFrame(), p, rp, x, y) self:ApplyAnchor() end function ReBar.prototype:BeginBarResize( sizingPoint ) local f = self.barFrame f:StartSizing(sizingPoint) f.resizing = true self.updateTime = DRAG_UPDATE_RATE f:SetScript("OnUpdate",function(frame, elapsed) self:ReflowButtons(elapsed) end) end function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn ) local f = self.barFrame f:StartSizing(sizingPoint) f.resizing = true local r = self.config.rows local c = self.config.columns local s = self.config.spacing local sz = self.config.size self.updateTime = DRAG_UPDATE_RATE if mouseBtn == "LeftButton" then f:SetMinResize(c*(12 + s) +0.1, r*(12 + s) +0.1) f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeButtons(elapsed) end) elseif mouseBtn == "RightButton" then f:SetMinResize(c*sz+0.1, r*sz+0.1) f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeSpacing(elapsed) end) end end function ReBar.prototype:FinishResize() local f = self.barFrame f:StopMovingOrSizing() f.resizing = false f:SetScript("OnUpdate",nil) self:ApplySize() end -- utility function to get the height, width, and button size attributes function ReBar.prototype:GetLayout() local c = self.config local f = self.barFrame return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing end -- add and remove buttons dynamically as the bar is resized function ReBar.prototype:ReflowButtons( elapsed ) self.updateTime = self.updateTime - elapsed if self.updateTime <= 0 then self.updateTime = DRAG_UPDATE_RATE local w, h, sz, r, c, sp = self:GetLayout() self.config.rows = math.floor( (h+1) / (sz + sp) ) self.config.columns = math.floor( (w+1) / (sz + sp) ) if self.config.rows ~= r or self.config.columns ~= c then self:AcquireButtons() self:LayoutButtons() end end end -- change the size of buttons as the bar is resized function ReBar.prototype:DragSizeButtons( elapsed ) self.updateTime = self.updateTime - elapsed if self.updateTime <= 0 then self.updateTime = DRAG_UPDATE_RATE local w, h, sz, r, c, sp = self:GetLayout() local newSzW = math.floor((w - c*sp)/c) local newSzH = math.floor((h - r*sp)/r) self.config.size = math.max(12, math.min(newSzW, newSzH)) if self.config.size ~= sz then self:LayoutButtons() self:UpdateResizeTooltip() end end end -- change the spacing of buttons as the bar is resized function ReBar.prototype:DragSizeSpacing( elapsed ) self.updateTime = self.updateTime - elapsed if self.updateTime <= 0 then self.updateTime = DRAG_UPDATE_RATE local w, h, sz, r, c, sp = self:GetLayout() local newSpW = math.floor((w - c*sz)/c) local newSpH = math.floor((h - r*sz)/r) self.config.spacing = math.max(0, math.min(newSpW, newSpH)) if self.config.spacing ~= sp then self:LayoutButtons() self:UpdateResizeTooltip() end end end -- update the drag tooltip to indicate current sizes function ReBar.prototype:UpdateResizeTooltip() GameTooltipTextRight4:SetText(self.config.size) GameTooltipTextRight5:SetText(self.config.spacing) GameTooltip:Show() end function ReBar.prototype:ShowTooltip() GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT") GameTooltip:AddLine(self.config.btnConfig.subtype.." Bar "..self.barID..(self.config.visible and "" or " (Hidden)")) GameTooltip:AddLine("Drag to move") GameTooltip:AddLine("Shift-drag for sticky mode") GameTooltip:AddLine("Right-click for options") GameTooltip:Show() end function ReBar.prototype:ShowButtonResizeTooltip(point) GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) GameTooltip:AddLine("Drag to resize buttons") GameTooltip:AddLine("Right-click-drag") GameTooltip:AddLine("to change spacing") GameTooltip:AddDoubleLine("Size: ", "0") GameTooltip:AddDoubleLine("Spacing: ", "0") self:UpdateResizeTooltip() end function ReBar.prototype:ShowBarResizeTooltip(point) GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) GameTooltip:AddLine("Drag to add/remove buttons") GameTooltip:Show() end