mirror of
https://github.com/CCLeonOS/LeonOS.git
synced 2026-03-03 15:17:01 +00:00
添加 LeonOS 的基本实现,包括: - 核心 API 模块(colors, disk, gps, keys, multishell, parallel, rednet, redstone, settings, vector) - 命令行程序(about, alias, bg, clear, copy, delete, edit, fg, help, list, lua, mkdir, move, paint, peripherals, programs, reboot, set, shutdown, threads) - 系统启动脚本和包管理 - 文档(README.md, LICENSE) - 开发工具(devbin)和更新程序 实现功能: - 完整的线程管理系统 - 兼容 ComputerCraft 的 API 设计 - 改进的 shell 和命令补全系统 - 多标签终端支持 - 设置管理系统
369 lines
9.2 KiB
Lua
369 lines
9.2 KiB
Lua
-- window api
|
|
|
|
local term = require("term")
|
|
local colors = require("colors")
|
|
local expect = require("cc.expect").expect
|
|
local range = require("cc.expect").range
|
|
local window = {}
|
|
|
|
local rep = string.rep
|
|
local sub = string.sub
|
|
local max = math.max
|
|
local min = math.min
|
|
|
|
local function into_buffer(buf, x, y, text)
|
|
if not text then return end
|
|
if not buf[y] then return end
|
|
text = sub(text, 1, #buf[y] - x + 1)
|
|
if x < 1 then
|
|
text = sub(text, -x + 2)
|
|
x = 1
|
|
end
|
|
local olen = #buf[y]
|
|
if x + #text > olen then
|
|
buf[y] = sub(buf[y], 0, max(0, x-1)) .. text
|
|
else
|
|
buf[y] = sub(buf[y], 0, max(0, x-1)) .. text .. buf[y]:sub(x + #text)
|
|
end
|
|
buf[y] = sub(buf[y], 1, olen)
|
|
end
|
|
|
|
function window.create(parent, x, y, width, height, visible)
|
|
if type(parent) ~= "table" then expect(1, parent, "table") end
|
|
if parent == term then
|
|
error("do not pass 'term' as a window parent", 0)
|
|
end
|
|
if type(x) ~= "number" then expect(2, x, "number") end
|
|
if type(y) ~= "number" then expect(3, y, "number") end
|
|
if type(width) ~= "number" then expect(4, width, "number") end
|
|
if type(height) ~= "number" then expect(5, height, "number") end
|
|
if type(visible) ~= "boolean" then expect(6, visible, "boolean", "nil") end
|
|
if visible == nil then visible = true end
|
|
|
|
local cursorX, cursorY, cursorBlink = 1, 1, false
|
|
local foreground, background = colors.toBlit(colors.white),
|
|
colors.toBlit(colors.black)
|
|
local textbuf, fgbuf, bgbuf = {}, {}, {}
|
|
|
|
local win = {}
|
|
|
|
local palette = {}
|
|
for i=0, 15, 1 do
|
|
palette[i] = colors.packRGB(parent.getPaletteColor(2^i))
|
|
end
|
|
|
|
local function drawLine(i)
|
|
parent.setCursorPos(x, y + i - 1)
|
|
if not textbuf[i] then return end
|
|
parent.blit(textbuf[i], fgbuf[i], bgbuf[i])
|
|
end
|
|
|
|
local function draw()
|
|
local blink = parent.getCursorBlink()
|
|
parent.setCursorBlink(false)
|
|
|
|
local parentW, parentH = parent.getSize()
|
|
local firstVisible = math.max(1, -y+2)
|
|
|
|
for i=1, math.min(height, parentH), 1 do
|
|
drawLine(firstVisible+i-1)
|
|
end
|
|
|
|
parent.setCursorBlink(blink)
|
|
end
|
|
|
|
local function restorePalette()
|
|
for i=0, 15, 1 do
|
|
parent.setPaletteColor(2^i, palette[i])
|
|
end
|
|
end
|
|
|
|
local function restoreCursorBlink()
|
|
parent.setCursorBlink(cursorBlink)
|
|
end
|
|
|
|
local function restoreCursorPos()
|
|
if cursorX > 0 and cursorY > 0 and
|
|
cursorX <= width and cursorY <= height then
|
|
parent.setCursorPos(x + cursorX - 1, y + cursorY - 1)
|
|
else
|
|
parent.setCursorPos(0, 0)
|
|
end
|
|
end
|
|
|
|
local function restoreCursorColor()
|
|
parent.setTextColor(2^tonumber(foreground, 16))
|
|
end
|
|
|
|
function win.write(text)
|
|
if type(text) ~= "string" then expect(1, text, "string") end
|
|
local fg, bg = rep(foreground, #text), background:rep(#text)
|
|
into_buffer(textbuf, cursorX, cursorY, text)
|
|
into_buffer(fgbuf, cursorX, cursorY, fg)
|
|
into_buffer(bgbuf, cursorX, cursorY, bg)
|
|
cursorX = max(-100, min(cursorX + #text, width + 1))
|
|
|
|
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
|
|
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then win.redraw() end
|
|
end
|
|
|
|
function win.blit(text, tcol, bcol)
|
|
if type(text) ~= "string" then expect(1, text, "string") end
|
|
if type(tcol) ~= "string" then expect(2, tcol, "string") end
|
|
if type(bcol) ~= "string" then expect(3, bcol, "string") end
|
|
assert(#text == #tcol and #text == #bcol, "mismatched argument lengths")
|
|
|
|
into_buffer(textbuf, cursorX, cursorY, text)
|
|
into_buffer(fgbuf, cursorX, cursorY, tcol)
|
|
into_buffer(bgbuf, cursorX, cursorY, bcol)
|
|
cursorX = max(0, min(cursorX + #text, width + 1))
|
|
|
|
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
|
|
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then
|
|
drawLine(cursorY)
|
|
restoreCursorColor()
|
|
restoreCursorPos()
|
|
end
|
|
end
|
|
|
|
function win.clear()
|
|
local fore = rep(foreground, width)
|
|
local back = rep(background, width)
|
|
local blank = rep(" ", width)
|
|
|
|
for i=1, height, 1 do
|
|
textbuf[i] = blank
|
|
fgbuf[i] = fore
|
|
bgbuf[i] = back
|
|
end
|
|
|
|
if visible then
|
|
win.redraw()
|
|
end
|
|
end
|
|
|
|
|
|
function win.clearLine()
|
|
local emptyText, emptyFg, emptyBg =
|
|
rep(" ", width),
|
|
rep(foreground, width),
|
|
rep(background, width)
|
|
|
|
textbuf[cursorY] = emptyText
|
|
fgbuf[cursorY] = emptyFg
|
|
bgbuf[cursorY] = emptyBg
|
|
|
|
local firstVisible, _, maxHeight = math.max(1, -y+2), parent.getSize()
|
|
if visible and cursorY >= firstVisible and cursorY <= firstVisible+maxHeight then
|
|
win.redraw()
|
|
end
|
|
end
|
|
|
|
function win.getCursorPos()
|
|
return cursorX, cursorY
|
|
end
|
|
|
|
function win.setCursorPos(_x, _y)
|
|
if type(_x) ~= "number" then expect(1, _x, "number") end
|
|
if type(_y) ~= "number" then expect(2, _y, "number") end
|
|
|
|
cursorX, cursorY = _x, _y
|
|
if visible then
|
|
restoreCursorPos()
|
|
end
|
|
end
|
|
|
|
function win.setCursorBlink(blink)
|
|
cursorBlink = not not blink
|
|
if visible then
|
|
restoreCursorBlink()
|
|
end
|
|
end
|
|
|
|
function win.getCursorBlink()
|
|
return cursorBlink
|
|
end
|
|
|
|
function win.isColor()
|
|
return parent.isColor()
|
|
end
|
|
|
|
win.isColour = win.isColor
|
|
|
|
function win.setTextColor(color)
|
|
if type(color) ~= "number" then expect(1, color, "number") end
|
|
foreground = colors.toBlit(color) or foreground
|
|
if visible then
|
|
restoreCursorColor()
|
|
end
|
|
end
|
|
|
|
win.setTextColour = win.setTextColor
|
|
|
|
function win.setPaletteColor(color, r, g, b)
|
|
if type(color) ~= "number" then expect(1, color, "number") end
|
|
if type(r) ~= "number" then expect(2, r, "number") end
|
|
|
|
if r < 1 then
|
|
if type(g) ~= "number" then expect(3, g, "number") end
|
|
if type(b) ~= "number" then expect(4, b, "number") end
|
|
palette[math.floor(math.log(color, 2))] = colors.packRGB(r, g, b)
|
|
else
|
|
palette[math.floor(math.log(color, 2))] = r
|
|
end
|
|
|
|
if visible then
|
|
restorePalette()
|
|
end
|
|
end
|
|
|
|
win.setPaletteColour = win.setPaletteColor
|
|
|
|
function win.getPaletteColor(color)
|
|
if type(color) ~= "number" then expect(1, color, "number") end
|
|
return palette[math.floor(math.log(color, 2))]
|
|
end
|
|
|
|
win.getPaletteColour = win.getPaletteColor
|
|
|
|
function win.setBackgroundColor(color)
|
|
if type(color) ~= "number" then expect(1, color, "number") end
|
|
background = colors.toBlit(color)
|
|
end
|
|
|
|
win.setBackgroundColour = win.setBackgroundColor
|
|
|
|
function win.getSize()
|
|
return width, height
|
|
end
|
|
|
|
function win.scroll(n)
|
|
if type(n) ~= "number" then expect(1, n, "number") end
|
|
|
|
if n == 0 then return end
|
|
local fg = rep(foreground, width)
|
|
local bg = rep(background, width)
|
|
local blank = rep(" ", width)
|
|
|
|
if n > 0 then
|
|
for _=1, n, 1 do
|
|
table.remove(textbuf, 1)
|
|
textbuf[#textbuf+1] = blank
|
|
table.remove(fgbuf, 1)
|
|
fgbuf[#fgbuf+1] = fg
|
|
table.remove(bgbuf, 1)
|
|
bgbuf[#bgbuf+1] = bg
|
|
end
|
|
else
|
|
for _=1, -n, 1 do
|
|
table.insert(textbuf, 1, blank)
|
|
textbuf[#textbuf] = nil
|
|
table.insert(fgbuf, 1, fg)
|
|
fgbuf[#fgbuf] = nil
|
|
table.insert(bgbuf, 1, bg)
|
|
bgbuf[#bgbuf] = nil
|
|
end
|
|
end
|
|
|
|
if visible then
|
|
win.redraw()
|
|
end
|
|
end
|
|
|
|
function win.getTextColor()
|
|
return 2^tonumber(foreground, 16)
|
|
end
|
|
|
|
win.getTextColour = win.getTextColor
|
|
|
|
function win.getBackgroundColor()
|
|
return 2^tonumber(background, 16)
|
|
end
|
|
|
|
win.getBackgroundColour = win.getBackgroundColor
|
|
|
|
function win.getLine(ly)
|
|
if type(ly) ~= "number" then expect(1, ly, "number") end
|
|
if ly < 1 or ly > height then range(ly, 1, height) end
|
|
return textbuf[ly], fgbuf[ly], bgbuf[ly]
|
|
end
|
|
|
|
function win.setVisible(vis)
|
|
if vis and not visible then
|
|
draw()
|
|
restorePalette()
|
|
restoreCursorBlink()
|
|
restoreCursorPos()
|
|
restoreCursorColor()
|
|
end
|
|
visible = not not vis
|
|
end
|
|
|
|
function win.redraw()
|
|
if visible then
|
|
draw()
|
|
restorePalette()
|
|
restoreCursorPos()
|
|
restoreCursorBlink()
|
|
restoreCursorColor()
|
|
end
|
|
end
|
|
|
|
function win.restoreCursor()
|
|
if visible then
|
|
restoreCursorBlink()
|
|
restoreCursorPos()
|
|
restoreCursorColor()
|
|
end
|
|
end
|
|
|
|
function win.getPosition()
|
|
return x, y
|
|
end
|
|
|
|
local function resize_buffer(buf, nw, nh, c)
|
|
if nw > width then
|
|
for i=1, #buf, 1 do
|
|
buf[i] = buf[i] .. sub(rep(buf[i], -1), nw - width)
|
|
end
|
|
end
|
|
|
|
if nh > #buf then
|
|
for _=1, nh - #buf, 1 do
|
|
buf[#buf+1] = rep(c, nw)
|
|
end
|
|
end
|
|
end
|
|
|
|
function win.reposition(nx, ny, nw, nh, npar)
|
|
if type(nx) ~= "number" then expect(1, nx, "number") end
|
|
if type(ny) ~= "number" then expect(2, ny, "number") end
|
|
if type(nw) ~= "number" then expect(3, nw, "number", "nil") end
|
|
if type(nh) ~= "number" then expect(4, nh, "number", "nil") end
|
|
if type(npar) ~= "table" then expect(5, npar, "table", "nil") end
|
|
|
|
x, y, width, height, parent =
|
|
nx or x, ny or y,
|
|
nw or width, nh or height,
|
|
npar or parent
|
|
|
|
resize_buffer(textbuf, width, height, " ")
|
|
resize_buffer(fgbuf, width, height, "0")
|
|
resize_buffer(bgbuf, width, height, "f")
|
|
|
|
if visible then
|
|
win.redraw()
|
|
end
|
|
end
|
|
|
|
function win.at(_x, _y)
|
|
win.setCursorPos(_x, _y)
|
|
return win
|
|
end
|
|
|
|
win.clear()
|
|
return win
|
|
end
|
|
|
|
return window
|