mirror of
https://github.com/LDDestroier/CC/
synced 2024-11-12 13:00:01 +00:00
a3abda09df
Added the windont.info table, which will tell you miscellaneous information about the API + time in which the render function was last called + list of all windows rendered last + amount of windows rendered last + amount of term.blit calls during last render Fixed term.scroll Fixed transparency Added "meta.renderBuddies" table which renders all windows associated with the main one inside the table after rendering the main one.
373 lines
12 KiB
Lua
373 lines
12 KiB
Lua
-- Windon't
|
|
-- enhanced window API by LDDestroier
|
|
-- intended for general use within all me new programs
|
|
--
|
|
-- Unique features:
|
|
-- + Transparency within windows
|
|
-- + Built-in window layering
|
|
|
|
local to_blit, to_colors = {}, {}
|
|
for i = 1, 16 do
|
|
to_blit[2 ^ (i - 1)] = ("0123456789abcdef"):sub(i, i)
|
|
to_colors[("0123456789abcdef"):sub(i, i)] = 2 ^ (i - 1)
|
|
end
|
|
to_blit[0], to_colors["-"] = "-", 0
|
|
|
|
local getTime = function()
|
|
return 24 * os.day() + os.time()
|
|
end
|
|
|
|
local windont = {
|
|
baseTerm = term.current(),
|
|
config = {
|
|
defaultTextColor = "0", -- default text color (what " " corresponds to in term.blit's second argument)
|
|
defaultBackColor = "f", -- default background color (what " " corresponds to in term.blit's third argument)
|
|
clearScreen = false, -- if true, will clear the screen during render
|
|
},
|
|
info = {
|
|
BLIT_CALLS = 0, -- amount of term.blit calls during the last render
|
|
LAST_RENDER_TIME = 0, -- last time in which render was called
|
|
LAST_RENDER_AMOUNT = 0, -- amount of windows drawn during last render
|
|
LAST_RENDER_WINDOWS = {}, -- table of the last window objects that were rendered
|
|
}
|
|
}
|
|
|
|
-- check if space on screenBuffer is transparent
|
|
local check = function(buff, x, y, blitLayer)
|
|
if buff[blitLayer or 1][y] then
|
|
return (blitLayer or buff[1][y][x]) and (
|
|
(not buff[blitLayer or 2][y][x] or buff[blitLayer or 2][y][x] ~= "-") or
|
|
(not buff[blitLayer or 3][y][x] or buff[blitLayer or 3][y][x] ~= "-")
|
|
) and (
|
|
not (buff[1][y][x] == " " and buff[3][y][x] == "-")
|
|
)
|
|
end
|
|
end
|
|
|
|
-- draws one or more windon't objects
|
|
-- should not draw over any terminal space that isn't occupied by a window
|
|
|
|
windont.render = function(...)
|
|
local windows = {...}
|
|
local bT = windont.baseTerm
|
|
local scr_x, scr_y = bT.getSize()
|
|
local screenBuffer = {{}, {}, {}}
|
|
local blitList = {} -- list of blit commands per line
|
|
local c = 1 -- current blitList entry
|
|
|
|
local cTime = getTime()
|
|
|
|
local AMNT_OF_BLITS = 0 -- how many blit calls are there?
|
|
|
|
local cx, cy -- each window's absolute X and Y
|
|
local buffer
|
|
|
|
for y = 1, scr_y do
|
|
screenBuffer[1][y] = {}
|
|
screenBuffer[2][y] = {}
|
|
screenBuffer[3][y] = {}
|
|
blitList = {}
|
|
c = 1
|
|
for x = 1, scr_x do
|
|
for i = #windows, 1, -1 do
|
|
if windows[i].meta.visible then
|
|
buffer = windows[i].meta.buffer
|
|
cx = x - windows[i].meta.x + 1
|
|
cy = y - windows[i].meta.y + 1
|
|
if check(buffer, cx, cy) then
|
|
screenBuffer[1][y][x] = check(buffer, cx, cy) and buffer[1][cy][cx] or screenBuffer[1][y][x]
|
|
screenBuffer[2][y][x] = check(buffer, cx, cy, 2) and buffer[2][cy][cx] or screenBuffer[3][y][x]
|
|
screenBuffer[3][y][x] = check(buffer, cx, cy, 3) and buffer[3][cy][cx] or screenBuffer[3][y][x]
|
|
end
|
|
end
|
|
end
|
|
if windont.config.clearScreen then
|
|
screenBuffer[1][y][x] = screenBuffer[1][y][x] or " "
|
|
end
|
|
screenBuffer[2][y][x] = screenBuffer[2][y][x] or windont.config.defaultBackColor -- intentionally not the default text color
|
|
screenBuffer[3][y][x] = screenBuffer[3][y][x] or windont.config.defaultBackColor
|
|
if check(screenBuffer, x, y) then
|
|
if check(screenBuffer, x - 1, y) then
|
|
blitList[c][1] = blitList[c][1] .. screenBuffer[1][y][x]
|
|
blitList[c][2] = blitList[c][2] .. screenBuffer[2][y][x]
|
|
blitList[c][3] = blitList[c][3] .. screenBuffer[3][y][x]
|
|
else
|
|
c = x
|
|
blitList[c] = {
|
|
screenBuffer[1][y][x],
|
|
screenBuffer[2][y][x],
|
|
screenBuffer[3][y][x]
|
|
}
|
|
end
|
|
end
|
|
end
|
|
for k,v in pairs(blitList) do
|
|
bT.setCursorPos(k, y)
|
|
bT.blit(v[1], v[2], v[3])
|
|
AMNT_OF_BLITS = AMNT_OF_BLITS + 1
|
|
end
|
|
end
|
|
|
|
windont.info.BLIT_CALLS = AMNT_OF_BLITS
|
|
windont.info.LAST_RENDER_AMOUNT = #windows
|
|
windont.info.LAST_RENDER_WINDOWS = windows
|
|
windont.info.LAST_RENDER_TIME = cTime
|
|
windont.info.LAST_RENDER_DURATION = getTime() - cTime
|
|
|
|
end
|
|
|
|
-- creates a new windon't object that can be manipulated the same as a regular window
|
|
|
|
windont.newWindow = function( x, y, width, height, misc )
|
|
|
|
-- check argument types
|
|
assert(type(x) == "number", "argument #1 must be number, got " .. type(x))
|
|
assert(type(y) == "number", "argument #2 must be number, got " .. type(y))
|
|
assert(type(width) == "number", "argument #3 must be number, got " .. type(width))
|
|
assert(type(height) == "number", "argument #4 must be number, got " .. type(height))
|
|
|
|
-- check argument validity
|
|
assert(x > 0, "x position must be above zero")
|
|
assert(y > 0, "y position must be above zero")
|
|
assert(width > 0, "width must be above zero")
|
|
assert(height > 0, "height must be above zero")
|
|
|
|
local bT = windont.baseTerm
|
|
|
|
local output = {}
|
|
misc = misc or {}
|
|
local meta = {
|
|
x = x or 1, -- x position of the window
|
|
y = y or 1, -- y position of the window
|
|
width = width, -- width of the buffer
|
|
height = height, -- height of the buffer
|
|
buffer = {}, -- stores contents of terminal in buffer[1][y][x] format
|
|
renderBuddies = {}, -- renders any other window objects stored here after rendering here
|
|
|
|
cursorX = misc.cursorX or 1,
|
|
cursorY = misc.cursorY or 1,
|
|
|
|
textColor = misc.textColor or windont.config.defaultTextColor, -- current text color
|
|
backColor = misc.backColor or windont.config.defaultBackColor, -- current background color
|
|
|
|
blink = true, -- cursor blink
|
|
isColor = bT.isColor(), -- if true, then it's an advanced computer
|
|
alwaysRender = false, -- render after every terminal operation
|
|
visible = true, -- if false, don't render ever
|
|
|
|
-- make a new buffer (optionally uses an existing buffer as a reference)
|
|
newBuffer = function(width, height, char, text, back, drawAtop)
|
|
local output = drawAtop or {{}, {}, {}}
|
|
for y = 1, height do
|
|
output[1][y] = output[1][y] or {}
|
|
output[2][y] = output[2][y] or {}
|
|
output[3][y] = output[3][y] or {}
|
|
for x = 1, width do
|
|
output[1][y][x] = output[1][y][x] or char or " "
|
|
output[2][y][x] = output[2][y][x] or text or "0"
|
|
output[3][y][x] = output[3][y][x] or back or "f"
|
|
end
|
|
end
|
|
return output
|
|
end
|
|
}
|
|
|
|
-- initialize the buffer
|
|
meta.buffer = meta.newBuffer(meta.width, meta.height, " ", meta.textColor, meta.backColor)
|
|
|
|
output.meta = meta
|
|
|
|
output.write = function(text)
|
|
assert(type(text) == "string", "argument must be string")
|
|
for i = 1, #text do
|
|
if meta.cursorX >= 1 and meta.cursorX <= meta.width and meta.cursorY >= 1 and meta.cursorY <= meta.height then
|
|
meta.buffer[1][meta.cursorY][meta.cursorX] = text:sub(i,i)
|
|
meta.buffer[2][meta.cursorY][meta.cursorX] = meta.textColor
|
|
meta.buffer[3][meta.cursorY][meta.cursorX] = meta.backColor
|
|
meta.cursorX = meta.cursorX + 1
|
|
end
|
|
end
|
|
if meta.alwaysRender then
|
|
--local limit = math.max(0, meta.width - meta.cursorX + 1)
|
|
bT.setCursorPos(meta.x, meta.y)
|
|
bT.blit(
|
|
table.unpack(meta.buffer[1][meta.cursorY]),
|
|
table.unpack(meta.buffer[2][meta.cursorY]),
|
|
table.unpack(meta.buffer[3][meta.cursorY])
|
|
)
|
|
end
|
|
end
|
|
|
|
output.blit = function(char, text, back)
|
|
assert(type(char) == "string" and type(text) == "string" and type(back) == "string", "all arguments must be strings")
|
|
assert(#char == #text and #text == #back, "arguments must be same length")
|
|
for i = 1, #char do
|
|
if meta.cursorX >= 1 and meta.cursorX <= meta.width and meta.cursorY >= 1 and meta.cursorY <= meta.height then
|
|
meta.buffer[1][meta.cursorY][meta.cursorX] = char:sub(i,i)
|
|
meta.buffer[2][meta.cursorY][meta.cursorX] = text:sub(i,i) == " " and windont.config.defaultTextColor or text:sub(i,i)
|
|
meta.buffer[3][meta.cursorY][meta.cursorX] = back:sub(i,i) == " " and windont.config.defaultBackColor or back:sub(i,i)
|
|
meta.cursorX = meta.cursorX + 1
|
|
end
|
|
end
|
|
if meta.alwaysRender then
|
|
--local limit = math.max(0, meta.width - meta.cursorX + 1)
|
|
bT.setCursorPos(meta.x, meta.y)
|
|
bT.blit(
|
|
table.unpack(meta.buffer[1][meta.cursorY]),
|
|
table.unpack(meta.buffer[2][meta.cursorY]),
|
|
table.unpack(meta.buffer[3][meta.cursorY])
|
|
)
|
|
end
|
|
end
|
|
|
|
output.setCursorPos = function(x, y)
|
|
assert(type(x) == "number", "argument #1 must be number, got " .. type(x))
|
|
assert(type(y) == "number", "argument #2 must be number, got " .. type(y))
|
|
meta.cursorX, meta.cursorY = x, y
|
|
if meta.alwaysRender then
|
|
bT.setCursorPos(meta.x + meta.cursorX - 1, meta.y + meta.cursorY - 1)
|
|
end
|
|
end
|
|
|
|
output.getCursorPos = function()
|
|
return meta.cursorX, meta.cursorY
|
|
end
|
|
|
|
output.setTextColor = function(color)
|
|
if to_blit[color] then
|
|
meta.textColor = to_blit[color]
|
|
else
|
|
error("Invalid color (got " .. color .. ")")
|
|
end
|
|
end
|
|
output.setTextColour = output.setTextColor
|
|
|
|
output.setBackgroundColor = function(color)
|
|
if to_blit[color] then
|
|
meta.backColor = to_blit[color]
|
|
else
|
|
error("Invalid color (got " .. color .. ")")
|
|
end
|
|
end
|
|
output.setBackgroundColour = output.setBackgroundColor
|
|
|
|
output.getTextColor = function()
|
|
return to_colors[meta.textColor]
|
|
end
|
|
output.getTextColour = output.getTextColor
|
|
|
|
output.getBackgroundColor = function()
|
|
return to_colors[meta.backColor]
|
|
end
|
|
output.getBackgroundColour = output.getBackgroundColor
|
|
|
|
output.setVisible = function(visible)
|
|
assert(type(visible) == "number", "bad argument #1 (expected boolean, got " .. type(visible) .. ")")
|
|
meta.visible = visible and true or false
|
|
end
|
|
|
|
output.clear = function()
|
|
meta.buffer = meta.newBuffer(meta.width, meta.height, " ", meta.textColor, meta.backColor)
|
|
end
|
|
|
|
output.clearLine = function()
|
|
meta.buffer[meta.cursorY] = nil
|
|
meta.buffer = meta.newBuffer(meta.width, meta.height, " ", meta.textColor, meta.backColor, meta.buffer)
|
|
if meta.alwaysRender then
|
|
bT.setCursorPos(meta.x, meta.y + meta.cursorY - 1)
|
|
bT.blit(
|
|
(" "):rep(meta.width),
|
|
(meta.textColor):rep(meta.width),
|
|
(meta.backColor):rep(meta.width)
|
|
)
|
|
end
|
|
end
|
|
|
|
output.getLine = function(y)
|
|
assert(type(y) == "number", "bad argument #1 (expected number, got " .. type(y) .. ")")
|
|
assert(meta.buffer[1][y], "Line is out of range.")
|
|
return table.concat(meta.buffer[1][y]), table.concat(meta.buffer[2][y]), table.concat(meta.buffer[3][y])
|
|
end
|
|
|
|
output.scroll = function(amplitude)
|
|
if amplitude > 0 then
|
|
for i = 1, amplitude do
|
|
table.remove(meta.buffer[1], 1)
|
|
table.remove(meta.buffer[2], 1)
|
|
table.remove(meta.buffer[3], 1)
|
|
end
|
|
else
|
|
for i = 1, -amplitude do
|
|
table.insert(meta.buffer[1], 1, false)
|
|
table.insert(meta.buffer[2], 1, false)
|
|
table.insert(meta.buffer[3], 1, false)
|
|
end
|
|
end
|
|
meta.buffer = meta.newBuffer(meta.width, meta.height, " ", meta.textColor, meta.backColor, meta.buffer)
|
|
if meta.alwaysRender then
|
|
output.redraw()
|
|
end
|
|
end
|
|
|
|
output.getSize = function()
|
|
return height, width
|
|
end
|
|
|
|
output.isColor = function()
|
|
return meta.isColor
|
|
end
|
|
output.isColour = output.isColor
|
|
|
|
output.reposition = function(x, y, width, height)
|
|
assert(type(x) == "number", "bad argument #1 (expected number, got " .. type(x) .. ")")
|
|
assert(type(y) == "number", "bad argument #2 (expected number, got " .. type(y) .. ")")
|
|
meta.x = math.floor(x)
|
|
meta.y = math.floor(y)
|
|
if width then
|
|
assert(type(width) == "number", "bad argument #3 (expected number, got " .. type(width) .. ")")
|
|
assert(type(height) == "number", "bad argument #4 (expected number, got " .. type(height) .. ")")
|
|
meta.width = width
|
|
meta.height = height
|
|
meta.buffer = meta.newBuffer(meta.width, meta.height, " ", meta.textColor, meta.backColor, meta.buffer)
|
|
end
|
|
if meta.alwaysRender then
|
|
output.redraw()
|
|
end
|
|
end
|
|
|
|
output.restoreCursor = function()
|
|
bT.setCursorPos(meta.x + meta.cursorX - 1, meta.y + meta.cursorY - 1)
|
|
bT.setCursorBlink(meta.blink)
|
|
end
|
|
|
|
output.getPosition = function()
|
|
return meta.x, meta.y
|
|
end
|
|
|
|
output.setCursorBlink = function(blink)
|
|
meta.blink = blink and true or false
|
|
end
|
|
|
|
output.getCursorBlink = function(blink)
|
|
return meta.blink
|
|
end
|
|
|
|
output.setPaletteColor = bT.setPaletteColor
|
|
output.setPaletteColour = bT.setPaletteColour
|
|
output.getPaletteColor = bT.getPaletteColor
|
|
output.getPaletteColour = bT.getPaletteColour
|
|
|
|
output.redraw = function()
|
|
if #meta.renderBuddies > 0 then
|
|
windont.render(output, table.unpack(meta.renderBuddies))
|
|
else
|
|
windont.render(output)
|
|
end
|
|
end
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
return windont
|