---------------------------------------------------------------------- -- L00: Leatrix Plus Library ---------------------------------------------------------------------- -- LibDBIcon 10.0.1 -- 11: LibStub: (?s)-- LibStubStart\R?\K.*?(?=-- LibStubEnd) -- 12: CallbackHandler-1.0: (?s)-- CallbackStart\R?\K.*?(?=-- CallbackEnd) -- 13: LibDataBroker-1.1: (?s)-- DataBrokerStart\R?\K.*?(?=-- DataBrokerEnd) -- 14: LibDBIcon-1.0 10.0.1: (?s)-- LibDBIconStart\R?\K.*?(?=-- LibDBIconEnd) -- LibChatAnims 10.0.1 -- 15: LibChatAnims: (?s)-- LibChatAnimsStart\R?\K.*?(?=-- LibChatAnimsEnd) local void, Leatrix_Plus = ... ---------------------------------------------------------------------- -- L11: LibDBIcon: LibStub ---------------------------------------------------------------------- local function LeaLibStub() -- LibStubStart -- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! local LibStub = _G[LIBSTUB_MAJOR] -- Check to see is this version of the stub is obsolete if not LibStub or LibStub.minor < LIBSTUB_MINOR then LibStub = LibStub or {libs = {}, minors = {} } _G[LIBSTUB_MAJOR] = LibStub LibStub.minor = LIBSTUB_MINOR -- LibStub:NewLibrary(major, minor) -- major (string) - the major version of the library -- minor (string or number ) - the minor version of the library -- -- returns nil if a newer or same version of the lib is already present -- returns empty library object or old library object if upgrade is needed function LibStub:NewLibrary(major, minor) assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") local oldminor = self.minors[major] if oldminor and oldminor >= minor then return nil end self.minors[major], self.libs[major] = minor, self.libs[major] or {} return self.libs[major], oldminor end -- LibStub:GetLibrary(major, [silent]) -- major (string) - the major version of the library -- silent (boolean) - if true, library is optional, silently return nil if its not found -- -- throws an error if the library can not be found (except silent is set) -- returns the library object if found function LibStub:GetLibrary(major, silent) if not self.libs[major] and not silent then error(("Cannot find a library instance of %q."):format(tostring(major)), 2) end return self.libs[major], self.minors[major] end -- LibStub:IterateLibraries() -- -- Returns an iterator for the currently registered libraries function LibStub:IterateLibraries() return pairs(self.libs) end setmetatable(LibStub, { __call = LibStub.GetLibrary }) end -- LibStubEnd end LeaLibStub() ---------------------------------------------------------------------- -- L12: LibDBIcon: CallbackHandler ---------------------------------------------------------------------- local function LeaCallbackHandler() -- CallbackStart --[[ $Id: CallbackHandler-1.0.lua 26 2022-12-12 15:09:39Z nevcairiel $ ]] local MAJOR, MINOR = "CallbackHandler-1.0", 8 local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) if not CallbackHandler then return end -- No upgrade needed local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} -- Lua APIs local securecallfunction, error = securecallfunction, error local setmetatable, rawget = setmetatable, rawget local next, select, pairs, type, tostring = next, select, pairs, type, tostring local function Dispatch(handlers, ...) local index, method = next(handlers) if not method then return end repeat securecallfunction(method, ...) index, method = next(handlers, index) until not method end -------------------------------------------------------------------------- -- CallbackHandler:New -- -- target - target object to embed public APIs in -- RegisterName - name of the callback registration API, default "RegisterCallback" -- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" -- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName) RegisterName = RegisterName or "RegisterCallback" UnregisterName = UnregisterName or "UnregisterCallback" if UnregisterAllName==nil then -- false is used to indicate "don't want this method" UnregisterAllName = "UnregisterAllCallbacks" end -- we declare all objects and exported APIs inside this closure to quickly gain access -- to e.g. function names, the "target" parameter, etc -- Create the registry object local events = setmetatable({}, meta) local registry = { recurse=0, events=events } -- registry:Fire() - fires the given event/message into the registry function registry:Fire(eventname, ...) if not rawget(events, eventname) or not next(events[eventname]) then return end local oldrecurse = registry.recurse registry.recurse = oldrecurse + 1 Dispatch(events[eventname], eventname, ...) registry.recurse = oldrecurse if registry.insertQueue and oldrecurse==0 then -- Something in one of our callbacks wanted to register more callbacks; they got queued for event,callbacks in pairs(registry.insertQueue) do local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten. for object,func in pairs(callbacks) do events[event][object] = func -- fire OnUsed callback? if first and registry.OnUsed then registry.OnUsed(registry, target, event) first = nil end end end registry.insertQueue = nil end end -- Registration of a callback, handles: -- self["method"], leads to self["method"](self, ...) -- self with function ref, leads to functionref(...) -- "addonId" (instead of self) with function ref, leads to functionref(...) -- all with an optional arg, which, if present, gets passed as first argument (after self if present) target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) if type(eventname) ~= "string" then error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) end method = method or eventname local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. if type(method) ~= "string" and type(method) ~= "function" then error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) end local regfunc if type(method) == "string" then -- self["method"] calling style if type(self) ~= "table" then error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) elseif self==target then error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) elseif type(self[method]) ~= "function" then error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) end if select("#",...)>=1 then -- this is not the same as testing for arg==nil! local arg=select(1,...) regfunc = function(...) self[method](self,arg,...) end else regfunc = function(...) self[method](self,...) end end else -- function ref with self=object or self="addonId" or self=thread if type(self)~="table" and type(self)~="string" and type(self)~="thread" then error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) end if select("#",...)>=1 then -- this is not the same as testing for arg==nil! local arg=select(1,...) regfunc = function(...) method(arg,...) end else regfunc = method end end if events[eventname][self] or registry.recurse<1 then -- if registry.recurse<1 then -- we're overwriting an existing entry, or not currently recursing. just set it. events[eventname][self] = regfunc -- fire OnUsed callback? if registry.OnUsed and first then registry.OnUsed(registry, target, eventname) end else -- we're currently processing a callback in this registry, so delay the registration of this new entry! -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency registry.insertQueue = registry.insertQueue or setmetatable({},meta) registry.insertQueue[eventname][self] = regfunc end end -- Unregister a callback target[UnregisterName] = function(self, eventname) if not self or self==target then error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) end if type(eventname) ~= "string" then error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) end if rawget(events, eventname) and events[eventname][self] then events[eventname][self] = nil -- Fire OnUnused callback? if registry.OnUnused and not next(events[eventname]) then registry.OnUnused(registry, target, eventname) end end if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then registry.insertQueue[eventname][self] = nil end end -- OPTIONAL: Unregister all callbacks for given selfs/addonIds if UnregisterAllName then target[UnregisterAllName] = function(...) if select("#",...)<1 then error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) end if select("#",...)==1 and ...==target then error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) end for i=1,select("#",...) do local self = select(i,...) if registry.insertQueue then for eventname, callbacks in pairs(registry.insertQueue) do if callbacks[self] then callbacks[self] = nil end end end for eventname, callbacks in pairs(events) do if callbacks[self] then callbacks[self] = nil -- Fire OnUnused callback? if registry.OnUnused and not next(callbacks) then registry.OnUnused(registry, target, eventname) end end end end end end return registry end -- CallbackHandler purposefully does NOT do explicit embedding. Nor does it -- try to upgrade old implicit embeds since the system is selfcontained and -- relies on closures to work. -- CallbackEnd end LeaCallbackHandler() ---------------------------------------------------------------------- -- L13: LibDBIcon: LibDataBroker ---------------------------------------------------------------------- local function LeaDataBroker() -- DataBrokerStart assert(LibStub, "LibDataBroker-1.1 requires LibStub") assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0") local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4) if not lib then return end oldminor = oldminor or 0 lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib) lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {} local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks if oldminor < 2 then lib.domt = { __metatable = "access denied", __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end, } end if oldminor < 3 then lib.domt.__newindex = function(self, key, value) if not attributestorage[self] then attributestorage[self] = {} end if attributestorage[self][key] == value then return end attributestorage[self][key] = value local name = namestorage[self] if not name then return end callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self) callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self) callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self) callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self) end end if oldminor < 2 then function lib:NewDataObject(name, dataobj) if self.proxystorage[name] then return end if dataobj then assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table") self.attributestorage[dataobj] = {} for i,v in pairs(dataobj) do self.attributestorage[dataobj][i] = v dataobj[i] = nil end end dataobj = setmetatable(dataobj or {}, self.domt) self.proxystorage[name], self.namestorage[dataobj] = dataobj, name self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj) return dataobj end end if oldminor < 1 then function lib:DataObjectIterator() return pairs(self.proxystorage) end function lib:GetDataObjectByName(dataobjectname) return self.proxystorage[dataobjectname] end function lib:GetNameByDataObject(dataobject) return self.namestorage[dataobject] end end if oldminor < 4 then local next = pairs(attributestorage) function lib:pairs(dataobject_or_name) local t = type(dataobject_or_name) assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name assert(attributestorage[dataobj], "Data object not found") return next, attributestorage[dataobj], nil end local ipairs_iter = ipairs(attributestorage) function lib:ipairs(dataobject_or_name) local t = type(dataobject_or_name) assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name assert(attributestorage[dataobj], "Data object not found") return ipairs_iter, attributestorage[dataobj], 0 end end -- DataBrokerEnd end LeaDataBroker() ---------------------------------------------------------------------- -- L14: LibDBIcon: LibDBIcon ---------------------------------------------------------------------- local function LeaLibDBIcon() -- LibDBIconStart --@curseforge-project-slug: libdbicon-1-0@ ----------------------------------------------------------------------- -- LibDBIcon-1.0 -- -- Allows addons to easily create a lightweight minimap icon as an alternative to heavier LDB displays. -- local DBICON10 = "LibDBIcon-1.0" local DBICON10_MINOR = 51 -- Bump on changes if not LibStub then error(DBICON10 .. " requires LibStub.") end local ldb = LibStub("LibDataBroker-1.1", true) if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR) if not lib then return end lib.objects = lib.objects or {} lib.callbackRegistered = lib.callbackRegistered or nil lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) lib.radius = lib.radius or 5 local next, Minimap, CreateFrame, AddonCompartmentFrame = next, Minimap, CreateFrame, AddonCompartmentFrame lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate") local isDraggingButton = false function lib:IconCallback(event, name, key, value) if lib.objects[name] then if key == "icon" then lib.objects[name].icon:SetTexture(value) elseif key == "iconCoords" then lib.objects[name].icon:UpdateCoord() elseif key == "iconR" then local _, g, b = lib.objects[name].icon:GetVertexColor() lib.objects[name].icon:SetVertexColor(value, g, b) elseif key == "iconG" then local r, _, b = lib.objects[name].icon:GetVertexColor() lib.objects[name].icon:SetVertexColor(r, value, b) elseif key == "iconB" then local r, g = lib.objects[name].icon:GetVertexColor() lib.objects[name].icon:SetVertexColor(r, g, value) end end end if not lib.callbackRegistered then ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback") ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconCoords", "IconCallback") ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconR", "IconCallback") ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconG", "IconCallback") ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconB", "IconCallback") lib.callbackRegistered = true end local function getAnchors(frame) local x, y = frame:GetCenter() if not x or not y then return "CENTER" end local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or "" local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM" return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf end local function onEnter(self) if isDraggingButton then return end for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Stop() button:SetAlpha(1) end end local obj = self.dataObject if obj.OnTooltipShow then lib.tooltip:SetOwner(self, "ANCHOR_NONE") lib.tooltip:SetPoint(getAnchors(self)) obj.OnTooltipShow(lib.tooltip) lib.tooltip:Show() elseif obj.OnEnter then obj.OnEnter(self) end end local function onLeave(self) lib.tooltip:Hide() if not isDraggingButton then for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Play() end end end local obj = self.dataObject if obj.OnLeave then obj.OnLeave(self) end end local function onEnterCompartment(self) local buttonName = self.value local object = lib.objects[buttonName] if object and object.dataObject then if object.dataObject.OnTooltipShow then lib.tooltip:SetOwner(self, "ANCHOR_NONE") lib.tooltip:SetPoint(getAnchors(self)) object.dataObject.OnTooltipShow(lib.tooltip) lib.tooltip:Show() elseif object.dataObject.OnEnter then object.dataObject.OnEnter(self) end end end local function onLeaveCompartment(self) lib.tooltip:Hide() local buttonName = self.value local object = lib.objects[buttonName] if object and object.dataObject then if object.dataObject.OnLeave then object.dataObject.OnLeave(self) end end end -------------------------------------------------------------------------------- local onDragStart, updatePosition do local minimapShapes = { ["ROUND"] = {true, true, true, true}, ["SQUARE"] = {false, false, false, false}, ["CORNER-TOPLEFT"] = {false, false, false, true}, ["CORNER-TOPRIGHT"] = {false, false, true, false}, ["CORNER-BOTTOMLEFT"] = {false, true, false, false}, ["CORNER-BOTTOMRIGHT"] = {true, false, false, false}, ["SIDE-LEFT"] = {false, true, false, true}, ["SIDE-RIGHT"] = {true, false, true, false}, ["SIDE-TOP"] = {false, false, true, true}, ["SIDE-BOTTOM"] = {true, true, false, false}, ["TRICORNER-TOPLEFT"] = {false, true, true, true}, ["TRICORNER-TOPRIGHT"] = {true, false, true, true}, ["TRICORNER-BOTTOMLEFT"] = {true, true, false, true}, ["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false}, } local rad, cos, sin, sqrt, max, min = math.rad, math.cos, math.sin, math.sqrt, math.max, math.min function updatePosition(button, position) local angle = rad(position or 225) local x, y, q = cos(angle), sin(angle), 1 if x < 0 then q = q + 1 end if y > 0 then q = q + 2 end local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND" local quadTable = minimapShapes[minimapShape] local w = (Minimap:GetWidth() / 2) + lib.radius local h = (Minimap:GetHeight() / 2) + lib.radius if quadTable[q] then x, y = x*w, y*h else local diagRadiusW = sqrt(2*(w)^2)-10 local diagRadiusH = sqrt(2*(h)^2)-10 x = max(-w, min(x*diagRadiusW, w)) y = max(-h, min(y*diagRadiusH, h)) end button:SetPoint("CENTER", Minimap, "CENTER", x, y) end end local function onClick(self, b) if self.dataObject.OnClick then self.dataObject.OnClick(self, b) end end local function onMouseDown(self) self.isMouseDown = true self.icon:UpdateCoord() end local function onMouseUp(self) self.isMouseDown = false self.icon:UpdateCoord() end do local deg, atan2 = math.deg, math.atan2 local function onUpdate(self) local mx, my = Minimap:GetCenter() local px, py = GetCursorPosition() local scale = Minimap:GetEffectiveScale() px, py = px / scale, py / scale local pos = 225 if self.db then pos = deg(atan2(py - my, px - mx)) % 360 self.db.minimapPos = pos else pos = deg(atan2(py - my, px - mx)) % 360 self.minimapPos = pos end updatePosition(self, pos) end function onDragStart(self) self:LockHighlight() self.isMouseDown = true self.icon:UpdateCoord() self:SetScript("OnUpdate", onUpdate) isDraggingButton = true lib.tooltip:Hide() for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Stop() button:SetAlpha(1) end end end end local function onDragStop(self) self:SetScript("OnUpdate", nil) self.isMouseDown = false self.icon:UpdateCoord() self:UnlockHighlight() isDraggingButton = false for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Play() end end end local defaultCoords = {0, 1, 0, 1} local function updateCoord(self) local coords = self:GetParent().dataObject.iconCoords or defaultCoords local deltaX, deltaY = 0, 0 if not self:GetParent().isMouseDown then deltaX = (coords[2] - coords[1]) * 0.05 deltaY = (coords[4] - coords[3]) * 0.05 end self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY) end local function createButton(name, object, db, customCompartmentIcon) local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap) button.dataObject = object button.db = db button:SetFrameStrata("MEDIUM") button:SetFixedFrameStrata(true) button:SetFrameLevel(8) button:SetFixedFrameLevel(true) button:SetSize(31, 31) button:RegisterForClicks("anyUp") button:RegisterForDrag("LeftButton") button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight" if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then local overlay = button:CreateTexture(nil, "OVERLAY") overlay:SetSize(50, 50) overlay:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder" overlay:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0) local background = button:CreateTexture(nil, "BACKGROUND") background:SetSize(24, 24) background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background" background:SetPoint("CENTER", button, "CENTER", 0, 1) local icon = button:CreateTexture(nil, "ARTWORK") icon:SetSize(18, 18) icon:SetTexture(object.icon) icon:SetPoint("CENTER", button, "CENTER", 0, 1) button.icon = icon else local overlay = button:CreateTexture(nil, "OVERLAY") overlay:SetSize(53, 53) overlay:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder" overlay:SetPoint("TOPLEFT") local background = button:CreateTexture(nil, "BACKGROUND") background:SetSize(20, 20) background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background" background:SetPoint("TOPLEFT", 7, -5) local icon = button:CreateTexture(nil, "ARTWORK") icon:SetSize(17, 17) icon:SetTexture(object.icon) icon:SetPoint("TOPLEFT", 7, -6) button.icon = icon end button.isMouseDown = false local r, g, b = button.icon:GetVertexColor() button.icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b) button.icon.UpdateCoord = updateCoord button.icon:UpdateCoord() button:SetScript("OnEnter", onEnter) button:SetScript("OnLeave", onLeave) button:SetScript("OnClick", onClick) if not db or not db.lock then button:SetScript("OnDragStart", onDragStart) button:SetScript("OnDragStop", onDragStop) end button:SetScript("OnMouseDown", onMouseDown) button:SetScript("OnMouseUp", onMouseUp) button.fadeOut = button:CreateAnimationGroup() local animOut = button.fadeOut:CreateAnimation("Alpha") animOut:SetOrder(1) animOut:SetDuration(0.2) animOut:SetFromAlpha(1) animOut:SetToAlpha(0) animOut:SetStartDelay(1) button.fadeOut:SetToFinalAlpha(true) lib.objects[name] = button if lib.loggedIn then updatePosition(button, db and db.minimapPos) if not db or not db.hide then button:Show() else button:Hide() end end if db and db.showInCompartment then lib:AddButtonToCompartment(name, customCompartmentIcon) end lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback end -- Wait a bit with the initial positioning to let any GetMinimapShape addons -- load up. if not lib.loggedIn then local frame = CreateFrame("Frame") frame:SetScript("OnEvent", function(self) for _, button in next, lib.objects do updatePosition(button, button.db and button.db.minimapPos) if not button.db or not button.db.hide then button:Show() else button:Hide() end end lib.loggedIn = true self:SetScript("OnEvent", nil) end) frame:RegisterEvent("PLAYER_LOGIN") end do local function OnMinimapEnter() if isDraggingButton then return end for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Stop() button:SetAlpha(1) end end end local function OnMinimapLeave() if isDraggingButton then return end for _, button in next, lib.objects do if button.showOnMouseover then button.fadeOut:Play() end end end Minimap:HookScript("OnEnter", OnMinimapEnter) Minimap:HookScript("OnLeave", OnMinimapLeave) end -------------------------------------------------------------------------------- -- Button API -- function lib:Register(name, object, db, customCompartmentIcon) if not object.icon then error("Can't register LDB objects without icons set!") end if lib:GetMinimapButton(name) then error(DBICON10.. ": Object '".. name .."' is already registered.") end createButton(name, object, db, customCompartmentIcon) end function lib:Lock(name) local button = lib:GetMinimapButton(name) if button then button:SetScript("OnDragStart", nil) button:SetScript("OnDragStop", nil) if button.db then button.db.lock = true end end end function lib:Unlock(name) local button = lib:GetMinimapButton(name) if button then button:SetScript("OnDragStart", onDragStart) button:SetScript("OnDragStop", onDragStop) if button.db then button.db.lock = nil end end end function lib:Hide(name) local button = lib:GetMinimapButton(name) if button then button:Hide() end end function lib:Show(name) local button = lib:GetMinimapButton(name) if button then button:Show() updatePosition(button, button.db and button.db.minimapPos or button.minimapPos) end end function lib:IsRegistered(name) return lib.objects[name] and true or false end function lib:Refresh(name, db) local button = lib:GetMinimapButton(name) if button then if db then button.db = db end updatePosition(button, button.db and button.db.minimapPos or button.minimapPos) if not button.db or not button.db.hide then button:Show() else button:Hide() end if not button.db or not button.db.lock then button:SetScript("OnDragStart", onDragStart) button:SetScript("OnDragStop", onDragStop) else button:SetScript("OnDragStart", nil) button:SetScript("OnDragStop", nil) end end end function lib:ShowOnEnter(name, value) local button = lib:GetMinimapButton(name) if button then if value then button.showOnMouseover = true button.fadeOut:Stop() button:SetAlpha(0) else button.showOnMouseover = false button.fadeOut:Stop() button:SetAlpha(1) end end end function lib:GetMinimapButton(name) return lib.objects[name] end function lib:GetButtonList() local t = {} for name in next, lib.objects do t[#t+1] = name end return t end function lib:SetButtonRadius(radius) if type(radius) == "number" then lib.radius = radius for _, button in next, lib.objects do updatePosition(button, button.db and button.db.minimapPos or button.minimapPos) end end end function lib:SetButtonToPosition(button, position) updatePosition(lib.objects[button] or button, position) end -------------------------------------------------------------------------------- -- Addon Compartment API -- function lib:IsButtonCompartmentAvailable() if AddonCompartmentFrame then return true end end function lib:IsButtonInCompartment(buttonName) local object = lib.objects[buttonName] if object and object.db and object.db.showInCompartment then return true end return false end function lib:AddButtonToCompartment(buttonName, customIcon) local object = lib.objects[buttonName] if object and not object.compartmentData and AddonCompartmentFrame then if object.db then object.db.showInCompartment = true end object.compartmentData = { text = buttonName, icon = customIcon or object.dataObject.icon, notCheckable = true, registerForAnyClick = true, func = function(frame, _, _, _, clickType) object.dataObject.OnClick(frame, clickType) end, funcOnEnter = onEnterCompartment, funcOnLeave = onLeaveCompartment, } AddonCompartmentFrame:RegisterAddon(object.compartmentData) end end function lib:RemoveButtonFromCompartment(buttonName) local object = lib.objects[buttonName] if object and object.compartmentData then for i = 1, #AddonCompartmentFrame.registeredAddons do local entry = AddonCompartmentFrame.registeredAddons[i] if entry == object.compartmentData then object.compartmentData = nil if object.db then object.db.showInCompartment = nil end table.remove(AddonCompartmentFrame.registeredAddons, i) AddonCompartmentFrame:UpdateDisplay() return end end end end -------------------------------------------------------------------------------- -- Upgrades -- for name, button in next, lib.objects do local db = button.db if not db or not db.lock then button:SetScript("OnDragStart", onDragStart) button:SetScript("OnDragStop", onDragStop) end button:SetScript("OnEnter", onEnter) button:SetScript("OnLeave", onLeave) button:SetScript("OnClick", onClick) button:SetScript("OnMouseDown", onMouseDown) button:SetScript("OnMouseUp", onMouseUp) if not button.fadeOut then -- Upgrade to 39 button.fadeOut = button:CreateAnimationGroup() local animOut = button.fadeOut:CreateAnimation("Alpha") animOut:SetOrder(1) animOut:SetDuration(0.2) animOut:SetFromAlpha(1) animOut:SetToAlpha(0) animOut:SetStartDelay(1) button.fadeOut:SetToFinalAlpha(true) end end lib:SetButtonRadius(lib.radius) -- Upgrade to 40 if lib.notCreated then -- Upgrade to 50 for name in next, lib.notCreated do createButton(name, lib.notCreated[name][1], lib.notCreated[name][2]) end lib.notCreated = nil end -- LibDBIconEnd end LeaLibDBIcon() ---------------------------------------------------------------------- -- L15: LibChatAnims (load on demand) ---------------------------------------------------------------------- function Leatrix_Plus:LeaPlusLCA() -- LibChatAnimsStart --@curseforge-project-slug: libchatanims@ local MAJOR, MINOR = "LibChatAnims", 4 -- Bump minor on changes local LCA = LibStub:NewLibrary(MAJOR, MINOR) if not LCA then return end -- No upgrade needed LCA.animations = LCA.animations or {} -- Animation storage LCA.alerting = LCA.alerting or {} -- Chat tab alerting storage local anims = LCA.animations local alerting = LCA.alerting function LCA:IsAlerting(tab) if alerting[tab] then return true end end ---------------------------------------------------- -- Note, most of this code is simply replicated from -- Blizzard's FloatingChatFrame.lua file. -- The only real changes are the creation and use -- of animations vs the use of UIFrameFlash. -- --FCFDockOverflowButton_UpdatePulseState = function(self) -- local dock = self:GetParent() -- local shouldPulse = false -- for _, chatFrame in pairs(FCFDock_GetChatFrames(dock)) do -- local chatTab = _G[chatFrame:GetName().."Tab"] -- if ( not chatFrame.isStaticDocked and chatTab.alerting) then -- -- Make sure the rects are valid. (Not always the case when resizing the WoW client -- if ( not chatTab:GetRight() or not dock.scrollFrame:GetRight() ) then -- return false -- end -- -- Check if it's off the screen. -- local DELTA = 3 -- Chosen through experimentation -- if ( chatTab:GetRight() < (dock.scrollFrame:GetLeft() + DELTA) or chatTab:GetLeft() > (dock.scrollFrame:GetRight() - DELTA) ) then -- shouldPulse = true -- break -- end -- end -- end -- -- local tex = self:GetHighlightTexture() -- if shouldPulse then -- if not anims[tex] then -- anims[tex] = tex:CreateAnimationGroup() -- -- local fade1 = anims[tex]:CreateAnimation("Alpha") -- fade1:SetDuration(1) -- fade1:SetFromAlpha(0) -- fade1:SetToAlpha(1) -- fade1:SetOrder(1) -- -- local fade2 = anims[tex]:CreateAnimation("Alpha") -- fade2:SetDuration(1) -- fade2:SetFromAlpha(1) -- fade2:SetToAlpha(0) -- fade2:SetOrder(2) -- end -- tex:Show() -- tex:SetAlpha(0) -- anims[tex]:SetLooping("REPEAT") -- anims[tex]:Play() -- -- self:LockHighlight() -- self.alerting = true -- else -- if anims[tex] then -- anims[tex]:Stop() -- end -- self:UnlockHighlight() -- tex:SetAlpha(1) -- tex:Show() -- self.alerting = false -- end -- -- if self.list:IsShown() then -- FCFDockOverflowList_Update(self.list, dock) -- end -- return true --end --FCFDockOverflowListButton_SetValue = function(button, chatFrame) -- local chatTab = _G[chatFrame:GetName().."Tab"] -- button.chatFrame = chatFrame -- button:SetText(chatFrame.name) -- -- local colorTable = chatTab.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE -- -- if chatTab.selectedColorTable then -- button:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b) -- else -- button:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) -- end -- -- button.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b) -- -- if chatTab.conversationIcon then -- button.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b) -- button.conversationIcon:Show() -- else -- button.conversationIcon:Hide() -- end -- -- if chatTab.alerting then -- button.alerting = true -- if not anims[button.glow] then -- anims[button.glow] = button.glow:CreateAnimationGroup() -- -- local fade1 = anims[button.glow]:CreateAnimation("Alpha") -- fade1:SetDuration(1) -- fade1:SetFromAlpha(0) -- fade1:SetToAlpha(1) -- fade1:SetOrder(1) -- -- local fade2 = anims[button.glow]:CreateAnimation("Alpha") -- fade2:SetDuration(1) -- fade2:SetFromAlpha(1) -- fade2:SetToAlpha(0) -- fade2:SetOrder(2) -- end -- button.glow:Show() -- button.glow:SetAlpha(0) -- anims[button.glow]:SetLooping("REPEAT") -- anims[button.glow]:Play() -- else -- button.alerting = false -- if anims[button.glow] then -- anims[button.glow]:Stop() -- end -- button.glow:Hide() -- end -- button:Show() --end FCF_StartAlertFlash = function(chatFrame) local chatTab = _G[chatFrame:GetName().."Tab"] if chatFrame.minFrame then if not anims[chatFrame.minFrame] then anims[chatFrame.minFrame] = chatFrame.minFrame.glow:CreateAnimationGroup() local fade1 = anims[chatFrame.minFrame]:CreateAnimation("Alpha") fade1:SetDuration(1) fade1:SetFromAlpha(0) fade1:SetToAlpha(1) fade1:SetOrder(1) local fade2 = anims[chatFrame.minFrame]:CreateAnimation("Alpha") fade2:SetDuration(1) fade2:SetFromAlpha(1) fade2:SetToAlpha(0) fade2:SetOrder(2) end chatFrame.minFrame.glow:Show() chatFrame.minFrame.glow:SetAlpha(0) anims[chatFrame.minFrame]:SetLooping("REPEAT") anims[chatFrame.minFrame]:Play() --chatFrame.minFrame.alerting = true alerting[chatFrame.minFrame] = true end if not anims[chatTab.glow] then anims[chatTab.glow] = chatTab.glow:CreateAnimationGroup() local fade1 = anims[chatTab.glow]:CreateAnimation("Alpha") fade1:SetDuration(1) fade1:SetFromAlpha(0) fade1:SetToAlpha(1) fade1:SetOrder(1) local fade2 = anims[chatTab.glow]:CreateAnimation("Alpha") fade2:SetDuration(1) fade2:SetFromAlpha(1) fade2:SetToAlpha(0) fade2:SetOrder(2) end chatTab.glow:Show() chatTab.glow:SetAlpha(0) anims[chatTab.glow]:SetLooping("REPEAT") anims[chatTab.glow]:Play() --chatTab.alerting = true alerting[chatTab] = true -- START function FCFTab_UpdateAlpha(chatFrame) local mouseOverAlpha, noMouseAlpha = 0, 0 if not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) then mouseOverAlpha = 1.0 --CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA noMouseAlpha = 0.4 -- CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA else mouseOverAlpha = 1.0 -- CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA noMouseAlpha = 1.0 -- CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA end if chatFrame.hasBeenFaded then chatTab:SetAlpha(mouseOverAlpha) else chatTab:SetAlpha(noMouseAlpha) end --END function FCFTab_UpdateAlpha(chatFrame) --FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton) end FCF_StopAlertFlash = function(chatFrame) local chatTab = _G[chatFrame:GetName().."Tab"] if chatFrame.minFrame then if anims[chatFrame.minFrame] then anims[chatFrame.minFrame]:Stop() end chatFrame.minFrame.glow:Hide() --chatFrame.minFrame.alerting = false alerting[chatFrame.minFrame] = nil end if anims[chatTab.glow] then anims[chatTab.glow]:Stop() end chatTab.glow:Hide() --chatTab.alerting = false alerting[chatTab] = nil -- START function FCFTab_UpdateAlpha(chatFrame) local mouseOverAlpha, noMouseAlpha = 0, 0 if not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) then mouseOverAlpha = 1.0 --CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA noMouseAlpha = 0.4 -- CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA else mouseOverAlpha = 0.6 --CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA noMouseAlpha = 0.2 --CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA end if chatFrame.hasBeenFaded then chatTab:SetAlpha(mouseOverAlpha) else chatTab:SetAlpha(noMouseAlpha) end --END function FCFTab_UpdateAlpha(chatFrame) --FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton) end -- LibChatAnimsEnd end -- L16: End