Files
LeonOS/data/computercraft/lua/rom/apis/window.lua

369 lines
9.2 KiB
Lua
Raw Normal View History

-- window api
local term = require("term")
local colors = require("colors")
local expect = require("cc.expect").expect
local range = require("cc.expect").range
local window = {}
local rep = string.rep
local sub = string.sub
local max = math.max
local min = math.min
local function into_buffer(buf, x, y, text)
if not text then return end
if not buf[y] then return end
text = sub(text, 1, #buf[y] - x + 1)
if x < 1 then
text = sub(text, -x + 2)
x = 1
end
local olen = #buf[y]
if x + #text > olen then
buf[y] = sub(buf[y], 0, max(0, x-1)) .. text
else
buf[y] = sub(buf[y], 0, max(0, x-1)) .. text .. buf[y]:sub(x + #text)
end
buf[y] = sub(buf[y], 1, olen)
end
function window.create(parent, x, y, width, height, visible)
if type(parent) ~= "table" then expect(1, parent, "table") end
if parent == term then
error("do not pass 'term' as a window parent", 0)
end
if type(x) ~= "number" then expect(2, x, "number") end
if type(y) ~= "number" then expect(3, y, "number") end
if type(width) ~= "number" then expect(4, width, "number") end
if type(height) ~= "number" then expect(5, height, "number") end
if type(visible) ~= "boolean" then expect(6, visible, "boolean", "nil") end
if visible == nil then visible = true end
local cursorX, cursorY, cursorBlink = 1, 1, false
local foreground, background = colors.toBlit(colors.white),
colors.toBlit(colors.black)
local textbuf, fgbuf, bgbuf = {}, {}, {}
local win = {}
local palette = {}
for i=0, 15, 1 do
palette[i] = colors.packRGB(parent.getPaletteColor(2^i))
end
local function drawLine(i)
parent.setCursorPos(x, y + i - 1)
if not textbuf[i] then return end
parent.blit(textbuf[i], fgbuf[i], bgbuf[i])
end
local function draw()
local blink = parent.getCursorBlink()
parent.setCursorBlink(false)
local parentW, parentH = parent.getSize()
local firstVisible = math.max(1, -y+2)
for i=1, math.min(height, parentH), 1 do
drawLine(firstVisible+i-1)
end
parent.setCursorBlink(blink)
end
local function restorePalette()
for i=0, 15, 1 do
parent.setPaletteColor(2^i, palette[i])
end
end
local function restoreCursorBlink()
parent.setCursorBlink(cursorBlink)
end
local function restoreCursorPos()
if cursorX > 0 and cursorY > 0 and
cursorX <= width and cursorY <= height then
parent.setCursorPos(x + cursorX - 1, y + cursorY - 1)
else
parent.setCursorPos(0, 0)
end
end
local function restoreCursorColor()
parent.setTextColor(2^tonumber(foreground, 16))
end
function win.write(text)
if type(text) ~= "string" then expect(1, text, "string") end
local fg, bg = rep(foreground, #text), background:rep(#text)
into_buffer(textbuf, cursorX, cursorY, text)
into_buffer(fgbuf, cursorX, cursorY, fg)
into_buffer(bgbuf, cursorX, cursorY, bg)
cursorX = max(-100, min(cursorX + #text, width + 1))
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then win.redraw() end
end
function win.blit(text, tcol, bcol)
if type(text) ~= "string" then expect(1, text, "string") end
if type(tcol) ~= "string" then expect(2, tcol, "string") end
if type(bcol) ~= "string" then expect(3, bcol, "string") end
assert(#text == #tcol and #text == #bcol, "mismatched argument lengths")
into_buffer(textbuf, cursorX, cursorY, text)
into_buffer(fgbuf, cursorX, cursorY, tcol)
into_buffer(bgbuf, cursorX, cursorY, bcol)
cursorX = max(0, min(cursorX + #text, width + 1))
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then
drawLine(cursorY)
restoreCursorColor()
restoreCursorPos()
end
end
function win.clear()
local fore = rep(foreground, width)
local back = rep(background, width)
local blank = rep(" ", width)
for i=1, height, 1 do
textbuf[i] = blank
fgbuf[i] = fore
bgbuf[i] = back
end
if visible then
win.redraw()
end
end
function win.clearLine()
local emptyText, emptyFg, emptyBg =
rep(" ", width),
rep(foreground, width),
rep(background, width)
textbuf[cursorY] = emptyText
fgbuf[cursorY] = emptyFg
bgbuf[cursorY] = emptyBg
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then
win.redraw()
end
end
function win.getCursorPos()
return cursorX, cursorY
end
function win.setCursorPos(_x, _y)
if type(_x) ~= "number" then expect(1, _x, "number") end
if type(_y) ~= "number" then expect(2, _y, "number") end
cursorX, cursorY = _x, _y
if visible then
restoreCursorPos()
end
end
function win.setCursorBlink(blink)
cursorBlink = not not blink
if visible then
restoreCursorBlink()
end
end
function win.getCursorBlink()
return cursorBlink
end
function win.isColor()
return parent.isColor()
end
win.isColour = win.isColor
function win.setTextColor(color)
if type(color) ~= "number" then expect(1, color, "number") end
foreground = colors.toBlit(color) or foreground
if visible then
restoreCursorColor()
end
end
win.setTextColour = win.setTextColor
function win.setPaletteColor(color, r, g, b)
if type(color) ~= "number" then expect(1, color, "number") end
if type(r) ~= "number" then expect(2, r, "number") end
if r < 1 then
if type(g) ~= "number" then expect(3, g, "number") end
if type(b) ~= "number" then expect(4, b, "number") end
palette[math.floor(math.log(color, 2))] = colors.packRGB(r, g, b)
else
palette[math.floor(math.log(color, 2))] = r
end
if visible then
restorePalette()
end
end
win.setPaletteColour = win.setPaletteColor
function win.getPaletteColor(color)
if type(color) ~= "number" then expect(1, color, "number") end
return palette[math.floor(math.log(color, 2))]
end
win.getPaletteColour = win.getPaletteColor
function win.setBackgroundColor(color)
if type(color) ~= "number" then expect(1, color, "number") end
background = colors.toBlit(color)
end
win.setBackgroundColour = win.setBackgroundColor
function win.getSize()
return width, height
end
function win.scroll(n)
if type(n) ~= "number" then expect(1, n, "number") end
if n == 0 then return end
local fg = rep(foreground, width)
local bg = rep(background, width)
local blank = rep(" ", width)
if n > 0 then
for _=1, n, 1 do
table.remove(textbuf, 1)
textbuf[#textbuf+1] = blank
table.remove(fgbuf, 1)
fgbuf[#fgbuf+1] = fg
table.remove(bgbuf, 1)
bgbuf[#bgbuf+1] = bg
end
else
for _=1, -n, 1 do
table.insert(textbuf, 1, blank)
textbuf[#textbuf] = nil
table.insert(fgbuf, 1, fg)
fgbuf[#fgbuf] = nil
table.insert(bgbuf, 1, bg)
bgbuf[#bgbuf] = nil
end
end
if visible then
win.redraw()
end
end
function win.getTextColor()
return 2^tonumber(foreground, 16)
end
win.getTextColour = win.getTextColor
function win.getBackgroundColor()
return 2^tonumber(background, 16)
end
win.getBackgroundColour = win.getBackgroundColor
function win.getLine(ly)
if type(ly) ~= "number" then expect(1, ly, "number") end
if ly < 1 or ly > height then range(ly, 1, height) end
return textbuf[ly], fgbuf[ly], bgbuf[ly]
end
function win.setVisible(vis)
if vis and not visible then
draw()
restorePalette()
restoreCursorBlink()
restoreCursorPos()
restoreCursorColor()
end
visible = not not vis
end
function win.redraw()
if visible then
draw()
restorePalette()
restoreCursorPos()
restoreCursorBlink()
restoreCursorColor()
end
end
function win.restoreCursor()
if visible then
restoreCursorBlink()
restoreCursorPos()
restoreCursorColor()
end
end
function win.getPosition()
return x, y
end
local function resize_buffer(buf, nw, nh, c)
if nw > width then
for i=1, #buf, 1 do
buf[i] = buf[i] .. sub(rep(buf[i], -1), nw - width)
end
end
if nh > #buf then
for _=1, nh - #buf, 1 do
buf[#buf+1] = rep(c, nw)
end
end
end
function win.reposition(nx, ny, nw, nh, npar)
if type(nx) ~= "number" then expect(1, nx, "number") end
if type(ny) ~= "number" then expect(2, ny, "number") end
if type(nw) ~= "number" then expect(3, nw, "number", "nil") end
if type(nh) ~= "number" then expect(4, nh, "number", "nil") end
if type(npar) ~= "table" then expect(5, npar, "table", "nil") end
x, y, width, height, parent =
nx or x, ny or y,
nw or width, nh or height,
npar or parent
resize_buffer(textbuf, width, height, " ")
resize_buffer(fgbuf, width, height, "0")
resize_buffer(bgbuf, width, height, "f")
if visible then
win.redraw()
end
end
function win.at(_x, _y)
win.setCursorPos(_x, _y)
return win
end
win.clear()
return win
end
return window