local utils = require('libs/utils') local function noTitleFn() return "" end local function withColor(win, textColor, backgroundColor, callbackFn) 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 local result = table.pack(callbackFn(win)) if originalTextColor then win.setTextColor(originalTextColor) end if originalBackgroundColor then win.setBackgroundColor(originalBackgroundColor) end return table.unpack(result) end -- local function createWriteWithColor(textColor, backgroundColor, givenWin) -- local win = givenWin or term -- return function(str) -- return withColor(win, textColor, backgroundColor, function() -- return win.write(str) -- 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 function renderCountersMap(win, countersMap, selectedCounter) win.clear() win.setCursorPos(1, 1) local _, height = win.getSize() -- local nbCounters = utils.sizeof(countersMap) -- local totalCount = getTotalCount(countersMap) -- if titleFn ~= noTitleFn then -- withColor(win, colors.white, colors.green, function() -- win.clearLine() -- win.write(titleFn(countersMap, selectedCounter)) -- end) -- -- topMargin = TITLE_MARGIN -- end local selectedPage = math.floor((selectedCounter - 1) / height) + 1 -- local totalPages = (nbCounters % height) + 1 local nbElementsToOmit = (selectedPage - 1) * height local displayedCounters = takeN(dropN(countersMap, nbElementsToOmit), height) local cursorYIndex = 1 for k,v in pairs(displayedCounters) do win.setCursorPos(1, cursorYIndex) local writeLine = function() win.write(tostring(v.name) .. ' ' .. tostring(v.count)) end if k == selectedCounter then withColor(win, colors.black, colors.white, writeLine) else withColor(win, colors.white, colors.black, writeLine) end cursorYIndex = cursorYIndex + 1 end end local function renderTitle(win, countersMap, selectedCounter, titleFn) win.clear() win.setCursorPos(1, 1) withColor(win, colors.white, colors.green, function() win.clearLine() win.write(titleFn(countersMap, selectedCounter)) 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 = 1 term.clear() local width, height = term.getSize() local mainWin = window.create(term.current(), 1, 1 + topHeight, width, height - topHeight) local titleWin = window.create(term.current(), 1, 1, width, 1 + topHeight) local shouldContinue = true while shouldContinue do renderTitle(titleWin, countersMap, selectedCounter, titleFn) renderCountersMap(mainWin, countersMap, selectedCounter) 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