MattiasBuelens

CCGUI element

Jul 5th, 2012
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.86 KB | None | 0 0
  1. --[[
  2.  
  3.     ComputerCraft GUI
  4.     Element
  5.  
  6. --]]
  7.  
  8. ccgui = ccgui or {}
  9.  
  10. -- Alignment enumerations
  11. ccgui.Align = { Left = 0, Center = 1, Right = 2 }
  12. ccgui.VAlign = { Top = 0, Middle = 1, Bottom = 2 }
  13.  
  14. --[[
  15.  
  16.     Element
  17.  
  18. ]]--
  19.  
  20. local Element = common.newClass({
  21.     -- Parent element
  22.     parent = nil,
  23.     -- Need repaint
  24.     --needsRepaint = true,
  25.     -- Colors
  26.     foreground = colours.black,
  27.     background = 0,
  28.     -- Size and bounding box for drawing
  29.     size = nil,
  30.     bbox = nil,
  31.     -- Border
  32.     border = ccgui.newBorder(),
  33.     -- Padding
  34.     padding = ccgui.newMargins(0),
  35.     -- Visibility
  36.     isVisible = true
  37. }, common.Observable)
  38. ccgui.Element = Element
  39.  
  40. function Element:init()
  41.     common.Observable.init(self)
  42.  
  43.     self.padding = ccgui.newMargins(self.padding)
  44.     self.border = ccgui.newBorder(self.border)
  45.  
  46.     -- Mouse
  47.     self:on("mouse_click", self.mouseClick, self)
  48.  
  49.     -- Focus
  50.     self:on("focus", self.updateFocus, self)
  51.  
  52.     -- Paint
  53.     self:on("paint", self.clear, self)
  54.     self:on("paint", self.drawBorder, self)
  55.  
  56.     --self:markRepaint()
  57. end
  58.  
  59. function Element:show()
  60.     if not self.isVisible then
  61.         --self:markRepaint()
  62.         self.isVisible = true
  63.         return true
  64.     end
  65.     return false
  66. end
  67.  
  68. function Element:hide()
  69.     if self.isVisible then
  70.         --self:markRepaint()
  71.         self.isVisible = false
  72.         return true
  73.     end
  74.     return false
  75. end
  76.  
  77. --[[
  78.  
  79.     Bounding box
  80.  
  81. --]]
  82.  
  83. -- Inner bounding box, without border and padding
  84. function Element:inner(bbox)
  85.     if bbox == nil then
  86.         print("invalid bbox")
  87.         for k,v in pairs(self) do
  88.             print(tostring(k).."="..tostring(v))
  89.         end
  90.         error()
  91.     end
  92.     assert(bbox ~= nil, "invalid bbox")
  93.     assert(self.padding ~= nil, "invalid padding")
  94.     assert(self.border ~= nil, "invalid border")
  95.  
  96.     return bbox:contract(self.padding):contract(self.border:margins())
  97. end
  98.  
  99. -- Outer bounding box, with border and padding
  100. function Element:outer(bbox)
  101.     assert(bbox ~= nil, "invalid bbox")
  102.     assert(self.padding ~= nil, "invalid padding")
  103.     assert(self.border ~= nil, "invalid border")
  104.  
  105.     return bbox:expand(self.padding):expand(self.border:margins())
  106. end
  107.  
  108. -- Calculate element size within given size box
  109. function Element:calcSize(size)
  110.     self.size = ccgui.newRectangle(0, 0, 0, 0)
  111. end
  112.  
  113. -- Calculate element layout within given bounding box
  114. function Element:calcLayout(bbox)
  115.     self.bbox = bbox
  116. end
  117.  
  118. -- Update element layout within given bounding box
  119. function Element:updateLayout(bbox)
  120.     self:calcSize(bbox)
  121.     self:calcLayout(ccgui.newRectangle(bbox:tl(), self.size:size()))
  122. end
  123.  
  124. -- Check if the bounding box with padding contains the given point
  125. function Element:contains(x, y)
  126.     if self.bbox == nil then return false end
  127.     return self:inner(self.bbox):expand(self.padding):contains(x, y)
  128. end
  129.  
  130. --[[
  131.  
  132.     Focus
  133.  
  134. --]]
  135.  
  136. function Element:canFocus()
  137.     return false
  138. end
  139.  
  140. function Element:focus()
  141.     if not self:canFocus() then
  142.         return false
  143.     end
  144.  
  145.     -- Set focus
  146.     if not self.hasFocus then
  147.         self.hasFocus = true
  148.         self:trigger("focus", self)
  149.     end
  150.  
  151.     return true
  152. end
  153.  
  154. function Element:blur()
  155.     if not self:canFocus() then
  156.         return false
  157.     end
  158.  
  159.     -- Set focus
  160.     if self.hasFocus then
  161.         self.hasFocus = false
  162.         self:trigger("blur", self)
  163.     end
  164.  
  165.     return true
  166. end
  167.  
  168. function Element:updateFocus(newFocus)
  169.     -- Blur if this element lost focus
  170.     if self ~= newFocus then
  171.         self:blur()
  172.     end
  173.     -- Bubble up to parent
  174.     if self.parent ~= nil then
  175.         self.parent:updateFocus(newFocus)
  176.     end
  177. end
  178.  
  179. function Element:mouseClick(button, x, y)
  180.     if button == 1 then
  181.         -- Left mouse button
  182.         -- Take focus when focusable and contains mouse pointer
  183.         if self:canFocus() and self:contains(x, y) then
  184.             self:focus()
  185.         end
  186.     end
  187. end
  188.  
  189. --[[
  190.  
  191.     Painting
  192.  
  193. ]]--
  194.  
  195. -- Get the output device for drawing
  196. function Element:getOutput()
  197.     -- Bubble up to parent
  198.     return self.parent:getOutput()
  199. end
  200.  
  201. --[[function Element:markRepaint()
  202.     self.needsRepaint = true
  203. end
  204.  
  205. function Element:unmarkRepaint()
  206.     self.needsRepaint = false
  207. end]]--
  208.  
  209. function Element:paint()
  210.     if not self.isVisible then return end
  211.     self:trigger("beforepaint")
  212.     if self.bbox ~= nil then
  213.         self:trigger("paint")
  214.     end
  215.     self:trigger("afterpaint")
  216. end
  217.  
  218. -- Clear element's bounding box
  219. function Element:clear()
  220.     local bbox = self.bbox
  221.     for y=0,bbox.h-1 do
  222.         for x=0,bbox.w-1 do
  223.             self:draw(bbox.x + x, bbox.y + y, " ", self.foreground, self.background)
  224.         end
  225.     end
  226. end
  227.  
  228. -- Draw single text line within bounding rectangle
  229. function Element:draw(x, y, text, fgColor, bgColor, bounds)
  230.     if type(x) == "table" then
  231.         -- Position given as vector
  232.         return self:draw(x.x, x.y, y, text, fgColor, bgColor)
  233.     end
  234.  
  235.     if bounds then
  236.         -- Check vertical bounds
  237.         if y < bounds.y or y >= bounds.y + bounds.h then
  238.             return
  239.         end
  240.         -- Limit to horizontal bounds
  241.         local startIdx = 1 + math.max(0, bounds.x - x)
  242.         local endIdx = math.min(#text, bounds.x + bounds.w - x)
  243.         text = string.sub(text, startIdx, endIdx)
  244.         x = x + startIdx - 1
  245.     end
  246.  
  247.     self:drawUnsafe(x, y, text, fgColor, bgColor)
  248. end
  249.  
  250. -- Unsafe drawing
  251. function Element:drawUnsafe(x, y, text, fgColor, bgColor)
  252.     -- Draw on parent
  253.     if self.isVisible and self.parent ~= nil then
  254.         self.parent:drawUnsafe(x, y, text, fgColor, bgColor)
  255.     end
  256. end
  257.  
  258. -- Draw line
  259. function Element:drawLine(line, color)
  260.     -- Draw each point along the line
  261.     for i,point in ipairs(line:points()) do
  262.         self:draw(point, " ", colours.white, color)
  263.     end
  264. end
  265.  
  266. -- Draw single border
  267. function Element:drawSingleBorder(side)
  268.     if(self.border:has(side)) then
  269.         self:drawLine(self.bbox[side](self.bbox), self.border:get(side))
  270.     end
  271. end
  272.  
  273. -- Draw all borders
  274. function Element:drawBorder()
  275.     self:drawSingleBorder("left")
  276.     self:drawSingleBorder("right")
  277.     self:drawSingleBorder("top")
  278.     self:drawSingleBorder("bottom")
  279. end
  280.  
  281. -- Bubble event up to parent
  282. function Element:bubbleEvent(event)
  283.     self:on(event, function(self, ...)
  284.         if self.parent ~= nil then
  285.             self.parent:trigger(event, ...)
  286.         end
  287.     end, self)
  288. end
Advertisement
Add Comment
Please, Sign In to add comment