forked from Dusk/ShaguTweaks-ClassicAPI
250 lines
12 KiB
Lua
250 lines
12 KiB
Lua
local _G = ShaguTweaks.GetGlobalEnv()
|
|
local T = ShaguTweaks.T
|
|
local API = ShaguTweaks.API
|
|
local module = ShaguTweaks:register({
|
|
title = T["Hide Player Frame Resources"],
|
|
description = T["Hides the original player health and power bars, leaving the clean round portrait and name. Hold Ctrl+Shift+Alt to drag the name independently; right-click with those keys held to reset it. Personal Resource Display is independent."],
|
|
expansions = { ["vanilla"] = true }, category = T["Unit Frames"], enabled = nil,
|
|
})
|
|
local function MoveRegion(region, holder, x, y)
|
|
if not region then return end
|
|
region:SetParent(holder)
|
|
region:ClearAllPoints()
|
|
region:SetPoint("TOPLEFT", holder, "TOPLEFT", x, y)
|
|
end
|
|
module.enable = function(self)
|
|
if self.scheduled then return end
|
|
self.scheduled = true
|
|
local function Setup()
|
|
if self.installed or not PlayerFrame or not PlayerPortrait or not PlayerFrameTexture then return end
|
|
if not PlayerPortrait:GetLeft() or not PlayerFrame:GetLeft() then return end
|
|
self.installed = true
|
|
local width = PlayerFrameHealthBar:GetWidth()
|
|
local portraitLeft, portraitTop = PlayerPortrait:GetLeft() - 8, PlayerPortrait:GetTop() + 4
|
|
local function Holder(key, w, h, x, y)
|
|
local holder = CreateFrame("Frame", "ShaguTweaksPlayer" .. key, PlayerFrame)
|
|
holder:SetWidth(w); holder:SetHeight(h)
|
|
holder:SetFrameLevel(PlayerFrame:GetFrameLevel() + 3)
|
|
holder:SetPoint("TOPLEFT", PlayerFrame, "TOPLEFT", x - PlayerFrame:GetLeft(), y - PlayerFrame:GetTop())
|
|
return holder
|
|
end
|
|
local portrait = Holder("Portrait", 80, 80, portraitLeft, portraitTop)
|
|
local name = Holder("Name", width + 8, 23, portraitLeft + 85, portraitTop - 14)
|
|
ShaguTweaks.PlayerFrameResourcesLayout = { portrait = portrait, name = name }
|
|
ShaguTweaks_config.PlayerFrameResources = ShaguTweaks_config.PlayerFrameResources or {}
|
|
local positions = ShaguTweaks_config.PlayerFrameResources
|
|
local nameX, nameY = portraitLeft + 85 - PlayerFrame:GetLeft(), portraitTop - 14 - PlayerFrame:GetTop()
|
|
local function PositionName()
|
|
name:ClearAllPoints()
|
|
if positions.Name then
|
|
name:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", positions.Name.x, positions.Name.y)
|
|
else
|
|
name:SetPoint("TOPLEFT", PlayerFrame, "TOPLEFT", nameX, nameY)
|
|
end
|
|
end
|
|
local dragging, dropped
|
|
local function StopName()
|
|
if not dragging then return end
|
|
name:StopMovingOrSizing()
|
|
name:SetUserPlaced(false)
|
|
dragging, dropped = nil, true
|
|
local x, y = name:GetLeft(), name:GetTop()
|
|
if x and y then positions.Name = { x = x, y = y } end
|
|
PositionName()
|
|
end
|
|
name:SetMovable(true)
|
|
name:SetClampedToScreen(true)
|
|
name:EnableMouse(true)
|
|
name:RegisterForDrag("LeftButton")
|
|
name:SetScript("OnDragStart", function()
|
|
if not API.AreMoveModifiersDown() then return end
|
|
dragging, dropped = true, nil
|
|
name:StartMoving()
|
|
end)
|
|
name:SetScript("OnDragStop", StopName)
|
|
name:SetScript("OnHide", StopName)
|
|
name:SetScript("OnMouseUp", function()
|
|
if API.AreMoveModifiersDown() and arg1 == "RightButton" then
|
|
StopName()
|
|
positions.Name, dropped = nil, nil
|
|
PositionName()
|
|
elseif dragging then
|
|
StopName()
|
|
dropped = nil
|
|
elseif dropped then
|
|
dropped = nil
|
|
elseif PlayerFrame_OnClick then
|
|
-- Retain native unit clicks even after the name is moved away.
|
|
local previous = this
|
|
this = PlayerFrame
|
|
PlayerFrame_OnClick(arg1)
|
|
this = previous
|
|
end
|
|
end)
|
|
PositionName()
|
|
-- Split the native artwork before changing its source texture's anchors.
|
|
-- Preserve its UV orientation (the player's stock artwork is mirrored).
|
|
local art = PlayerFrameTexture
|
|
local path = art:GetTexture()
|
|
local u, v, unused, bottom, right = art:GetTexCoord()
|
|
local artWidth, artHeight = PlayerFrame:GetWidth(), PlayerFrame:GetHeight()
|
|
local r, g, b, a = art:GetVertexColor()
|
|
local function Crop(holder, x, y, w, h)
|
|
local texture = holder:CreateTexture(nil, "OVERLAY")
|
|
texture:SetTexture(path)
|
|
texture:SetTexCoord(u + (right-u)*x/artWidth, u + (right-u)*(x+w)/artWidth,
|
|
v + (bottom-v)*y/artHeight, v + (bottom-v)*(y+h)/artHeight)
|
|
texture:SetAllPoints(holder)
|
|
texture:SetVertexColor(r, g, b, a)
|
|
return texture
|
|
end
|
|
-- Keep the native level badge on the left. Complete the right side from
|
|
-- the clean upper-left quadrant, leaving space for the live resting icon
|
|
-- without mirroring a second level badge into the artwork. The native
|
|
-- resting/combat icon shares the original left badge's position.
|
|
portrait.art = Crop(portrait, 34, 8, 40, 72)
|
|
portrait.artRight = Crop(portrait, 74, 8, -40, 36)
|
|
portrait.artBottomRight = Crop(portrait, 74, 44, -40, -36)
|
|
local function Piece(texture, x, y, height)
|
|
texture:ClearAllPoints()
|
|
texture:SetPoint("TOPLEFT", portrait, "TOPLEFT", x, y)
|
|
texture:SetWidth(40)
|
|
texture:SetHeight(height)
|
|
end
|
|
Piece(portrait.art, 0, 0, 72)
|
|
Piece(portrait.artRight, 40, 0, 36)
|
|
Piece(portrait.artBottomRight, 40, -36, 36)
|
|
|
|
-- The native lower-left quadrant includes a dark rectangular shadow
|
|
-- beside the level badge. Use the same clean quadrant as the lower right,
|
|
-- then restore only the badge circle, not its surrounding shadow.
|
|
portrait.badge = Crop(portrait, 37, 50, 32, 32)
|
|
portrait.badge:ClearAllPoints()
|
|
portrait.badge:SetPoint("TOPLEFT", portrait, "TOPLEFT", 3, -42)
|
|
portrait.badge:SetWidth(32)
|
|
portrait.badge:SetHeight(32)
|
|
if type(portrait.badge.SetMask) == "function" then
|
|
portrait.art:SetTexCoord(u + (right-u)*34/artWidth, u + (right-u)*74/artWidth,
|
|
v + (bottom-v)*8/artHeight, v + (bottom-v)*44/artHeight)
|
|
Piece(portrait.art, 0, 0, 36)
|
|
portrait.artBottomLeft = Crop(portrait, 34, 44, 40, -36)
|
|
Piece(portrait.artBottomLeft, 0, -36, 36)
|
|
portrait.badge:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
|
|
-- Keep the badge above every ring piece but below the number/state icons.
|
|
portrait.badgeOverlay = CreateFrame("Frame", nil, portrait)
|
|
portrait.badgeOverlay:SetAllPoints(portrait)
|
|
portrait.badgeOverlay:SetFrameLevel(portrait:GetFrameLevel() + 1)
|
|
portrait.badge:SetParent(portrait.badgeOverlay)
|
|
else
|
|
-- Older clients retain the original left half and its native badge.
|
|
portrait.badge:Hide()
|
|
end
|
|
|
|
-- The combined frame texture has a portrait arc at the left ends of its
|
|
-- bars. Give the separate name strip a rounded Blizzard border.
|
|
local border = {
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
edgeSize = 12, tile = true, tileSize = 8,
|
|
insets = { left = 3, right = 3, top = 3, bottom = 3 },
|
|
}
|
|
local color = ShaguTweaks.UIBorder
|
|
name:SetBackdrop(border)
|
|
name:SetBackdropBorderColor(color and color.r or 1, color and color.g or 1,
|
|
color and color.b or 1, 1)
|
|
|
|
-- Keep status/role indicators with the portrait. Their native event
|
|
-- handlers and parent visibility continue running unchanged.
|
|
local indicators = { "PlayerHitIndicator", "PlayerPVPIcon", "PlayerPVPIconHitArea",
|
|
"PlayerLeaderIcon", "PlayerMasterIcon", "PlayerRestIcon", "PlayerAttackIcon",
|
|
"PlayerAttackBackground", "PlayerStatusGlow", "PlayerFrameGroupIndicator" }
|
|
local indicatorPoints = {}
|
|
for i = 1, table.getn(indicators) do
|
|
local region = _G[indicators[i]]
|
|
if region and region:GetLeft() and region:GetTop() then
|
|
indicatorPoints[i] = { region:GetLeft() - portraitLeft, region:GetTop() - portraitTop }
|
|
end
|
|
end
|
|
-- Snapshot first: some indicators are anchored to other indicators.
|
|
for i = 1, table.getn(indicators) do
|
|
local point = indicatorPoints[i]
|
|
if point then MoveRegion(_G[indicators[i]], portrait, point[1], point[2]) end
|
|
end
|
|
MoveRegion(PlayerPortrait, portrait, 8, -4)
|
|
if _G.PlayerLevelText then
|
|
-- Put the native text above the ring and portrait, centered over the
|
|
-- native left-hand badge. The stock level-update code keeps owning it.
|
|
local levelX, levelY = 19, -58
|
|
if PlayerLevelText.GetCenter then
|
|
local x, y = PlayerLevelText:GetCenter()
|
|
if x and y then levelX, levelY = x - portraitLeft, y - portraitTop end
|
|
end
|
|
portrait.levelOverlay = CreateFrame("Frame", nil, portrait)
|
|
portrait.levelOverlay:SetAllPoints(portrait)
|
|
portrait.levelOverlay:SetFrameLevel(portrait:GetFrameLevel() + 5)
|
|
PlayerLevelText:SetParent(portrait.levelOverlay)
|
|
PlayerLevelText:ClearAllPoints()
|
|
PlayerLevelText:SetPoint("CENTER", portrait.levelOverlay, "TOPLEFT", levelX, levelY)
|
|
PlayerLevelText:SetDrawLayer("BACKGROUND")
|
|
PlayerLevelText:SetAlpha(1)
|
|
PlayerLevelText:SetText(UnitLevel("player"))
|
|
PlayerLevelText:Show()
|
|
-- Keep the level above the ring but BELOW its native state icons.
|
|
-- Their existing Show/Hide logic then covers the number while resting
|
|
-- or in combat and reveals it again without adding another event loop.
|
|
for _, key in ipairs({ "PlayerRestIcon", "PlayerAttackIcon", "PlayerAttackBackground", "PlayerStatusGlow" }) do
|
|
local indicator = _G[key]
|
|
if indicator then indicator:SetParent(portrait.levelOverlay) end
|
|
end
|
|
end
|
|
local playerName = PlayerFrame.name or _G.PlayerName
|
|
if playerName then
|
|
playerName:SetParent(name)
|
|
playerName:ClearAllPoints()
|
|
playerName:SetPoint("CENTER", name, "CENTER", 0, 0)
|
|
end
|
|
-- Big Health deliberately hides the stock name background. Keep its
|
|
-- color source for that module, but draw a separate class strip here.
|
|
name.classBackground = name:CreateTexture(nil, "BACKGROUND")
|
|
name.classBackground:SetPoint("TOPLEFT", name, "TOPLEFT", 4, -3)
|
|
name.classBackground:SetPoint("BOTTOMRIGHT", name, "BOTTOMRIGHT", -4, 3)
|
|
local healthTexture = PlayerFrameHealthBar:GetStatusBarTexture()
|
|
name.classBackground:SetTexture(healthTexture and healthTexture:GetTexture()
|
|
or "Interface\\TargetingFrame\\UI-StatusBar")
|
|
local _, class = UnitClass("player")
|
|
local palette = ShaguTweaks.ModernClassColors or RAID_CLASS_COLORS
|
|
local classColor = palette and palette[class]
|
|
local cr, cg, cb = PlayerFrameHealthBar:GetStatusBarColor()
|
|
name.classBackground:SetVertexColor(classColor and classColor.r or cr,
|
|
classColor and classColor.g or cg, classColor and classColor.b or cb, 1)
|
|
if ShaguTweaks_config[T["Hide Player Name"]] == 1 then name:Hide() end
|
|
|
|
-- Keep native bar objects and events alive. Copies may still mirror them.
|
|
local function Suppress(region)
|
|
if not region then return end
|
|
local setAlpha = region.SetAlpha
|
|
setAlpha(region, 0)
|
|
ShaguTweaks.hooksecurefunc(region, "SetAlpha", function(object) setAlpha(object, 0) end)
|
|
end
|
|
Suppress(PlayerFrameTexture)
|
|
Suppress(_G.PlayerFrameBackground)
|
|
Suppress(_G.PlayerFrameNameBackground)
|
|
Suppress(PlayerFrameHealthBar)
|
|
Suppress(PlayerFrameManaBar)
|
|
Suppress(_G.PlayerFrameAlternatePowerBar)
|
|
if PlayerStatusTexture then
|
|
MoveRegion(PlayerStatusTexture, portrait, 1, 0)
|
|
local function CropStatus()
|
|
PlayerStatusTexture:SetTexCoord(0, 72/256, 0, 66/128)
|
|
PlayerStatusTexture:SetWidth(72)
|
|
PlayerStatusTexture:SetHeight(66)
|
|
end
|
|
if type(PlayerStatusTexture.SetMask) == "function" then
|
|
PlayerStatusTexture:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
|
|
end
|
|
ShaguTweaks.hooksecurefunc("PlayerFrame_UpdateStatus", CropStatus)
|
|
CropStatus()
|
|
end
|
|
end
|
|
API.AfterWorldReady(Setup, true)
|
|
end
|