diff --git a/src/Classes/CompareBuySimilar.lua b/src/Classes/CompareBuySimilar.lua index 3559161c67..a2e457f4e7 100644 --- a/src/Classes/CompareBuySimilar.lua +++ b/src/Classes/CompareBuySimilar.lua @@ -347,19 +347,7 @@ function M.openPopup(item, slotName, primaryBuild) uri = result end - -- Helper: create a numeric EditControl without +/- spinner buttons, and - -- with a preset changeFunc - local function newPlainNumericEdit(anchor, rect, init, prompt, limit, integer) - local format = integer and "%D" or "^%d." - local ctrl = new("EditControl", anchor, rect, init, prompt, format, limit, rebuildUrl) - -- Remove the +/- spinner buttons that "%D" filter triggers - ctrl.isNumeric = false - if ctrl.controls then - if ctrl.controls.buttonDown then ctrl.controls.buttonDown.shown = false end - if ctrl.controls.buttonUp then ctrl.controls.buttonUp.shown = false end - end - return ctrl - end + if isUnique then -- Unique item name label controls.nameLabel = new("LabelControl", nil, {0, ctrlY, 0, 16}, "^x" .. (colorCodes[item.rarity] or "FFFFFF"):gsub("%^x","") .. item.name) @@ -378,8 +366,8 @@ function M.openPopup(item, slotName, primaryBuild) -- Item level ctrlY = ctrlY + 4 controls.ilvlLabel = new("LabelControl", {"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Item Level:") - controls.ilvlMin = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Min", 4, true) - controls.ilvlMax = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Max", 4, true) + controls.ilvlMin = tradeHelpers.newPlainNumericEdit(nil, { minFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Min", 4, true, rebuildUrl) + controls.ilvlMax = tradeHelpers.newPlainNumericEdit(nil, { maxFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Max", 4, true, rebuildUrl) ctrlY = ctrlY + rowHeight -- Defence stat rows @@ -387,8 +375,8 @@ function M.openPopup(item, slotName, primaryBuild) local prefix = "def" .. i controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl) controls[prefix .. "Label"] = new("LabelControl", {"LEFT", controls[prefix .. "Check"], "RIGHT"}, {4, 0, 0, 16}, "^7" .. def.label) - controls[prefix .. "Min"] = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, tostring(m_floor(def.value)), "Min", 6, true) - controls[prefix .. "Max"] = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Max", 6, true) + controls[prefix .. "Min"] = tradeHelpers.newPlainNumericEdit(nil, { minFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, tostring(m_floor(def.value)), "Min", 6, true, rebuildUrl) + controls[prefix .. "Max"] = tradeHelpers.newPlainNumericEdit(nil, { maxFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Max", 6, true, rebuildUrl) ctrlY = ctrlY + rowHeight end @@ -445,8 +433,8 @@ function M.openPopup(item, slotName, primaryBuild) -- when the trade site has a dropdown for the value, we opt to disable -- the inputs as they are numeric if not (entry.isOption or entry.needsExactValue) and entry.value then - controls[prefix .. "Min"] = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, controlYPos, fieldW, fieldH}, entry.value ~= 0 and tostring(entry.value) or "", "Min", 8) - controls[prefix .. "Max"] = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, controlYPos, fieldW, fieldH}, "", "Max", 8) + controls[prefix .. "Min"] = tradeHelpers.newPlainNumericEdit(nil, { minFieldX - popupWidth / 2, controlYPos, fieldW, fieldH }, entry.value ~= 0 and tostring(entry.value) or "", "Min", 8, rebuildUrl) + controls[prefix .. "Max"] = tradeHelpers.newPlainNumericEdit(nil, { maxFieldX - popupWidth / 2, controlYPos, fieldW, fieldH }, "", "Max", 8, rebuildUrl) if not canSearch then controls[prefix .. "Min"].enabled = function() return false end controls[prefix .. "Max"].enabled = function() return false end diff --git a/src/Classes/TradeHelpers.lua b/src/Classes/TradeHelpers.lua index 228f244e15..627c923113 100644 --- a/src/Classes/TradeHelpers.lua +++ b/src/Classes/TradeHelpers.lua @@ -529,4 +529,17 @@ function M.drawCompactSlotRow(drawY, slotLabel, pItem, cItem, hoverItem, hoverItemsTab, hoverBoxX, hoverBoxY, hoverBoxW, hoverBoxH end +-- Helper: create a numeric EditControl without +/- spinner buttons, and +-- with a preset changeFunc intended for mod values +function M.newPlainNumericEdit(anchor, rect, init, prompt, limit, integer, changeFunc) + local format = integer and "%D" or "^%d." + local ctrl = new("EditControl", anchor, rect, init, prompt, format, limit, changeFunc) + -- Remove the +/- spinner buttons that "%D" filter triggers + ctrl.isNumeric = false + if ctrl.controls then + if ctrl.controls.buttonDown then ctrl.controls.buttonDown.shown = false end + if ctrl.controls.buttonUp then ctrl.controls.buttonUp.shown = false end + end + return ctrl +end return M diff --git a/src/Classes/TradeQuery.lua b/src/Classes/TradeQuery.lua index b1d3831965..e7ad71554b 100644 --- a/src/Classes/TradeQuery.lua +++ b/src/Classes/TradeQuery.lua @@ -841,6 +841,14 @@ function TradeQueryClass:UpdateDropdownList(row_idx) self.controls["resultDropdown".. row_idx].selIndex = 1 self.controls["resultDropdown".. row_idx]:SetList(dropdownLabels) end +function TradeQueryClass:ResetResultRow(rowIdx) + self.itemIndexTbl[rowIdx] = nil + self.sortedResultTbl[rowIdx] = nil + self.resultTbl[rowIdx] = nil + self.totalPrice[rowIdx] = nil + self:UpdateDropdownList(rowIdx) + self.controls.fullPrice.label = "^7Total Price: " .. self:GetTotalPriceString() +end function TradeQueryClass:UpdateControlsWithItems(row_idx) local sortMode = self.itemSortSelectionList[self.pbItemSortSelectionIndex] local sortedItems, errMsg = self:SortFetchResults(row_idx, sortMode) @@ -857,10 +865,7 @@ function TradeQueryClass:UpdateControlsWithItems(row_idx) self.sortedResultTbl[row_idx] = sortedItems if not sortedItems[1] then - self.itemIndexTbl[row_idx] = nil - self.totalPrice[row_idx] = nil - self.controls.fullPrice.label = "Total Price: " .. self:GetTotalPriceString() - self:UpdateDropdownList(row_idx) + self:ResetResultRow(row_idx) self:SetNotice(self.controls.pbNotice, "^4No compatible items found for this slot.") return end @@ -1134,11 +1139,7 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite return m_min(m_max(index or 1, 1), self.sortedResultTbl[row_idx] and #self.sortedResultTbl[row_idx] or 1) end controls["changeButton"..row_idx] = new("ButtonControl", { "LEFT", controls["name"..row_idx], "LEFT"}, {135 + 8, 0, 80, row_height}, "<< Search", function() - self.itemIndexTbl[row_idx] = nil - self.sortedResultTbl[row_idx] = nil - self.resultTbl[row_idx] = nil - self.totalPrice[row_idx] = nil - self.controls.fullPrice.label = "^7Total Price: " .. self:GetTotalPriceString() + self:ResetResultRow(row_idx) end) controls["changeButton"..row_idx].shown = function() return self.resultTbl[row_idx] end controls["resultDropdown"..row_idx] = new("DropDownControl", { "TOPLEFT", controls["changeButton"..row_idx], "TOPRIGHT"}, {8, 0, 351, row_height}, {}, function(index) diff --git a/src/Classes/TradeQueryGenerator.lua b/src/Classes/TradeQueryGenerator.lua index 41314a37b5..eca7aa77c5 100644 --- a/src/Classes/TradeQueryGenerator.lua +++ b/src/Classes/TradeQueryGenerator.lua @@ -890,6 +890,7 @@ Implicits: 0]] calcFunc = calcFunc, options = options, slot = slot, + requiredMods = options.requiredMods, } -- OnFrame will pick this up and begin the work @@ -990,6 +991,7 @@ function TradeQueryGeneratorClass:FinishQuery() local selectedTradeType = self.tradeTypes[self.tradeTypeIndex] -- Generate trade query str and open in browser local filters = 0 + local requiredMods = self.calcContext.requiredMods or {} local queryTable = { query = { filters = self.calcContext.special.queryFilters or { @@ -1006,6 +1008,10 @@ function TradeQueryGeneratorClass:FinishQuery() type = "weight", value = { min = minWeight }, filters = { } + }, + requiredMods and { + type = "and", + filters = {} } } }, @@ -1032,6 +1038,7 @@ function TradeQueryGeneratorClass:FinishQuery() if options.sockets and options.sockets > 0 then num_extra = num_extra + 1 end + num_extra = num_extra + #requiredMods local effective_max = MAX_FILTERS - num_extra @@ -1057,6 +1064,10 @@ function TradeQueryGeneratorClass:FinishQuery() break end end + for _, entry in ipairs(requiredMods) do + local filters = queryTable.query.stats[2].filters + t_insert(filters, { id = entry.tradeId, value = { min = entry.value } }) + end if not options.includeMirrored then queryTable.query.filters.misc_filters = { disabled = false, @@ -1118,7 +1129,8 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb local controls = { } local options = { } - local popupHeight = 110 + local popupHeight = 80 + local popupWidth = 400 local isJewelSlot = slot and slot.slotName:find("Jewel") ~= nil @@ -1201,15 +1213,22 @@ Remove: anoints are completely ignored, and removed from items.]] end updateLastAnchor(controls.jewelSlot) end - - + -- forward declarations for functions interacting with mod filter selectors + ---@type fun(): table + local getModList + ---@type fun(controls: any, modList: any) + local setModSelectors + -- jewel type selector if isJewelSlot and not context.slotTbl.unique then - controls.jewelType = new("DropDownControl", {"TOPLEFT",lastItemAnchor,"BOTTOMLEFT"}, {0, 5, 100, 18}, { "Base", "Radius" }, function(index, value) end) + controls.jewelType = new("DropDownControl", { "TOPLEFT", lastItemAnchor, "BOTTOMLEFT" }, { 0, 5, 100, 18 }, { "Base", "Radius" }, function(index, value) + -- update mod list for selectors + local mods = getModList() + setModSelectors(controls, mods) + end) controls.jewelType.selIndex = self.lastJewelType or 1 - controls.jewelTypeLabel = new("LabelControl", {"RIGHT",controls.jewelType,"LEFT"}, {-5, 0, 0, 16}, "Jewel Type:") + controls.jewelTypeLabel = new("LabelControl", { "RIGHT", controls.jewelType, "LEFT" }, { -5, 0, 0, 16 }, "Jewel Type:") updateLastAnchor(controls.jewelType) end - -- Add max price limit selection dropbox local currencyDropdownNames = { } for _, currency in ipairs(currencyTable) do @@ -1258,6 +1277,7 @@ Remove: anoints are completely ignored, and removed from items.]] end popupHeight = popupHeight + 4 + local selectedMods = {} controls.generateQuery = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {-45, -10, 80, 20}, "Execute", function() local selectedJewelSlot = controls.jewelSlot and controls.jewelSlot:GetSelValue() if controls.jewelSlot and not selectedJewelSlot then @@ -1309,6 +1329,9 @@ Remove: anoints are completely ignored, and removed from items.]] options.sockets = tonumber(controls.sockets.buf) self.lastSockets = options.sockets end + if #selectedMods > 0 then + options.requiredMods = copyTable(selectedMods) + end options.statWeights = statWeights self:StartQuery(slot, options) @@ -1320,5 +1343,122 @@ Remove: anoints are completely ignored, and removed from items.]] controls.cancel = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {45, -10, 80, 20}, "Cancel", function() main:ClosePopup() end) - main:OpenPopup(400, popupHeight, "Query Options", controls) + + if context.slotTbl.unique then + main:OpenPopup(popupWidth, popupHeight, "Query Options", controls) + return + end + + local _, headerYPos = lastItemAnchor:GetPos() + -- intended width of the whole row, including dropdown and aux controls + local totalWidth = 340 + -- size of min value input + local fieldWidth = 60 + -- size of clear button + local buttonSize = 20 + -- gap between controls + local xSpacing = 4 + local auxControlWidth = buttonSize + fieldWidth + 2 * xSpacing + + local _, lastItemY = lastItemAnchor:GetPos() + local _, lastItemH = lastItemAnchor:GetSize() + controls.modSelectorHeaderAnchor = new("Control", { "TOPLEFT", nil, "TOPLEFT" }, + -- position right below last item, centered horizontally + { (popupWidth - totalWidth) / 2, lastItemH + lastItemY, 0, 0 }, + "") + updateLastAnchor(controls.modSelectorHeaderAnchor) + -- get mod selector list + getModList = function() + _, itemCategory = tradeHelpers.getTradeCategory(slot.slotName, slot and self.itemsTab.items[slot.selItemId]) + -- add radius/base as they have different mods + if controls.jewelType then + itemCategory = controls.jewelType:GetSelValue() .. itemCategory + end + local mods = { { label = "^7+ Add Required Stat" } } + for _, modType in ipairs({ "Explicit", "Implicit", "Corrupted" }) do + for idStr, modData in pairs(self.modData[modType]) do + if modData[itemCategory] ~= nil then + local text = "^7" .. modData.tradeMod.text:gsub("(%a+) Passive Skills in Radius also grant ", "%1: ") + if modType ~= "Explicit" then + -- dim-ish red or the greenish yellow trade site uses for implicits slightly brightened + local colour = modType == "Corrupted" and "^x9E3E38" or "^x989654" + text = text .. string.format(" %s(%s)", colour, modType) + end + t_insert(mods, { label = text, tradeId = modData.tradeMod.id }) + end + end + end + return mods + end + -- amount of mod selectors: technically we could have 40, but the more we have the fewer + -- stats fit in the weighted sum, and this means a static popup size is ok + local maxSelectors = 3 + -- set mod selector dropdown labels, adjust width, and possibly change the mod list + setModSelectors = function(controls, modList) + -- reset selections + if modList then + selectedMods = {} + end + for i = 1, maxSelectors do + local mod = selectedMods[i] + local selector = controls["modSelector" .. i] + local minimumBox = controls["modSelectorMin" .. i] + if modList then + selector:SetList(modList) + end + if mod then + selector:SelByValue(mod.label, "label") + selector.width = totalWidth - auxControlWidth + minimumBox.buf = mod.value or "" + else + selector.selIndex = 1 + selector.width = totalWidth + end + selector:CheckDroppedWidth(true) + end + end + -- mod filter dropdown and aux controls + for i = 1, maxSelectors do + -- dropdown which lists all mods that fit + local dropdown = new("DropDownControl", { "TOPLEFT", lastItemAnchor, "BOTTOMLEFT" }, + { 0, 4, totalWidth, 20 }, nil, + function(idx, val) + if idx == 1 then + table.remove(selectedMods, i) + else + selectedMods[i] = copyTable(val) + end + setModSelectors(controls) + end) + dropdown.shown = function() + return not not selectedMods[i - 1] or i == 1 + end + updateLastAnchor(dropdown) + dropdown:SetList(mods) + controls["modSelector" .. i] = dropdown + + -- box that sets minimum value for filter + local minimumBox = tradeHelpers.newPlainNumericEdit({ "LEFT", lastItemAnchor, "RIGHT" }, + { xSpacing, 0, fieldWidth, buttonSize }, "", "Min", 6, false, function(val) + selectedMods[i].value = tonumber(val) + end) + minimumBox.shown = function() + return not not selectedMods[i] + end + controls["modSelectorMin" .. i] = minimumBox + + -- button which removes the mod row + local clearButton = new("ButtonControl", { "LEFT", minimumBox, "RIGHT" }, { xSpacing, 0, buttonSize, buttonSize }, + "x", function() + table.remove(selectedMods, i) + setModSelectors(controls) + end) + clearButton.shown = function() + return not not selectedMods[i] + end + controls["modSelectorClear" .. i] = clearButton + end + setModSelectors(controls, getModList()) + + main:OpenPopup(popupWidth, popupHeight, "Query Options", controls) end \ No newline at end of file