diff --git a/Modules/Tracker/QuestieTracker.lua b/Modules/Tracker/QuestieTracker.lua index a6a322d..8604f19 100644 --- a/Modules/Tracker/QuestieTracker.lua +++ b/Modules/Tracker/QuestieTracker.lua @@ -845,11 +845,7 @@ function QuestieTracker:Update() -- Setup local QuestieTracker:Update vars local trackerFontSizeZone = Questie.db.profile.trackerFontSizeZone local trackerFontSizeQuest = Questie.db.profile.trackerFontSizeQuest - -- The supertrack button sits at the very left of a quest line, so the whole quest list is - -- indented past it: otherwise it is clipped by the tracker's left edge and collides with the - -- quest item buttons, which share that gutter. - local superTrackMarginLeft = TrackerLinePool.GetSuperTrackMarginReserve() - local questMarginLeft = (trackerMarginLeft + trackerMarginRight) - (18 - trackerFontSizeQuest) + superTrackMarginLeft + local questMarginLeft = (trackerMarginLeft + trackerMarginRight) - (18 - trackerFontSizeQuest) local objectiveMarginLeft = questMarginLeft + trackerFontSizeQuest local questItemButtonSize = 12 + trackerFontSizeQuest local objectiveColor = Questie.db.profile.trackerColorObjectives @@ -899,11 +895,9 @@ function QuestieTracker:Update() line.criteriaMark:Hide() line.playButton:Hide() - -- Setup Zone Label. Indented like the quest lines below it: the supertrack - -- buttons overflow their own line at larger sizes, and the zone label is the - -- only text that would otherwise share that gutter with them. + -- Setup Zone Label line.label:ClearAllPoints() - line.label:SetPoint("TOPLEFT", line, "TOPLEFT", superTrackMarginLeft, 0) + line.label:SetPoint("TOPLEFT", line, "TOPLEFT", 0, 0) -- Set Zone Title and default Min/Max states if Questie.db.char.collapsedZones[zoneName] then @@ -930,19 +924,19 @@ function QuestieTracker:Update() -- Check and measure Zone Label text width and update tracker width QuestieTracker:UpdateWidth(line.label:GetStringWidth() + trackerMarginLeft + - superTrackMarginLeft + trackerMarginRight) + trackerMarginRight) -- Set Zone Label and Line widths - line.label:SetWidth(trackerBaseFrame:GetWidth() - trackerMarginLeft - superTrackMarginLeft - trackerMarginRight) - line:SetWidth(line.label:GetWidth() + superTrackMarginLeft) + line.label:SetWidth(trackerBaseFrame:GetWidth() - trackerMarginLeft - trackerMarginRight) + line:SetWidth(line.label:GetWidth()) -- Compare largest text Label in the tracker with current Label, then save widest width trackerLineWidth = math.max(trackerLineWidth, - line.label:GetStringWidth() + trackerMarginLeft + superTrackMarginLeft) + line.label:GetStringWidth() + trackerMarginLeft) -- Setup Min/Max Button line.expandZone:ClearAllPoints() - line.expandZone:SetPoint("TOPLEFT", line, "TOPLEFT", superTrackMarginLeft, 0) + line.expandZone:SetPoint("TOPLEFT", line, "TOPLEFT", 0, 0) line.expandZone:SetWidth(line.label:GetWidth()) line.expandZone:SetHeight(line.label:GetHeight()) line.expandZone:Show() @@ -967,6 +961,10 @@ function QuestieTracker:Update() -- Safety check - make sure we didn't run over our linePool limit. if not line then return "BREAK" end + -- Kept so the supertrack button, which lives on the title line, can be + -- re-centred over the finished quest block further down. + local questTitleLine = line + -- Set Line Mode, Types, Clickers line:SetMode("quest") line:SetOnClick("quest") @@ -1181,7 +1179,7 @@ function QuestieTracker:Update() end -- Attach button to Quest Title linePool - button:SetPoint("TOPLEFT", button.line, "TOPLEFT", superTrackMarginLeft, 0) + button:SetPoint("TOPLEFT", button.line, "TOPLEFT", 0, 0) button:SetParent(button.line) button:Show() @@ -1195,6 +1193,10 @@ function QuestieTracker:Update() button:SetParent(UIParent) button:Hide() end + + -- The quest item button owns this slot, so the marker steps out to + -- the left of the line for as long as it is there. + button.line.superTrackButton:SetItemButtonShown(button:IsShown()) else -- Button failed to get setup for some reason or the quest item is now gone. Hide it and enable the Quest Min/Max button. -- See previous comment for details on why we're setting this button to UIParent. @@ -1289,7 +1291,7 @@ function QuestieTracker:Update() -- Attach button to Quest Title linePool altButton:SetPoint("TOPLEFT", altButton.line, "TOPLEFT", - superTrackMarginLeft + 2 + questItemButtonSize, 0) + 2 + questItemButtonSize, 0) altButton:SetParent(altButton.line) altButton:Show() @@ -1590,6 +1592,16 @@ function QuestieTracker:Update() -- Adds 2 pixels and "Padding Between Quests" setting in Tracker Options line:SetHeight(line.label:GetHeight() + (Questie.db.profile.trackerQuestPadding + 2)) + + -- Centre the supertrack button on the quest's whole text block now that its + -- objective lines are drawn and their heights are final. + if questTitleLine.superTrackButton.questId then + local blockHeight = TrackerLinePool.GetQuestBlockHeight(questTitleLine, line) + + if blockHeight then + questTitleLine.superTrackButton:SetBlockHeight(blockHeight) + end + end end primaryButton = false @@ -1648,9 +1660,9 @@ function QuestieTracker:Update() line.criteriaMark:Hide() line.playButton:Hide() - -- Setup Zone Label (indented past the supertrack button gutter, as above) + -- Setup Zone Label line.label:ClearAllPoints() - line.label:SetPoint("TOPLEFT", line, "TOPLEFT", superTrackMarginLeft, 0) + line.label:SetPoint("TOPLEFT", line, "TOPLEFT", 0, 0) -- Set Zone Title and Min/Max states if Questie.db.char.collapsedZones[zoneName] then @@ -1679,15 +1691,15 @@ function QuestieTracker:Update() -- Check and measure Zone Label text width and update tracker width QuestieTracker:UpdateWidth(line.label:GetStringWidth() + trackerMarginLeft + - superTrackMarginLeft + trackerMarginRight) + trackerMarginRight) -- Set Zone Label and Line widths - line.label:SetWidth(trackerBaseFrame:GetWidth() - trackerMarginLeft - superTrackMarginLeft - trackerMarginRight) - line:SetWidth(line.label:GetWidth() + superTrackMarginLeft) + line.label:SetWidth(trackerBaseFrame:GetWidth() - trackerMarginLeft - trackerMarginRight) + line:SetWidth(line.label:GetWidth()) -- Compare largest text Label in the tracker with current Label, then save widest width trackerLineWidth = math.max(trackerLineWidth, - line.label:GetStringWidth() + trackerMarginLeft + superTrackMarginLeft) + line.label:GetStringWidth() + trackerMarginLeft) -- Setup Min/Max Button line.expandZone:ClearAllPoints() diff --git a/Modules/Tracker/TrackerLinePool.lua b/Modules/Tracker/TrackerLinePool.lua index 11a52f9..8f453bc 100644 --- a/Modules/Tracker/TrackerLinePool.lua +++ b/Modules/Tracker/TrackerLinePool.lua @@ -115,19 +115,13 @@ local linePool = {} local buttonPool = {} local lineMarginLeft = 10 --- Gutter given to the supertrack button, which sits flush with the left edge of a quest line. The --- collapse button, the quest item buttons and the labels are all shifted right by this much, so --- nothing lands on top of it and nothing hangs over the tracker's left edge. Fed into --- questMarginLeft, which every width calculation already builds on, so the tracker widens to match. -function TrackerLinePool.GetSuperTrackMarginReserve() - if (not Questie.db.profile.trackerShowSuperTrackButton) or (not TrackerUtils:IsSuperTrackAvailable()) then - return 0 - end +-- Gap kept between the supertrack button and whatever it is tucked in next to. +local superTrackButtonGap = 2 - -- Reserved even for quests whose button is hidden, so the list does not shift around as quests - -- come in and out of the supertrackable set. - return (Questie.db.profile.trackerSuperTrackButtonSize or 25) + 4 -end +-- Left edge of a quest line's collapse button. QuestieTracker anchors it at questMarginLeft - 8 +-- with a width of trackerFontSizeQuest, and questMarginLeft carries a matching + trackerFontSizeQuest, +-- so it lands on a flat 18 whatever the font size is. +local superTrackCollapseButtonLeft = 18 ---@param questFrame Frame function TrackerLinePool.Initialize(questFrame) @@ -529,9 +523,62 @@ function TrackerLinePool.Initialize(questFrame) superTrackButton.SetSuperTrackButton = function(self, questId) self.questId = questId + -- Back to the title line on its own: the objective lines below have not been laid out + -- yet, so the tracker measures the block and calls SetBlockHeight once they are. Same + -- for the quest item button, which is set up further down and owns this slot. + self.blockHeight = nil + self.itemButtonShown = nil self:RefreshSuperTrackButton() end + -- Horizontally: tucked in to the left of whatever else owns the head of the line -- the + -- quest item button where there is one, the collapse button where there is not. It hangs + -- over the line's left edge, and off the tracker entirely at larger sizes; giving the + -- marker a column of its own would mean indenting every quest in the tracker for it. + -- Vertically: centred on the quest's whole text block, title plus objectives, the height + -- the tracker hands us. Without one, centred on the quest title alone, which is all that + -- exists at the point the button is first set up. + superTrackButton.AnchorSuperTrackButton = function(self) + local buttonSize = Questie.db.profile.trackerSuperTrackButtonSize or 25 + local blockHeight = self.blockHeight or Questie.db.profile.trackerFontSizeQuest + local slotLeft = self.itemButtonShown and 0 or superTrackCollapseButtonLeft + local offsetX = slotLeft - superTrackButtonGap - buttonSize + + -- The lines live inside the tracker's scroll frame, which clips anything hanging over + -- its edge, so a marker that reaches past it is reparented above the clip. It stays + -- anchored to its line either way, and every redraw hides it by hand + -- (ResetLinesForChange) before deciding whether to show it again. + self:SetParent(((offsetX + lineMarginLeft) < 0) and trackerQuestFrame or line) + + self:ClearAllPoints() + self:SetPoint("TOPLEFT", line, "TOPLEFT", offsetX, (buttonSize - blockHeight) / 2 + 1) + + -- Has to sit above the tracker backdrop, which is what swallows a frame left at level 0. + -- Strata comes from the line rather than from whichever parent it ended up with, so the + -- two cases draw the same. + self:SetFrameStrata(line:GetFrameStrata()) + self:SetFrameLevel(line:GetFrameLevel() + 10) + end + + superTrackButton.SetBlockHeight = function(self, blockHeight) + if self.blockHeight == blockHeight then + return + end + + self.blockHeight = blockHeight + self:AnchorSuperTrackButton() + end + + superTrackButton.SetItemButtonShown = function(self, shown) + shown = shown and true or false + if (self.itemButtonShown or false) == shown then + return + end + + self.itemButtonShown = shown + self:AnchorSuperTrackButton() + end + superTrackButton.RefreshSuperTrackButton = function(self) -- No map pin means the client has nothing to point the marker at (quest in another zone, -- or a quest without map coordinates), so there is nothing to offer. @@ -581,12 +628,7 @@ function TrackerLinePool.Initialize(questFrame) -- while the mouse is still held down. self:SetPressedOffset(false) - -- Flush with the left edge of the line, in the gutter GetSuperTrackMarginReserve keeps - -- clear. Anchored to the top rather than centred on the line so the button stays level - -- with the first row of a quest title that wraps, matching the collapse button. - local fontSizeQuest = Questie.db.profile.trackerFontSizeQuest - self:ClearAllPoints() - self:SetPoint("TOPLEFT", line, "TOPLEFT", 0, (buttonSize - fontSizeQuest) / 2 + 1) + self:AnchorSuperTrackButton() -- The icon carries the selected variant itself; the glow is the one part the pin draws -- as a separate texture. @@ -596,8 +638,6 @@ function TrackerLinePool.Initialize(questFrame) self.glow:Hide() end - -- Has to sit above the tracker backdrop, which is what swallows a frame left at level 0. - self:SetFrameLevel(line:GetFrameLevel() + 10) self:Show() end @@ -701,6 +741,9 @@ function TrackerLinePool.Initialize(questFrame) line.expandQuest = expandQuest + -- Its own slot in the pool, so a run of lines drawn for one quest can be walked back over. + line.lineIndex = i + linePool[i] = line nextFrame = line end @@ -1060,6 +1103,49 @@ function TrackerLinePool.GetCurrentButton() return buttonPool[buttonIndex] end +-- Height of the block of lines a single quest was drawn into, title line through last objective. +-- Added up from the heights the tracker itself set rather than measured off the frames: on login +-- the tracker has not been laid out yet, and GetTop/GetBottom then report positions from a +-- half-built frame, which is enough to fling a marker centred on the result off the tracker. +---@return number|nil blockHeight +function TrackerLinePool.GetQuestBlockHeight(firstLine, lastLine) + if (not firstLine) or (not lastLine) or (not firstLine.lineIndex) or (not lastLine.lineIndex) then + return nil + end + + if lastLine.lineIndex < firstLine.lineIndex then + return nil + end + + local blockHeight = 0 + for i = firstLine.lineIndex, lastLine.lineIndex do + local line = linePool[i] + if not line then + return nil + end + + blockHeight = blockHeight + line:GetHeight() + end + + -- The last line of a quest carries the padding to the next one. That is empty space below the + -- text, so it plays no part in where the block's centre is. A quest collapsed down to its title + -- is the exception: that single line is the whole quest, and neither reference reads right on + -- its own -- against the text alone the marker rides high over the row's empty half, against + -- the whole row it sits low under the title it belongs to -- so it splits the difference. + local trailingPadding = Questie.db.profile.trackerQuestPadding + 2 + if lastLine.lineIndex == firstLine.lineIndex then + trailingPadding = trailingPadding / 2 + end + + blockHeight = blockHeight - trailingPadding + + if blockHeight <= 0 then + return nil + end + + return blockHeight +end + ---@return table|nil lineIndex linePool[lineIndex - 1] function TrackerLinePool.GetPreviousLine() lineIndex = lineIndex - 1 @@ -1109,6 +1195,10 @@ function TrackerLinePool.HideUnusedLines() line.expandZone.zoneId = nil line.criteriaMark.mode = nil line.playButton.mode = nil + -- Hidden by hand: a marker that overflows to the left of its line is parented above the + -- scroll frame's clip, so hiding the line no longer hides it. + line.superTrackButton.questId = nil + line.superTrackButton:Hide() end end end