Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local event = require("event")
- local gpu = component.gpu
- local computer = require("computer")
- local filesystem = require("filesystem")
- local unicode = require("unicode")
- local term = require("term")
- -- Screen and buffer setup
- local screenWidth, screenHeight = gpu.getResolution()
- -- Nexium OS configuration
- local Nexium = {
- version = "1.6",
- running = true,
- windows = {},
- activeWindow = nil,
- minimizedWindows = {},
- startMenu = {x = 1, y = screenHeight - 10, width = 20, height = 10, dragging = false, dragOffsetX = 0, dragOffsetY = 0},
- taskbar = {height = 1},
- desktop = {icons = {}},
- background = {color = 0x000040, pattern = "."},
- contextMenu = {visible = false, x = 1, y = 1, width = 20, height = 5, items = {}},
- }
- local backBuffer = {}
- local frontBuffer = {}
- local showDesktopIcons = false
- -- Initialize buffers
- local function initializeBuffers()
- for y = 1, screenHeight do
- backBuffer[y], frontBuffer[y] = {}, {}
- for x = 1, screenWidth do
- backBuffer[y][x] = {char = " ", fg = 0xFFFFFF, bg = Nexium.background.color}
- frontBuffer[y][x] = {char = " ", fg = 0xFFFFFF, bg = Nexium.background.color}
- end
- end
- end
- -- Clean the screen
- local function cleanScreen()
- gpu.setBackground(Nexium.background.color)
- gpu.setForeground(0xFFFFFF)
- gpu.fill(1, 1, screenWidth, screenHeight, " ")
- initializeBuffers()
- end
- -- Draw to back buffer
- local function drawToBuffer(x, y, char, fg, bg)
- if x >= 1 and x <= screenWidth and y >= 1 and y <= screenHeight then
- backBuffer[y][x] = {char = char, fg = fg, bg = bg}
- end
- end
- -- Efficient buffer swap and screen update
- local function swapBuffers()
- local updates = {}
- for y = 1, screenHeight do
- for x = 1, screenWidth do
- if backBuffer[y][x].char ~= frontBuffer[y][x].char or
- backBuffer[y][x].fg ~= frontBuffer[y][x].fg or
- backBuffer[y][x].bg ~= frontBuffer[y][x].bg then
- table.insert(updates, {x, y, backBuffer[y][x].char, backBuffer[y][x].fg, backBuffer[y][x].bg})
- frontBuffer[y][x] = {char = backBuffer[y][x].char, fg = backBuffer[y][x].fg, bg = backBuffer[y][x].bg}
- end
- end
- end
- if #updates > 0 then
- gpu.setBackground(updates[1][5])
- gpu.setForeground(updates[1][4])
- for _, update in ipairs(updates) do
- if update[4] ~= gpu.getForeground() then gpu.setForeground(update[4]) end
- if update[5] ~= gpu.getBackground() then gpu.setBackground(update[5]) end
- gpu.set(update[1], update[2], update[3])
- end
- end
- end
- -- Draw text to buffer
- local function drawText(x, y, text, fg, bg)
- if not (x and y and text and fg and bg) then return end
- for i = 1, unicode.len(text) do
- local char = unicode.sub(text, i, i)
- if x + i - 1 <= screenWidth then
- drawToBuffer(x + i - 1, y, char, fg, bg)
- else
- break
- end
- end
- end
- -- Draw rectangle to buffer
- local function drawRect(x, y, width, height, fg, bg)
- for dy = 0, height - 1 do
- for dx = 0, width - 1 do
- drawToBuffer(x + dx, y + dy, " ", fg, bg)
- end
- end
- end
- -- Window class
- local Window = {}
- Window.__index = Window
- function Window.new(title, x, y, width, height, program)
- local self = setmetatable({}, Window)
- self.title = title
- self.x = x
- self.y = y
- self.width = width
- self.height = height
- self.content = {}
- self.dragging = false
- self.resizing = false
- self.dragOffsetX = 0
- self.dragOffsetY = 0
- self.minimized = false
- self.maximized = false
- self.oldDimensions = {}
- self.program = program
- if self.program then
- self.program.window = self
- if self.program.init then
- self.program.init()
- end
- end
- return self
- end
- function Window:draw()
- if self.minimized then return end
- drawRect(self.x, self.y, self.width, self.height, 0xFFFFFF, 0x000000)
- drawRect(self.x, self.y, self.width, 1, 0xFFFFFF, 0x0000FF)
- drawText(self.x + 1, self.y, self.title, 0xFFFFFF, 0x0000FF)
- drawText(self.x + self.width - 3, self.y, "x", 0xFFFFFF, 0xFF0000)
- drawText(self.x + self.width - 5, self.y, "-", 0xFFFFFF, 0x00FF00)
- drawText(self.x + self.width - 7, self.y, "+", 0xFFFFFF, 0x0000FF)
- drawText(self.x + self.width - 1, self.y + self.height - 1, "▟", 0xFFFFFF, 0x000000)
- if self.program and self.program.draw then
- self.program.draw()
- else
- for i, line in ipairs(self.content) do
- drawText(self.x + 1, self.y + i, line, 0xFFFFFF, 0x000000)
- end
- end
- end
- function Window:handleEvent(e)
- if self.minimized then return false end
- if e[1] == "touch" then
- local x, y = e[3], e[4]
- if y == self.y and x >= self.x and x < self.x + self.width then
- if x == self.x + self.width - 1 then
- return "close"
- elseif x == self.x + self.width - 3 then
- self.minimized = true
- return "minimize"
- elseif x == self.x + self.width - 5 then
- if self.maximized then
- self.x, self.y, self.width, self.height = table.unpack(self.oldDimensions)
- else
- self.oldDimensions = {self.x, self.y, self.width, self.height}
- self.x, self.y = 1, 2
- self.width, self.height = screenWidth, screenHeight - 2
- end
- self.maximized = not self.maximized
- return "maximize"
- else
- self.dragging = true
- self.dragOffsetX = x - self.x
- self.dragOffsetY = y - self.y
- end
- elseif x == self.x + self.width - 1 and y == self.y + self.height - 1 then
- self.resizing = true
- self.dragOffsetX = self.width - 1
- self.dragOffsetY = self.height - 1
- elseif y > self.y and y < self.y + self.height and x >= self.x and x < self.x + self.width then
- if self.program and self.program.handleEvent then
- return self.program.handleEvent(e)
- end
- end
- elseif e[1] == "drag" then
- if self.dragging then
- self.x = math.max(1, math.min(screenWidth - self.width, e[3] - self.dragOffsetX))
- self.y = math.max(2, math.min(screenHeight - self.height, e[4] - self.dragOffsetY))
- elseif self.resizing then
- self.width = math.max(10, math.min(screenWidth - self.x + 1, e[3] - self.x + 1))
- self.height = math.max(5, math.min(screenHeight - self.y + 1, e[4] - self.y + 1))
- end
- elseif e[1] == "drop" then
- self.dragging = false
- self.resizing = false
- elseif self.program and self.program.handleEvent then
- return self.program.handleEvent(e)
- end
- return false
- end
- -- Program implementations
- local programs = {}
- -- Terminal
- programs.terminal = function()
- local program = {}
- local history = {}
- local command = ""
- local function updateContent()
- local win = program.window
- win.content = {}
- for i = math.max(1, #history - win.height + 3), #history do
- table.insert(win.content, history[i] or "")
- end
- table.insert(win.content, "> " .. command)
- end
- local function writeOutput(text)
- for line in text:gmatch("[^\n]+") do
- table.insert(history, line)
- end
- while #history > 1000 do
- table.remove(history, 1)
- end
- updateContent()
- end
- local function executeCommand(cmd)
- local func, err = load("return " .. cmd, "=stdin", "t", _G)
- if not func then
- func, err = load(cmd, "=stdin", "t", _G)
- end
- if not func then
- writeOutput("Error: " .. tostring(err))
- else
- local result = table.pack(xpcall(func, debug.traceback))
- if not result[1] then
- writeOutput("Error: " .. tostring(result[2]))
- else
- for i = 2, result.n do
- writeOutput(tostring(result[i]))
- end
- end
- end
- end
- function program.init()
- writeOutput("Welcome to Nexium Terminal (Basic OpenOS compatibility)")
- writeOutput("Type 'help()' for available commands")
- updateContent()
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- if e[4] == 28 then -- Enter key
- writeOutput("> " .. command)
- executeCommand(command)
- command = ""
- elseif e[4] == 14 then -- Backspace
- command = unicode.sub(command, 1, -2)
- else
- local char = unicode.char(e[3])
- if char:match("%g") or char == " " then
- command = command .. char
- end
- end
- updateContent()
- return true
- end
- return false
- end
- return program
- end
- -- Lua Script Runner
- programs.luaRunner = function(filePath)
- local component = require("component")
- local computer = require("computer")
- local unicode = require("unicode")
- local program = {}
- local virtualScreen = {}
- local virtualGPU = {}
- local scrollPosition = 0
- local inputBuffer = ""
- local isWaitingForInput = false
- local inputCallback = nil
- local needsRedraw = true
- -- Initialize virtual screen (larger size)
- local vScreenWidth, vScreenHeight = 160, 50 -- Even larger size
- for y = 1, vScreenHeight do
- virtualScreen[y] = {}
- for x = 1, vScreenWidth do
- virtualScreen[y][x] = {char = " ", fg = 0xFFFFFF, bg = 0x000000}
- end
- end
- -- Create virtual GPU functions
- local currentFG, currentBG = 0xFFFFFF, 0x000000
- local currentDepth = 4 -- Assume 4-bit color depth
- local function createProxy(target)
- return setmetatable({}, {
- __index = function(_, key)
- if type(target[key]) == "function" then
- return function(...)
- local result = target[key](...)
- needsRedraw = true
- return result
- end
- else
- return target[key]
- end
- end
- })
- end
- virtualGPU.setBackground = function(color, isPaletteIndex)
- currentBG = color
- needsRedraw = true
- return true
- end
- virtualGPU.setForeground = function(color, isPaletteIndex)
- currentFG = color
- needsRedraw = true
- return true
- end
- virtualGPU.set = function(x, y, text, vertical)
- if y >= 1 and y <= vScreenHeight then
- if vertical then
- for i = 1, math.min(unicode.len(text), vScreenHeight - y + 1) do
- local char = unicode.sub(text, i, i)
- if x >= 1 and x <= vScreenWidth then
- virtualScreen[y + i - 1][x] = {char = char, fg = currentFG, bg = currentBG}
- end
- end
- else
- for i = 1, math.min(unicode.len(text), vScreenWidth - x + 1) do
- local char = unicode.sub(text, i, i)
- virtualScreen[y][x + i - 1] = {char = char, fg = currentFG, bg = currentBG}
- end
- end
- end
- needsRedraw = true
- return true
- end
- virtualGPU.fill = function(x, y, w, h, char)
- char = unicode.sub(char or " ", 1, 1)
- for dy = 0, h - 1 do
- for dx = 0, w - 1 do
- if y + dy >= 1 and y + dy <= vScreenHeight and x + dx >= 1 and x + dx <= vScreenWidth then
- virtualScreen[y + dy][x + dx] = {char = char, fg = currentFG, bg = currentBG}
- end
- end
- end
- needsRedraw = true
- return true
- end
- virtualGPU.copy = function(x, y, w, h, tx, ty)
- local tempScreen = {}
- for dy = 0, h - 1 do
- tempScreen[dy + 1] = {}
- for dx = 0, w - 1 do
- if y + dy >= 1 and y + dy <= vScreenHeight and x + dx >= 1 and x + dx <= vScreenWidth then
- tempScreen[dy + 1][dx + 1] = virtualScreen[y + dy][x + dx]
- end
- end
- end
- for dy = 0, h - 1 do
- for dx = 0, w - 1 do
- if ty + dy >= 1 and ty + dy <= vScreenHeight and tx + dx >= 1 and tx + dx <= vScreenWidth then
- virtualScreen[ty + dy][tx + dx] = tempScreen[dy + 1][dx + 1] or {char = " ", fg = currentFG, bg = currentBG}
- end
- end
- end
- needsRedraw = true
- return true
- end
- virtualGPU.getResolution = function() return vScreenWidth, vScreenHeight end
- virtualGPU.setResolution = function(width, height) return true end -- Ignore resolution changes
- virtualGPU.maxResolution = function() return vScreenWidth, vScreenHeight end
- virtualGPU.getDepth = function() return currentDepth end
- virtualGPU.setDepth = function(depth) currentDepth = depth; return true end
- virtualGPU.maxDepth = function() return 8 end
- virtualGPU.getBackground = function() return currentBG end
- virtualGPU.getForeground = function() return currentFG end
- virtualGPU.getPaletteColor = function(index) return 0 end -- Dummy palette
- virtualGPU.setPaletteColor = function(index, color) return true end -- Ignore palette changes
- virtualGPU.getScreen = function() return {} end -- Dummy screen
- virtualGPU.getViewport = function() return 1, 1, vScreenWidth, vScreenHeight end
- virtualGPU.setViewport = function(x, y, width, height) return true end -- Ignore viewport changes
- virtualGPU.bind = function(address) return true end -- Dummy bind function
- local function handleInput()
- if inputCallback then
- inputCallback(inputBuffer)
- inputBuffer = ""
- isWaitingForInput = false
- inputCallback = nil
- end
- end
- function program.init()
- local file, err = io.open(filePath, "r")
- if not file then
- virtualGPU.set(1, 1, "Error opening file: " .. tostring(err))
- return
- end
- local content = file:read("*all")
- file:close()
- local env = setmetatable({}, {__index = _G})
- env.component = setmetatable({}, {
- __index = function(_, key)
- if key == "gpu" then
- return createProxy(virtualGPU)
- elseif key == "list" then
- return function() return {"gpu"} end
- else
- return component[key]
- end
- end
- })
- env.computer = createProxy(computer)
- env.gpu = createProxy(virtualGPU)
- env.print = function(...)
- local args = {...}
- local text = table.concat(args, "\t")
- for i, line in ipairs(text:gmatch("[^\n]+")) do
- virtualGPU.set(1, i, line)
- end
- end
- env.io = {
- write = function(...)
- local args = {...}
- local text = table.concat(args)
- virtualGPU.set(1, 1, text)
- end,
- read = function(...)
- isWaitingForInput = true
- local co = coroutine.running()
- inputCallback = function(input)
- coroutine.resume(co, input)
- end
- return coroutine.yield()
- end
- }
- local func, err = load(content, "=" .. filePath, "t", env)
- if not func then
- virtualGPU.set(1, 1, "Error loading script: " .. tostring(err))
- return
- end
- local co = coroutine.create(func)
- local function resume()
- local success, result = coroutine.resume(co)
- if not success then
- virtualGPU.set(1, vScreenHeight, "Error: " .. tostring(result))
- elseif coroutine.status(co) ~= "dead" then
- -- Schedule the next resume
- computer.pushSignal("lua_runner_continue")
- end
- needsRedraw = true
- end
- -- Start the coroutine
- resume()
- -- Set up a handler for continuing the script
- event.listen("lua_runner_continue", resume)
- end
- function program.draw()
- if needsRedraw then
- local win = program.window
- for y = 1, math.min(win.height - 2, vScreenHeight) do
- for x = 1, math.min(win.width - 2, vScreenWidth) do
- local vChar = virtualScreen[y + scrollPosition] and virtualScreen[y + scrollPosition][x] or {char = " ", fg = 0xFFFFFF, bg = 0x000000}
- if win.x and win.y and vChar.char and vChar.fg and vChar.bg then
- drawText(win.x + x, win.y + y, vChar.char, vChar.fg, vChar.bg)
- end
- end
- end
- -- Draw input line
- if win.x and win.y and win.width then
- drawText(win.x + 1, win.y + win.height - 1, string.rep("-", win.width - 2), 0xFFFFFF, 0x000000)
- local inputText = isWaitingForInput and ("> " .. inputBuffer) or ""
- drawText(win.x + 1, win.y + win.height, inputText, 0xFFFFFF, 0x000000)
- end
- needsRedraw = false
- end
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- if isWaitingForInput then
- if e[4] == 28 then -- Enter key
- handleInput()
- elseif e[4] == 14 then -- Backspace
- inputBuffer = unicode.sub(inputBuffer, 1, -2)
- else
- local char = unicode.char(e[3])
- if char:match("%g") or char == " " then
- inputBuffer = inputBuffer .. char
- end
- end
- else
- if e[4] == 200 then -- Up arrow
- scrollPosition = math.max(0, scrollPosition - 1)
- elseif e[4] == 208 then -- Down arrow
- scrollPosition = math.min(vScreenHeight - (program.window.height - 3), scrollPosition + 1)
- end
- end
- needsRedraw = true
- return true
- end
- return false
- end
- return program
- end
- -- File Explorer
- programs.fileExplorer = function()
- local program = {}
- local currentPath = "/"
- local files = {}
- local selectedFile = 1
- local function updateFileList()
- files = {}
- for file in filesystem.list(currentPath) do
- table.insert(files, file)
- end
- table.sort(files)
- end
- local function updateContent()
- local win = program.window
- win.content = {"Current path: " .. currentPath, ""}
- for i, file in ipairs(files) do
- local prefix = i == selectedFile and "> " or " "
- table.insert(win.content, prefix .. file)
- end
- end
- function program.init()
- updateFileList()
- updateContent()
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- if e[4] == 200 then -- Up arrow
- selectedFile = math.max(1, selectedFile - 1)
- elseif e[4] == 208 then -- Down arrow
- selectedFile = math.min(#files, selectedFile + 1)
- elseif e[4] == 28 then -- Enter
- local selected = files[selectedFile]
- if selected then
- local fullPath = filesystem.concat(currentPath, selected)
- if filesystem.isDirectory(fullPath) then
- currentPath = fullPath
- updateFileList()
- selectedFile = 1
- else
- -- Check if it's a .lua file
- if selected:match("%.lua$") then
- local luaRunner = programs.luaRunner(fullPath)
- -- Create a larger window for the Lua Runner
- table.insert(Nexium.windows, Window.new("Lua: " .. selected, 1, 1, screenWidth, screenHeight - 1, luaRunner))
- else
- -- Handle other file types or show an error
- computer.beep(1000, 0.2)
- end
- end
- end
- elseif e[4] == 14 then -- Backspace
- currentPath = filesystem.path(currentPath) or "/"
- updateFileList()
- selectedFile = 1
- end
- updateContent()
- return true
- end
- return false
- end
- return program
- end
- -- Settings
- programs.settings = function()
- local program = {}
- local settings = {
- {"Background Color", Nexium.background.color},
- {"Background Pattern", Nexium.background.pattern},
- {"Show Desktop Icons", showDesktopIcons},
- }
- local selectedSetting = 1
- local function updateContent()
- local win = program.window
- win.content = {"Nexium OS Settings", ""}
- for i, setting in ipairs(settings) do
- local prefix = i == selectedSetting and "> " or " "
- table.insert(win.content, prefix .. setting[1] .. ": " .. tostring(setting[2]))
- end
- end
- function program.init()
- updateContent()
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- if e[4] == 200 then -- Up arrow
- selectedSetting = math.max(1, selectedSetting - 1)
- elseif e[4] == 208 then -- Down arrow
- selectedSetting = math.min(#settings, selectedSetting + 1)
- elseif e[4] == 28 then -- Enter
- -- Toggle or cycle through options
- if selectedSetting == 1 then
- settings[1][2] = settings[1][2] == 0x000040 and 0x004000 or 0x000040
- Nexium.background.color = settings[1][2]
- elseif selectedSetting == 2 then
- settings[2][2] = settings[2][2] == "." and "*" or "."
- Nexium.background.pattern = settings[2][2]
- elseif selectedSetting == 3 then
- settings[3][2] = not settings[3][2]
- showDesktopIcons = settings[3][2]
- end
- end
- updateContent()
- return true
- end
- return false
- end
- return program
- end
- -- About
- programs.about = function()
- local program = {}
- function program.init()
- local win = program.window
- local totalMemory = computer.totalMemory()
- local freeMemory = computer.freeMemory()
- win.content = {
- "Nexium OS v" .. Nexium.version,
- "",
- "System Information:",
- "Total Memory: " .. math.floor(totalMemory / 1024) .. " KB",
- "Free Memory: " .. math.floor(freeMemory / 1024) .. " KB",
- "Used Memory: " .. math.floor((totalMemory - freeMemory) / 1024) .. " KB",
- "Uptime: " .. math.floor(computer.uptime()) .. " seconds",
- "",
- "Press any key to close"
- }
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- return "close"
- end
- return false
- end
- return program
- end
- -- Task Manager
- programs.taskManager = function()
- local program = {}
- local selectedTask = 1
- local updateInterval = 1 -- Update performance metrics every second
- local lastUpdate = 0
- local lastUsedMemory = 0
- local memoryDelta = 0
- local function getPerformanceMetrics()
- local totalMemory = computer.totalMemory()
- local freeMemory = computer.freeMemory()
- local usedMemory = totalMemory - freeMemory
- local memoryUsage = math.floor((usedMemory / totalMemory) * 100)
- -- Calculate memory usage change
- memoryDelta = usedMemory - lastUsedMemory
- lastUsedMemory = usedMemory
- -- Calculate a pseudo "activity" percentage based on memory changes
- local activity = math.min(100, math.abs(memoryDelta) / 1024) -- 1 KB change = 1% activity, max 100%
- return {
- activity = math.floor(activity),
- memory = memoryUsage,
- totalMemory = math.floor(totalMemory / 1024),
- freeMemory = math.floor(freeMemory / 1024),
- uptime = math.floor(computer.uptime())
- }
- end
- local function updateContent()
- local win = program.window
- local metrics = getPerformanceMetrics()
- win.content = {
- "Task Manager",
- string.format("System Activity: %d%%", metrics.activity),
- string.format("Memory Usage: %d%% (%d KB / %d KB)", metrics.memory, metrics.totalMemory - metrics.freeMemory, metrics.totalMemory),
- string.format("Uptime: %d seconds", metrics.uptime),
- ""
- }
- for i, window in ipairs(Nexium.windows) do
- local prefix = i == selectedTask and "> " or " "
- table.insert(win.content, prefix .. window.title)
- end
- table.insert(win.content, "")
- table.insert(win.content, "Press Enter to close selected task")
- table.insert(win.content, "Press Esc to exit Task Manager")
- end
- function program.init()
- updateContent()
- end
- function program.draw()
- local currentTime = computer.uptime()
- if currentTime - lastUpdate >= updateInterval then
- updateContent()
- lastUpdate = currentTime
- end
- for i, line in ipairs(program.window.content) do
- drawText(program.window.x + 1, program.window.y + i, line, 0xFFFFFF, 0x000000)
- end
- end
- function program.handleEvent(e)
- if e[1] == "key_down" then
- if e[4] == 200 then -- Up arrow
- selectedTask = math.max(1, selectedTask - 1)
- elseif e[4] == 208 then -- Down arrow
- selectedTask = math.min(#Nexium.windows, selectedTask + 1)
- elseif e[4] == 28 then -- Enter
- if Nexium.windows[selectedTask] then
- table.remove(Nexium.windows, selectedTask)
- selectedTask = math.min(selectedTask, #Nexium.windows)
- end
- elseif e[4] == 1 then -- Esc
- return "close"
- end
- updateContent()
- return true
- end
- return false
- end
- return program
- end
- -- Desktop icons
- local function initializeDesktopIcons()
- Nexium.desktop.icons = {
- {name = "Terminal", x = 2, y = 2, program = programs.terminal},
- {name = "File Explorer", x = 2, y = 4, program = programs.fileExplorer},
- {name = "Settings", x = 2, y = 6, program = programs.settings},
- {name = "About", x = 2, y = 8, program = programs.about},
- {name = "Task Manager", x = 2, y = 10, program = programs.taskManager},
- }
- end
- -- Draw desktop icons
- local function drawDesktopIcons()
- if showDesktopIcons then
- for _, icon in ipairs(Nexium.desktop.icons) do
- drawText(icon.x, icon.y, icon.name, 0xFFFFFF, Nexium.background.color)
- end
- end
- end
- -- Draw start menu
- local function drawStartMenu()
- drawRect(Nexium.startMenu.x, Nexium.startMenu.y, Nexium.startMenu.width, Nexium.startMenu.height, 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y, "Nexium Start Menu", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 2, "1. Terminal", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 3, "2. File Explorer", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 4, "3. Settings", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 5, "4. About", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 6, "5. Task Manager", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 7, "6. Toggle Desktop Icons", 0xFFFFFF, 0x0000FF)
- drawText(Nexium.startMenu.x, Nexium.startMenu.y + 8, "7. Shutdown", 0xFFFFFF, 0x0000FF)
- end
- -- Draw taskbar
- local function drawTaskbar()
- drawRect(1, screenHeight, screenWidth, 1, 0xFFFFFF, 0x000000)
- local x = 1
- for i, win in ipairs(Nexium.windows) do
- local title = unicode.sub(win.title, 1, 10)
- drawText(x, screenHeight, title, win.minimized and 0x808080 or 0xFFFFFF, 0x000000)
- x = x + #title + 2
- end
- end
- -- Handle events
- local function handleEvents()
- local e = {event.pull(0.05)}
- if e[1] == "touch" then
- local x, y = e[3], e[4]
- if y >= Nexium.startMenu.y and y < Nexium.startMenu.y + Nexium.startMenu.height and
- x >= Nexium.startMenu.x and x < Nexium.startMenu.x + Nexium.startMenu.width then
- -- Start menu interaction
- local option = y - Nexium.startMenu.y
- if option == 2 then
- table.insert(Nexium.windows, Window.new("Terminal", 10, 5, 60, 20, programs.terminal()))
- elseif option == 3 then
- table.insert(Nexium.windows, Window.new("File Explorer", 10, 5, 50, 15, programs.fileExplorer()))
- elseif option == 4 then
- table.insert(Nexium.windows, Window.new("Settings", 15, 5, 40, 12, programs.settings()))
- elseif option == 5 then
- table.insert(Nexium.windows, Window.new("About", 20, 5, 40, 12, programs.about()))
- elseif option == 6 then
- table.insert(Nexium.windows, Window.new("Task Manager", 25, 5, 50, 15, programs.taskManager()))
- elseif option == 7 then
- showDesktopIcons = not showDesktopIcons
- elseif option == 8 then
- Nexium.running = false
- else
- -- Start dragging the start menu
- Nexium.startMenu.dragging = true
- Nexium.startMenu.dragOffsetX = x - Nexium.startMenu.x
- Nexium.startMenu.dragOffsetY = y - Nexium.startMenu.y
- end
- elseif y == screenHeight then
- -- Taskbar click
- local buttonX = 1
- for i, win in ipairs(Nexium.windows) do
- local buttonWidth = #win.title + 2
- if x >= buttonX and x < buttonX + buttonWidth then
- win.minimized = not win.minimized
- break
- end
- buttonX = buttonX + buttonWidth
- end
- else
- -- Check desktop icons
- if showDesktopIcons then
- for _, icon in ipairs(Nexium.desktop.icons) do
- if x >= icon.x and x < icon.x + #icon.name and y == icon.y then
- table.insert(Nexium.windows, Window.new(icon.name, 10, 5, 60, 20, icon.program()))
- return
- end
- end
- end
- -- Check windows
- for i = #Nexium.windows, 1, -1 do
- local result = Nexium.windows[i]:handleEvent(e)
- if result then
- if result == "close" then
- table.remove(Nexium.windows, i)
- elseif result == "minimize" then
- -- Already handled in Window:handleEvent
- elseif result == "maximize" then
- -- Already handled in Window:handleEvent
- else
- -- Move window to top
- local win = table.remove(Nexium.windows, i)
- table.insert(Nexium.windows, win)
- end
- return
- end
- end
- end
- elseif e[1] == "drag" then
- if Nexium.startMenu.dragging then
- Nexium.startMenu.x = math.max(1, math.min(screenWidth - Nexium.startMenu.width, e[3] - Nexium.startMenu.dragOffsetX))
- Nexium.startMenu.y = math.max(1, math.min(screenHeight - Nexium.startMenu.height, e[4] - Nexium.startMenu.dragOffsetY))
- else
- for _, win in ipairs(Nexium.windows) do
- win:handleEvent(e)
- end
- end
- elseif e[1] == "drop" then
- Nexium.startMenu.dragging = false
- for _, win in ipairs(Nexium.windows) do
- win:handleEvent(e)
- end
- elseif e[1] == "key_down" then
- -- Pass key events to the active window
- if #Nexium.windows > 0 then
- Nexium.windows[#Nexium.windows]:handleEvent(e)
- end
- end
- end
- -- Main loop
- local function main()
- initializeDesktopIcons()
- while Nexium.running do
- -- Clear back buffer
- for y = 1, screenHeight do
- for x = 1, screenWidth do
- backBuffer[y][x] = {char = Nexium.background.pattern, fg = 0xFFFFFF, bg = Nexium.background.color}
- end
- end
- drawDesktopIcons()
- for _, win in ipairs(Nexium.windows) do
- win:draw()
- end
- drawTaskbar()
- drawStartMenu()
- handleEvents()
- swapBuffers()
- end
- end
- -- Add some basic commands for the terminal
- _G.help = function()
- return [[
- Available commands:
- - help(): Show this help message
- - print(...): Print arguments
- - math functions (sin, cos, tan, etc.)
- - string functions (len, sub, etc.)
- - table functions (insert, remove, etc.)
- - os.exit(): Exit Nexium OS
- ]]
- end
- _G.os = _G.os or {}
- _G.os.exit = function()
- Nexium.running = false
- end
- -- Start the OS
- print("Starting Nexium OS...")
- cleanScreen()
- main()
- cleanScreen()
- print("Nexium OS has shut down.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement