From 1470426cf86a6b1056f3c78b90146e15323c5888 Mon Sep 17 00:00:00 2001 From: xoxorwr Date: Sun, 30 Aug 2026 11:11:47 +0000 Subject: [PATCH 1/2] Apply changes from https://github.com/PathOfBuildingCommunity/PathOfBuilding/pull/9965 --- src/Classes/CalcSectionControl.lua | 293 +++++++++++++++++++++++-- src/Classes/CalcSectionControl.lua.rej | 19 ++ src/Classes/CalcsTab.lua | 24 +- src/Modules/Build.lua | 7 + src/Modules/Build.lua.rej | 43 ++++ 5 files changed, 362 insertions(+), 24 deletions(-) create mode 100644 src/Classes/CalcSectionControl.lua.rej create mode 100644 src/Modules/Build.lua.rej diff --git a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua index 66dea3cb87..795baca127 100644 --- a/src/Classes/CalcSectionControl.lua +++ b/src/Classes/CalcSectionControl.lua @@ -33,7 +33,9 @@ function CalcSectionClass:CalcSectionControl(calcsTab, width, id, group, colour, for _, data in ipairs(subSec.data) do for _, colData in ipairs(data) do + colData.calcSection = self if colData.control then + self.hasControls = true -- Add control to the section's control list and set show/hide function self.controls[colData.controlName] = colData.control colData.control.shown = function() @@ -230,7 +232,6 @@ end function CalcSectionClass:Draw(viewPort, noTooltip) local x, y = self:GetPos() local width, height = self:GetSize() - local cursorX, cursorY = GetCursorPos() local actor = self.calcsTab.input.showMinion and self.calcsTab.calcsEnv.minion or self.calcsTab.calcsEnv.player -- Draw border and background SetDrawLayer(nil, -10) @@ -238,35 +239,289 @@ function CalcSectionClass:Draw(viewPort, noTooltip) DrawImage(nil, x, y, width, height) SetDrawColor(0.10, 0.10, 0.10) DrawImage(nil, x + 2, y + 2, width - 4, height - 4) - + + self:DrawContent(x, y, width, actor, viewPort, false, noTooltip) +end + +function CalcSectionClass:OnKeyDown(key, doubleClick) + if not self:IsShown() or not self:IsEnabled() then + return + end + local mOverControl = self:GetMouseOverControl() + if mOverControl and mOverControl.OnKeyDown then + return mOverControl:OnKeyDown(key) + end + local mOver, mOverComp = self:IsMouseOver() + if key:match("BUTTON") then + if not mOver then + return + end + if mOverComp then + -- Pin the stat breakdown + self.calcsTab:SetDisplayStat(mOverComp, true) + return self.calcsTab.controls.breakdown + end + end + return +end + +function CalcSectionClass:OnKeyUp(key) + if not self:IsShown() or not self:IsEnabled() then + return + end + local mOverControl = self:GetMouseOverControl() + if mOverControl and mOverControl.OnKeyUp then + return mOverControl:OnKeyUp(key) + end + return +end + +function CalcSectionClass:ToggleOverlay() + self.isOverlay = not self.isOverlay + if self.isOverlay then + local x, y = self:GetPos() + self.overlayX = x + self.overlayY = y + t_insert(self.calcsTab.build.overlayPanes, self) + else + local panes = self.calcsTab.build.overlayPanes + for i, pane in ipairs(panes) do + if pane == self then + table.remove(panes, i) + break + end + end + self.dragging = false + end +end + +function CalcSectionClass:RaiseOverlay() + local panes = self.calcsTab.build.overlayPanes + for i, pane in ipairs(panes) do + if pane == self then + table.remove(panes, i) + t_insert(panes, self) + break + end + end +end + +function CalcSectionClass:IsMouseInOverlay(cursorX, cursorY) + if not self.isOverlay or not self.calcsTab.calcsEnv then return false end + local x = self.overlayX + local y = self.overlayY + if cursorX < x or cursorX > x + self.width or cursorY < y then return false end + return cursorY < y + self:GetOverlayHeight() +end + +function CalcSectionClass:GetOverlayHeight() + local height = 28 + local enabled = self.calcsTab.calcsEnv and self.calcsTab:CheckFlag(self) + for i, subSec in ipairs(self.subSection) do + height = height + 22 + if not subSec.collapsed and enabled then + for _, rowData in ipairs(subSec.data) do + if self.calcsTab:CheckFlag(rowData) then + height = height + 18 + end + end + height = height + 2 + elseif i == 1 then + break + end + end + return height +end + +function CalcSectionClass:HandleOverlayClick(key, cursorX, cursorY) + if key ~= "LEFTBUTTON" then return end + + self:RaiseOverlay() + + local x = self.overlayX + local y = self.overlayY + local overlayWidth = self.width + + -- Check close button + local closeX = x + overlayWidth - 18 + local closeY = y + 2 + if cursorX >= closeX and cursorX <= closeX + 14 and cursorY >= closeY and cursorY <= closeY + 16 then + self:ToggleOverlay() + return + end + + local lineY = y + 26 + local primary = true + for i, subSec in ipairs(self.subSection) do + local secEnabled = self.calcsTab:CheckFlag(self) + + -- Check subsection toggle + if secEnabled then + local toggleX = x + overlayWidth - 18 + local toggleY = lineY + 3 + if cursorX >= toggleX and cursorX <= toggleX + 14 and cursorY >= toggleY and cursorY <= toggleY + 16 then + subSec.collapsed = not subSec.collapsed + self.overlayRevision = nil + self.calcsTab.modFlag = true + return + end + end + + if subSec.collapsed or not secEnabled then + if primary then + break + else + lineY = lineY + 20 + primary = false + end + else + lineY = lineY + 20 + primary = false + for _, rowData in ipairs(subSec.data) do + if self.calcsTab:CheckFlag(rowData) then + for _, colData in ipairs(rowData) do + local cellX = x + (colData.xOffset or 134) + local cellW = colData.width or (overlayWidth - 136) + if cursorX >= cellX and cursorX <= cellX + cellW and cursorY >= lineY + 2 and cursorY <= lineY + 19 then + if colData.format and self.calcsTab:CheckFlag(colData) then + self.calcsTab:SetDisplayStat(colData, true) + end + return + end + end + lineY = lineY + 18 + end + end + lineY = lineY + 2 + end + end + + -- Start dragging + if cursorY >= y and cursorY <= y + 24 then + self.dragging = true + self.dragOffX = cursorX - self.overlayX + self.dragOffY = cursorY - self.overlayY + end +end + +function CalcSectionClass:HandleOverlayRelease(key) + if key == "LEFTBUTTON" then + self.dragging = false + end +end + +function CalcSectionClass:DrawOverlay(viewPort, inputEvents) + local cursorX, cursorY = GetCursorPos() + self.overlayBreakdownCell = nil + + if self.overlayRevision ~= self.calcsTab.build.outputRevision then + self:UpdateSize() + self.overlayRevision = self.calcsTab.build.outputRevision + end + + if self.dragging then + self.overlayX = cursorX - self.dragOffX + self.overlayY = cursorY - self.dragOffY + end + + self.overlayX = m_max(viewPort.x, m_min(self.overlayX, viewPort.x + viewPort.width - self.width)) + self.overlayY = m_max(viewPort.y, m_min(self.overlayY, viewPort.y + viewPort.height - 24)) + + local x = self.overlayX + local y = self.overlayY + local overlayWidth = self.width + local actor = self.calcsTab.calcsEnv and (self.calcsTab.input.showMinion and self.calcsTab.calcsEnv.minion or self.calcsTab.calcsEnv.player) + + -- Calculate content height + local totalHeight = self:GetOverlayHeight() + + -- Ensure it's above most other controls + SetDrawLayer(12) + + -- Draw background + SetDrawColor(0.08, 0.08, 0.08, 0.95) + DrawImage(nil, x, y, overlayWidth, totalHeight) + + -- Draw border + SetDrawColor(self.colour) + DrawImage(nil, x, y, overlayWidth, 1) + DrawImage(nil, x, y + totalHeight - 1, overlayWidth, 1) + DrawImage(nil, x, y, 1, totalHeight) + DrawImage(nil, x + overlayWidth - 1, y, 1, totalHeight) + + -- Draw header + SetDrawColor(0.18, 0.18, 0.18) + DrawImage(nil, x + 1, y + 1, overlayWidth - 2, 22) + SetDrawColor(1, 1, 1) + local cbx = x + overlayWidth - 16 + local cby = y + 3 + DrawImageQuad(nil, cbx + 3, cby + 5, cbx + 5, cby + 3, cbx + 13, cby + 11, cbx + 11, cby + 13) + DrawImageQuad(nil, cbx + 11, cby + 3, cbx + 13, cby + 5, cbx + 5, cby + 13, cbx + 3, cby + 11) + + -- Separator + SetDrawColor(self.colour) + DrawImage(nil, x + 2, y + 24, overlayWidth - 4, 1) + + -- Draw content + self:DrawContent(x, y + 26, overlayWidth, actor, viewPort, true) + + -- Draw stat breakdown + if self.calcsTab.displayData and (self.overlayBreakdownCell or (self.calcsTab.displayPinned and self.calcsTab.displayData.calcSection == self)) then + local cd = self.calcsTab.displayData + local origX, origY = cd.x, cd.y + cd.x = x + (cd.xOffset or 134) + cd.y = y + 26 + (cd.yOffset or 0) + self.calcsTab.controls.breakdown:Draw(viewPort) + cd.x, cd.y = origX, origY + end + self.overlayBreakdownCell = nil + + SetDrawLayer(0) +end + +function CalcSectionClass:DrawContent(drawX, startLineY, drawWidth, actor, viewPort, isOverlay, noTooltip) + local cursorX, cursorY = GetCursorPos() + local lineY = startLineY local primary = true - local lineY = y + local enabled = isOverlay and (actor and self.calcsTab:CheckFlag(self)) or self.enabled + for _, subSec in ipairs(self.subSection) do - -- Draw line above label + -- Top border SetDrawColor(self.colour) - DrawImage(nil, x + 2, lineY, width - 4, 2) - SetDrawColor(0.10, 0.10, 0.10) - -- Draw label - if not self.enabled then - DrawString(x + 3, lineY + 3, "LEFT", 16, "VAR BOLD", "^8"..subSec.label) + DrawImage(nil, drawX + 2, lineY, drawWidth - 4, 2) + + -- Label + if not enabled then + local lx = isOverlay and drawX + 4 or drawX + 3 + DrawString(lx, lineY + 3, "LEFT", 16, "VAR BOLD", "^8"..(subSec.label or "")) else + local lx = isOverlay and drawX + 4 or drawX + 3 local textColor = "^7" - if self.calcsTab:SearchMatch(subSec.label) then + if not isOverlay and self.calcsTab:SearchMatch(subSec.label) then textColor = colorCodes.HIGHLIGHT end - DrawString(x + 3, lineY + 3, "LEFT", 16, "VAR BOLD", textColor..subSec.label..":") + DrawString(lx, lineY + 3, "LEFT", 16, "VAR BOLD", textColor..(subSec.label or "")..":") if subSec.data.extra then - local x = x + 3 + DrawStringWidth(16, "VAR BOLD", subSec.label) + 10 - DrawString(x, lineY + 3, "LEFT", 16, "VAR", "^7"..formatCalcStr(subSec.data.extra, actor)) + local ex = lx + DrawStringWidth(16, "VAR BOLD", subSec.label) + (isOverlay and 12 or 10) + DrawString(ex, lineY + 3, "LEFT", 16, "VAR", "^7"..formatCalcStr(subSec.data.extra, actor)) end end - -- Draw line below label + + -- Bottom border SetDrawColor(self.colour) - DrawImage(nil, x + 2, lineY + 20, width - 4, 2) - -- Draw controls - SetDrawLayer(nil, 0) - self:DrawControls(viewPort, noTooltip and self.calcsTab.selControl) - if subSec.collapsed or not self.enabled then + DrawImage(nil, drawX + 2, lineY + 20, drawWidth - 4, 2) + + -- Toggle + if isOverlay then + if enabled then + DrawString(drawX + drawWidth - 16, lineY + 3, "LEFT", 14, "VAR", "^7"..(subSec.collapsed and "+" or "-")) + end + else + SetDrawLayer(nil, 0) + self:DrawControls(viewPort, noTooltip and self.calcsTab.selControl) + end + + if subSec.collapsed or not enabled then if primary then return else diff --git a/src/Classes/CalcSectionControl.lua.rej b/src/Classes/CalcSectionControl.lua.rej new file mode 100644 index 0000000000..d4ec03f759 --- /dev/null +++ b/src/Classes/CalcSectionControl.lua.rej @@ -0,0 +1,19 @@ +diff a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua (rejected hunks) +@@ -4,6 +4,8 @@ + -- Section control used in the Calcs tab + -- + local t_insert = table.insert ++local m_max = math.max ++local m_min = math.min + + local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost", function(self, calcsTab, width, id, group, colour, subSection, updateFunc) + self.Control(calcsTab, {0, 0, width, 0}) +@@ -53,7 +57,7 @@ local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost" + self:ToggleOverlay() + end) + self.controls.popOut.shown = function() +- return self.enabled and not self.isOverlay ++ return self.enabled and not self.isOverlay and not self.hasControls + end + self.isOverlay = false + self.overlayX = 320 diff --git a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua index 4c06f2cd8c..4ed3fe035d 100644 --- a/src/Classes/CalcsTab.lua +++ b/src/Classes/CalcsTab.lua @@ -274,7 +274,7 @@ function CalcsTabClass:Draw(viewPort, inputEvents) local maxY = 0 for _, section in ipairs(self.sectionList) do section:UpdateSize() - if section.enabled then + if section.enabled and not section.isOverlay then local col if section.group == 1 then -- Group 1: Offense or 3 wide sections @@ -323,7 +323,7 @@ function CalcsTabClass:Draw(viewPort, inputEvents) colY[c] = m_max(colY[1], colY[2], colY[3]) end for _, section in ipairs(self.sectionList) do - if section.enabled and (main.portraitMode and section.group == 2 or section.group == 3) then + if section.enabled and not section.isOverlay and (main.portraitMode and section.group == 2 or section.group == 3) then local col = 3 if colY[col] + section.height + 4 >= m_max(viewPort.y + viewPort.height, maxY) then -- No room in the 4th column, find the highest available location in columns 1-4 @@ -345,9 +345,11 @@ function CalcsTabClass:Draw(viewPort, inputEvents) self.controls.scrollBar.height = viewPort.height self.controls.scrollBar:SetContentDimension(maxY - (baseY - 26), viewPort.height) for _, section in ipairs(self.sectionList) do - -- Give sections their actual Y position and let them update - section.y = section.y - self.controls.scrollBar.offset - section:UpdatePos() + if not section.isOverlay then + -- Give sections their actual Y position and let them update + section.y = section.y - self.controls.scrollBar.offset + section:UpdatePos() + end end self.controls.search.y = 4 - self.controls.scrollBar.offset @@ -382,7 +384,15 @@ function CalcsTabClass:Draw(viewPort, inputEvents) self.displayData = nil end + local breakdown = self.controls.breakdown + local overlayBreakdown = breakdown.sourceData and breakdown.sourceData.calcSection and breakdown.sourceData.calcSection.isOverlay + if overlayBreakdown then + breakdown.shown = false + end self:DrawControls(viewPort, self.selControl) + if overlayBreakdown then + breakdown.shown = true + end if self.displayData then if self.displayPinned and not self.selControl then @@ -410,6 +420,10 @@ function CalcsTabClass:SetDisplayStat(displayData, pin) if not displayData or (not pin and self.displayPinned) then return end + if pin and self.displayPinned and self.displayData == displayData then + self:ClearDisplayStat() + return + end self.displayData = displayData self.displayPinned = pin self.controls.breakdown:SetBreakdownData(displayData, pin) diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua index aec7c05ded..d3bbfd4bcf 100644 --- a/src/Modules/Build.lua +++ b/src/Modules/Build.lua @@ -1401,6 +1401,13 @@ function buildMode:OnFrame(inputEvents) self.compareTab:Draw(tabViewPort, inputEvents) end + -- Draw overlay panes on top of all tab content (last = topmost) + for _, pane in ipairs(self.overlayPanes) do + if pane.isOverlay then + pane:DrawOverlay(main.viewPort, inputEvents) + end + end + self.unsaved = self.modFlag or self.notesTab.modFlag or self.partyTab.modFlag or self.configTab.modFlag or self.treeTab.modFlag or self.treeTab.searchFlag or self.spec.modFlag or self.skillsTab.modFlag or self.itemsTab.modFlag or self.calcsTab.modFlag SetDrawLayer(5) diff --git a/src/Modules/Build.lua.rej b/src/Modules/Build.lua.rej new file mode 100644 index 0000000000..c56481f0a5 --- /dev/null +++ b/src/Modules/Build.lua.rej @@ -0,0 +1,43 @@ +diff a/src/Modules/Build.lua b/src/Modules/Build.lua (rejected hunks) +@@ -1178,23 +1178,40 @@ function buildMode:OnFrame(inputEvents) + + -- Consume mouse events for overlay panes before normal input processing + local cursorX, cursorY = GetCursorPos() ++ local breakdown = self.calcsTab.controls.breakdown ++ local overlayBreakdown = self.calcsTab.displayPinned and self.calcsTab.displayData ++ and self.calcsTab.displayData.calcSection and self.calcsTab.displayData.calcSection.isOverlay + for i = #inputEvents, 1, -1 do + local event = inputEvents[i] + if not event then break end + if event.type == "KeyDown" and event.key:match("BUTTON") then +- for _, pane in ipairs(self.overlayPanes) do ++ for paneIndex = #self.overlayPanes, 1, -1 do ++ local pane = self.overlayPanes[paneIndex] + if pane.isOverlay and pane:IsMouseInOverlay(cursorX, cursorY) then + pane:HandleOverlayClick(event.key, cursorX, cursorY) + inputEvents[i] = nil + break + end + end ++ if inputEvents[i] and overlayBreakdown and breakdown:IsMouseOver() then ++ self.overlayBreakdownControl = breakdown:OnKeyDown(event.key, event.doubleClick) ++ inputEvents[i] = nil ++ end + elseif event.type == "KeyUp" and event.key:match("BUTTON") then + for _, pane in ipairs(self.overlayPanes) do + if pane.isOverlay then + pane:HandleOverlayRelease(event.key) + end + end ++ if self.overlayBreakdownControl then ++ self.overlayBreakdownControl:OnKeyUp(event.key) ++ self.overlayBreakdownControl = nil ++ inputEvents[i] = nil ++ end ++ elseif event.type == "KeyUp" and overlayBreakdown and breakdown:IsMouseOver() ++ and (breakdown.controls.scrollBar:IsScrollDownKey(event.key) or breakdown.controls.scrollBar:IsScrollUpKey(event.key)) then ++ breakdown:OnKeyUp(event.key) ++ inputEvents[i] = nil + end + end + From ac59db2ca7a3154df16e84dd00aea0fd36924b3c Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 31 Aug 2026 03:05:48 +1000 Subject: [PATCH 2/2] Fix port --- spec/System/TestCalcSectionOverlay_spec.lua | 162 ++++++++++++++++++++ src/Classes/CalcSectionControl.lua | 132 ++++++++-------- src/Classes/CalcSectionControl.lua.rej | 19 --- src/Modules/Build.lua | 42 +++++ src/Modules/Build.lua.rej | 43 ------ 5 files changed, 269 insertions(+), 129 deletions(-) create mode 100644 spec/System/TestCalcSectionOverlay_spec.lua delete mode 100644 src/Classes/CalcSectionControl.lua.rej delete mode 100644 src/Modules/Build.lua.rej diff --git a/spec/System/TestCalcSectionOverlay_spec.lua b/spec/System/TestCalcSectionOverlay_spec.lua new file mode 100644 index 0000000000..68012933ff --- /dev/null +++ b/spec/System/TestCalcSectionOverlay_spec.lua @@ -0,0 +1,162 @@ +describe("TestCalcSectionOverlay", function() + before_each(function() + newBuild() + end) + + local function findSections() + local pinnable + local controlled + for _, section in ipairs(build.calcsTab.sectionList) do + if section.hasControls then + controlled = controlled or section + else + pinnable = pinnable or section + end + end + return pinnable, controlled + end + + it("initializes overlay state and pop-out controls", function() + assert.same({ }, build.overlayPanes) + + local pinnable, controlled = findSections() + assert.is_not_nil(pinnable) + assert.is_not_nil(controlled) + assert.is_not_nil(pinnable.controls.popOut) + assert.is_not_nil(controlled.controls.popOut) + + pinnable.enabled = true + controlled.enabled = true + assert.is_true(pinnable.controls.popOut.shown()) + assert.is_false(controlled.controls.popOut.shown()) + end) + + it("adds, raises, and removes overlay panes", function() + local first = findSections() + local second + for _, section in ipairs(build.calcsTab.sectionList) do + if section ~= first and not section.hasControls then + second = section + break + end + end + assert.is_not_nil(second) + + first.x, first.y = 100, 120 + second.x, second.y = 200, 220 + first:ToggleOverlay() + second:ToggleOverlay() + assert.same({ first, second }, build.overlayPanes) + assert.is_true(first.isOverlay) + assert.is_false(first.shown()) + + first:RaiseOverlay() + assert.same({ second, first }, build.overlayPanes) + + first:ToggleOverlay() + assert.same({ second }, build.overlayPanes) + assert.is_false(first.isOverlay) + assert.is_false(first.dragging) + end) + + it("closes an overlay through its close button", function() + local section = findSections() + section.x, section.y = 100, 120 + section:ToggleOverlay() + + section:HandleOverlayClick("LEFTBUTTON", section.overlayX + section.width - 10, section.overlayY + 10) + + assert.is_false(section.isOverlay) + assert.same({ }, build.overlayPanes) + end) + + it("draws a populated overlay outside the Calcs tab", function() + build.viewMode = "CALCS" + runCallback("OnFrame") + local section + for _, candidate in ipairs(build.calcsTab.sectionList) do + if candidate.enabled and not candidate.hasControls then + section = candidate + break + end + end + assert.is_not_nil(section) + section:ToggleOverlay() + build.viewMode = "TREE" + + assert.has_no.errors(function() + runCallback("OnFrame") + end) + end) + + it("routes a click only to the topmost overlay", function() + local clicked = { } + local function fakePane(name) + return { + isOverlay = true, + IsMouseInOverlay = function() + return true + end, + HandleOverlayClick = function() + table.insert(clicked, name) + end, + HandleOverlayRelease = function() + end, + DrawOverlay = function() + end, + } + end + build.overlayPanes = { fakePane("bottom"), fakePane("top") } + local inputEvents = { { type = "KeyDown", key = "LEFTBUTTON" } } + + build:OnFrame(inputEvents) + + assert.same({ "top" }, clicked) + assert.is_nil(inputEvents[1]) + end) + + it("unpins a stat breakdown when its cell is clicked again", function() + local displayData + for _, section in ipairs(build.calcsTab.sectionList) do + for _, subSection in ipairs(section.subSection) do + for _, rowData in ipairs(subSection.data) do + for _, colData in ipairs(rowData) do + if colData.format then + displayData = colData + break + end + end + if displayData then break end + end + if displayData then break end + end + if displayData then break end + end + assert.is_not_nil(displayData) + assert.is_not_nil(displayData.calcSection) + build.calcsTab.controls.breakdown.SetBreakdownData = function() + end + + build.calcsTab:SetDisplayStat(displayData, true) + assert.are.equal(displayData, build.calcsTab.displayData) + assert.is_true(build.calcsTab.displayPinned) + + build.calcsTab:SetDisplayStat(displayData, true) + assert.is_nil(build.calcsTab.displayData) + assert.is_nil(build.calcsTab.displayPinned) + end) + + it("does not attach another pane's pinned breakdown to a hovered overlay", function() + local section = findSections() + local pinnedData = { calcSection = section } + local hoveredData = { calcSection = section } + build.calcsTab.controls.breakdown.SetBreakdownData = function() + end + build.calcsTab:SetDisplayStat(pinnedData, true) + + section:SetOverlayDisplayStat(hoveredData) + + assert.are.equal(pinnedData, build.calcsTab.displayData) + assert.is_false(section.overlayBreakdownCell) + end) +end) diff --git a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua index 795baca127..06fe0f0dc6 100644 --- a/src/Classes/CalcSectionControl.lua +++ b/src/Classes/CalcSectionControl.lua @@ -4,6 +4,8 @@ -- Section control used in the Calcs tab -- local t_insert = table.insert +local m_max = math.max +local m_min = math.min ---@class CalcSectionControl: Control, ControlHost local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost") @@ -61,8 +63,20 @@ function CalcSectionClass:CalcSectionControl(calcsTab, width, id, group, colour, end end end + self.controls.popOut = new("ButtonControl"):ButtonControl({ "TOPRIGHT", self, "TOPRIGHT" }, { -22, 3, 16, 16 }, "^", function() + self:ToggleOverlay() + end) + self.controls.popOut.shown = function() + return self.enabled and not self.isOverlay and not self.hasControls + end + self.isOverlay = false + self.overlayX = 320 + self.overlayY = 50 + self.dragging = false + self.dragOffX = 0 + self.dragOffY = 0 self.shown = function() - return self.enabled + return self.enabled and not self.isOverlay end return self end @@ -479,6 +493,11 @@ function CalcSectionClass:DrawOverlay(viewPort, inputEvents) SetDrawLayer(0) end +function CalcSectionClass:SetOverlayDisplayStat(colData) + self.calcsTab:SetDisplayStat(colData) + self.overlayBreakdownCell = self.calcsTab.displayData == colData +end + function CalcSectionClass:DrawContent(drawX, startLineY, drawWidth, actor, viewPort, isOverlay, noTooltip) local cursorX, cursorY = GetCursorPos() local lineY = startLineY @@ -531,86 +550,65 @@ function CalcSectionClass:DrawContent(drawX, startLineY, drawWidth, actor, viewP else lineY = lineY + 20 primary = false - local rows = 0; + local rows = 0 for _, rowData in ipairs(subSec.data) do - if rowData.enabled then + if (isOverlay and actor and self.calcsTab:CheckFlag(rowData)) or (not isOverlay and rowData.enabled) then rows = rows + 1 - local textColor = "^7" - if rowData.color then - textColor = rowData.color - end - if rowData.label then - SetDrawColor(rowData.bgCol or "^0") - DrawImage(nil, x + 2, lineY + 2, 130, 18) - if self.calcsTab:SearchMatch(rowData.label) then - textColor = colorCodes.HIGHLIGHT + if not isOverlay then + local textColor = rowData.color or "^7" + if rowData.label then + SetDrawColor(rowData.bgCol or "^0") + DrawImage(nil, drawX + 2, lineY + 2, 130, 18) + if self.calcsTab:SearchMatch(rowData.label) then + textColor = colorCodes.HIGHLIGHT + end + DrawString(drawX + 132, lineY + 2, "RIGHT_X", 16, "VAR", textColor..rowData.label.."^7:") end - DrawString(x + 132, lineY + 2, "RIGHT_X", 16, "VAR", textColor..rowData.label..":") + elseif rowData.label then + DrawString(drawX + 132, lineY + 2, "RIGHT_X", 16, "VAR", "^7"..rowData.label.."^7:") end - for colour, colData in ipairs(rowData) do - -- Draw column separator at the left end of the cell + for _, colData in ipairs(rowData) do + local cellX = isOverlay and (drawX + (colData.xOffset or 134)) or colData.x + local cellW = isOverlay and (colData.width or (drawWidth - 136)) or colData.width + local cellY = isOverlay and lineY + 2 or colData.y + local cellH = colData.height or 18 + SetDrawColor(self.colour) - DrawImage(nil, colData.x, lineY + 2, 2, colData.height) - if colData.format and self.calcsTab:CheckFlag(colData) then - if cursorY >= viewPort.y and cursorY < viewPort.y + viewPort.height and cursorX >= colData.x and cursorY >= colData.y and cursorX < colData.x + colData.width and cursorY < colData.y + colData.height then - self.calcsTab:SetDisplayStat(colData) + DrawImage(nil, cellX, lineY + 2, 2, cellH) + + if colData.format and (isOverlay or self.calcsTab:CheckFlag(colData)) then + if (isOverlay and actor and self.calcsTab:CheckFlag(colData)) or not isOverlay then + if isOverlay then + if cursorY >= lineY + 2 and cursorY < lineY + 20 and cursorX >= cellX and cursorX < cellX + cellW then + self:SetOverlayDisplayStat(colData) + end + elseif cursorY >= viewPort.y and cursorY < viewPort.y + viewPort.height and cursorX >= cellX and cursorY >= cellY and cursorX < cellX + cellW and cursorY < cellY + cellH then + self.calcsTab:SetDisplayStat(colData) + end + + if not isOverlay and self.calcsTab.displayData == colData then + SetDrawColor(0.25, 1, 0.25) + DrawImage(nil, cellX + 2, cellY, cellW - 2, cellH) + SetDrawColor(rowData.bgCol or "^0") + DrawImage(nil, cellX + 3, cellY + 1, cellW - 4, cellH - 2) + else + SetDrawColor(rowData.bgCol or "^0") + DrawImage(nil, cellX + 2, lineY + 2, cellW - 2, 18) + end + + local textSize = rowData.textSize or 14 + SetViewport(cellX + 3, isOverlay and lineY + 2 or cellY, cellW - 4, 18) + DrawString(1, 9 - textSize / 2, "LEFT", textSize, "VAR", "^7"..formatCalcStr(colData.format, actor, colData)) + SetViewport() end - if self.calcsTab.displayData == colData then - -- This is the display stat, draw a green border around this cell - SetDrawColor(0.25, 1, 0.25) - DrawImage(nil, colData.x + 2, colData.y, colData.width - 2, colData.height) - SetDrawColor(rowData.bgCol or "^0") - DrawImage(nil, colData.x + 3, colData.y + 1, colData.width - 4, colData.height - 2) - else - SetDrawColor(rowData.bgCol or "^0") - DrawImage(nil, colData.x + 2, colData.y, colData.width - 2, colData.height) - end - local textSize = rowData.textSize or 14 - SetViewport(colData.x + 3, colData.y, colData.width - 4, colData.height) - DrawString(1, 9 - textSize/2, "LEFT", textSize, "VAR", "^7"..formatCalcStr(colData.format, actor, colData)) - SetViewport() end end lineY = lineY + 18 end end - -- If there's at least one enabled row in this subsection, offset by the border for the subsection label if rows > 0 then lineY = lineY + 2 end end end end - -function CalcSectionClass:OnKeyDown(key, doubleClick) - if not self:IsShown() or not self:IsEnabled() then - return - end - local mOverControl = self:GetMouseOverControl() - if mOverControl and mOverControl.OnKeyDown then - return mOverControl:OnKeyDown(key) - end - local mOver, mOverComp = self:IsMouseOver() - if key:match("BUTTON") then - if not mOver then - return - end - if mOverComp then - -- Pin the stat breakdown - self.calcsTab:SetDisplayStat(mOverComp, true) - return self.calcsTab.controls.breakdown - end - end - return -end - -function CalcSectionClass:OnKeyUp(key) - if not self:IsShown() or not self:IsEnabled() then - return - end - local mOverControl = self:GetMouseOverControl() - if mOverControl and mOverControl.OnKeyUp then - return mOverControl:OnKeyUp(key) - end - return -end \ No newline at end of file diff --git a/src/Classes/CalcSectionControl.lua.rej b/src/Classes/CalcSectionControl.lua.rej deleted file mode 100644 index d4ec03f759..0000000000 --- a/src/Classes/CalcSectionControl.lua.rej +++ /dev/null @@ -1,19 +0,0 @@ -diff a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua (rejected hunks) -@@ -4,6 +4,8 @@ - -- Section control used in the Calcs tab - -- - local t_insert = table.insert -+local m_max = math.max -+local m_min = math.min - - local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost", function(self, calcsTab, width, id, group, colour, subSection, updateFunc) - self.Control(calcsTab, {0, 0, width, 0}) -@@ -53,7 +57,7 @@ local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost" - self:ToggleOverlay() - end) - self.controls.popOut.shown = function() -- return self.enabled and not self.isOverlay -+ return self.enabled and not self.isOverlay and not self.hasControls - end - self.isOverlay = false - self.overlayX = 320 diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua index d3bbfd4bcf..52137ddeea 100644 --- a/src/Modules/Build.lua +++ b/src/Modules/Build.lua @@ -537,6 +537,8 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin -- ensure that we don't refer to outdated calc tab sections self.breakdownIndex = nil self.compareTab = new("CompareTab"):CompareTab(self) + -- Used for pinned calculation panes + self.overlayPanes = { } -- Load sections from the build file self.savers = { @@ -1332,6 +1334,46 @@ function buildMode:OnFrame(inputEvents) self.spec.allocMode = (self.spec.allocMode + 1) % 3 end end + + -- Consume mouse events for overlay panes before normal input processing + local cursorX, cursorY = GetCursorPos() + local breakdown = self.calcsTab.controls.breakdown + local overlayBreakdown = self.calcsTab.displayPinned and self.calcsTab.displayData + and self.calcsTab.displayData.calcSection and self.calcsTab.displayData.calcSection.isOverlay + for i = #inputEvents, 1, -1 do + local event = inputEvents[i] + if event then + if event.type == "KeyDown" and event.key:match("BUTTON") then + for paneIndex = #self.overlayPanes, 1, -1 do + local pane = self.overlayPanes[paneIndex] + if pane.isOverlay and pane:IsMouseInOverlay(cursorX, cursorY) then + pane:HandleOverlayClick(event.key, cursorX, cursorY) + inputEvents[i] = nil + break + end + end + if inputEvents[i] and overlayBreakdown and breakdown:IsMouseOver() then + self.overlayBreakdownControl = breakdown:OnKeyDown(event.key, event.doubleClick) + inputEvents[i] = nil + end + elseif event.type == "KeyUp" and event.key:match("BUTTON") then + for _, pane in ipairs(self.overlayPanes) do + if pane.isOverlay then + pane:HandleOverlayRelease(event.key) + end + end + if self.overlayBreakdownControl then + self.overlayBreakdownControl:OnKeyUp(event.key) + self.overlayBreakdownControl = nil + inputEvents[i] = nil + end + elseif event.type == "KeyUp" and overlayBreakdown and breakdown:IsMouseOver() + and (breakdown.controls.scrollBar:IsScrollDownKey(event.key) or breakdown.controls.scrollBar:IsScrollUpKey(event.key)) then + breakdown:OnKeyUp(event.key) + inputEvents[i] = nil + end + end + end self:ProcessControlsInput(inputEvents, main.viewPort) self.controls.classDrop:SelByValue(self.spec.curClassId, "classId") diff --git a/src/Modules/Build.lua.rej b/src/Modules/Build.lua.rej deleted file mode 100644 index c56481f0a5..0000000000 --- a/src/Modules/Build.lua.rej +++ /dev/null @@ -1,43 +0,0 @@ -diff a/src/Modules/Build.lua b/src/Modules/Build.lua (rejected hunks) -@@ -1178,23 +1178,40 @@ function buildMode:OnFrame(inputEvents) - - -- Consume mouse events for overlay panes before normal input processing - local cursorX, cursorY = GetCursorPos() -+ local breakdown = self.calcsTab.controls.breakdown -+ local overlayBreakdown = self.calcsTab.displayPinned and self.calcsTab.displayData -+ and self.calcsTab.displayData.calcSection and self.calcsTab.displayData.calcSection.isOverlay - for i = #inputEvents, 1, -1 do - local event = inputEvents[i] - if not event then break end - if event.type == "KeyDown" and event.key:match("BUTTON") then -- for _, pane in ipairs(self.overlayPanes) do -+ for paneIndex = #self.overlayPanes, 1, -1 do -+ local pane = self.overlayPanes[paneIndex] - if pane.isOverlay and pane:IsMouseInOverlay(cursorX, cursorY) then - pane:HandleOverlayClick(event.key, cursorX, cursorY) - inputEvents[i] = nil - break - end - end -+ if inputEvents[i] and overlayBreakdown and breakdown:IsMouseOver() then -+ self.overlayBreakdownControl = breakdown:OnKeyDown(event.key, event.doubleClick) -+ inputEvents[i] = nil -+ end - elseif event.type == "KeyUp" and event.key:match("BUTTON") then - for _, pane in ipairs(self.overlayPanes) do - if pane.isOverlay then - pane:HandleOverlayRelease(event.key) - end - end -+ if self.overlayBreakdownControl then -+ self.overlayBreakdownControl:OnKeyUp(event.key) -+ self.overlayBreakdownControl = nil -+ inputEvents[i] = nil -+ end -+ elseif event.type == "KeyUp" and overlayBreakdown and breakdown:IsMouseOver() -+ and (breakdown.controls.scrollBar:IsScrollDownKey(event.key) or breakdown.controls.scrollBar:IsScrollUpKey(event.key)) then -+ breakdown:OnKeyUp(event.key) -+ inputEvents[i] = nil - end - end -