From 85228b134b2289ad45c76208d2daa741f021c2d5 Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Sun, 22 Mar 2026 20:16:01 -0400 Subject: [PATCH] feat: add order quantity popup for item ordering in dashboard --- manager/display.lua | 163 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 4 deletions(-) diff --git a/manager/display.lua b/manager/display.lua index f08e988..bd7ea5d 100644 --- a/manager/display.lua +++ b/manager/display.lua @@ -41,6 +41,9 @@ local selectedAmount = 1 local amountOptions = {1, 4, 8, 16, 32, 64} local searchQuery = "" local showKeyboard = false +local orderPopupItem = nil +local orderPopupShort = nil +local orderPopupQty = 1 local smelterView = "status" ------------------------------------------------- @@ -473,6 +476,117 @@ local function buildMainPage() end, }, + -- Order quantity popup (full-screen overlay; starts disabled) + orderPopup = UI.Window { + x = 1, y = 1, ex = -1, ey = -1, + backgroundColor = colors.black, + enable = function() end, -- toggled manually + draw = function(self) + self:clear(colors.black) + self._zones = {} + + local dw = math.min(self.width - 2, 30) + local dh = 8 + local dx = math.floor((self.width - dw) / 2) + 1 + local dy = math.floor((self.height - dh) / 2) + 1 + + -- Title row (blue background) + local title = "Order: " .. (orderPopupShort or "?") + if #title > dw - 2 then title = title:sub(1, dw - 2) end + self:write(dx, dy, string.rep(" ", dw), colors.blue) + local titleX = dx + math.floor((dw - #title) / 2) + self:write(titleX, dy, title, colors.blue, colors.white) + + -- Dialog body rows (gray background) + for row = 1, dh - 1 do + self:write(dx, dy + row, string.rep(" ", dw), colors.gray) + end + + -- Quantity display (row 2) + local qtyStr = string.format("Quantity: %d", orderPopupQty) + local qtyX = dx + math.floor((dw - #qtyStr) / 2) + self:write(qtyX, dy + 2, qtyStr, colors.gray, colors.white) + + -- Increment buttons (row 4): [-8] [-1] [+1] [+8] + local incBtns = { + { label = " -8 ", delta = -8, bg = colors.red }, + { label = " -1 ", delta = -1, bg = colors.red }, + { label = " +1 ", delta = 1, bg = colors.green }, + { label = " +8 ", delta = 8, bg = colors.green }, + } + local totalIncW = 0 + for _, b in ipairs(incBtns) do totalIncW = totalIncW + #b.label end + totalIncW = totalIncW + (#incBtns - 1) * 2 + local incX = dx + math.floor((dw - totalIncW) / 2) + local incRow = dy + 4 + for _, b in ipairs(incBtns) do + self:write(incX, incRow, b.label, b.bg, colors.white) + table.insert(self._zones, { + x1 = incX, y1 = incRow, + x2 = incX + #b.label - 1, y2 = incRow, + action = "order_delta", data = b.delta, + }) + incX = incX + #b.label + 2 + end + + -- Preset buttons (row 5): [1] [4] [8] [16] [32] [64] + local presets = {1, 4, 8, 16, 32, 64} + local totalPreW = 0 + for _, p in ipairs(presets) do totalPreW = totalPreW + #tostring(p) + 2 end + totalPreW = totalPreW + (#presets - 1) + local preX = dx + math.floor((dw - totalPreW) / 2) + local preRow = dy + 5 + for _, p in ipairs(presets) do + local label = " " .. tostring(p) .. " " + local bg = (p == orderPopupQty) and colors.cyan or colors.lightGray + local fg = (p == orderPopupQty) and colors.white or colors.black + self:write(preX, preRow, label, bg, fg) + table.insert(self._zones, { + x1 = preX, y1 = preRow, + x2 = preX + #label - 1, y2 = preRow, + action = "order_set", data = p, + }) + preX = preX + #label + 1 + end + + -- Action buttons (row 7): [Cancel] [Order] + local cancelLabel = " Cancel " + local orderLabel = " Order " + local actRow = dy + 7 + local cancelX = dx + math.floor(dw / 4) - math.floor(#cancelLabel / 2) + local orderX = dx + math.floor(3 * dw / 4) - math.floor(#orderLabel / 2) + self:write(cancelX, actRow, cancelLabel, colors.red, colors.white) + table.insert(self._zones, { + x1 = cancelX, y1 = actRow, + x2 = cancelX + #cancelLabel - 1, y2 = actRow, + action = "order_cancel", + }) + self:write(orderX, actRow, orderLabel, colors.lime, colors.white) + table.insert(self._zones, { + x1 = orderX, y1 = actRow, + x2 = orderX + #orderLabel - 1, y2 = actRow, + action = "order_confirm", + }) + end, + eventHandler = function(self, event) + if event.type == 'mouse_click' then + if self._zones then + for _, zone in ipairs(self._zones) do + if event.x >= zone.x1 and event.x <= zone.x2 + and event.y >= zone.y1 and event.y <= zone.y2 then + self:emit({ type = zone.action, data = zone.data, element = self }) + return true + end + end + end + -- Click outside dialog dismisses popup + self:emit({ type = 'order_cancel', element = self }) + return true + end + return UI.Window.eventHandler(self, event) + end, + }, + -- Notification overlay notification = UI.Notification { anchor = 'bottom', @@ -504,7 +618,7 @@ local function buildMainPage() searchQuery = searchQuery .. " " end D.refreshItemGrid() - self.searchRow:draw() + selfitem.total self.footerBar:draw() self:sync() return true @@ -534,14 +648,55 @@ local function buildMainPage() elseif event.type == 'grid_select' then local row = event.selected if row and row.name then - local short = shortName(row.name) - state.statusMessage = string.format("Ordering %s x%d...", short, selectedAmount) + -- Hide keyboard if showing + if showKeyboard then + showKeyboard = false + self.keyboard:disable() + end + -- Show order popup + orderPopupItem = row.name + orderPopupShort = shortName(row.name) + orderPopupQty = selectedAmount + UI.Window.enable(self.orderPopup) + self.orderPopup:raise() + self.orderPopup:draw() + self:sync() + end + return true + + elseif event.type == 'order_delta' then + orderPopupQty = math.max(1, math.min(999, orderPopupQty + event.data)) + self.orderPopup:draw() + self:sync() + return true + + elseif event.type == 'order_set' then + orderPopupQty = event.data + self.orderPopup:draw() + self:sync() + return true + + elseif event.type == 'order_confirm' then + if orderPopupItem then + local short = shortName(orderPopupItem) + state.statusMessage = string.format("Ordering %s x%d...", short, orderPopupQty) state.statusColor = colors.cyan state.statusTimer = 10 activity.dispensing = true state.needsRedraw = true - ops.orderItem(row.name, selectedAmount) + ops.orderItem(orderPopupItem, orderPopupQty) end + self.orderPopup:disable() + orderPopupItem = nil + self:draw() + self:sync() + return true + + elseif event.type == 'order_cancel' then + self.orderPopup:disable() + orderPopupItem = nil + self:draw() + self:sync() return true elseif event.type == 'amount_select' then