jille_Jr icon

CC: Display API - Latest release

jille_Jr | PRO | 11/19/13 03:08:30 PM UTC | 0 ⭐ | 559 👁️ | Never ⏰ | []
Lua |

12.58 KB

|

None

|

0 👍

/

0 👎

-- display API 
-- made by akaJag
-- work in progress
 
function round(num)
    if type(num) ~= "number" then return num end
    if num%1<.5 then num=math.floor(num) end
    if num%1>=.5 then num=math.ceil(num) end
    return num
end
 
function setupdaterate(class,s)
    class.updaterate = s
end
 
function getupdaterate(class)
    return class.updaterate
end
 
function removepixles(class)
    local w,h = class.obj.getSize()
    
    -- check row
    local width = next(class.pixles)
    while width do
        if width > w or width < 0 then
            -- remove row
            local tmpw = width
            width = next(class.pixles,width)
            class.pixles[tmpw] = nil
        else
            -- check column
            local height = next(class.pixles[width])
            while height do
                if height > h or height < 0 then
                    -- remove column
                    local tmph = height
                    height = next(class.pixles[width],height)
                    class.pixles[width][tmph] = nil
                else
                    -- next iteration
                    height = next(class.pixles[width],height)
                end
            end
            -- next iteration
            width = next(class.pixles,width)
        end
    end
end
 
function fixpixles(class)
    local w,h = class.obj.getSize()
    for width = 1,w do
        if class.pixles[width] == nil then class.pixles[width] = {} end
        for height = 1,h do
            if class.pixles[width][height] == nil then
                class.pixles[width][height] = {sym=" ",bg=colors.black,fg=colors.white}
            end
        end
    end
end
 
-- returns:
--  (number) update time
function update(class)
    local startupdate = os.clock()
    
    class:removepixles()
    class:fixpixles()
    
    local endupdate = os.clock()
    return endupdate - startupdate
end
 
function draw(class)
    local startdraw = os.clock()
    
    for w in pairs(class.pixles) do
        for h,pixle in pairs(class.pixles[w]) do
            class.obj.setCursorPos(w,h)
            class.obj.setBackgroundColor(pixle.bg or colors.black)
            class.obj.setTextColor(pixle.fg or colors.white)
            class.obj.write(pixle.sym or " ")
        end
    end
    
    local enddraw = os.clock()
    return enddraw - startdraw
end
 
-- can be used in a parallel loop
-- dont forget to do prepareloop() before running
-- stop it with stoploop()
function loop(class)
    if not running then return end
    local s = class:update()
    s = s + class:draw()
    sleep(updaterate - s)
end
 
function prepareloop(class)
    class.looprunning = true
    class.looptime = os.clock()
end
 
-- returns the time the loop has been on
function stoploop()
    class.looprunning = false
    return os.clock - class.looptime
end
 
function setcolor(class,fg,bg)
    class.fgcolor = fg or class.fgcolor
    class.bgcolor = bg or class.bgcolor
end
 
function getcolor(class)
    return class.fgcolor,class.bgcolor
end
 
function setfgcolor(class,col)
    class.fgcolor = col
end
 
function getfgcolor(class)
    return class.fgcolor
end
 
function setbgcolor(class,col)
    class.bgcolor = col
end
 
function getbgcolor(class)
    return class.bgcolor
end
 
-- stroke is only used with "line" draw mode
function setstroke(class,var)
    class.stroke=var
end
 
function getstroke(class)
    return class.stroke
end
 
-- clears the entire screen
-- bg = only change background, ignore text
function clear(class,bg)
    for w in pairs(class.pixles) do
        for h,pixle in pairs(class.pixles[w]) do
            class.pixles[w][h].bg = class.bgcolor
            if bg ~= true then
                class.pixles[w][h].sym = " "
            end
        end
    end
end
 
-- trans = transparant option
function write(class,str,x,y,trans)
    x=round(x) y=round(y)
    
    -- utf8 to utf32
    local strtotbl = function(str)
        local tbl = {}
        for uchar in str:gmatch("([%z\1-\127\194-\244][\128-\191]*)") do
            table.insert(tbl,uchar)
        end
        return tbl
    end
    
    local text = strtotbl(str)
    
    for count = 1,#text do
        if class.pixles[x+count-1] then
            if class.pixles[x+count-1][y] then
                class.pixles[x+count-1][y].sym = text[count]
                class.pixles[x+count-1][y].fg = class.fgcolor
                if trans ~= true then
                    class.pixles[x+count-1][y].bg = class.bgcolor
                end
            end
        end
    end
end
 
function line(class,x1,y1,x2,y2,bg)
    -- Bresenham's algorithm
    local dx = x2 - x1
    if dx < 0 then dx = -dx end
    local dy = y2 - y1
    if dy < 0 then dy = -dy end
    
    local sx,sy
    if x1 < x2 then sx = 1
    else sx = -1 end
    if y1 < y2 then sy = 1
    else sy = -1 end
    
    local err = dx - dy
    
    repeat
        local x,y = round(x1),round(y1)
        if class.pixles[x] then
            if class.pixles[x][y] then
                class.pixles[x][y].bg = class.bgcolor
                if bg ~= true then
                    class.pixles[x][y].sym = " "
                end
            end
        end
        
        if x1 == x2 and y1 == y2 then break end
        local e2 = 2*err
        if e2 > -dy then
            err = err - dy
            x1 = x1 + sx
        end
        if e2 < dx then
            err = err + dx
            y1 = y1 + sy
        end
    until false
end
 
-- supported modes: fill, line
-- bg = only set background color
function rect(class,mode,x1,y1,x2,y2,bg)
    x1=round(x1) y1=round(y1) x2=round(x2) y2=round(y2)
    if mode == "fill" then
        for x = x1,x2 do
            for y = y1,y2 do
                if class.pixles[x] ~= nil then
                    if class.pixles[x][y] ~= nil then
                        class.pixles[x][y].bg = class.bgcolor
                        if bg ~= true then
                            class.pixles[x][y].sym = " "
                        end
                    end
                end
            end
        end
    elseif mode == "line" then
        -- top line
        for x = x1,x2 do
            for y = y1,y1+class.stroke-1 do
                if class.pixles[x] ~= nil then
                    if class.pixles[x][y] ~= nil then
                        class.pixles[x][y].bg = class.bgcolor
                        if bg ~= true then
                            class.pixles[x][y].sym = " "
                        end
                    end
                end
            end
        end
        -- bottom line
        for x = x1,x2 do
            for y = y2-class.stroke+1,y2 do
                if class.pixles[x] ~= nil then
                    if class.pixles[x][y] ~= nil then
                        class.pixles[x][y].bg = class.bgcolor
                        if bg ~= true then
                            class.pixles[x][y].sym = " "
                        end
                    end
                end
            end
        end
        -- right line
        for x = x2-class.stroke+1,x2 do
            for y = y1,y2 do
                if class.pixles[x] ~= nil then
                    if class.pixles [x][y] ~= nil then
                        class.pixles[x][y].bg = class.bgcolor
                        if bg ~= true then
                            class.pixles[x][y].sym = " "
                        end
                    end
                end
            end
        end
        -- left line
        for x = x1,x1+class.stroke-1 do
            for y = y1,y2 do
                if class.pixles[x] ~= nil then
                    if class.pixles [x][y] ~= nil then
                        class.pixles[x][y].bg = class.bgcolor
                        if bg ~= true then
                            class.pixles[x][y].sym = " "
                        end
                    end
                end
            end
        end
    end
end
 
-- supported modes: fill, line
-- bg = only set background color
function circle(class,mode,x,y,r,bg)
    x=round(x) y=round(y)
    for w in pairs(class.pixles) do
        for h in pairs(class.pixles[w]) do
            -- pythagrias sats
            -- a^2 + b^2 = c^2
            local dis = math.sqrt((w-x)^2 + (h-y)^2)
            if dis <= r then
                if mode == "fill" or
                (mode == "line" and dis >= r-class.stroke) then
                    if class.pixles[w] ~= nil then
                        if class.pixles[w][h] ~= nil then
                            class.pixles[w][h].bg = class.bgcolor
                            if bg ~= true then
                                class.pixles[w][h].sym = " "
                            end
                        end
                    end
                end
            end
        end
    end
end
 
-- x,y = top left corner of text field
-- w = width of text field
-- l = max lenght of text
-- c = make the text look like a certain character
-- trans = transparent
-- callback = function, gets events as parameters, if returns true then exit
function read(class,x,y,w,l,initstr,c,trans,callback)
    -- set functions
    local strtotbl = function(str)
        local tbl = {}
        for uchar in str:gmatch("([%z\1-\127\194-\244][\128-\191]*)") do
            table.insert(tbl,uchar)
        end
        return tbl
    end
 
    local tbltostr = function(tbl)
        local str = ""
        for _,value in pairs(tbl) do
            str=str..tostring(value)
        end
        return str
    end
    
    local add = function(tbl,index,element)
        for i = table.maxn(tbl),index,-1 do
            tbl[i+1] = tbl[i]
        end
        tbl[index] = element
    end
 
    local remove = function(tbl,index)
        local max = table.maxn(tbl)
        for i = index+1,max do
            tbl[i-1] = tbl[i]
        end
        tbl[max] = nil
    end
    
    -- check/correct arguments
    x=round(x) y=round(y) w=round(w) l=round(l)
    if type(l)~="number" then l=-1 end
    if type(initstr)~="string" then initstr="" end
    local running = true
    local text = strtotbl(initstr)
    local padding = table.maxn(text)-w
    local cursor = table.maxn(text)+1
    
    callback = callback or function(ev,p1,p2,p3,p4,p5)
        if ev == "key" and p1 == keys.enter then
            return true
        end
    end
    
    while running do
        -- fix cursor and padding
        if cursor > table.maxn(text) then cursor = table.maxn(text) end
        if cursor < 0 then cursor = 0 end
        if padding > table.maxn(text)-1 then padding = table.maxn(text)-1 end
        if padding < 0 then padding = 0 end
        
        -- drawing
        if trans ~= true then
            class:rect("fill",x,y,x+w,y,false)
        end
        if type(c) == "string" then
            local str = c:rep(math.floor(table.maxn(text)/#c)) .. c:sub(1,table.maxn(text)%#c)
            class:write(str:sub(padding+1,padding+w+1),x,y,true)
        else
            for pos = padding+1,math.min(table.maxn(text),w+padding+1) do
                if text[pos] then
                    class:write(text[pos],x+pos-padding-1,y,true)
                end
            end
        end
        
        class:update()
        class:draw()
        
        if cursor-padding <= w and cursor-padding >= 0 then
            class.obj.setCursorPos(x+cursor-padding,y)
            class.obj.setTextColor(class:getfgcolor())
            class.obj.setCursorBlink(true)
        end
        
        local ev,p1,p2,p3,p4,p5 = os.pullEvent()
        
        class.obj.setCursorBlink(false)
        
        if callback(ev,p1,p2,p3,p4,p5) == true then
            local str = tbltostr(text)
            return str,ev,p1,p2,p3,p4,p5
        end
        if ev == "key" then
            if p1 == keys.left then
                -- move left
                cursor = cursor - 1
                if cursor<padding then padding = padding - 1 end
            elseif p1 == keys.right then
                -- move right
                cursor = cursor + 1
                if cursor-padding > w then padding = padding + 1 end
            elseif p1 == keys.backspace then
                -- remove a character
                --local num = cursor-1
                --if num < 0 then num = 0 end
                --text = text:sub(1,num) .. text:sub(cursor+1)
                remove(text,cursor)
                cursor = cursor - 1
                if cursor<padding then padding = padding - 1 end
            elseif p1 == keys.delete then
                -- remove a character
                if text[cursor+1] then
                    remove(text,cursor+1)
                end
                --text = text:sub(1,cursor) .. text:sub(cursor+2)
            elseif p1 == keys.home then
                -- jump to start
                cursor = 0
                padding = 0
            elseif p1 == keys["end"] then
                -- jump to end
                cursor = table.maxn(text)
                padding = table.maxn(text)-w
            end
        elseif ev == "char" then
            if table.maxn(text) < l or l <= 0 then -- check length limit
                -- add a character
                --text = text:sub(1,cursor) .. p1 .. text:sub(cursor+1)
                add(text,cursor+1,p1)
                cursor = cursor + 1
                if cursor-padding > w then padding = padding + 1 end
            end
        elseif (ev == "mouse_click" and class.type == "term")
        or (ev == "monitor_touch" and class.type == "monitor" and p1 == class.path) then
            -- move cursor
            -- x=p2, y=p3
            if p2<x then p2=x end
            if p2>x+w then p2=x+w end
            cursor = p2-x+padding
        elseif ev == "mouse_scroll" then
            -- scrolling left/right
            padding = padding + p1
        end
    end
end
 
function load(objpath)
    local startload = os.clock()
    
    tobj = {}
    
    -- object variables
    objpath = objpath or "N/A"
    if peripheral.isPresent(objpath)
    and peripheral.getType(objpath) == "monitor" then
        tobj.obj = peripheral.wrap(objpath or "N/A")
        tobj.type = "monitor"
        tobj.path = objpath
        tobj.eventname = "monitor_touch"
    else
        tobj.type = "term"
        tobj.obj = term
        tobj.path = "N/A"
        tobj.eventname = "mouse_click"
    end
    
    -- variables
    tobj.pixles = {}
    tobj.updaterate = 0.2
    tobj.looprunning = false
    tobj.looptime = 0
    tobj.stroke = 1
    tobj.bgcolor = colors.black
    tobj.fgcolor = colors.white
    
    -- misc functions
    tobj.setupdaterate = setupdaterate
    tobj.getupdaterate = getupdaterate
    tobj.removepixles = removepixles
    tobj.fixpixles = fixpixles
    tobj.update = update
    tobj.draw = draw
    tobj.loop = loop
    tobj.prepareloop = prepareloop
    tobj.stoploop = stoploop
    
    -- color functions
    tobj.setcolor = setcolor
    tobj.setfgcolor = setfgcolor
    tobj.setbgcolor = setbgcolor
    tobj.getcolor = getcolor
    tobj.getfgcolor = getfgcolor
    tobj.getbgcolor = getbgcolor
    tobj.setstroke = setstroke
    tobj.getstroke = getstroke
    -- british
    tobj.setcolour = setcolor
    tobj.setfgcolour = setfgcolor
    tobj.setbgcolour = setbgcolor
    tobj.getcolour = getcolor
    tobj.getfgcolour = getfgcolor
    tobj.getbgcolour = getbgcolor
    
    -- drawing functions
    tobj.clear = clear
    tobj.write = write
    tobj.line = line
    tobj.rect = rect
    tobj.circle = circle
    tobj.read = read
    
    tobj:removepixles()
    tobj:fixpixles()
    
    local endload = os.clock()
    return tobj,endload-startload
end

Comments