local utils = require('libs/utils') local function noTitleFn() return "" end local function createWriteWithColor(textColor, backgroundColor, givenWin) local win = givenWin or term local originalTextColor = nil local originalBackgroundColor = nil if textColor then originalTextColor = win.getTextColor() win.setTextColor(textColor) end if backgroundColor then originalBackgroundColor = win.getBackgroundColor() win.setBackgroundColor(backgroundColor) end return function(str) win.write(str) if originalTextColor then win.setTextColor(originalTextColor) end if originalBackgroundColor then win.setBackgroundColor(originalBackgroundColor) end end end local function getTotalCount(countersMap) local total = 0 for _, counterPayload in pairs(countersMap) do if counterPayload then total = total + (counterPayload.count or 0) end end return total end local function dropN(t, n) local result = {} for k,v in pairs(t) do if n == 0 then result[k] = v else n = n - 1 end end return result end local function takeN(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(win, countersMap, selectedCounter, titleFn) local writeRegular = createWriteWithColor(colors.white, colors.black, win) local writeSelected = createWriteWithColor(colors.black, colors.white, win) win.setCursorPos(1, 1) local _, height = win.getSize() -- local nbCounters = utils.sizeof(countersMap) -- local totalCount = getTotalCount(countersMap) local topMargin = 0 local bottomMargin = 0 if titleFn ~= noTitleFn then writeRegular('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 = takeN(dropN(countersMap, nbElementsToOmit), availableHeight) local cursorYIndex = 1 + topMargin for k,v in pairs(displayedCounters) do win.setCursorPos(1, cursorYIndex) local line = tostring(v.name) .. ' ' .. tostring(v.count) if k == selectedCounter then writeSelected(line) else writeRegular(line) end 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 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 topHeight = 0 if titleFn ~= noTitleFn then topHeight = 1 end term.clear() local width, height = term.getSize() local mainWin = window.create(term.current(), 1, 1 + topHeight, width, height - topHeight) local shouldContinue = true while shouldContinue do mainWin.clear() renderCountersMap(mainWin, countersMap, selectedCounter, titleFn) local _, keyPressed, _ = 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 counterPayload = countersMap[selectedCounter] if counterPayload and counterPayload.count and counterPayload.count > 0 then countersMap[selectedCounter] = { count = counterPayload.count - 1, name = counterPayload.name } globalCounter = globalCounter - 1 end elseif keyPressed == keys.right and globalCounter < counterMax then local counterPayload = countersMap[selectedCounter] if counterPayload and counterPayload.count then countersMap[selectedCounter] = { count = counterPayload.count + 1, name = counterPayload.name } globalCounter = globalCounter + 1 end elseif keyPressed == keys.enter then shouldContinue = false end end return countersMap, selectedCounter end return CountersSelector