CC-Tweaked/src/main/resources/data/computercraft/lua/rom/apis/window.lua

490 lines
16 KiB
Lua

local expect = dofile("rom/modules/main/cc/expect.lua").expect
local tHex = {
[ colors.white ] = "0",
[ colors.orange ] = "1",
[ colors.magenta ] = "2",
[ colors.lightBlue ] = "3",
[ colors.yellow ] = "4",
[ colors.lime ] = "5",
[ colors.pink ] = "6",
[ colors.gray ] = "7",
[ colors.lightGray ] = "8",
[ colors.cyan ] = "9",
[ colors.purple ] = "a",
[ colors.blue ] = "b",
[ colors.brown ] = "c",
[ colors.green ] = "d",
[ colors.red ] = "e",
[ colors.black ] = "f",
}
local type = type
local string_rep = string.rep
local string_sub = string.sub
function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
expect(1, parent, "table")
expect(2, nX, "number")
expect(3, nY, "number")
expect(4, nWidth, "number")
expect(5, nHeight, "number")
expect(6, bStartVisible, "boolean", "nil")
if parent == term then
error( "term is not a recommended window parent, try term.current() instead", 2 )
end
local sEmptySpaceLine
local tEmptyColorLines = {}
local function createEmptyLines( nWidth )
sEmptySpaceLine = string_rep( " ", nWidth )
for n=0,15 do
local nColor = 2^n
local sHex = tHex[nColor]
tEmptyColorLines[nColor] = string_rep( sHex, nWidth )
end
end
createEmptyLines( nWidth )
-- Setup
local bVisible = (bStartVisible ~= false)
local nCursorX = 1
local nCursorY = 1
local bCursorBlink = false
local nTextColor = colors.white
local nBackgroundColor = colors.black
local tLines = {}
local tPalette = {}
do
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[ nTextColor ]
local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]
for y=1,nHeight do
tLines[y] = {
text = sEmptyText,
textColor = sEmptyTextColor,
backgroundColor = sEmptyBackgroundColor,
}
end
for i=0,15 do
local c = 2 ^ i
tPalette[c] = { parent.getPaletteColour( c ) }
end
end
-- Helper functions
local function updateCursorPos()
if nCursorX >= 1 and nCursorY >= 1 and
nCursorX <= nWidth and nCursorY <= nHeight then
parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 )
else
parent.setCursorPos( 0, 0 )
end
end
local function updateCursorBlink()
parent.setCursorBlink( bCursorBlink )
end
local function updateCursorColor()
parent.setTextColor( nTextColor )
end
local function redrawLine( n )
local tLine = tLines[ n ]
parent.setCursorPos( nX, nY + n - 1 )
parent.blit( tLine.text, tLine.textColor, tLine.backgroundColor )
end
local function redraw()
for n=1,nHeight do
redrawLine( n )
end
end
local function updatePalette()
for k,v in pairs( tPalette ) do
parent.setPaletteColour( k, v[1], v[2], v[3] )
end
end
local function internalBlit( sText, sTextColor, sBackgroundColor )
local nStart = nCursorX
local nEnd = nStart + #sText - 1
if nCursorY >= 1 and nCursorY <= nHeight then
if nStart <= nWidth and nEnd >= 1 then
-- Modify line
local tLine = tLines[ nCursorY ]
if nStart == 1 and nEnd == nWidth then
tLine.text = sText
tLine.textColor = sTextColor
tLine.backgroundColor = sBackgroundColor
else
local sClippedText, sClippedTextColor, sClippedBackgroundColor
if nStart < 1 then
local nClipStart = 1 - nStart + 1
local nClipEnd = nWidth - nStart + 1
sClippedText = string_sub( sText, nClipStart, nClipEnd )
sClippedTextColor = string_sub( sTextColor, nClipStart, nClipEnd )
sClippedBackgroundColor = string_sub( sBackgroundColor, nClipStart, nClipEnd )
elseif nEnd > nWidth then
local nClipEnd = nWidth - nStart + 1
sClippedText = string_sub( sText, 1, nClipEnd )
sClippedTextColor = string_sub( sTextColor, 1, nClipEnd )
sClippedBackgroundColor = string_sub( sBackgroundColor, 1, nClipEnd )
else
sClippedText = sText
sClippedTextColor = sTextColor
sClippedBackgroundColor = sBackgroundColor
end
local sOldText = tLine.text
local sOldTextColor = tLine.textColor
local sOldBackgroundColor = tLine.backgroundColor
local sNewText, sNewTextColor, sNewBackgroundColor
if nStart > 1 then
local nOldEnd = nStart - 1
sNewText = string_sub( sOldText, 1, nOldEnd ) .. sClippedText
sNewTextColor = string_sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor
sNewBackgroundColor = string_sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor
else
sNewText = sClippedText
sNewTextColor = sClippedTextColor
sNewBackgroundColor = sClippedBackgroundColor
end
if nEnd < nWidth then
local nOldStart = nEnd + 1
sNewText = sNewText .. string_sub( sOldText, nOldStart, nWidth )
sNewTextColor = sNewTextColor .. string_sub( sOldTextColor, nOldStart, nWidth )
sNewBackgroundColor = sNewBackgroundColor .. string_sub( sOldBackgroundColor, nOldStart, nWidth )
end
tLine.text = sNewText
tLine.textColor = sNewTextColor
tLine.backgroundColor = sNewBackgroundColor
end
-- Redraw line
if bVisible then
redrawLine( nCursorY )
end
end
end
-- Move and redraw cursor
nCursorX = nEnd + 1
if bVisible then
updateCursorColor()
updateCursorPos()
end
end
-- Terminal implementation
local window = {}
function window.write( sText )
sText = tostring( sText )
internalBlit( sText, string_rep( tHex[ nTextColor ], #sText ), string_rep( tHex[ nBackgroundColor ], #sText ) )
end
function window.blit( sText, sTextColor, sBackgroundColor )
if type(sText) ~= "string" then expect(1, sText, "string") end
if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end
if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end
if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then
error( "Arguments must be the same length", 2 )
end
internalBlit( sText, sTextColor, sBackgroundColor )
end
function window.clear()
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[ nTextColor ]
local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]
for y=1,nHeight do
tLines[y] = {
text = sEmptyText,
textColor = sEmptyTextColor,
backgroundColor = sEmptyBackgroundColor,
}
end
if bVisible then
redraw()
updateCursorColor()
updateCursorPos()
end
end
function window.clearLine()
if nCursorY >= 1 and nCursorY <= nHeight then
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[ nTextColor ]
local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]
tLines[ nCursorY ] = {
text = sEmptyText,
textColor = sEmptyTextColor,
backgroundColor = sEmptyBackgroundColor,
}
if bVisible then
redrawLine( nCursorY )
updateCursorColor()
updateCursorPos()
end
end
end
function window.getCursorPos()
return nCursorX, nCursorY
end
function window.setCursorPos( x, y )
if type(x) ~= "number" then expect(1, x, "number") end
if type(y) ~= "number" then expect(2, y, "number") end
nCursorX = math.floor( x )
nCursorY = math.floor( y )
if bVisible then
updateCursorPos()
end
end
function window.setCursorBlink( blink )
if type(blink) ~= "boolean" then expect(1, blink, "boolean") end
bCursorBlink = blink
if bVisible then
updateCursorBlink()
end
end
function window.getCursorBlink()
return bCursorBlink
end
local function isColor()
return parent.isColor()
end
function window.isColor()
return isColor()
end
function window.isColour()
return isColor()
end
local function setTextColor( color )
if type(color) ~= "number" then expect(1, color, "number") end
if tHex[color] == nil then
error( "Invalid color (got " .. color .. ")" , 2 )
end
nTextColor = color
if bVisible then
updateCursorColor()
end
end
window.setTextColor = setTextColor
window.setTextColour = setTextColor
function window.setPaletteColour( colour, r, g, b )
if type(colour) ~= "number" then expect(1, colour, "number") end
if tHex[colour] == nil then
error( "Invalid color (got " .. colour .. ")" , 2 )
end
local tCol
if type(r) == "number" and g == nil and b == nil then
tCol = { colours.unpackRGB( r ) }
tPalette[ colour ] = tCol
else
if type(r) ~= "number" then expect(2, r, "number") end
if type(g) ~= "number" then expect(3, g, "number") end
if type(b) ~= "number" then expect(4, b, "number") end
tCol = tPalette[ colour ]
tCol[1] = r
tCol[2] = g
tCol[3] = b
end
if bVisible then
return parent.setPaletteColour( colour, tCol[1], tCol[2], tCol[3] )
end
end
window.setPaletteColor = window.setPaletteColour
function window.getPaletteColour( colour )
if type(colour) ~= "number" then expect(1, colour, "number") end
if tHex[colour] == nil then
error( "Invalid color (got " .. colour .. ")" , 2 )
end
local tCol = tPalette[ colour ]
return tCol[1], tCol[2], tCol[3]
end
window.getPaletteColor = window.getPaletteColour
local function setBackgroundColor( color )
if type(color) ~= "number" then expect(1, color, "number") end
if tHex[color] == nil then
error( "Invalid color (got " .. color .. ")", 2 )
end
nBackgroundColor = color
end
window.setBackgroundColor = setBackgroundColor
window.setBackgroundColour = setBackgroundColor
function window.getSize()
return nWidth, nHeight
end
function window.scroll( n )
if type(n) ~= "number" then expect(1, n, "number") end
if n ~= 0 then
local tNewLines = {}
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[ nTextColor ]
local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]
for newY=1,nHeight do
local y = newY + n
if y >= 1 and y <= nHeight then
tNewLines[newY] = tLines[y]
else
tNewLines[newY] = {
text = sEmptyText,
textColor = sEmptyTextColor,
backgroundColor = sEmptyBackgroundColor,
}
end
end
tLines = tNewLines
if bVisible then
redraw()
updateCursorColor()
updateCursorPos()
end
end
end
function window.getTextColor()
return nTextColor
end
function window.getTextColour()
return nTextColor
end
function window.getBackgroundColor()
return nBackgroundColor
end
function window.getBackgroundColour()
return nBackgroundColor
end
function window.getLine(y)
if type(y) ~= "number" then expect(1, y, "number") end
if y < 1 or y > nHeight then
error("Line is out of range.", 2)
end
return tLines[y].text, tLines[y].textColor, tLines[y].backgroundColor
end
-- Other functions
function window.setVisible( bVis )
if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end
if bVisible ~= bVis then
bVisible = bVis
if bVisible then
window.redraw()
end
end
end
function window.redraw()
if bVisible then
redraw()
updatePalette()
updateCursorBlink()
updateCursorColor()
updateCursorPos()
end
end
function window.restoreCursor()
if bVisible then
updateCursorBlink()
updateCursorColor()
updateCursorPos()
end
end
function window.getPosition()
return nX, nY
end
function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )
if type(nNewX) ~= "number" then expect(1, nNewX, "number") end
if type(nNewY) ~= "number" then expect(2, nNewY, "number") end
if nNewWidth ~= nil or nNewHeight ~= nil then
expect(3, nNewWidth, "number")
expect(4, nNewHeight, "number")
end
nX = nNewX
nY = nNewY
if nNewWidth and nNewHeight then
local tNewLines = {}
createEmptyLines( nNewWidth )
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[ nTextColor ]
local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ]
for y=1,nNewHeight do
if y > nHeight then
tNewLines[y] = {
text = sEmptyText,
textColor = sEmptyTextColor,
backgroundColor = sEmptyBackgroundColor
}
else
local tOldLine = tLines[y]
if nNewWidth == nWidth then
tNewLines[y] = tOldLine
elseif nNewWidth < nWidth then
tNewLines[y] = {
text = string_sub( tOldLine.text, 1, nNewWidth ),
textColor = string_sub( tOldLine.textColor, 1, nNewWidth ),
backgroundColor = string_sub( tOldLine.backgroundColor, 1, nNewWidth ),
}
else
tNewLines[y] = {
text = tOldLine.text .. string_sub( sEmptyText, nWidth + 1, nNewWidth ),
textColor = tOldLine.textColor .. string_sub( sEmptyTextColor, nWidth + 1, nNewWidth ),
backgroundColor = tOldLine.backgroundColor .. string_sub( sEmptyBackgroundColor, nWidth + 1, nNewWidth ),
}
end
end
end
nWidth = nNewWidth
nHeight = nNewHeight
tLines = tNewLines
end
if bVisible then
window.redraw()
end
end
if bVisible then
window.redraw()
end
return window
end