Add and optimize requested TokensWorth modules
Merge the audited TokensWorth-derived modules and ClassicAPI-focused optimizations into the default branch.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Hide Macro Text"],
|
||||
description = T["Hides macro names on action buttons."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Action Bar"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
local function HideMacroText(button)
|
||||
if not button or not button.GetName then return end
|
||||
|
||||
local name = button:GetName()
|
||||
local text = name and _G[name .. "Name"]
|
||||
if text then text:SetAlpha(0) end
|
||||
end
|
||||
|
||||
for i = 1, 24 do
|
||||
HideMacroText(_G["BonusActionButton" .. i])
|
||||
end
|
||||
|
||||
for i = 1, 12 do
|
||||
HideMacroText(_G["ActionButton" .. i])
|
||||
HideMacroText(_G["MultiBarRightButton" .. i])
|
||||
HideMacroText(_G["MultiBarLeftButton" .. i])
|
||||
HideMacroText(_G["MultiBarBottomLeftButton" .. i])
|
||||
HideMacroText(_G["MultiBarBottomRightButton" .. i])
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local T = ShaguTweaks.T
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Mouseover Right"],
|
||||
description = T["Hide the right actionbar and show it on mouseover."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Action Bar"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
ShaguTweaks.CreateMouseoverActionBar(MultiBarRight, "SHOW_MULTI_ACTIONBAR_3")
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local T = ShaguTweaks.T
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Mouseover Right 2"],
|
||||
description = T["Hide the second right actionbar and show it on mouseover."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Action Bar"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
ShaguTweaks.CreateMouseoverActionBar(MultiBarLeft, "SHOW_MULTI_ACTIONBAR_4")
|
||||
end
|
||||
@@ -0,0 +1,138 @@
|
||||
-- Shared mouseover actionbar helper.
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
|
||||
if not ShaguTweaks.CreateMouseoverActionBar then
|
||||
ShaguTweaks.CreateMouseoverActionBar = function(bar, visibilityFlag)
|
||||
if not bar or not visibilityFlag then return end
|
||||
if bar.ShaguTweaksMouseoverController then return end
|
||||
|
||||
local controller = CreateFrame("Frame", nil, UIParent)
|
||||
local hotspot = CreateFrame("Frame", nil, UIParent)
|
||||
|
||||
controller.bar = bar
|
||||
controller.hotspot = hotspot
|
||||
controller.visibilityFlag = visibilityFlag
|
||||
controller.enabled = false
|
||||
controller.elapsed = 0
|
||||
controller.idle = 0
|
||||
|
||||
bar.ShaguTweaksMouseoverController = controller
|
||||
|
||||
-- One invisible reveal area replaces the original per-button overlay
|
||||
-- frames. It only accepts mouse input while the actionbar is hidden.
|
||||
hotspot:SetAllPoints(bar)
|
||||
hotspot:SetFrameStrata("DIALOG")
|
||||
hotspot:EnableMouse(false)
|
||||
hotspot:Hide()
|
||||
|
||||
local function ReadEnabled()
|
||||
return _G[visibilityFlag] and true or false
|
||||
end
|
||||
|
||||
local function StopWatching()
|
||||
controller:SetScript("OnUpdate", nil)
|
||||
controller.elapsed = 0
|
||||
controller.idle = 0
|
||||
end
|
||||
|
||||
local function StartWatching()
|
||||
if not controller.enabled or not bar:IsShown() then return end
|
||||
|
||||
hotspot:EnableMouse(false)
|
||||
controller.elapsed = 0
|
||||
controller.idle = 0
|
||||
|
||||
controller:SetScript("OnUpdate", function()
|
||||
this.elapsed = this.elapsed + (arg1 or 0)
|
||||
if this.elapsed < .10 then return end
|
||||
|
||||
local step = this.elapsed
|
||||
this.elapsed = 0
|
||||
|
||||
if not this.enabled then
|
||||
StopWatching()
|
||||
hotspot:EnableMouse(false)
|
||||
hotspot:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
if not bar:IsShown() then
|
||||
StopWatching()
|
||||
hotspot:Show()
|
||||
hotspot:EnableMouse(true)
|
||||
return
|
||||
end
|
||||
|
||||
if MouseIsOver(bar) then
|
||||
this.idle = 0
|
||||
return
|
||||
end
|
||||
|
||||
this.idle = this.idle + step
|
||||
if this.idle >= 2 then
|
||||
StopWatching()
|
||||
bar:Hide()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function Sync()
|
||||
controller.enabled = ReadEnabled()
|
||||
|
||||
if not controller.enabled then
|
||||
StopWatching()
|
||||
hotspot:EnableMouse(false)
|
||||
hotspot:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
hotspot:Show()
|
||||
|
||||
if bar:IsShown() then
|
||||
StartWatching()
|
||||
else
|
||||
hotspot:EnableMouse(true)
|
||||
end
|
||||
end
|
||||
|
||||
hotspot:SetScript("OnEnter", function()
|
||||
if not controller.enabled then return end
|
||||
|
||||
hotspot:EnableMouse(false)
|
||||
bar:Show()
|
||||
-- The bar's OnShow script starts the watcher. Avoid a second redundant
|
||||
-- StartWatching() call here.
|
||||
end)
|
||||
|
||||
-- Keep existing scripts intact while observing native/UI-addon visibility
|
||||
-- changes. These wrappers are installed once per bar.
|
||||
local oldOnShow = bar:GetScript("OnShow")
|
||||
bar:SetScript("OnShow", function()
|
||||
if oldOnShow then oldOnShow() end
|
||||
if controller.enabled then StartWatching() end
|
||||
end)
|
||||
|
||||
local oldOnHide = bar:GetScript("OnHide")
|
||||
bar:SetScript("OnHide", function()
|
||||
if oldOnHide then oldOnHide() end
|
||||
|
||||
StopWatching()
|
||||
|
||||
if controller.enabled then
|
||||
hotspot:Show()
|
||||
hotspot:EnableMouse(true)
|
||||
else
|
||||
hotspot:EnableMouse(false)
|
||||
hotspot:Hide()
|
||||
end
|
||||
end)
|
||||
|
||||
controller:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
controller:RegisterEvent("CVAR_UPDATE")
|
||||
controller:SetScript("OnEvent", Sync)
|
||||
|
||||
Sync()
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local hooksecurefunc = ShaguTweaks.hooksecurefunc
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Cursor Tooltip"],
|
||||
description = T["Attaches default tooltips to the cursor."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Tooltip & Items"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
if ShaguTweaks.CursorTooltipInstalled then return end
|
||||
ShaguTweaks.CursorTooltipInstalled = true
|
||||
|
||||
-- Keep the native helper for non-GameTooltip callers. The feature only
|
||||
-- needs to move the normal world/UI GameTooltip and should not unexpectedly
|
||||
-- change other tooltip frames that may reuse the same helper.
|
||||
local originalDefaultAnchor = ShaguTweaks.CursorTooltipOriginalDefaultAnchor
|
||||
or _G.GameTooltip_SetDefaultAnchor
|
||||
|
||||
ShaguTweaks.CursorTooltipOriginalDefaultAnchor = originalDefaultAnchor
|
||||
|
||||
local cursor = CreateFrame("Frame", nil, UIParent)
|
||||
cursor:SetWidth(1)
|
||||
cursor:SetHeight(1)
|
||||
cursor:Hide()
|
||||
|
||||
local following = false
|
||||
local lastX, lastY, lastScale
|
||||
|
||||
local function UpdateCursor(force)
|
||||
local scale = UIParent:GetEffectiveScale()
|
||||
if not scale or scale == 0 then scale = UIParent:GetScale() end
|
||||
if not scale or scale == 0 then scale = 1 end
|
||||
|
||||
local x, y = GetCursorPosition()
|
||||
|
||||
-- GetCursorPosition is cheap and required for following the pointer, but
|
||||
-- avoid a frame-layout operation while the mouse is completely still.
|
||||
if not force and x == lastX and y == lastY and scale == lastScale then
|
||||
return
|
||||
end
|
||||
|
||||
lastX, lastY, lastScale = x, y, scale
|
||||
|
||||
-- Reusing the same CENTER anchor updates it in place; ClearAllPoints every
|
||||
-- rendered frame is unnecessary.
|
||||
cursor:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x / scale, y / scale)
|
||||
end
|
||||
|
||||
cursor:SetScript("OnUpdate", function()
|
||||
if not following or not GameTooltip:IsShown() then
|
||||
this:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
UpdateCursor(false)
|
||||
end)
|
||||
|
||||
function _G.GameTooltip_SetDefaultAnchor(tooltip, parent)
|
||||
if tooltip ~= GameTooltip then
|
||||
return originalDefaultAnchor(tooltip, parent)
|
||||
end
|
||||
|
||||
tooltip:SetOwner(parent or UIParent, "ANCHOR_NONE")
|
||||
tooltip:ClearAllPoints()
|
||||
|
||||
-- Position once before Show() so there is no first-frame jump from the
|
||||
-- cursor frame's default origin.
|
||||
UpdateCursor(true)
|
||||
|
||||
tooltip:SetPoint("BOTTOMLEFT", cursor, "TOPRIGHT", 12, 12)
|
||||
tooltip:SetClampedToScreen(true)
|
||||
tooltip.default = 1
|
||||
|
||||
following = true
|
||||
end
|
||||
|
||||
-- Default anchoring normally happens before GameTooltip:Show(). Start the
|
||||
-- per-frame cursor tracker only once the tooltip is actually visible.
|
||||
hooksecurefunc(GameTooltip, "Show", function()
|
||||
if not following then return end
|
||||
|
||||
UpdateCursor(true)
|
||||
cursor:Show()
|
||||
end)
|
||||
|
||||
hooksecurefunc(GameTooltip, "Hide", function()
|
||||
following = false
|
||||
cursor:Hide()
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Hide Combat Tooltip"],
|
||||
description = T["Hides the tooltip in combat. Hold Shift to show it temporarily."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Tooltip & Items"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
if ShaguTweaks.HideCombatTooltipInstalled then return end
|
||||
ShaguTweaks.HideCombatTooltipInstalled = true
|
||||
|
||||
local controller = CreateFrame("Frame", nil, UIParent)
|
||||
local inCombat = UnitAffectingCombat("player") and true or false
|
||||
local shiftDown = API.IsShiftKeyDown() and true or false
|
||||
local guardActive = false
|
||||
local elapsed = 0
|
||||
|
||||
local function Apply()
|
||||
if not inCombat then
|
||||
if GameTooltip:GetAlpha() ~= 1 then
|
||||
GameTooltip:SetAlpha(1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local alpha = shiftDown and 1 or 0
|
||||
if GameTooltip:GetAlpha() ~= alpha then
|
||||
GameTooltip:SetAlpha(alpha)
|
||||
end
|
||||
end
|
||||
|
||||
local function GuardTick()
|
||||
elapsed = elapsed + (arg1 or 0)
|
||||
if elapsed < .05 then return end
|
||||
elapsed = 0
|
||||
|
||||
-- ClassicAPI provides modifier events, so normal clients don't need to
|
||||
-- query Shift here. This fallback is only for old environments.
|
||||
if not API.modifierstate then
|
||||
shiftDown = API.IsShiftKeyDown() and true or false
|
||||
end
|
||||
|
||||
Apply()
|
||||
end
|
||||
|
||||
local function StartGuard()
|
||||
if guardActive or not inCombat or not GameTooltip:IsShown() then return end
|
||||
|
||||
guardActive = true
|
||||
elapsed = 0
|
||||
controller:SetScript("OnUpdate", GuardTick)
|
||||
end
|
||||
|
||||
local function StopGuard()
|
||||
if not guardActive then return end
|
||||
|
||||
guardActive = false
|
||||
elapsed = 0
|
||||
controller:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
local function RefreshShift()
|
||||
shiftDown = API.IsShiftKeyDown() and true or false
|
||||
|
||||
if inCombat and GameTooltip:IsShown() then
|
||||
Apply()
|
||||
StartGuard()
|
||||
end
|
||||
end
|
||||
|
||||
local function EnterCombat()
|
||||
inCombat = true
|
||||
shiftDown = API.IsShiftKeyDown() and true or false
|
||||
|
||||
if GameTooltip:IsShown() then
|
||||
Apply()
|
||||
StartGuard()
|
||||
end
|
||||
end
|
||||
|
||||
local function LeaveCombat()
|
||||
inCombat = false
|
||||
StopGuard()
|
||||
Apply()
|
||||
end
|
||||
|
||||
-- Vanilla/Turtle can restore GameTooltip alpha internally while updating a
|
||||
-- visible unit tooltip. A purely event-driven implementation therefore does
|
||||
-- not stay hidden reliably. The guard below exists only while BOTH combat
|
||||
-- and an actual GameTooltip are active, and is throttled to 20 Hz instead of
|
||||
-- running the full upstream logic every rendered frame.
|
||||
local oldOnShow = GameTooltip:GetScript("OnShow")
|
||||
GameTooltip:SetScript("OnShow", function()
|
||||
if oldOnShow then oldOnShow() end
|
||||
|
||||
if inCombat then
|
||||
shiftDown = API.IsShiftKeyDown() and true or false
|
||||
Apply()
|
||||
StartGuard()
|
||||
else
|
||||
Apply()
|
||||
end
|
||||
end)
|
||||
|
||||
local oldOnHide = GameTooltip:GetScript("OnHide")
|
||||
GameTooltip:SetScript("OnHide", function()
|
||||
if oldOnHide then oldOnHide() end
|
||||
StopGuard()
|
||||
end)
|
||||
|
||||
controller:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
controller:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||
controller:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
|
||||
if API.modifierstate then
|
||||
controller:RegisterEvent("MODIFIER_STATE_CHANGED")
|
||||
end
|
||||
|
||||
controller:SetScript("OnEvent", function()
|
||||
if event == "PLAYER_REGEN_DISABLED" then
|
||||
EnterCombat()
|
||||
elseif event == "PLAYER_REGEN_ENABLED" then
|
||||
LeaveCombat()
|
||||
elseif event == "MODIFIER_STATE_CHANGED" then
|
||||
RefreshShift()
|
||||
elseif event == "PLAYER_ENTERING_WORLD" then
|
||||
if UnitAffectingCombat("player") then
|
||||
EnterCombat()
|
||||
else
|
||||
LeaveCombat()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if inCombat then
|
||||
EnterCombat()
|
||||
else
|
||||
LeaveCombat()
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,283 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Movable Unit Frames Extended"],
|
||||
description = T["Party frames, minimap, buffs, weapon buffs and debuffs can be moved while Ctrl+Shift are held."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Unit Frames"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
ShaguTweaks_config = ShaguTweaks_config or {}
|
||||
ShaguTweaks_config["MoveUnitframesExtended"] = ShaguTweaks_config["MoveUnitframesExtended"] or {}
|
||||
|
||||
local movedb = ShaguTweaks_config["MoveUnitframesExtended"]
|
||||
local unlocked = false
|
||||
local states = {}
|
||||
|
||||
-- Turtle WoW places the first debuff at BuffButton32 in the layout this
|
||||
-- module targets. BuffButton16 from the original mod is intentionally not
|
||||
-- used here.
|
||||
local targets = {
|
||||
{ name = "PartyMemberFrame1" },
|
||||
{ name = "PartyMemberFrame2" },
|
||||
{ name = "PartyMemberFrame3" },
|
||||
{ name = "PartyMemberFrame4" },
|
||||
{ name = "Minimap", moveParent = true },
|
||||
{ name = "BuffButton0" },
|
||||
{ name = "BuffButton32" },
|
||||
{ name = "TempEnchant1" },
|
||||
}
|
||||
|
||||
local function Resolve(target)
|
||||
local handle = _G[target.name]
|
||||
if not handle then return end
|
||||
|
||||
local moveFrame = target.moveParent and handle:GetParent() or handle
|
||||
if not moveFrame then return end
|
||||
|
||||
return handle, moveFrame
|
||||
end
|
||||
|
||||
local function PositionKey(target, moveFrame)
|
||||
return (moveFrame.GetName and moveFrame:GetName()) or target.name
|
||||
end
|
||||
|
||||
local function SavePosition(target, moveFrame)
|
||||
if not moveFrame then
|
||||
local _, resolved = Resolve(target)
|
||||
moveFrame = resolved
|
||||
end
|
||||
if not moveFrame then return end
|
||||
|
||||
local left = moveFrame:GetLeft()
|
||||
local top = moveFrame:GetTop()
|
||||
if not left or not top then return end
|
||||
|
||||
movedb[PositionKey(target, moveFrame)] = { left, top }
|
||||
end
|
||||
|
||||
local function RestorePosition(target)
|
||||
local _, moveFrame = Resolve(target)
|
||||
if not moveFrame then return end
|
||||
|
||||
local pos = movedb[PositionKey(target, moveFrame)]
|
||||
if not pos or not pos[1] or not pos[2] then return end
|
||||
|
||||
moveFrame:SetMovable(true)
|
||||
if moveFrame.SetUserPlaced then moveFrame:SetUserPlaced(true) end
|
||||
moveFrame:ClearAllPoints()
|
||||
moveFrame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", pos[1], pos[2])
|
||||
end
|
||||
|
||||
local grid
|
||||
local function CreateGrid()
|
||||
if grid then return grid end
|
||||
|
||||
grid = CreateFrame("Frame", nil, WorldFrame)
|
||||
grid:SetAllPoints(WorldFrame)
|
||||
grid:Hide()
|
||||
|
||||
local size = 1
|
||||
local width = GetScreenWidth()
|
||||
local height = GetScreenHeight()
|
||||
local ratio = width / height
|
||||
local adjustedHeight = height * ratio
|
||||
local wStep = width / 64
|
||||
local hStep = adjustedHeight / 64
|
||||
|
||||
for i = 0, 64 do
|
||||
local line = grid:CreateTexture(nil, i == 32 and "BORDER" or "BACKGROUND")
|
||||
if i == 32 then
|
||||
line:SetTexture(.8, .6, 0)
|
||||
else
|
||||
line:SetTexture(0, 0, 0, .2)
|
||||
end
|
||||
line:SetPoint("TOPLEFT", grid, "TOPLEFT", i * wStep - (size / 2), 0)
|
||||
line:SetPoint("BOTTOMRIGHT", grid, "BOTTOMLEFT", i * wStep + (size / 2), 0)
|
||||
end
|
||||
|
||||
local rows = floor(height / hStep)
|
||||
local middle = floor(rows / 2)
|
||||
|
||||
for i = 1, rows do
|
||||
local line = grid:CreateTexture(nil, i == middle and "BORDER" or "BACKGROUND")
|
||||
if i == middle then
|
||||
line:SetTexture(.8, .6, 0)
|
||||
else
|
||||
line:SetTexture(0, 0, 0, .2)
|
||||
end
|
||||
line:SetPoint("TOPLEFT", grid, "TOPLEFT", 0, -(i * hStep) + (size / 2))
|
||||
line:SetPoint("BOTTOMRIGHT", grid, "TOPRIGHT", 0, -(i * hStep + size / 2))
|
||||
end
|
||||
|
||||
return grid
|
||||
end
|
||||
|
||||
local function UnlockTarget(index, target)
|
||||
local handle, moveFrame = Resolve(target)
|
||||
if not handle or not moveFrame then return end
|
||||
|
||||
states[index] = states[index] or {}
|
||||
local state = states[index]
|
||||
if state.active then return end
|
||||
|
||||
state.active = true
|
||||
state.dragged = false
|
||||
state.handle = handle
|
||||
state.moveFrame = moveFrame
|
||||
state.onDragStart = handle:GetScript("OnDragStart")
|
||||
state.onDragStop = handle:GetScript("OnDragStop")
|
||||
|
||||
if handle.IsMouseEnabled then
|
||||
state.mouseEnabled = handle:IsMouseEnabled() and true or false
|
||||
else
|
||||
state.mouseEnabled = nil
|
||||
end
|
||||
|
||||
if moveFrame.IsMovable then
|
||||
state.movable = moveFrame:IsMovable() and true or false
|
||||
else
|
||||
state.movable = nil
|
||||
end
|
||||
|
||||
if moveFrame.IsUserPlaced then
|
||||
state.userPlaced = moveFrame:IsUserPlaced() and true or false
|
||||
else
|
||||
state.userPlaced = nil
|
||||
end
|
||||
|
||||
moveFrame:SetMovable(true)
|
||||
handle:EnableMouse(true)
|
||||
handle:RegisterForDrag("LeftButton")
|
||||
|
||||
handle:SetScript("OnDragStart", function()
|
||||
state.dragged = true
|
||||
|
||||
if moveFrame.SetUserPlaced then
|
||||
moveFrame:SetUserPlaced(true)
|
||||
end
|
||||
|
||||
moveFrame:StartMoving()
|
||||
end)
|
||||
|
||||
handle:SetScript("OnDragStop", function()
|
||||
moveFrame:StopMovingOrSizing()
|
||||
|
||||
if state.dragged then
|
||||
SavePosition(target, moveFrame)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function LockTarget(index, target)
|
||||
local state = states[index]
|
||||
if not state or not state.active then return end
|
||||
|
||||
local handle = state.handle
|
||||
local moveFrame = state.moveFrame
|
||||
|
||||
if moveFrame then
|
||||
moveFrame:StopMovingOrSizing()
|
||||
|
||||
-- Only persist an anchor if the user actually dragged this frame. The
|
||||
-- previous test version saved every frame whenever Ctrl+Shift was
|
||||
-- released, which could turn untouched default-managed UI elements into
|
||||
-- permanently absolute-positioned frames.
|
||||
if state.dragged then
|
||||
SavePosition(target, moveFrame)
|
||||
end
|
||||
|
||||
if state.movable ~= nil then
|
||||
moveFrame:SetMovable(state.movable)
|
||||
end
|
||||
|
||||
if not state.dragged
|
||||
and state.userPlaced ~= nil
|
||||
and moveFrame.SetUserPlaced then
|
||||
moveFrame:SetUserPlaced(state.userPlaced)
|
||||
end
|
||||
end
|
||||
|
||||
if handle then
|
||||
handle:SetScript("OnDragStart", state.onDragStart)
|
||||
handle:SetScript("OnDragStop", state.onDragStop)
|
||||
|
||||
if state.mouseEnabled ~= nil then
|
||||
handle:EnableMouse(state.mouseEnabled)
|
||||
end
|
||||
end
|
||||
|
||||
state.active = false
|
||||
end
|
||||
|
||||
local function UnlockAll()
|
||||
if unlocked then return end
|
||||
unlocked = true
|
||||
|
||||
for i, target in ipairs(targets) do
|
||||
UnlockTarget(i, target)
|
||||
end
|
||||
|
||||
CreateGrid():Show()
|
||||
end
|
||||
|
||||
local function LockAll()
|
||||
if not unlocked then return end
|
||||
|
||||
for i, target in ipairs(targets) do
|
||||
LockTarget(i, target)
|
||||
end
|
||||
|
||||
if grid then grid:Hide() end
|
||||
unlocked = false
|
||||
end
|
||||
|
||||
local function UpdateLockState()
|
||||
if API.IsShiftKeyDown() and API.IsControlKeyDown() then
|
||||
UnlockAll()
|
||||
else
|
||||
LockAll()
|
||||
end
|
||||
end
|
||||
|
||||
local events = CreateFrame("Frame")
|
||||
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
|
||||
if API.modifierstate then
|
||||
events:RegisterEvent("MODIFIER_STATE_CHANGED")
|
||||
end
|
||||
|
||||
events:SetScript("OnEvent", function()
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
for _, target in ipairs(targets) do
|
||||
RestorePosition(target)
|
||||
end
|
||||
end
|
||||
|
||||
UpdateLockState()
|
||||
end)
|
||||
|
||||
-- ClassicAPI supplies MODIFIER_STATE_CHANGED. Only old/fallback environments
|
||||
-- use a throttled state check.
|
||||
if not API.modifierstate then
|
||||
events.elapsed = 0
|
||||
events:SetScript("OnUpdate", function()
|
||||
this.elapsed = this.elapsed + (arg1 or 0)
|
||||
if this.elapsed < .10 then return end
|
||||
this.elapsed = 0
|
||||
UpdateLockState()
|
||||
end)
|
||||
end
|
||||
|
||||
for _, target in ipairs(targets) do
|
||||
RestorePosition(target)
|
||||
end
|
||||
|
||||
UpdateLockState()
|
||||
end
|
||||
@@ -0,0 +1,140 @@
|
||||
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||
|
||||
local _G = ShaguTweaks.GetGlobalEnv()
|
||||
local T = ShaguTweaks.T
|
||||
local API = ShaguTweaks.API
|
||||
|
||||
local module = ShaguTweaks:register({
|
||||
title = T["Unit Frame Abbreviated Names"],
|
||||
description = T["Abbreviates long target and target-of-target names."],
|
||||
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||
category = T["Unit Frames"],
|
||||
enabled = nil,
|
||||
})
|
||||
|
||||
module.enable = function(self)
|
||||
local maxLength = 15
|
||||
local cache = {}
|
||||
|
||||
local function AbbrevWord(word)
|
||||
return string.sub(word, 1, 1) .. ". "
|
||||
end
|
||||
|
||||
local function GetShortName(unit)
|
||||
local name = UnitName(unit)
|
||||
if not name then
|
||||
cache[unit] = nil
|
||||
return
|
||||
end
|
||||
|
||||
local cached = cache[unit]
|
||||
if cached and cached.raw == name then
|
||||
return cached.short
|
||||
end
|
||||
|
||||
local short = name
|
||||
|
||||
if strlen(short) > maxLength then
|
||||
short = string.gsub(short, "^(%S+) ", AbbrevWord)
|
||||
end
|
||||
|
||||
if strlen(short) > maxLength then
|
||||
short = string.gsub(short, "(%S+) ", AbbrevWord)
|
||||
end
|
||||
|
||||
cache[unit] = {
|
||||
raw = name,
|
||||
short = short,
|
||||
}
|
||||
|
||||
return short
|
||||
end
|
||||
|
||||
local function GetNameText(frame)
|
||||
if not frame then return end
|
||||
if frame.name then return frame.name end
|
||||
|
||||
if frame.GetName then
|
||||
local frameName = frame:GetName()
|
||||
if frameName then
|
||||
return _G[frameName .. "Name"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateFrame(frame, unit)
|
||||
local text = GetNameText(frame)
|
||||
local name = GetShortName(unit)
|
||||
if not text or not name then return end
|
||||
|
||||
-- Avoid forcing a FontString update when the displayed value is already
|
||||
-- correct. This matters most for the legacy 250 ms target-of-target
|
||||
-- fallback.
|
||||
if not text.GetText or text:GetText() ~= name then
|
||||
text:SetText(name)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateTarget()
|
||||
UpdateFrame(TargetFrame, "target")
|
||||
end
|
||||
|
||||
local function UpdateTargetTarget()
|
||||
if TargetofTargetFrame then
|
||||
UpdateFrame(TargetofTargetFrame, "targettarget")
|
||||
end
|
||||
end
|
||||
|
||||
local function EventValid(name)
|
||||
return API.eventutils
|
||||
and _G.C_EventUtils
|
||||
and _G.C_EventUtils.IsEventValid
|
||||
and _G.C_EventUtils.IsEventValid(name)
|
||||
end
|
||||
|
||||
local events = CreateFrame("Frame")
|
||||
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
events:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
|
||||
local hasUnitTarget = EventValid("UNIT_TARGET")
|
||||
local hasUnitName = EventValid("UNIT_NAME_UPDATE")
|
||||
|
||||
if hasUnitTarget then events:RegisterEvent("UNIT_TARGET") end
|
||||
if hasUnitName then events:RegisterEvent("UNIT_NAME_UPDATE") end
|
||||
|
||||
events:SetScript("OnEvent", function()
|
||||
if event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_TARGET_CHANGED" then
|
||||
UpdateTarget()
|
||||
UpdateTargetTarget()
|
||||
elseif event == "UNIT_TARGET" then
|
||||
if arg1 == "target" then UpdateTargetTarget() end
|
||||
elseif event == "UNIT_NAME_UPDATE" then
|
||||
if arg1 == "target" then
|
||||
UpdateTarget()
|
||||
elseif arg1 == "targettarget" then
|
||||
UpdateTargetTarget()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ClassicAPI normally provides UNIT_TARGET. Keep a lightweight Vanilla
|
||||
-- fallback only when that event isn't available instead of running every
|
||||
-- rendered frame like the original module.
|
||||
if not hasUnitTarget then
|
||||
local fallback = CreateFrame("Frame")
|
||||
fallback.elapsed = 0
|
||||
|
||||
fallback:SetScript("OnUpdate", function()
|
||||
this.elapsed = this.elapsed + (arg1 or 0)
|
||||
if this.elapsed < .25 then return end
|
||||
this.elapsed = 0
|
||||
|
||||
if UnitName("targettarget") then
|
||||
UpdateTargetTarget()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
UpdateTarget()
|
||||
UpdateTargetTarget()
|
||||
end
|
||||
Reference in New Issue
Block a user