Files

204 lines
6.7 KiB
Lua

local T = ShaguTweaks.T
local module = ShaguTweaks:register({
title = T["Enlarged Minimap"],
description = T["Increases the minimap size and shifts buff icons left to prevent overlap."],
expansions = { ["vanilla"] = true },
category = T["Minimap & World Map"],
enabled = false,
order = 73,
config = {
["minimap.scale"] = 1.2,
}
})
local function EnsurePoint(frame, point, relativeTo, relativePoint, x, y)
if not frame then return end
local currentPoint, currentRelative, currentRelativePoint, currentX, currentY = frame:GetPoint(1)
if currentPoint == point and currentRelative == relativeTo
and currentRelativePoint == relativePoint and currentX == x and currentY == y then
return
end
frame:ClearAllPoints()
frame:SetPoint(point, relativeTo, relativePoint, x, y)
end
local function GetMoverState(group)
local state = ShaguTweaks.MovableUnitFramesState
if not state then return false, false end
local manual = state.manual and state.manual[group] and true or false
local dragging = state.dragging and state.dragging[group] and true or false
return manual, dragging
end
local function GetMovedPosition(key)
local config = ShaguTweaks_config and ShaguTweaks_config["MoveUnitframes"]
return config and config[key]
end
local function EnsureMovedPosition(frame, key)
local pos = GetMovedPosition(key)
if not frame or not pos or not pos[1] or not pos[2] then return end
EnsurePoint(frame, "TOPLEFT", UIParent, "BOTTOMLEFT", pos[1], pos[2])
end
-- Keep a moved/scaled minimap fully on screen without touching its saved
-- Movable Unit Frames position. Bounds are compared in physical screen space
-- because MinimapCluster can have a different effective scale than UIParent.
local function ClampMinimapToScreen()
local frame = MinimapCluster
if not frame or not UIParent then return end
local left = frame:GetLeft()
local right = frame:GetRight()
local top = frame:GetTop()
local bottom = frame:GetBottom()
if not left or not right or not top or not bottom then return end
local frameScale = frame:GetEffectiveScale()
local uiScale = UIParent:GetEffectiveScale()
if not frameScale or frameScale <= 0 or not uiScale or uiScale <= 0 then return end
local uiLeft = (UIParent:GetLeft() or 0) * uiScale
local uiRight = (UIParent:GetRight() or UIParent:GetWidth()) * uiScale
local uiTop = (UIParent:GetTop() or UIParent:GetHeight()) * uiScale
local uiBottom = (UIParent:GetBottom() or 0) * uiScale
local frameLeft = left * frameScale
local frameRight = right * frameScale
local frameTop = top * frameScale
local frameBottom = bottom * frameScale
local dx, dy = 0, 0
if frameLeft < uiLeft then
dx = uiLeft - frameLeft
elseif frameRight > uiRight then
dx = uiRight - frameRight
end
if frameBottom < uiBottom then
dy = uiBottom - frameBottom
elseif frameTop > uiTop then
dy = uiTop - frameTop
end
if dx == 0 and dy == 0 then return end
-- Anchor from the measured top-left so only the overflowing amount is moved.
-- This changes the live position only; the saved mover coordinates stay intact.
local newLeft = (frameLeft + dx - uiLeft) / frameScale
local newTop = (frameTop + dy - uiBottom) / frameScale
frame:ClearAllPoints()
frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", newLeft, newTop)
end
-- Layout coordinates can lag one frame after SetScale()/SetPoint() on Vanilla.
-- Coalesce clamp requests into a single deferred pass with no permanent OnUpdate.
local minimapClampFrame = CreateFrame("Frame")
minimapClampFrame:Hide()
minimapClampFrame:SetScript("OnUpdate", function()
this:Hide()
ClampMinimapToScreen()
end)
ShaguTweaks.ScheduleMinimapClamp = function()
minimapClampFrame:Show()
end
module.enable = function(self)
local scale = module.config["minimap.scale"]
if scale < 1.0 then scale = 1.0 end
if scale > 2.0 then scale = 2.0 end
if MinimapCluster.SetClampedToScreen then
MinimapCluster:SetClampedToScreen(true)
end
MinimapCluster:SetScale(scale)
ShaguTweaks.ScheduleMinimapClamp()
-- BuffFrame is anchored to UIParent TOPRIGHT/TOPRIGHT x=-205 y=-13 by vanilla.
-- The C engine can restore these anchors after aura layout updates, so keep a
-- lightweight per-frame verifier and only write when an anchor actually moved.
local extra = MinimapCluster:GetWidth() * (scale - 1.0)
local targetX = -205 - extra
local targetY = -13
-- BuffButton16 is the anchor for the player debuff row in vanilla 1.12.
local debuffX = -205 - extra
local debuffY = -13 - 70
-- BuffButton8 ends the top buff row and can overlap an enlarged minimap.
local buffRowX = -205 - extra
local buffRowY = debuffY + 26
-- Reuse a single verifier if enable() is called again. This prevents stacked
-- OnUpdate frames from fighting over the same anchors.
if not self.enforcer then
self.enforcer = CreateFrame("Frame")
end
local enforcer = self.enforcer
enforcer:SetScript("OnUpdate", function()
local buffsManual, buffsDragging = GetMoverState("buffs")
local debuffsManual, debuffsDragging = GetMoverState("debuffs")
local weaponManual, weaponDragging = GetMoverState("weapon")
-- Manually moved aura groups always win. While a group is actively being
-- dragged, do not write any anchor for it; once released, enforce the
-- saved user position instead of the Enlarged Minimap default.
if buffsManual then
if not buffsDragging then
EnsureMovedPosition(BuffButton0, "BuffButton0")
end
else
EnsurePoint(BuffFrame, "TOPRIGHT", UIParent, "TOPRIGHT", targetX, targetY)
if BuffButton8 then
EnsurePoint(BuffButton8, "TOPRIGHT", UIParent, "TOPRIGHT", buffRowX, buffRowY)
end
end
if debuffsManual then
if not debuffsDragging then
EnsureMovedPosition(BuffButton32, "BuffButton32")
end
elseif BuffButton16 then
EnsurePoint(BuffButton16, "TOPRIGHT", UIParent, "TOPRIGHT", debuffX, debuffY)
end
if weaponManual then
if not weaponDragging then
EnsureMovedPosition(TempEnchant1, "TempEnchant1")
if TempEnchant2 and TempEnchant1 then
EnsurePoint(TempEnchant2, "TOP", TempEnchant1, "BOTTOM", 0, -2)
end
end
else
-- Temporary enchant buttons are also restored by the stock aura layout.
-- Verify their anchors like the buff rows instead of clearing and setting
-- them unconditionally every frame.
if TempEnchant1 then
EnsurePoint(TempEnchant1, "TOPLEFT", BuffFrame, "TOPRIGHT", 5, 0)
end
if TempEnchant2 and TempEnchant1 then
EnsurePoint(TempEnchant2, "TOP", TempEnchant1, "BOTTOM", 0, -2)
end
end
end)
end
module.disable = function(self)
if self.enforcer then
self.enforcer:SetScript("OnUpdate", nil)
end
end