local utils = require('libs/utils') local function noTitleFn() return "" end local savedTextColor = nil local savedBackgroundColor = nil local function saveTermConfig() savedTextColor = term.getTextColor() savedBackgroundColor = term.getBackgroundColor() end local function restoreTermConfig() term.setTextColor(savedTextColor) term.setBackgroundColor(savedBackgroundColor) end local function getTotalCount(countersMap) local total = 0 for _, counter in pairs(countersMap) do total = total + (counter or 0) end return total end local function omitN(t, n) local result = {} for k,v in pairs(t) do if n == 0 then result[k] = v end n = n - 1 end return result end local function pickN(t, n) local result = {} for k,v in pairs(t) do if n == 0 then break end result[k] = v n = n - 1 end return result end local TITLE_MARGIN = 1 local function renderCountersMap(countersMap, selectedCounter, titleFn) term.setCursorPos(1, 1) local _, height = term.getSize() -- local nbCounters = utils.sizeof(countersMap) local selectedCounterKey = countersMap[selectedCounter] -- local totalCount = getTotalCount(countersMap) local topMargin = 0 local bottomMargin = 0 if titleFn ~= noTitleFn then term.clearLine() term.write('custom title: ' .. titleFn(countersMap, selectedCounter)) topMargin = TITLE_MARGIN end local availableHeight = height - topMargin - bottomMargin local selectedPage = math.floor(selectedCounter / availableHeight) + 1 -- local totalPages = (nbCounters % availableHeight) + 1 local nbElementsToOmit = (selectedPage - 1) * availableHeight local displayedCounters = pickN(omitN(countersMap, nbElementsToOmit), availableHeight) local cursorYIndex = 1 + topMargin for k,v in pairs(displayedCounters) do term.clearLine() term.setCursorPos(1, cursorYIndex) if k == selectedCounterKey then term.setBackgroundColor(colors.white) term.setTextColor(colors.black) else term.setBackgroundColor(colors.black) term.setTextColor(colors.white) end term.write(tostring(k) .. ' ' .. tostring(v)) cursorYIndex = cursorYIndex + 1 end end local function CountersSelector(initialCountersMap, config) local countersMap = utils.shallowClone(initialCountersMap) local counterMax = config.counterMax local titleFn = config.titleFn or noTitleFn if not counterMax then error('no counterMax found in CountersSelector config') end if utils.sizeof(countersMap) == 0 then error('empty countersMap provided') end saveTermConfig() term.clear() local selectedCounter = 1 local nbCounters = utils.sizeof(countersMap) local globalCounter = getTotalCount(countersMap) if globalCounter > counterMax then error('counter cannot be greater than the counterMax') end local shouldContinue = true while shouldContinue do renderCountersMap(countersMap, selectedCounter, titleFn) local _, keyPressed, isHeld = os.pullEvent('key') if keyPressed == keys.up then selectedCounter = math.max(1, selectedCounter - 1) elseif keyPressed == keys.down then selectedCounter = math.min(nbCounters, selectedCounter + 1) elseif keyPressed == keys.left and globalCounter > 0 then local currentCount = countersMap[selectedCounter] if currentCount and currentCount > 0 then countersMap[selectedCounter] = currentCount - 1 globalCounter = globalCounter - 1 end elseif keyPressed == keys.right and globalCounter < counterMax then local currentCount = countersMap[selectedCounter] if currentCount then countersMap[selectedCounter] = currentCount + 1 globalCounter = globalCounter + 1 end elseif keyPressed == keys.enter then shouldContinue = false end end restoreTermConfig() return countersMap, selectedCounter end return CountersSelector