forked from hkc/cc-stuff
232 lines
7.0 KiB
Lua
232 lines
7.0 KiB
Lua
local expect = require("cc.expect").expect
|
|
local function todo() error("todo!") end
|
|
local pretty = require "cc.pretty"
|
|
|
|
local BigTerm = {
|
|
write = function(self, text)
|
|
local w = self.getSize()
|
|
for i = 1, #text do
|
|
if self._pos.x <= w then
|
|
self._blitpixel(
|
|
self._pos.x,
|
|
self._pos.y,
|
|
text:sub(i, i),
|
|
self._colorChar(self._colorForeground),
|
|
self._colorChar(self._colorBackground)
|
|
)
|
|
self._pos.x = self._pos.x + 1
|
|
end
|
|
end
|
|
end,
|
|
blit = function(self, text, foreground, background)
|
|
local x, y = self._pos.x, self._pos.y
|
|
local w = #text
|
|
local LIMIT = 0
|
|
local ox = 1
|
|
while w > 0 and LIMIT < 20 do
|
|
local mon, i, lx, ly = self._getMonitorForScreenPos(x, y)
|
|
if not mon then break end
|
|
local remaining = mon._w - lx
|
|
mon.p.setCursorPos(lx + 1, ly + 1)
|
|
mon.p.blit(
|
|
text:sub(ox, ox + w),
|
|
foreground:sub(ox, ox + w - 1),
|
|
background:sub(ox, ox + w - 1)
|
|
)
|
|
w = w - remaining
|
|
x = x + remaining
|
|
ox = ox + remaining
|
|
end
|
|
end,
|
|
clear = function(self)
|
|
self._forEachMonitor(function(mon)
|
|
mon.p.clear()
|
|
end)
|
|
end,
|
|
clearLine = function(self) todo() end,
|
|
scroll = function(self, n)
|
|
-- TODO: NOPE! store framebuffer and write lines onto other screens
|
|
self._forEachMonitor(function(mon)
|
|
mon.p.scroll(n)
|
|
end)
|
|
end,
|
|
|
|
getCursorPos = function(self) return self._pos.x, self._pos.y end,
|
|
setCursorPos = function(self, x, y)
|
|
self._pos.x = x
|
|
self._pos.y = y
|
|
-- TODO: move cursor to the correct monitor and hide it from others
|
|
end,
|
|
|
|
setCursorBlink = function(self, state) todo() end,
|
|
getCursorBlink = function(self) todo() end,
|
|
|
|
isColor = function(self) return true end,
|
|
getSize = function(self)
|
|
local w, h = 0, 0
|
|
for ix = 1, self._w do
|
|
local mon = self._findMonitor(ix, 1)
|
|
w = w + mon._w
|
|
end
|
|
for iy = 1, self._h do
|
|
local mon = self._findMonitor(1, iy)
|
|
h = h + mon._h
|
|
end
|
|
return w, h
|
|
end,
|
|
|
|
setTextColor = function(self, fg)
|
|
self._forEachMonitor(function(mon)
|
|
mon.p.setTextColor(fg)
|
|
end)
|
|
self._colorForeground = fg
|
|
end,
|
|
getTextColor = function(self) todo() end,
|
|
|
|
setBackgroundColor = function(self, bg)
|
|
self._forEachMonitor(function(mon)
|
|
mon.p.setBackgroundColor(bg)
|
|
end)
|
|
self._colorBackground = bg
|
|
end,
|
|
getBackgroundColor = function(self) todo() end,
|
|
|
|
setTextScale = function(self, scale)
|
|
self._scale = scale
|
|
self._reset()
|
|
end,
|
|
getTextScale = function(self)
|
|
return self._scale
|
|
end,
|
|
|
|
setPaletteColor = function(self, index, color, g, b)
|
|
expect(1, index, "number")
|
|
expect(2, color, "number")
|
|
expect(3, g, "number", "nil")
|
|
expect(4, b, "number", "nil")
|
|
if index < 0 or index > 32768 or math.log(index, 2) % 1 ~= 0 then
|
|
error("index out of range")
|
|
end
|
|
|
|
local r = color
|
|
if g == nil or b == nil then
|
|
if color < 0 or color > 0xFFFFFF then
|
|
error("color out of range")
|
|
end
|
|
r = bit.band(0xFF, bit.brshift(color, 16)) / 255
|
|
g = bit.band(0xFF, bit.brshift(color, 8)) / 255
|
|
b = bit.band(0xFF, bit.brshift(color, 0)) / 255
|
|
else
|
|
if r < 0 or r > 1.0 then error("red channel out of range") end
|
|
if g < 0 or g > 1.0 then error("green channel out of range") end
|
|
if b < 0 or b > 1.0 then error("blue channel out of range") end
|
|
end
|
|
|
|
self._palette[index] = bit.bor(
|
|
bit.blshift(math.floor(r * 255), 16),
|
|
bit.blshift(math.floor(g * 255), 8),
|
|
bit.blshift(math.floor(b * 255), 0)
|
|
)
|
|
self._forEachMonitor(function(mon)
|
|
mon.p.setPaletteColor(index, r, g, b)
|
|
end)
|
|
end,
|
|
getPaletteColor = function(self, index) todo() end,
|
|
|
|
-- internals
|
|
|
|
_colorChar = function(self, v)
|
|
return string.format("%x", math.floor(math.log(v, 2)))
|
|
end,
|
|
|
|
_reset = function(self)
|
|
self._w = 1
|
|
self._h = 1
|
|
self._forEachMonitor(function(mon, i)
|
|
mon.p.setTextScale(self._scale)
|
|
local w, h = mon.p.getSize()
|
|
self._monitors[i]._w = w
|
|
self._monitors[i]._h = h
|
|
if mon.x > self._w then self._w = mon.x end
|
|
if mon.y > self._h then self._h = mon.y end
|
|
for id, color in pairs(self._palette) do
|
|
mon.p.setPaletteColor(id, color)
|
|
end
|
|
end)
|
|
end,
|
|
|
|
_blitpixel = function(self, x, y, c, bg, fg)
|
|
bg = bg or "0"
|
|
fg = fg or "f"
|
|
local mon = self._getMonitorForScreenPos(x, y)
|
|
mon.p.setCursorPos(((x - 1) % mon._w) + 1, ((y - 1) % mon._h) + 1)
|
|
mon.p.blit(c, bg, fg)
|
|
end,
|
|
|
|
_findMonitor = function(self, x, y)
|
|
for i = 1, #self._monitors do
|
|
local mon = self._monitors[i]
|
|
if mon.x == x and mon.y == y then
|
|
return mon, i
|
|
end
|
|
end
|
|
end,
|
|
|
|
_getMonitorForScreenPos = function(self, x, y)
|
|
local oy = 1
|
|
for iy = 1, self._h do
|
|
local ox = 1
|
|
for ix = 1, self._w do
|
|
local mon, i = self._findMonitor(ix, iy)
|
|
if x >= ox and x < (ox + mon._w) and y >= oy and y < (oy + mon._h) then
|
|
return mon, i, x - ox, y - oy
|
|
end
|
|
ox = ox + mon._w
|
|
end
|
|
local mon, i = self._findMonitor(1, iy)
|
|
oy = oy + mon._h
|
|
end
|
|
end,
|
|
|
|
_forEachMonitor = function(self, fun)
|
|
for i = 1, #self._monitors do
|
|
fun(self._monitors[i], i)
|
|
end
|
|
end,
|
|
|
|
}
|
|
|
|
local lib = {}
|
|
function lib.fromFile(conf)
|
|
local fp = assert(io.open(conf, "r"))
|
|
local conf = textutils.unserializeJSON(fp:read("a"))
|
|
fp:close()
|
|
local monitors = {}
|
|
for addr, pos in pairs(conf.monitors) do
|
|
local p = assert(peripheral.wrap(addr))
|
|
table.insert(monitors, { p = p, x = pos.x, y = pos.y })
|
|
end
|
|
return lib.new(monitors, { palette = conf.palette, scale = conf.scale })
|
|
end
|
|
function lib.new(monitors, args)
|
|
args = args or {}
|
|
local mon = setmetatable({
|
|
_monitors = monitors,
|
|
_pos = { x = 1, y = 1 },
|
|
_blink = false,
|
|
_colorForeground = colors.white,
|
|
_colorBackground = colors.black,
|
|
_scale = args.scale or 1.0,
|
|
_palette = args.palette or {},
|
|
}, { __index = BigTerm })
|
|
for name, method in pairs(BigTerm) do
|
|
if type(method) == "function" then
|
|
mon[name] = function(...) return method(mon, ...) end
|
|
end
|
|
end
|
|
mon._reset()
|
|
return mon
|
|
end
|
|
|
|
return lib
|