-- 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) for count = 1,#str do if class.pixles[x+count-1] then if class.pixles[x+count-1][y] then class.pixles[x+count-1][y].sym = str:sub(count,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 local function strtotbl(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 function tbltostr(tbl) local str = "" for _,value in pairs(tbl) do str=str..tostring(value) 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) 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 = initstr or "" local padding = #text-w local cursor = #text 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 > #text then cursor = #text end if cursor < 0 then cursor = 0 end if padding > #text-1 then padding = #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 local tbl = strtotbl(text) if type(c) == "string" then local str = c:rep(math.floor(#tbl/#c)) .. c:sub(1,#tbl%#c) class:write(str:sub(padding+1,padding+w+1),x,y,true) else local count = 0 for index = padding+1,padding+w+1 do if text[index] then class:write(text[index],x+count,y,true) end count = count + 1 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 return text,ev,p1,p2,p3,p4,p5 end if ev == "key" then if p1 == keys.left then -- move left cursor = cursor - 1 if cursor 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) cursor = cursor - 1 if cursor 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 p2x+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