Files
RelationshipsAttune/Minimap.lua
T
2026-07-16 17:56:42 +01:00

169 lines
6.0 KiB
Lua

-- RelationshipsAttune: Minimap.lua
-- A standalone, freely-movable, hideable button (parented to UIParent so it
-- can be dragged anywhere on the screen, not just around the minimap ring).
-- Pure Lua 5.0 / WoW 1.12 safe (Turtle/Octo compatible).
--
-- Options are stored in RelationshipsAttuneDB.options:
-- minimapX : number (x offset from UIParent CENTER, in UI pixels)
-- minimapY : number (y offset from UIParent CENTER, in UI pixels)
-- minimapHide : boolean (true = hidden)
-- Legacy angle/radius fields are migrated to X/Y on first load.
RelationshipsAttune = RelationshipsAttune or {}
local RA = RelationshipsAttune
RA.Minimap = {}
local MM = RA.Minimap
local BTN_NAME = "RelationshipsAttuneMinimapButton"
local ICON = "Interface\\Icons\\INV_Misc_Book_09"
local function opts()
if not RelationshipsAttuneDB then RelationshipsAttuneDB = {} end
if not RelationshipsAttuneDB.options then RelationshipsAttuneDB.options = {} end
local o = RelationshipsAttuneDB.options
-- Migrate legacy angle/radius (around the minimap) into free X/Y.
if type(o.minimapX) ~= "number" or type(o.minimapY) ~= "number" then
local ang = (type(o.minimapAngle) == "number") and o.minimapAngle or 200
local rad = (type(o.minimapRadius) == "number") and o.minimapRadius or 80
local r = ang * math.pi / 180
local mx, my = 0, 0
if Minimap and Minimap.GetCenter then
local cx, cy = Minimap:GetCenter()
if cx then mx, my = cx, cy end
end
local ux, uy = 0, 0
if UIParent and UIParent.GetCenter then
local ucx, ucy = UIParent:GetCenter()
if ucx then ux, uy = ucx, ucy end
end
o.minimapX = (mx - ux) + math.cos(r) * rad
o.minimapY = (my - uy) + math.sin(r) * rad
end
if o.minimapHide == nil then o.minimapHide = false end
return o
end
local function applyPosition(btn)
local o = opts()
btn:ClearAllPoints()
btn:SetPoint("CENTER", UIParent, "CENTER", o.minimapX, o.minimapY)
end
MM._updatePosition = applyPosition
local function onDragUpdate()
-- Do all math in the button's own effective scale. The button is
-- parented to Minimap, whose effective scale can differ from
-- UIParent's; mixing scales makes the icon drift away from the cursor.
local btn = this
local bscale = btn:GetEffectiveScale() or 1
local uscale = UIParent:GetEffectiveScale() or 1
local mx, my = GetCursorPosition()
mx = mx / bscale
my = my / bscale
local ucx, ucy = UIParent:GetCenter()
if not ucx then return end
-- Convert UIParent center from UIParent scale into btn scale.
ucx = ucx * uscale / bscale
ucy = ucy * uscale / bscale
local o = opts()
o.minimapX = mx - ucx
o.minimapY = my - ucy
applyPosition(btn)
end
function MM:Create()
if getglobal(BTN_NAME) then return getglobal(BTN_NAME) end
-- Parent to Minimap so button-collector addons (MinimapButtonBag /
-- MBB, and similar) can discover and manage this button the same way
-- they discover Blizzard's built-in minimap buttons. SetPoint still
-- anchors to UIParent CENTER so the button can be dragged anywhere
-- on screen -- the anchor frame is independent of the parent frame.
local btn = CreateFrame("Button", BTN_NAME, Minimap)
btn:SetWidth(31); btn:SetHeight(31)
btn:SetFrameStrata("MEDIUM")
btn:SetFrameLevel(8)
btn:EnableMouse(true)
btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
btn:RegisterForDrag("LeftButton", "RightButton")
btn:SetMovable(true)
-- Allow the button to sit off-screen (via /attune pos or /attune offscreen)
-- while remaining discoverable by MinimapButtonBag.
if btn.SetClampedToScreen then btn:SetClampedToScreen(false) end
-- MBB-friendly highlight so the button visually matches other
-- minimap buttons once it has been swept into the bag.
btn:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
-- Round border ring (standard minimap-button look)
local overlay = btn:CreateTexture(nil, "OVERLAY")
overlay:SetWidth(53); overlay:SetHeight(53)
overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
overlay:SetPoint("TOPLEFT", btn, "TOPLEFT", 0, 0)
local icon = btn:CreateTexture(nil, "BACKGROUND")
icon:SetWidth(20); icon:SetHeight(20)
icon:SetTexture(ICON)
icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
icon:SetPoint("TOPLEFT", btn, "TOPLEFT", 7, -6)
btn.icon = icon
btn:SetScript("OnClick", function()
if RA.UI and RA.UI.Toggle then RA.UI:Toggle() end
end)
btn:SetScript("OnDragStart", function()
this:LockHighlight()
this:SetScript("OnUpdate", onDragUpdate)
end)
btn:SetScript("OnDragStop", function()
this:UnlockHighlight()
this:SetScript("OnUpdate", nil)
end)
btn:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:AddLine("Relationships Attune", 1, 0.82, 0)
GameTooltip:AddLine("Left-click: open / close window", 0.9, 0.9, 0.9)
GameTooltip:AddLine("Drag: move anywhere on screen", 0.9, 0.9, 0.9)
GameTooltip:AddLine("/attune offscreen - park off-screen (MBB safe)", 0.6, 0.8, 1)
GameTooltip:AddLine("/attune hide - hide this button", 0.6, 0.8, 1)
GameTooltip:Show()
end)
btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
applyPosition(btn)
self.btn = btn
return btn
end
function MM:Show()
local o = opts()
o.minimapHide = false
local btn = self:Create()
btn:Show()
end
function MM:Hide()
local o = opts()
o.minimapHide = true
if self.btn then self.btn:Hide() end
end
function MM:Toggle()
local o = opts()
if o.minimapHide then self:Show() else self:Hide() end
end
function MM:Refresh()
local o = opts()
local btn = self:Create()
if o.minimapHide then btn:Hide() else btn:Show() end
applyPosition(btn)
end
function MM:Init()
self:Refresh()
end