minecraft-cc-tools/libs/ui/CountersSelector.lua
2024-05-23 22:30:40 +02:00

245 lines
6.1 KiB
Lua

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 resetAllCounters(countersMap)
local result = {}
for k, counterPayload in pairs(countersMap) do
result[k] = {
name = counterPayload.name,
count = 0
}
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)
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 incrementSelectedCounter(countersMap, selectedCounter)
local counterPayload = countersMap[selectedCounter]
if counterPayload and counterPayload.count then
countersMap[selectedCounter] = {
count = counterPayload.count + 1,
name = counterPayload.name
}
return true
end
return false
end
local function decrementSelectedCounter(countersMap, selectedCounter)
local counterPayload = countersMap[selectedCounter]
if counterPayload and counterPayload.count and counterPayload.count > 0 then
countersMap[selectedCounter] = {
count = counterPayload.count - 1,
name = counterPayload.name
}
return true
end
return false
end
local function switchMinMaxSelectedCounter(countersMap, selectedCounter, maxPossibleCount)
local counterPayload = countersMap[selectedCounter]
if counterPayload and counterPayload.count then
if counterPayload.count > 0 then
countersMap[selectedCounter] = {
count = 0,
name = counterPayload.name
}
else
countersMap[selectedCounter] = {
count = maxPossibleCount,
name = counterPayload.name
}
end
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
if decrementSelectedCounter(countersMap, selectedCounter) then
globalCounter = globalCounter - 1
end
elseif keyPressed == keys.right and globalCounter < counterMax then
if incrementSelectedCounter(countersMap, selectedCounter) then
globalCounter = globalCounter + 1
end
elseif keyPressed == keys.m then
switchMinMaxSelectedCounter(countersMap, selectedCounter, counterMax - globalCounter)
globalCounter = getTotalCount(countersMap)
elseif keyPressed == keys.r then
countersMap = resetAllCounters(countersMap)
globalCounter = 0
elseif keyPressed == keys.enter then
shouldContinue = false
elseif keyPressed == keys.q then
return nil
end
end
return countersMap, selectedCounter
end
return CountersSelector