diff --git a/AutoCombatLogger.lua b/AutoCombatLogger.lua index e69de29..1e8cfed 100644 --- a/AutoCombatLogger.lua +++ b/AutoCombatLogger.lua @@ -0,0 +1,213 @@ +--[[ + print(LoggingCombat()) + print(LoggingCombat(true)) + - getinstanceinfo() +--]] + +local _, AutoCombatLogger = ... + +-- UI variables. +local X_START = 16 +local X_SPACING = 200 +local Y_SPACING = -25 +local BUTTONS_PER_ROW = 3 + +-- Variables. +local minimapIcon = LibStub("LibDBIcon-1.0") +local buttons = {} +local dungeons = { + [719] = "Blackfathom Deeps", + [1584] = "Blackrock Depths", + [1583] = "Blackrock Spire", + [2557] = "Dire Maul", + [721] = "Gnomeregan", + [2100] = "Maraudon", + [2437] = "Ragefire Chasm", + [722] = "Razorfen Downs", + [491] = "Razorfen Kraul", + [796] = "Scarlet Monastery", + [2057] = "Scholomance", + [209] = "Shadowfang Keep", + [2017] = "Stratholme", + [1477] = "Temple of Atal'Hakkar", + [1581] = "The Deadmines", + [717] = "The Stockade", + [1337] = "Uldaman", + [718] = "Wailing Caverns", + [1176] = "Zul'Farrak" +} +local raids = { + [2677] = "Blackwing Lair", + [2717] = "Molten Core", + [3456] = "Naxxramas", + [2159] = "Onyxia's Lair", + [3429] = "AQ20", + [3428] = "AQ40", + [1977] = "Zul'Gurub" +} + +-- Shows or hides the addon. +local function toggleFrame() + if AutoCombatLoggerFrame:IsVisible() then + AutoCombatLoggerFrame:Hide() + else + AutoCombatLoggerFrame:Show() + end +end + +-- Shows or hides the minimap button. +local function toggleMinimapButton() + ACLOptions.minimapTable.hide = not ACLOptions.minimapTable.hide + if ACLOptions.minimapTable.hide then + minimapIcon:Hide("AutoCombatLogger") + print("|cFFFFFF00AutoCombatLogger:|r Minimap button hidden. Type /acl minimap to show it again.") + else + minimapIcon:Show("AutoCombatLogger") + end +end + +-- Initializes the minimap button. +local function initMinimapButton() + local obj = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("AutoCombatLogger", { + type = "launcher", + text = "AutoCombatLogger", + icon = "Interface/ICONS/Trade_Engineering", + OnClick = function(self, button) + if button == "LeftButton" then + toggleFrame() + elseif button == "RightButton" then + toggleMinimapButton() + end + end, + OnEnter = function(self) + GameTooltip:SetOwner(self, "ANCHOR_LEFT") + GameTooltip:AddLine("|cFFFFFFFFAutoCombatLogger|r") + GameTooltip:AddLine("Left click to open options.") + GameTooltip:AddLine("Right click to hide this minimap button.") + GameTooltip:Show() + end, + OnLeave = function(self) + GameTooltip:Hide() + end + }) + minimapIcon:Register("AutoCombatLogger", obj, ACLOptions.minimapTable) +end + +-- Sets slash commands. +local function initSlash() + SLASH_AUTOCOMBATLOGGER1 = "/autocombatlogger" + SLASH_AUTOCOMBATLOGGER2 = "/acl" + SlashCmdList["AUTOCOMBATLOGGER"] = function(msg) + msg = msg:lower() + if msg == "minimap" then + toggleMinimapButton() + return + end + toggleFrame() + end +end + +-- Initializes all checkboxes. +local function initCheckButtons() + -- Dungeons. + local index = 1 + for k, v in pairs(dungeons) do + -- Checkbuttons. + local checkButton = CreateFrame("CheckButton", nil, AutoCombatLoggerFrame, "UICheckButtonTemplate") + local x = X_START + X_SPACING * ((index - 1) % BUTTONS_PER_ROW) + local y = Y_SPACING * math.ceil(index / BUTTONS_PER_ROW) - 10 + checkButton:SetPoint("TOPLEFT", x, y) + checkButton:SetScript("OnClick", AutoCombatLoggerCheckButton_OnClick) + checkButton.instance = k + checkButton:SetChecked(ACLOptions.instances[k]) + buttons[#buttons + 1] = checkButton + -- Strings. + local string = AutoCombatLoggerFrame:CreateFontString(nil, "ARTWORK", "AutoCombatLoggerStringTemplate") + string:SetPoint("LEFT", checkButton, "RIGHT", 5, 0) + string:SetText(v) + index = index + 1 + end + -- Raids. + index = 1 + for k, v in pairs(raids) do + -- Checkbuttons. + local checkButton = CreateFrame("CheckButton", nil, AutoCombatLoggerFrame, "UICheckButtonTemplate") + local x = X_START + X_SPACING * ((index - 1) % BUTTONS_PER_ROW) + local y = Y_SPACING * math.ceil(index / BUTTONS_PER_ROW) - 240 + checkButton:SetPoint("TOPLEFT", x, y) + checkButton:SetScript("OnClick", AutoCombatLoggerCheckButton_OnClick) + checkButton.instance = k + checkButton:SetChecked(ACLOptions.instances[k]) + buttons[#buttons + 1] = checkButton + -- Strings. + local string = AutoCombatLoggerFrame:CreateFontString(nil, "ARTWORK", "AutoCombatLoggerStringTemplate") + string:SetPoint("LEFT", checkButton, "RIGHT", 5, 0) + string:SetText(v) + index = index + 1 + end +end + +-- Initializes everything. +local function init() + initMinimapButton() + initSlash() + initCheckButtons() + tinsert(UISpecialFrames, AutoCombatLoggerFrame:GetName()) +end + +-- Called when player clicks a checkbutton. +function AutoCombatLoggerCheckButton_OnClick(self) + ACLOptions.instances[self.instance] = not ACLOptions.instances[self.instance] +end + +-- Called when addon has been loaded. +function AutoCombatLogger_OnLoad(self) + self:RegisterForDrag("LeftButton") + self:RegisterEvent("ADDON_LOADED") + self:RegisterEvent("PLAYER_ENTERING_WORLD") + self:RegisterEvent("ZONE_CHANGED_NEW_AREA") +end + +-- Handles all events. +function AutoCombatLogger_OnEvent(self, event, ...) + if event == "ADDON_LOADED" and ... == "AutoCombatLogger" then + ACLOptions = ACLOptions or {} + ACLOptions.minimapTable = ACLOptions.minimapTable or {} + if not ACLOptions.instances then + ACLOptions.instances = { + [719] = true, + [1584] = true, + [1583] = true, + [2557] = true, + [721] = true, + [2100] = true, + [2437] = true, + [722] = true, + [491] = true, + [796] = true, + [2057] = true, + [209] = true, + [2017] = true, + [1477] = true, + [1581] = true, + [717] = true, + [1337] = true, + [718] = true, + [1176] = true, + [2677] = true, + [2717] = true, + [3456] = true, + [2159] = true, + [3429] = true, + [3428] = true, + [1977] = true + } + end + -- ACLOptions.instances = ACLOptions.instances or {} + print("|cFFFFFF00AutoCombatLogger|r loaded! Type /acl to toggle options. Remember to enable advanced combat logging in Interface > Network.") + elseif event == "PLAYER_ENTERING_WORLD" then + init() + AutoCombatLoggerFrame:Hide() + self:UnregisterEvent("PLAYER_ENTERING_WORLD") + end +end \ No newline at end of file diff --git a/AutoCombatLogger.toc b/AutoCombatLogger.toc index ed1ba3c..d6dc29b 100644 --- a/AutoCombatLogger.toc +++ b/AutoCombatLogger.toc @@ -8,7 +8,9 @@ # Load libraries. Libraries\LibStub\LibStub.lua Libraries\CallbackHandler-1.0\CallbackHandler-1.0.lua -Libraries\AceGUI-3.0\AceGUI-3.0.xml +Libraries\LibDataBroker-1.1\LibDataBroker-1.1.lua +Libraries\LibDBIcon-1.0\LibDBIcon-1.0.lua # Load core files. AutoCombatLogger.lua +AutoCombatLogger.xml diff --git a/AutoCombatLogger.xml b/AutoCombatLogger.xml new file mode 100644 index 0000000..5eb40bb --- /dev/null +++ b/AutoCombatLogger.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AutoCombatLogger_OnLoad(self) + + + self:StartMoving() + + + self:StopMovingOrSizing() + + + AutoCombatLogger_OnEvent(self, event, ...) + + + + diff --git a/Libraries/AceEvent-3.0/AceEvent-3.0.lua b/Libraries/AceEvent-3.0/AceEvent-3.0.lua new file mode 100644 index 0000000..7ccd880 --- /dev/null +++ b/Libraries/AceEvent-3.0/AceEvent-3.0.lua @@ -0,0 +1,126 @@ +--- AceEvent-3.0 provides event registration and secure dispatching. +-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around +-- CallbackHandler, and dispatches all game events or addon message to the registrees. +-- +-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by +-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object +-- and can be accessed directly, without having to explicitly call AceEvent itself.\\ +-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you +-- make into AceEvent. +-- @class file +-- @name AceEvent-3.0 +-- @release $Id: AceEvent-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $ +local CallbackHandler = LibStub("CallbackHandler-1.0") + +local MAJOR, MINOR = "AceEvent-3.0", 4 +local AceEvent = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceEvent then return end + +-- Lua APIs +local pairs = pairs + +AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame +AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib + +-- APIs and registry for blizzard events, using CallbackHandler lib +if not AceEvent.events then + AceEvent.events = CallbackHandler:New(AceEvent, + "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents") +end + +function AceEvent.events:OnUsed(target, eventname) + AceEvent.frame:RegisterEvent(eventname) +end + +function AceEvent.events:OnUnused(target, eventname) + AceEvent.frame:UnregisterEvent(eventname) +end + + +-- APIs and registry for IPC messages, using CallbackHandler lib +if not AceEvent.messages then + AceEvent.messages = CallbackHandler:New(AceEvent, + "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages" + ) + AceEvent.SendMessage = AceEvent.messages.Fire +end + +--- embedding and embed handling +local mixins = { + "RegisterEvent", "UnregisterEvent", + "RegisterMessage", "UnregisterMessage", + "SendMessage", + "UnregisterAllEvents", "UnregisterAllMessages", +} + +--- Register for a Blizzard Event. +-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied) +-- Any arguments to the event will be passed on after that. +-- @name AceEvent:RegisterEvent +-- @class function +-- @paramsig event[, callback [, arg]] +-- @param event The event to register for +-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name) +-- @param arg An optional argument to pass to the callback function + +--- Unregister an event. +-- @name AceEvent:UnregisterEvent +-- @class function +-- @paramsig event +-- @param event The event to unregister + +--- Register for a custom AceEvent-internal message. +-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied) +-- Any arguments to the event will be passed on after that. +-- @name AceEvent:RegisterMessage +-- @class function +-- @paramsig message[, callback [, arg]] +-- @param message The message to register for +-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name) +-- @param arg An optional argument to pass to the callback function + +--- Unregister a message +-- @name AceEvent:UnregisterMessage +-- @class function +-- @paramsig message +-- @param message The message to unregister + +--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message. +-- @name AceEvent:SendMessage +-- @class function +-- @paramsig message, ... +-- @param message The message to send +-- @param ... Any arguments to the message + + +-- Embeds AceEvent into the target object making the functions from the mixins list available on target:.. +-- @param target target object to embed AceEvent in +function AceEvent:Embed(target) + for k, v in pairs(mixins) do + target[v] = self[v] + end + self.embeds[target] = true + return target +end + +-- AceEvent:OnEmbedDisable( target ) +-- target (object) - target object that is being disabled +-- +-- Unregister all events messages etc when the target disables. +-- this method should be called by the target manually or by an addon framework +function AceEvent:OnEmbedDisable(target) + target:UnregisterAllEvents() + target:UnregisterAllMessages() +end + +-- Script to fire blizzard events into the event listeners +local events = AceEvent.events +AceEvent.frame:SetScript("OnEvent", function(this, event, ...) + events:Fire(event, ...) +end) + +--- Finally: upgrade our old embeds +for target, v in pairs(AceEvent.embeds) do + AceEvent:Embed(target) +end diff --git a/Libraries/LibDBIcon-1.0/LibDBIcon-1.0.lua b/Libraries/LibDBIcon-1.0/LibDBIcon-1.0.lua new file mode 100644 index 0000000..e865bdf --- /dev/null +++ b/Libraries/LibDBIcon-1.0/LibDBIcon-1.0.lua @@ -0,0 +1,470 @@ + +----------------------------------------------------------------------- +-- 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 = 43 -- 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.notCreated = lib.notCreated or {} +lib.radius = lib.radius or 5 +lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate") +local next, Minimap = next, Minimap +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 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) + local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap) + button.dataObject = object + button.db = db + button:SetFrameStrata("MEDIUM") + button:SetSize(31, 31) + button:SetFrameLevel(8) + button:RegisterForClicks("anyUp") + button:RegisterForDrag("LeftButton") + button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight" + 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 + button.isMouseDown = false + + local r, g, b = icon:GetVertexColor() + icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b) + + icon.UpdateCoord = updateCoord + 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 + lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback +end + +-- We could use a metatable.__index on lib.objects, but then we'd create +-- the icons when checking things like :IsRegistered, which is not necessary. +local function check(name) + if lib.notCreated[name] then + createButton(name, lib.notCreated[name][1], lib.notCreated[name][2]) + lib.notCreated[name] = nil + end +end + +-- Wait a bit with the initial positioning to let any GetMinimapShape addons +-- load up. +if not lib.loggedIn then + local f = CreateFrame("Frame") + f:SetScript("OnEvent", function(f) + 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 + f:SetScript("OnEvent", nil) + end) + f:RegisterEvent("PLAYER_LOGIN") +end + +local function getDatabase(name) + return lib.notCreated[name] and lib.notCreated[name][2] or lib.objects[name].db +end + +function lib:Register(name, object, db) + if not object.icon then error("Can't register LDB objects without icons set!") end + if lib.objects[name] or lib.notCreated[name] then error(DBICON10.. ": Object '".. name .."' is already registered.") end + if not db or not db.hide then + createButton(name, object, db) + else + lib.notCreated[name] = {object, db} + end +end + +function lib:Lock(name) + if not lib:IsRegistered(name) then return end + if lib.objects[name] then + lib.objects[name]:SetScript("OnDragStart", nil) + lib.objects[name]:SetScript("OnDragStop", nil) + end + local db = getDatabase(name) + if db then + db.lock = true + end +end + +function lib:Unlock(name) + if not lib:IsRegistered(name) then return end + if lib.objects[name] then + lib.objects[name]:SetScript("OnDragStart", onDragStart) + lib.objects[name]:SetScript("OnDragStop", onDragStop) + end + local db = getDatabase(name) + if db then + db.lock = nil + end +end + +function lib:Hide(name) + if not lib.objects[name] then return end + lib.objects[name]:Hide() +end + +function lib:Show(name) + check(name) + local button = lib.objects[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] or lib.notCreated[name]) and true or false +end + +function lib:Refresh(name, db) + check(name) + local button = lib.objects[name] + 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 + +function lib:GetMinimapButton(name) + return lib.objects[name] +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) + + function lib:ShowOnEnter(name, value) + local button = lib.objects[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 +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 + +-- Upgrade! +for name, button in next, lib.objects do + local db = getDatabase(name) + 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 diff --git a/Libraries/LibDataBroker-1.1/LibDataBroker-1.1.lua b/Libraries/LibDataBroker-1.1/LibDataBroker-1.1.lua new file mode 100644 index 0000000..f47c0cd --- /dev/null +++ b/Libraries/LibDataBroker-1.1/LibDataBroker-1.1.lua @@ -0,0 +1,90 @@ + +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