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 |