ElijahCrafter

Desktop

Nov 27th, 2025
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.15 KB | None | 0 0
  1. -- Desktop Module for SimpleOS
  2.  
  3. local ui = require("os.ui")
  4. local apps = require("os.apps")
  5.  
  6. local desktop = {}
  7.  
  8. -- State
  9. local running = true
  10. local menuOpen = false
  11. local menuType = nil -- "start" or "context" or "appmenu"
  12. local menuX, menuY = 1, 1
  13. local selectedApp = nil
  14. local dialogOpen = false
  15. local dialogType = nil
  16. local dialogInputs = {}
  17. local activeInput = 1
  18.  
  19. -- Icon grid settings
  20. local iconWidth = 7
  21. local iconHeight = 4
  22. local iconsPerRow = 6
  23. local iconStartX = 2
  24. local iconStartY = 2
  25.  
  26. -- Get icon position
  27. local function getIconPos(index)
  28. local row = math.floor((index - 1) / iconsPerRow)
  29. local col = (index - 1) % iconsPerRow
  30. local x = iconStartX + col * iconWidth
  31. local y = iconStartY + row * iconHeight
  32. return x, y
  33. end
  34.  
  35. -- Get icon at click position
  36. local function getIconAt(clickX, clickY)
  37. local appList = apps.getAll()
  38. for i, app in ipairs(appList) do
  39. local x, y = getIconPos(i)
  40. if ui.isInBounds(clickX, clickY, x, y, 5, 3) then
  41. return i
  42. end
  43. end
  44. return nil
  45. end
  46.  
  47. -- Draw desktop background
  48. local function drawBackground()
  49. local w, h = ui.getSize()
  50. ui.drawBox(1, 1, w, h - 1, ui.colors.desktop)
  51. end
  52.  
  53. -- Draw taskbar
  54. local function drawTaskbar()
  55. local w, h = ui.getSize()
  56. ui.drawBox(1, h, w, 1, ui.colors.taskbar)
  57.  
  58. -- Start button
  59. term.setCursorPos(1, h)
  60. term.setBackgroundColor(colors.green)
  61. term.setTextColor(colors.white)
  62. term.write(" Start ")
  63.  
  64. -- Clock
  65. local time = textutils.formatTime(os.time(), false)
  66. term.setCursorPos(w - #time, h)
  67. term.setBackgroundColor(ui.colors.taskbar)
  68. term.setTextColor(ui.colors.taskbarText)
  69. term.write(time)
  70. end
  71.  
  72. -- Draw all icons
  73. local function drawIcons()
  74. local appList = apps.getAll()
  75. for i, app in ipairs(appList) do
  76. local x, y = getIconPos(i)
  77. ui.drawIcon(x, y, app.name, app.symbol)
  78. end
  79. end
  80.  
  81. -- Draw start menu
  82. local function drawStartMenu()
  83. local w, h = ui.getSize()
  84. local menuWidth = 15
  85. local menuHeight = 6
  86. local x = 1
  87. local y = h - menuHeight
  88.  
  89. ui.drawBox(x, y, menuWidth, menuHeight, ui.colors.menuBg)
  90.  
  91. local items = {"New App", "Refresh", "Settings", "Shutdown"}
  92. term.setTextColor(ui.colors.menuText)
  93.  
  94. for i, item in ipairs(items) do
  95. term.setBackgroundColor(ui.colors.menuBg)
  96. term.setCursorPos(x + 1, y + i)
  97. term.write(item)
  98. end
  99.  
  100. menuX, menuY = x, y
  101. end
  102.  
  103. -- Draw context menu (right-click on app)
  104. local function drawAppMenu(appIndex)
  105. local x, y = getIconPos(appIndex)
  106. local menuWidth = 12
  107. local menuHeight = 4
  108.  
  109. -- Adjust position if menu would go off screen
  110. local w, h = ui.getSize()
  111. if x + menuWidth > w then x = w - menuWidth end
  112. if y + menuHeight > h - 1 then y = h - 1 - menuHeight end
  113.  
  114. ui.drawBox(x, y, menuWidth, menuHeight, ui.colors.menuBg)
  115.  
  116. local items = {"Run", "Edit", "Delete"}
  117. term.setTextColor(ui.colors.menuText)
  118.  
  119. for i, item in ipairs(items) do
  120. term.setBackgroundColor(ui.colors.menuBg)
  121. term.setCursorPos(x + 1, y + i - 1)
  122. term.write(item)
  123. end
  124.  
  125. menuX, menuY = x, y
  126. selectedApp = appIndex
  127. end
  128.  
  129. -- Draw new app dialog
  130. local function drawNewAppDialog()
  131. local w, h = ui.getSize()
  132. local dialogWidth = 30
  133. local dialogHeight = 10
  134. local x = math.floor((w - dialogWidth) / 2)
  135. local y = math.floor((h - dialogHeight) / 2)
  136.  
  137. ui.drawWindow(x, y, dialogWidth, dialogHeight, "New App")
  138.  
  139. term.setBackgroundColor(ui.colors.window)
  140. term.setTextColor(colors.black)
  141.  
  142. -- Name field
  143. term.setCursorPos(x + 2, y + 2)
  144. term.write("Name:")
  145. ui.drawInput(x + 9, y + 2, 18, dialogInputs.name or "", activeInput == 1)
  146.  
  147. -- Symbol field
  148. term.setCursorPos(x + 2, y + 4)
  149. term.write("Icon:")
  150. ui.drawInput(x + 9, y + 4, 3, dialogInputs.symbol or "", activeInput == 2)
  151.  
  152. -- Command field
  153. term.setCursorPos(x + 2, y + 6)
  154. term.write("Command:")
  155. ui.drawInput(x + 2, y + 7, 26, dialogInputs.command or "", activeInput == 3)
  156.  
  157. -- Buttons
  158. ui.drawButton(x + 5, y + 9, 8, 1, "Save", colors.green, colors.white)
  159. ui.drawButton(x + 17, y + 9, 8, 1, "Cancel", colors.red, colors.white)
  160.  
  161. return x, y, dialogWidth, dialogHeight
  162. end
  163.  
  164. -- Draw edit app dialog
  165. local function drawEditAppDialog()
  166. return drawNewAppDialog() -- Same layout, different title handled in state
  167. end
  168.  
  169. -- Refresh desktop
  170. local function refresh()
  171. drawBackground()
  172. drawTaskbar()
  173. drawIcons()
  174.  
  175. if menuOpen then
  176. if menuType == "start" then
  177. drawStartMenu()
  178. elseif menuType == "appmenu" then
  179. drawAppMenu(selectedApp)
  180. end
  181. end
  182.  
  183. if dialogOpen then
  184. if dialogType == "newapp" or dialogType == "editapp" then
  185. drawNewAppDialog()
  186. end
  187. end
  188. end
  189.  
  190. -- Handle start menu click
  191. local function handleStartMenuClick(clickX, clickY)
  192. local w, h = ui.getSize()
  193. local menuHeight = 6
  194. local y = h - menuHeight
  195.  
  196. local itemIndex = clickY - y
  197. if itemIndex >= 1 and itemIndex <= 4 then
  198. if itemIndex == 1 then
  199. -- New App
  200. dialogOpen = true
  201. dialogType = "newapp"
  202. dialogInputs = {name = "", symbol = "", command = ""}
  203. activeInput = 1
  204. elseif itemIndex == 2 then
  205. -- Refresh
  206. apps.load()
  207. elseif itemIndex == 3 then
  208. -- Settings (placeholder)
  209. elseif itemIndex == 4 then
  210. -- Shutdown
  211. running = false
  212. end
  213. end
  214. menuOpen = false
  215. end
  216.  
  217. -- Handle app menu click
  218. local function handleAppMenuClick(clickX, clickY)
  219. local itemIndex = clickY - menuY + 1
  220. if itemIndex >= 1 and itemIndex <= 3 then
  221. if itemIndex == 1 then
  222. -- Run
  223. apps.run(selectedApp)
  224. elseif itemIndex == 2 then
  225. -- Edit
  226. local app = apps.get(selectedApp)
  227. dialogOpen = true
  228. dialogType = "editapp"
  229. dialogInputs = {
  230. name = app.name,
  231. symbol = app.symbol,
  232. command = app.command
  233. }
  234. activeInput = 1
  235. elseif itemIndex == 3 then
  236. -- Delete
  237. apps.remove(selectedApp)
  238. end
  239. end
  240. menuOpen = false
  241. selectedApp = nil
  242. end
  243.  
  244. -- Handle dialog input
  245. local function handleDialogClick(clickX, clickY, dialogX, dialogY, dialogWidth, dialogHeight)
  246. -- Check input fields
  247. if ui.isInBounds(clickX, clickY, dialogX + 9, dialogY + 2, 18, 1) then
  248. activeInput = 1
  249. elseif ui.isInBounds(clickX, clickY, dialogX + 9, dialogY + 4, 3, 1) then
  250. activeInput = 2
  251. elseif ui.isInBounds(clickX, clickY, dialogX + 2, dialogY + 7, 26, 1) then
  252. activeInput = 3
  253. -- Check Save button
  254. elseif ui.isInBounds(clickX, clickY, dialogX + 5, dialogY + 9, 8, 1) then
  255. if dialogInputs.name ~= "" and dialogInputs.command ~= "" then
  256. if dialogType == "newapp" then
  257. apps.add(dialogInputs.name, dialogInputs.symbol, dialogInputs.command)
  258. elseif dialogType == "editapp" then
  259. apps.edit(selectedApp, dialogInputs.name, dialogInputs.symbol, dialogInputs.command)
  260. end
  261. end
  262. dialogOpen = false
  263. dialogInputs = {}
  264. selectedApp = nil
  265. -- Check Cancel button
  266. elseif ui.isInBounds(clickX, clickY, dialogX + 17, dialogY + 9, 8, 1) then
  267. dialogOpen = false
  268. dialogInputs = {}
  269. selectedApp = nil
  270. -- Check close button (X)
  271. elseif ui.isInBounds(clickX, clickY, dialogX + dialogWidth - 2, dialogY, 1, 1) then
  272. dialogOpen = false
  273. dialogInputs = {}
  274. selectedApp = nil
  275. end
  276. end
  277.  
  278. -- Handle key input for dialog
  279. local function handleDialogKey(key)
  280. if key == keys.tab then
  281. activeInput = activeInput % 3 + 1
  282. elseif key == keys.enter then
  283. if dialogInputs.name ~= "" and dialogInputs.command ~= "" then
  284. if dialogType == "newapp" then
  285. apps.add(dialogInputs.name, dialogInputs.symbol, dialogInputs.command)
  286. elseif dialogType == "editapp" then
  287. apps.edit(selectedApp, dialogInputs.name, dialogInputs.symbol, dialogInputs.command)
  288. end
  289. end
  290. dialogOpen = false
  291. dialogInputs = {}
  292. selectedApp = nil
  293. elseif key == keys.escape then
  294. dialogOpen = false
  295. dialogInputs = {}
  296. selectedApp = nil
  297. end
  298. end
  299.  
  300. -- Handle char input for dialog
  301. local function handleDialogChar(char)
  302. local field
  303. if activeInput == 1 then
  304. field = "name"
  305. if #dialogInputs.name < 10 then
  306. dialogInputs.name = dialogInputs.name .. char
  307. end
  308. elseif activeInput == 2 then
  309. field = "symbol"
  310. if #dialogInputs.symbol < 1 then
  311. dialogInputs.symbol = char
  312. end
  313. elseif activeInput == 3 then
  314. field = "command"
  315. if #dialogInputs.command < 50 then
  316. dialogInputs.command = dialogInputs.command .. char
  317. end
  318. end
  319. end
  320.  
  321. -- Handle backspace for dialog
  322. local function handleDialogBackspace()
  323. if activeInput == 1 then
  324. dialogInputs.name = dialogInputs.name:sub(1, -2)
  325. elseif activeInput == 2 then
  326. dialogInputs.symbol = ""
  327. elseif activeInput == 3 then
  328. dialogInputs.command = dialogInputs.command:sub(1, -2)
  329. end
  330. end
  331.  
  332. -- Main event handler
  333. local function handleEvent(event, p1, p2, p3)
  334. if event == "mouse_click" then
  335. local button, clickX, clickY = p1, p2, p3
  336. local w, h = ui.getSize()
  337.  
  338. -- Handle dialog clicks
  339. if dialogOpen then
  340. local dialogWidth = 30
  341. local dialogHeight = 10
  342. local dialogX = math.floor((w - dialogWidth) / 2)
  343. local dialogY = math.floor((h - dialogHeight) / 2)
  344. handleDialogClick(clickX, clickY, dialogX, dialogY, dialogWidth, dialogHeight)
  345. return
  346. end
  347.  
  348. -- Handle menu clicks
  349. if menuOpen then
  350. if menuType == "start" then
  351. handleStartMenuClick(clickX, clickY)
  352. elseif menuType == "appmenu" then
  353. handleAppMenuClick(clickX, clickY)
  354. end
  355. return
  356. end
  357.  
  358. -- Check taskbar
  359. if clickY == h then
  360. -- Start button
  361. if clickX >= 1 and clickX <= 7 then
  362. menuOpen = true
  363. menuType = "start"
  364. end
  365. return
  366. end
  367.  
  368. -- Check icons
  369. local iconIndex = getIconAt(clickX, clickY)
  370. if iconIndex then
  371. if button == 1 then
  372. -- Left click - run app
  373. apps.run(iconIndex)
  374. elseif button == 2 then
  375. -- Right click - show menu
  376. menuOpen = true
  377. menuType = "appmenu"
  378. selectedApp = iconIndex
  379. end
  380. else
  381. -- Click on empty space closes menus
  382. menuOpen = false
  383. end
  384.  
  385. elseif event == "key" then
  386. if dialogOpen then
  387. handleDialogKey(p1)
  388. elseif p1 == keys.escape then
  389. menuOpen = false
  390. end
  391.  
  392. elseif event == "char" then
  393. if dialogOpen then
  394. handleDialogChar(p1)
  395. end
  396.  
  397. elseif event == "key_up" then
  398. -- Handle backspace
  399. if p1 == keys.backspace and dialogOpen then
  400. handleDialogBackspace()
  401. end
  402. end
  403. end
  404.  
  405. -- Main run loop
  406. function desktop.run()
  407. running = true
  408.  
  409. while running do
  410. refresh()
  411. local event, p1, p2, p3 = os.pullEvent()
  412. handleEvent(event, p1, p2, p3)
  413. end
  414.  
  415. -- Clean exit
  416. term.setBackgroundColor(colors.black)
  417. term.setTextColor(colors.white)
  418. term.clear()
  419. term.setCursorPos(1, 1)
  420. print("SimpleOS shutdown complete.")
  421. end
  422.  
  423. return desktop
  424.  
Advertisement
Add Comment
Please, Sign In to add comment