feat(tooltip): ElvUI style without ElvUI; source in secondary only; fix learner source label

- ElvUI tooltip style: new 'ElvUI tooltip style' option (General tab, on by
  default) skins GameTooltip/WorldMapTooltip/ItemRefTooltip/shopping tooltips
  and the secondary learner frame with ElvUI's transparent flat look (dark bg
  + thin 1px border) when ElvUI is not installed. Corrected the secondary
  frame fallback that used the chunky WoW border. No-op when ElvUI is loaded.

- Source attribution now shows ONLY inside the secondary learner tooltip when
  'Use secondary learner tooltip' is enabled; removed from the main NPC/object/
  item tooltip and gated off entirely when the secondary tooltip is disabled
  (map-pin source gated the same way).

- Fixed learner-learned pins mislabelled 'AscensionDB': GetPinDataSource is now
  mode-aware and returns 'Learner' in learner mode when the entity has a learner
  record, even if AscensionDB also curates it (curated coords are discarded by
  GetNPC/GetObject in learner mode anyway).

Test-neutral (145 successes / same 7 pre-existing failures + 1 error).
This commit is contained in:
Xurkon
2026-06-09 21:52:55 -05:00
parent ee67653414
commit fa37ab8eb5
8 changed files with 121 additions and 40 deletions
+4
View File
@@ -22,12 +22,16 @@
### Features
- **[Tooltip - ElvUI Style Without ElvUI]** Added "ElvUI tooltip style" (General tab, on by default) which skins Questie's tooltips — the NPC/item/object and world-map-pin tooltips plus the secondary learner tooltip — with ElvUI's transparent flat look (dark `0.06/0.06/0.06/0.8` background and a thin 1px border) even when ElvUI is not installed, so they match instead of falling back to the chunky default WoW border. `QuestieTooltips:SkinDefaultTooltips` applies it to `GameTooltip`, `WorldMapTooltip`, `ItemRefTooltip` and the shopping tooltips (re-asserted on show), and the secondary learner frame's fallback style was corrected to the same thin border. No-op when ElvUI is loaded, since ElvUI skins the frames itself.
- **[Map - Looted Object Pins Disappear On Loot]** When you open/loot a quest object node (e.g. Fell Wood piles), that specific node's map/minimap pin now disappears immediately even if the objective is not yet fully collected, instead of all node pins staying until turn-in. On `LOOT_OPENED`, `QuestieQuest:RemoveLootedObjectivePins` finds the active object-objective spawn nearest the player's world position (within ~12 yards, since you stand on the node to loot it), records it as consumed in `Questie.db.char.lootedObjectSpawns`, and redraws just that objective so clustering recomputes with the looted node skipped. `_DetermineIconsToDraw` skips consumed object spawns, so removal persists across redraws and `/reload`. The looted history is cleared on quest accept (`QuestieQuest:ClearLootedSpawns`), so abandoning and re-doing the quest — including after an Ascension prestige — shows every node again. Scoped to `object`-type objectives; monster/kill pins are unchanged. Works in every data source mode (auto / learner / static / none): the suppression is centralized in the single shared `_DetermineIconsToDraw` draw path that all redraw routes funnel through (core `UpdateQuest`, the learner's debounced `_DoFlushActiveQuestPins`, slider redraws), and it operates on the already mode-resolved `objective.spawnList`. Matching is radius-based (1.5 zone units) rather than exact-coordinate so that in learner/auto mode a spawn the learner re-adds at the player's position for the just-looted node is also suppressed instead of re-appearing.
- **[Tooltip - Data Source Attribution (Accurate)]** Re-added the "Show data source" tooltip option (General tab, off by default) that adds a `Source:` line to NPC, object, item and world-map-pin tooltips. Unlike the previous version (removed in an earlier build for guessing the source from the global data-source mode), this is accurate per-pin/per-entity and never guesses: each pin is tagged with its real provenance at creation via the new `QuestieDB.GetPinDataSource(entityType, id, spawnData)` helper — `Learner` (per-spawn `isLearned` flag or a learner record), `AscensionDB` (a curated `ascensionOverrideKeys` override for the id), `Townsfolk` (manual/menu notes), or the base `Questie DB` — with a `Comms` overlay appended when comms holds data for the entity. Objective pins are tagged per-spawn in `_DetermineIconsToDraw`; available/finisher pins are quest-scoped (defaulted in `DrawWorldIcon`); manual notes are tagged in `DrawManualIcon`. World-map pins read the per-pin tag (`MapIconTooltip`); unit/object/item hovers derive it per-id at the render layer (`TooltipHandler` via `QuestieTooltips:GetDataSourceLine`). When a pin's source genuinely can't be determined, no line is shown rather than a misleading one.
### Bug Fixes
- **[Tooltip - Data Source In Secondary Tooltip Only]** The `Source:` attribution line now appears only inside the secondary learner tooltip (when "Use secondary learner tooltip" is enabled) and is never added to the main NPC/object/item tooltip; with the secondary tooltip disabled it does not appear at all. The map-pin source line is gated the same way. The "Show data source" option now depends on the secondary-tooltip option being enabled.
- **[Tooltip - Learner Pin Mislabelled As AscensionDB]** A spawn freshly learned via the learner was shown as `Source: AscensionDB` instead of `Learner`. `QuestieDB.GetPinDataSource` resolved AscensionDB-curated ownership before checking the learner, but in learner-only mode the displayed spawns are the learner's (curated coords are discarded by `GetNPC`/`GetObject`). It is now mode-aware: in learner mode, an entity with a learner record reports `Learner` even when AscensionDB also curates it.
- **[Learner - Learner-Only Mode No Longer Draws AscensionDB/Static Pins]** In learner-only mode the map/minimap drew curated AscensionDB (and static) spawns for every quest NPC/object the player had not personally recorded, instead of only the learner's own spawns. `QuestieDB:GetNPC`/`GetObject` fall back to the `npcDataOverrides`/`objectDataOverrides` entry for metadata when there is no learner record, and that entry's spawns (AscensionDB-curated for un-recorded entities) were being used as pins. Both functions now track whether a real learner record exists and, in learner mode, strip the spawns when it does not — so learner-only mode shows exclusively what the learner has recorded (the metadata fallback for names/tooltips is kept). Added a regression test. Recorded entities still show their learner spawns; auto/static/none modes are unchanged.
- **[Map - Quest Type Filters Now Apply To Minimap]** (#11) Quest-type filters (Available Dungeon/Raid/PvP/Repeatable/Event Quests, plus other `ShouldBeHidden` rules like untracked/unexplored and `enableMiniMapIcons`) were honored on the world map but not the minimap. The world-map icon stayed hidden once `ShouldBeHidden` filtered it, but the minimap icon's per-frame `FadeLogic` re-showed any hidden icon as soon as the player came within range, so e.g. a filtered dungeon quest still appeared on the minimap. `FadeLogic` now re-checks `ShouldBeHidden` before re-showing, so the same filters apply to both maps (fixed in both the world-icon and manual-icon minimap fade paths).
- **[Libs/AceComm - Long Comm Prefix Login Error]** (#12) Fixed a recurring login Lua error `AceComm:RegisterComm(...): prefix length is limited to 16 characters` on servers like ChromieCraft. The cause is a third-party addon (e.g. AtlasLoot) registering an AceComm prefix longer than the client's 16-character limit; because Questie's bundled AceComm is the LibStub winner and its `xpcall` polyfill wraps AceAddon's `OnEnable`, the upstream hard `error()` surfaced through Questie's frames every login. Our bundled `AceComm:RegisterComm` now degrades gracefully for over-long prefixes (which can never work on the client anyway): it warns once and skips the registration instead of throwing, so the offending addon's `OnEnable` is no longer aborted and the error popup is gone.
+22 -11
View File
@@ -2626,22 +2626,33 @@ function QuestieDB.GetPinDataSource(entityType, id, spawnData)
end
if not id then return nil end
-- AscensionDB-curated entity (has at least one curated override field for this id).
local settings = _GetLearnerSettings()
local mode = settings and settings.dataSourceMode or "auto"
-- Does the learner have a record for this entity?
local learner = Questie.dbLearner and Questie.dbLearner.global
local bucket = learner and ((entityType == "OBJECT" and learner.objects)
or (entityType == "QUEST" and learner.quests)
or (entityType == "ITEM" and learner.items)
or learner.npcs)
local hasLearner = bucket and bucket[id] ~= nil
-- In learner-only mode the displayed spawns ARE the learner's (GetNPC/GetObject
-- return the learner record and discard curated coords), so the learner is the
-- authoritative source even for AscensionDB-curated entities. Without this, a
-- freshly-learned curated NPC was mislabelled "AscensionDB".
if mode == "learner" and hasLearner then
return "Learner"
end
-- AscensionDB-curated entity (authoritative in auto/static modes).
local ascKeys = QuestieDB.ascensionOverrideKeys and QuestieDB.ascensionOverrideKeys[entityType]
if ascKeys and ascKeys[id] and next(ascKeys[id]) then
return "AscensionDB"
end
-- Learner-known entity (learned data exists for this id).
local learner = Questie.dbLearner and Questie.dbLearner.global
if learner then
local bucket = (entityType == "OBJECT" and learner.objects)
or (entityType == "QUEST" and learner.quests)
or (entityType == "ITEM" and learner.items)
or learner.npcs
if bucket and bucket[id] then
return "Learner"
end
if hasLearner then
return "Learner"
end
return "Questie DB"
@@ -562,14 +562,32 @@ function QuestieOptions.tabs.general:Initialize()
type = "toggle",
order = 8.605,
name = function() return l10n('Show data source'); end,
desc = function() return l10n('Adds a "Source:" line to NPC, object and map-pin tooltips showing where the data came from (Questie DB, AscensionDB, Learner, Townsfolk, Comms). Only shown when the source is actually known.'); end,
desc = function() return l10n('Adds a "Source:" line (Questie DB, AscensionDB, Learner, Townsfolk, Comms) inside the secondary learner tooltip. Requires "Use secondary learner tooltip"; never shown in the main tooltip and not shown at all when the secondary tooltip is disabled. Only shown when the source is actually known.'); end,
width = 1.5,
disabled = function() return not Questie.db.profile.enableTooltips; end,
disabled = function() return not (Questie.db.profile.enableTooltips and Questie.db.profile.learnerTooltipUseSecondary == true); end,
get = function() return Questie.db.profile.enableTooltipsSource == true end,
set = function(_, value)
Questie.db.profile.enableTooltipsSource = value
end
},
elvuiStyleTooltips = {
type = "toggle",
order = 8.606,
name = function() return l10n('ElvUI tooltip style'); end,
desc = function() return l10n('Skin Questie tooltips (NPC/item/map-pin and the secondary learner tooltip) with the ElvUI transparent style even when ElvUI is not installed. Has no effect when ElvUI is loaded, since ElvUI skins them itself. Takes full effect after a reload.'); end,
width = 1.5,
disabled = function() return not Questie.db.profile.enableTooltips; end,
get = function() return Questie.db.profile.elvuiStyleTooltips ~= false end,
set = function(_, value)
Questie.db.profile.elvuiStyleTooltips = value
if value then
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips")
if QuestieTooltips and QuestieTooltips.SkinDefaultTooltips then
QuestieTooltips:SkinDefaultTooltips()
end
end
end
},
partyOnlyToggle = {
type = "toggle",
order = 8.61,
@@ -88,6 +88,7 @@ function QuestieOptionsDefaults:Load()
enableTooltipsQuestID = false,
enableTooltipsQuestLevel = true,
enableTooltipsSource = false,
elvuiStyleTooltips = true,
showQuestXpAtMaxLevel = true,
enableTooltipsNextInChain = true,
learnerTooltips = true,
+20 -9
View File
@@ -4615,17 +4615,19 @@ local function _ApplyElvUIStyleTooltip(frame)
return
end
end
-- ElvUI default "Transparent" template — see ElvUI/Core/Toolkit.lua:82
-- and ElvUI/Settings/Profile.lua:29-31. Hard-coded so the secondary
-- frame looks the same with or without ElvUI.
-- ElvUI "Transparent" template — see ElvUI/Core/Toolkit.lua SetTemplate and
-- ElvUI/Settings/Profile.lua:29-31. ElvUI uses a FLAT texture for both the
-- background and the border with a 1px (E.mult) edge, NOT the chunky default
-- WoW tooltip border — so use a solid texture and edgeSize 1 to match.
if not frame.SetBackdrop then return end
local FLAT = "Interface\\ChatFrame\\ChatFrameBackground" -- solid 1x1 texture on 3.3.5
frame:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 12,
insets = {left = 3, right = 3, top = 3, bottom = 3},
bgFile = FLAT,
edgeFile = FLAT,
tile = false,
tileSize = 0,
edgeSize = 1,
insets = {left = 0, right = 0, top = 0, bottom = 0},
})
-- (0.06, 0.06, 0.06, 0.8) — ElvUI's default backdropfadecolor
frame:SetBackdropColor(0.06, 0.06, 0.06, 0.8)
@@ -4779,6 +4781,15 @@ local function _AddLearnedSpawnTooltipLine(unitToken)
for _, pair in ipairs(lines) do
rendered[#rendered + 1] = pair[1] .. ": " .. pair[2]
end
-- Data-source attribution belongs ONLY in this secondary frame, and only when the
-- source option is enabled. It is never added to the main tooltip; when the secondary
-- learner tooltip is disabled it does not appear at all.
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips")
local sourceLine = QuestieTooltips and QuestieTooltips.GetDataSourceLine
and QuestieTooltips:GetDataSourceLine("m_" .. npcId)
if sourceLine then
rendered[#rendered + 1] = sourceLine
end
-- Spacer after learner section
rendered[#rendered + 1] = " "
_ShowLearnerTooltipFrame(GameTooltip, rendered)
+3
View File
@@ -107,6 +107,9 @@ end
--- the label is accurate, plus a Comms overlay when comms holds data for this id.
local function _GetWorldMapDataSourceLine(pinData)
if not Questie.db.profile.enableTooltipsSource then return nil end
-- Source attribution is tied to the secondary learner tooltip: only show it when that
-- option is enabled, and never otherwise (matches the unit-hover behaviour).
if Questie.db.profile.learnerTooltipUseSecondary ~= true then return nil end
local src = pinData and pinData.DataSource
local parts = {}
if src then tinsert(parts, src) end
+48
View File
@@ -123,6 +123,9 @@ end
---@param key string @"m_<npcId>" | "o_<objectId>" | "i_<itemId>"
local function _GetTooltipSourceLine(key)
if not Questie.db.profile.enableTooltipsSource then return nil end
-- Source attribution is shown only inside the secondary learner tooltip; never when
-- that option is disabled (the only caller is the secondary frame, but gate here too).
if Questie.db.profile.learnerTooltipUseSecondary ~= true then return nil end
if not key then return nil end
local prefix = key:sub(1, 2)
local id = tonumber(key:sub(3))
@@ -668,6 +671,49 @@ _InitObjectiveTexts = function(objectivesText, objectiveIndex, playerName)
return objectivesText
end
-- Apply ElvUI's "Transparent" tooltip look (flat dark background + thin 1px border) so
-- Questie's tooltips match the ElvUI style even when ElvUI is not installed. ElvUI uses a
-- FLAT texture for both the background and the border with a 1px edge (see
-- ElvUI/Core/Toolkit.lua SetTemplate + Settings/Profile.lua:29-31), not the chunky default
-- WoW tooltip border.
local _ELV_FLAT = "Interface\\ChatFrame\\ChatFrameBackground" -- solid 1x1 texture on 3.3.5
local function _ApplyElvUIStyle(frame)
if not frame or not frame.SetBackdrop then return end
frame:SetBackdrop({
bgFile = _ELV_FLAT,
edgeFile = _ELV_FLAT,
tile = false,
tileSize = 0,
edgeSize = 1,
insets = { left = 0, right = 0, top = 0, bottom = 0 },
})
frame:SetBackdropColor(0.06, 0.06, 0.06, 0.8) -- ElvUI backdropfadecolor
frame:SetBackdropBorderColor(0, 0, 0, 1) -- ElvUI bordercolor (black)
end
-- Skins the standard tooltip frames Questie writes into. No-op when ElvUI is loaded (it
-- skins them itself) or when the option is disabled.
function QuestieTooltips:SkinDefaultTooltips()
if (not Questie.db) or (not Questie.db.profile) or Questie.db.profile.elvuiStyleTooltips == false then return end
if IsAddOnLoaded("ElvUI") then return end
for _, name in ipairs({ "GameTooltip", "ItemRefTooltip", "ShoppingTooltip1", "ShoppingTooltip2", "WorldMapTooltip" }) do
local frame = _G[name]
if frame then
_ApplyElvUIStyle(frame)
-- The default UI re-applies its template backdrop (e.g. item-quality borders) on
-- some shows; re-assert our flat look on show so it doesn't revert.
if not frame.__questieElvHook then
frame.__questieElvHook = true
frame:HookScript("OnShow", function(self)
if Questie.db.profile.elvuiStyleTooltips ~= false and not IsAddOnLoaded("ElvUI") then
_ApplyElvUIStyle(self)
end
end)
end
end
end
end
function QuestieTooltips:Initialize()
-- For the clicked item frame.
ItemRefTooltip:HookScript("OnTooltipSetItem", _QuestieTooltips.AddItemDataToTooltip)
@@ -750,6 +796,8 @@ function QuestieTooltips:Initialize()
end
end
end)
QuestieTooltips:SkinDefaultTooltips()
end
return QuestieTooltips
+3 -18
View File
@@ -329,11 +329,9 @@ function _QuestieTooltips:AddUnitDataToTooltip()
end
end
-- Data-source attribution (opt-in; internally gated and nil when source unknown).
local npcSourceLine = QuestieTooltips:GetDataSourceLine("m_" .. npcId)
if npcSourceLine then
GameTooltip:AddLine(npcSourceLine)
end
-- Data-source attribution is rendered by QuestieLearner's secondary tooltip frame
-- (only when the secondary learner tooltip is enabled), never inline in the main
-- tooltip — see _AddLearnedSpawnTooltipLine.
local npcNum = tonumber(npcId)
if npcNum then
@@ -400,11 +398,6 @@ function _QuestieTooltips:AddItemDataToTooltip()
self:AddLine(v)
end
end
-- Data-source attribution (opt-in; internally gated and nil when source unknown).
local itemSourceLine = QuestieTooltips:GetDataSourceLine("i_" .. (itemId or 0))
if itemSourceLine then
self:AddLine(itemSourceLine)
end
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
end
lastItemId = itemId;
@@ -459,14 +452,6 @@ function _QuestieTooltips:AddObjectDataToTooltip(name)
end
end
end
-- Data-source attribution for the hovered object (opt-in; nil when unknown).
local firstObjectId = lookup[1]
if firstObjectId then
local objSourceLine = QuestieTooltips:GetDataSourceLine("o_" .. firstObjectId)
if objSourceLine then
GameTooltip:AddLine(objSourceLine)
end
end
if QuestieTooltips.ResizeTooltip then
QuestieTooltips:ResizeTooltip(GameTooltip)
end