diff --git a/src/Classes/Tooltip.lua b/src/Classes/Tooltip.lua index 47ae39bf53..31f8efe1bc 100644 --- a/src/Classes/Tooltip.lua +++ b/src/Classes/Tooltip.lua @@ -186,12 +186,26 @@ end function TooltipClass:GetDynamicSize(viewPort) local staticttW, staticttH = self:GetSize() - local columns, ttH = self:CalculateColumns(0, 0, staticttH, staticttW, viewPort) - local ttW = columns * staticttW + local columns, ttH, _, extraColumnWidth = self:CalculateColumns(0, 0, staticttH, staticttW, viewPort) + + -- ensure extra column width has sensible value + extraColumnWidth = (columns > 1 and extraColumnWidth > 0) and extraColumnWidth or staticttW + local ttW = staticttW + (m_max(columns - 1, 0) * extraColumnWidth) return ttW + H_PAD, ttH + V_PAD end +--- Calculates the column breaks, layout heights, and individual rendering instructions for tooltip lines. +--- By default, items exceeding window height will wrap to a new column. +---@param ttY number Base y-coordinate for the tooltip content +---@param ttX number Base x-coordinate for the tooltip content +---@param ttH number The total estimated height of the tooltip content, used to determine column breakpoints +---@param ttW number The pixel width of the primary (first) tooltip column +---@param viewPort table A table `{x, y, width, height}` containing active screen boundaries +---@return number columns The total number of layout columns generated +---@return number maxColumnHeight The maximum pixel height reached across all formatted columns +---@return table drawStack An array of sequential rendering instructions (texts, images, separators, and their coordinates) +---@return number extraColumnWidth The required dynamic pixel width calculated for any additional columns beyond the first function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) local y = ttY + 2 * BORDER_WIDTH if self.titleYOffset then @@ -200,6 +214,7 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) local x = ttX local columns = 1 -- reset to count columns by block heights local currentBlock = 1 + local extraColumnWidth = 0 local maxColumnHeight = 0 local drawStack = {} local font @@ -235,7 +250,7 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) local curX = ttX + ttW / 2 - totalWidth / 2 -- Draw title t_insert(drawStack, {curX, y + (titleSize - titleSize)/2, "LEFT", titleSize, font, title.text}) - curX = curX + DrawStringWidth(titleSize, font, title.text) + 6 + curX = curX + DrawStringWidth(titleSize, font, title.text) + (H_PAD / 2) -- Draw oils local maxOilHeight = 0 @@ -273,12 +288,17 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) if lineCentered == nil then lineCentered = self.center end - local lineX = lineCentered and (x + ttW / 2) or (x + 6) + local lineX = lineCentered and (x + ttW / 2) or (x + (H_PAD / 2)) local lineAlign = lineCentered and "CENTER_X" or "LEFT" t_insert(drawStack, {lineX, y, lineAlign, data.size, font, data.text}) y = y + data.size + 2 + -- track max width for extra columns + if columns > 1 then + extraColumnWidth = m_max(extraColumnWidth, DrawStringWidth(data.size, font, data.text) + H_PAD) + end + elseif data.separatorImage and main.showFlavourText then local sepSize = data.size or 10 if currentBlock ~= data.block and y + sepSize > ttY + math.min(ttH, viewPort.height) then @@ -287,7 +307,7 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) columns = columns + 1 end currentBlock = data.block - t_insert(drawStack, {{ handle = data.separatorImage, isSeparator = true }, x + 6, y, ttW - 12, sepSize}) + t_insert(drawStack, {{ handle = data.separatorImage, isSeparator = true }, x + (H_PAD / 2), y, ttW - H_PAD, sepSize}) y = y + sepSize + 2 elseif self.lines[i + 1] and self.lines[i - 1] and self.lines[i + 1].text then @@ -298,9 +318,51 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) maxColumnHeight = m_max(y - ttY + 2 * BORDER_WIDTH, maxColumnHeight) end - return columns, maxColumnHeight, drawStack -end + -- Resizing/Shrinking drawStack elements in extra columns + -- NOTE: this logic depends on the current structure of `drawStack` --> needs adjustment if lengths or coordinates logic changes + if columns > 1 and extraColumnWidth > 0 then + for _, line in ipairs(drawStack) do + local isText = #line >= 6 -- Text elements have 6 props, images/separators have 5 + local xIdx = isText and 1 or 2 -- `x` value at index 1 for text, 2 otherwise + local origX = line[xIdx] + + -- calculate column index (origX is at least x * original widths from start) + local colIndex = m_floor((origX - ttX) / ttW) + 1 + + if colIndex > 1 then + local oldBaseX = ttX + ttW * (colIndex - 1) + local newBaseX = ttX + ttW + extraColumnWidth * (colIndex - 2) -- `- 2` because first column is unchanged + + -- Update x coordinates + if isText and line[3] == "CENTER_X" then + -- centered texts + line[xIdx] = newBaseX + extraColumnWidth / 2 + else + -- "LEFT" aligned text and images (NOTE: "RIGHT" aligned does not seem to exist) + line[xIdx] = origX - oldBaseX + newBaseX + end + + -- Resize separators/dividers (technically unlikely to appear in extra columns, but just in case) + if not isText then + -- separator images have `width` value at index 4 + if line[1] and type(line[1]) == "table" and line[1].isSeparator then + line[4] = extraColumnWidth - H_PAD -- "fancy" separators get extra padding + else + line[4] = extraColumnWidth - BORDER_WIDTH + end + end + end + end + end + return columns, maxColumnHeight, drawStack, extraColumnWidth +end +--- Draws tooltip to screen +---@param x number x-coordinate to draw the tooltip at +---@param y number y-coordinate to draw the tooltip at +---@param w number|nil optional width of the UI element being hovered over. Tooltip will position itself outside this box (if possible) +---@param h number|nil optional height of the UI element being hovered over. Needs to be provided alongside `w` +---@param viewPort table A table `{x, y, width, height}` contains active screen boundaries function TooltipClass:Draw(x, y, w, h, viewPort) if #self.lines == 0 then return @@ -355,7 +417,8 @@ function TooltipClass:Draw(x, y, w, h, viewPort) end local ttX = x local ttY = y - if w and h then + local isHoverToolTip = w and h -- `w` and `h` typically only provided for hover tooltips + if isHoverToolTip then ttX = ttX + w + 5 if ttX + ttW > viewPort.x + viewPort.width then ttX = m_max(viewPort.x, x - 5 - ttW) @@ -367,13 +430,34 @@ function TooltipClass:Draw(x, y, w, h, viewPort) ttY = m_max(viewPort.y, y + h - ttH) end end - - local columns, maxColumnHeight, drawStack = self:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) + -- Initial column calculation + local columns, maxColumnHeight, drawStack, extraColumnWidth = self:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) + + -- ensure extraColumnWidth has sensible value and calculate new total width (original width + extraColumns) + extraColumnWidth = (columns > 1 and extraColumnWidth > 0) and extraColumnWidth or ttW + local totalDrawWidth = ttW + (m_max(columns - 1, 0) * extraColumnWidth) + + -- If hover tooltip and extra columns don't fit, shift to left and adjust drawStack (because hover tooltips can't scroll) + if columns > 1 and isHoverToolTip and totalDrawWidth + ttX >= viewPort.x + viewPort.width then + local newX = m_max(viewPort.x, viewPort.x + viewPort.width - totalDrawWidth) + local offsetX = newX - ttX + ttX = newX + + for _, line in ipairs(drawStack) do + if #line < 6 then + -- Text element entries have 6 entries and `x` at `[2]` + line[2] = line[2] + offsetX + else + -- Image, Separators, etc. have 5 entries and `x` at `[1]` + line[1] = line[1] + offsetX + end + end + end -- background shading currently must be drawn before text lines. API change will allow something like the commented lines below SetDrawColor(0, 0, 0, .85) --SetDrawLayer(nil, GetDrawLayer() - 5) - DrawImage(nil, ttX, ttY + BORDER_WIDTH, ttW * columns - BORDER_WIDTH, maxColumnHeight - 2 * BORDER_WIDTH) + DrawImage(nil, ttX, ttY + BORDER_WIDTH, totalDrawWidth - BORDER_WIDTH, maxColumnHeight - 2 * BORDER_WIDTH) --SetDrawLayer(nil, GetDrawLayer()) SetDrawColor(1, 1, 1) @@ -517,11 +601,16 @@ function TooltipClass:Draw(x, y, w, h, viewPort) else SetDrawColor(unpack(self.color)) end + + -- draw vertical borders, accounting for separate extra column width for i = 0, columns do - DrawImage(nil, ttX + ttW * i - BORDER_WIDTH * math.ceil(i^2 / (i^2 + 1)), ttY, BORDER_WIDTH, maxColumnHeight) + local extraColXOffset = i > 0 and ttW + ((i - 1) * extraColumnWidth) or 0 + local currentX = ttX + extraColXOffset + DrawImage(nil, currentX - BORDER_WIDTH * math.ceil(i^2 / (i^2 + 1)), ttY, BORDER_WIDTH, maxColumnHeight) end - DrawImage(nil, ttX, ttY, ttW * columns, BORDER_WIDTH) -- top border - DrawImage(nil, ttX, ttY + maxColumnHeight - BORDER_WIDTH, ttW * columns, BORDER_WIDTH) -- bottom border + -- draw horizontal borders + DrawImage(nil, ttX, ttY, totalDrawWidth, BORDER_WIDTH) -- top + DrawImage(nil, ttX, ttY + maxColumnHeight - BORDER_WIDTH, totalDrawWidth, BORDER_WIDTH) -- bottom return ttW, ttH end