Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ######################################## --
- -- --
- -- Better UI API for ComputerCraft v2 inDev --
- -- --
- -- ######################################## --
- -- ################################################################################
- --
- -- Base functions being used for many things
- function cur(target, x, y) target.setCursorPos(x, y) end
- function color(target,fg,bg) if fg ~= 0 then target.setTextColor(fg) end if bg ~= 0 then target.setBackgroundColor(bg) end end
- function drawPixel(target, x, y, nColour) if nColour then term.setBackgroundColor( nColour ) end cur(target, x, y) v.write(' ') end
- function split(se,sep) local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) se:gsub(pattern, function(c) fields[#fields+1] = c end) return fields end
- function inTable(tbl, item)
- if type(item) == 'table' then
- for i, v in pairs(item) do for key,value in pairs(tbl) do if value == v then return i, key end end end
- elseif type(item) == 'string' then
- for key,value in pairs(tbl) do if value == item then return key end end
- end
- return 0
- end
- function unpackPat(tbl, pattern)
- local a = {}
- for i, v in ipairs(pattern) do
- a[i] = tbl[v]
- end
- return unpack(a)
- end
- function contPos(self,x,y,cont)
- local loop = true
- newx, newy = 0, 0
- while loop do
- newx = newx + self.ui[cont].x
- newy = newy + self.ui[cont].y
- if self.ui[cont].cont then
- cont = self.ui[cont].cont
- else
- loop = false
- end
- return newx, newy
- end
- end
- function pairsByKey(t, f)
- local a = {}
- for n in pairs(t) do table.insert(a, n) end
- table.sort(a, f)
- local i = 0 -- iterator variable
- local iter = function () -- iterator function
- i = i + 1
- if a[i] == nil then return nil
- else return a[i], t[a[i]]
- end
- end
- return iter
- end
- --
- -- ################################################################################
- -- ################################################################################
- -- New UI list constructor
- --
- function new(defTag, defDis)
- local uiList = {}
- uiList.ui = {}
- uiList.set = {}
- uiList.get = {}
- uiList.utils = {}
- uiList.config = {}
- uiList.config.defDis = defDis or {term}
- uiList.config.defTag = defTag or {'all'}
- uiList.config.defFG = colors.white
- uiList.config.defBG = colors.black
- uiList.config.pattern = {} -- Defines the patterns the different element types use that can be edited (setCommonAttribute)
- uiList.config.pattern.button = {'x', 'y', 'colors', 'tag', 'display', 'text', 'enabled', 'exe', 'ret', 'visible', 'cont'}
- uiList.config.pattern.label = {'x', 'y', 'colors', 'tag', 'display', 'text', 'enabled', 'cont'}
- uiList.config.pattern.radio = {'x', 'y', 'colors', 'tag', 'display', 'text', 'enabled', 'exe', 'ret', 'visible', 'value', 'cont'}
- uiList.config.pattern.checkbox = {'x', 'y', 'colors', 'tag', 'display', 'text', 'enabled', 'exe', 'ret', 'visible', 'value', 'cont'}
- uiList.config.pattern.point = {'x', 'y', 'colors', 'text', 'enabled', 'cont'}
- function uiList:addPoint(key, x, y, enabled) -- Add a point used to mark position
- if not(key) or not(x) or not(y) then return false end
- self.ui[key] = {name = key, type = 'point', x = x, y = y, enabled = true}
- local temp = self.ui[key]
- function temp:setColors(fg,bg) self.colors = {fg, bg} end
- return self.ui[key]
- end
- function uiList:addLabel(key, x, y, text, tag, display)
- if not(key) or not(x) or not(y) or not(text) or self.ui[key] then return false end
- self.ui[key] = {name = key, type = 'label', x = x, y = y, text = text, tag = tag or self.config.defTag, display = display or self.config.defDis, visible = true, enabled = true}
- local temp = self.ui[key]
- function temp:setColors(fg,bg) self.colors = {fg, bg} end
- return self.ui[key]
- end
- function uiList:addButton(key, x, y, text, tag, display)
- if not(key) or not(x) or not(y) or not(text) then return false end
- self.ui[key] = {name = key, type = 'button', x = x, y = y, text = text, tag = tag or self.config.defTag, display = display or self.config.defDis, visible = true, enabled = true}
- local temp = self.ui[key]
- function temp:setColors(fg,bg) self.colors = {fg, bg} end
- function temp:setAction(act) if type(act) == 'function' then self.exe = act else self.ret = act end end
- return self.ui[key]
- end
- function uiList:addRadio(key, x, y, text, tag, display)
- if not(key) or not(x) or not(y) or not(text) then return false end
- self.ui[key] = {name = key, type = 'radio', x = x, y = y, text = text, tag = tag or self.config.defTag, display = display or self.config.defDis, visible = true, enabled = true, value = 0}
- local temp = self.ui[key]
- function temp:setColors(fg,bg) self.colors = {fg, bg} end
- function temp:setAction(act) if type(act) == 'function' then self.exe = act else self.ret = act end end
- function temp:setChar(disabled, enabled) self.custChar = disabled..enabled end
- return self.ui[key]
- end
- function uiList:addCheckbox(key, x, y, text, tag, display)
- if not(key) or not(x) or not(y) or not(text) then return false end
- self.ui[key] = {name = key, type = 'checkbox', x = x, y = y, text = text, tag = tag or self.config.defTag, display = display or self.config.defDis, visible = true, enabled = true, value = 0}
- local temp = self.ui[key]
- function temp:setColors(fg,bg) self.colors = {fg, bg} end
- function temp:setAction(act) if type(act) == 'function' then self.exe = act else self.ret = act end end
- function temp:setChar(disabled, enabled) self.custChar = disabled..enabled end
- return self.ui[key]
- end
- function uiList:del(key) self.ui[key] = nil return true end -- Working
- function uiList:draw(tags)
- local ut = self.utils
- local tags = tags or self.config.tag or self.config.defTag
- for key, value in ut.pairsByKey(self.ui) do
- local t, x, y, text, tag, display, enabled= ut.unpackPat(value,{'type', 'x', 'y', 'text', 'tag', 'display', 'enabled'})
- local visible = value.visible
- if visible == nil then
- local visible = true
- end
- local colors = value.colors
- local cont = value.cont
- local custChar = value.custChar
- local val = value.value
- f, b = nil, nil
- if colors then f, b = unpack(colors) end
- if cont and self.ui[cont] then
- x = self.ui[cont].x + x
- y = self.ui[cont].y + y
- if not(b) and self.ui[cont].colors then
- b = self.ui[cont].colors[2]
- end
- enabled = self.ui[cont].enabled
- end
- fg = f or self.config.defFG
- bg = b or self.config.defBG
- if enabled and visible and t ~= 'point' and ut.inTable(tags, tag) > 0 then
- if type(text) == 'table' then
- local textMax = 0
- for i, v in ipairs(text) do
- if type(v) ~= 'table' and v:len() > textMax then textMax = v:len() end
- if type(v) == 'table' and v[1]:len() > textMax then textMax = v[1]:len() end
- end
- for i, v in ipairs(text) do
- if type(v) ~= 'table' and v:len() < textMax then text[i] = text[i]..string.rep(' ', textMax - v:len()) end
- if type(v) == 'table' and v[1]:len() < textMax then text[i][1] = text[i][1]..string.rep(' ', textMax - v[1]:len()) end
- end
- end
- for _, dis in pairs(display) do
- ut.color(dis, fg, bg)
- if type(text) == 'table' then
- for i, v in ipairs(text) do
- ut.color(dis, fg, bg)
- ut.cur(dis, x, y + (i - 1))
- if type(v) == 'table' then
- subTxt, subFG, subBG = unpack(v)
- ut.color(dis, subFG, subBG)
- dis.write(subTxt)
- else
- dis.write(v)
- end
- end
- else
- if t == 'radio' or t == 'checkbox' then
- custChar = custChar or 'O0'
- if #custChar > 1 then
- text = custChar:sub(1+val,1+val)..text
- end
- end
- ut.cur(dis, x, y)
- dis.write(text)
- end
- end
- end
- end
- return true
- end
- function uiList:mouse(pos, tags, display)
- local ut = self.utils
- local mx, my = unpack(pos)
- tags = tags or self.config.defTag
- disp = display or self.config.defDis
- clicked = {}
- for key, value in ut.pairsByKey(self.ui) do
- t, x, y, text, tag, display, enabled = ut.unpackPat(value,{'type', 'x', 'y', 'text', 'tag', 'display', 'enabled'})
- if ut.inTable(tags, tag) > 0 and enabled and ut.inTable({'button','radio','checkbox'}, t) > 0 then
- local cont = value.cont
- if cont and self.ui[cont] then
- x = self.ui[cont].x + x
- y = self.ui[cont].y + y
- end
- if type(text) == 'table' then
- local textMax = 0 for _, v in ipairs(text) do if type(v) == 'table' then v = v[1] end if v:len() > textMax then textMax = v:len() end end
- if my >= y and my <= y - 1 + #text and mx >= x and mx <= (x - 1 + textMax) then
- table.insert(clicked, {value.ret, key, {mx + 1 - x, my + 1 - y}})
- end
- else
- if t == 'radio' or t == 'checkbox' then text = text..' ' end
- if my == y and mx >= x and mx <= (x + text:len() - 1) then
- table.insert(clicked, {value.ret, key, {mx + 1 - x, my + 1 - y}})
- end
- end
- end
- end
- if #clicked == 0 then
- return nil
- else
- for i, v in pairs(clicked) do
- local curList = self.ui[v[2]]
- if curList.type == 'radio' and curList.cont then
- if curList.value == 0 then
- grp = curList.cont
- for ind, val in pairs(self.ui) do
- if val['type'] == 'radio' and val.cont and val.cont == curList.cont then
- if val.value ~= 0 then val.value = 0 end
- end
- end
- curList.value = 1
- end
- if curList.exe and type(curList.exe) == 'function' then
- curList:exe(self)
- end
- elseif curList.type == 'checkbox' then
- if curList.value == 0 then
- curList.value = 1
- else
- curList.value = 0
- end
- elseif curList.type == 'button' then
- if curList.exe and type(curList.exe) == 'function' then
- curList:exe(self)
- end
- end
- end
- return clicked
- end
- end
- -- ################################################################################
- --
- -- Utils functions, contains the draw shapes 'n' stuff with some string utils
- function uiList:getRadio(cont) for i, v in pairs(self.ui) do if v.type == 'radio' and v.value == 1 and v.cont == cont then return v end end return nil end
- function uiList:getCheckbox(cont) local res = {} for i, v in pairs(self.ui) do if v.type == 'checkbox' and v.value == 1 and v.cont == cont then table.insert(res, v) end end if #res > 0 then return res else return nil end end
- function uiList:setCommonAttribute(regEx, attrib)
- for key, val in pairs(self.ui) do
- local validate = true
- local ut = self.utils
- for i, v in pairs(regEx) do
- if not(val[i]) or not(val[i]:find(v)) then
- validate = false
- break
- end
- end
- if validate then
- t = val.type
- for i, v in pairs(attrib) do
- if ut.inTable(self.config.pattern[t], i) > 0 then
- val[i] = v
- end
- end
- end
- end
- end
- uiList.utils.pairsByKey = pairsByKey
- uiList.utils.draw = {}
- uiList.utils.dbg = function(p) print( ' <> ',p,' <> ') sleep(2) end
- uiList.utils.draw.line = line
- uiList.utils.draw.box = box
- uiList.utils.draw.outline = outline
- uiList.utils.unpackPat = unpackPat
- uiList.utils.cur = cur
- uiList.utils.color = color
- uiList.utils.split = split
- uiList.utils.inTable = inTable
- --
- -- ################################################################################
- return uiList
- end
- --
- -- End of new() constructor
- -- ################################################################################
- function drawOutline(x1,y1, x2, y2, target, c)
- drawLine(x1,y1, x1, y2, target, c)
- drawLine(x1,y2, x2, y2, target, c)
- drawLine(x2,y1, x2, y2, target, c)
- drawLine(x1,y1, x2, y1, target, c)
- end
- function outline(self, x1,y1, x2, y2, target, c)
- self.line(x1,y1, x1, y2, target, c)
- self.line(x1,y2, x2, y2, target, c)
- self.line(x2,y1, x2, y2, target, c)
- self.line(x1,y1, x2, y1, target, c)
- end
- -- function from paintutils ported for using targets
- local function drawPixelInternal( xPos, yPos, target )
- target.setCursorPos(xPos, yPos)
- target.write(" ")
- end
- -- function to draw a filled box on target
- function drawBox(startX, startY, endX, endY, target, nColour)
- if startY <= endY then s = 1 else s= -1 end
- for index=startY, endY, s do
- drawLine( startX, index, endX, index, target, nColour )
- end
- end
- function box(self, startX, startY, endX, endY, target, nColour)
- if startY <= endY then s = 1 else s= -1 end
- for index=startY, endY, s do
- self.line( startX, index, endX, index, target, nColour )
- end
- end
- -- function to draw line using targets
- function drawLine(startX, startY, endX, endY, target, nColour)
- for i, v in pairs(target) do
- line( startX, startY, endX, endY, v, nColour )
- end
- end
- -- function from paintutils ported for using targets
- local function line(startX, startY, endX, endY, v, nColour )
- local function drawPixelInternal( xPos, yPos, target ) target.setCursorPos(xPos, yPos) target.write(" ") end
- if nColour then
- v.setBackgroundColor( nColour )
- end
- startX = math.floor(startX)
- startY = math.floor(startY)
- endX = math.floor(endX)
- endY = math.floor(endY)
- if startX == endX and startY == endY then
- drawPixelInternal( startX, startY, v )
- return
- end
- local minX = math.min( startX, endX )
- if minX == startX then
- minY = startY
- maxX = endX
- maxY = endY
- else
- minY = endY
- maxX = startX
- maxY = startY
- end
- local xDiff = maxX - minX
- local yDiff = maxY - minY
- if xDiff > math.abs(yDiff) then
- local y = minY
- local dy = yDiff / xDiff
- for x=minX,maxX do
- drawPixelInternal( x, math.floor( y + 0.5 ), v )
- y = y + dy
- end
- else
- local x = minX
- local dx = xDiff / yDiff
- if maxY >= minY then
- for y=minY,maxY do
- drawPixelInternal( math.floor( x + 0.5 ), y, v )
- x = x + dx
- end
- else
- for y=minY,maxY,-1 do
- drawPixelInternal( math.floor( x + 0.5 ), y, v )
- x = x - dx
- end
- end
- end
- end
- --
- -- ################################################################################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement