Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- tableUtils18.lua
- local tableUtils = {}
- -- Writes text with specified colors and restores original colors afterward
- function tableUtils.writeText(target, text, textColor, backgroundColor, y, fillLine)
- local originalTextColor = target.getTextColor()
- local originalBackgroundColor = target.getBackgroundColor()
- local width = target.getSize()
- if y then
- target.setCursorPos(1, y)
- end
- target.setTextColor(textColor)
- target.setBackgroundColor(backgroundColor)
- if fillLine then
- text = text .. string.rep(" ", width - #text)
- end
- target.write(text)
- target.setTextColor(originalTextColor)
- target.setBackgroundColor(originalBackgroundColor)
- end
- -- Formats a number into a string with two decimal places
- function tableUtils.formatDecimals(value)
- if type(value) == "number" then
- return string.format("%.2f", value)
- end
- return tostring(value or "N/A")
- end
- -- Formats a string to keep only the first letter and make it capital
- function tableUtils.formatFirstLetterCapital(value)
- if type(value) == "string" and value ~= "" then
- return string.upper(string.sub(value, 1, 1))
- end
- return "N/A"
- end
- -- Formats a location table into a string (e.g., "x, y, z")
- function tableUtils.formatLocation(v)
- if type(v) == "table" and v.x and v.y and v.z then
- return string.format("%d, %d, %d", v.x, v.y, v.z)
- else
- return "N/A"
- end
- end
- -- Formats a list of resources into a comma-separated string
- function tableUtils.formatResources(resources)
- if type(resources) ~= "table" then return "N/A" end
- local names = {}
- for _, resource in ipairs(resources) do
- table.insert(names, resource.displayName or "N/A")
- end
- return table.concat(names, ", ")
- end
- -- Sums a specific field in a table of items
- function tableUtils.sumFieldInTable(data, fieldToSum)
- if not data or type(data) ~= "table" or #data == 0 then
- return "N/A"
- end
- local total = 0
- for _, item in ipairs(data) do
- if item[fieldToSum] then
- total = total + item[fieldToSum]
- end
- end
- return total
- end
- -- Processes records into rows based on the provided fields
- function tableUtils.processRecords(records, fields)
- local rows = {}
- for _, record in ipairs(records) do
- local row = {}
- for _, field in ipairs(fields) do
- local parts = {}
- for part in field.path:gmatch("[^.]+") do
- table.insert(parts, part)
- end
- local value = record
- for _, part in ipairs(parts) do
- value = value[part]
- if value == nil then break end
- end
- if field.formatter then
- value = field.formatter(value) or "N/A"
- else
- if type(value) == "boolean" then
- value = value and "True" or "False"
- else
- value = tostring(value or "N/A")
- end
- end
- table.insert(row, value)
- end
- table.insert(rows, row)
- end
- return rows
- end
- -- Flattens nested records into a single list, extracting a specific field
- function tableUtils.flattenRecords(data, field)
- if not data or type(data) ~= "table" or #data == 0 then
- return "N/A"
- end
- local records = {}
- for _, outerTable in ipairs(data) do
- if outerTable and outerTable[field] then
- table.insert(records, outerTable[field])
- end
- end
- if #records == 0 then
- return "N/A"
- end
- return table.concat(records, ", ")
- end
- -- Sorts records based on the provided sort configuration
- function tableUtils.sortRecords(records, sortConfig)
- if not sortConfig then return records end
- table.sort(records, function(a, b)
- local parts = {}
- for part in sortConfig.field:gmatch("[^.]+") do
- table.insert(parts, part)
- end
- local valueA = a
- local valueB = b
- for _, part in ipairs(parts) do
- valueA = valueA and valueA[part]
- valueB = valueB and valueB[part]
- end
- if valueA == nil then return false end
- if valueB == nil then return true end
- local numA, numB = tonumber(valueA), tonumber(valueB)
- if numA and numB then
- if sortConfig.direction == "desc" then
- return numA > numB
- else
- return numA < numB
- end
- else
- if sortConfig.direction == "desc" then
- return tostring(valueA) > tostring(valueB)
- else
- return tostring(valueA) < tostring(valueB)
- end
- end
- end)
- return records
- end
- -- Calculates column widths based on the provided fields and rows
- function tableUtils.calculateColumnWidths(rows, fields)
- local colWidths = {}
- for i, field in ipairs(fields) do
- colWidths[i] = #field.header
- for _, row in ipairs(rows) do
- colWidths[i] = math.max(colWidths[i], #row[i])
- end
- colWidths[i] = colWidths[i] + 1 -- Add padding
- end
- return colWidths
- end
- -- Builds a formatted line for output
- function tableUtils.buildLine(values, colWidths)
- local line = ""
- for i, value in ipairs(values) do
- line = line .. value .. " " .. string.rep(" ", colWidths[i] - #value - 1)
- end
- return line
- end
- -- Generates the final output for display
- function tableUtils.generateOutput(rows, colWidths, fields)
- local output = {
- tableUtils.buildLine((function()
- local t = {}
- for _, field in ipairs(fields) do
- table.insert(t, field.header)
- end
- return t
- end)(), colWidths)
- }
- for _, row in ipairs(rows) do
- table.insert(output, tableUtils.buildLine(row, colWidths))
- end
- return output
- end
- -- Displays data on a monitor or terminal
- function tableUtils.displayData(target, titleLines, header, pageData, currentPage, totalPages, totalRecords)
- target.clear()
- if target.setTextScale then
- target.setTextScale(1)
- end
- local width, height = target.getSize()
- local paginationText = string.format("Page %d/%d", currentPage, totalPages)
- local titleLine = titleLines[1]
- local originalTextColor = target.getTextColor()
- local originalBgColor = target.getBackgroundColor()
- target.setCursorPos(1, 1)
- target.setBackgroundColor(titleLine.bgColor)
- target.clearLine()
- target.setCursorPos(1, 1)
- tableUtils.writeText(target, titleLine.text, titleLine.textColor, titleLine.bgColor, nil, false)
- target.setCursorPos(width - #paginationText + 1, 1)
- tableUtils.writeText(target, paginationText, colors.white, titleLine.bgColor, nil, false)
- target.setTextColor(originalTextColor)
- target.setBackgroundColor(originalBgColor)
- for i = 2, #titleLines do
- tableUtils.writeText(target, titleLines[i].text, titleLines[i].textColor, titleLines[i].bgColor, i, true)
- end
- tableUtils.writeText(target, header, colors.gray, colors.black, #titleLines + 1, false)
- local lineY = #titleLines + 2
- for _, line in ipairs(pageData) do
- if lineY >= height then break end
- target.setCursorPos(1, lineY)
- target.setTextColor(colors.white)
- target.write(line)
- lineY = lineY + 1
- end
- target.setTextColor(originalTextColor)
- target.setBackgroundColor(originalBgColor)
- end
- -- Prepares data for display on a monitor or terminal
- function tableUtils.preparePageData(data, fields, target)
- local rows = tableUtils.processRecords(data, fields)
- local colWidths = tableUtils.calculateColumnWidths(rows, fields)
- local output = tableUtils.generateOutput(rows, colWidths, fields)
- return {
- header = output[1],
- dataLines = {unpack(output, 2, #output)},
- width = target.getSize(),
- height = select(2, target.getSize())
- }
- end
- -- Returns a table containing the current page data and pagination information
- function tableUtils.getPageInfo(dataLines, currentPage, pageSize)
- local totalPages = math.max(math.ceil(#dataLines / pageSize), 1)
- currentPage = ((currentPage - 1) % totalPages) + 1
- local startIdx = (currentPage - 1) * pageSize + 1
- return {
- pageData = {unpack(dataLines, startIdx, math.min(currentPage * pageSize, #dataLines))},
- currentPage = currentPage,
- totalPages = totalPages
- }
- end
- -- Refreshes data at regular intervals
- function tableUtils.refreshData(config, state, collectDataCallback)
- while true do
- state.data, state.totalRecords = collectDataCallback(config)
- state.data = tableUtils.sortRecords(state.data, config.sort)
- state.needsRefresh = true
- sleep(config.refreshInterval)
- end
- end
- -- Renders the UI on a monitor and terminal
- function tableUtils.renderUI(config, state)
- while true do
- if state.needsRefresh then
- local monitorPage = tableUtils.preparePageData(state.data or {}, config.monitorFields, config.peripherals.monitor)
- local terminalPage = tableUtils.preparePageData(state.data or {}, config.terminalFields, term)
- state.monitorInfo = tableUtils.getPageInfo(monitorPage.dataLines, state.currentPageMonitor, monitorPage.height - 4)
- state.terminalInfo = tableUtils.getPageInfo(terminalPage.dataLines, state.currentPageTerminal, terminalPage.height - 4)
- local titleLines = {
- {text = config.title.." ("..state.totalRecords..")", textColor = colors.white, bgColor = colors.blue},
- {text = "ALERT MESSAGES", textColor = colors.white, bgColor = colors.red}
- }
- tableUtils.displayData(config.peripherals.monitor, titleLines, monitorPage.header, state.monitorInfo.pageData, state.monitorInfo.currentPage, state.monitorInfo.totalPages, state.totalRecords)
- tableUtils.displayData(term, titleLines, terminalPage.header, state.terminalInfo.pageData, state.terminalInfo.currentPage, state.terminalInfo.totalPages, state.totalRecords)
- state.needsRefresh = false
- end
- sleep(0.1)
- end
- end
- -- Handles input from the monitor and terminal
- function tableUtils.handleInput(state)
- while true do
- parallel.waitForAny(
- function()
- os.pullEvent("monitor_touch")
- state.currentPageMonitor = (state.currentPageMonitor % state.monitorInfo.totalPages) + 1
- state.needsRefresh = true
- end,
- function()
- os.pullEvent("mouse_click")
- state.currentPageTerminal = (state.currentPageTerminal % state.terminalInfo.totalPages) + 1
- state.needsRefresh = true
- end
- )
- end
- end
- return tableUtils
Advertisement
Add Comment
Please, Sign In to add comment