SHOW:
|
|
- or go back to the newest paste.
| 1 | -- display API | |
| 2 | -- made by akaJag | |
| 3 | -- work in progress | |
| 4 | ||
| 5 | function round(num) | |
| 6 | if type(num) ~= "number" then return num end | |
| 7 | if num%1<.5 then num=math.floor(num) end | |
| 8 | if num%1>=.5 then num=math.ceil(num) end | |
| 9 | return num | |
| 10 | end | |
| 11 | ||
| 12 | function setupdaterate(class,s) | |
| 13 | class.updaterate = s | |
| 14 | end | |
| 15 | ||
| 16 | function getupdaterate(class) | |
| 17 | return class.updaterate | |
| 18 | end | |
| 19 | ||
| 20 | function removepixles(class) | |
| 21 | local w,h = class.obj.getSize() | |
| 22 | ||
| 23 | -- check row | |
| 24 | local width = next(class.pixles) | |
| 25 | while width do | |
| 26 | if width > w or width < 0 then | |
| 27 | -- remove row | |
| 28 | local tmpw = width | |
| 29 | width = next(class.pixles,width) | |
| 30 | class.pixles[tmpw] = nil | |
| 31 | else | |
| 32 | -- check column | |
| 33 | local height = next(class.pixles[width]) | |
| 34 | while height do | |
| 35 | if height > h or height < 0 then | |
| 36 | -- remove column | |
| 37 | local tmph = height | |
| 38 | height = next(class.pixles[width],height) | |
| 39 | class.pixles[width][tmph] = nil | |
| 40 | else | |
| 41 | -- next iteration | |
| 42 | height = next(class.pixles[width],height) | |
| 43 | end | |
| 44 | end | |
| 45 | -- next iteration | |
| 46 | width = next(class.pixles,width) | |
| 47 | end | |
| 48 | end | |
| 49 | end | |
| 50 | ||
| 51 | function fixpixles(class) | |
| 52 | local w,h = class.obj.getSize() | |
| 53 | for width = 1,w do | |
| 54 | if class.pixles[width] == nil then class.pixles[width] = {} end
| |
| 55 | for height = 1,h do | |
| 56 | if class.pixles[width][height] == nil then | |
| 57 | class.pixles[width][height] = {sym=" ",bg=colors.black,fg=colors.white}
| |
| 58 | end | |
| 59 | end | |
| 60 | end | |
| 61 | end | |
| 62 | ||
| 63 | -- returns: | |
| 64 | -- (number) update time | |
| 65 | function update(class) | |
| 66 | local startupdate = os.clock() | |
| 67 | ||
| 68 | class:removepixles() | |
| 69 | class:fixpixles() | |
| 70 | ||
| 71 | local endupdate = os.clock() | |
| 72 | return endupdate - startupdate | |
| 73 | end | |
| 74 | ||
| 75 | function draw(class) | |
| 76 | local startdraw = os.clock() | |
| 77 | ||
| 78 | for w in pairs(class.pixles) do | |
| 79 | for h,pixle in pairs(class.pixles[w]) do | |
| 80 | class.obj.setCursorPos(w,h) | |
| 81 | class.obj.setBackgroundColor(pixle.bg or colors.black) | |
| 82 | class.obj.setTextColor(pixle.fg or colors.white) | |
| 83 | class.obj.write(pixle.sym or " ") | |
| 84 | end | |
| 85 | end | |
| 86 | ||
| 87 | local enddraw = os.clock() | |
| 88 | return enddraw - startdraw | |
| 89 | end | |
| 90 | ||
| 91 | -- can be used in a parallel loop | |
| 92 | -- dont forget to do prepareloop() before running | |
| 93 | -- stop it with stoploop() | |
| 94 | function loop(class) | |
| 95 | if not running then return end | |
| 96 | local s = class:update() | |
| 97 | s = s + class:draw() | |
| 98 | sleep(updaterate - s) | |
| 99 | end | |
| 100 | ||
| 101 | function prepareloop(class) | |
| 102 | class.looprunning = true | |
| 103 | class.looptime = os.clock() | |
| 104 | end | |
| 105 | ||
| 106 | -- returns the time the loop has been on | |
| 107 | function stoploop() | |
| 108 | class.looprunning = false | |
| 109 | return os.clock - class.looptime | |
| 110 | end | |
| 111 | ||
| 112 | function setcolor(class,fg,bg) | |
| 113 | class.fgcolor = fg or class.fgcolor | |
| 114 | class.bgcolor = bg or class.bgcolor | |
| 115 | end | |
| 116 | ||
| 117 | function getcolor(class) | |
| 118 | return class.fgcolor,class.bgcolor | |
| 119 | end | |
| 120 | ||
| 121 | function setfgcolor(class,col) | |
| 122 | class.fgcolor = col | |
| 123 | end | |
| 124 | ||
| 125 | function getfgcolor(class) | |
| 126 | return class.fgcolor | |
| 127 | end | |
| 128 | ||
| 129 | function setbgcolor(class,col) | |
| 130 | class.bgcolor = col | |
| 131 | end | |
| 132 | ||
| 133 | function getbgcolor(class) | |
| 134 | return class.bgcolor | |
| 135 | end | |
| 136 | ||
| 137 | -- stroke is only used with "line" draw mode | |
| 138 | function setstroke(class,var) | |
| 139 | class.stroke=var | |
| 140 | end | |
| 141 | ||
| 142 | function getstroke(class) | |
| 143 | return class.stroke | |
| 144 | end | |
| 145 | ||
| 146 | -- clears the entire screen | |
| 147 | -- bg = only change background, ignore text | |
| 148 | function clear(class,bg) | |
| 149 | for w in pairs(class.pixles) do | |
| 150 | for h,pixle in pairs(class.pixles[w]) do | |
| 151 | class.pixles[w][h].bg = class.bgcolor | |
| 152 | if bg ~= true then | |
| 153 | class.pixles[w][h].sym = " " | |
| 154 | end | |
| 155 | end | |
| 156 | end | |
| 157 | end | |
| 158 | ||
| 159 | -- trans = transparant option | |
| 160 | function write(class,str,x,y,trans) | |
| 161 | x=round(x) y=round(y) | |
| 162 | for count = 1,#str do | |
| 163 | if class.pixles[x+count-1] then | |
| 164 | if class.pixles[x+count-1][y] then | |
| 165 | class.pixles[x+count-1][y].sym = str:sub(count,count) | |
| 166 | class.pixles[x+count-1][y].fg = class.fgcolor | |
| 167 | if trans ~= true then | |
| 168 | class.pixles[x+count-1][y].bg = class.bgcolor | |
| 169 | end | |
| 170 | end | |
| 171 | end | |
| 172 | end | |
| 173 | end | |
| 174 | ||
| 175 | function line(class,x1,y1,x2,y2,bg) | |
| 176 | -- Bresenham's algorithm | |
| 177 | local dx = x2 - x1 | |
| 178 | if dx < 0 then dx = -dx end | |
| 179 | local dy = y2 - y1 | |
| 180 | if dy < 0 then dy = -dy end | |
| 181 | ||
| 182 | local sx,sy | |
| 183 | if x1 < x2 then sx = 1 | |
| 184 | else sx = -1 end | |
| 185 | if y1 < y2 then sy = 1 | |
| 186 | else sy = -1 end | |
| 187 | ||
| 188 | local err = dx - dy | |
| 189 | ||
| 190 | repeat | |
| 191 | local x,y = round(x1),round(y1) | |
| 192 | if class.pixles[x] then | |
| 193 | if class.pixles[x][y] then | |
| 194 | class.pixles[x][y].bg = class.bgcolor | |
| 195 | if bg ~= true then | |
| 196 | class.pixles[x][y].sym = " " | |
| 197 | end | |
| 198 | end | |
| 199 | end | |
| 200 | ||
| 201 | if x1 == x2 and y1 == y2 then break end | |
| 202 | local e2 = 2*err | |
| 203 | if e2 > -dy then | |
| 204 | err = err - dy | |
| 205 | x1 = x1 + sx | |
| 206 | end | |
| 207 | if e2 < dx then | |
| 208 | err = err + dx | |
| 209 | y1 = y1 + sy | |
| 210 | end | |
| 211 | until false | |
| 212 | end | |
| 213 | ||
| 214 | -- supported modes: fill, line | |
| 215 | -- bg = only set background color | |
| 216 | function rect(class,mode,x1,y1,x2,y2,bg) | |
| 217 | x1=round(x1) y1=round(y1) x2=round(x2) y2=round(y2) | |
| 218 | if mode == "fill" then | |
| 219 | for x = x1,x2 do | |
| 220 | for y = y1,y2 do | |
| 221 | if class.pixles[x] ~= nil then | |
| 222 | if class.pixles[x][y] ~= nil then | |
| 223 | class.pixles[x][y].bg = class.bgcolor | |
| 224 | if bg ~= true then | |
| 225 | class.pixles[x][y].sym = " " | |
| 226 | end | |
| 227 | end | |
| 228 | end | |
| 229 | end | |
| 230 | end | |
| 231 | elseif mode == "line" then | |
| 232 | -- top line | |
| 233 | for x = x1,x2 do | |
| 234 | for y = y1,y1+class.stroke-1 do | |
| 235 | if class.pixles[x] ~= nil then | |
| 236 | if class.pixles[x][y] ~= nil then | |
| 237 | class.pixles[x][y].bg = class.bgcolor | |
| 238 | if bg ~= true then | |
| 239 | class.pixles[x][y].sym = " " | |
| 240 | end | |
| 241 | end | |
| 242 | end | |
| 243 | end | |
| 244 | end | |
| 245 | -- bottom line | |
| 246 | for x = x1,x2 do | |
| 247 | for y = y2-class.stroke+1,y2 do | |
| 248 | if class.pixles[x] ~= nil then | |
| 249 | if class.pixles[x][y] ~= nil then | |
| 250 | class.pixles[x][y].bg = class.bgcolor | |
| 251 | if bg ~= true then | |
| 252 | class.pixles[x][y].sym = " " | |
| 253 | end | |
| 254 | end | |
| 255 | end | |
| 256 | end | |
| 257 | end | |
| 258 | -- right line | |
| 259 | for x = x2-class.stroke+1,x2 do | |
| 260 | for y = y1,y2 do | |
| 261 | if class.pixles[x] ~= nil then | |
| 262 | if class.pixles [x][y] ~= nil then | |
| 263 | class.pixles[x][y].bg = class.bgcolor | |
| 264 | if bg ~= true then | |
| 265 | class.pixles[x][y].sym = " " | |
| 266 | end | |
| 267 | end | |
| 268 | end | |
| 269 | end | |
| 270 | end | |
| 271 | -- left line | |
| 272 | for x = x1,x1+class.stroke-1 do | |
| 273 | for y = y1,y2 do | |
| 274 | if class.pixles[x] ~= nil then | |
| 275 | if class.pixles [x][y] ~= nil then | |
| 276 | class.pixles[x][y].bg = class.bgcolor | |
| 277 | if bg ~= true then | |
| 278 | class.pixles[x][y].sym = " " | |
| 279 | end | |
| 280 | end | |
| 281 | end | |
| 282 | end | |
| 283 | end | |
| 284 | end | |
| 285 | end | |
| 286 | ||
| 287 | -- supported modes: fill, line | |
| 288 | -- bg = only set background color | |
| 289 | function circle(class,mode,x,y,r,bg) | |
| 290 | x=round(x) y=round(y) | |
| 291 | for w in pairs(class.pixles) do | |
| 292 | for h in pairs(class.pixles[w]) do | |
| 293 | -- pythagrias sats | |
| 294 | -- a^2 + b^2 = c^2 | |
| 295 | local dis = math.sqrt((w-x)^2 + (h-y)^2) | |
| 296 | if dis <= r then | |
| 297 | if mode == "fill" or | |
| 298 | (mode == "line" and dis >= r-class.stroke) then | |
| 299 | if class.pixles[w] ~= nil then | |
| 300 | if class.pixles[w][h] ~= nil then | |
| 301 | class.pixles[w][h].bg = class.bgcolor | |
| 302 | if bg ~= true then | |
| 303 | class.pixles[w][h].sym = " " | |
| 304 | end | |
| 305 | end | |
| 306 | end | |
| 307 | end | |
| 308 | end | |
| 309 | end | |
| 310 | end | |
| 311 | end | |
| 312 | ||
| 313 | local function strtotbl(str) | |
| 314 | local tbl = {}
| |
| 315 | for uchar in str:gmatch("([%z\1-\127\194-\244][\128-\191]*)") do
| |
| 316 | table.insert(tbl,uchar) | |
| 317 | end | |
| 318 | return tbl | |
| 319 | end | |
| 320 | ||
| 321 | local function tbltostr(tbl) | |
| 322 | local str = "" | |
| 323 | for _,value in pairs(tbl) do | |
| 324 | - | local text = initstr |
| 324 | + | str=str..tostring(value) |
| 325 | - | local padding = text:len()-w |
| 325 | + | |
| 326 | - | local cursor = text:len() |
| 326 | + | |
| 327 | ||
| 328 | -- x,y = top left corner of text field | |
| 329 | -- w = width of text field | |
| 330 | -- l = max lenght of text | |
| 331 | -- c = make the text look like a certain character | |
| 332 | -- trans = transparent | |
| 333 | -- callback = function, gets events as parameters, if returns true then exit | |
| 334 | function read(class,x,y,w,l,initstr,c,trans,callback) | |
| 335 | x=round(x) y=round(y) w=round(w) l=round(l) | |
| 336 | if type(l)~="number" then l=-1 end | |
| 337 | if type(initstr)~="string" then initstr="" end | |
| 338 | local running = true | |
| 339 | local text = initstr or "" | |
| 340 | local padding = #text-w | |
| 341 | local cursor = #text | |
| 342 | ||
| 343 | callback = callback or function(ev,p1,p2,p3,p4,p5) | |
| 344 | if ev == "key" and p1 == keys.enter then | |
| 345 | return true | |
| 346 | - | local str = c:rep(math.floor(#text/#c)) .. c:sub(1,#text%#c) |
| 346 | + | |
| 347 | end | |
| 348 | ||
| 349 | - | class:write(text:sub(padding+1,padding+w+1),x,y,true) |
| 349 | + | |
| 350 | -- fix cursor and padding | |
| 351 | if cursor > #text then cursor = #text end | |
| 352 | if cursor < 0 then cursor = 0 end | |
| 353 | if padding > #text-1 then padding = #text-1 end | |
| 354 | if padding < 0 then padding = 0 end | |
| 355 | ||
| 356 | -- drawing | |
| 357 | if trans ~= true then | |
| 358 | class:rect("fill",x,y,x+w,y,false)
| |
| 359 | end | |
| 360 | local tbl = strtotbl(text) | |
| 361 | if type(c) == "string" then | |
| 362 | local str = c:rep(math.floor(#tbl/#c)) .. c:sub(1,#tbl%#c) | |
| 363 | class:write(str:sub(padding+1,padding+w+1),x,y,true) | |
| 364 | else | |
| 365 | local count = 0 | |
| 366 | for index = padding+1,padding+w+1 do | |
| 367 | if text[index] then | |
| 368 | class:write(text[index],x+count,y,true) | |
| 369 | end | |
| 370 | count = count + 1 | |
| 371 | end | |
| 372 | end | |
| 373 | ||
| 374 | class:update() | |
| 375 | class:draw() | |
| 376 | ||
| 377 | if cursor-padding <= w and cursor-padding >= 0 then | |
| 378 | class.obj.setCursorPos(x+cursor-padding,y) | |
| 379 | class.obj.setTextColor(class:getfgcolor()) | |
| 380 | class.obj.setCursorBlink(true) | |
| 381 | end | |
| 382 | ||
| 383 | local ev,p1,p2,p3,p4,p5 = os.pullEvent() | |
| 384 | ||
| 385 | class.obj.setCursorBlink(false) | |
| 386 | ||
| 387 | if callback(ev,p1,p2,p3,p4,p5) == true then | |
| 388 | return text,ev,p1,p2,p3,p4,p5 | |
| 389 | end | |
| 390 | if ev == "key" then | |
| 391 | if p1 == keys.left then | |
| 392 | -- move left | |
| 393 | cursor = cursor - 1 | |
| 394 | if cursor<padding then padding = padding - 1 end | |
| 395 | elseif p1 == keys.right then | |
| 396 | -- move right | |
| 397 | cursor = cursor + 1 | |
| 398 | if cursor-padding > w then padding = padding + 1 end | |
| 399 | elseif p1 == keys.backspace then | |
| 400 | -- remove a character | |
| 401 | local num = cursor-1 | |
| 402 | if num < 0 then num = 0 end | |
| 403 | text = text:sub(1,num) .. text:sub(cursor+1) | |
| 404 | cursor = cursor - 1 | |
| 405 | if cursor<padding then padding = padding - 1 end | |
| 406 | elseif p1 == keys.delete then | |
| 407 | -- remove a character | |
| 408 | text = text:sub(1,cursor) .. text:sub(cursor+2) | |
| 409 | elseif p1 == keys.home then | |
| 410 | cursor = 0 | |
| 411 | padding = 0 | |
| 412 | elseif p1 == keys["end"] then | |
| 413 | cursor = text:len() | |
| 414 | padding = text:len()-w | |
| 415 | end | |
| 416 | elseif ev == "char" then | |
| 417 | if #text < l or l <= 0 then -- check length limit | |
| 418 | -- add a character | |
| 419 | text = text:sub(1,cursor) .. p1 .. text:sub(cursor+1) | |
| 420 | cursor = cursor + 1 | |
| 421 | if cursor-padding > w then padding = padding + 1 end | |
| 422 | end | |
| 423 | elseif (ev == "mouse_click" and class.type == "term") | |
| 424 | or (ev == "monitor_touch" and class.type == "monitor" and p1 == class.path) then | |
| 425 | -- move cursor | |
| 426 | -- x=p2, y=p3 | |
| 427 | if p2<x then p2=x end | |
| 428 | if p2>x+w then p2=x+w end | |
| 429 | cursor = p2-x+padding | |
| 430 | elseif ev == "mouse_scroll" then | |
| 431 | -- scrolling left/right | |
| 432 | padding = padding + p1 | |
| 433 | end | |
| 434 | end | |
| 435 | end | |
| 436 | ||
| 437 | function load(objpath) | |
| 438 | local startload = os.clock() | |
| 439 | ||
| 440 | tobj = {}
| |
| 441 | ||
| 442 | -- object variables | |
| 443 | objpath = objpath or "N/A" | |
| 444 | if peripheral.isPresent(objpath) | |
| 445 | and peripheral.getType(objpath) == "monitor" then | |
| 446 | tobj.obj = peripheral.wrap(objpath or "N/A") | |
| 447 | tobj.type = "monitor" | |
| 448 | tobj.path = objpath | |
| 449 | tobj.eventname = "monitor_touch" | |
| 450 | else | |
| 451 | tobj.type = "term" | |
| 452 | tobj.obj = term | |
| 453 | tobj.path = "N/A" | |
| 454 | tobj.eventname = "mouse_click" | |
| 455 | end | |
| 456 | ||
| 457 | -- variables | |
| 458 | tobj.pixles = {}
| |
| 459 | tobj.updaterate = 0.2 | |
| 460 | tobj.looprunning = false | |
| 461 | tobj.looptime = 0 | |
| 462 | tobj.stroke = 1 | |
| 463 | tobj.bgcolor = colors.black | |
| 464 | tobj.fgcolor = colors.white | |
| 465 | ||
| 466 | -- misc functions | |
| 467 | tobj.setupdaterate = setupdaterate | |
| 468 | tobj.getupdaterate = getupdaterate | |
| 469 | tobj.removepixles = removepixles | |
| 470 | tobj.fixpixles = fixpixles | |
| 471 | tobj.update = update | |
| 472 | tobj.draw = draw | |
| 473 | tobj.loop = loop | |
| 474 | tobj.prepareloop = prepareloop | |
| 475 | tobj.stoploop = stoploop | |
| 476 | ||
| 477 | -- color functions | |
| 478 | tobj.setcolor = setcolor | |
| 479 | tobj.setfgcolor = setfgcolor | |
| 480 | tobj.setbgcolor = setbgcolor | |
| 481 | tobj.getcolor = getcolor | |
| 482 | tobj.getfgcolor = getfgcolor | |
| 483 | tobj.getbgcolor = getbgcolor | |
| 484 | tobj.setstroke = setstroke | |
| 485 | tobj.getstroke = getstroke | |
| 486 | -- british | |
| 487 | tobj.setcolour = setcolor | |
| 488 | tobj.setfgcolour = setfgcolor | |
| 489 | tobj.setbgcolour = setbgcolor | |
| 490 | tobj.getcolour = getcolor | |
| 491 | tobj.getfgcolour = getfgcolor | |
| 492 | tobj.getbgcolour = getbgcolor | |
| 493 | ||
| 494 | -- drawing functions | |
| 495 | tobj.clear = clear | |
| 496 | tobj.write = write | |
| 497 | tobj.line = line | |
| 498 | tobj.rect = rect | |
| 499 | tobj.circle = circle | |
| 500 | tobj.read = read | |
| 501 | ||
| 502 | tobj:removepixles() | |
| 503 | tobj:fixpixles() | |
| 504 | ||
| 505 | local endload = os.clock() | |
| 506 | return tobj,endload-startload | |
| 507 | end |