mirror of https://github.com/kepler155c/opus
175 lines
3.7 KiB
Lua
175 lines
3.7 KiB
Lua
local colors = _G.colors
|
|
local _rep = string.rep
|
|
local _sub = string.sub
|
|
|
|
local Blit = { }
|
|
|
|
Blit.colorPalette = { }
|
|
Blit.grayscalePalette = { }
|
|
|
|
for n = 1, 16 do
|
|
Blit.colorPalette[2 ^ (n - 1)] = _sub("0123456789abcdef", n, n)
|
|
Blit.grayscalePalette[2 ^ (n - 1)] = _sub("088888878877787f", n, n)
|
|
end
|
|
|
|
-- default palette
|
|
Blit.palette = Blit.colorPalette
|
|
|
|
function Blit:init(t, args)
|
|
if args then
|
|
for k,v in pairs(args) do
|
|
self[k] = v
|
|
end
|
|
end
|
|
|
|
if type(t) == 'string' then
|
|
-- create a blit from a string
|
|
self.text, self.bg, self.fg = Blit.toblit(t, args or { })
|
|
|
|
elseif type(t) == 'number' then
|
|
-- create a fixed width blit
|
|
self.width = t
|
|
self.text = _rep(' ', self.width)
|
|
self.bg = _rep(self.palette[args.bg], self.width)
|
|
self.fg = _rep(self.palette[args.fg], self.width)
|
|
|
|
else
|
|
self.text = t.text
|
|
self.bg = t.bg
|
|
self.fg = t.fg
|
|
end
|
|
end
|
|
|
|
function Blit:write(x, text, bg, fg)
|
|
self:insert(x, text,
|
|
bg and _rep(self.palette[bg], #text),
|
|
fg and _rep(self.palette[fg], #text))
|
|
end
|
|
|
|
function Blit:insert(x, text, bg, fg)
|
|
if x <= self.width then
|
|
local width = #text
|
|
local tx, tex
|
|
|
|
if x < 1 then
|
|
tx = 2 - x
|
|
width = width + x - 1
|
|
x = 1
|
|
end
|
|
|
|
if x + width - 1 > self.width then
|
|
tex = self.width - x + (tx or 1)
|
|
width = tex - (tx or 1) + 1
|
|
end
|
|
|
|
if width > 0 then
|
|
local function replace(sstr, rstr)
|
|
if tx or tex then
|
|
rstr = _sub(rstr, tx or 1, tex)
|
|
end
|
|
if x == 1 and width == self.width then
|
|
return rstr
|
|
elseif x == 1 then
|
|
return rstr .. _sub(sstr, x + width)
|
|
elseif x + width > self.width then
|
|
return _sub(sstr, 1, x - 1) .. rstr
|
|
end
|
|
return _sub(sstr, 1, x - 1) .. rstr .. _sub(sstr, x + width)
|
|
end
|
|
|
|
self.text = replace(self.text, text)
|
|
if fg then
|
|
self.fg = replace(self.fg, fg)
|
|
end
|
|
if bg then
|
|
self.bg = replace(self.bg, bg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Blit:sub(s, e)
|
|
return Blit({
|
|
text = self.text:sub(s, e),
|
|
bg = self.bg:sub(s, e),
|
|
fg = self.fg:sub(s, e),
|
|
})
|
|
end
|
|
|
|
function Blit:wrap(max)
|
|
local lines = { }
|
|
local data = self
|
|
|
|
repeat
|
|
if #data.text <= max then
|
|
table.insert(lines, data)
|
|
break
|
|
elseif data.text:sub(max+1, max+1) == ' ' then
|
|
table.insert(lines, data:sub(1, max))
|
|
data = data:sub(max + 2)
|
|
else
|
|
local x = data.text:sub(1, max)
|
|
local s = x:match('(.*) ') or x
|
|
table.insert(lines, data:sub(1, #s))
|
|
data = data:sub(#s + 1)
|
|
end
|
|
local t = data.text:match('^%s*(.*)')
|
|
local spaces = #data.text - #t
|
|
if spaces > 0 then
|
|
data = data:sub(spaces + 1)
|
|
end
|
|
until not data.text or #data.text == 0
|
|
|
|
return lines
|
|
end
|
|
|
|
-- convert a string of text to blit format doing color conversion
|
|
-- and processing ansi color sequences
|
|
function Blit.toblit(str, cs)
|
|
local text, fg, bg = '', '', ''
|
|
|
|
if not cs.cbg then
|
|
-- reset colors
|
|
cs.rbg = cs.bg or colors.black
|
|
cs.rfg = cs.fg or colors.white
|
|
-- current colors
|
|
cs.cbg = cs.rbg
|
|
cs.cfg = cs.rfg
|
|
|
|
cs.palette = cs.palette or Blit.palette
|
|
end
|
|
|
|
str = str:gsub('(.-)\027%[([%d;]+)m',
|
|
function(k, seq)
|
|
text = text .. k
|
|
bg = bg .. string.rep(cs.palette[cs.cbg], #k)
|
|
fg = fg .. string.rep(cs.palette[cs.cfg], #k)
|
|
for color in string.gmatch(seq, "%d+") do
|
|
color = tonumber(color)
|
|
if color == 0 then
|
|
-- reset to default
|
|
cs.cfg = cs.rfg
|
|
cs.cbg = cs.rbg
|
|
elseif color > 20 then
|
|
cs.cbg = 2 ^ (color - 21)
|
|
else
|
|
cs.cfg = 2 ^ (color - 1)
|
|
end
|
|
end
|
|
return k
|
|
end)
|
|
|
|
local k = str:sub(#text + 1)
|
|
return text .. k,
|
|
bg .. string.rep(cs.palette[cs.cbg], #k),
|
|
fg .. string.rep(cs.palette[cs.cfg], #k)
|
|
end
|
|
|
|
return setmetatable(Blit, {
|
|
__call = function(_, ...)
|
|
local obj = setmetatable({ }, { __index = Blit })
|
|
obj:init(...)
|
|
return obj
|
|
end
|
|
})
|