Implement overview scrolling

This commit is contained in:
Max
2026-06-01 05:04:39 +02:00
parent e5f7da3cc5
commit 8a5e4a0fb1
+240 -22
View File
@@ -1,10 +1,11 @@
local mon = peripheral.find("monitor")
assert(mon, "Kein Monitor gefunden")
local monName = peripheral.getName(mon)
local SCREEN_WIDTH = 40
mon.setTextScale(0.5)
local SCREEN_WIDTH, SCREEN_HEIGHT = mon.getSize()
local oldTerm = term.redirect(mon)
local Pine3D = require("Pine3D")
@@ -20,6 +21,8 @@ local itemById
local defaultBaseId
local fallbackIcon = false
local backButton = false
local scrollUpButton = false
local scrollDownButton = false
local drawOverview
local function ensureChainsLoaded()
@@ -233,6 +236,30 @@ local function getBackButton()
return backButton
end
local function getScrollUpButton()
if scrollUpButton == false then
scrollUpButton = parseNfpImage(table.concat({
" 00 ",
"0000",
"0 0",
}, "\n"))
end
return scrollUpButton
end
local function getScrollDownButton()
if scrollDownButton == false then
scrollDownButton = parseNfpImage(table.concat({
"0 0",
"0000",
" 00 ",
}, "\n"))
end
return scrollDownButton
end
local function imageSize(img)
local w, h = 0, 0
@@ -296,7 +323,12 @@ local function drawNfpScaled(buffer, img, x, y, scaleX, scaleY)
for dy = 0, scaleY - 1 do
for dx = 0, scaleX - 1 do
buffer:setPixel(px + dx, py + dy, col)
local drawX = px + dx
local drawY = py + dy
if drawX >= 1 and drawX <= buffer.width and drawY >= 1 and drawY <= buffer.height then
buffer:setPixel(drawX, drawY, col)
end
end
end
end
@@ -304,6 +336,31 @@ local function drawNfpScaled(buffer, img, x, y, scaleX, scaleY)
end
end
local function fillRect(buffer, x, y, width, height, color)
local startX = math.max(1, x)
local startY = math.max(1, y)
local endX = math.min(buffer.width, x + width - 1)
local endY = math.min(buffer.height, y + height - 1)
if startX > endX or startY > endY then
return
end
for py = startY, endY do
for px = startX, endX do
buffer:setPixel(px, py, color)
end
end
end
local function cellToPixelX(cellX)
return (cellX - 1) * 2 + 1
end
local function cellToPixelY(cellY)
return (cellY - 1) * 3 + 1
end
local function assertBufferValid(frame)
local valid = {
[colors.white] = true,
@@ -335,10 +392,10 @@ local function assertBufferValid(frame)
end
end
local function drawItem(img, cellX, cellY, count)
local function drawItem(img, cellX, cellY, count, offsetY)
-- Normale Monitor-Zellen in Pine3D-Teletext-Pixel umrechnen.
local x = (cellX - 1) * 2 + 1
local y = (cellY - 1) * 3 + 1
local x = cellToPixelX(cellX)
local y = cellToPixelY(cellY) + (offsetY or 0)
local imgW, imgH = 0, 0
@@ -347,7 +404,9 @@ local function drawItem(img, cellX, cellY, count)
if img then
imgW, imgH = imageSize(img)
drawNfpScaled(frame.buffer, img, x, y, scaleX, scaleY)
if y <= frame.buffer.height and y + imgH * scaleY - 1 >= 1 then
drawNfpScaled(frame.buffer, img, x, y, scaleX, scaleY)
end
end
local text = formatCount(count)
@@ -366,11 +425,13 @@ local function drawItem(img, cellX, cellY, count)
dy = 1,
}
-- Schatten
mf.writeOn(frame, text, colors.black, rightX + 1, bottomY + 1, options)
if bottomY >= 1 and y <= frame.buffer.height then
-- Schatten
mf.writeOn(frame, text, colors.black, rightX + 1, bottomY + 1, options)
-- Weißer Count
mf.writeOn(frame, text, colors.white, rightX, bottomY, options)
-- Weißer Count
mf.writeOn(frame, text, colors.white, rightX, bottomY, options)
end
end
local function drawPage(base_id)
@@ -421,10 +482,69 @@ end
drawOverview = function()
local items = getBaseItemIds()
local sortedItemIds = {}
local itemCounts = {}
local visibleItemCount = 0
local totalRows = 0
local maxScrollRow = 0
local currentScrollRow = 0
local targetScrollRow = 0
local refreshTimer
local animationTimer
local columns = 3
local rowsPerView = 3
local baseCellX = 4
local baseCellY = 2
local colStepCells = 12
local rowStepCells = 6
local rowStepPixels = rowStepCells * 3
local scrollbarX = SCREEN_WIDTH - 1
local scrollbarWidth = 2
local scrollbarButtonHeight = 3
local scrollbarTrackY = scrollbarButtonHeight + 1
local scrollbarTrackHeight = SCREEN_HEIGHT - scrollbarButtonHeight * 2
local scrollbarPixelX = cellToPixelX(scrollbarX)
local scrollbarPixelWidth = scrollbarWidth * 2
local scrollbarTrackPixelY = cellToPixelY(scrollbarTrackY)
local scrollbarTrackPixelHeight = math.max(0, scrollbarTrackHeight * 3)
local function clampScrollRow(row)
return math.max(0, math.min(maxScrollRow, row))
end
local function getThumbMetrics()
if scrollbarTrackPixelHeight <= 0 then
return scrollbarTrackPixelY, 0
end
if totalRows <= rowsPerView or maxScrollRow == 0 then
return scrollbarTrackPixelY, scrollbarTrackPixelHeight
end
local thumbHeight = math.max(4, math.floor(scrollbarTrackPixelHeight * rowsPerView / totalRows + 0.5))
local thumbTravel = scrollbarTrackPixelHeight - thumbHeight
local thumbY = scrollbarTrackPixelY + math.floor((currentScrollRow / maxScrollRow) * thumbTravel + 0.5)
return thumbY, thumbHeight
end
local function scheduleAnimation()
if not animationTimer and math.abs(targetScrollRow - currentScrollRow) > 0.001 then
animationTimer = os.startTimer(0.05)
end
end
local function scrollTo(row)
local clampedRow = clampScrollRow(row)
if clampedRow ~= targetScrollRow then
targetScrollRow = clampedRow
scheduleAnimation()
end
end
local function renderOverview()
local itemCounts = getMeItemCounts(items)
itemCounts = getMeItemCounts(items)
for i = 1, #items do
sortedItemIds[i] = items[i]
@@ -441,23 +561,59 @@ drawOverview = function()
return a < b
end)
visibleItemCount = math.min(#sortedItemIds, 9)
totalRows = math.ceil(#sortedItemIds / columns)
maxScrollRow = math.max(0, totalRows - rowsPerView)
currentScrollRow = clampScrollRow(currentScrollRow)
targetScrollRow = clampScrollRow(targetScrollRow)
local firstVisibleRow = math.floor(currentScrollRow)
local rowOffsetPixels = -math.floor((currentScrollRow - firstVisibleRow) * rowStepPixels + 0.5)
local firstVisibleIndex = firstVisibleRow * columns + 1
local lastVisibleIndex = math.min(#sortedItemIds, (firstVisibleRow + rowsPerView + 1) * columns)
frame.buffer:clear()
for i = 1, visibleItemCount do
for i = firstVisibleIndex, lastVisibleIndex do
local itemId = sortedItemIds[i]
local item = getItemById(itemId)
local icon = getItemIcon(item) or getFallbackIcon()
drawItem(icon, 4+(8+4)*((i-1)%3), 2+(5+1)*math.floor((i-1)/3), itemCounts[itemId] or 0)
local relativeIndex = i - firstVisibleIndex
local col = relativeIndex % columns
local row = math.floor(relativeIndex / columns)
drawItem(
icon,
baseCellX + colStepCells * col,
baseCellY + rowStepCells * row,
itemCounts[itemId] or 0,
rowOffsetPixels
)
end
visibleItemCount = math.max(0, math.min(#sortedItemIds - firstVisibleRow * columns, rowsPerView * columns))
local upButtonY = cellToPixelY(1)
local downButtonY = cellToPixelY(SCREEN_HEIGHT - scrollbarButtonHeight + 1)
local upColor = targetScrollRow > 0 and colors.gray or colors.lightGray
local downColor = targetScrollRow < maxScrollRow and colors.gray or colors.lightGray
local thumbY, thumbHeight = getThumbMetrics()
fillRect(frame.buffer, scrollbarPixelX, upButtonY, scrollbarPixelWidth, scrollbarButtonHeight * 3, upColor)
fillRect(frame.buffer, scrollbarPixelX, downButtonY, scrollbarPixelWidth, scrollbarButtonHeight * 3, downColor)
if scrollbarTrackPixelHeight > 0 then
fillRect(frame.buffer, scrollbarPixelX, scrollbarTrackPixelY, scrollbarPixelWidth, scrollbarTrackPixelHeight, colors.gray)
fillRect(frame.buffer, scrollbarPixelX, thumbY, scrollbarPixelWidth, thumbHeight, colors.white)
end
drawNfpScaled(frame.buffer, getScrollUpButton(), scrollbarPixelX, upButtonY + 2, 1, 1)
drawNfpScaled(frame.buffer, getScrollDownButton(), scrollbarPixelX, downButtonY + 3, 1, 1)
assertBufferValid(frame)
frame:drawBuffer()
end
renderOverview()
local refreshTimer = os.startTimer(30)
refreshTimer = os.startTimer(30)
while true do
local event, p1, x, y = os.pullEvent()
@@ -465,16 +621,78 @@ drawOverview = function()
if event == "timer" and p1 == refreshTimer then
renderOverview()
refreshTimer = os.startTimer(30)
scheduleAnimation()
elseif event == "timer" and p1 == animationTimer then
local delta = targetScrollRow - currentScrollRow
if math.abs(delta) <= 0.001 then
currentScrollRow = targetScrollRow
animationTimer = nil
else
local step = delta * 0.35
if step > 0 then
step = math.max(0.08, math.min(step, 0.45))
else
step = math.min(-0.08, math.max(step, -0.45))
end
if math.abs(step) >= math.abs(delta) then
currentScrollRow = targetScrollRow
animationTimer = nil
else
currentScrollRow = currentScrollRow + step
animationTimer = os.startTimer(0.05)
end
end
renderOverview()
elseif event == "monitor_touch" and p1 == monName then
local col = math.floor((x - 4) / 12)
local row = math.floor((y - 2) / 6)
if x >= scrollbarX and x < scrollbarX + scrollbarWidth then
if y <= scrollbarButtonHeight then
scrollTo(targetScrollRow - 1)
elseif y > SCREEN_HEIGHT - scrollbarButtonHeight then
scrollTo(targetScrollRow + 1)
elseif scrollbarTrackHeight > 0 then
local touchPixelY = cellToPixelY(y) + 1
local thumbY, thumbHeight = getThumbMetrics()
if col >= 0 and col < 3 and row >= 0 and row < 3 then
local index = row * 3 + col + 1
if touchPixelY < thumbY then
if maxScrollRow > 0 then
local thumbTravel = scrollbarTrackPixelHeight - thumbHeight
local targetPixelY = math.max(
scrollbarTrackPixelY,
math.min(scrollbarTrackPixelY + thumbTravel, touchPixelY - math.floor(thumbHeight / 2))
)
local progress = (targetPixelY - scrollbarTrackPixelY) / math.max(1, thumbTravel)
scrollTo(progress * maxScrollRow)
end
elseif touchPixelY > thumbY + thumbHeight - 1 then
if maxScrollRow > 0 then
local thumbTravel = scrollbarTrackPixelHeight - thumbHeight
local targetPixelY = math.max(
scrollbarTrackPixelY,
math.min(scrollbarTrackPixelY + thumbTravel, touchPixelY - math.floor(thumbHeight / 2))
)
local progress = (targetPixelY - scrollbarTrackPixelY) / math.max(1, thumbTravel)
scrollTo(progress * maxScrollRow)
end
end
end
else
local col = math.floor((x - baseCellX) / colStepCells)
local firstVisibleRow = math.floor(currentScrollRow)
local rowOffsetPixels = (currentScrollRow - firstVisibleRow) * rowStepPixels
local touchPixelY = cellToPixelY(y) + 1
local row = math.floor((touchPixelY - cellToPixelY(baseCellY) + rowOffsetPixels) / rowStepPixels)
if index <= visibleItemCount then
drawPage(sortedItemIds[index])
return
if col >= 0 and col < columns and row >= 0 and row < rowsPerView + 1 then
local index = (firstVisibleRow + row) * columns + col + 1
if index >= 1 and index <= #sortedItemIds and index <= firstVisibleRow * columns + visibleItemCount + columns then
drawPage(sortedItemIds[index])
return
end
end
end
end