Advertisement
OmegaRogue

test

Nov 12th, 2017
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.09 KB | None | 0 0
  1. --------------------------------------------------------------------------------
  2. -- Computer Craft GUI API by jpossi   (jascha@ja-s.de)                        --
  3. --  https://github.com/possi/computercraft_gui                                --
  4. --                                                                            --
  5. -- Copyright: GPL 2 http://www.gnu.de/documents/gpl-2.0.en.html               --
  6. --------------------------------------------------------------------------------
  7.  
  8. local api = {
  9.     debug = false,
  10.     screenThreadInterval = 1,
  11.     colorcodes = {
  12.         ["0"] = colors.black,
  13.         ["1"] = colors.blue,
  14.         ["2"] = colors.lime,
  15.         ["3"] = colors.green,
  16.         ["4"] = colors.brown,
  17.         ["5"] = colors.magenta,
  18.         ["6"] = colors.orange,
  19.         ["7"] = colors.lightGray,
  20.         ["8"] = colors.gray,
  21.         ["9"] = colors.cyan,
  22.         ["a"] = colors.lime,
  23.         ["b"] = colors.lightBlue,
  24.         ["c"] = colors.red,
  25.         ["d"] = colors.pink,
  26.         ["e"] = colors.yellow,
  27.         ["f"] = colors.white,
  28.     },
  29. }
  30.  
  31. -- -------------------
  32. --  Helper
  33. -- -------------------
  34.  
  35. local function extend(class, obj)
  36.     obj = obj or {}
  37.     setmetatable(obj, { __index = class})
  38.     return obj
  39. end
  40. local function create(class, ...)
  41.     if class.new ~= nil then
  42.         return class.new(...)
  43.     else
  44.         local obj = extend(class)
  45.         if (obj._init ~= nil) then
  46.             obj:_init(...)
  47.         end
  48.         return obj
  49.     end
  50. end
  51.  
  52. local function calculateNegativePos(x, y, w, h)
  53.     if x < 0 then
  54.         if w == nil then error("Can not calculate negative position without parent width") end
  55.         x = w + x + 1
  56.     end
  57.     if y < 0 then
  58.         if h == nil then error("Can not calculate negative position without parent height") end
  59.         y = h + y + 1
  60.     end
  61.     return x, y
  62. end
  63.  
  64. local function pdebug(...)
  65.     if not api.debug then return end
  66.     term.setBackgroundColor(colors.black)
  67.     term.setTextColor(colors.yellow)
  68.     print(...)
  69. end
  70. local pxdebug_y = 1
  71. local function pxdebug(...)
  72.     if not api.debug then return end
  73.     term.setBackgroundColor(colors.black)
  74.     term.setTextColor(colors.yellow)
  75.     local x, y = term.getCursorPos()
  76.     term.setCursorPos(1, pxdebug_y)
  77.     print(...)
  78.     local tmpx, tmpy = term.getCursorPos()
  79.     pxdebug_y = tmpy
  80.     local w, h = term.getSize()
  81.     if (pxdebug_y >= h) then
  82.         pxdebug_y = 1
  83.     end
  84.     term.setCursorPos(x, y)
  85. end
  86. api.pxdebug = pxdebug
  87. api.pdebug = pdebug
  88.  
  89. -- -------------------
  90. --  GUI-Interfaces
  91. -- -------------------
  92.  
  93. local widget = {hide = false, parent = nil}
  94. function widget:setParent(parent)
  95.     self.parent = parent
  96. end
  97. function widget:getParent()
  98.     return self.parent
  99. end
  100.  
  101. local colorAble = extend(widget)
  102. function colorAble:_init()
  103.     self.c = {bg = nil, fg = nil}
  104. end
  105. function colorAble:setTextColor(color)
  106.     self.c.fg = color
  107. end
  108. function colorAble:setBackgroundColor(color)
  109.     self.c.bg = color
  110. end
  111. function colorAble:applyColors()
  112.     if self.c.bg ~= nil then
  113.         term.setBackgroundColor(self.c.bg)
  114.     end
  115.     if self.c.fg ~= nil then
  116.         term.setTextColor(self.c.fg)
  117.     end
  118. end
  119.  
  120.  
  121. -- -------------------
  122. --  GUI-Classes
  123. -- -------------------
  124.  
  125. --
  126. -- Frame
  127. --
  128.  
  129. local frame = extend(colorAble)
  130. function frame._init(self)
  131.     colorAble._init(self)
  132.     self.widgets = {}
  133.     self.pos = {x = nil, y = nil}
  134.     self.padding = {t = 0, r = 0, b = 0, l = 0}
  135.     self.size = {w = nil, h = nil}
  136. end
  137. function frame:setPadding(t, r, b, l)
  138.     self.padding = {
  139.         t = t,
  140.         r = r ~= nil and r or t,
  141.         b = b ~= nil and b or t,
  142.         l = l ~= nil and l or (r ~= nil and r or t),
  143.     }
  144. end
  145. function frame:getPadding()
  146.     return self.padding
  147. end
  148. function frame:getInnerSize()
  149.     local w, h = self:getSize()
  150.     return w - self.padding.l - self.padding.r, h - self.padding.t - self.padding.b
  151. end
  152. function frame:getParentSize()
  153.     local pw, ph = nil, nil
  154.     if self.parent ~= nil then
  155.         pw, ph = self.parent:getSize()
  156.     end
  157.     return pw, ph
  158. end
  159. function frame:getPosition()
  160.     return self.pos.x, self.pos.y
  161. end
  162. function frame:setPosition(x, y, align) -- absolute only
  163.     --[[if (align ~= nil and align ~= "left" and self.parent == nil) then
  164.         error("Can not position frame right/center without a parent")
  165.     elseif (align ~= nil and align ~= "left" and (self.size.w == nil) then
  166.         error("Can not position frame right/center without a parent")
  167.     end]]--
  168.     if align ~= nil then error("NYI") end
  169.     local pw, ph = self:getParentSize()
  170.     x, y = calculateNegativePos(x, y, pw, ph)
  171.     self.pos = {x = x, y = y}
  172. end
  173. function frame:setPositions(x, y, x2, y2)
  174.     local pw, ph = nil, nil
  175.     if self.parent ~= nil then
  176.         pw, ph = self.parent:getSize()
  177.     end
  178.     local pw, ph = self:getParentSize()
  179.     x, y = calculateNegativePos(x, y, pw, ph)
  180.     x2, y2 = calculateNegativePos(x2, y2, pw, ph)
  181.     self.size = {w = x2 - x + 1, h = y2 - y + 1}
  182.     self.pos = {x = x, y = y}
  183. end
  184. function frame:setSize(w, h)
  185.     self.size.w = w
  186.     self.size.h = h
  187. end
  188. function frame:getSize()
  189.     return self.size.w, self.size.h
  190. end
  191. function frame:add(widget)
  192.     table.insert(self.widgets, widget)
  193.     if (type(widget) == "table" and widget.setParent ~= nil) then
  194.         widget:setParent(self)
  195.     end
  196.     return widget
  197. end
  198. function frame:remove(widget)
  199.     for i, v in ipairs(self.widgets) do
  200.         if v == widget then
  201.             table.remove(self.widgets, i)
  202.             return widget
  203.         end
  204.     end
  205.     return nil
  206. end
  207. function frame:draw(screen)
  208.     --pxdebug(term.getCursorPos())
  209.     --pxdebug(self:getCursorPosition())
  210.     --pdebug(self.c.bg)
  211.     if self.c.bg ~= nil then
  212.         for x = 1, self.size.w do
  213.             for y = 1, self.size.h do
  214.                 local ax, ay = self:getAbsolutePosition(x, y)
  215.                 paintutils.drawPixel(ax, ay, self.c.bg)
  216.             end
  217.         end
  218.     end
  219.     self:applyColors()
  220.     self:setCursorPosition(1 + self.padding.l, 1 + self.padding.t)
  221.     --pxdebug("frame painted: ", self)
  222.     for i, widget in pairs(self.widgets) do
  223.         if type(widget) == "function" then
  224.             widget(self)
  225.         elseif not widget.hide then
  226.             if (widget.getPosition ~= nil and widget:getPosition() ~= nil) then
  227.                 term.setCursorPos(self:getAbsolutePosition(widget:getPosition()))
  228.             end
  229.             widget:draw(self)
  230.         else
  231.             --pxdebug("hidden: ", widget)
  232.         end
  233.         self:applyColors()
  234.     end
  235. end
  236. function frame:click(frame, event, x, y)
  237.     --pdebug("@", x, ", ", y)
  238.     for i, widget in pairs(self.widgets) do
  239.         if (type(widget) == "table" and widget.getPosition ~= nil) then
  240.             local px, py = widget:getPosition()
  241.             local w, h = widget:getSize()
  242.             --pdebug(px, ",", py, " + ", w, ",", h)
  243.             if (x >= px and x < px + w and y >= py and y < py + h) then
  244.                 --pdebug("click")
  245.                 widget:click(self, event, x - px + 1, y - py + 1)
  246.             end
  247.         end
  248.     end
  249. end
  250. function frame:getScreen()
  251.     return self.parent:getScreen()
  252. end
  253. function frame:getAbsolutePosition(x, y)
  254.     local px, py = self.parent:getAbsolutePosition(self.pos.x, self.pos.y)
  255.     return px + x - 1, py + y - 1
  256. end
  257. function frame:getRelativePosition(x, y)
  258.     local px, py = self.parent:getAbsolutePosition(self.pos.x, self.pos.y)
  259.     return x - px + 1, y - py + 1
  260. end
  261. function frame:getCursorPosition()
  262.     return self:getRelativePosition(term.getCursorPos())
  263. end
  264. function frame:setCursorPosition(x, y)
  265.     return term.setCursorPos(self:getAbsolutePosition(x, y))
  266. end
  267. function frame:frame()
  268.     return self:add(create(frame))
  269. end
  270.  
  271. --
  272. -- Screen
  273. -- Provides all methods, a Frame also provides (same interface) but has its own implementation, because a screen is alwas absolute
  274. --
  275.  
  276. local screen = extend(colorAble, {
  277.     setParent = nil,
  278.     getParent = nil,
  279. })
  280. do
  281.     -- Link Interface-Methods from Frame
  282.     local fs = {
  283.         "add",
  284.         "click",
  285.         "remove",
  286.         "setPadding",
  287.         "getPadding",
  288.         "getInnerSize",
  289.         "setCursorPosition",
  290.         "getCursorPosition",
  291.         "frame",
  292.     }
  293.     for i, f in pairs(fs) do
  294.         screen[f] = frame[f]
  295.     end
  296. end
  297. function screen._init(self)
  298.     colorAble._init(self)
  299.     self.widgets = {}
  300.     self.cb = {draw = nil, adraw = nil, thread = nil}
  301.     self.padding = {t = 0, r = 0, b = 0, l = 0}
  302. end
  303. function screen:getSize()
  304.     return term.getSize()
  305. end
  306. function screen:draw()
  307.     self:applyColors()
  308.     pxdebug_y = 1
  309.     term.clear()
  310.     term.setCursorPos(1 + self.padding.l, 1 + self.padding.t)
  311.     if self.cb.draw ~= nil then
  312.         self.cb.draw(self)
  313.     end
  314.     for i, widget in ipairs(self.widgets) do
  315.         if type(widget) == "function" then
  316.             widget(self)
  317.         elseif not widget.hide then
  318.             if (widget.getPosition ~= nil and widget:getPosition() ~= nil) then
  319.                 term.setCursorPos(widget:getPosition())
  320.             end
  321.             widget:draw(self)
  322.         end
  323.         self:applyColors()
  324.     end
  325.     if self.cb.adraw ~= nil then
  326.         self.cb.adraw(self)
  327.     end
  328. end
  329. function screen:onDraw(callback)
  330.     self.cb.draw = callback
  331. end
  332. function screen:afterDraw(callback)
  333.     self.cb.adraw = callback
  334. end
  335. function screen:setThread(routine)
  336.     self.cb.thread = routine
  337. end
  338. function screen:wait()
  339.     self.wait = true
  340.     local timer;
  341.     if (self.cb.thread ~= nil) then
  342.         timer = os.startTimer(api.screenThreadInterval)
  343.     end
  344.     repeat
  345.         local event, a1, a2, a3 = os.pullEvent()
  346.         if (event == "monitor_touch" or event == "mouse_click") then
  347.             local x, y = a2, a3
  348.             self:click(nil, event, x, y)
  349.         elseif (event == "timer" and a1 == timer) then
  350.             timer = os.startTimer(api.screenThreadInterval)
  351.             if (type(self.cb.thread) == "thread" and coroutine.status(self.cb.thread) == "suspended") then
  352.                 coroutine.resume(self.cb.thread, self)
  353.             else
  354.                 self.cb.thread(self)
  355.             end
  356.         end
  357.     until not self.wait
  358. end
  359. function screen:stop()
  360.     self.wait = false
  361. end
  362. function screen:getScreen()
  363.     return self
  364. end
  365. function screen:getAbsolutePosition(x, y)
  366.     return x, y
  367. end
  368. function screen:getRelativePosition(x, y)
  369.     return x, y
  370. end
  371. function screen:reset()
  372.     pxdebug_y = 1
  373.     term.setTextColor(colors.white)
  374.     term.setBackgroundColor(colors.black)
  375.     term.clear()
  376.     term.setCursorPos(1, 1)
  377. end
  378.  
  379. --
  380. -- Text-Label
  381. --
  382.  
  383. local text = extend(colorAble)
  384. function text._init(self, str)
  385.     colorAble._init(self)
  386.     self.text = str
  387.     self.slow = nil
  388. end
  389. function text:setText(str)
  390.     self.text = str
  391. end
  392. function text:setSlow(cps)
  393.     self.slow = cps
  394. end
  395. function text:nl(x, y)
  396.     x = 1
  397.     y = y + 1
  398.     self.size.h = self.size.h + 1
  399.     if (self.parent) then
  400.         --[[local pw, ph = self.parent:getSize();
  401.         if (y > ph) then
  402.             error("String execeeds parent size")
  403.         end]]
  404.         self.parent:setCursorPosition(x, y)
  405.     end
  406.     return x, y
  407. end
  408. function text:_write(str)
  409.     if (self.slow ~= nil) then
  410.         textutils.slowWrite(str, self.slow)
  411.     else
  412.         term.write(str)
  413.     end
  414. end
  415. function text:draw(screen)
  416.     if self.parent == nil then
  417.         error("Missing parent-Widget", 2)
  418.     end
  419.     local p = self.parent
  420.     local x, y = p:getCursorPosition()
  421.    
  422.     --print(self.c.fg, " ")
  423.     --pxdebug(self.text:sub(1, 4), "#", self.c.bg)
  424.     --d(self.c)
  425.     self:applyColors()
  426.    
  427.     self.size = {w = 0, h = 1}
  428.     self.pos = {x = x, y = y}
  429.    
  430.     local linelength, blockheight = p:getInnerSize()
  431.    
  432.     local offset = 1
  433.     local i = string.find(self.text, "[%s$]")
  434.     while (offset <= string.len(self.text)) do
  435.         if (i == nil) then
  436.             i = string.len(self.text) + 1
  437.         end
  438.         local wordlength = i - offset
  439.         if (wordlength == 0) then
  440.             local char = string.sub(self.text, offset, offset)
  441.             if (char == "\r") then
  442.                 -- ignore
  443.             elseif (char == "\n") then
  444.                 x, y = self:nl(x, y)
  445.             elseif (char == "$") then
  446.                 local ccode = string.sub(self.text, offset + 1, offset + 1)
  447.                 if (api.colorcodes[ccode] ~= nil) then
  448.                     term.setTextColor(api.colorcodes[ccode])
  449.                     offset = offset + 1
  450.                 elseif (ccode == "r") then
  451.                     if (self.c.fg) then
  452.                         term.setTextColor(self.c.fg)
  453.                     end
  454.                     offset = offset + 1
  455.                 elseif (ccode ~= "$") then
  456.                     self:_write(char)
  457.                 end
  458.             else
  459.                 if (x + 1 > linelength) then
  460.                     x, y = self:nl(x, y)
  461.                 else
  462.                     x = x + 1
  463.                     self.size.w = math.max(self.size.w, x - 1)
  464.                     self:_write(char)
  465.                 end
  466.             end
  467.             offset = offset + 1
  468.         else
  469.             if (wordlength > linelength) then
  470.                 i = offset + (linelength - x) + 1
  471.             elseif (x + wordlength - 1 > linelength) then
  472.                 x, y = self:nl(x, y)
  473.             end
  474.             self:_write(string.sub(self.text, offset, i - 1))
  475.             x = x + wordlength
  476.             self.size.w = math.max(self.size.w, x - 1)
  477.             offset = i
  478.         end
  479.         i = string.find(self.text, "[%s$]", offset)
  480.     end
  481.     --pxdebug(string.sub(self.text, 1, 6), " ", self.size.w, " ", self.size.h)
  482. end
  483.  
  484. --
  485. -- Button
  486. --
  487.  
  488. local button = extend(text)
  489. function button._init(self, str)
  490.     text._init(self, str)
  491.     self.pos = {x = nil, y = nil}
  492.     self.size = {w = nil, h = nil}
  493.     self.cb = nil
  494.     self.parent = nil
  495. end
  496. function button:setPosition(x, y, align) -- absolute only
  497.     if (self.parent == nil) then
  498.         error("A parent have to be set first", 2)
  499.     end
  500.     local pw, ph = self.parent:getSize()
  501.     x, y = calculateNegativePos(x, y, pw, ph)
  502.     if align == "right" then
  503.         local w, h = self:getSize()
  504.         x = x - w + 1
  505.     end
  506.     self.pos = {x = x, y = y}
  507. end
  508. function button:getPosition()
  509.     return self.pos.x, self.pos.y -- computed by text.draw
  510. end
  511. function button:getSize()
  512.     if self.size.w ~= nil and self.size.h ~= nil then
  513.         return self.size.w, self.size.h -- computed by text.draw
  514.     else
  515.         return string.len(self.text), 1
  516.     end
  517. end
  518. function button:onClick(callback)
  519.     self.cb = callback
  520. end
  521. function button:click(frame, event, x, y)
  522.     --[[if (self.parent ~= nil and self.c.fg ~= nil and self.c.bg ~= nil and self.pos.x ~= nil and self.pos.y ~= nil) then
  523.         self.parent:setCursorPosition(self.pos.x, self.pos.y)
  524.         local tmp = {self.c.fg, self.c.bg};
  525.         self.c.fg = tmp.bg;
  526.         self.c.bg = tmp.fg;
  527.         self:draw()
  528.         self.c = tmp;
  529.         sleep(0.2)
  530.     end]]
  531.     if (self.cb ~= nil) then
  532.         self.cb(self, frame, event, x, y)
  533.     end
  534. end
  535.  
  536.  
  537. --
  538. -- Radio-Group
  539. --
  540.  
  541. local radioGroup = extend(widget)
  542. function radioGroup._init(self)
  543.     self.entries = {}
  544.     self.cb = {change = nil}
  545.     self.value = nil
  546.     --self.padding = 0
  547. end
  548. --[[function radioGroup:setPadding(c)
  549.     self.padding = c
  550. end]]
  551. function radioGroup:onChange(callback)
  552.     self.cb.change = callback
  553. end
  554. function radioGroup:addEntry(value, label)
  555.     if (self.parent == nil) then
  556.         error("A parent have to be set first", 2)
  557.     end
  558.     local this = self
  559.     if label == nil then
  560.         label = value
  561.     end
  562.     local b = create(button)
  563.     b.value = value
  564.     b.label = label
  565.     b:onClick(function(button, frame, event, x, y)
  566.         if (this.cb.change ~= nil) then
  567.             this.cb.change(this, button, this.value, button.value, frame)
  568.         end
  569.         this.value = button.value
  570.         pxdebug("click button ", button.pos.x, " ", button.pos.y)
  571.         this:redraw(frame)
  572.     end)
  573.     self.entries[value] = self.parent:add(b)
  574.     self.parent:add(create(text, "\n"))
  575.     return b
  576. end
  577. function radioGroup:draw(frame)
  578.     for value, button in pairs(self.entries) do
  579.         local pf = self.value == button.value and "(X) " or "( ) "
  580.         button:setText(pf .. button.label)
  581.     end
  582. end
  583. function radioGroup:redraw(frame)
  584.     for value, button in pairs(self.entries) do
  585.         local pf = self.value == button.value and "(X) " or "( ) "
  586.         button:setText(pf .. button.label)
  587.         frame:setCursorPosition(button.pos.x, button.pos.y)
  588.         button:draw()
  589.     end
  590. end
  591.  
  592.  
  593. -- -------------------
  594. --  Public-API
  595. -- -------------------
  596.  
  597.  
  598. function api.screen()
  599.     return create(screen)
  600. end
  601. function api.text(...)
  602.     return create(text, ...)
  603. end
  604. function api.textln(str)
  605.     return create(text, (str or "") .. "\n")
  606. end
  607. function api.button(...)
  608.     return create(button, ...)
  609. end
  610. function api.radios(...)
  611.     return create(radioGroup, ...)
  612. end
  613. function api.frame(...)
  614.     return create(frame, ...)
  615. end
  616.  
  617. gui = api;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement