mirror of
https://github.com/kepler155c/opus
synced 2024-12-26 00:20:26 +00:00
generalized canvas
This commit is contained in:
parent
8e381d3ebf
commit
19ed191086
@ -2,6 +2,8 @@ local Util = require('util')
|
|||||||
|
|
||||||
local Terminal = { }
|
local Terminal = { }
|
||||||
|
|
||||||
|
local _sgsub = string.gsub
|
||||||
|
|
||||||
function Terminal.scrollable(ct, size)
|
function Terminal.scrollable(ct, size)
|
||||||
|
|
||||||
local size = size or 25
|
local size = size or 25
|
||||||
@ -108,7 +110,10 @@ function Terminal.toGrayscale(ct)
|
|||||||
|
|
||||||
local function translate(s)
|
local function translate(s)
|
||||||
if s then
|
if s then
|
||||||
s = s:gsub("%d+", bcolors)
|
for k,v in pairs(bcolors) do
|
||||||
|
s = _sgsub(s, k, v)
|
||||||
|
end
|
||||||
|
-- s = _sgsub(s, "%d+", bcolors) -- not working in cc 1.75 ???
|
||||||
end
|
end
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
361
sys/apis/ui.lua
361
sys/apis/ui.lua
@ -1,39 +1,11 @@
|
|||||||
local Ansi = require('ansi')
|
local Canvas = require('ui.canvas')
|
||||||
local class = require('class')
|
local class = require('class')
|
||||||
local Event = require('event')
|
local Event = require('event')
|
||||||
local Region = require('ui.region')
|
|
||||||
local Tween = require('ui.tween')
|
local Tween = require('ui.tween')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local mapColorToGray = {
|
local _srep = string.rep
|
||||||
[ colors.white ] = colors.white,
|
local _ssub = string.sub
|
||||||
[ colors.orange ] = colors.lightGray,
|
|
||||||
[ colors.magenta ] = colors.lightGray,
|
|
||||||
[ colors.lightBlue ] = colors.lightGray,
|
|
||||||
[ colors.yellow ] = colors.lightGray,
|
|
||||||
[ colors.lime ] = colors.lightGray,
|
|
||||||
[ colors.pink ] = colors.lightGray,
|
|
||||||
[ colors.gray ] = colors.gray,
|
|
||||||
[ colors.lightGray ] = colors.lightGray,
|
|
||||||
[ colors.cyan ] = colors.lightGray,
|
|
||||||
[ colors.purple ] = colors.gray,
|
|
||||||
[ colors.blue ] = colors.gray,
|
|
||||||
[ colors.brown ] = colors.gray,
|
|
||||||
[ colors.green ] = colors.lightGray,
|
|
||||||
[ colors.red ] = colors.gray,
|
|
||||||
[ colors.black ] = colors.black,
|
|
||||||
}
|
|
||||||
|
|
||||||
local mapColorToPaint = { }
|
|
||||||
for n = 1, 16 do
|
|
||||||
mapColorToPaint[2 ^ (n - 1)] = string.sub("0123456789abcdef", n, n)
|
|
||||||
end
|
|
||||||
|
|
||||||
local mapGrayToPaint = { }
|
|
||||||
for n = 0, 15 do
|
|
||||||
local gs = mapColorToGray[2 ^ n]
|
|
||||||
mapGrayToPaint[2 ^ n] = mapColorToPaint[gs]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function safeValue(v)
|
local function safeValue(v)
|
||||||
local t = type(v)
|
local t = type(v)
|
||||||
@ -473,7 +445,7 @@ end
|
|||||||
function Manager:getDefaults(element, args)
|
function Manager:getDefaults(element, args)
|
||||||
local defaults = Util.deepCopy(element.defaults)
|
local defaults = Util.deepCopy(element.defaults)
|
||||||
if args then
|
if args then
|
||||||
Manager.setProperties(defaults, args)
|
Manager:setProperties(defaults, args)
|
||||||
end
|
end
|
||||||
return defaults
|
return defaults
|
||||||
end
|
end
|
||||||
@ -487,8 +459,7 @@ function Manager:exitPullEvents()
|
|||||||
Event.exitPullEvents()
|
Event.exitPullEvents()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- inconsistent
|
function Manager:setProperties(obj, args)
|
||||||
function Manager.setProperties(obj, args)
|
|
||||||
if args then
|
if args then
|
||||||
for k,v in pairs(args) do
|
for k,v in pairs(args) do
|
||||||
if k == 'accelerators' then
|
if k == 'accelerators' then
|
||||||
@ -521,7 +492,7 @@ UI.Window.defaults = {
|
|||||||
}
|
}
|
||||||
function UI.Window:init(args)
|
function UI.Window:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Window, args)
|
local defaults = UI:getDefaults(UI.Window, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
|
|
||||||
if self.parent then
|
if self.parent then
|
||||||
self:setParent()
|
self:setParent()
|
||||||
@ -623,7 +594,7 @@ function UI.Window:resize()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UI.Window:add(children)
|
function UI.Window:add(children)
|
||||||
UI.setProperties(self, children)
|
UI:setProperties(self, children)
|
||||||
self:initChildren()
|
self:initChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -686,15 +657,14 @@ function UI.Window:clear(bg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UI.Window:clearLine(y, bg)
|
function UI.Window:clearLine(y, bg)
|
||||||
local filler = string.rep(' ', self.width)
|
self:write(1, y, _srep(' ', self.width), bg)
|
||||||
self:write(1, y, filler, bg)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function UI.Window:clearArea(x, y, width, height, bg)
|
function UI.Window:clearArea(x, y, width, height, bg)
|
||||||
if width > 0 then
|
if width > 0 then
|
||||||
local filler = string.rep(' ', width)
|
local filler = _srep(' ', width)
|
||||||
for i = 0, height-1 do
|
for i = 0, height - 1 do
|
||||||
self:write(x, y+i, filler, bg)
|
self:write(x, y + i, filler, bg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -719,9 +689,9 @@ function UI.Window:centeredWrite(y, text, bg, fg)
|
|||||||
self:write(1, y, text, bg)
|
self:write(1, y, text, bg)
|
||||||
else
|
else
|
||||||
local space = math.floor((self.width-#text) / 2)
|
local space = math.floor((self.width-#text) / 2)
|
||||||
local filler = string.rep(' ', space + 1)
|
local filler = _srep(' ', space + 1)
|
||||||
local str = filler:sub(1, space) .. text
|
local str = _ssub(filler, 1, space) .. text
|
||||||
str = str .. filler:sub(self.width - #str + 1)
|
str = str .. _ssub(filler, self.width - #str + 1)
|
||||||
self:write(1, y, str, bg, fg)
|
self:write(1, y, str, bg, fg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -732,15 +702,15 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
local function nextWord(line, cx)
|
local function nextWord(line, cx)
|
||||||
local result = { line:find("(%w+)", cx) }
|
local result = { line:find("(%w+)", cx) }
|
||||||
if #result > 1 and result[2] > cx then
|
if #result > 1 and result[2] > cx then
|
||||||
return line:sub(cx, result[2] + 1)
|
return _ssub(line, cx, result[2] + 1)
|
||||||
elseif #result > 0 and result[1] == cx then
|
elseif #result > 0 and result[1] == cx then
|
||||||
result = { line:find("(%w+)", result[2] + 1) }
|
result = { line:find("(%w+)", result[2] + 1) }
|
||||||
if #result > 0 then
|
if #result > 0 then
|
||||||
return line:sub(cx, result[1] + 1)
|
return _ssub(line, cx, result[1] + 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if cx <= #line then
|
if cx <= #line then
|
||||||
return line:sub(cx, #line)
|
return _ssub(line, cx, #line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -753,9 +723,9 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
if pos < s then
|
if pos < s then
|
||||||
table.insert(t, f:sub(pos, s - 1))
|
table.insert(t, _ssub(f, pos, s - 1))
|
||||||
end
|
end
|
||||||
local seq = f:sub(s)
|
local seq = _ssub(f, s)
|
||||||
seq = seq:match("\027%[([%d;]+)m")
|
seq = seq:match("\027%[([%d;]+)m")
|
||||||
local e = { }
|
local e = { }
|
||||||
for color in string.gmatch(seq, "%d+") do
|
for color in string.gmatch(seq, "%d+") do
|
||||||
@ -773,7 +743,7 @@ function UI.Window:print(text, bg, fg, indent)
|
|||||||
pos = s + #seq + 3
|
pos = s + #seq + 3
|
||||||
end
|
end
|
||||||
if pos < #f then
|
if pos < #f then
|
||||||
table.insert(t, f:sub(pos))
|
table.insert(t, _ssub(f, pos))
|
||||||
end
|
end
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
@ -907,231 +877,6 @@ function UI.Window:eventHandler(event)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Blit data manipulation --]]--
|
|
||||||
local Canvas = class()
|
|
||||||
function Canvas:init(args)
|
|
||||||
self.x = 1
|
|
||||||
self.y = 1
|
|
||||||
|
|
||||||
Util.merge(self, args)
|
|
||||||
|
|
||||||
self.height = self.ey - self.y + 1
|
|
||||||
self.width = self.ex - self.x + 1
|
|
||||||
|
|
||||||
self.lines = { }
|
|
||||||
for i = 1, self.height do
|
|
||||||
self.lines[i] = { }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:resize(w, h)
|
|
||||||
for i = self.height, h do
|
|
||||||
self.lines[i] = { }
|
|
||||||
end
|
|
||||||
|
|
||||||
while #self.lines > h do
|
|
||||||
table.remove(self.lines, #self.lines)
|
|
||||||
end
|
|
||||||
|
|
||||||
if w ~= self.width then
|
|
||||||
for i = 1, self.height do
|
|
||||||
self.lines[i] = { }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self.ex = self.x + w - 1
|
|
||||||
self.ey = self.y + h - 1
|
|
||||||
|
|
||||||
self.width = w
|
|
||||||
self.height = h
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:colorToPaintColor(c)
|
|
||||||
if self.isColor then
|
|
||||||
return mapColorToPaint[c]
|
|
||||||
end
|
|
||||||
return mapGrayToPaint[c]
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:copy()
|
|
||||||
local b = Canvas({ x = self.x, y = self.y, ex = self.ex, ey = self.ey })
|
|
||||||
for i = 1, self.ey - self.y + 1 do
|
|
||||||
b.lines[i].text = self.lines[i].text
|
|
||||||
b.lines[i].fg = self.lines[i].fg
|
|
||||||
b.lines[i].bg = self.lines[i].bg
|
|
||||||
end
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:addLayer(layer, bg, fg)
|
|
||||||
local canvas = Canvas({
|
|
||||||
x = layer.x,
|
|
||||||
y = layer.y,
|
|
||||||
ex = layer.x + layer.width - 1,
|
|
||||||
ey = layer.y + layer.height - 1,
|
|
||||||
isColor = self.isColor,
|
|
||||||
})
|
|
||||||
canvas:clear(bg, fg)
|
|
||||||
|
|
||||||
canvas.parent = self
|
|
||||||
if not self.layers then
|
|
||||||
self.layers = { }
|
|
||||||
end
|
|
||||||
table.insert(self.layers, canvas)
|
|
||||||
return canvas
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:removeLayer()
|
|
||||||
for k, layer in pairs(self.parent.layers) do
|
|
||||||
if layer == self then
|
|
||||||
self:setVisible(false)
|
|
||||||
table.remove(self.parent.layers, k)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:setVisible(visible)
|
|
||||||
self.visible = visible
|
|
||||||
if not visible then
|
|
||||||
self.parent:dirty()
|
|
||||||
-- set parent's lines to dirty for each line in self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:write(x, y, text, bg, tc)
|
|
||||||
|
|
||||||
if y > 0 and y <= self.height and x <= self.width then
|
|
||||||
|
|
||||||
local width = #text
|
|
||||||
|
|
||||||
if x < 1 then
|
|
||||||
text = text:sub(2 - x)
|
|
||||||
width = width + x - 1
|
|
||||||
x = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if x + width - 1 > self.width then
|
|
||||||
text = text:sub(1, self.width - x + 1)
|
|
||||||
width = #text
|
|
||||||
end
|
|
||||||
|
|
||||||
if width > 0 then
|
|
||||||
|
|
||||||
local function replace(sstr, pos, rstr, width)
|
|
||||||
return sstr:sub(1, pos-1) .. rstr .. sstr:sub(pos+width)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fill(sstr, pos, rstr, width)
|
|
||||||
return sstr:sub(1, pos-1) .. string.rep(rstr, width) .. sstr:sub(pos+width)
|
|
||||||
end
|
|
||||||
|
|
||||||
local line = self.lines[y]
|
|
||||||
line.dirty = true
|
|
||||||
line.text = replace(line.text, x, text, width)
|
|
||||||
if bg then
|
|
||||||
line.bg = fill(line.bg, x, self:colorToPaintColor(bg), width)
|
|
||||||
end
|
|
||||||
if tc then
|
|
||||||
line.fg = fill(line.fg, x, self:colorToPaintColor(tc), width)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:writeLine(y, text, fg, bg)
|
|
||||||
self.lines[y].dirty = true
|
|
||||||
self.lines[y].text = text
|
|
||||||
self.lines[y].fg = fg
|
|
||||||
self.lines[y].bg = bg
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:reset()
|
|
||||||
self.region = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:clear(bg, fg)
|
|
||||||
local width = self.ex - self.x + 1
|
|
||||||
local text = string.rep(' ', width)
|
|
||||||
fg = string.rep(self:colorToPaintColor(fg), width)
|
|
||||||
bg = string.rep(self:colorToPaintColor(bg), width)
|
|
||||||
for i = 1, self.ey - self.y + 1 do
|
|
||||||
self:writeLine(i, text, fg, bg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:punch(rect)
|
|
||||||
if not self.regions then
|
|
||||||
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
|
||||||
end
|
|
||||||
self.regions:subRect(rect.x, rect.y, rect.ex, rect.ey)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:blitClipped(device)
|
|
||||||
for _,region in ipairs(self.regions.region) do
|
|
||||||
self:blit(device,
|
|
||||||
{ x = region[1] - self.x + 1,
|
|
||||||
y = region[2] - self.y + 1,
|
|
||||||
ex = region[3]- self.x + 1,
|
|
||||||
ey = region[4] - self.y + 1 },
|
|
||||||
{ x = region[1], y = region[2] })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:dirty()
|
|
||||||
for _, line in pairs(self.lines) do
|
|
||||||
line.dirty = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:clean()
|
|
||||||
for y, line in ipairs(self.lines) do
|
|
||||||
line.dirty = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:render(device, layers)
|
|
||||||
layers = layers or self.layers
|
|
||||||
if layers then
|
|
||||||
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
|
||||||
local l = Util.shallowCopy(layers)
|
|
||||||
for _, canvas in ipairs(layers) do
|
|
||||||
table.remove(l, 1)
|
|
||||||
if canvas.visible then
|
|
||||||
self:punch(canvas)
|
|
||||||
canvas:render(device, l)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:blitClipped(device)
|
|
||||||
self:reset()
|
|
||||||
else
|
|
||||||
self:blit(device)
|
|
||||||
end
|
|
||||||
self:clean()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Canvas:blit(device, src, tgt)
|
|
||||||
src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 }
|
|
||||||
tgt = tgt or self
|
|
||||||
|
|
||||||
for i = 0, src.ey - src.y do
|
|
||||||
local line = self.lines[src.y + i]
|
|
||||||
if line and line.dirty then
|
|
||||||
local t, fg, bg = line.text, line.fg, line.bg
|
|
||||||
if src.x > 1 or src.ex < self.ex then
|
|
||||||
t = t:sub(src.x, src.ex)
|
|
||||||
fg = fg:sub(src.x, src.ex)
|
|
||||||
bg = bg:sub(src.x, src.ex)
|
|
||||||
end
|
|
||||||
--if tgt.y + i > self.ey then -- wrong place to do clipping ??
|
|
||||||
-- break
|
|
||||||
--end
|
|
||||||
device.setCursorPos(tgt.x, tgt.y + i)
|
|
||||||
device.blit(t, fg, bg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[-- TransitionSlideLeft --]]--
|
--[[-- TransitionSlideLeft --]]--
|
||||||
UI.TransitionSlideLeft = class()
|
UI.TransitionSlideLeft = class()
|
||||||
UI.TransitionSlideLeft.defaults = {
|
UI.TransitionSlideLeft.defaults = {
|
||||||
@ -1141,7 +886,7 @@ UI.TransitionSlideLeft.defaults = {
|
|||||||
}
|
}
|
||||||
function UI.TransitionSlideLeft:init(args)
|
function UI.TransitionSlideLeft:init(args)
|
||||||
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args)
|
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
|
|
||||||
self.pos = { x = self.ex }
|
self.pos = { x = self.ex }
|
||||||
self.tween = Tween.new(self.ticks, self.pos, { x = self.x }, self.easing)
|
self.tween = Tween.new(self.ticks, self.pos, { x = self.x }, self.easing)
|
||||||
@ -1181,7 +926,7 @@ UI.TransitionSlideRight.defaults = {
|
|||||||
}
|
}
|
||||||
function UI.TransitionSlideRight:init(args)
|
function UI.TransitionSlideRight:init(args)
|
||||||
local defaults = UI:getDefaults(UI.TransitionSlideRight, args)
|
local defaults = UI:getDefaults(UI.TransitionSlideRight, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
|
|
||||||
self.pos = { x = self.x }
|
self.pos = { x = self.x }
|
||||||
self.tween = Tween.new(self.ticks, self.pos, { x = self.ex }, self.easing)
|
self.tween = Tween.new(self.ticks, self.pos, { x = self.ex }, self.easing)
|
||||||
@ -1220,7 +965,7 @@ UI.TransitionExpandUp.defaults = {
|
|||||||
}
|
}
|
||||||
function UI.TransitionExpandUp:init(args)
|
function UI.TransitionExpandUp:init(args)
|
||||||
local defaults = UI:getDefaults(UI.TransitionExpandUp, args)
|
local defaults = UI:getDefaults(UI.TransitionExpandUp, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
self.pos = { y = self.ey + 1 }
|
self.pos = { y = self.ey + 1 }
|
||||||
self.tween = Tween.new(self.ticks, self.pos, { y = self.y }, self.easing)
|
self.tween = Tween.new(self.ticks, self.pos, { y = self.y }, self.easing)
|
||||||
end
|
end
|
||||||
@ -1240,7 +985,7 @@ UI.TransitionGrow.defaults = {
|
|||||||
}
|
}
|
||||||
function UI.TransitionGrow:init(args)
|
function UI.TransitionGrow:init(args)
|
||||||
local defaults = UI:getDefaults(UI.TransitionGrow, args)
|
local defaults = UI:getDefaults(UI.TransitionGrow, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
self.tween = Tween.new(self.ticks,
|
self.tween = Tween.new(self.ticks,
|
||||||
{ x = self.width / 2 - 1, y = self.height / 2 - 1, w = 1, h = 1 },
|
{ x = self.width / 2 - 1, y = self.height / 2 - 1, w = 1, h = 1 },
|
||||||
{ x = 1, y = 1, w = self.width, h = self.height }, self.easing)
|
{ x = 1, y = 1, w = self.width, h = self.height }, self.easing)
|
||||||
@ -1268,7 +1013,7 @@ UI.Device.defaults = {
|
|||||||
function UI.Device:init(args)
|
function UI.Device:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Device)
|
local defaults = UI:getDefaults(UI.Device)
|
||||||
defaults.device = term.current()
|
defaults.device = term.current()
|
||||||
UI.setProperties(defaults, args)
|
UI:setProperties(defaults, args)
|
||||||
|
|
||||||
if defaults.deviceType then
|
if defaults.deviceType then
|
||||||
defaults.device = device[defaults.deviceType]
|
defaults.device = device[defaults.deviceType]
|
||||||
@ -1413,11 +1158,11 @@ end
|
|||||||
function UI.StringBuffer:insert(s, width)
|
function UI.StringBuffer:insert(s, width)
|
||||||
local len = #tostring(s or '')
|
local len = #tostring(s or '')
|
||||||
if len > width then
|
if len > width then
|
||||||
s = s:sub(1, width)
|
s = _ssub(s, 1, width)
|
||||||
end
|
end
|
||||||
table.insert(self.buffer, s)
|
table.insert(self.buffer, s)
|
||||||
if len < width then
|
if len < width then
|
||||||
table.insert(self.buffer, string.rep(' ', width - len))
|
table.insert(self.buffer, _srep(' ', width - len))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1434,7 +1179,7 @@ local SB = { }
|
|||||||
function SB:new(width)
|
function SB:new(width)
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
width = width,
|
width = width,
|
||||||
buf = string.rep(' ', width)
|
buf = _srep(' ', width)
|
||||||
}, { __index = SB })
|
}, { __index = SB })
|
||||||
end
|
end
|
||||||
function SB:insert(x, str, width)
|
function SB:insert(x, str, width)
|
||||||
@ -1446,12 +1191,12 @@ function SB:insert(x, str, width)
|
|||||||
width = self.width - x
|
width = self.width - x
|
||||||
end
|
end
|
||||||
if width > 0 then
|
if width > 0 then
|
||||||
self.buf = self.buf:sub(1, x - 1) .. str:sub(1, width) .. self.buf:sub(x + width)
|
self.buf = _ssub(self.buf, 1, x - 1) .. _ssub(str, 1, width) .. _ssub(self.buf, x + width)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function SB:fill(x, ch, width)
|
function SB:fill(x, ch, width)
|
||||||
width = width or self.width - x + 1
|
width = width or self.width - x + 1
|
||||||
self:insert(x, string.rep(ch, width))
|
self:insert(x, _srep(ch, width))
|
||||||
end
|
end
|
||||||
function SB:center(str)
|
function SB:center(str)
|
||||||
self:insert(math.max(1, math.ceil((self.width - #str + 1) / 2)), str)
|
self:insert(math.max(1, math.ceil((self.width - #str + 1) / 2)), str)
|
||||||
@ -1477,7 +1222,7 @@ UI.Page.defaults = {
|
|||||||
function UI.Page:init(args)
|
function UI.Page:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Page)
|
local defaults = UI:getDefaults(UI.Page)
|
||||||
defaults.parent = UI.defaultDevice
|
defaults.parent = UI.defaultDevice
|
||||||
UI.setProperties(defaults, args)
|
UI:setProperties(defaults, args)
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
|
|
||||||
if self.z then
|
if self.z then
|
||||||
@ -2124,7 +1869,7 @@ UI.Menu.defaults = {
|
|||||||
function UI.Menu:init(args)
|
function UI.Menu:init(args)
|
||||||
local defaults = UI:getDefaults(UI.Menu)
|
local defaults = UI:getDefaults(UI.Menu)
|
||||||
defaults.values = args['menuItems']
|
defaults.values = args['menuItems']
|
||||||
UI.setProperties(defaults, args)
|
UI:setProperties(defaults, args)
|
||||||
UI.Grid.init(self, defaults)
|
UI.Grid.init(self, defaults)
|
||||||
self.pageSize = #args.menuItems
|
self.pageSize = #args.menuItems
|
||||||
end
|
end
|
||||||
@ -2321,7 +2066,7 @@ UI.MenuBar.defaults = {
|
|||||||
|
|
||||||
function UI.MenuBar:init(args)
|
function UI.MenuBar:init(args)
|
||||||
local defaults = UI:getDefaults(UI.MenuBar, args)
|
local defaults = UI:getDefaults(UI.MenuBar, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
|
|
||||||
if not self.children then
|
if not self.children then
|
||||||
self.children = { }
|
self.children = { }
|
||||||
@ -2335,13 +2080,10 @@ function UI.MenuBar:init(args)
|
|||||||
local buttonProperties = {
|
local buttonProperties = {
|
||||||
x = x,
|
x = x,
|
||||||
width = #button.text + self.spacing,
|
width = #button.text + self.spacing,
|
||||||
-- backgroundColor = self.backgroundColor,
|
|
||||||
-- backgroundFocusColor = colors.gray,
|
|
||||||
-- textColor = self.textColor,
|
|
||||||
centered = false,
|
centered = false,
|
||||||
}
|
}
|
||||||
x = x + buttonProperties.width
|
x = x + buttonProperties.width
|
||||||
UI.setProperties(buttonProperties, button)
|
UI:setProperties(buttonProperties, button)
|
||||||
if button.name then
|
if button.name then
|
||||||
self[button.name] = UI.MenuItem(buttonProperties)
|
self[button.name] = UI.MenuItem(buttonProperties)
|
||||||
else
|
else
|
||||||
@ -2868,28 +2610,18 @@ function UI.ProgressBar:init(args)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function UI.ProgressBar:draw()
|
function UI.ProgressBar:draw()
|
||||||
|
self:clear()
|
||||||
local width = math.ceil(self.value / 100 * self.width)
|
local width = math.ceil(self.value / 100 * self.width)
|
||||||
if width > 0 then
|
self:clearArea(1, 1, width, self.height, self.progressColor)
|
||||||
self:write(1, 1, string.rep(' ', width), self.progressColor)
|
|
||||||
end
|
|
||||||
local x = width
|
|
||||||
width = self.width - width
|
|
||||||
if width > 0 then
|
|
||||||
self:write(x + 1,
|
|
||||||
1, string.rep(' ', width), self.backgroundColor)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function UI.ProgressBar:setProgress(progress)
|
|
||||||
self.value = progress
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- VerticalMeter --]]--
|
--[[-- VerticalMeter --]]--
|
||||||
UI.VerticalMeter = class(UI.Window)
|
UI.VerticalMeter = class(UI.Window)
|
||||||
UI.VerticalMeter.defaults = {
|
UI.VerticalMeter.defaults = {
|
||||||
UIElement = 'VerticalMeter',
|
UIElement = 'VerticalMeter',
|
||||||
|
backgroundColor = colors.gray,
|
||||||
meterColor = colors.lime,
|
meterColor = colors.lime,
|
||||||
height = 1,
|
width = 1,
|
||||||
value = 0,
|
value = 0,
|
||||||
}
|
}
|
||||||
function UI.VerticalMeter:init(args)
|
function UI.VerticalMeter:init(args)
|
||||||
@ -2899,19 +2631,8 @@ end
|
|||||||
|
|
||||||
function UI.VerticalMeter:draw()
|
function UI.VerticalMeter:draw()
|
||||||
local height = self.height - math.ceil(self.value / 100 * self.height)
|
local height = self.height - math.ceil(self.value / 100 * self.height)
|
||||||
local filler = string.rep(' ', self.width)
|
self:clear()
|
||||||
|
self:clearArea(1, height + 1, self.width, self.height, self.meterColor)
|
||||||
for i = 1, height do
|
|
||||||
self:write(1, i, filler, self.backgroundColor)
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = height+1, self.height do
|
|
||||||
self:write(1, i, filler, self.meterColor)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function UI.VerticalMeter:setPercent(percent)
|
|
||||||
self.value = percent
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Button --]]--
|
--[[-- Button --]]--
|
||||||
@ -3281,7 +3002,7 @@ function UI.Text:draw()
|
|||||||
self:write(1, 1, Util.widthify(value, self.width), self.backgroundColor)
|
self:write(1, 1, Util.widthify(value, self.width), self.backgroundColor)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-- Text --]]--
|
--[[-- TextArea --]]--
|
||||||
UI.TextArea = class(UI.Window)
|
UI.TextArea = class(UI.Window)
|
||||||
UI.TextArea.defaults = {
|
UI.TextArea.defaults = {
|
||||||
UIElement = 'TextArea',
|
UIElement = 'TextArea',
|
||||||
|
364
sys/apis/ui/canvas.lua
Normal file
364
sys/apis/ui/canvas.lua
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
local class = require('class')
|
||||||
|
local Region = require('ui.region')
|
||||||
|
local Util = require('util')
|
||||||
|
|
||||||
|
local _srep = string.rep
|
||||||
|
local _ssub = string.sub
|
||||||
|
|
||||||
|
local mapColorToGray = {
|
||||||
|
[ colors.white ] = colors.white,
|
||||||
|
[ colors.orange ] = colors.lightGray,
|
||||||
|
[ colors.magenta ] = colors.lightGray,
|
||||||
|
[ colors.lightBlue ] = colors.lightGray,
|
||||||
|
[ colors.yellow ] = colors.lightGray,
|
||||||
|
[ colors.lime ] = colors.lightGray,
|
||||||
|
[ colors.pink ] = colors.lightGray,
|
||||||
|
[ colors.gray ] = colors.gray,
|
||||||
|
[ colors.lightGray ] = colors.lightGray,
|
||||||
|
[ colors.cyan ] = colors.lightGray,
|
||||||
|
[ colors.purple ] = colors.gray,
|
||||||
|
[ colors.blue ] = colors.gray,
|
||||||
|
[ colors.brown ] = colors.gray,
|
||||||
|
[ colors.green ] = colors.lightGray,
|
||||||
|
[ colors.red ] = colors.gray,
|
||||||
|
[ colors.black ] = colors.black,
|
||||||
|
}
|
||||||
|
|
||||||
|
local mapColorToPaint = { }
|
||||||
|
for n = 1, 16 do
|
||||||
|
mapColorToPaint[2 ^ (n - 1)] = _ssub("0123456789abcdef", n, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
local mapGrayToPaint = { }
|
||||||
|
for n = 0, 15 do
|
||||||
|
local gs = mapColorToGray[2 ^ n]
|
||||||
|
mapGrayToPaint[2 ^ n] = mapColorToPaint[gs]
|
||||||
|
end
|
||||||
|
|
||||||
|
local Canvas = class()
|
||||||
|
function Canvas:init(args)
|
||||||
|
|
||||||
|
self.x = 1
|
||||||
|
self.y = 1
|
||||||
|
self.layers = { }
|
||||||
|
|
||||||
|
Util.merge(self, args)
|
||||||
|
|
||||||
|
self.height = self.ey - self.y + 1
|
||||||
|
self.width = self.ex - self.x + 1
|
||||||
|
|
||||||
|
self.lines = { }
|
||||||
|
for i = 1, self.height do
|
||||||
|
self.lines[i] = { }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:resize(w, h)
|
||||||
|
for i = self.height, h do
|
||||||
|
self.lines[i] = { }
|
||||||
|
end
|
||||||
|
|
||||||
|
while #self.lines > h do
|
||||||
|
table.remove(self.lines, #self.lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
if w ~= self.width then
|
||||||
|
for i = 1, self.height do
|
||||||
|
self.lines[i] = { }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.ex = self.x + w - 1
|
||||||
|
self.ey = self.y + h - 1
|
||||||
|
|
||||||
|
self.width = w
|
||||||
|
self.height = h
|
||||||
|
|
||||||
|
self:dirty()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:colorToPaintColor(c)
|
||||||
|
if self.isColor then
|
||||||
|
return mapColorToPaint[c]
|
||||||
|
end
|
||||||
|
return mapGrayToPaint[c]
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:copy()
|
||||||
|
local b = Canvas({ x = self.x, y = self.y, ex = self.ex, ey = self.ey })
|
||||||
|
for i = 1, self.ey - self.y + 1 do
|
||||||
|
b.lines[i].text = self.lines[i].text
|
||||||
|
b.lines[i].fg = self.lines[i].fg
|
||||||
|
b.lines[i].bg = self.lines[i].bg
|
||||||
|
end
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:addLayer(layer, bg, fg)
|
||||||
|
local canvas = Canvas({
|
||||||
|
x = layer.x,
|
||||||
|
y = layer.y,
|
||||||
|
ex = layer.x + layer.width - 1,
|
||||||
|
ey = layer.y + layer.height - 1,
|
||||||
|
isColor = self.isColor,
|
||||||
|
})
|
||||||
|
canvas:clear(bg, fg)
|
||||||
|
|
||||||
|
canvas.parent = self
|
||||||
|
table.insert(self.layers, canvas)
|
||||||
|
return canvas
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:removeLayer()
|
||||||
|
for k, layer in pairs(self.parent.layers) do
|
||||||
|
if layer == self then
|
||||||
|
self:setVisible(false)
|
||||||
|
table.remove(self.parent.layers, k)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:setVisible(visible)
|
||||||
|
self.visible = visible
|
||||||
|
if not visible then
|
||||||
|
self.parent:dirty()
|
||||||
|
-- set parent's lines to dirty for each line in self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:write(x, y, text, bg, fg)
|
||||||
|
if bg then
|
||||||
|
bg = _srep(self:colorToPaintColor(bg), #text)
|
||||||
|
end
|
||||||
|
if fg then
|
||||||
|
fg = _srep(self:colorToPaintColor(fg), #text)
|
||||||
|
end
|
||||||
|
self:writeBlit(x, y, text, bg, fg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:writeBlit(x, y, text, bg, fg)
|
||||||
|
if y > 0 and y <= self.height and x <= self.width then
|
||||||
|
|
||||||
|
local width = #text
|
||||||
|
|
||||||
|
-- fix ffs
|
||||||
|
if x < 1 then
|
||||||
|
text = _ssub(text, 2 - x)
|
||||||
|
if bg then
|
||||||
|
bg = _ssub(bg, 2 - x)
|
||||||
|
end
|
||||||
|
if bg then
|
||||||
|
fg = _ssub(fg, 2 - x)
|
||||||
|
end
|
||||||
|
width = width + x - 1
|
||||||
|
x = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if x + width - 1 > self.width then
|
||||||
|
text = _ssub(text, 1, self.width - x + 1)
|
||||||
|
if bg then
|
||||||
|
bg = _ssub(bg, 1, self.width - x + 1)
|
||||||
|
end
|
||||||
|
if bg then
|
||||||
|
fg = _ssub(fg, 1, self.width - x + 1)
|
||||||
|
end
|
||||||
|
width = #text
|
||||||
|
end
|
||||||
|
|
||||||
|
if width > 0 then
|
||||||
|
|
||||||
|
local function replace(sstr, pos, rstr, width)
|
||||||
|
if pos == 1 and width == self.width then
|
||||||
|
return rstr
|
||||||
|
elseif pos == 1 then
|
||||||
|
return rstr .. _ssub(sstr, pos+width)
|
||||||
|
elseif pos + width > self.width then
|
||||||
|
return _ssub(sstr, 1, pos-1) .. rstr
|
||||||
|
end
|
||||||
|
return _ssub(sstr, 1, pos-1) .. rstr .. _ssub(sstr, pos+width)
|
||||||
|
end
|
||||||
|
|
||||||
|
local line = self.lines[y]
|
||||||
|
line.dirty = true
|
||||||
|
line.text = replace(line.text, x, text, width)
|
||||||
|
if fg then
|
||||||
|
line.fg = replace(line.fg, x, fg, width)
|
||||||
|
end
|
||||||
|
if bg then
|
||||||
|
line.bg = replace(line.bg, x, bg, width)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:writeLine(y, text, fg, bg)
|
||||||
|
self.lines[y].dirty = true
|
||||||
|
self.lines[y].text = text
|
||||||
|
self.lines[y].fg = fg
|
||||||
|
self.lines[y].bg = bg
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:reset()
|
||||||
|
self.regions = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:clear(bg, fg)
|
||||||
|
local width = self.ex - self.x + 1
|
||||||
|
local text = _srep(' ', width)
|
||||||
|
fg = _srep(self:colorToPaintColor(fg), width)
|
||||||
|
bg = _srep(self:colorToPaintColor(bg), width)
|
||||||
|
for i = 1, self.ey - self.y + 1 do
|
||||||
|
self:writeLine(i, text, fg, bg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:punch(rect)
|
||||||
|
if not self.regions then
|
||||||
|
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
||||||
|
end
|
||||||
|
self.regions:subRect(rect.x, rect.y, rect.ex, rect.ey)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:blitClipped(device)
|
||||||
|
for _,region in ipairs(self.regions.region) do
|
||||||
|
self:blit(device,
|
||||||
|
{ x = region[1] - self.x + 1,
|
||||||
|
y = region[2] - self.y + 1,
|
||||||
|
ex = region[3]- self.x + 1,
|
||||||
|
ey = region[4] - self.y + 1 },
|
||||||
|
{ x = region[1], y = region[2] })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:redraw(device)
|
||||||
|
self:reset()
|
||||||
|
if #self.layers > 0 then
|
||||||
|
for _,layer in pairs(self.layers) do
|
||||||
|
self:punch(layer)
|
||||||
|
end
|
||||||
|
self:blitClipped(device)
|
||||||
|
else
|
||||||
|
self:blit(device)
|
||||||
|
end
|
||||||
|
self:clean()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:isDirty()
|
||||||
|
for _, line in pairs(self.lines) do
|
||||||
|
if line.dirty then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:dirty()
|
||||||
|
for _, line in pairs(self.lines) do
|
||||||
|
line.dirty = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:clean()
|
||||||
|
for y, line in pairs(self.lines) do
|
||||||
|
line.dirty = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:render(device, layers) --- redrawAll ?
|
||||||
|
layers = layers or self.layers
|
||||||
|
if #layers > 0 then
|
||||||
|
self.regions = Region.new(self.x, self.y, self.ex, self.ey)
|
||||||
|
local l = Util.shallowCopy(layers)
|
||||||
|
for _, canvas in ipairs(layers) do
|
||||||
|
table.remove(l, 1)
|
||||||
|
if canvas.visible then
|
||||||
|
self:punch(canvas)
|
||||||
|
canvas:render(device, l)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:blitClipped(device)
|
||||||
|
self:reset()
|
||||||
|
else
|
||||||
|
self:blit(device)
|
||||||
|
end
|
||||||
|
self:clean()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas:blit(device, src, tgt)
|
||||||
|
src = src or { x = 1, y = 1, ex = self.ex - self.x + 1, ey = self.ey - self.y + 1 }
|
||||||
|
tgt = tgt or self
|
||||||
|
|
||||||
|
for i = 0, src.ey - src.y do
|
||||||
|
local line = self.lines[src.y + i]
|
||||||
|
if line and line.dirty then
|
||||||
|
local t, fg, bg = line.text, line.fg, line.bg
|
||||||
|
if src.x > 1 or src.ex < self.ex then
|
||||||
|
t = _ssub(t, src.x, src.ex)
|
||||||
|
fg = _ssub(fg, src.x, src.ex)
|
||||||
|
bg = _ssub(bg, src.x, src.ex)
|
||||||
|
end
|
||||||
|
--if tgt.y + i > self.ey then -- wrong place to do clipping ??
|
||||||
|
-- break
|
||||||
|
--end
|
||||||
|
device.setCursorPos(tgt.x, tgt.y + i)
|
||||||
|
device.blit(t, fg, bg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Canvas.convertWindow(win, parent, x, y)
|
||||||
|
|
||||||
|
local w, h = win.getSize()
|
||||||
|
|
||||||
|
win.canvas = Canvas({
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
ex = x + w - 1,
|
||||||
|
ey = y + h - 1,
|
||||||
|
isColor = win.isColor(),
|
||||||
|
})
|
||||||
|
|
||||||
|
function win.clear()
|
||||||
|
win.canvas:clear(win.getBackgroundColor(), win.getTextColor())
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.clearLine()
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
win.canvas:write(1,
|
||||||
|
y,
|
||||||
|
_srep(' ', win.canvas.width),
|
||||||
|
win.getBackgroundColor(),
|
||||||
|
win.getTextColor())
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.write(str)
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
win.canvas:write(x,
|
||||||
|
y,
|
||||||
|
str,
|
||||||
|
win.getBackgroundColor(),
|
||||||
|
win.getTextColor())
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.blit(text, fg, bg)
|
||||||
|
local x, y = win.getCursorPos()
|
||||||
|
win.canvas:writeBlit(x, y, text, bg, fg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.redraw()
|
||||||
|
win.canvas:redraw(parent)
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.scroll()
|
||||||
|
error('CWin:scroll: not implemented')
|
||||||
|
end
|
||||||
|
|
||||||
|
function win.reposition(x, y, width, height)
|
||||||
|
win.canvas.x, win.canvas.y = x, y
|
||||||
|
win.canvas:resize(width or win.canvas.width, height or win.canvas.height)
|
||||||
|
end
|
||||||
|
|
||||||
|
win.clear()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Canvas
|
@ -17,8 +17,8 @@ function Glasses:init(args)
|
|||||||
}
|
}
|
||||||
defaults.width, defaults.height = term.getSize()
|
defaults.width, defaults.height = term.getSize()
|
||||||
|
|
||||||
UI.setProperties(defaults, args)
|
UI:setProperties(defaults, args)
|
||||||
UI.setProperties(self, defaults)
|
UI:setProperties(self, defaults)
|
||||||
|
|
||||||
self.bridge = Peripheral.get({
|
self.bridge = Peripheral.get({
|
||||||
type = 'openperipheral_bridge',
|
type = 'openperipheral_bridge',
|
||||||
|
@ -177,7 +177,7 @@ function UI.Icon:init(args)
|
|||||||
width = 14,
|
width = 14,
|
||||||
height = 4,
|
height = 4,
|
||||||
}
|
}
|
||||||
UI.setProperties(defaults, args)
|
UI:setProperties(defaults, args)
|
||||||
UI.Window.init(self, defaults)
|
UI.Window.init(self, defaults)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -327,8 +327,8 @@ function page:refresh()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function page:resize()
|
function page:resize()
|
||||||
self:refresh()
|
|
||||||
UI.Page.resize(self)
|
UI.Page.resize(self)
|
||||||
|
self:refresh()
|
||||||
end
|
end
|
||||||
|
|
||||||
function page:eventHandler(event)
|
function page:eventHandler(event)
|
||||||
|
@ -25,7 +25,8 @@ local Config = require('config')
|
|||||||
local Opus = require('opus')
|
local Opus = require('opus')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
-- Begin multishell
|
local SESSION_FILE = 'usr/config/multishell.session'
|
||||||
|
|
||||||
local parentTerm = term.current()
|
local parentTerm = term.current()
|
||||||
local w,h = parentTerm.getSize()
|
local w,h = parentTerm.getSize()
|
||||||
local tabs = {}
|
local tabs = {}
|
||||||
@ -228,6 +229,7 @@ local function launchProcess(tab)
|
|||||||
selectTab(previousTab)
|
selectTab(previousTab)
|
||||||
end
|
end
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
|
saveSession()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
tabs[tab.tabId] = tab
|
tabs[tab.tabId] = tab
|
||||||
@ -259,6 +261,19 @@ local function resizeWindows()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function saveSession()
|
||||||
|
local t = { }
|
||||||
|
for _,process in pairs(tabs) do
|
||||||
|
if process.path and not process.isOverview and not process.hidden then
|
||||||
|
table.insert(t, {
|
||||||
|
path = process.path,
|
||||||
|
args = process.args,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--Util.writeTable(SESSION_FILE, t)
|
||||||
|
end
|
||||||
|
|
||||||
local control
|
local control
|
||||||
local hotkeys = { }
|
local hotkeys = { }
|
||||||
|
|
||||||
@ -383,6 +398,11 @@ function multishell.openTab(tab)
|
|||||||
else
|
else
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not tab.hidden then
|
||||||
|
saveSession()
|
||||||
|
end
|
||||||
|
|
||||||
return tab.tabId
|
return tab.tabId
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -454,6 +474,7 @@ end)
|
|||||||
|
|
||||||
local function startup()
|
local function startup()
|
||||||
local hasError
|
local hasError
|
||||||
|
local session = Util.readTable(SESSION_FILE)
|
||||||
|
|
||||||
local overviewId = multishell.openTab({
|
local overviewId = multishell.openTab({
|
||||||
path = 'sys/apps/Overview.lua',
|
path = 'sys/apps/Overview.lua',
|
||||||
@ -471,6 +492,12 @@ local function startup()
|
|||||||
hasError = true
|
hasError = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if session then
|
||||||
|
for _,v in pairs(session) do
|
||||||
|
multishell.openTab(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if hasError then
|
if hasError then
|
||||||
print()
|
print()
|
||||||
error('An autorun program has errored')
|
error('An autorun program has errored')
|
||||||
|
@ -27,13 +27,17 @@ if not socket then
|
|||||||
error('Unable to connect to ' .. remoteId .. ' on port 5900')
|
error('Unable to connect to ' .. remoteId .. ' on port 5900')
|
||||||
end
|
end
|
||||||
|
|
||||||
local w, h = term.getSize()
|
local function writeTermInfo()
|
||||||
socket:write({
|
local w, h = term.getSize()
|
||||||
|
socket:write({
|
||||||
type = 'termInfo',
|
type = 'termInfo',
|
||||||
width = w,
|
width = w,
|
||||||
height = h,
|
height = h,
|
||||||
isColor = term.isColor(),
|
isColor = term.isColor(),
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
writeTermInfo()
|
||||||
|
|
||||||
local ct = Util.shallowCopy(term.current())
|
local ct = Util.shallowCopy(term.current())
|
||||||
|
|
||||||
@ -78,6 +82,8 @@ while true do
|
|||||||
type = 'shellRemote',
|
type = 'shellRemote',
|
||||||
event = e,
|
event = e,
|
||||||
})
|
})
|
||||||
|
elseif event == 'term_resize' then
|
||||||
|
writeTermInfo()
|
||||||
elseif event == 'terminate' then
|
elseif event == 'terminate' then
|
||||||
socket:close()
|
socket:close()
|
||||||
ct.setBackgroundColor(colors.black)
|
ct.setBackgroundColor(colors.black)
|
||||||
|
@ -2,7 +2,7 @@ local Event = require('event')
|
|||||||
local Socket = require('socket')
|
local Socket = require('socket')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local function wrapTerm(socket, termInfo)
|
local function vncHost(socket)
|
||||||
local methods = { 'blit', 'clear', 'clearLine', 'setCursorPos', 'write',
|
local methods = { 'blit', 'clear', 'clearLine', 'setCursorPos', 'write',
|
||||||
'setTextColor', 'setTextColour', 'setBackgroundColor',
|
'setTextColor', 'setTextColour', 'setBackgroundColor',
|
||||||
'setBackgroundColour', 'scroll', 'setCursorBlink', }
|
'setBackgroundColour', 'scroll', 'setCursorBlink', }
|
||||||
@ -27,17 +27,6 @@ local function wrapTerm(socket, termInfo)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
socket.term.getSize = function()
|
|
||||||
return termInfo.width, termInfo.height
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function vncHost(socket, termInfo)
|
|
||||||
|
|
||||||
wrapTerm(socket, termInfo)
|
|
||||||
|
|
||||||
os.queueEvent('term_resize')
|
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local data = socket:read()
|
local data = socket:read()
|
||||||
if not data then
|
if not data then
|
||||||
@ -47,6 +36,11 @@ local function vncHost(socket, termInfo)
|
|||||||
|
|
||||||
if data.type == 'shellRemote' then
|
if data.type == 'shellRemote' then
|
||||||
os.queueEvent(unpack(data.event))
|
os.queueEvent(unpack(data.event))
|
||||||
|
elseif data.type == 'termInfo' then
|
||||||
|
socket.term.getSize = function()
|
||||||
|
return data.width, data.height
|
||||||
|
end
|
||||||
|
os.queueEvent('term_resize')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -65,13 +59,9 @@ Event.addRoutine(function()
|
|||||||
|
|
||||||
print('vnc: connection from ' .. socket.dhost)
|
print('vnc: connection from ' .. socket.dhost)
|
||||||
|
|
||||||
local termInfo = socket:read(5)
|
|
||||||
if termInfo then
|
|
||||||
-- no new process - only 1 connection allowed
|
-- no new process - only 1 connection allowed
|
||||||
-- due to term size issues
|
-- due to term size issues
|
||||||
vncHost(socket, termInfo)
|
vncHost(socket)
|
||||||
else
|
|
||||||
socket:close()
|
socket:close()
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user