feat(appgui): 添加应用GUI界面支持及包类型管理

新增appgui API用于绘制顶部和底部状态栏,提供一致的UI界面
在package.json中添加type字段区分应用和API包类型
更新安装程序以使用新的appgui界面
修改pkg程序以支持根据包类型安装到不同目录
添加appgui使用文档和演示程序
This commit is contained in:
2025-09-12 17:10:44 +08:00
parent 429b98ab00
commit 0bb365cadb
7 changed files with 346 additions and 33 deletions

View File

@@ -4,6 +4,7 @@
"description": "An example package for LeonOS", "description": "An example package for LeonOS",
"author": "LeonMMcoset", "author": "LeonMMcoset",
"license": "MIT", "license": "MIT",
"type": "app",
"dependencies": {}, "dependencies": {},
"files": [ "files": [
"example.lua" "example.lua"

View File

@@ -0,0 +1,94 @@
-- appgui API for LeonOS
-- Provides simple topbar and downbar drawing functions
local term = require("term")
local colors = require("colors")
local expect = require("cc.expect").expect
local appgui = {}
--- Draws a top bar with the specified text centered
--- @param text string The text to display in the top bar
--- @param fgColor number Optional foreground color (default: white)
--- @param bgColor number Optional background color (default: blue)
function appgui.topbar(text, fgColor, bgColor)
expect(1, text, "string")
expect(2, fgColor, "number", "nil")
expect(3, bgColor, "number", "nil")
-- Default colors
fgColor = fgColor or colors.white
bgColor = bgColor or colors.blue
-- Save current colors
local oldFg = term.getTextColor()
local oldBg = term.getBackgroundColor()
-- Get terminal size
local w, h = term.getSize()
-- Set colors and position
term.setTextColor(fgColor)
term.setBackgroundColor(bgColor)
term.setCursorPos(1, 1)
-- Clear the top line
term.clearLine()
-- Calculate padding for centered text
local padding = math.floor((w - #text) / 2)
-- Draw the top bar with centered text
term.write(string.rep(" ", padding) .. text .. string.rep(" ", padding))
-- Restore original colors
term.setTextColor(oldFg)
term.setBackgroundColor(oldBg)
-- Move cursor below the top bar
term.setCursorPos(1, 2)
end
--- Draws a bottom bar with the specified text centered
--- @param text string The text to display in the bottom bar
--- @param fgColor number Optional foreground color (default: white)
--- @param bgColor number Optional background color (default: blue)
function appgui.downbar(text, fgColor, bgColor)
expect(1, text, "string")
expect(2, fgColor, "number", "nil")
expect(3, bgColor, "number", "nil")
-- Default colors
fgColor = fgColor or colors.white
bgColor = bgColor or colors.blue
-- Save current colors
local oldFg = term.getTextColor()
local oldBg = term.getBackgroundColor()
-- Get terminal size
local w, h = term.getSize()
-- Set colors and position
term.setTextColor(fgColor)
term.setBackgroundColor(bgColor)
term.setCursorPos(1, h)
-- Clear the bottom line
term.clearLine()
-- Calculate padding for centered text
local padding = math.floor((w - #text) / 2)
-- Draw the bottom bar with centered text
term.write(string.rep(" ", padding) .. text .. string.rep(" ", padding))
-- Restore original colors
term.setTextColor(oldFg)
term.setBackgroundColor(oldBg)
-- Move cursor to a safe position
term.setCursorPos(1, 1)
end
return appgui

View File

@@ -0,0 +1,103 @@
=== appgui API ===
The `appgui` API provides simple functions for drawing top bars and bottom bars in LeonOS applications, making it easy to create consistent user interfaces.
== Introduction ==
The appgui API is designed to simplify the process of adding professional-looking UI elements to your applications. It provides two main functions for drawing centered text bars at the top or bottom of the screen.
== Available Functions ==
- **appgui.topbar(text, [fgColor], [bgColor])**: Draws a top bar with centered text
- **appgui.downbar(text, [fgColor], [bgColor])**: Draws a bottom bar with centered text
== Function Parameters ==
Both functions accept the following parameters:
- **text**: (string) The text to display in the bar
- **fgColor**: (number, optional) The foreground color (default: white)
- **bgColor**: (number, optional) The background color (default: blue)
== Usage Examples ==
=== Basic Usage ===
First, you need to import the appgui module:
>>color yellow
local appgui = require("appgui")
>>color white
Then you can use the functions to draw bars:
1. Draw a top bar with default colors (white text on blue background):
>>color yellow
appgui.topbar("My Application Title")
>>color white
2. Draw a bottom bar with default colors:
>>color yellow
appgui.downbar("Status: Ready")
>>color white
=== Custom Colors ===
You can specify custom colors using the `colors` module:
>>color yellow
local colors = require("colors")
-- Red text on yellow background
appgui.topbar("Warning Message", colors.red, colors.yellow)
-- Green text on black background
appgui.downbar("Success", colors.green, colors.black)
>>color white
=== Complete Example ===
Here's a complete example showing how to use both top and bottom bars in an application:
>>color yellow
local appgui = require("appgui")
local term = require("term")
local colors = require("colors")
-- Clear the screen
term.clear()
-- Draw top and bottom bars
appgui.topbar("My Application")
appgui.downbar("Press Q to quit")
-- Add some content
print()
print("Welcome to my application!")
print()
print("This is a demonstration of the appgui API.")
print()
-- Wait for 'Q' key to exit
while true do
local event, key = os.pullEvent("key")
if key == 16 then -- Q key
break
end
end
>>color white
== Notes ==
- The text will be automatically centered in the bar
- The functions will preserve the original terminal colors by saving and restoring them
- After drawing a top bar, the cursor will be positioned below the bar
- After drawing a bottom bar, the cursor will be positioned at the top of the screen
- You can use any colors available in the `colors` module
- If the text is longer than the terminal width, it will be truncated
== See Also ==
- **colors**: For available color values
- **term**: For other terminal manipulation functions
- **appgui_demo**: A demonstration program showing the appgui API in action

View File

@@ -52,10 +52,33 @@ The package.json file contains metadata about your package. Here's an example:
- **version**: The package version (semantic versioning recommended) - **version**: The package version (semantic versioning recommended)
- **author**: Your name or username - **author**: Your name or username
- **description**: A short description of what the package does - **description**: A short description of what the package does
- **type**: The type of your package ("app" for applications, "api" for libraries)
- **main**: The main Lua file to load - **main**: The main Lua file to load
- **dependencies**: Other packages your package depends on - **dependencies**: Other packages your package depends on
- **exports**: Functions or variables to export for other programs to use - **exports**: Functions or variables to export for other programs to use
== Package Type Field ==
The `type` field in package.json determines where your package files will be installed:
- **app**: Files will be installed in the `/app` directory (default behavior)
- **api**: Files will be installed in the `/leonos/apis` directory
Example of a package.json with type field:
>>color yellow
{
"name": "example-api",
"version": "1.0.0",
"author": "Your Name",
"description": "An example API package",
"type": "api",
"main": "example-api.lua",
"dependencies": {},
"exports": {}
}
>>color white
== Writing Package Code == == Writing Package Code ==
Edit the `<package_name>.lua` file to add your code. Here's a simple example: Edit the `<package_name>.lua` file to add your code. Here's a simple example:

View File

@@ -0,0 +1,64 @@
-- appgui_demo.lua
-- Demonstration of the appgui API for drawing top and bottom bars
local appgui = require("appgui")
local term = require("term")
local colors = require("colors")
-- Clear the screen before starting
term.clear()
-- Draw the top bar with default colors (white text on blue background)
appgui.topbar("LeonOS App GUI Demo")
-- Add some content in the middle
print()
print("This is a demonstration of the appgui API.")
print()
print("The top bar shows the application title.")
print("The bottom bar shows the status information.")
print()
print("Press any key to see custom colors...")
-- Wait for a key press
os.pullEvent("key")
-- Clear the screen and redraw with custom colors
term.clear()
appgui.topbar("Custom Colored Top Bar", colors.yellow, colors.red)
-- Add some content
print()
print("Now with custom colors!")
print()
print("Top bar: Yellow text on Red background")
print()
print("Press any key to continue...")
-- Wait for a key press
os.pullEvent("key")
-- Clear the screen and draw both top and bottom bars
term.clear()
appgui.topbar("Complete GUI Demo")
appgui.downbar("Status: Running - Press Q to quit")
-- Add some content in the middle
print()
print("Now you can see both top and bottom bars.")
print()
print("Try resizing the terminal window to see how the text stays centered.")
print()
print("Press Q to exit this demo.")
-- Main loop to handle key presses
while true do
local event, key = os.pullEvent("key")
if key == 16 then -- Q key
break
end
end
-- Clear the screen before exiting
term.clear()
print("AppGUI Demo has ended.")

View File

@@ -54,6 +54,7 @@ local function create_package(pkg_name)
description = "A new package for LeonOS", description = "A new package for LeonOS",
author = "LeonOS User", author = "LeonOS User",
license = "MIT", license = "MIT",
type = "app", -- 默认类型为app
dependencies = {}, dependencies = {},
files = { files = {
pkg_name .. ".lua" pkg_name .. ".lua"
@@ -288,18 +289,25 @@ local function install_github_package(repo_path, options)
meta_file:write(textutils.serializeJSON(meta, false)) meta_file:write(textutils.serializeJSON(meta, false))
meta_file:close() meta_file:close()
-- 下载并安装文件 -- 根据package类型确定安装目录
print("Installing version: " .. pkg_version) print("Installing version: " .. pkg_version)
local app_dir = "/app" local install_dir
if not fs.exists(app_dir) then if meta.type and meta.type == "api" then
fs.makeDir(app_dir) install_dir = "/leonos/apis"
else
install_dir = "/app" -- 默认安装到app目录
end
-- 确保安装目录存在
if not fs.exists(install_dir) then
fs.makeDir(install_dir)
end end
local success_count = 0 local success_count = 0
local fail_count = 0 local fail_count = 0
for _, file_path in ipairs(meta.files or {}) do for _, file_path in ipairs(meta.files or {}) do
local dest = fs.combine(app_dir, file_path) local dest = fs.combine(install_dir, file_path)
if download_github_package_file(repo_path, file_path, dest) then if download_github_package_file(repo_path, file_path, dest) then
print("Installed: " .. file_path) print("Installed: " .. file_path)
@@ -386,17 +394,23 @@ local function install_package(pkg_name, options)
return false return false
end end
-- 安装文件 -- 根据package类型确定安装目录
print("Installing version: " .. latest_version) print("Installing version: " .. latest_version)
-- 确保app目录存在 local install_dir
local app_dir = "/app" if meta.type and meta.type == "api" then
if not fs.exists(app_dir) then install_dir = "/leonos/apis"
fs.makeDir(app_dir) else
install_dir = "/app" -- 默认安装到app目录
end
-- 确保安装目录存在
if not fs.exists(install_dir) then
fs.makeDir(install_dir)
end end
for _, file_path in ipairs(meta.files or {}) do for _, file_path in ipairs(meta.files or {}) do
local src = fs.combine(version_path, file_path) local src = fs.combine(version_path, file_path)
local dest = fs.combine(app_dir, file_path) local dest = fs.combine(install_dir, file_path)
-- 确保目标目录存在 -- 确保目标目录存在
local dest_dir = fs.getDir(dest) local dest_dir = fs.getDir(dest)
@@ -508,9 +522,14 @@ local function remove_package(pkg_name)
file:close() file:close()
local ok, meta = pcall(textutils.unserializeJSON, meta_content) local ok, meta = pcall(textutils.unserializeJSON, meta_content)
if ok and meta then if ok and meta then
-- 除包文件 -- 除包文件
for _, file_path in ipairs(meta.files or {}) do for _, file_path in ipairs(meta.files or {}) do
local dest = fs.combine("/rom", file_path) local dest
if meta.type and meta.type == "api" then
dest = fs.combine("/leonos/apis", file_path)
else
dest = fs.combine("/app", file_path)
end
if fs.exists(dest) then if fs.exists(dest) then
fs.delete(dest) fs.delete(dest)
print("Removed: " .. file_path) print("Removed: " .. file_path)

View File

@@ -1,5 +1,5 @@
-- LeonOS installer -- LeonOS installer
local INSTALLER_VERSION = "1.0.3 Beta 1" local INSTALLER_VERSION = "1.0.3 Beta 2"
local DEFAULT_ROM_DIR = "/leonos" local DEFAULT_ROM_DIR = "/leonos"
print("Start loading LeonOS installer ("..INSTALLER_VERSION..")...") print("Start loading LeonOS installer ("..INSTALLER_VERSION..")...")
@@ -69,25 +69,28 @@ term.write("[Installer] Loading done.\n")
local term = require("term") local term = require("term")
local colors = require("colors") local colors = require("colors")
local rc = require("rc") local rc = require("rc")
-- 保存当前颜色设置 local appgui = require("appgui")
local old_fg = term.getTextColor() -- -- 保存当前颜色设置
local old_bg = term.getBackgroundColor() -- local old_fg = term.getTextColor()
-- local old_bg = term.getBackgroundColor()
-- 设置名称栏颜色并显示 -- -- 设置名称栏颜色并显示
term.setTextColor(colors.white) -- term.setTextColor(colors.white)
term.setBackgroundColor(colors.cyan) -- term.setBackgroundColor(colors.cyan)
term.at(1, 1).clearLine() -- term.at(1, 1).clearLine()
term.at(1, 1).write("=== LeonOS Installer ===") -- term.at(1, 1).write("=== LeonOS Installer ===")
-- -- 恢复颜色设置
-- term.setTextColor(old_fg)
-- term.setBackgroundColor(old_bg)
-- term.at(1, 2)
-- -- 只清除顶栏以下的区域
-- for y=2, term.getSize() do
-- term.at(1, y).clearLine()
-- end
-- term.at(1, 2)
appgui.topbar("=== LeonOS Installer ===")
-- 恢复颜色设置
term.setTextColor(old_fg)
term.setBackgroundColor(old_bg)
term.at(1, 2)
-- 只清除顶栏以下的区域
for y=2, term.getSize() do
term.at(1, y).clearLine()
end
term.at(1, 2)
tu.coloredPrint(colors.yellow, tu.coloredPrint(colors.yellow,
"LeonOS Installer (v"..INSTALLER_VERSION..")\n=======================") "LeonOS Installer (v"..INSTALLER_VERSION..")\n=======================")
tu.coloredPrint("You are going to install LeonOS "..INSTALLER_VERSION.." to your computer.") tu.coloredPrint("You are going to install LeonOS "..INSTALLER_VERSION.." to your computer.")
@@ -96,10 +99,13 @@ tu.coloredPrint("If you want to keep the existing files, please backup them firs
tu.coloredPrint(colors.yellow, "Are you sure? (y/n)") tu.coloredPrint(colors.yellow, "Are you sure? (y/n)")
local confirm = read() local confirm = read()
if confirm ~= "y" then if confirm ~= "y" then
term.at(1, y).clearLine()
print("Installation cancelled.") print("Installation cancelled.")
return return
end end
for y=2, term.getSize() do
term.at(1, y).clearLine()
end
local ROM_DIR local ROM_DIR
-- tu.coloredPrint("Enter installation directory ", colors.yellow, "[", -- tu.coloredPrint("Enter installation directory ", colors.yellow, "[",
-- colors.lightBlue, DEFAULT_ROM_DIR, colors.yellow, "]") -- colors.lightBlue, DEFAULT_ROM_DIR, colors.yellow, "]")
@@ -200,7 +206,10 @@ assert(io.open(
"https://gh.catmak.name/https://raw.githubusercontent.com/CCLeonOS/LeonOS/refs/heads/main/unbios.lua" "https://gh.catmak.name/https://raw.githubusercontent.com/CCLeonOS/LeonOS/refs/heads/main/unbios.lua"
)):close() )):close()
ok() ok()
os.sleep(0.5)
for y=2, term.getSize() do
term.at(1, y).clearLine()
end
tu.coloredPrint(colors.yellow, "Your computer will restart in 3 seconds.") tu.coloredPrint(colors.yellow, "Your computer will restart in 3 seconds.")
local _, y = term.getCursorPos() local _, y = term.getCursorPos()