A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 919 lines 30 kB view raw
1--[[ 2 __________ __ ___. 3 Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 \/ \/ \/ \/ \/ 8 $Id$ 9 Example Lua RBIMAGE script 10 Copyright (C) 2009 by Maurus Cuelenaere -- some prior work 11 Copyright (C) 2017 William Wilgus 12 This program is free software; you can redistribute it and/or 13 modify it under the terms of the GNU General Public License 14 as published by the Free Software Foundation; either version 2 15 of the License, or (at your option) any later version. 16 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17 KIND, either express or implied. 18]]-- 19 20require("actions") -- Contains rb.actions & rb.contexts 21-- require("buttons") -- Contains rb.buttons -- not needed for this example 22 23local _math = require("math_ex") -- missing math sine cosine, sqrt, clamp functions 24local _timer = require("timer") 25local _clr = require("color") -- clrset, clrinc provides device independent colors 26local _lcd = require("lcd") -- lcd helper functions 27local _print = require("print") -- advanced text printing 28local _img = require("image") -- image manipulation save, rotate, resize, tile, new, load 29local _img_save = require("image_save") 30local _blit = require("blit") -- handy list of blit operations 31local _draw = require("draw") -- draw all the things (primitives) 32local _draw_floodfill = require("draw_floodfill") 33local _draw_text = require("draw_text") 34 35--local scrpath = rb.current_path()" 36 37--package.path = scrpath .. "/?.lua;" .. package.path --add lua_scripts directory to path 38 39require("printmenus") --menu 40 41--[[ RBIMAGE library functions 42NOTE!! on x, y coordinates + width & height 43---------------------------------------------- 44When making a new image you specify the width and height say (10, 20). 45Intutively (at least to me) (0,0) (offset addressing) would reference the first 46pixel (top left) and the last pixel (bottom, right) would be (w-1, h-1) or (9, 19) 47but the original rbimage library (like lua) uses 1-based arrays (ordinal addressing) 48for the image data so the first pixel is (1,1) and the last pixel is (w, h) 49this presents a bit of a problem when interfacing with the internal rockbox 50functions as you must remeber to convert all lua coordinates to 0 based coordinates. 51I have opted to not change this in the name of compatibility with old scripts 52 53NOTE2!! on width & height versus offset_x & offset_y :copy() 54------------------------------------------------------------------------ 55The only place where RBIMAGE deviates from (ordinal addressing) is in the blit 56/ copy function sx, sy and dx, dy still refer to the same pixel as all the 57other functions but offset_x, and offset_y are zero based 58Example (assuming same sized images) 59dst:copy(src, 1,1, 1,1, 0, 0) 60would copy the first pixel from src to the first pixel of dst 61dst:copy(src, 1,1, 1,1, dst:width()-1, dst:height()-1) would copy all of src to dst 62this might be a bit confusing but makes reversing images (negative offsets) easier. 63Since offsets are auto calculated if empty or out of range you could call it as 64dst:copy(src, 1,1, 1,1, dst:width(), dst:height()) or even 65dst:copy(src, 1,1, 1,1) if you prefered and get the same result 66]] 67 68--'CONSTANTS' (in lua there really is no such thing as all vars are mutable) 69-------------------------------------------------------- 70--colors for fg/bg ------------------------ 71local WHITE = _clr.set(-1, 255, 255, 255) 72local BLACK = _clr.set(0, 0, 0, 0) 73local RED = _clr.set(WHITE, 255) 74local GREEN = _clr.set(WHITE, 0, 255) 75local BLUE = _clr.set(WHITE, 0, 0, 255) 76------------------------------------------- 77local clrs 78local CANCEL_BUTTON = rb.actions.PLA_CANCEL 79local LCD_DEPTH = rb.LCD_DEPTH 80-- EXAMPLES ---------------------------------------------------------------------- EXAMPLES--------------------------------------------------------------------- 81function my_blit(dst_val, dx, dy, src_val, sx, sy) 82 -- user defined blit operation 83 --this function gets called for every pixel you specify 84 --you may change pixels in both the source and dest image 85 --return nil to stop early 86 87 if LCD_DEPTH < 2 then 88 return src_val 89 end 90 91 if dst_val == WHITE and bit.band(dx, 1) == 1 and bit.band(dy, 1) == 1 then 92 return BLACK; 93 elseif dst_val == WHITE then 94 return src_val 95 end 96 97 return dst_val 98end 99 100function create_logo() 101 --[[creates a small logo from data array]] 102 103 -- moves scope of white and black from global to local 104 local WHITE = WHITE 105 local BLACK = BLACK 106 107 --[[small array with 16 bits of data per element (16-bits in y direction) 108 while the number of elements (32) is the x direction. 109 in other words 16 rows X 32 columns, totally abritrary actually 110 you could easily rotate or flip it by changing the for loops below ]] 111 local logo = {0xFFFF, 0xFFFF, 0x8001, 0x8001, 0x9E7F, 0x9E7F, 0x9E7F, 0x9E7F, 112 0x9E3F, 0x9E3F, 0x804F, 0x804F, 0xC0E1, 0xC0F1, 0xFFFD, 0xFFFF, 113 0xFFFF, 0xFFFF, 0x8001, 0x8001, 0xFF01, 0xFF01, 0xFEFB, 0xFEFB, 114 0xFDFD, 0xFDFD, 0xFDFD, 0xFCF9, 0xFE03, 0xFE03, 0xFFFF, 0xFFFF} 115 116 local img, img1, img2, img3 117 118 img = _img.new(_lcd.W, _lcd.H) 119 img:clear(BLACK) --[[always clear an image after you create it if you 120 intend to do any thing besides copy something 121 entirely to it as there is no guarantee what 122 state the data within is in, it could be all 123 0's or it could be every digit of PI ]] 124 125 -- check for an error condition bail if error 126 if(not img or not logo) then 127 return nil 128 end 129 130 local logosz = table.getn(logo) 131 local bits = 16 -- each element contains 16 pixels 132 local data = 0 133 134 for i=1, math.min(logosz, _lcd.W) do 135 for j=0, math.min(bits, _lcd.H) do 136 137 if bit.band(bit.lshift(1, bits - j), logo[i]) > 0 then 138 data = WHITE 139 else 140 data = BLACK 141 end 142 -- Set the pixel at position i, j+1 to the copied data 143 img:set(i, j + 1, data) 144 end 145 end 146 147 -- make a new image the size of our generated logo 148 img1 = _img.new(logosz + 1, bits + 1) 149 150 -- img.copy(dest, source, dx, dy, sx, sy, [w, h]) 151 img1:copy(img, 1, 1, 1, 1) 152 153 --[[lua does auto garbage collection, but it is still 154 a good idea to set large items to nil when done anyways]] 155 img = nil 156 157 local sl -- new image size 158 if _lcd.W < _lcd.H then 159 sl = _lcd.W / 3 160 else 161 sl = _lcd.H / 3 162 end 163 164 -- make sl always even by subtracting 1 if needed 165 sl = bit.band(sl, bit.bnot(1)) 166 if sl < 16 then 167 sl = 16 168 end 169 170 img2 = _img.new(sl, sl) 171 --img2:clear(BLACK) -- doesn't need cleared since we copy to it entirely 172 173 --[[we are going to resize the image since the data supplied is 32 x 16 174 pixels its really tiny on most screens]] 175 _img.resize(img2, img1) 176 177 img1 = nil 178 179 img3 = _img.new(sl, sl) 180 img3:clear(BLACK) 181 182 if IS_COLOR_TARGET == true then 183 local c_yellow = _clr.set(WHITE, 0xFC, 0xC0, 0x00) 184 local c_grey = _clr.set(WHITE, 0xD4, 0xE3, 0xF3) 185 local c_dkgrey = _clr.set(WHITE, 0xB4, 0xC3, 0xD3) 186 -- if dest pixel == source pixel make dest pixel yellow 187 img3:copy(img2, 1, 1, 1, 1, nil, nil, false, _blit.BDEQS, c_yellow) 188 -- xor src pixel to dest pixel if both are 0 or both are 1 dest = 0 189 img2:copy(img3, 1, 1, 2, 1, nil, nil, false, _blit.BXOR) 190 -- if dest pixel color > src pixel color copy grey to dest 191 img2:copy(img3, 1, 1, 1, 1, nil, nil, false, _blit.BDGTS, c_grey) 192 -- set img3 to grey 193 img3:clear(c_dkgrey) 194 end 195 196 -- make a WHITE square in the middle 197 198 img3:clear(WHITE, 4,4, img3:width() - 3, img3:height() - 3) 199 200 img3:copy(img2, 1, 1, 1, 1, nil, nil, false, _blit.CUSTOM, my_blit) 201 img2 = nil 202 _img_save(img3, "pix.bmp") 203 return img3 204end -- copy_logo 205 206-- draws an olive erm ball and returns it 207function create_ball() 208 local sl -- image size 209 if _lcd.W < _lcd.H then 210 sl = _lcd.W / 5 211 else 212 sl = _lcd.H / 5 213 end 214 215 -- make sl always even by subtracting 1 if needed 216 sl = bit.band(sl, bit.bnot(1)) 217 if sl < 16 then 218 sl = 16 219 end 220 local img = _img.new(sl, sl) 221 img:clear(0) 222 _draw.circle_filled(img, sl/2, sl/2, sl/2 - 1, _clr.set(-1, 255), _clr.set(0, 100)) 223 _draw.circle_filled(img, sl/3, sl/3, sl/10, _clr.set(-1, 255, 0, 0)) 224 return img 225end 226 227-- bounces img around on screen 228function bounce_image(img) 229 local timer = _timer() -- creates a new timer -- saves index 230 local wait 231 -- make a copy of the current screen for later 232 local screen_img = _lcd:duplicate() 233 234 local img_sqy = _img.new(img:width() + img:width() / 8, img:height()) 235 local img_sqx = _img.new(img:width(), img:height() + img:height() / 8) 236 _img.resize(img_sqy, img) 237 _img.resize(img_sqx, img) 238 239 -- moves definition of CANCEL_BUTTON from global to local 240 local CANCEL_BUTTON = CANCEL_BUTTON 241-------------------------------------------------------- 242 local imgn = img 243 local hold = 0 244 local sx = 1 -- starting x 245 local sy = 1 -- starting y 246 247 local ex = _lcd.W - img:width() - 2 248 local ey = _lcd.H - img:width() - 2 249 250 -- threshold resets speed, inverts image 251 local tx = ex / 5 252 local ty = ey / 5 253 254 local last_x = sx 255 local last_y = sy 256 257 local x = sx 258 local y = sy 259 260 local dx = 1 261 local dy = 1 262 -- negative width\height cause the image to be drawn from the opposite end 263 local fx = _lcd.W 264 local fy = _lcd.H 265 266 local function invert_images() 267 img:invert(); 268 img_sqx:invert() 269 img_sqy:invert() 270 end 271 272 local loops = (_lcd.W * _lcd.H) / 2 273 while (loops > 0) do 274 275 if IS_COLOR_TARGET then 276 if bit.band(loops, 128) == 128 then 277 _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, _blit.BOR) 278 _lcd:copy(screen_img, x, y, x, y, imgn:width(), imgn:height(), 279 false, _blit.BDEQC, imgn:get(1,1)) 280 else 281 _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, _blit.BSNEC, imgn:get(1,1)) 282 end 283 else 284 local blitop 285 286 if imgn:get(1,1) ~= 0 then 287 blitop = _blit.BSNOT 288 else 289 blitop = _blit.BXOR 290 end 291 292 _lcd:copy(imgn, x, y, 1, 1, fx, fy, false, blitop, WHITE) 293 end 294 295 if hold < 1 then 296 imgn = img 297 else 298 hold = hold - 1 299 end 300 _lcd:update() 301 302 x = x + dx 303 y = y + dy 304 305 if y >= ey or y <= sy then 306 dy = (-dy) 307 fy = (-fy) 308 imgn = img_sqy 309 hold = 3 310 if dx < 0 and y < 10 then 311 dx = dx - 5 312 end 313 if dx > tx then 314 dx = 5; 315 dy = 5; 316 invert_images() 317 end 318 end 319 320 if x >= ex or x <= sx then 321 dx = (-dx) 322 fx = (-fx) 323 imgn = img_sqx 324 hold = 3 325 if dy < 0 and x < 10 then 326 dy = dy - 5 327 end 328 if dy > ty then 329 dx = 5; 330 dy = 5; 331 invert_images() 332 end 333 end 334 335 x = _math.clamp(x, sx, ex) 336 y = _math.clamp(y, sy, ey) 337 338 -- copy original image back to screen 339 _lcd:copy(screen_img) 340 341 loops = loops -1 342 343 wait = timer:check(true) --checks timer and updates last time 344 if wait >= 5 then 345 wait = 0 346 elseif wait < 5 then 347 wait = 5 - wait 348 end 349 -- 0 = timeout immediately 350 -- ( -1 would be never timeout, and >0 is amount of 'ticks' before timeout) 351 if rb.get_plugin_action(wait) == CANCEL_BUTTON then 352 break; 353 end 354 end 355 356 timer:stop() -- destroys timer, also returns time since last time 357 358 -- leave the screen how we found it 359 _lcd:copy(screen_img) 360end -- image_bounce 361 362-- draws a gradient using available colors 363function draw_gradient(img, x, y, w, h, direction, clrs) 364 x = x or 1 365 y = y or 1 366 w = w or img:width() - x 367 h = h or img:height() - y 368 local zstep = 0 369 local step = 1 370 if IS_COLOR_TARGET == true then -- Only do this when we're on a color target 371 local z = 1 372 local c = 1 373 clrs = clrs or {255,255,255} 374 local function gradient_rgb(p, c1, c2) 375 -- tried squares of difference but blends were very abrupt 376 local r = c1.r + (p * (c2.r - c1.r) / 10500) 377 local g = c1.g + (p * (c2.g - c1.g) / 10000) 378 local b = c1.b + (p * (c2.b - c1.b) / 09999) 379 return _clr.set(nil, r, g, b) 380 end 381 local function check_z() 382 if z > 10000 and c < #clrs - 1 then 383 z = 1 384 c = c + 1 385 elseif z > 10000 then 386 z = 10000 387 end 388 end 389 if direction == "V" then 390 zstep = math.max(1, (10000 / ((w - 1) / (#clrs - 1)) + bit.band(#clrs, 1))) 391 for i=x, w + x do 392 check_z() 393 _draw.vline(img, i, y, h, gradient_rgb(z, clrs[c], clrs[c + 1])) 394 z = z + zstep 395 end 396 else 397 zstep = math.max(1, (10000 / ((h - 1) / (#clrs - 1)) + bit.band(#clrs, 1))) 398 for j=y, h + y do 399 check_z() 400 _draw.hline(img, x, j, w, gradient_rgb(z, clrs[c], clrs[c + 1])) 401 z = z + zstep 402 end 403 end 404 else -- not a color target but might be greyscale 405 local clr = _clr.set(-1) 406 for i=x, w + x do 407 for j=y, h + y do 408 -- Set the pixel at position i, j to the specified color 409 img:set(i, j, clr) 410 end 411 clr = _clr.inc(clr, 1) 412 end 413 end 414--rb.sleep(1000) 415end -- draw_gradient 416 417function twist(img) 418--[[ local fg 419 if rb.lcd_get_foreground then 420 fg = rb.lcd_get_foreground() 421 end]] 422 423 local ims = {} 424 ims.strip = _img.tile(img, img:width(), _lcd.H + img:height()) 425 ims.y_init = {img:height(), 1} 426 ims.y_finl = {1, img:height()} 427 ims.y_inc = {-2, 4} 428 ims.y_pos = nil 429 430 -- together define the width of the overall object 431 local x_off=(_lcd.W/2) 432 local m = _lcd.W 433 local z = -m 434 local zi = 1 435 436 -- angles of rotation for each leaf 437 local ANGLES = {0, 45, 90, 135, 180, 225, 270, 315} 438 local elems = #ANGLES 439 local _XCOORD = {} 440 441 -- color alternates each leaf 442 local colors = { WHITE, _clr.set(0, 0, 0, 0) } 443 local c = 0 444 445 -- calculated position of each point in the sine wave(s) 446 local xs, xe 447 448 --[[--Profiling code 449 local timer = _timer.start()]] 450 451 for rot = 0, 6000, 4 do 452 _lcd:clear(BLACK) 453 454 for y=1, _lcd.H do 455 456 local function get_sines() 457 local sc = m + z 458 if sc == 0 then 459 sc = 1 -- prevent divide by 0 460 elseif sc + z > _lcd.W then 461 zi = -1 462 colors[2] = _clr.inc(colors[2], 1, 0, 50, 0) 463 elseif sc + z < -(_lcd.W) then 464 zi = 1 465 colors[1] = _clr.inc(colors[1], -1, 0, 10, 0) 466 end 467 if colors[2] == colors[1] then 468 colors[2] = _clr.inc(colors[2], 1) 469 end 470 for j = 1, elems do 471 _XCOORD[j] = _math.d_sin(y + ANGLES[j] + rot) / sc + x_off 472 end 473 _XCOORD[0] = _XCOORD[elems] -- loop table for efficient wrap 474 end 475 476 get_sines() 477 for k = 1, elems do 478 xs = _XCOORD[k] 479 xe = _XCOORD[(k+1) % elems] 480 if xs < 1 or xe > _lcd.W then 481 while xs < 1 or xe > _lcd.W do 482 m = m + 1 -- shift m in order to scale object min/max 483 get_sines() 484 xs = _XCOORD[k] 485 xe = _XCOORD[(k+1) % elems] 486 end 487 end 488 c = (c % 2) + 1 489 if xs < xe then 490 -- defines the direction of leaves & fills them 491 492 _lcd:set(xs, y, colors[c]) 493 _lcd:set(xe, y, colors[c]) 494 _lcd:line(xs + 1, y, xe - 1, y, colors[3 - c], true) 495 end 496 end 497 498 end 499 500 do -- stripes and shifts image strips; blits it into the colors(1) leaves 501 local y 502 local y_col = 1 503 local w = ims.strip:width() - 1 504 local h = ims.strip:height() - 1 505 if ims.y_pos ~= nil then 506 for i = 1, #ims.y_pos do 507 ims.y_pos[i] = ims.y_pos[i] + ims.y_inc[i] 508 509 if (ims.y_inc[i] > 0 and ims.y_pos[i] > ims.y_finl[i]) 510 or (ims.y_inc[i] < 0 and ims.y_pos[i] < ims.y_finl[i]) then 511 ims.y_pos[i] = ims.y_init[i] 512 end 513 end 514 else 515 ims.y_pos = {ims.y_init[1], ims.y_init[2]} 516 end 517 518 for ix = 1, _lcd.W, w do 519 y_col = y_col + 1 520 y = ims.y_pos[(y_col % 2) + 1] 521 if LCD_DEPTH > 1 then 522 _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BDEQC, colors[1]) 523 else 524 _lcd:copy(ims.strip, ix, 1, 1, y, w, h, false, _blit.BSAND) 525 end 526 end 527 end 528 529 _lcd:update() 530 z = z + zi 531 532 if rb.get_plugin_action(0) == CANCEL_BUTTON then 533 break 534 end 535 collectgarbage("step") 536 end 537 --[[--Profiling code 538 _print.f("%d", _timer.stop(timer)) 539 rb.sleep(rb.HZ * 10)]] 540end -- twist 541 542function draw_target(img) 543 544 local clr = _clr.set(0, 0, 0, 0) 545 546 -- make a copy of original screen for restoration 547 local screen_img = _lcd:duplicate() 548 549 rad_m = math.min(_lcd.W, _lcd.H) 550 551 for s = -_lcd.W /4, 16 do 552 img:copy(screen_img) 553 s = math.max(1, math.abs(s)) 554 for r = 1, rad_m /2 - 10, s do 555 clr = _clr.inc(clr, 1, r * 5, r * 10, r * 20) 556 _draw.circle(img, _lcd.CX, _lcd.CY, r, clr) 557 end 558 559 _lcd:update() 560 if rb.get_plugin_action( 20) == CANCEL_BUTTON then 561 z = 16; 562 break; 563 end 564 end 565 566end -- draw_target 567 568function draw_sweep(img, cx, cy, radius, color) 569 local timer = _timer() --creates a new timer saves index 570 local wait 571 local x 572 local y 573 --make a copy of original screen for restoration 574 local screen_img = _lcd:duplicate() 575 _draw.circle(img, cx, cy, radius, color) 576 for d = 630, 270, - 5 do 577 if d % 45 == 0 then 578 img:copy(screen_img) 579 _draw.circle(img, cx, cy, radius, color) 580 l = 0 581 end 582 x = cx + radius * _math.d_cos(d) / 10000 583 y = cy + radius * _math.d_sin(d) / 10000 584 585 586 _draw.line(img, cx, cy, x, y, color) 587 l = l + 1 588 if l > 1 then 589 x1 = cx + (radius - 1) * _math.d_cos(d + 1) / 10000 590 y1 = cy + (radius - 1) * _math.d_sin(d + 1) / 10000 591 _draw_floodfill(img, x1, y1, BLACK, color) 592 end 593 _lcd:update() 594 wait = timer:check(true) --checks timer and updates last time 595 if wait >= 50 then 596 wait = 0 597 elseif wait < 50 then 598 wait = 50 - wait 599 end 600 if rb.get_plugin_action( wait) == CANCEL_BUTTON then 601 break 602 end 603 end 604 timer:stop() --destroys timer, also returns time since last time 605 screen_img = nil 606end -- draw_sweep 607 608function rotate_image(img) 609 local blitop = _blit.BOR 610 local i = 1 611 local d = 0 612 local ximg 613 local x, y, w, h, xr, yr 614 615 ximg = _img.rotate(img, 45) -- image will be largest at this point 616 w = ximg:width() 617 h = ximg:height() 618 xr = (_lcd.W - w) / 2 619 yr = (_lcd.H - h) / 2 620 --make a copy of original screen for restoration 621 local screen_img -- = _lcd:duplicate() 622 screen_img =_img.new(w, h) 623 screen_img :copy(_LCD, 1, 1, xr, yr, w, h) 624 --_print.f("CW") 625 626 --[[--Profiling code 627 local timer = _timer.start()]] 628 629 while d >= 0 do 630 ximg = _img.rotate(img, d) 631 w = ximg:width() 632 h = ximg:height() 633 x = (_lcd.W - w) / 2 634 y = (_lcd.H - h) / 2 635 636 -- copy our rotated image onto the background 637 _lcd:copy(ximg, x, y, 1, 1, w, h, false, blitop) 638 _lcd:update() 639 --restore the portion of the background we destroyed 640 _lcd:copy(screen_img, xr, yr, 1, 1) 641 642 if d > 0 and d % 360 == 0 then 643 _lcd:copy(ximg, x, y, 1, 1, w, h) 644 _lcd:update() 645 if i == 1 then i = 0 end 646 if d == 1440 or i < 0 then 647 if i < 0 then 648 i = i - 5 649 else 650 i = - 5 651 end 652 blitop = _blit.BXOR 653 --_print.f("CCW") 654 --rb.sleep(rb.HZ) 655 else 656 i = i + 5 657 --_print.f("CW") 658 --rb.sleep(rb.HZ) 659 end 660 661 end 662 d = d + i 663 664 if rb.get_plugin_action(0) == CANCEL_BUTTON then 665 break; 666 end 667 end 668 669 _lcd:copy(ximg, x, y, 1, 1, w, h) 670 --[[-- Profiling code 671 _print.f("%d", _timer.stop(timer)) 672 rb.sleep(rb.HZ * 10)]] 673end -- rotate_image 674 675-- shows blitting with a mask 676function blit_mask(dst) 677 local timer = _timer() 678 local r = math.min(_lcd.CX, _lcd.CY) / 5 679 680 local bmask = _img.new(_lcd.W, _lcd.H) 681 bmask:clear(0) 682 683 _draw.circle_filled(bmask, _lcd.CX, _lcd.CY, r, WHITE) 684 local color = _clr.set(0, 0, 0 ,0) 685 for z = 0, 100 do 686 z = z + timer:check(true) 687 color = _clr.inc(color, 1, z * 5, z * 10, z * 20) 688 dst:copy(bmask, 1, 1, 1, 1, nil, nil, false, _blit.BSAND, color) 689 _lcd:update() 690 691 if rb.get_plugin_action(0) == CANCEL_BUTTON then 692 break 693 end 694 end 695end -- blit_mask 696 697-- draws an X on the screen 698function draw_x() 699 _draw.line(_LCD, 1, 1, _lcd.W, _lcd.H, WHITE) 700 _draw.line(_LCD, _lcd.W, 1, 1, _lcd.H, WHITE) 701 702 _draw.hline(_LCD, 10, _lcd.CY , _lcd.W - 21, WHITE) 703 704 _draw.vline(_LCD, _lcd.CX, 20 , _lcd.H - 41, WHITE) 705 706 _draw.rect(_LCD, _lcd.CX - 17, _lcd.CY - 17, 34, 34, WHITE) 707 _lcd:update() 708 rb.sleep(100) 709end -- draw_x 710 711--fills an image with random colors 712function random_img(img) 713 local min = _clr.set(0, 0, 0, 0) 714 local max = _clr.set(-1, 255, 255, 255) 715 math.randomseed(rb.current_tick()) 716 for x = 1, img:width() do 717 for y = 1, img:height() do 718 img:set(x, y, math.random(min, max)) 719 end 720 end 721end -- random_img 722 723function rainbow_img(img) 724--draw a gradient using available colors 725 if IS_COLOR_TARGET == true then 726 --R O Y G B I V 727 clrs = { 728 {r = 255, g = 255, b = 255}, -- white 729 {r = 000, g = 000, b = 000}, -- black 730 {r = 200, g = 000, b = 000}, -- red 731 {r = 255, g = 000, b = 000}, -- red 732 {r = 255, g = 100, b = 033}, -- orange 733 {r = 255, g = 127, b = 000}, -- orange 734 {r = 255, g = 200, b = 033}, -- yellow 735 {r = 255, g = 255, b = 000}, -- yellow 736 {r = 050, g = 255, b = 000}, -- green 737 {r = 000, g = 125, b = 125}, -- green 738 {r = 000, g = 000, b = 255}, -- blue 739 {r = 033, g = 025, b = 200}, -- indigo 740 {r = 075, g = 000, b = 150}, -- indigo 741 {r = 127, g = 000, b = 150}, -- violet 742 {r = 150, g = 000, b = 255}, -- violet 743 {r = 255, g = 255, b = 255}, -- white 744 {r = 000, g = 000, b = 000}, -- black 745 } 746 else 747 end 748 draw_gradient(img, 1, 1, nil, nil, "V", clrs) 749end -- rainbow_img 750 751-- draws a rounded rectangle with text 752function rock_lua() 753 local res, w, h = _lcd:text_extent("W", rb.FONT_UI) 754 w = _lcd.W - 10 755 h = h + 4 756 _draw.rounded_rect_filled(_LCD, 5, 5, w, h, 15, WHITE) 757 _draw_text(_LCD, 5, 5, w, h, nil, BLACK, "ROCKlua!") 758 _lcd:update() 759 rb.sleep(100) 760end -- rock_lua 761 762-- draws a rounded rectangle with long text 763function long_text() 764 local txt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 765 local res, w, h = _lcd:text_extent(txt, rb.FONT_UI) 766 local resp, wp, hp = _lcd:text_extent(" ", rb.FONT_UI) 767 local wait = 0 768 w = w + wp * 3 769 h = h + 4 770 local img = _img.new(w + 1, h + 1) 771 img:clear(BLACK) 772 _draw.rounded_rect_filled(img, 1, 1, w, h, 15, WHITE) 773 _draw_text(img, 1, 1, nil, nil, nil, BLACK, txt) 774 775 for p = -w + 1, w - 1 do 776 wait = 0 777 p = math.abs(p) 778 _lcd:copy(img, 1, _lcd.H - h, w - p, 1) 779 _lcd:update() 780 if p == 0 or w - p == 1 then wait = 100; rb.sleep(50) end 781 if rb.get_plugin_action(wait) == CANCEL_BUTTON then 782 break 783 end 784 end 785 786end -- long_text 787 788-- creates or loads an image to use as logo 789function get_logo() 790 local logo_img = _img.load("/pix.bmp") --loads the previously saved image (if we saved it before) 791 792 --create a logo if an image wasn't saved previously 793 if(not logo_img) then 794 logo_img = create_logo() 795 end 796 797 --fallback 798 if(not logo_img) then 799 -- Load a BMP file in the variable backdrop 800 local base = "/.rockbox/icons/" 801 local backdrop = _img.load("/image.bmp") --user supplied image 802 or _img.load(base .. "tango_small_viewers.bmp") 803 or _img.load(base .. "tango_small_viewers_mono.bmp") 804 or _img.load(base .. "tango_small_mono.bmp") 805 or _img.load(base .. "tango_icons.16x16.bmp") 806 or _img.load(base .. "tango_icons_viewers.16x16.bmp") 807 or _img.load(base .. "viewers.bmp") 808 or _img.load(base .. "viewers.6x8x1.bmp") 809 or _img.load(base .. "viewers.6x8x2.bmp") 810 or _img.load(base .. "viewers.6x8x10.bmp") 811 or _img.load(base .. "viewers.6x8x16.bmp") 812 logo_img = backdrop 813 end 814 return logo_img 815end -- get_logo 816 817-- uses print_table to display a menu 818function main_menu() 819 820 local mt = { 821 [1] = "Rocklua RLI Example", 822 [2] = "The X", 823 [3] = "Blit Mask", 824 [4] = "Target", 825 [5] = "Sweep", 826 [6] = "Bouncing Ball (olive)", 827 [7] = "The Twist", 828 [8] = "Image Rotation", 829 [9] = "Long Text", 830 [10] = "Rainbow Image", 831 [11] = "Random Image", 832 [12] = "Clear Screen", 833 [13] = "Save Screen", 834 [14] = "Exit" 835 } 836 local ft = { 837 [0] = exit_now, --if user cancels do this function 838 [1] = function(TITLE) return true end, -- shouldn't happen title occupies this slot 839 [2] = function(THE_X) draw_x() end, 840 [3] = function(BLITM) blit_mask(_lcd()) end, 841 [4] = function(TARGT) draw_target(_lcd()) end, 842 [5] = function(SWEEP) 843 local r = math.min(_lcd.CX, _lcd.CY) - 20 844 draw_sweep(_lcd(), _lcd.CX, _lcd.CY, r, _clr.set(-1, 0, 255, 0)) 845 end, 846 [6] = function(BOUNC) bounce_image(create_ball()) end, 847 [7] = function(TWIST) twist(get_logo()) end, 848 [8] = function(ROTAT) rotate_image(get_logo()) end, 849 [9] = long_text, 850 [10] = function(RAINB) 851 rainbow_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ) 852 end, 853 [11] = function(RANDM) 854 random_img(_lcd()); _lcd:update(); rb.sleep(rb.HZ) 855 end, 856 [12] = function(CLEAR) _lcd:clear(BLACK); rock_lua() end, 857 [13] = function(SAVEI) _LCD:invert(); _img_save(_LCD, "/rocklua.bmp") end, 858 [14] = function(EXIT_) return true end 859 } 860 861 if LCD_DEPTH < 2 then 862 table.remove(mt, 10) 863 table.remove(ft, 10) 864 end 865 866 print_menu(mt, ft) 867 868end 869-------------------------------------------------------------------------------- 870function exit_now() 871 _lcd:update() 872 _lcd:splashf(rb.HZ * 5, "ran for %d seconds", _timer.stop("main") / rb.HZ) 873 os.exit() 874end -- exit_now 875-------------------------------------------------------------------------------- 876 877--MAIN PROGRAM------------------------------------------------------------------ 878_timer("main") -- keep track of how long the program ran 879 880-- Clear the screen 881_lcd:clear(BLACK) 882 883if LCD_DEPTH > 1 then 884--draw a gradient using available colors 885if IS_COLOR_TARGET == true then 886 clrs = { 887 {r = 255, g = 000, b = 000}, -- red 888 {r = 000, g = 255, b = 000}, -- green 889 {r = 000, g = 000, b = 255}, -- blue 890 } 891else 892end 893 local w = bit.rshift(_lcd.W, 2) 894 local h = bit.rshift(_lcd.H, 2) 895 draw_gradient(_lcd(), (_lcd.W - w)/2 - 1, (_lcd.H - h)/3 - 1, w, h, "H", clrs) 896 _lcd:update() 897 rb.sleep(rb.HZ) 898end 899 900do 901local img = _img.load("/rocklua.bmp") 902 if not img then 903 rock_lua() 904 else 905 _lcd:image(img) 906 end 907end 908_lcd:update() 909rb.sleep(rb.HZ / 2) 910 911if rb.cpu_boost then rb.cpu_boost(true) end 912 913main_menu() 914 915if rb.cpu_boost then rb.cpu_boost(false) end 916 917exit_now() 918 919-- For a reference list of all functions available, see apps/plugins/lua/rocklib.c (and apps/plugin.h)