diff --git a/Broker_RaidMakeup.lua b/Broker_RaidMakeup.lua index f4f17ed..2f364c0 100644 --- a/Broker_RaidMakeup.lua +++ b/Broker_RaidMakeup.lua @@ -75,9 +75,9 @@ BRM.DebugMode = true -- Print debug output to the chat frame. function BRM:DebugPrint(...) - if (BRM.DebugMode) then + if not BRM.DebugMode then return end + print ("|cff" .. "a00000" .. "BRM Debug:|r", ...) - end end -- BRM:DebugPrint @@ -87,6 +87,50 @@ function BRM:ChatPrint(...) end -- BRM:DebugPrint +-- Debugging code to see what the hell is being passed in... +function BRM:PrintVarArgs(...) + if not BRM.DebugMode then return end + + local n = select('#', ...) + BRM:DebugPrint ("There are ", n, " items in varargs.") + local msg + for i = 1, n do + msg = select(i, ...) + BRM:DebugPrint ("Item ", i, " is ", msg) + end +end -- BRM:PrintVarArgs() + + +-- Dumps a table into chat. Not intended for production use. +function BRM:DumpTable(tab, indent) + if not BRM.DebugMode then return end + + if not indent then indent = 0 end + if indent > 10 then + BRM:DebugPrint("Recursion is at 11 already; aborting.") + return + end + for k, v in pairs(tab) do + local s = "" + if indent > 0 then + for i = 0, indent do + s = s .. " " + end + end + if "table" == type(v) then + s = s .. "Item " .. k .. " is sub-table." + BRM:DebugPrint(s) + indent = indent + 1 + BRM:DumpTable(v, indent) + indent = indent - 1 + else + s = s .. "Item " .. k .. " is " .. tostring(v) + BRM:DebugPrint(s) + end + end +end -- BRM:DumpTable() + + --######################################### --# Icon class setup --######################################### @@ -247,7 +291,7 @@ SlashCmdList.BRM = function (...) BRM:HandleCommandLine(...) end function BRM:HandleCommandLine() BRM.DebugMode = not BRM.DebugMode - BRM:ChatPrint("Printing debug statements is now " .. (BRM.DebugMode and "on." or "off.")) + BRM:ChatPrint("Printing debug statements is now " .. (BRM.DebugMode and "on" or "off") .. ".") end --@end-alpha@ @@ -262,10 +306,10 @@ BRM.DPSCount = 0 BRM.UnknownCount = 0 BRM.TotalCount = 0 --- The game is firing the ACTIVE_TALENT_GROUP_CHANGED event before the PLAYER_LOGIN event. +-- The game is firing the ACTIVE_TALENT_GROUP_CHANGED event before the PLAYER_ENTERING_WORLD event. -- Since we're not fully in the world yet at that point, the group and raid query functions are returning unexpected results. -- So, we use this variable to track whether the add-on is loaded and active. --- We turn it on in the PLAYER_LOGIN event. +-- We turn it on in the PLAYER_ENTERING_WORLD event. BRM.IsActive = false --######################################### @@ -410,9 +454,17 @@ BRM.LDO = _G.LibStub("LibDataBroker-1.1"):NewDataObject("Broker_RaidMakeup", { -- Handler for if user clicks on the display -function BRM.LDO:OnClick(...) +function BRM.LDO:OnClick(button) BRM:DebugPrint("Got click on LDB object") + if button == "LeftButton" then + BRM:DebugPrint("Got left button") + elseif button == "RightButton" then + BRM:DebugPrint("Got right button") + else + BRM:DebugPrint("Got some other button") + end + -- I'm trying to capture which situations don't result in an automatic update. -- That essentially indicates either an event I missed coding for, or some kind of bug that resulted in invalid role counts. local old_TankCount = BRM.TankCount @@ -447,6 +499,7 @@ function BRM.LDO:OnClick(...) end -- BRM.LDO:OnClick() + --######################################### --# Events to register and handle --######################################### @@ -457,26 +510,64 @@ function BRM.Events:PLAYER_LOGIN(...) BRM:DebugPrint("Got PLAYER_LOGIN event") end -- BRM.Events:PLAYER_LOGIN() --- This event is only for debugging. + +-- This event is for loading our saved settings. function BRM.Events:ADDON_LOADED(addon) BRM:DebugPrint("Got ADDON_LOADED for " .. addon) - if addon == "Broker_RaidMakeup" then - BRM:DebugPrint("Now processing stuff for this addon") - end -- if Broker_RaidMakeup + if addon ~= "Broker_RaidMakeup" then return end + + + --######################################### + --# Load saved settings + --######################################### + + BRM:DebugPrint("Loading or creating DB") + if BRM_DB then + -- Load the settings saved by the game. + BRM:DebugPrint ("Restoring existing BRM DB") + BRM.DB = BRM_DB + + -- This situation should only occur during development, but just in case, let's handle it. + if not BRM.DB.MinimapSettings then BRM.DB.MinimapSettings = {} end + else + -- Initialize settings on first use + BRM:DebugPrint ("Creating new BRM DB") + BRM.DB = {} + BRM.DB.Version = 1 + BRM.DB.MinimapSettings = {} + end + + BRM:DebugPrint ("DB contents follow") + BRM:DumpTable(BRM.DB) + BRM:DebugPrint ("End DB contents") + + --######################################### + --# Minimap button for LDB object + --######################################### + + -- Creating the minimap icon requires somewhere to save the data. + -- We don't load that until this event. + -- So, this is the earliest point we can create the minimap icon. + + BRM.MinimapIcon = LibStub("LibDBIcon-1.0") + BRM.MinimapIcon:Register("Broker_RaidMakeup", BRM.LDO, BRM.DB.MinimapSettings) end -- BRM.Events:ADDON_LOADED() + -- This triggers when someone joins or leaves a group, or changes their spec or role in the group. function BRM.Events:GROUP_ROSTER_UPDATE(...) BRM:DebugPrint("Got GROUP_ROSTER_UPDATE") BRM:UpdateComposition() end -- BRM.Events:GROUP_ROSTER_UPDATE() + -- This triggers when the player changes their talent spec. function BRM.Events:ACTIVE_TALENT_GROUP_CHANGED(...) BRM:DebugPrint("Got ACTIVE_TALENT_GROUP_CHANGED") BRM:UpdateComposition() end -- BRM.Events:ACTIVE_TALENT_GROUP_CHANGED() + -- On-load handler for addon initialization. function BRM.Events:PLAYER_ENTERING_WORLD(...) -- Announce our load. @@ -496,11 +587,11 @@ function BRM.Events:PLAYER_ENTERING_WORLD(...) if BRM.FACTION_HORDE == BRM.Faction then BRM:DebugPrint("Faction is Horde") - BRM:DebugPrint(BRM.HordeIcon:GetIconStringInner()) + BRM:DebugPrint("Inner string is " .. BRM.HordeIcon:GetIconStringInner()) BRM.LDO.icon = BRM.HordeIcon.IconFile elseif BRM.FACTION_ALLIANCE == BRM.Faction then BRM:DebugPrint("Faction is Alliance") - BRM:DebugPrint(BRM.AllianceIcon:GetIconStringInner()) + BRM:DebugPrint("Inner string is " .. BRM.AllianceIcon:GetIconStringInner()) BRM.LDO.icon = BRM.AllianceIcon.IconFile else -- What the hell? @@ -510,6 +601,13 @@ function BRM.Events:PLAYER_ENTERING_WORLD(...) end -- BRM.Events:PLAYER_ENTERING_WORLD() +-- Save the db on logout. +function BRM.Events:PLAYER_LOGOUT(...) + BRM:DebugPrint ("In PLAYER_LOGOUT, saving DB.") + BRM_DB = BRM.DB +end -- BRM.Events:PLAYER_LOGOUT() + + --######################################### --# Implement the event handlers --######################################### diff --git a/Broker_RaidMakeup.toc b/Broker_RaidMakeup.toc index 984ccf5..0b0e0b3 100644 --- a/Broker_RaidMakeup.toc +++ b/Broker_RaidMakeup.toc @@ -7,8 +7,14 @@ ## X-Curse-Project-ID: 294431 ## X-WoWI-ID: 24656 -libs\LibStub\LibStub.lua -libs\CallbackHandler-1.0\CallbackHandler-1.0.lua -libs\LibDataBroker-1.1\LibDataBroker-1.1.lua +## SavedVariablesPerCharacter: BRM_DB + + +#@no-lib-strip@ +Libs\LibStub\LibStub.lua +Libs\CallbackHandler-1.0\CallbackHandler-1.0.lua +Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua +Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua +#@end-no-lib-strip@ Broker_RaidMakeup.lua diff --git a/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua b/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua new file mode 100644 index 0000000..00925ec --- /dev/null +++ b/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua @@ -0,0 +1,334 @@ + +----------------------------------------------------------------------- +-- 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 = 36 -- 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.disabled = lib.disabled or nil +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.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate") + +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 self.isMoving then return 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) + local obj = self.dataObject + lib.tooltip:Hide() + if obj.OnLeave then obj.OnLeave(self) end +end + +-------------------------------------------------------------------------------- + +local onClick, onMouseUp, onMouseDown, onDragStart, onDragStop, 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}, + } + + function updatePosition(button) + local angle = math.rad(button.db and button.db.minimapPos or button.minimapPos or 225) + local x, y, q = math.cos(angle), math.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] + if quadTable[q] then + x, y = x*80, y*80 + else + local diagRadius = 103.13708498985 --math.sqrt(2*(80)^2)-10 + x = math.max(-80, math.min(x*diagRadius, 80)) + y = math.max(-80, math.min(y*diagRadius, 80)) + end + button:SetPoint("CENTER", Minimap, "CENTER", x, y) + end +end + +function onClick(self, b) if self.dataObject.OnClick then self.dataObject.OnClick(self, b) end end +function onMouseDown(self) self.isMouseDown = true; self.icon:UpdateCoord() end +function onMouseUp(self) self.isMouseDown = false; self.icon:UpdateCoord() end + +do + local function onUpdate(self) + local mx, my = Minimap:GetCenter() + local px, py = GetCursorPosition() + local scale = Minimap:GetEffectiveScale() + px, py = px / scale, py / scale + if self.db then + self.db.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 + else + self.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 + end + updatePosition(self) + end + + function onDragStart(self) + self:LockHighlight() + self.isMouseDown = true + self.icon:UpdateCoord() + self:SetScript("OnUpdate", onUpdate) + self.isMoving = true + lib.tooltip:Hide() + end +end + +function onDragStop(self) + self:SetScript("OnUpdate", nil) + self.isMouseDown = false + self.icon:UpdateCoord() + self:UnlockHighlight() + self.isMoving = nil +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) + + lib.objects[name] = button + + if lib.loggedIn then + updatePosition(button) + 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 + +lib.loggedIn = lib.loggedIn or false +-- 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() + for _, object in pairs(lib.objects) do + updatePosition(object) + if not lib.disabled and (not object.db or not object.db.hide) then object:Show() + else object:Hide() end + end + lib.loggedIn = true + f:SetScript("OnEvent", nil) + f = 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("Already registered, nubcake.") end + if not lib.disabled and (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) + if lib.disabled then return end + check(name) + lib.objects[name]:Show() + updatePosition(lib.objects[name]) +end +function lib:IsRegistered(name) + return (lib.objects[name] or lib.notCreated[name]) and true or false +end +function lib:Refresh(name, db) + if lib.disabled then return end + check(name) + local button = lib.objects[name] + if db then button.db = db end + updatePosition(button) + 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 + +function lib:EnableLibrary() + lib.disabled = nil + for name, object in pairs(lib.objects) do + if not object.db or not object.db.hide then + object:Show() + updatePosition(object) + end + end + for name, data in pairs(lib.notCreated) do + if not data.db or not data.db.hide then + createButton(name, data[1], data[2]) + lib.notCreated[name] = nil + end + end +end + +function lib:DisableLibrary() + lib.disabled = true + for name, object in pairs(lib.objects) do + object:Hide() + end +end +