Advertisement
nonogamer9

Nexium OS : An OpenComputers Operating System With Real Multitasking

Aug 22nd, 2024 (edited)
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.23 KB | Software | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local gpu = component.gpu
  4. local computer = require("computer")
  5. local filesystem = require("filesystem")
  6. local unicode = require("unicode")
  7. local term = require("term")
  8.  
  9. -- Screen and buffer setup
  10. local screenWidth, screenHeight = gpu.getResolution()
  11.  
  12. -- Nexium OS configuration
  13. local Nexium = {
  14.   version = "1.6",
  15.   running = true,
  16.   windows = {},
  17.   activeWindow = nil,
  18.   minimizedWindows = {},
  19.   startMenu = {x = 1, y = screenHeight - 10, width = 20, height = 10, dragging = false, dragOffsetX = 0, dragOffsetY = 0},
  20.   taskbar = {height = 1},
  21.   desktop = {icons = {}},
  22.   background = {color = 0x000040, pattern = "."},
  23.   contextMenu = {visible = false, x = 1, y = 1, width = 20, height = 5, items = {}},
  24. }
  25.  
  26. local backBuffer = {}
  27. local frontBuffer = {}
  28. local showDesktopIcons = false
  29.  
  30. -- Initialize buffers
  31. local function initializeBuffers()
  32.   for y = 1, screenHeight do
  33.     backBuffer[y], frontBuffer[y] = {}, {}
  34.     for x = 1, screenWidth do
  35.       backBuffer[y][x] = {char = " ", fg = 0xFFFFFF, bg = Nexium.background.color}
  36.       frontBuffer[y][x] = {char = " ", fg = 0xFFFFFF, bg = Nexium.background.color}
  37.     end
  38.   end
  39. end
  40.  
  41. -- Clean the screen
  42. local function cleanScreen()
  43.   gpu.setBackground(Nexium.background.color)
  44.   gpu.setForeground(0xFFFFFF)
  45.   gpu.fill(1, 1, screenWidth, screenHeight, " ")
  46.   initializeBuffers()
  47. end
  48.  
  49. -- Draw to back buffer
  50. local function drawToBuffer(x, y, char, fg, bg)
  51.   if x >= 1 and x <= screenWidth and y >= 1 and y <= screenHeight then
  52.     backBuffer[y][x] = {char = char, fg = fg, bg = bg}
  53.   end
  54. end
  55.  
  56. -- Efficient buffer swap and screen update
  57. local function swapBuffers()
  58.   local updates = {}
  59.   for y = 1, screenHeight do
  60.     for x = 1, screenWidth do
  61.       if backBuffer[y][x].char ~= frontBuffer[y][x].char or
  62.          backBuffer[y][x].fg ~= frontBuffer[y][x].fg or
  63.          backBuffer[y][x].bg ~= frontBuffer[y][x].bg then
  64.         table.insert(updates, {x, y, backBuffer[y][x].char, backBuffer[y][x].fg, backBuffer[y][x].bg})
  65.         frontBuffer[y][x] = {char = backBuffer[y][x].char, fg = backBuffer[y][x].fg, bg = backBuffer[y][x].bg}
  66.       end
  67.     end
  68.   end
  69.  
  70.   if #updates > 0 then
  71.     gpu.setBackground(updates[1][5])
  72.     gpu.setForeground(updates[1][4])
  73.     for _, update in ipairs(updates) do
  74.       if update[4] ~= gpu.getForeground() then gpu.setForeground(update[4]) end
  75.       if update[5] ~= gpu.getBackground() then gpu.setBackground(update[5]) end
  76.       gpu.set(update[1], update[2], update[3])
  77.     end
  78.   end
  79. end
  80.  
  81. -- Draw text to buffer
  82. local function drawText(x, y, text, fg, bg)
  83.   if not (x and y and text and fg and bg) then return end
  84.   for i = 1, unicode.len(text) do
  85.     local char = unicode.sub(text, i, i)
  86.     if x + i - 1 <= screenWidth then
  87.       drawToBuffer(x + i - 1, y, char, fg, bg)
  88.     else
  89.       break
  90.     end
  91.   end
  92. end
  93.  
  94. -- Draw rectangle to buffer
  95. local function drawRect(x, y, width, height, fg, bg)
  96.   for dy = 0, height - 1 do
  97.     for dx = 0, width - 1 do
  98.       drawToBuffer(x + dx, y + dy, " ", fg, bg)
  99.     end
  100.   end
  101. end
  102.  
  103. -- Window class
  104. local Window = {}
  105. Window.__index = Window
  106.  
  107. function Window.new(title, x, y, width, height, program)
  108.   local self = setmetatable({}, Window)
  109.   self.title = title
  110.   self.x = x
  111.   self.y = y
  112.   self.width = width
  113.   self.height = height
  114.   self.content = {}
  115.   self.dragging = false
  116.   self.resizing = false
  117.   self.dragOffsetX = 0
  118.   self.dragOffsetY = 0
  119.   self.minimized = false
  120.   self.maximized = false
  121.   self.oldDimensions = {}
  122.   self.program = program
  123.   if self.program then
  124.     self.program.window = self
  125.     if self.program.init then
  126.       self.program.init()
  127.     end
  128.   end
  129.   return self
  130. end
  131.  
  132. function Window:draw()
  133.   if self.minimized then return end
  134.   drawRect(self.x, self.y, self.width, self.height, 0xFFFFFF, 0x000000)
  135.   drawRect(self.x, self.y, self.width, 1, 0xFFFFFF, 0x0000FF)
  136.   drawText(self.x + 1, self.y, self.title, 0xFFFFFF, 0x0000FF)
  137.   drawText(self.x + self.width - 3, self.y, "x", 0xFFFFFF, 0xFF0000)
  138.   drawText(self.x + self.width - 5, self.y, "-", 0xFFFFFF, 0x00FF00)
  139.   drawText(self.x + self.width - 7, self.y, "+", 0xFFFFFF, 0x0000FF)
  140.   drawText(self.x + self.width - 1, self.y + self.height - 1, "▟", 0xFFFFFF, 0x000000)
  141.   if self.program and self.program.draw then
  142.     self.program.draw()
  143.   else
  144.     for i, line in ipairs(self.content) do
  145.       drawText(self.x + 1, self.y + i, line, 0xFFFFFF, 0x000000)
  146.     end
  147.   end
  148. end
  149.  
  150. function Window:handleEvent(e)
  151.   if self.minimized then return false end
  152.   if e[1] == "touch" then
  153.     local x, y = e[3], e[4]
  154.     if y == self.y and x >= self.x and x < self.x + self.width then
  155.       if x == self.x + self.width - 1 then
  156.         return "close"
  157.       elseif x == self.x + self.width - 3 then
  158.         self.minimized = true
  159.         return "minimize"
  160.       elseif x == self.x + self.width - 5 then
  161.         if self.maximized then
  162.           self.x, self.y, self.width, self.height = table.unpack(self.oldDimensions)
  163.         else
  164.           self.oldDimensions = {self.x, self.y, self.width, self.height}
  165.           self.x, self.y = 1, 2
  166.           self.width, self.height = screenWidth, screenHeight - 2
  167.         end
  168.         self.maximized = not self.maximized
  169.         return "maximize"
  170.       else
  171.         self.dragging = true
  172.         self.dragOffsetX = x - self.x
  173.         self.dragOffsetY = y - self.y
  174.       end
  175.     elseif x == self.x + self.width - 1 and y == self.y + self.height - 1 then
  176.       self.resizing = true
  177.       self.dragOffsetX = self.width - 1
  178.       self.dragOffsetY = self.height - 1
  179.     elseif y > self.y and y < self.y + self.height and x >= self.x and x < self.x + self.width then
  180.       if self.program and self.program.handleEvent then
  181.         return self.program.handleEvent(e)
  182.       end
  183.     end
  184.   elseif e[1] == "drag" then
  185.     if self.dragging then
  186.       self.x = math.max(1, math.min(screenWidth - self.width, e[3] - self.dragOffsetX))
  187.       self.y = math.max(2, math.min(screenHeight - self.height, e[4] - self.dragOffsetY))
  188.     elseif self.resizing then
  189.       self.width = math.max(10, math.min(screenWidth - self.x + 1, e[3] - self.x + 1))
  190.       self.height = math.max(5, math.min(screenHeight - self.y + 1, e[4] - self.y + 1))
  191.     end
  192.   elseif e[1] == "drop" then
  193.     self.dragging = false
  194.     self.resizing = false
  195.   elseif self.program and self.program.handleEvent then
  196.     return self.program.handleEvent(e)
  197.   end
  198.   return false
  199. end
  200.  
  201. -- Program implementations
  202. local programs = {}
  203.  
  204. -- Terminal
  205. programs.terminal = function()
  206.   local program = {}
  207.   local history = {}
  208.   local command = ""
  209.  
  210.   local function updateContent()
  211.     local win = program.window
  212.     win.content = {}
  213.     for i = math.max(1, #history - win.height + 3), #history do
  214.       table.insert(win.content, history[i] or "")
  215.     end
  216.     table.insert(win.content, "> " .. command)
  217.   end
  218.  
  219.   local function writeOutput(text)
  220.     for line in text:gmatch("[^\n]+") do
  221.       table.insert(history, line)
  222.     end
  223.     while #history > 1000 do
  224.       table.remove(history, 1)
  225.     end
  226.     updateContent()
  227.   end
  228.  
  229.   local function executeCommand(cmd)
  230.     local func, err = load("return " .. cmd, "=stdin", "t", _G)
  231.     if not func then
  232.       func, err = load(cmd, "=stdin", "t", _G)
  233.     end
  234.     if not func then
  235.       writeOutput("Error: " .. tostring(err))
  236.     else
  237.       local result = table.pack(xpcall(func, debug.traceback))
  238.       if not result[1] then
  239.         writeOutput("Error: " .. tostring(result[2]))
  240.       else
  241.         for i = 2, result.n do
  242.           writeOutput(tostring(result[i]))
  243.         end
  244.       end
  245.     end
  246.   end
  247.  
  248.   function program.init()
  249.     writeOutput("Welcome to Nexium Terminal (Basic OpenOS compatibility)")
  250.     writeOutput("Type 'help()' for available commands")
  251.     updateContent()
  252.   end
  253.  
  254.   function program.handleEvent(e)
  255.     if e[1] == "key_down" then
  256.       if e[4] == 28 then  -- Enter key
  257.         writeOutput("> " .. command)
  258.         executeCommand(command)
  259.         command = ""
  260.       elseif e[4] == 14 then  -- Backspace
  261.         command = unicode.sub(command, 1, -2)
  262.       else
  263.         local char = unicode.char(e[3])
  264.         if char:match("%g") or char == " " then
  265.           command = command .. char
  266.         end
  267.       end
  268.       updateContent()
  269.       return true
  270.     end
  271.     return false
  272.   end
  273.  
  274.   return program
  275. end
  276.  
  277. -- Lua Script Runner
  278. programs.luaRunner = function(filePath)
  279.   local component = require("component")
  280.   local computer = require("computer")
  281.   local unicode = require("unicode")
  282.  
  283.   local program = {}
  284.   local virtualScreen = {}
  285.   local virtualGPU = {}
  286.   local scrollPosition = 0
  287.   local inputBuffer = ""
  288.   local isWaitingForInput = false
  289.   local inputCallback = nil
  290.   local needsRedraw = true
  291.  
  292.   -- Initialize virtual screen (larger size)
  293.   local vScreenWidth, vScreenHeight = 160, 50  -- Even larger size
  294.   for y = 1, vScreenHeight do
  295.     virtualScreen[y] = {}
  296.     for x = 1, vScreenWidth do
  297.       virtualScreen[y][x] = {char = " ", fg = 0xFFFFFF, bg = 0x000000}
  298.     end
  299.   end
  300.  
  301.   -- Create virtual GPU functions
  302.   local currentFG, currentBG = 0xFFFFFF, 0x000000
  303.   local currentDepth = 4  -- Assume 4-bit color depth
  304.  
  305.   local function createProxy(target)
  306.     return setmetatable({}, {
  307.       __index = function(_, key)
  308.         if type(target[key]) == "function" then
  309.           return function(...)
  310.             local result = target[key](...)
  311.             needsRedraw = true
  312.             return result
  313.           end
  314.         else
  315.           return target[key]
  316.         end
  317.       end
  318.     })
  319.   end
  320.  
  321.   virtualGPU.setBackground = function(color, isPaletteIndex)
  322.     currentBG = color
  323.     needsRedraw = true
  324.     return true
  325.   end
  326.  
  327.   virtualGPU.setForeground = function(color, isPaletteIndex)
  328.     currentFG = color
  329.     needsRedraw = true
  330.     return true
  331.   end
  332.  
  333.   virtualGPU.set = function(x, y, text, vertical)
  334.     if y >= 1 and y <= vScreenHeight then
  335.       if vertical then
  336.         for i = 1, math.min(unicode.len(text), vScreenHeight - y + 1) do
  337.           local char = unicode.sub(text, i, i)
  338.           if x >= 1 and x <= vScreenWidth then
  339.             virtualScreen[y + i - 1][x] = {char = char, fg = currentFG, bg = currentBG}
  340.           end
  341.         end
  342.       else
  343.         for i = 1, math.min(unicode.len(text), vScreenWidth - x + 1) do
  344.           local char = unicode.sub(text, i, i)
  345.           virtualScreen[y][x + i - 1] = {char = char, fg = currentFG, bg = currentBG}
  346.         end
  347.       end
  348.     end
  349.     needsRedraw = true
  350.     return true
  351.   end
  352.  
  353.   virtualGPU.fill = function(x, y, w, h, char)
  354.     char = unicode.sub(char or " ", 1, 1)
  355.     for dy = 0, h - 1 do
  356.       for dx = 0, w - 1 do
  357.         if y + dy >= 1 and y + dy <= vScreenHeight and x + dx >= 1 and x + dx <= vScreenWidth then
  358.           virtualScreen[y + dy][x + dx] = {char = char, fg = currentFG, bg = currentBG}
  359.         end
  360.       end
  361.     end
  362.     needsRedraw = true
  363.     return true
  364.   end
  365.  
  366.   virtualGPU.copy = function(x, y, w, h, tx, ty)
  367.     local tempScreen = {}
  368.     for dy = 0, h - 1 do
  369.       tempScreen[dy + 1] = {}
  370.       for dx = 0, w - 1 do
  371.         if y + dy >= 1 and y + dy <= vScreenHeight and x + dx >= 1 and x + dx <= vScreenWidth then
  372.           tempScreen[dy + 1][dx + 1] = virtualScreen[y + dy][x + dx]
  373.         end
  374.       end
  375.     end
  376.     for dy = 0, h - 1 do
  377.       for dx = 0, w - 1 do
  378.         if ty + dy >= 1 and ty + dy <= vScreenHeight and tx + dx >= 1 and tx + dx <= vScreenWidth then
  379.           virtualScreen[ty + dy][tx + dx] = tempScreen[dy + 1][dx + 1] or {char = " ", fg = currentFG, bg = currentBG}
  380.         end
  381.       end
  382.     end
  383.     needsRedraw = true
  384.     return true
  385.   end
  386.  
  387.   virtualGPU.getResolution = function() return vScreenWidth, vScreenHeight end
  388.   virtualGPU.setResolution = function(width, height) return true end  -- Ignore resolution changes
  389.   virtualGPU.maxResolution = function() return vScreenWidth, vScreenHeight end
  390.   virtualGPU.getDepth = function() return currentDepth end
  391.   virtualGPU.setDepth = function(depth) currentDepth = depth; return true end
  392.   virtualGPU.maxDepth = function() return 8 end
  393.   virtualGPU.getBackground = function() return currentBG end
  394.   virtualGPU.getForeground = function() return currentFG end
  395.   virtualGPU.getPaletteColor = function(index) return 0 end  -- Dummy palette
  396.   virtualGPU.setPaletteColor = function(index, color) return true end  -- Ignore palette changes
  397.   virtualGPU.getScreen = function() return {} end  -- Dummy screen
  398.   virtualGPU.getViewport = function() return 1, 1, vScreenWidth, vScreenHeight end
  399.   virtualGPU.setViewport = function(x, y, width, height) return true end  -- Ignore viewport changes
  400.   virtualGPU.bind = function(address) return true end  -- Dummy bind function
  401.  
  402.   local function handleInput()
  403.     if inputCallback then
  404.       inputCallback(inputBuffer)
  405.       inputBuffer = ""
  406.       isWaitingForInput = false
  407.       inputCallback = nil
  408.     end
  409.   end
  410.  
  411.   function program.init()
  412.     local file, err = io.open(filePath, "r")
  413.     if not file then
  414.       virtualGPU.set(1, 1, "Error opening file: " .. tostring(err))
  415.       return
  416.     end
  417.    
  418.     local content = file:read("*all")
  419.     file:close()
  420.  
  421.     local env = setmetatable({}, {__index = _G})
  422.     env.component = setmetatable({}, {
  423.       __index = function(_, key)
  424.         if key == "gpu" then
  425.           return createProxy(virtualGPU)
  426.         elseif key == "list" then
  427.           return function() return {"gpu"} end
  428.         else
  429.           return component[key]
  430.         end
  431.       end
  432.     })
  433.     env.computer = createProxy(computer)
  434.     env.gpu = createProxy(virtualGPU)
  435.  
  436.     env.print = function(...)
  437.       local args = {...}
  438.       local text = table.concat(args, "\t")
  439.       for i, line in ipairs(text:gmatch("[^\n]+")) do
  440.         virtualGPU.set(1, i, line)
  441.       end
  442.     end
  443.     env.io = {
  444.       write = function(...)
  445.         local args = {...}
  446.         local text = table.concat(args)
  447.         virtualGPU.set(1, 1, text)
  448.       end,
  449.       read = function(...)
  450.         isWaitingForInput = true
  451.         local co = coroutine.running()
  452.         inputCallback = function(input)
  453.           coroutine.resume(co, input)
  454.         end
  455.         return coroutine.yield()
  456.       end
  457.     }
  458.  
  459.     local func, err = load(content, "=" .. filePath, "t", env)
  460.     if not func then
  461.       virtualGPU.set(1, 1, "Error loading script: " .. tostring(err))
  462.       return
  463.     end
  464.  
  465.     local co = coroutine.create(func)
  466.     local function resume()
  467.       local success, result = coroutine.resume(co)
  468.       if not success then
  469.         virtualGPU.set(1, vScreenHeight, "Error: " .. tostring(result))
  470.       elseif coroutine.status(co) ~= "dead" then
  471.         -- Schedule the next resume
  472.         computer.pushSignal("lua_runner_continue")
  473.       end
  474.       needsRedraw = true
  475.     end
  476.  
  477.     -- Start the coroutine
  478.     resume()
  479.  
  480.     -- Set up a handler for continuing the script
  481.     event.listen("lua_runner_continue", resume)
  482.   end
  483.  
  484.   function program.draw()
  485.   if needsRedraw then
  486.     local win = program.window
  487.     for y = 1, math.min(win.height - 2, vScreenHeight) do
  488.       for x = 1, math.min(win.width - 2, vScreenWidth) do
  489.         local vChar = virtualScreen[y + scrollPosition] and virtualScreen[y + scrollPosition][x] or {char = " ", fg = 0xFFFFFF, bg = 0x000000}
  490.         if win.x and win.y and vChar.char and vChar.fg and vChar.bg then
  491.           drawText(win.x + x, win.y + y, vChar.char, vChar.fg, vChar.bg)
  492.         end
  493.       end
  494.     end
  495.  
  496.     -- Draw input line
  497.     if win.x and win.y and win.width then
  498.       drawText(win.x + 1, win.y + win.height - 1, string.rep("-", win.width - 2), 0xFFFFFF, 0x000000)
  499.       local inputText = isWaitingForInput and ("> " .. inputBuffer) or ""
  500.       drawText(win.x + 1, win.y + win.height, inputText, 0xFFFFFF, 0x000000)
  501.     end
  502.  
  503.     needsRedraw = false
  504.   end
  505. end
  506.  
  507.   function program.handleEvent(e)
  508.     if e[1] == "key_down" then
  509.       if isWaitingForInput then
  510.         if e[4] == 28 then  -- Enter key
  511.           handleInput()
  512.         elseif e[4] == 14 then  -- Backspace
  513.           inputBuffer = unicode.sub(inputBuffer, 1, -2)
  514.         else
  515.           local char = unicode.char(e[3])
  516.           if char:match("%g") or char == " " then
  517.             inputBuffer = inputBuffer .. char
  518.           end
  519.         end
  520.       else
  521.         if e[4] == 200 then  -- Up arrow
  522.           scrollPosition = math.max(0, scrollPosition - 1)
  523.         elseif e[4] == 208 then  -- Down arrow
  524.           scrollPosition = math.min(vScreenHeight - (program.window.height - 3), scrollPosition + 1)
  525.         end
  526.       end
  527.       needsRedraw = true
  528.       return true
  529.     end
  530.     return false
  531.   end
  532.  
  533.   return program
  534. end
  535.  
  536. -- File Explorer
  537. programs.fileExplorer = function()
  538.   local program = {}
  539.   local currentPath = "/"
  540.   local files = {}
  541.   local selectedFile = 1
  542.  
  543.   local function updateFileList()
  544.     files = {}
  545.     for file in filesystem.list(currentPath) do
  546.       table.insert(files, file)
  547.     end
  548.     table.sort(files)
  549.   end
  550.  
  551.   local function updateContent()
  552.     local win = program.window
  553.     win.content = {"Current path: " .. currentPath, ""}
  554.     for i, file in ipairs(files) do
  555.       local prefix = i == selectedFile and "> " or "  "
  556.       table.insert(win.content, prefix .. file)
  557.     end
  558.   end
  559.  
  560.   function program.init()
  561.     updateFileList()
  562.     updateContent()
  563.   end
  564.  
  565.   function program.handleEvent(e)
  566.     if e[1] == "key_down" then
  567.       if e[4] == 200 then  -- Up arrow
  568.         selectedFile = math.max(1, selectedFile - 1)
  569.       elseif e[4] == 208 then  -- Down arrow
  570.         selectedFile = math.min(#files, selectedFile + 1)
  571.       elseif e[4] == 28 then  -- Enter
  572.         local selected = files[selectedFile]
  573.         if selected then
  574.           local fullPath = filesystem.concat(currentPath, selected)
  575.           if filesystem.isDirectory(fullPath) then
  576.             currentPath = fullPath
  577.             updateFileList()
  578.             selectedFile = 1
  579.           else
  580.             -- Check if it's a .lua file
  581.             if selected:match("%.lua$") then
  582.               local luaRunner = programs.luaRunner(fullPath)
  583.               -- Create a larger window for the Lua Runner
  584.               table.insert(Nexium.windows, Window.new("Lua: " .. selected, 1, 1, screenWidth, screenHeight - 1, luaRunner))
  585.             else
  586.               -- Handle other file types or show an error
  587.               computer.beep(1000, 0.2)
  588.             end
  589.           end
  590.         end
  591.       elseif e[4] == 14 then  -- Backspace
  592.         currentPath = filesystem.path(currentPath) or "/"
  593.         updateFileList()
  594.         selectedFile = 1
  595.       end
  596.       updateContent()
  597.       return true
  598.     end
  599.     return false
  600.   end
  601.  
  602.   return program
  603. end
  604.  
  605. -- Settings
  606. programs.settings = function()
  607.   local program = {}
  608.   local settings = {
  609.     {"Background Color", Nexium.background.color},
  610.     {"Background Pattern", Nexium.background.pattern},
  611.     {"Show Desktop Icons", showDesktopIcons},
  612.   }
  613.   local selectedSetting = 1
  614.  
  615.   local function updateContent()
  616.     local win = program.window
  617.     win.content = {"Nexium OS Settings", ""}
  618.     for i, setting in ipairs(settings) do
  619.       local prefix = i == selectedSetting and "> " or "  "
  620.       table.insert(win.content, prefix .. setting[1] .. ": " .. tostring(setting[2]))
  621.     end
  622.   end
  623.  
  624.   function program.init()
  625.     updateContent()
  626.   end
  627.  
  628.   function program.handleEvent(e)
  629.     if e[1] == "key_down" then
  630.       if e[4] == 200 then  -- Up arrow
  631.         selectedSetting = math.max(1, selectedSetting - 1)
  632.       elseif e[4] == 208 then  -- Down arrow
  633.         selectedSetting = math.min(#settings, selectedSetting + 1)
  634.       elseif e[4] == 28 then  -- Enter
  635.         -- Toggle or cycle through options
  636.         if selectedSetting == 1 then
  637.           settings[1][2] = settings[1][2] == 0x000040 and 0x004000 or 0x000040
  638.           Nexium.background.color = settings[1][2]
  639.         elseif selectedSetting == 2 then
  640.           settings[2][2] = settings[2][2] == "." and "*" or "."
  641.           Nexium.background.pattern = settings[2][2]
  642.         elseif selectedSetting == 3 then
  643.           settings[3][2] = not settings[3][2]
  644.           showDesktopIcons = settings[3][2]
  645.         end
  646.       end
  647.       updateContent()
  648.       return true
  649.     end
  650.     return false
  651.   end
  652.  
  653.   return program
  654. end
  655.  
  656. -- About
  657. programs.about = function()
  658.   local program = {}
  659.  
  660.   function program.init()
  661.     local win = program.window
  662.     local totalMemory = computer.totalMemory()
  663.     local freeMemory = computer.freeMemory()
  664.     win.content = {
  665.       "Nexium OS v" .. Nexium.version,
  666.       "",
  667.       "System Information:",
  668.       "Total Memory: " .. math.floor(totalMemory / 1024) .. " KB",
  669.       "Free Memory: " .. math.floor(freeMemory / 1024) .. " KB",
  670.       "Used Memory: " .. math.floor((totalMemory - freeMemory) / 1024) .. " KB",
  671.       "Uptime: " .. math.floor(computer.uptime()) .. " seconds",
  672.       "",
  673.       "Press any key to close"
  674.     }
  675.   end
  676.  
  677.   function program.handleEvent(e)
  678.     if e[1] == "key_down" then
  679.       return "close"
  680.     end
  681.     return false
  682.   end
  683.  
  684.   return program
  685. end
  686.  
  687. -- Task Manager
  688. programs.taskManager = function()
  689.   local program = {}
  690.   local selectedTask = 1
  691.   local updateInterval = 1  -- Update performance metrics every second
  692.   local lastUpdate = 0
  693.   local lastUsedMemory = 0
  694.   local memoryDelta = 0
  695.  
  696.   local function getPerformanceMetrics()
  697.     local totalMemory = computer.totalMemory()
  698.     local freeMemory = computer.freeMemory()
  699.     local usedMemory = totalMemory - freeMemory
  700.     local memoryUsage = math.floor((usedMemory / totalMemory) * 100)
  701.    
  702.     -- Calculate memory usage change
  703.     memoryDelta = usedMemory - lastUsedMemory
  704.     lastUsedMemory = usedMemory
  705.    
  706.     -- Calculate a pseudo "activity" percentage based on memory changes
  707.     local activity = math.min(100, math.abs(memoryDelta) / 1024)  -- 1 KB change = 1% activity, max 100%
  708.    
  709.     return {
  710.       activity = math.floor(activity),
  711.       memory = memoryUsage,
  712.       totalMemory = math.floor(totalMemory / 1024),
  713.       freeMemory = math.floor(freeMemory / 1024),
  714.       uptime = math.floor(computer.uptime())
  715.     }
  716.   end
  717.  
  718.   local function updateContent()
  719.     local win = program.window
  720.     local metrics = getPerformanceMetrics()
  721.     win.content = {
  722.       "Task Manager",
  723.       string.format("System Activity: %d%%", metrics.activity),
  724.       string.format("Memory Usage: %d%% (%d KB / %d KB)", metrics.memory, metrics.totalMemory - metrics.freeMemory, metrics.totalMemory),
  725.       string.format("Uptime: %d seconds", metrics.uptime),
  726.       ""
  727.     }
  728.     for i, window in ipairs(Nexium.windows) do
  729.       local prefix = i == selectedTask and "> " or "  "
  730.       table.insert(win.content, prefix .. window.title)
  731.     end
  732.     table.insert(win.content, "")
  733.     table.insert(win.content, "Press Enter to close selected task")
  734.     table.insert(win.content, "Press Esc to exit Task Manager")
  735.   end
  736.  
  737.   function program.init()
  738.     updateContent()
  739.   end
  740.  
  741.   function program.draw()
  742.     local currentTime = computer.uptime()
  743.     if currentTime - lastUpdate >= updateInterval then
  744.       updateContent()
  745.       lastUpdate = currentTime
  746.     end
  747.     for i, line in ipairs(program.window.content) do
  748.       drawText(program.window.x + 1, program.window.y + i, line, 0xFFFFFF, 0x000000)
  749.     end
  750.   end
  751.  
  752.   function program.handleEvent(e)
  753.     if e[1] == "key_down" then
  754.       if e[4] == 200 then  -- Up arrow
  755.         selectedTask = math.max(1, selectedTask - 1)
  756.       elseif e[4] == 208 then  -- Down arrow
  757.         selectedTask = math.min(#Nexium.windows, selectedTask + 1)
  758.       elseif e[4] == 28 then  -- Enter
  759.         if Nexium.windows[selectedTask] then
  760.           table.remove(Nexium.windows, selectedTask)
  761.           selectedTask = math.min(selectedTask, #Nexium.windows)
  762.         end
  763.       elseif e[4] == 1 then  -- Esc
  764.         return "close"
  765.       end
  766.       updateContent()
  767.       return true
  768.     end
  769.     return false
  770.   end
  771.  
  772.   return program
  773. end
  774.  
  775. -- Desktop icons
  776. local function initializeDesktopIcons()
  777.   Nexium.desktop.icons = {
  778.     {name = "Terminal", x = 2, y = 2, program = programs.terminal},
  779.     {name = "File Explorer", x = 2, y = 4, program = programs.fileExplorer},
  780.     {name = "Settings", x = 2, y = 6, program = programs.settings},
  781.     {name = "About", x = 2, y = 8, program = programs.about},
  782.     {name = "Task Manager", x = 2, y = 10, program = programs.taskManager},
  783.   }
  784. end
  785.  
  786. -- Draw desktop icons
  787. local function drawDesktopIcons()
  788.   if showDesktopIcons then
  789.     for _, icon in ipairs(Nexium.desktop.icons) do
  790.       drawText(icon.x, icon.y, icon.name, 0xFFFFFF, Nexium.background.color)
  791.     end
  792.   end
  793. end
  794.  
  795. -- Draw start menu
  796. local function drawStartMenu()
  797.   drawRect(Nexium.startMenu.x, Nexium.startMenu.y, Nexium.startMenu.width, Nexium.startMenu.height, 0xFFFFFF, 0x0000FF)
  798.   drawText(Nexium.startMenu.x, Nexium.startMenu.y, "Nexium Start Menu", 0xFFFFFF, 0x0000FF)
  799.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 2, "1. Terminal", 0xFFFFFF, 0x0000FF)
  800.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 3, "2. File Explorer", 0xFFFFFF, 0x0000FF)
  801.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 4, "3. Settings", 0xFFFFFF, 0x0000FF)
  802.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 5, "4. About", 0xFFFFFF, 0x0000FF)
  803.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 6, "5. Task Manager", 0xFFFFFF, 0x0000FF)
  804.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 7, "6. Toggle Desktop Icons", 0xFFFFFF, 0x0000FF)
  805.   drawText(Nexium.startMenu.x, Nexium.startMenu.y + 8, "7. Shutdown", 0xFFFFFF, 0x0000FF)
  806. end
  807.  
  808. -- Draw taskbar
  809. local function drawTaskbar()
  810.   drawRect(1, screenHeight, screenWidth, 1, 0xFFFFFF, 0x000000)
  811.   local x = 1
  812.   for i, win in ipairs(Nexium.windows) do
  813.     local title = unicode.sub(win.title, 1, 10)
  814.     drawText(x, screenHeight, title, win.minimized and 0x808080 or 0xFFFFFF, 0x000000)
  815.     x = x + #title + 2
  816.   end
  817. end
  818.  
  819. -- Handle events
  820. local function handleEvents()
  821.   local e = {event.pull(0.05)}
  822.   if e[1] == "touch" then
  823.     local x, y = e[3], e[4]
  824.     if y >= Nexium.startMenu.y and y < Nexium.startMenu.y + Nexium.startMenu.height and
  825.        x >= Nexium.startMenu.x and x < Nexium.startMenu.x + Nexium.startMenu.width then
  826.       -- Start menu interaction
  827.       local option = y - Nexium.startMenu.y
  828.       if option == 2 then
  829.         table.insert(Nexium.windows, Window.new("Terminal", 10, 5, 60, 20, programs.terminal()))
  830.       elseif option == 3 then
  831.         table.insert(Nexium.windows, Window.new("File Explorer", 10, 5, 50, 15, programs.fileExplorer()))
  832.       elseif option == 4 then
  833.         table.insert(Nexium.windows, Window.new("Settings", 15, 5, 40, 12, programs.settings()))
  834.       elseif option == 5 then
  835.         table.insert(Nexium.windows, Window.new("About", 20, 5, 40, 12, programs.about()))
  836.       elseif option == 6 then
  837.         table.insert(Nexium.windows, Window.new("Task Manager", 25, 5, 50, 15, programs.taskManager()))
  838.       elseif option == 7 then
  839.         showDesktopIcons = not showDesktopIcons
  840.       elseif option == 8 then
  841.         Nexium.running = false
  842.       else
  843.         -- Start dragging the start menu
  844.         Nexium.startMenu.dragging = true
  845.         Nexium.startMenu.dragOffsetX = x - Nexium.startMenu.x
  846.         Nexium.startMenu.dragOffsetY = y - Nexium.startMenu.y
  847.       end
  848.     elseif y == screenHeight then
  849.       -- Taskbar click
  850.       local buttonX = 1
  851.       for i, win in ipairs(Nexium.windows) do
  852.         local buttonWidth = #win.title + 2
  853.         if x >= buttonX and x < buttonX + buttonWidth then
  854.           win.minimized = not win.minimized
  855.           break
  856.         end
  857.         buttonX = buttonX + buttonWidth
  858.       end
  859.     else
  860.       -- Check desktop icons
  861.       if showDesktopIcons then
  862.         for _, icon in ipairs(Nexium.desktop.icons) do
  863.           if x >= icon.x and x < icon.x + #icon.name and y == icon.y then
  864.             table.insert(Nexium.windows, Window.new(icon.name, 10, 5, 60, 20, icon.program()))
  865.             return
  866.           end
  867.         end
  868.       end
  869.       -- Check windows
  870.       for i = #Nexium.windows, 1, -1 do
  871.         local result = Nexium.windows[i]:handleEvent(e)
  872.         if result then
  873.           if result == "close" then
  874.             table.remove(Nexium.windows, i)
  875.           elseif result == "minimize" then
  876.             -- Already handled in Window:handleEvent
  877.           elseif result == "maximize" then
  878.             -- Already handled in Window:handleEvent
  879.           else
  880.             -- Move window to top
  881.             local win = table.remove(Nexium.windows, i)
  882.             table.insert(Nexium.windows, win)
  883.           end
  884.           return
  885.         end
  886.       end
  887.     end
  888.   elseif e[1] == "drag" then
  889.     if Nexium.startMenu.dragging then
  890.       Nexium.startMenu.x = math.max(1, math.min(screenWidth - Nexium.startMenu.width, e[3] - Nexium.startMenu.dragOffsetX))
  891.       Nexium.startMenu.y = math.max(1, math.min(screenHeight - Nexium.startMenu.height, e[4] - Nexium.startMenu.dragOffsetY))
  892.     else
  893.       for _, win in ipairs(Nexium.windows) do
  894.         win:handleEvent(e)
  895.       end
  896.     end
  897.   elseif e[1] == "drop" then
  898.     Nexium.startMenu.dragging = false
  899.     for _, win in ipairs(Nexium.windows) do
  900.       win:handleEvent(e)
  901.     end
  902.   elseif e[1] == "key_down" then
  903.     -- Pass key events to the active window
  904.     if #Nexium.windows > 0 then
  905.       Nexium.windows[#Nexium.windows]:handleEvent(e)
  906.     end
  907.   end
  908. end
  909.  
  910. -- Main loop
  911. local function main()
  912.   initializeDesktopIcons()
  913.   while Nexium.running do
  914.     -- Clear back buffer
  915.     for y = 1, screenHeight do
  916.       for x = 1, screenWidth do
  917.         backBuffer[y][x] = {char = Nexium.background.pattern, fg = 0xFFFFFF, bg = Nexium.background.color}
  918.       end
  919.     end
  920.    
  921.     drawDesktopIcons()
  922.     for _, win in ipairs(Nexium.windows) do
  923.       win:draw()
  924.     end
  925.     drawTaskbar()
  926.     drawStartMenu()
  927.    
  928.     handleEvents()
  929.    
  930.     swapBuffers()
  931.   end
  932. end
  933.  
  934. -- Add some basic commands for the terminal
  935. _G.help = function()
  936.   return [[
  937. Available commands:
  938. - help(): Show this help message
  939. - print(...): Print arguments
  940. - math functions (sin, cos, tan, etc.)
  941. - string functions (len, sub, etc.)
  942. - table functions (insert, remove, etc.)
  943. - os.exit(): Exit Nexium OS
  944.   ]]
  945. end
  946.  
  947. _G.os = _G.os or {}
  948. _G.os.exit = function()
  949.   Nexium.running = false
  950. end
  951.  
  952. -- Start the OS
  953. print("Starting Nexium OS...")
  954. cleanScreen()
  955. main()
  956. cleanScreen()
  957. print("Nexium OS has shut down.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement