zodiak707

widget

Dec 26th, 2020 (edited)
543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.76 KB | None | 0 0
  1. -- Copyright Thomas Bogue 2013
  2. -- This program is free software: you can redistribute it and/or modify
  3. -- it under the terms of the GNU Lesser General Public License as published by
  4. -- the Free Software Foundation, either version 3 of the License, or
  5. -- (at your option) any later version.
  6.  
  7. -- This program is distributed in the hope that it will be useful,
  8. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. -- GNU Lesser General Public License for more details.
  11.  
  12. -- You should have received a copy of the GNU Lesser General Public License
  13. -- along with this program. If not, see <http://www.gnu.org/licenses/>.
  14.  
  15. monitor=nil
  16. defaultButtonBackground=colors.blue
  17. defaultButtonForeground=colors.white
  18. terminalBackground=colors.black
  19. defaultSliderForeground=colors.white
  20. defaultSliderBackground=colors.gray
  21. defaultFlagMonitorForeground=colors.white
  22. defaultProgressBarForeground=colors.white
  23. defaultProgressBarBackground=colors.gray
  24. redrawNeeded=false
  25.  
  26. function version()
  27. return "widget library v1.1"
  28. end
  29.  
  30. local function nop()
  31. end
  32.  
  33. function getMonitor()
  34. return monitor
  35. end
  36.  
  37. function setMonitor(m)
  38. monitor=m
  39. end
  40.  
  41. function getDefaultMonitor()
  42. --print("searching for advanced monitor...")
  43. facings={"top","bottom","right","left","front","back"}
  44. for key,facing in pairs(facings) do
  45. mon=peripheral.wrap(facing)
  46. --print("looking for an advanced monitor " .. facing .. " " .. tostring(mon))
  47. if (mon~=nil) then
  48. --print("peripheral found")
  49. if (mon.setTextColor~=nil) then
  50. --print("monitor found on ".. facing)
  51. return mon
  52. end
  53. end
  54. end
  55. --print("no advanced monitor found. Is this an advanced computer?")
  56. if (term.isColor()) then
  57. print("using the terminal as an advanced computer")
  58. return(term)
  59. else
  60. error("no advanced monitor or advanced computer found. This program requires advanced interface hardward. Please install either an advanced computer or an advanced monitor",0)
  61. end
  62. end
  63.  
  64. function newWidget()
  65. widget={}
  66. widget.draw=nop -- draw(widget)
  67. widget.onClick=nop -- onClick(widget,x,y)
  68. widget.onResize=nop -- onResize(widget)
  69. widget.hWeight=1
  70. widget.vWeight=1
  71. widget.width=nil
  72. widget.height=nil
  73. widget.x1=nil
  74. widget.y1=nil
  75. widget.x2=nil
  76. widget.y2=nil
  77.  
  78. function widget.size(widget)
  79. if (monitor==nil) then
  80. monitor=getDefaultMonitor()
  81. end
  82. widget.width,widget.height=monitor.getSize()
  83. widget.x1=1
  84. widget.y1=1
  85. widget.x2=widget.width
  86. widget.y2=widget.height
  87. widget.onResize(widget)
  88. widget.sized=true
  89. end
  90.  
  91. function widget.run(widget)
  92. if (widget==null) then
  93. error("invalid call to member function widget:run. Did you type widget.run instead?",2)
  94. end
  95. if (widget.sized==true) then
  96. else
  97. widget:size()
  98. end
  99. monitor.setBackgroundColor(terminalBackground)
  100. monitor.clear()
  101. widget:draw()
  102. widget.quit=false
  103. while not widget.quit do
  104. if (monitor==term) then
  105. event,side,x,y=os.pullEvent("mouse_click")
  106. else
  107. event,side,x,y=os.pullEvent("monitor_touch")
  108. end
  109. widget:processEvent(event,side,x,y)
  110. end
  111. monitor.setBackgroundColor(terminalBackground)
  112. monitor.clear()
  113. end
  114.  
  115. function widget.processEvent(widget,event,side,x,y)
  116. if (event=="monitor_touch" or event=="mouse_click") then
  117. widget:onClick(x,y)
  118. if (redrawNeeded) then
  119. monitor.setBackgroundColor(terminalBackground)
  120. monitor.clear()
  121. widget:draw()
  122. end
  123. end
  124. end
  125.  
  126. return(widget)
  127. end
  128.  
  129. function newContainer()
  130. container=newWidget()
  131. container.children={}
  132. container.vSpacingWeight=.1
  133. container.hSpacingWeight=.1
  134.  
  135. function container.draw(container)
  136. for key,child in pairs(container.children) do
  137. child:draw()
  138. end
  139. end
  140.  
  141. function container.onClick(container,x,y)
  142. for key,child in pairs(container.children) do
  143. if x>=child.x1 and x<=child.x2 and y>=child.y1 and y<=child.y2 then
  144. child:onClick(x,y)
  145. end
  146. end
  147. end
  148.  
  149. function container.resizeChildren(container)
  150. for key,child in pairs(container.children) do
  151. child:onResize()
  152. end
  153. end
  154.  
  155. container.onResize=resizeChildren
  156.  
  157. function container.add(container,widget)
  158. if (widget==nil) then
  159. error("attempt to add nil widget to a container. Did you perhaps type row.add when you meant row:add? Or column.add when you meant column:add?",2)
  160. end
  161. container.children[#container.children+1]=widget
  162. end
  163.  
  164. return(container)
  165. end
  166.  
  167. function newButton(label)
  168. button=newWidget()
  169. button.label=label
  170. button.backgroundColor=defaultButtonBackground
  171. button.foregroundColor=defaultButtonForeground
  172. button.labelX=nil
  173. button.labelY=nil
  174.  
  175. function button.drawFull(button)
  176. button.labelX=math.floor((button.x1+button.x2-button.label:len())/2)
  177. button.labelY=(button.y1+button.y2)/2
  178. monitor.setBackgroundColor(button.backgroundColor)
  179. monitor.setTextColor(button.foregroundColor)
  180. for x=button.x1,button.x2 do
  181. for y=button.y1,button.y2 do
  182. monitor.setCursorPos(x,y)
  183. monitor.write(" ")
  184. end
  185. end
  186. monitor.setCursorPos(button.labelX,button.labelY)
  187. monitor.write(button.label)
  188. end
  189.  
  190. function button.drawOutline(button)
  191. button.labelX=math.floor((button.x1+button.x2-button.label:len())/2)
  192. button.labelY=(button.y1+button.y2)/2
  193. monitor.setBackgroundColor(button.backgroundColor)
  194. for x=button.x1,button.x2 do
  195. monitor.setCursorPos(x,button.y1)
  196. monitor.write(" ")
  197. monitor.setCursorPos(x,button.y2)
  198. monitor.write(" ")
  199. end
  200. for y=button.y1+1,button.y2-1 do
  201. monitor.setCursorPos(button.x1,y)
  202. monitor.write(" ")
  203. monitor.setCursorPos(button.x2,y)
  204. monitor.write(" ")
  205. end
  206. monitor.setBackgroundColor(terminalBackground)
  207. for x=button.x1+1,button.x2-1 do
  208. for y=button.y1+1,button.y2-1 do
  209. monitor.setCursorPos(x,y)
  210. monitor.write(" ")
  211. end
  212. end
  213. monitor.setTextColor(button.foregroundColor)
  214. monitor.setCursorPos(button.labelX,button.labelY)
  215. monitor.write(button.label)
  216. end
  217.  
  218. function button.blink(button)
  219. button:drawOutline()
  220. os.sleep(.1)
  221. button:draw()
  222. end
  223.  
  224. button.draw=button.drawFull
  225. return(button)
  226. end
  227.  
  228. function newRow()
  229. row=newContainer()
  230.  
  231. function row.onResize(row)
  232. totalWeight=row.hSpacingWeight*(#row.children-1)
  233. for key,child in pairs(row.children) do
  234. totalWeight=totalWeight+child.hWeight
  235. end
  236. widths={}
  237. totalWidgetWidth=0
  238. for key,child in pairs(row.children) do
  239. widths[key]=math.floor(row.width*child.hWeight/totalWeight)
  240. totalWidgetWidth=totalWidgetWidth+widths[key]
  241. end
  242. remainingWidth=row.width-totalWidgetWidth
  243. if (#row.children>=1) then
  244. separatorWidth=1
  245. else
  246. separatorWidth=math.floor(remainingWidth/(#row.children-1))
  247. end
  248. currentPosition=row.x1 + math.floor((row.width-totalWidgetWidth-separatorWidth*(#row.children-1))/2)
  249. for key,child in pairs(row.children) do
  250. child.x1=currentPosition
  251. child.y1=row.y1
  252. currentPosition=currentPosition+widths[key]-1
  253. child.x2=currentPosition
  254. child.y2=row.y2
  255. currentPosition=currentPosition+separatorWidth+1
  256. child.width=widths[key]
  257. child.height=row.height
  258. end
  259. row:resizeChildren()
  260. end
  261.  
  262. return(row)
  263. end
  264.  
  265. function newColumn()
  266. column=newContainer()
  267.  
  268. function column.onResize(column)
  269. totalWeight=column.vSpacingWeight*(#column.children-1)
  270. for key,child in pairs(column.children) do
  271. totalWeight=totalWeight+child.vWeight
  272. end
  273. widths={}
  274. totalWidgetWidth=0
  275. for key,child in pairs(column.children) do
  276. widths[key]=math.floor(column.height*child.vWeight/totalWeight)
  277. totalWidgetWidth=totalWidgetWidth+widths[key]
  278. end
  279. remainingWidth=column.height-totalWidgetWidth
  280. if (#column.children>=1) then
  281. separatorWidth=1
  282. else
  283. separatorWidth=math.floor(remainingWidth/(#column.children-1))
  284. end
  285. currentPosition=column.y1 + math.floor((column.height-totalWidgetWidth-separatorWidth*(#column.children-1))/2)
  286. for key,child in pairs(column.children) do
  287. child.x1=column.x1
  288. child.y1=currentPosition
  289. currentPosition=currentPosition+widths[key]-1
  290. child.x2=column.x2
  291. child.y2=currentPosition
  292. child.width=column.width
  293. child.height=widths[key]
  294. currentPosition=currentPosition+separatorWidth+1
  295. end
  296. column:resizeChildren()
  297. end
  298.  
  299. return(column)
  300. end
  301.  
  302. function newToggleButton(label)
  303. button=newButton(label)
  304. function button.toggle(button)
  305. button.state=not button.state
  306. button:draw()
  307. end
  308.  
  309. function button.draw(button)
  310. if button.state then
  311. button:drawFull()
  312. else
  313. button:drawOutline()
  314. end
  315. end
  316.  
  317. button.onClick=button.toggle
  318. button.state=false
  319. return(button)
  320. end
  321.  
  322. function newLabel(text)
  323. label=newWidget()
  324. label.text=text
  325. label.textColor=defaultButtonForeground
  326. function label.draw(label)
  327. leftMargin=math.floor((label.width-label.text:len())/2)
  328. rightMargin=label.width-label.text:len()-leftMargin
  329. y=math.floor((label.y1+label.y2)/2)
  330. paddedText=string.rep(" ",leftMargin)..label.text..string.rep(" ",rightMargin)
  331. monitor.setTextColor(label.textColor)
  332. monitor.setCursorPos(label.x1,y)
  333. monitor.write(paddedText)
  334. end
  335.  
  336. return(label)
  337. end
  338.  
  339. function newSlider(min,max)
  340. slider=newWidget()
  341. slider.min=min
  342. slider.max=max
  343. slider.value=min
  344. slider.left=nil
  345. slider.foregroundColor=defaultSliderForeground
  346. slider.backgroundColor=defaultSliderBackground
  347.  
  348. function slider.draw(slider)
  349. range=slider.max-slider.min+1
  350. slider.left=math.floor((slider.x1+slider.x2-range)/2)
  351. margin=slider.left-slider.x1
  352. y=math.floor((slider.y1+slider.y2)/2)
  353. left=slider.value-slider.min+1
  354. right=slider.max-slider.value
  355. monitor.setCursorPos(slider.x1,y)
  356. monitor.setBackgroundColor(terminalBackground)
  357. monitor.write(string.rep(" ",margin))
  358. monitor.setBackgroundColor(slider.foregroundColor)
  359. monitor.write(string.rep(" ",left))
  360. monitor.setBackgroundColor(slider.backgroundColor)
  361. monitor.write(string.rep(" ",right))
  362. monitor.setBackgroundColor(terminalBackground)
  363. monitor.setTextColor(slider.foregroundColor)
  364. tag=" "..tostring(slider.value*25)
  365. roomleft=slider.width-margin-range-tag:len()
  366. if (roomleft>=0) then
  367. monitor.write(tag..string.rep(" ",slider.width-margin-tag:len()-range))
  368. end
  369. end
  370.  
  371. function slider.onClick(slider,x,y)
  372. slider.value=x-slider.left+slider.min
  373. if (slider.value<slider.min) then
  374. slider.value=slider.min
  375. else
  376. if (slider.value>slider.max) then
  377. slider.value=slider.max
  378. end
  379. end
  380. slider:draw()
  381. end
  382.  
  383. slider.adjust=slider.onClick
  384. return(slider)
  385. end
  386.  
  387. function newFlagMonitor(side) -- signal display widget
  388. flag=newWidget()
  389. flag.side=side
  390. flag.flags=0
  391. flag.sized=false
  392. flag.foregroundColor=defaultFlagMonitorForeground
  393.  
  394. function flag.get(flag,n)
  395. x=bit.blshift(1,n-1)
  396. y=bit.band(flag.flags,x)
  397. z=(y~=0)
  398. return z
  399. end
  400.  
  401. function flag.set(flag,n,value)
  402. if (value==nil) then
  403. value=true
  404. end
  405. if (value) then
  406. flag.flags=bit.bor(flag.flags,bit.blshift(1,n-1))
  407. else
  408. flag.flags=bit.band(flag.flags,bit.bnot(bit.blshift(1,n-1)))
  409. end
  410. flag:transmit()
  411. end
  412.  
  413. function flag.clear(flag,n)
  414. flag.flags=bit.band(flag.flags,bit.bnot(bit.blshift(1,n-1)))
  415. flag:transmit()
  416. end
  417.  
  418. function flag.toggle(flag,n)
  419. flag.flags=bit.bxor(flag.flags,bit.blshift(1,n-1))
  420. flag:transmit()
  421. end
  422.  
  423. function flag.transmit(flag)
  424. --print("transmitting " .. flag.flags .. " to " .. flag.side)
  425. redstone.setBundledOutput(flag.side,flag.flags)
  426. flag:draw()
  427. end
  428.  
  429. function flag.draw(flag)
  430. if ( not flag.sized ) then
  431. return
  432. end
  433. ylocal=math.floor((flag.y1+flag.y2)/2)
  434. xlocal=math.floor((flag.x1+flag.x2-8)/2)
  435. monitor.setCursorPos(xlocal,ylocal)
  436. for i=1,16 do
  437. color=bit.blshift(1,i-1)
  438. if (flag:get(i)) then
  439. monitor.setBackgroundColor(color)
  440. monitor.setTextColor(flag.foregroundColor)
  441. monitor.write(" ")
  442. else
  443. monitor.setBackgroundColor(terminalBackground)
  444. monitor.setTextColor(color)
  445. monitor.write(".")
  446. end
  447. if (i==8) then
  448. monitor.setCursorPos(xlocal,ylocal+1)
  449. end
  450. end
  451. end
  452.  
  453. function flag.onResize(flag)
  454. flag.sized=true
  455. end
  456.  
  457. return(flag)
  458. end
  459.  
  460. function newChooser(choice,options)
  461. chooser=newButton(choice)
  462. chooser.options=options
  463.  
  464. function chooser.choose(chooser)
  465. if (chooser.tab==nil) then
  466. chooser:formTab()
  467. end
  468. chooser.tab:run()
  469. redrawNeeded=true
  470. end
  471.  
  472. function chooser.buttonOnClick(button)
  473. button:blink()
  474. button.chooser.label=button.label
  475. button.chooser.tab.quit=true
  476. end
  477.  
  478. function chooser.formTab(chooser)
  479. chooser.tab=newRow()
  480. width,height=monitor.getSize()
  481. buttonsPerColumn=math.floor(height/4)
  482. numButtons=#(chooser.options)
  483. numColumns=math.ceil(numButtons/buttonsPerColumn)
  484. columnNum=1
  485. rowNum=1
  486. currentColumn=newColumn()
  487. for key,option in pairs(chooser.options) do
  488. if (rowNum>buttonsPerColumn) then
  489. rowNum=1
  490. columnNum=columnNum+1
  491. chooser.tab:add(currentColumn)
  492. currentColumn=newColumn()
  493. end
  494. choiceButton=newButton(option)
  495. choiceButton.vWeight=.3
  496. choiceButton.chooser=chooser
  497. choiceButton.onClick=chooser.buttonOnClick
  498. currentColumn:add(choiceButton)
  499. rowNum=rowNum+1
  500. end
  501. chooser.tab:add(currentColumn)
  502. end
  503.  
  504. chooser.onClick=chooser.choose
  505. chooser.tab=nil
  506. return(chooser)
  507. end
  508.  
  509. function newProgressBar(max)
  510. bar=newWidget()
  511. if (max==nil) then
  512. bar.max=1.0
  513. else
  514. bar.max=max
  515. end
  516. bar.value=0
  517. bar.foreground=defaultProgressBarForeground
  518. bar.background=defaultProgressBarBackground
  519.  
  520. function bar.draw(bar)
  521. y=math.floor((bar.y1+bar.y2)/2)
  522. xOn=math.floor(bar.width*bar.value/bar.max)
  523. xOff=bar.width-xOn
  524. monitor.setBackgroundColor(bar.foreground)
  525. monitor.setCursorPos(bar.x1,y)
  526. monitor.write(string.rep(" ",xOn))
  527. monitor.setBackgroundColor(bar.background)
  528. monitor.write(string.rep(" ",xOff))
  529. end
  530.  
  531. function bar.setValue(bar,value)
  532. bar.value=value
  533. bar:draw()
  534. end
  535.  
  536. function bar.getValue(bar)
  537. return(bar.value)
  538. end
  539.  
  540. return(bar)
  541. end
Add Comment
Please, Sign In to add comment