Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion API.lua
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ end
-- EXTERNAL HIGHLIGHTS
-- Allows external addons to highlight specific unit frames with
-- a colored border overlay. These are separate from DF's internal
-- selection/aggro/hover highlights and will not conflict.
-- selection/aggro/hover/focus highlights and will not conflict.
-- ============================================================

local externalHighlights = {}
Expand Down
22 changes: 20 additions & 2 deletions Config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,13 @@ DF.PartyDefaults = {
hidePlayerFrame = false,
showBlizzardSideMenu = true,

-- Focus Highlight
focusHighlightAlpha = 1,
focusHighlightColor = {r = 0, g = 0, b = 1, a = 1},
focusHighlightInset = 0,
focusHighlightMode = "NONE",
focusHighlightThickness = 1,

-- Hover Highlight
hoverHighlightAlpha = 0.8,
hoverHighlightColor = {r = 1, g = 1, b = 1, a = 1},
Expand Down Expand Up @@ -1860,7 +1867,9 @@ DF.PartyDefaults = {
testShowBossDebuffs = false,
testShowDispelGlow = false,
testShowExternalDef = false,
testShowFocus = false,
testShowHealPrediction = false,
testShowHover = false,
testShowIcons = true,
testShowMissingBuff = false,
testShowMyBuffIndicator = false,
Expand Down Expand Up @@ -2616,6 +2625,13 @@ DF.RaidDefaults = {
hidePlayerFrame = false,
showBlizzardSideMenu = true,

-- Focus Highlight
focusHighlightAlpha = 1,
focusHighlightColor = {r = 0, g = 0, b = 1, a = 1},
focusHighlightInset = 0,
focusHighlightMode = "NONE",
focusHighlightThickness = 1,

-- Hover Highlight
hoverHighlightAlpha = 0.8,
hoverHighlightColor = {r = 1, g = 1, b = 1, a = 1},
Expand Down Expand Up @@ -3096,8 +3112,10 @@ DF.RaidDefaults = {
testShowAuras = false,
testShowBossDebuffs = false,
testShowDispelGlow = false,
testShowExternalDef = false,
testShowHealPrediction = false,
testShowExternalDef = false,
testShowFocus = false,
testShowHealPrediction = false,
testShowHover = false,
testShowIcons = true,
testShowMissingBuff = false,
testShowMyBuffIndicator = false,
Expand Down
8 changes: 8 additions & 0 deletions Core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,12 @@ function DF:LightweightUpdateHighlight(highlightType)
inset = db.hoverHighlightInset or 0
alpha = db.hoverHighlightAlpha or 0.8
color = db.hoverHighlightColor or {r = 1, g = 1, b = 1}
elseif highlightType == "focus" then
highlight = frame.focusHighlight or frame.dfFocusHighlight
thickness = db.focusHighlightThickness or 2
inset = db.focusHighlightInset or 0
alpha = db.focusHighlightAlpha or 1
color = db.focusHighlightColor or {r = 0, g = 0, b = 1}
elseif highlightType == "aggro" then
highlight = frame.aggroHighlight or frame.dfAggroHighlight
thickness = db.aggroHighlightThickness or 2
Expand Down Expand Up @@ -930,6 +936,8 @@ function DF:LightweightUpdateHighlight(highlightType)
highlight = frame.selectionHighlight or frame.dfSelectionHighlight
elseif highlightType == "hover" then
highlight = frame.hoverHighlight or frame.dfHoverHighlight
elseif highlightType == "focus" then
highlight = frame.focusHighlight or frame.dfFocusHighlight
elseif highlightType == "aggro" then
highlight = frame.aggroHighlight or frame.dfAggroHighlight
end
Expand Down
9 changes: 9 additions & 0 deletions ExportCategories.lua
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,13 @@ DF.ExportCategories = {
"hoverHighlightMode",
"hoverHighlightThickness",

-- Focus Highlight
"focusHighlightAlpha",
"focusHighlightColor",
"focusHighlightInset",
"focusHighlightMode",
"focusHighlightThickness",

-- Health Threshold Fading
"healthFadeEnabled",
"healthFadeAlpha",
Expand Down Expand Up @@ -1055,6 +1062,8 @@ DF.ExportCategories = {
"testShowHealPrediction",
"testShowAggro",
"testShowSelection",
"testShowHover",
"testShowFocus",
"testShowOutOfRange",
"testShowDispelGlow",
"testShowExternalDef",
Expand Down
66 changes: 62 additions & 4 deletions Features/Highlights.lua
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,11 @@ local function GetOrCreateHighlight(frame, highlightType)
ch:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
ch:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)
ch:SetFrameStrata(frame:GetFrameStrata())
-- Frame levels: Aggro = +9, Hover = +10, Selection = +11
-- Frame levels: Aggro = +9, Hover = +10, Selection = +11, Focus = +12
local levelOffset = 9
if highlightType == "Hover" then levelOffset = 10
elseif highlightType == "Selection" then levelOffset = 11 end
elseif highlightType == "Selection" then levelOffset = 11
elseif highlightType == "Focus" then levelOffset = 12 end
ch:SetFrameLevel(frame:GetFrameLevel() + levelOffset)
ch:Hide()

Expand All @@ -248,6 +249,7 @@ local function GetOrCreateHighlight(frame, highlightType)
if self.dfSelectionHighlight then self.dfSelectionHighlight:Hide() end
if self.dfHoverHighlight then self.dfHoverHighlight:Hide() end
if self.dfAggroHighlight then self.dfAggroHighlight:Hide() end
if self.dfFocusHighlight then self.dfFocusHighlight:Hide() end
end)
frame.dfHighlightHooked = true
end
Expand Down Expand Up @@ -534,7 +536,7 @@ DF.UpdateHighlightStyleColor = UpdateHighlightStyleColor
-- UPDATE HIGHLIGHTS FOR A FRAME
-- ============================================================

function DF:UpdateHighlights(frame, forceSelection, forceAggro)
function DF:UpdateHighlights(frame, forceSelection, forceAggro, forceFocus)
if not frame then return end

-- DEBUG: Track what's happening
Expand All @@ -555,6 +557,7 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
if frame.dfSelectionHighlight then frame.dfSelectionHighlight:Hide() end
if frame.dfHoverHighlight then frame.dfHoverHighlight:Hide() end
if frame.dfAggroHighlight then frame.dfAggroHighlight:Hide() end
if frame.dfFocusHighlight then frame.dfFocusHighlight:Hide() end
return
end

Expand All @@ -570,6 +573,7 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
if frame.dfSelectionHighlight then frame.dfSelectionHighlight:Hide() end
if frame.dfHoverHighlight then frame.dfHoverHighlight:Hide() end
if frame.dfAggroHighlight then frame.dfAggroHighlight:Hide() end
if frame.dfFocusHighlight then frame.dfFocusHighlight:Hide() end
return
end

Expand All @@ -587,7 +591,7 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
if debugHighlights then
print(" inTestMode:", inTestMode and "true" or "false")
end
if inTestMode and forceSelection == nil and forceAggro == nil then
if inTestMode and forceSelection == nil and forceAggro == nil and forceFocus == nil then
-- Determine frame index for test mode
local frameIndex = nil

Expand Down Expand Up @@ -637,6 +641,8 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
print(" frameIndex:", frameIndex or "nil")
print(" db.testShowSelection:", db.testShowSelection and "true" or "false")
print(" db.testShowAggro:", db.testShowAggro and "true" or "false")
print(" db.testShowHover:", db.testShowHover and "true" or "false")
print(" db.testShowFocus:", db.testShowFocus and "true" or "false")
end

-- Apply test mode highlights based on settings
Expand All @@ -647,6 +653,9 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
if db.testShowAggro then
forceAggro = (frameIndex == 1) -- Second frame gets aggro
end
if db.testShowFocus then
forceFocus = (frameIndex == 2) -- Third frame gets focus
end
end

if debugHighlights then
Expand Down Expand Up @@ -753,6 +762,48 @@ function DF:UpdateHighlights(frame, forceSelection, forceAggro)
SelectionAnimator_Remove(hoverHighlight)
end

-- Check if unit is focused - can be overridden for test mode
local isFocused = forceFocus
if isFocused == nil then
isFocused = unit and UnitIsUnit(unit, "focus")
end

-- Focus Highlight
local focusHighlight = GetOrCreateHighlight(frame, "Focus")
local focusMode = db.focusHighlightMode or "NONE"
local wantFocus = isFocused and focusMode ~= "NONE"

if debugHighlights then
print(" wantFocus:", wantFocus and "true" or "false")
end

if wantFocus then
local c = db.focusHighlightColor or {r = 0, g = 0, b = 1}
local focusThickness = db.focusHighlightThickness or 2
local focusInset = db.focusHighlightInset or 0

-- Apply pixel-perfect adjustments (use PixelPerfectThickness to ensure min 1px)
if db.pixelPerfect then
focusThickness = DF:PixelPerfectThickness(focusThickness)
focusInset = DF:PixelPerfect(focusInset)
end

ApplyHighlightStyle(
focusHighlight,
focusMode,
focusThickness,
focusInset,
c.r, c.g, c.b,
db.focusHighlightAlpha or 1,
db
)
else
HideAnimatedBorder(focusHighlight)
HideGlowLayers(focusHighlight)
focusHighlight:Hide()
SelectionAnimator_Remove(focusHighlight)
end

-- Aggro Highlight
local aggroHighlight = GetOrCreateHighlight(frame, "Aggro")
local wantAggro = isAggro and aggroMode ~= "NONE"
Expand Down Expand Up @@ -947,6 +998,7 @@ DF.UpdateAllHighlights = UpdateAllHighlights
-- PERFORMANCE: Converted from 0.1s timer (~450 calls/sec) to event-driven.
-- Events used:
-- PLAYER_TARGET_CHANGED - Update all frames (old target loses selection, new gains)
-- PLAYER_FOCUS_CHANGED - Update all frames (old focus loses highlight, new gains)
-- UNIT_THREAT_SITUATION_UPDATE - Update specific unit's frame for aggro changes
-- PLAYER_REGEN_ENABLED - Safety refresh when leaving combat (clears any stuck highlights)
-- GROUP_ROSTER_UPDATE - Safety refresh when group composition changes
Expand All @@ -956,6 +1008,7 @@ DF.UpdateAllHighlights = UpdateAllHighlights

local highlightEventFrame = CreateFrame("Frame")
highlightEventFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
highlightEventFrame:RegisterEvent("PLAYER_FOCUS_CHANGED")
highlightEventFrame:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE")
highlightEventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
highlightEventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
Expand All @@ -968,6 +1021,11 @@ highlightEventFrame:SetScript("OnEvent", function(self, event, ...)
-- Target changed - need to update ALL frames
-- (old target loses selection highlight, new target gains it)
UpdateAllHighlights()

elseif event == "PLAYER_FOCUS_CHANGED" then
-- Focus changed - need to update ALL frames
-- (old focus loses focus highlight, new focus gains it)
UpdateAllHighlights()

elseif event == "UNIT_THREAT_SITUATION_UPDATE" then
-- Threat changed on specific unit - update that frame
Expand Down
2 changes: 2 additions & 0 deletions Locales/enUS.lua
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ L["Floating Bar"] = true
L["Floating Bar Anchor"] = true
L["Floating Bar Position"] = true
L["Focus"] = true
L["Focus Highlight"] = true
L["Focus Settings"] = true
L["Font"] = true
L["Font Outline"] = true
L["Font Settings"] = true
Expand Down
1 change: 1 addition & 0 deletions Options/AutoProfiles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ local OVERRIDE_TAB_MAP = {
{"statusIconFont", "indicators_icons", L["Icons"]},
{"selectionHighlight", "indicators_highlights", L["Highlights"]},
{"hoverHighlight", "indicators_highlights", L["Highlights"]},
{"focusHighlight", "indicators_highlights", L["Highlights"]},
{"aggroHighlight", "indicators_highlights", L["Highlights"]},
{"aggro", "indicators_highlights", L["Highlights"]},
-- Pinned frames (prefix match for "pinned.N.setting" format)
Expand Down
28 changes: 27 additions & 1 deletion Options/Options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6914,7 +6914,7 @@ function DF:SetupGUIPages(GUI, CreateCategory, CreateSubTab, BuildPage)
local pageHighlights = CreateSubTab("indicators", "indicators_highlights", L["Highlights"])
BuildPage(pageHighlights, function(self, db, Add, AddSpace, AddSyncPoint)
-- Copy button at top
Add(CreateCopyButton(self.child, {"selectionHighlight", "hoverHighlight", "aggroHighlight", "aggro"}, L["Highlights"], "indicators_highlights"), 25, 2)
Add(CreateCopyButton(self.child, {"selectionHighlight", "hoverHighlight", "focusHighlight", "aggroHighlight", "aggro"}, L["Highlights"], "indicators_highlights"), 25, 2)

AddSpace(10, "both")

Expand Down Expand Up @@ -6987,6 +6987,32 @@ function DF:SetupGUIPages(GUI, CreateCategory, CreateSubTab, BuildPage)
currentSection = nil
AddSpace(10, "both")

-- ========================================
-- FOCUS HIGHLIGHT SECTION
-- ========================================
local focusSection = Add(GUI:CreateCollapsibleSection(self.child, L["Focus Highlight"], true), 36, "both")
currentSection = focusSection

local function HideFocusOptions(d) return d.focusHighlightMode == "NONE" end

local focusGroup = GUI:CreateSettingsGroup(self.child, 260)
focusGroup:AddWidget(GUI:CreateHeader(self.child, L["Focus Settings"]), 40)
focusGroup:AddWidget(GUI:CreateDropdown(self.child, L["Mode"], highlightModes, db, "focusHighlightMode", function()
self:RefreshStates()
end), 55)
local focusThick = focusGroup:AddWidget(GUI:CreateSlider(self.child, L["Thickness"], 1, 10, 1, db, "focusHighlightThickness", nil, function() DF:LightweightUpdateHighlight("focus") end, true), 55)
focusThick.hideOn = HideFocusOptions
local focusInset = focusGroup:AddWidget(GUI:CreateSlider(self.child, L["Inset"], -10, 10, 1, db, "focusHighlightInset", nil, function() DF:LightweightUpdateHighlight("focus") end, true), 55)
focusInset.hideOn = HideFocusOptions
local focusAlpha = focusGroup:AddWidget(GUI:CreateSlider(self.child, L["Alpha"], 0.1, 1.0, 0.05, db, "focusHighlightAlpha", nil, function() DF:LightweightUpdateHighlight("focus") end, true), 55)
focusAlpha.hideOn = HideFocusOptions
local focusCol = focusGroup:AddWidget(GUI:CreateColorPicker(self.child, L["Color"], db, "focusHighlightColor", false, nil, function() DF:LightweightUpdateHighlight("focus") end, true), 35)
focusCol.hideOn = HideFocusOptions
AddToSection(focusGroup, nil, 1)

currentSection = nil
AddSpace(10, "both")

-- ========================================
-- AGGRO HIGHLIGHT SECTION
-- ========================================
Expand Down
2 changes: 1 addition & 1 deletion TRANSLATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ These appear as GUI control labels, column headers, or dropdown options:
| `"Group"` | Raid group | A WoW raid group (1-8), not a generic group. |
| `"Handle"` | Drag handle | The UI element you click to drag/move the frame container. |
| `"Health"` | Health points | A unit's hit points / life total. |
| `"Highlight"` | Visual overlay | A colored glow or border shown on hover/selection/aggro. |
| `"Highlight"` | Visual overlay | A colored glow or border shown on hover/selection/aggro/focus. |
| `"Hook"` | Attachment method | How the pet frame connects to its owner frame. |
| `"Horizontal"` | Direction | Left-to-right layout. |
| `"Icon"` | Small image | A buff/debuff icon, role icon, or status icon. |
Expand Down
6 changes: 5 additions & 1 deletion TestMode/TestMode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,7 @@ function DF:UpdateTestFrame(frame, index, applyLayout)
if ADEngine then ADEngine:ClearFrame(frame) end
end

-- Update selection and aggro highlights for test mode
-- Update all highlights (selection, aggro, etc.) for test mode
-- UpdateHighlights now handles test mode internally
if DF.UpdateHighlights then
DF:UpdateHighlights(frame)
Expand Down Expand Up @@ -6770,6 +6770,9 @@ function DF:CreateTestPanel()
panel.showAggroCheck = secHighlights:AddCheckbox("Aggro", "testShowAggro", function()
if DF.UpdateAllTestHighlights then DF:UpdateAllTestHighlights() end
end, "indicators_highlights")
panel.showFocusCheck = secHighlights:AddCheckbox("Focus", "testShowFocus", function()
if DF.UpdateAllTestHighlights then DF:UpdateAllTestHighlights() end
end, "indicators_highlights")

-- ============================================================
-- PRESETS FOOTER
Expand Down Expand Up @@ -6914,6 +6917,7 @@ function DF:CreateTestPanel()
self.showIconsCheck:SetChecked(db.testShowIcons ~= false)
self.showSelectionCheck:SetChecked(db.testShowSelection)
self.showAggroCheck:SetChecked(db.testShowAggro)
self.showFocusCheck:SetChecked(db.testShowFocus)

-- Buff/Debuff sliders
local buffCount = db.testBuffCount or 3
Expand Down