Add files via upload
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
BNP = BNP or {}
|
||||
|
||||
local MIN_SCALE = 0.50
|
||||
local MAX_SCALE = 1.50
|
||||
local DEFAULT_SCALE = 1.00
|
||||
|
||||
local function Clamp(value)
|
||||
if value < MIN_SCALE then return MIN_SCALE end
|
||||
if value > MAX_SCALE then return MAX_SCALE end
|
||||
return value
|
||||
end
|
||||
|
||||
function BNP:GetNameplateScale()
|
||||
BNP_DB = BNP_DB or {}
|
||||
return Clamp(tonumber(BNP_DB.nameplateScale) or DEFAULT_SCALE)
|
||||
end
|
||||
|
||||
local function EffectiveScale()
|
||||
local uiScale = 1.0
|
||||
if UIParent and UIParent.GetScale then
|
||||
uiScale = UIParent:GetScale() or 1.0
|
||||
end
|
||||
return uiScale * BNP:GetNameplateScale()
|
||||
end
|
||||
|
||||
local function CaptureAnchorState(object, plate, wrapper)
|
||||
if not object or not object.GetPoint then return nil end
|
||||
|
||||
local state = {
|
||||
object = object,
|
||||
points = {},
|
||||
}
|
||||
|
||||
local count = 1
|
||||
if object.GetNumPoints then
|
||||
count = object:GetNumPoints() or 1
|
||||
if count < 1 then count = 1 end
|
||||
end
|
||||
|
||||
local i
|
||||
for i = 1, count do
|
||||
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
|
||||
if point then
|
||||
if relativeTo == plate then
|
||||
relativeTo = wrapper
|
||||
end
|
||||
|
||||
state.points[table.getn(state.points) + 1] = {
|
||||
point = point,
|
||||
relativeTo = relativeTo or wrapper,
|
||||
relativePoint = relativePoint or point,
|
||||
x = x or 0,
|
||||
y = y or 0,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return state
|
||||
end
|
||||
|
||||
local function AnchorStateMatches(state)
|
||||
if not state or not state.object or not state.object.GetPoint then return false end
|
||||
|
||||
local object = state.object
|
||||
local expectedCount = table.getn(state.points)
|
||||
local currentCount = expectedCount
|
||||
|
||||
if object.GetNumPoints then
|
||||
currentCount = object:GetNumPoints() or 0
|
||||
end
|
||||
|
||||
if currentCount ~= expectedCount then
|
||||
return false
|
||||
end
|
||||
|
||||
local i
|
||||
for i = 1, expectedCount do
|
||||
local expected = state.points[i]
|
||||
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
|
||||
|
||||
if point ~= expected.point
|
||||
or relativeTo ~= expected.relativeTo
|
||||
or relativePoint ~= expected.relativePoint
|
||||
or math.abs((x or 0) - expected.x) > 0.01
|
||||
or math.abs((y or 0) - expected.y) > 0.01 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function RestoreAnchorState(state, wrapper)
|
||||
if not state or not state.object then return end
|
||||
|
||||
local object = state.object
|
||||
|
||||
if object.GetParent and object.SetParent and object:GetParent() ~= wrapper then
|
||||
object:SetParent(wrapper)
|
||||
end
|
||||
|
||||
-- Do nothing in the common case. Blizzard normally only rewrites a subset
|
||||
-- of nameplate anchors while moving, most notably the level FontString.
|
||||
if AnchorStateMatches(state) then return end
|
||||
|
||||
if not object.ClearAllPoints or not object.SetPoint then return end
|
||||
|
||||
object:ClearAllPoints()
|
||||
|
||||
local i
|
||||
for i = 1, table.getn(state.points) do
|
||||
local p = state.points[i]
|
||||
object:SetPoint(
|
||||
p.point,
|
||||
p.relativeTo or wrapper,
|
||||
p.relativePoint or p.point,
|
||||
p.x,
|
||||
p.y
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local function SetHoverGlow(plate, shown)
|
||||
if not plate or not plate.glow then return end
|
||||
|
||||
if shown then
|
||||
if plate.glow.Show then
|
||||
plate.glow:Show()
|
||||
end
|
||||
else
|
||||
if plate.glow.Hide then
|
||||
plate.glow:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function SetYOffsetMouseMode(plate, wrapper, offset)
|
||||
if not plate or not wrapper then return end
|
||||
|
||||
-- Always use the visual wrapper as BNP's interactive frame, including at
|
||||
-- Y Offset 0. Previously offset 0 used Blizzard's native Button while
|
||||
-- positive offsets used BNPScaleWrapper. That split mouse path caused the
|
||||
-- original Blizzard mouseover glow to disappear at offset 0.
|
||||
--
|
||||
-- Keeping clicks, hit geometry and hover feedback on the same frame also
|
||||
-- guarantees that the clickable area follows the visible plate at every
|
||||
-- configured Y offset.
|
||||
if plate.EnableMouse then
|
||||
plate:EnableMouse(false)
|
||||
end
|
||||
|
||||
if wrapper.EnableMouse then
|
||||
wrapper:EnableMouse(true)
|
||||
end
|
||||
|
||||
if wrapper.RegisterForClicks then
|
||||
wrapper:RegisterForClicks("LeftButtonUp")
|
||||
end
|
||||
|
||||
if not wrapper.BNPClickForwardInstalled then
|
||||
wrapper:SetScript("OnClick", function()
|
||||
local current = this or wrapper
|
||||
local parent = current and current.plate or plate
|
||||
if parent and parent:IsShown() and parent.Click then
|
||||
parent:Click()
|
||||
end
|
||||
end)
|
||||
wrapper.BNPClickForwardInstalled = true
|
||||
end
|
||||
|
||||
if not wrapper.BNPMouseoverFeedbackInstalled then
|
||||
wrapper:SetScript("OnEnter", function()
|
||||
local current = this or wrapper
|
||||
local parent = current and current.plate or plate
|
||||
SetHoverGlow(parent, true)
|
||||
end)
|
||||
|
||||
wrapper:SetScript("OnLeave", function()
|
||||
local current = this or wrapper
|
||||
local parent = current and current.plate or plate
|
||||
SetHoverGlow(parent, false)
|
||||
end)
|
||||
|
||||
wrapper.BNPMouseoverFeedbackInstalled = true
|
||||
end
|
||||
end
|
||||
|
||||
local function ApplyWrapperOffset(plate, wrapper)
|
||||
if not plate or not wrapper then return end
|
||||
|
||||
local offset = 0
|
||||
if BNP.GetNameplateYOffset then
|
||||
offset = BNP:GetNameplateYOffset()
|
||||
end
|
||||
|
||||
-- Move only the child visual container. The WorldFrame-projected Blizzard
|
||||
-- nameplate itself keeps its original anchor and can continue to be
|
||||
-- repositioned by the client every frame.
|
||||
wrapper:ClearAllPoints()
|
||||
wrapper:SetPoint("TOPLEFT", plate, "TOPLEFT", 0, offset)
|
||||
wrapper:SetPoint("BOTTOMRIGHT", plate, "BOTTOMRIGHT", 0, offset)
|
||||
|
||||
SetYOffsetMouseMode(plate, wrapper, offset)
|
||||
end
|
||||
|
||||
local function EnsureScaleWrapper(plate)
|
||||
if not plate or plate.BNPScaleWrapper then return end
|
||||
|
||||
local originalWidth = plate:GetWidth()
|
||||
local originalHeight = plate:GetHeight()
|
||||
|
||||
local wrapper = CreateFrame("Button", nil, plate)
|
||||
wrapper:SetAllPoints(plate)
|
||||
wrapper.plate = plate
|
||||
wrapper.originalWidth = originalWidth
|
||||
wrapper.originalHeight = originalHeight
|
||||
wrapper.BNPAnchorStates = {}
|
||||
wrapper:EnableMouse(false)
|
||||
|
||||
plate.BNPScaleWrapper = wrapper
|
||||
|
||||
-- Capture the ORIGINAL Blizzard anchors before changing parentage.
|
||||
-- Those stored anchors become BNP's authoritative visual layout whenever
|
||||
-- Y-offset is enabled.
|
||||
if plate.healthbar then
|
||||
local state = CaptureAnchorState(plate.healthbar, plate, wrapper)
|
||||
if state then
|
||||
table.insert(wrapper.BNPAnchorStates, state)
|
||||
end
|
||||
|
||||
plate.healthbar:SetParent(wrapper)
|
||||
RestoreAnchorState(state, wrapper)
|
||||
plate.healthbar:SetFrameLevel(1)
|
||||
end
|
||||
|
||||
local regions = { plate:GetRegions() }
|
||||
local i, object
|
||||
for i, object in pairs(regions) do
|
||||
if object and object.SetParent then
|
||||
local state = CaptureAnchorState(object, plate, wrapper)
|
||||
if state then
|
||||
table.insert(wrapper.BNPAnchorStates, state)
|
||||
end
|
||||
|
||||
object:SetParent(wrapper)
|
||||
RestoreAnchorState(state, wrapper)
|
||||
end
|
||||
end
|
||||
|
||||
ApplyWrapperOffset(plate, wrapper)
|
||||
end
|
||||
|
||||
function BNP:ApplyNameplateScale(plate)
|
||||
if not plate then return end
|
||||
EnsureScaleWrapper(plate)
|
||||
|
||||
local wrapper = plate.BNPScaleWrapper
|
||||
if not wrapper then return end
|
||||
|
||||
local scale = EffectiveScale()
|
||||
wrapper:SetScale(scale)
|
||||
ApplyWrapperOffset(plate, wrapper)
|
||||
|
||||
-- ShaguTweaks also adjusts the original frame bounds so Blizzard's world
|
||||
-- positioning remains correct while the child visuals honor UI scale.
|
||||
plate:SetWidth(wrapper.originalWidth * scale)
|
||||
plate:SetHeight(wrapper.originalHeight * scale)
|
||||
end
|
||||
|
||||
function BNP:ApplyNameplateScaleAll()
|
||||
local plate
|
||||
for plate in pairs(self.plates) do
|
||||
self:ApplyNameplateScale(plate)
|
||||
end
|
||||
end
|
||||
|
||||
function BNP:ApplyNameplateYOffsetAll()
|
||||
local plate
|
||||
for plate in pairs(self.plates or {}) do
|
||||
if plate then
|
||||
self:ApplyNameplateScale(plate)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function BNP:MaintainNameplateYOffset(plate)
|
||||
if not plate or not plate:IsShown() then return end
|
||||
if not self.GetNameplateYOffset or self:GetNameplateYOffset() <= 0 then return end
|
||||
|
||||
EnsureScaleWrapper(plate)
|
||||
|
||||
local wrapper = plate.BNPScaleWrapper
|
||||
if not wrapper then return end
|
||||
|
||||
-- Never rediscover regions through plate:GetRegions() here. Once BNP moves
|
||||
-- Blizzard regions into the wrapper they are no longer guaranteed to be
|
||||
-- returned by plate:GetRegions(). Keep and maintain the original region
|
||||
-- objects captured during wrapper creation instead.
|
||||
local states = wrapper.BNPAnchorStates or {}
|
||||
local i
|
||||
for i = 1, table.getn(states) do
|
||||
RestoreAnchorState(states[i], wrapper)
|
||||
end
|
||||
|
||||
ApplyWrapperOffset(plate, wrapper)
|
||||
end
|
||||
|
||||
function BNP:SetNameplateScale(value)
|
||||
value = tonumber(value)
|
||||
if not value then
|
||||
self:Print("Usage: /bnp scale 0.5-1.5")
|
||||
return
|
||||
end
|
||||
|
||||
value = Clamp(value)
|
||||
BNP_DB = BNP_DB or {}
|
||||
BNP_DB.nameplateScale = value
|
||||
self:ApplyNameplateScaleAll()
|
||||
|
||||
self:Print("Nameplate scale multiplier set to " .. tostring(value) .. ".")
|
||||
end
|
||||
|
||||
function BNP:ResetNameplateScale()
|
||||
BNP_DB = BNP_DB or {}
|
||||
BNP_DB.nameplateScale = DEFAULT_SCALE
|
||||
self:ApplyNameplateScaleAll()
|
||||
self:Print("Nameplate scale multiplier reset to 1.0 (Shagu/UI scale behavior).")
|
||||
end
|
||||
|
||||
if BNP.libnameplate then
|
||||
table.insert(BNP.libnameplate.OnInit, function(plate)
|
||||
local current = plate or this
|
||||
if not current then return end
|
||||
BNP:ApplyNameplateScale(current)
|
||||
end)
|
||||
|
||||
table.insert(BNP.libnameplate.OnShow, function(plate)
|
||||
local current = plate or this
|
||||
if not current then return end
|
||||
BNP:ApplyNameplateScale(current)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user