275 lines
7.1 KiB
Lua
275 lines
7.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, win))
|
|
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 switchToMaxSelectedCounter(countersMap, selectedCounter, maxPossibleCount)
|
|
local counterPayload = countersMap[selectedCounter]
|
|
|
|
if counterPayload and counterPayload.count then
|
|
countersMap[selectedCounter] = {
|
|
count = maxPossibleCount,
|
|
name = counterPayload.name
|
|
}
|
|
end
|
|
end
|
|
|
|
local function switchToMinSelectedCounter(countersMap, selectedCounter)
|
|
local counterPayload = countersMap[selectedCounter]
|
|
|
|
if counterPayload and counterPayload.count then
|
|
countersMap[selectedCounter] = {
|
|
count = 0,
|
|
name = counterPayload.name
|
|
}
|
|
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
|
|
|
|
local width, height = term.getSize()
|
|
local mainHeight = height - topHeight
|
|
local nbOfElemsPerPage = mainHeight
|
|
local mainWin = window.create(term.current(), 1, 1 + topHeight, width, mainHeight)
|
|
local titleWin = window.create(term.current(), 1, 1, width, 1 + topHeight)
|
|
|
|
local forceExited = false
|
|
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.home then
|
|
selectedCounter = 1
|
|
elseif keyPressed == keys['end'] then
|
|
selectedCounter = nbCounters
|
|
elseif keyPressed == keys.pageUp then
|
|
selectedCounter = math.max(1, selectedCounter - nbOfElemsPerPage)
|
|
elseif keyPressed == keys.pageDown then
|
|
selectedCounter = math.min(nbCounters, selectedCounter + nbOfElemsPerPage)
|
|
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
|
|
switchToMaxSelectedCounter(countersMap, selectedCounter, counterMax - globalCounter)
|
|
globalCounter = getTotalCount(countersMap)
|
|
elseif keyPressed == keys.delete then
|
|
switchToMinSelectedCounter(countersMap, selectedCounter)
|
|
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
|
|
os.pullEvent('key_up') -- fix to avoid writing a 'q' in the terminal on exit
|
|
shouldContinue = false
|
|
forceExited = true
|
|
end
|
|
end
|
|
|
|
mainWin.clear()
|
|
titleWin.clear()
|
|
|
|
-- TODO: better window management on clear
|
|
term.clear()
|
|
term.setCursorPos(1, 1)
|
|
|
|
if forceExited then
|
|
return nil
|
|
end
|
|
|
|
return countersMap, selectedCounter
|
|
end
|
|
|
|
return CountersSelector |