R3C0NF16UR3D

wm.lua

Jul 31st, 2023
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 36.58 KB | None | 0 0
  1. local component = require("component")
  2. local gpu = component.gpu
  3. local event = require("event")
  4. local unicode = require("unicode")
  5. local computer = require("computer")
  6.  
  7. -- libthread from Zer0Galaxy found on openprograms.ru
  8. local computer = require("computer")
  9. computer.SingleThread = computer.pullSignal
  10. --local thread = {}
  11.  
  12. local mainThread
  13. local timeouts
  14.  
  15. local function MultiThread( _timeout )
  16. if coroutine.running()==mainThread then
  17. local mintime = _timeout or math.huge
  18. local co=next(timeouts)
  19. while co do
  20. if coroutine.status( co ) == "dead" then
  21. timeouts[co],co=nil,next(timeouts,co)
  22. else
  23. if timeouts[co] < mintime then mintime=timeouts[co] end
  24. co=next(timeouts,co)
  25. end
  26. end
  27. if not next(timeouts) then
  28. computer.pullSignal=computer.SingleThread
  29. computer.pushSignal("AllThreadsDead")
  30. end
  31. local event={computer.SingleThread(mintime)}
  32. local ok, param
  33. for co in pairs(timeouts) do
  34. ok, param = coroutine.resume( co, table.unpack(event) )
  35. if not ok then timeouts={} error( param )
  36. else timeouts[co] = param or math.huge end
  37. end
  38. return table.unpack(event)
  39. else
  40. return coroutine.yield( _timeout )
  41. end
  42. end
  43.  
  44. function threadInit()
  45. mainThread=coroutine.running()
  46. timeouts={}
  47. end
  48.  
  49.  
  50.  
  51. local wm = {}
  52.  
  53. function wm.threadCreate(f,...)
  54. computer.pullSignal=MultiThread
  55. local co=coroutine.create(f)
  56. timeouts[co]=math.huge
  57. local ok, param = coroutine.resume( co, ... )
  58. if not ok then timeouts={} error( param )
  59. else timeouts[co] = param or math.huge end
  60. return co
  61. end
  62.  
  63.  
  64.  
  65.  
  66. local versionMajor = 1
  67. local versionMinor = 2
  68. local versionState = "Release 1"
  69.  
  70.  
  71. local color={}
  72. color.black=0x000000
  73. color.gray=0xA9A9A9
  74. color.lightBlue=0x808080
  75. color.white=0xFFFFFF
  76. color.magenta=0xFF00FF
  77. color.yellow=0xFFFF00
  78. color.green=0x00FF00
  79. color.darkGreen=0x008000
  80. color.blue=0x0000ff
  81. color.red=0xFF0000
  82. color.orange=0xFFA500
  83. color.brown=0xA52A2A
  84. color.lightRed=0xF00000
  85. color.darkGray=0x202020
  86.  
  87. -- screen colors
  88. local Color = {}
  89. Color.ScreenBackground = color.lightBlue
  90. Color.ScreenForeground = color.white
  91. Color.TopLineBackground = color.darkGray
  92. Color.TopLineForeground = color.white
  93. Color.BottomLineBackground = color.darkGray
  94. Color.BottomLineForeground = color.white
  95. Color.BottomLineActive = color.red
  96. Color.TopLineActive = color.red
  97. Color.RunningDot = color.green
  98.  
  99. -- window colors
  100. Color.WindowBackground = color.gray
  101. Color.WindowForeground = color.black
  102. Color.WindowActiveFrameBackground = color.blue
  103. Color.WindowActiveFrameForeground = color.white
  104. Color.WindowInactiveFrameBackground = color.magenta
  105. Color.WindowInactiveFrameForeground = color.white
  106. Color.Shadow = color.black
  107. Color.Frame = color.white
  108.  
  109. --menu colors
  110. Color.MenuBackground = color.darkGray
  111. Color.MenuForeground = color.white
  112. Color.MenuSelectedBackground = color.darkGreen
  113. Color.MenuSelectedForeground = color.white
  114. Color.startMenuBackground = color.darkGray
  115. Color.startMenuForeground = color.white
  116. Color.startMenuActiveBackground = color.darkGray
  117. Color.startMenuActiveForeground = color.red
  118. Color.systemMenuBackground = color.darkGray
  119. Color.systemMenuForeground = color.white
  120. Color.systemMenuActiveBackground = color.darkGray
  121. Color.systemMenuActiveForeground = color.red
  122.  
  123. -- frames
  124. local frame = {
  125. -- horizontal, vertical, left-top, right-top, left-bottom, right-bottom
  126. ["Flat"] = {0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020},
  127. ["Double"] = {0x2550, 0x2551, 0x2554, 0x2557, 0x255A, 0x255D},
  128. ["Small"] = {0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518},
  129. ["Bold"] = {0x2501, 0x2503, 0x0250F, 0x2513, 0x2517, 0x251B}
  130. }
  131.  
  132. local windowFrame = frame.Bold -- standard frame for windows is double line
  133. local useWindowShadows = true
  134. local useBoxShadows = true
  135.  
  136. local menuFrame = frame.Small
  137.  
  138. local ScreenWidth, ScreenHeight = gpu.getResolution()
  139.  
  140. local blockMouse = false
  141.  
  142. function wm.setBoxShadow(state)
  143. useBoxShadows = state
  144. end
  145.  
  146. function wm.useShadows(state)
  147. useWindowShadows = state
  148. end
  149.  
  150. function wm.getShadowState()
  151. return useWindowShadows
  152. end
  153.  
  154. function wm.getShadowBoxed()
  155. return useBoxShadows
  156. end
  157.  
  158. local userLevel = 100
  159. local userName = ""
  160.  
  161. function wm.setUserLevel(level)
  162. userLevel = level
  163. end
  164.  
  165. function wm.getUserLevel()
  166. return userLevel
  167. end
  168.  
  169. function wm.getUsername()
  170. return userName
  171. end
  172.  
  173. function wm.setUsername(name)
  174. userName = name
  175. end
  176.  
  177. -- general functions
  178.  
  179. function clearScreen()
  180. gpu.setBackground(Color.ScreenBackground)
  181. gpu.setForeground(Color.ScreenForeground)
  182. gpu.fill(1, 2, ScreenWidth, ScreenHeight - 2, " ")
  183. end
  184.  
  185. function drawScreen()
  186. gpu.setBackground(Color.TopLineBackground)
  187. gpu.setForeground(Color.TopLineForeground)
  188. gpu.fill(1, 1, ScreenWidth, 1, " ")
  189. gpu.setBackground(Color.BottomLineBackground)
  190. gpu.setForeground(Color.BottomLineForeground)
  191. gpu.fill(1, ScreenHeight, ScreenWidth, 1, " ")
  192. end
  193.  
  194.  
  195. -- gui elements
  196. local Element = {}
  197. Element.__index = Element
  198.  
  199. function Element:New(id, x, y, w, h, text, callback)
  200. element = setmetatable({
  201. id = id or "unknown", -- id for identification of type, eg. label, button
  202. x = x or 1,
  203. y = y or 1,
  204. w = w or 1,
  205. h = h or 1,
  206. text = text,
  207. alignment = "left",
  208. autoWordWrap = false,
  209. protected = false, -- use for inputs to set asterix as letter (password input)
  210. background = nil,
  211. foreground = nil,
  212. callback = callback or nil, -- callback that's called when element is clicked
  213. drawCallback = nil, -- callback for draw function
  214. handleCallback = nil, -- callback for handling the element
  215. activeBackground = nil, -- colors for clicked
  216. activeForeground = nil,
  217. isActive = false,
  218. max = 0,
  219. min = 0,
  220. value = 0,
  221. steps = 1,
  222. state = false, -- can be used for checkboxes
  223. data = {}, -- used for element groups, like radio bottons
  224. selected = 1, -- for selected elements in groups
  225. first = 1,
  226. last = 1,
  227. type = 1, -- if there are differend types of the element, like lines (small or double)
  228. ignoreMouseBlock = false, -- if set to true, element will ignore the mouse block function
  229. userData1 = {},
  230. userData2 = {}, -- extra space for user created elements
  231. userData3 = {},
  232. },Element)
  233. return element
  234. end
  235.  
  236. local function correctPos(win, self)
  237. local x = self.x + win.x
  238. local y = self.y + win.y
  239. local w = self.w - 1
  240. local h = self.h
  241.  
  242. while x + w > win.x + win.w - 1 do -- element is too long
  243. w = w - 1
  244. end
  245. if w < 0 then
  246. w = 0
  247. end
  248. while y + h > win.y + win.h do -- element is too long
  249. h = h - 1
  250. end
  251. if h < 0 then
  252. h = 0
  253. end
  254. return x, y, w, h
  255. end
  256.  
  257.  
  258. function checkElementTouch(x, y, b, win, self)
  259. for j = 1, #win.elements do
  260. if win.elements[j].isActive == true then
  261. return
  262. end
  263. end
  264. local sx, sy, sw, sh = correctPos(win, self)
  265. if x >= sx and x <= sx + sw and x < win.x + win.w - 1 then
  266. if y >= sy and y <= sy + sh - 1 then
  267. if self.handleCallback then
  268. if self.handleCallback(win, self, x, y, b) == false then -- first the handle callback for further actions
  269. return -- we get out, if the handle callback gives a false back. no user callback then
  270. end
  271. end
  272. if self.callback then
  273. if blockMouse == false or self.ignoreMouseBlock == true then
  274. self.callback(self, win) -- second the user callback
  275. end
  276. end
  277. end
  278. end
  279. end
  280.  
  281.  
  282.  
  283.  
  284.  
  285. -- for the window list menu
  286. local windowListMenu = {}
  287.  
  288. -- Window stuff
  289. local Window = {}
  290. Window.__index = Window
  291.  
  292. local WindowList = {}
  293.  
  294.  
  295. local function redrawAllWindows()
  296. for i = 1, #WindowList do
  297. if WindowList[i].lowered == false then-- don't display lowered windows
  298. WindowList[i]:draw()
  299. end
  300. end
  301. end
  302.  
  303. local function resortWindows()
  304. for i = 1, #WindowList do
  305. WindowList[i].id = i -- resort the id values
  306. end
  307. end
  308.  
  309. function Window:New(x, y, w, h, text)
  310. window = setmetatable({
  311. x = x,
  312. y = y + 1, -- start under the top line
  313. w = w,
  314. h = h,
  315. text = text,
  316. id = #WindowList + 1,
  317. lowered = true,
  318. buffer = {},
  319. buffer2 = {},
  320. moving = false,
  321. elements = {},
  322. disableButtons = false,
  323. sticky = false,
  324. hide = false,
  325. onCloseCallback = nil,
  326. onLowerCallback = nil,
  327. onTop = false,
  328. refesh = true,
  329. }, Window)
  330. table.insert(WindowList, window)
  331. return window
  332. end
  333.  
  334. function Window:saveBackground()
  335. self.buffer = {} -- clear the buffer
  336. -- for the active window we save the whole background, if it is not moving, or lowered
  337. --[[
  338. if self.id == #WindowList and self.moving == false and self.lowered == false then
  339. for i = 1, self. w do
  340. self.buffer[i] = {}
  341. for j = 1, self.h + 1 do
  342. local c, fg, bg = gpu.get(self.x + i - 1, self.y + j - 1)
  343. self.buffer[i][j] = {["c"] = c, ["fg"] = fg, ["bg"] = bg}
  344. end
  345. end
  346. elseif self.id == #WindowList then
  347. ]]--
  348. for x = self.x, self.x + self.w do
  349. local c, fg, bg = gpu.get(x, self.y)
  350. table.insert(self.buffer, {c, fg, bg}) -- insert the character and colors into the buffer
  351. end
  352. -- end
  353. end
  354.  
  355. function Window:restoreBackground()
  356. -- for the active window we restore the whole background, if it is not moving or lowered
  357. --[[
  358. if self.id == #WindowList and self.moving == false and self.lowered == false then
  359. local oldBG = -1
  360. local oldFG = -1
  361. for i = 1, self.w do
  362. for j = 1, self.h + 1 do
  363. if oldBG ~= self.buffer[i][j].bg then
  364. gpu.setBackground(self.buffer[i][j].bg)
  365. oldBG = self.buffer[i][j].bg
  366. end
  367. if oldFG ~= self.buffer[i][j].fg then
  368. gpu.setForeground(self.buffer[i][j].fg)
  369. oldFG = self.buffer[i][j].fg
  370. end
  371. gpu.set(self.x + i - 1, self.y + j - 1, self.buffer[i][j].c)
  372. end
  373. end
  374. elseif self.id == #WindowList then
  375. ]]--
  376. local oldFG, oldBG
  377. for x, value in pairs(self.buffer) do
  378. local bg = value[3]
  379. local fg = value[2]
  380. if oldBG ~= bg then
  381. gpu.setBackground(bg)
  382. oldBG = bg
  383. end
  384. if oldFG ~= fg then
  385. gpu.setForeground(fg)
  386. oldFG = fg
  387. end
  388. gpu.set(self.x + x -1, self.y, value[1])
  389. end
  390. -- end
  391. end
  392.  
  393. function Window:draw()
  394. -- check size of window depending an screen an correct the position if outside
  395. if self.y < 2 then -- no window on top line of screen
  396. self.y = 2
  397. end
  398. if self.x < 1 then
  399. self.x = 1
  400. end
  401. if self.x + self.w > ScreenWidth then
  402. self.x = ScreenWidth - self.w
  403. end
  404. if useWindowShadows == true then
  405. if self.y + self.h > ScreenHeight - 2 then
  406. self.y = ScreenHeight - 2 - self.h -- we need the bottom line of screen for window manager
  407. end
  408. else
  409. if self.y + self.h > ScreenHeight - 1 then
  410. self.y = ScreenHeight - 1 - self.h -- we need the bottom line of screen for window manager
  411. end
  412. end
  413. -- save the background of the top line for moving
  414. self:saveBackground()
  415. -- color of top line depends if window is on top or in background
  416. if self.id == #WindowList then
  417. gpu.setForeground(Color.WindowActiveFrameForeground)
  418. gpu.setBackground(Color.WindowActiveFrameBackground)
  419. else
  420. gpu.setForeground(Color.WindowInactiveFrameForeground)
  421. gpu.setBackground(Color.WindowInactiveFrameBackground)
  422. end
  423. -- display the top line of the window
  424. gpu.fill(self.x, self.y, self.w, 1, " ")
  425. if string.len(self.text) <= self.w - 3 then
  426. gpu.set(self.x + math.floor((self.w/2) - (string.len(self.text)/2)), self.y, self.text)
  427. else
  428. gpu.set(self.x +1, self.y, string.sub(self.text,1, self.w - 3))
  429. end
  430. if self.sticky == false then
  431. gpu.set(self.x, self.y, "#")
  432. end
  433. if self.disableButtons == false then
  434. gpu.set(self.x + self.w - 2, self.y, "_X")
  435. end
  436. if self.moving == false then
  437. -- fill the window main body
  438. gpu.setBackground(Color.WindowBackground)
  439. gpu.setForeground(Color.Frame)
  440. gpu.fill(self.x, self.y + 1, self.w, self.h, " ")
  441. -- paint the frame
  442. gpu.fill(self.x, self.y + 1, 1, self.h - 1, unicode.char(windowFrame[2]))
  443. gpu.fill(self.x + self.w - 1, self.y + 1, 1, self.h - 1, unicode.char(windowFrame[2]))
  444. gpu.fill(self.x + 1, self.y + self.h, self.w - 2, 1, unicode.char(windowFrame[1]))
  445. gpu.set(self.x, self.y + self.h, unicode.char(windowFrame[5]))
  446. gpu.set(self.x + self.w - 1, self.y + self.h, unicode.char(windowFrame[6]))
  447. if useWindowShadows == true then
  448. gpu.setForeground(Color.Shadow)
  449. gpu.setBackground(Color.Shadow)
  450. gpu.fill(self.x + 1, self.y + self.h + 1, self.w - 1, 1, " ")
  451. gpu.fill(self.x + self.w, self.y + 1, 1, self.h + 1, " ")
  452. if useBoxShadows == true then
  453. _, _, Background, _ = gpu.get(self.x + self.w, self.y)
  454. gpu.setBackground(Background)
  455. gpu.set(self.x + self.w, self.y, unicode.char(0x25E3))
  456. _, _, Background, _ = gpu.get(self.x, self.y + self.h + 1)
  457. gpu.setBackground(Background)
  458. gpu.set(self.x, self.y + self.h + 1, unicode.char(0x25E5))
  459. end
  460.  
  461. end
  462. -- redraw all elements in window
  463. for i = 1, #self.elements do
  464. self.elements[i].drawCallback(self, self.elements[i]) -- each element has his own callback for drawing it
  465. end
  466. end
  467. end
  468.  
  469. -- checks if window is touched and raise it, if it is not the top one
  470. function Window:onTouch(x, y, b)
  471. if self.lowered == true then
  472. return false
  473. end
  474.  
  475. for key, value in pairs(self.elements) do
  476. if x >= self.x and x <= self.x + self.w - 1 and self.moving == false then
  477. if y >= self.y and y <= self.y + self.h then
  478. if self.id < #WindowList then
  479. if blockMouse == false then
  480. wm.raiseWindow(self)
  481. end
  482. end
  483. checkElementTouch(x, y, b, self, value)
  484. end
  485. end
  486. end
  487.  
  488. if blockMouse == true then
  489. return true
  490. end
  491. -- check if one of the window buttons is clicked (lower or close)
  492. if x == self.x + self.w - 1 and y == self.y and self.moving == false and self.disableButtons == false then -- close button
  493. wm.closeWindow(self)
  494. return true
  495. elseif x == self.x + self.w - 2 and y == self.y and self.moving == false and self.disableButtons == false then -- lower button
  496. wm.lowerWindow(self)
  497. return true
  498. elseif x == self.x and y == self.y and self.sticky == false then -- then movement button
  499. self.moving = not self.moving -- switch movemnt mode of window
  500. wm.raiseWindow(self)
  501. return true
  502. end
  503.  
  504. if x >= self.x and x <= self.x + self.w - 1 and self.moving == false then
  505. if y >= self.y and y <= self.y + self.h then
  506. if self.id < #WindowList then
  507. -- window is lower, then the top one. raise it top level
  508. wm.raiseWindow(self)
  509. return true
  510. else
  511. return true
  512. end
  513. end
  514. end
  515.  
  516.  
  517. return false
  518. end
  519.  
  520. function Window:move(x, y)
  521. self.x = x
  522. self.y = y
  523. end
  524.  
  525. -- top and bottom stuff
  526. local symbolList = {}
  527. local Symbol = {}
  528. Symbol.__index = Symbol
  529.  
  530. function Symbol:New(x, y, icon, program, level, w)
  531. symbol = setmetatable({
  532. x = x,
  533. y = y,
  534. level = level or 0,
  535. icon = icon or "?",
  536. w = w or 1,
  537. program = loadfile(program),
  538. runningState = false,
  539. },Symbol)
  540. table.insert(symbolList, symbol)
  541. if symbolList[#symbolList].program and symbolList[#symbolList].runningState == false then
  542. symbolList[#symbolList].program(#symbolList, "load", 0, symbolList[#symbolList].icon)
  543. end
  544. end
  545.  
  546. local function drawSymbols()
  547. gpu.setBackground(Color.BottomLineBackground)
  548. gpu.setForeground(Color.BottomLineForeground)
  549. for i = 1, #symbolList do
  550. gpu.set(symbolList[i].x, symbolList[i].y, symbolList[i].icon)
  551. end
  552. end
  553.  
  554. function symbolTouchCheck(x, y, b)
  555. if blockMouse == true then
  556. return
  557. end
  558. for i = 1, #symbolList do
  559. if x <= symbolList[i].x + symbolList[i].w - 1 and x >= symbolList[i].x and y == symbolList[i].y then
  560. if symbolList[i].program and symbolList[i].runningState == false then
  561. if userLevel >= symbolList[i].level then
  562. symbolList[i].program(i, "execute", math.floor(b), symbolList[i].icon)
  563. end
  564. end
  565. end
  566. end
  567. end
  568.  
  569. function wm.newSymbol(icon, program, level)
  570. local w = string.len(icon)
  571. if w < 1 then
  572. w = 1
  573. end
  574. for i = 1, #symbolList do
  575. w = w + symbolList[i].w
  576. end
  577. local x = ScreenWidth - w + 1
  578. local y = ScreenHeight
  579. l = string.len(icon)
  580. if l < 1 then
  581. l = 1
  582. end
  583. ret = Symbol:New(x, y, icon, program, level, l)
  584. drawSymbols()
  585. return ret
  586. end
  587.  
  588. function wm.setSymbolSize(id, size)
  589. local w = size
  590. for i = 1, #symbolList do
  591. if i ~= id then
  592. w = w + symbolList[i].w
  593. end
  594. end
  595. symbolList[id].w = size
  596. symbolList[id].x = ScreenWidth - w + 1
  597. drawSymbols()
  598. end
  599.  
  600. function wm.setIcon(id, icon)
  601. symbolList[id].icon = icon
  602. drawSymbols()
  603. end
  604.  
  605. function wm.setSymbolProgram(self, program)
  606. self.program = loadfile(program)
  607. end
  608.  
  609. function wm.drawSymbol(id, c)
  610. gpu.setBackground(Color.BottomLineBackground)
  611. if c then
  612. gpu.setForeground(c)
  613. else
  614. gpu.setForeground(Color.BottomLineForeground)
  615. end
  616. gpu.set(symbolList[id].x, symbolList[id].y, symbolList[id].icon)
  617. end
  618.  
  619. function wm.getSymbolPos(id)
  620. return symbolList[id].x, symbolList[id].y
  621. end
  622.  
  623. function wm.setRunningState(num, state)
  624. symbolList[num].runningState = state
  625. end
  626.  
  627. -- menu stuff
  628. local Menu = {}
  629. Menu.__index = Menu
  630.  
  631. local MenuList = {}
  632. local menuIsActive = 0
  633.  
  634. function Menu:New(x, y, w, text, callback)
  635. menu = setmetatable({
  636. id = #MenuList + 1,
  637. x = x,
  638. y = y,
  639. w = w,
  640. text = text,
  641. entries = {},
  642. selected = 1,
  643. callback = callback,
  644. useFrame = false,
  645. buffer = {}
  646. }, Menu)
  647. for i = 1, w + 2 do
  648. menu.buffer[i] = {}
  649. for j = 1, 20 do
  650. menu.buffer[i][j] = { ["bg"] = 0, ["fg"] = 0, ["ch"] = " " }
  651. end
  652. end
  653. table.insert(MenuList, menu) -- just for loop over all menus
  654. return menu
  655. end
  656.  
  657. function menuSaveBackground(self)
  658. local w = self.w
  659. local h = #self.entries
  660. if self.useFrame == true then
  661. h = h + 2
  662. -- needed if menu list is empty
  663. if h == 2 then
  664. return
  665. end
  666. end
  667. if h == 0 then
  668. return
  669. end
  670. for i = 1, w do
  671. for j = 1, h do
  672. local ch, fg, bg = gpu.get(self.x + i - 1, self.y + j - 1)
  673. self.buffer[i][j] = { ["bg"] = bg, ["fg"] = fg, ["ch"] = ch }
  674. end
  675. end
  676. end
  677.  
  678. function restoreMenuBackground(self)
  679. local oldBG, oldFG
  680. local w = self.w
  681. local h = #self.entries
  682. if self.useFrame == true then
  683. h = h + 2
  684. -- needed if menu list is empty
  685. if h == 2 then
  686. return
  687. end
  688. end
  689. if h == 0 then
  690. return
  691. end
  692. for i = 1, w do
  693. for j = 1, h do
  694. if oldBG ~= self.buffer[i][j].bg then
  695. gpu.setBackground(self.buffer[i][j].bg)
  696. oldBG = self.buffer[i][j].bg
  697. end
  698. if oldFG ~= self.buffer[i][j].fg then
  699. oldFG = self.buffer[i][j].fg
  700. end
  701. gpu.set(self.x + i - 1, self.y + j - 1, self.buffer[i][j].ch)
  702. end
  703. end
  704. end
  705.  
  706. function Menu:draw()
  707. if #self.entries == 0 then
  708. return
  709. end
  710. if self.x <= 1 then
  711. self.x = 1
  712. end
  713. if self.x + self.w > ScreenWidth then
  714. self.x = ScreenWidth - self.w
  715. end
  716. if self.y < 2 then
  717. self.y = 2
  718. end
  719. if self.useFrame == true then
  720. if self.y + #self.entries + 2 > ScreenHeight then
  721. self.y = ScreenHeight - #self.entries - 2
  722. end
  723. else
  724. if self.y + #self.entries > ScreenHeight then
  725. self.y = ScreenHeight - #self.entries
  726. end
  727. end
  728. menuSaveBackground(self)
  729. for i = 1, #self.entries do
  730. if i == self.selected then
  731. gpu.setBackground(Color.MenuSelectedBackground)
  732. gpu.setForeground(Color.MenuSelectedForeground)
  733. else
  734. gpu.setBackground(Color.MenuBackground)
  735. gpu.setForeground(Color.MenuForeground)
  736. end
  737. if self.useFrame == true then
  738. gpu.fill(self.x + 1, self.y + i, self.w - 2, 1, " ")
  739. gpu.set(self.x + 1, self.y + i, string.sub(self.entries[i], 1, self.w - 2))
  740. -- start frame
  741. gpu.setBackground(Color.MenuBackground)
  742. gpu.setForeground(Color.MenuForeground)
  743. gpu.set(self.x, self.y + i, unicode.char(menuFrame[2]))
  744. gpu.set(self.x + self.w - 1, self.y + i, unicode.char(menuFrame[2]))
  745. gpu.set(self.x, self.y, unicode.char(menuFrame[3]))
  746. gpu.set(self.x + self.w - 1, self.y, unicode.char(menuFrame[4]))
  747. gpu.set(self.x, self.y + #self.entries + 1, unicode.char(menuFrame[5]))
  748. gpu.set(self.x + self.w - 1, self.y + #self.entries + 1, unicode.char(menuFrame[6]))
  749. else
  750. gpu.fill(self.x , self.y + i - 1, self.w, 1, " ")
  751. gpu.set(self.x, self.y + i - 1, string.sub(self.entries[i], 1, self.w - 1))
  752. end
  753. end
  754. if self.useFrame == true then
  755. gpu.fill(self.x + 1, self.y, self.w - 2, 1, unicode.char(menuFrame[1]))
  756. gpu.fill(self.x + 1, self.y + #self.entries + 1, self.w - 2, 1, unicode.char(menuFrame[1]))
  757. gpu.set(self.x + math.floor(self.w/2) - math.floor(string.len(self.text)/2), self.y, self.text)
  758. end
  759. end
  760.  
  761. function Menu:onTouch(x, y, b)
  762. if blockMouse == true then
  763. return
  764. end
  765. if b == 0 then -- menus will only accept left mouse button
  766. -- touch is inside menu
  767. if x >= self.x and x <= self.x + self.w - 1 then
  768. if y >= self.y and y <= self.y + #self.entries then
  769. -- FIXME: Need to be redone, because sometimes the wrong window is selected if menu is shown over a window.
  770. --Then the window under the menu will become the active one
  771. if self.useFrame == true then
  772. self.selected = y - self.y
  773. -- restoreMenuBackground(self)
  774. self:draw()
  775. os.sleep(0.1) -- give user a chance to see the click :-)
  776. -- restoreMenuBackground(self)
  777. self.callback(y - self.y)
  778. else
  779. self.selected = y - self.y + 1
  780. -- restoreMenuBackground(self)
  781. self:draw()
  782. os.sleep(0.1) -- give user a chance to see the click :-)
  783. -- restoreMenuBackground(self)
  784. self.callback(y - self.y + 1)
  785. end
  786. end
  787. else
  788. -- restoreMenuBackground(self)
  789. end
  790. else
  791. -- restoreMenuBackground(self)
  792. end
  793. -- at last deactivate menu and get back to window handling
  794. menuIsActive = 0
  795. clearScreen()
  796. redrawAllWindows()
  797. end
  798.  
  799.  
  800. -- screen event handling
  801. function screenTouchCheck(x, y, b)
  802. if blockMouse == false then
  803. if y > 1 and y < ScreenHeight then -- ignore touch on top or bottom line
  804. if b == 1 then -- right mouse button opens window list
  805. wm.clearMenu(windowListMenu)
  806. wm.menuSetPosition(windowListMenu, x, y)
  807. for i = 1, #WindowList do
  808. if WindowList[i].hide == false then -- hide windows will not shown in window list
  809. if WindowList[i].lowered == true then
  810. wm.insertMenu(windowListMenu, "-" .. WindowList[i].text)
  811. else
  812. wm.insertMenu(windowListMenu, " " .. WindowList[i].text)
  813. end
  814. end
  815. end
  816. wm.drawMenu(windowListMenu)
  817. end
  818. end
  819. end
  820. end
  821.  
  822. local systemMenu = {}
  823. local systemMenuState = false
  824. local systemMenuEnabled = true
  825. local systemMenuPos = 1
  826.  
  827. local systemMenuList = {}
  828. local SystemMenuElement = {}
  829. SystemMenuElement.__index = SystemMenuElement
  830.  
  831. local function drawSystemMenu()
  832. if systemMenuEnabled == true then
  833. if systemMenuState == false then
  834. gpu.setBackground(Color.systemMenuBackground)
  835. gpu.setForeground(Color.systemMenuForeground)
  836. elseif systemMenuState == true then
  837. gpu.setBackground(Color.systemMenuActiveBackground)
  838. gpu.setForeground(Color.systemMenuActiveForeground)
  839. end
  840. gpu.set(systemMenuPos, 1, "[system]")
  841. end
  842. end
  843.  
  844.  
  845. function SystemMenuElement:New(name, path, param, level, Type)
  846. sm = setmetatable ({
  847. name = name,
  848. path = path,
  849. level = level or 0,
  850. isActive = false,
  851. Type = Type or 0,
  852. param = param or nil,
  853. },SystemMenuElement)
  854. wm.insertMenu(systemMenu, name)
  855. table.insert(systemMenuList, sm)
  856. wm.menuSetPosition(systemMenu, systemMenuPos - 10, 1)
  857. drawSystemMenu()
  858. return sm
  859. end
  860.  
  861. function systemmenuTouchCheck(x, y, b)
  862. if blockMouse == true then
  863. return
  864. end
  865. if y == 1 and x >= systemMenuPos and x <= systemMenuPos + 7 then -- menu clicked
  866. systemMenuState = not systemMenuState
  867. drawSystemMenu()
  868. if systemMenuState == true then
  869. wm.drawMenu(systemMenu)
  870. end
  871. end
  872. end
  873.  
  874. function wm.addSystemMenu(name, path, param, level, Type)
  875. SystemMenuElement:New(name, path, param, level, Type)
  876. end
  877.  
  878. local function systemMenuCallback(entry)
  879. systemMenuState = false
  880. drawSystemMenu()
  881. if systemMenuList[entry].isActive == false then
  882. systemMenuList[entry].isActive = true
  883. if userLevel >= systemMenuList[entry].level then
  884. if systemMenuList[entry].Type == 0 then
  885. wm.startProgram(systemMenuList[entry].path, entry)(systemMenuList[entry].param)
  886. elseif systemMenuList[entry].Type == 1 then
  887. systemMenuList[entry].path(systemMenuList[entry].param)
  888. end
  889. end
  890. end
  891. end
  892.  
  893. function wm.enableSytemMenu(state)
  894. systemMenuEnabled = state
  895. end
  896.  
  897. function wm.setSystemMenuPos(pos)
  898. if pos == "left" then
  899. systemMenuPos = 1
  900. elseif pos == "right" then
  901. systemMenuPos = ScreenWidth - 8
  902. end
  903. end
  904.  
  905. local startMenu = {}
  906. local startMenuState = false
  907. local startMenuEnabled = true
  908.  
  909. local startMenuList = {}
  910. local StartMenuElement = {}
  911. StartMenuElement.__index = StartMenuElement
  912.  
  913. local function drawStartMenu()
  914. if startMenuEnabled == true then
  915. if startMenuState == false then
  916. gpu.setBackground(Color.startMenuBackground)
  917. gpu.setForeground(Color.startMenuForeground)
  918. elseif startMenuState == true then
  919. gpu.setBackground(Color.startMenuActiveBackground)
  920. gpu.setForeground(Color.startMenuActiveForeground)
  921. end
  922. gpu.set(2, ScreenHeight, "[start]")
  923. end
  924. end
  925.  
  926.  
  927. function StartMenuElement:New(name, path, param, level, Type)
  928. sm = setmetatable ({
  929. name = name,
  930. path = path,
  931. level = level or 0,
  932. isActive = false,
  933. Type = Type or 0,
  934. param = param or nil,
  935. },StartMenuElement)
  936. wm.insertMenu(startMenu, name)
  937. table.insert(startMenuList, sm)
  938. wm.menuSetPosition(startMenu, 2, ScreenHeight - 2 - #startMenuList)
  939. drawStartMenu()
  940. return sm
  941. end
  942.  
  943. function startmenuTouchCheck(x, y, b)
  944. if blockMouse == true then
  945. return
  946. end
  947. if y == ScreenHeight and x >= 1 and x <= 7 then -- start clicked
  948. startMenuState = not startMenuState
  949. drawStartMenu()
  950. if startMenuState == true then
  951. wm.drawMenu(startMenu)
  952. end
  953. end
  954. end
  955.  
  956. function wm.addStartMenu(name, path, param, level, Type)
  957. StartMenuElement:New(name, path, param, level, Type)
  958. end
  959.  
  960. local function startMenuCallback(entry)
  961. startMenuState = false
  962. drawStartMenu()
  963. if startMenuList[entry].isActive == false then
  964. startMenuList[entry].isActive = true
  965. if userLevel >= startMenuList[entry].level then
  966. if startMenuList[entry].Type == 0 then
  967. wm.startProgram(startMenuList[entry].path, entry)(startMenuList[entry].param)
  968. elseif startMenuList[entry].Type == 1 then
  969. startMenuList[entry].path(startMenuList[entry].param)
  970. end
  971. end
  972. end
  973. end
  974.  
  975. function wm.shutdown(reboot)
  976. computer.shutdown(reboot)
  977. end
  978.  
  979. function wm.exitProgram(id)
  980. startMenuList[id].isActive = false
  981. end
  982.  
  983. function wm.enableStartMenu(state)
  984. startMenuEnabled = state
  985. end
  986.  
  987. function wm.clearStartMenu()
  988. startMenuList = {}
  989. wm.clearMenu(startMenu)
  990. end
  991.  
  992. -- event listeners
  993.  
  994. -- the touch event handler it self
  995. local function TouchEventListener(_, _, x, y, b)
  996. if menuIsActive == 0 then -- if a menu is running, no window management
  997. local wasWindowAction = false
  998. -- needs to be backwards, because top window is allways last in list
  999. for i = #WindowList, 1, -1 do
  1000. -- window touch returns true, if window is on top
  1001. if WindowList[i]:onTouch(x, y, b) == true then
  1002. wasWindowAction = true -- needed for on screen clicks, if click was inside any window
  1003. break
  1004. end
  1005. end
  1006. if wasWindowAction == false then -- the click was somewhere on the screen, outside a window
  1007. if systemMenuState == true then
  1008. restoreMenuBackground(systemMenu)
  1009. systemMenuState = false
  1010. drawSystemMenu()
  1011. end
  1012. if startMenuState == true then
  1013. restoreMenuBackground(startMenu)
  1014. startMenuState = false
  1015. drawStartMenu()
  1016. end
  1017. screenTouchCheck(x, y, b)
  1018. end
  1019. elseif menuIsActive > 0 then
  1020. -- handle menu touch
  1021. if systemMenuState == true then
  1022. restoreMenuBackground(systemMenu)
  1023. systemMenuState = false
  1024. drawSystemMenu()
  1025. end
  1026. if startMenuState == true then
  1027. restoreMenuBackground(startMenu)
  1028. startMenuState = false
  1029. drawStartMenu()
  1030. end
  1031. MenuList[menuIsActive]:onTouch(x, y, b)
  1032. end
  1033. -- bottom line check
  1034. if y == ScreenHeight then
  1035. if systemMenuState == true then
  1036. restoreMenuBackground(systemMenu)
  1037. systemMenuState = false
  1038. drawSystemMenu()
  1039. end
  1040. if x > 10 then
  1041. symbolTouchCheck(x, y, b)
  1042. elseif startMenuEnabled == true then
  1043. startmenuTouchCheck(x, y, b)
  1044. end
  1045. elseif y == 1 then
  1046. if startMenuState == true then
  1047. restoreMenuBackground(startMenu)
  1048. startMenuState = false
  1049. drawStartMenu()
  1050. end
  1051. systemmenuTouchCheck(x, y, b)
  1052. end
  1053. end
  1054.  
  1055. local function DragEventListener(_, _, x, y, b)
  1056. if blockMouse == false then
  1057. if WindowList[#WindowList].moving == true then
  1058. WindowList[#WindowList]:restoreBackground()
  1059. WindowList[#WindowList]:move(x, y)
  1060. WindowList[#WindowList]:draw()
  1061. -- clearScreen()
  1062. -- AllWindows()
  1063. end
  1064. end
  1065. end
  1066.  
  1067. local function DropEventListener(_, _, x, y, b)
  1068. if blockMouse == false then
  1069. WindowList[#WindowList].moving = false
  1070. WindowList[#WindowList]:draw()
  1071. end
  1072. end
  1073.  
  1074.  
  1075. local DriverList = {}
  1076. local Driver = {}
  1077. Driver.__index = Driver
  1078.  
  1079. function Driver:New(name, description, copyright, version)
  1080. driver = setmetatable({
  1081. id = #DriverList + 1,
  1082. name = name,
  1083. description = description or "",
  1084. copyright = copyright or "",
  1085. version = version or "0.0"
  1086. },Driver)
  1087. table.insert(DriverList, driver)
  1088. return driver
  1089. end
  1090.  
  1091. dotPosition = ScreenWidth
  1092.  
  1093. function wm.registerDriver(name, description, copyright, version)
  1094. Driver:New(name, description, copyright, version)
  1095. dotPosition = dotPosition - 1
  1096. return dotPosition
  1097. end
  1098.  
  1099. function wm.getDriverList()
  1100. return DriverList
  1101. end
  1102.  
  1103. local function autoUpdateTimerCallback()
  1104. MultiThread()
  1105. end
  1106.  
  1107.  
  1108. -- General functions
  1109. function wm.getActiveWindow()
  1110. return WindowList[#WindowList]
  1111. end
  1112.  
  1113. function wm.blockMouse(state)
  1114. blockMouse = state
  1115. end
  1116.  
  1117. function windowMenuListCallback(entry)
  1118. wm.raiseWindow(WindowList[entry])
  1119. end
  1120.  
  1121. local timerEventTimer
  1122.  
  1123. function wm.startProgram(path, id)
  1124. local program = loadfile(path)(id)
  1125. local th = wm.threadCreate(program)
  1126. end
  1127.  
  1128. -- must be called once before using the gui
  1129. function wm.startGui()
  1130. gpu.setBackground(color.black)
  1131. gpu.setForeground(color.white)
  1132. gpu.fill(1, 1, ScreenWidth, ScreenHeight, " ")
  1133. gpu.set(1,1,"Starting windowmanager")
  1134. clearScreen()
  1135. drawScreen()
  1136.  
  1137. -- build up the empty menu for the window list menu
  1138. windowListMenu = wm.newMenu(1, 1, 20, "Window list", windowMenuListCallback) -- x and y will be changed later
  1139. if startMenuEnabled == true then
  1140. startMenu = wm.newMenu(1, ScreenHeight, 20, "", startMenuCallback)
  1141. wm.menuUseFrame(startMenu, true)
  1142. end
  1143. if systemMenuEnabled == true then
  1144. systemMenu = wm.newMenu(1, 1, 20, "", systemMenuCallback)
  1145. wm.menuUseFrame(systemMenu, true)
  1146. end
  1147. wm.menuUseFrame(windowListMenu, true)
  1148.  
  1149. redrawAllWindows()
  1150.  
  1151.  
  1152. event.listen("touch", TouchEventListener)
  1153. event.listen("drag", DragEventListener)
  1154. event.listen("drop", DropEventListener)
  1155. autoUpdateTimer = event.timer(0.1, autoUpdateTimerCallback, math.huge)
  1156. threadInit()
  1157.  
  1158. end
  1159.  
  1160. function wm.exitGui()
  1161. gpu.setBackground(color.black)
  1162. gpu.setForeground(color.white)
  1163. gpu.fill(1, 1, ScreenWidth, ScreenHeight, " ")
  1164. gpu.set(1, 1, "Stopping event listeners ")
  1165. event.ignore("touch", TouchEventListener)
  1166. event.ignore("drag", DragEventListener)
  1167. event.ignore("drop", DropEventListener)
  1168. event.cancel(autoUpdateTimer)
  1169. gpu.set(26, 1, "ok")
  1170. local d = 12
  1171. gpu.set(1,2, "Cleaning up")
  1172. for i = #WindowList, 1, -1 do
  1173. table.remove(WindowList, i)
  1174. gpu.set(d, 2, ".")
  1175. d = d + 1
  1176. end
  1177. for i = #symbolList, 1, -1 do
  1178. if symbolList[i].program then
  1179. symbolList[i].program(i, "unload", 0, symbolList[i].icon)
  1180. symbolList[i].program = nil
  1181. end
  1182. table.remove(symbolList, i)
  1183. gpu.set(d, 2, ".")
  1184. d = d + 1
  1185. end
  1186. gpu.set(d, 2, "ok")
  1187. gpu.set(1,3, "Gui stopped")
  1188. gpu.set(1,4, "You better reboot now :-)")
  1189. os.exit()
  1190. end
  1191.  
  1192. function wm.setTopText(text)
  1193. gpu.setBackground(Color.TopLineBackground)
  1194. gpu.setForeground(Color.TopLineForeground)
  1195. gpu.fill(1, 1, ScreenWidth, 1, " ")
  1196. gpu.set(math.floor(ScreenWidth/2) - math.floor(string.len(text)/2), 1, text)
  1197. end
  1198.  
  1199.  
  1200. function wm.getColors()
  1201. return Color
  1202. end
  1203.  
  1204. function wm.getVersion()
  1205. return versionMajor, versionMinor, versionState
  1206. end
  1207.  
  1208. function wm.getWindowFrame()
  1209. return windowFrame
  1210. end
  1211.  
  1212. function wm.setWindowFrame(num)
  1213. if num == 1 then
  1214. windowFrame = frame.Small
  1215. elseif num == 2 then
  1216. windowFrame = frame.Double
  1217. elseif num == 3 then
  1218. windowFrame = frame.Bold
  1219. elseif num == 4 then
  1220. windowFrame = frame.Flat
  1221. end
  1222. end
  1223.  
  1224. function wm.getShadow()
  1225. return useWindowShadows
  1226. end
  1227.  
  1228. function wm.setShadow(state)
  1229. useWindowShadows = state
  1230. end
  1231.  
  1232. function wm.getMenuFrame()
  1233. return menuFrame
  1234. end
  1235.  
  1236. function wm.setMenuFrame(num)
  1237. if num == 1 then
  1238. menuFrame = frame.Small
  1239. elseif num == 2 then
  1240. menuFrame = frame.Double
  1241. elseif num == 3 then
  1242. menuFrame = frame.Bold
  1243. elseif num == 4 then
  1244. menuFrame = frame.Flat
  1245. end
  1246. end
  1247.  
  1248.  
  1249. -- Window functions
  1250.  
  1251. function wm.getViewport(self)
  1252. return self.x, self.y + 1, self.w - 2, self.h - 1
  1253. end
  1254.  
  1255. function wm.newWindow(x, y, w, h, text)
  1256. return Window:New(x, y, w, h, text)
  1257. end
  1258.  
  1259. -- set a window to top over all other windows
  1260. function wm.raiseWindow(self)
  1261. self.lowered = false
  1262. table.remove(WindowList, self.id) -- remove the window from table
  1263. table.insert(WindowList, self) -- insert window as last in table
  1264. resortWindows()
  1265. for i = #WindowList - 1, 1, -1 do -- take movement of all windows
  1266. WindowList[i].moving = false
  1267. end
  1268. self.onTop = true
  1269. clearScreen()
  1270. redrawAllWindows()
  1271. end
  1272.  
  1273. function wm.closeWindow(self)
  1274. -- self:restoreBackground()
  1275. if self.onCloseCallback then
  1276. if self.onCloseCallback(self) == false then
  1277. return
  1278. end
  1279. end
  1280. table.remove(WindowList, self.id)
  1281. self = nil
  1282. resortWindows()
  1283. clearScreen()
  1284. redrawAllWindows()
  1285. end
  1286.  
  1287. function wm.lowerWindow(self)
  1288. -- self:restoreBackground()
  1289. if self.onLowerCallback then
  1290. if self.onLowerCallback(self) == false then
  1291. return
  1292. end
  1293. end
  1294. self.lowered = true
  1295. for i = #WindowList, 1, -1 do -- raise the next available window from end of list
  1296. if WindowList[i].lowered == false then
  1297. wm.raiseWindow(WindowList[i])
  1298. break
  1299. end
  1300. end
  1301.  
  1302. clearScreen()
  1303. redrawAllWindows()
  1304. end
  1305.  
  1306. function wm.disableWindowButtons(self, state)
  1307. self.disableButtons = state
  1308. end
  1309.  
  1310. function wm.setWindowSticky(self, state)
  1311. self.sticky = state
  1312. end
  1313.  
  1314. function wm.hideWindow(self, state)
  1315. self.hide = state
  1316. end
  1317.  
  1318. function wm.setOnCloseCallback(self, callback)
  1319. self.onCloseCallback = callback
  1320. end
  1321.  
  1322. function wm.setOnLowerCallback(self, callback)
  1323. self.onLowerCallback = callback
  1324. end
  1325.  
  1326. function wm.getWindowInfo(self)
  1327. if self.lowered == false then
  1328. return self.x, self.y, self.w, self.h, self.text, #self.elements
  1329. elseif self.lowered == true then
  1330. return 0, 0, 0, 0, self.text, #self.elements
  1331. end
  1332. end
  1333.  
  1334.  
  1335. function wm.redraw()
  1336. clearScreen()
  1337. redrawAllWindows()
  1338. end
  1339.  
  1340. -- gui elements
  1341. function wm.addElement(self, element)
  1342. table.insert(self.elements, element)
  1343. end
  1344.  
  1345. function wm.newElement(id, x, y, w, h, text, callback)
  1346. return Element:New(id, x, y, w, h, text, callback)
  1347. end
  1348.  
  1349.  
  1350.  
  1351.  
  1352.  
  1353. -- Menu functions
  1354. function wm.newMenu(x, y, w, text, callback)
  1355. return Menu:New(x, y, w, text, callback)
  1356. end
  1357.  
  1358. function wm.insertMenu(self, entry)
  1359. table.insert(self.entries, entry)
  1360. end
  1361.  
  1362. function wm.removeMenu(self, entry)
  1363. table.remove(self.entries, entry)
  1364. end
  1365.  
  1366. function wm.clearMenu(self)
  1367. self.entries = {}
  1368. end
  1369.  
  1370. function wm.setMenuCallback(self, callback)
  1371. self.callback = callback
  1372. end
  1373.  
  1374. function wm.drawMenu(self)
  1375. if menuIsActive ~= self.id and menuIsActive > 0 then
  1376. restoreMenuBackground(MenuList[menuIsActive])
  1377. end
  1378. menuIsActive = self.id
  1379. self.selected = 1
  1380. self:draw()
  1381. end
  1382.  
  1383. function wm.menuSetPosition(self, x, y)
  1384. self.x = x
  1385. self.y = y
  1386. end
  1387.  
  1388. function wm.menuUseFrame(self, state)
  1389. self.useFrame = state
  1390. end
  1391.  
  1392.  
  1393. return wm
Advertisement
Add Comment
Please, Sign In to add comment