mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 16:13:05 -04:00
I rewrote some of the problematic scripts to use an event loop which fixed most of the issues but it turns out the underlying issue is that when the device is under load the timeout that detects a repeat press makes the key a repeat press and we miss the initial press completely due to being under load and under the gun Adds entries for PLA_EXIT and PLA_CANCEL with a Repeat press Change-Id: I8247b0ebd37fc58608f6be126c49e56f8375e9cf
458 lines
16 KiB
Lua
458 lines
16 KiB
Lua
--[[ Rockbox vector logo
|
|
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
*
|
|
* Copyright (C) 2026 William Wilgus
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
]]
|
|
local _clr = require("color") -- clrset, clrinc provides device independent colors
|
|
local _lcd = require("lcd") -- lcd helper functions
|
|
local actions = require("menubuttons")
|
|
|
|
local WHITE = _clr.set(-1, 255, 255, 255)
|
|
local BLACK = _clr.set(0, 0, 0, 0)
|
|
local YELLOW = _clr.set(BLACK, 255, 192, 0)
|
|
local GREY = _clr.set(WHITE, 180, 195, 211)
|
|
if rb.LCD_DEPTH == 2 then --greyscale display
|
|
YELLOW = _clr.set(2, 255, 192, 0)
|
|
GREY = _clr.set(1, 180, 195, 211)
|
|
end
|
|
|
|
if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
|
|
|
|
--poly draw from draw_poly.lua with negative (inverse) scaling added and optimizations
|
|
local _poly = {} do
|
|
-- Internal Constants
|
|
local rocklib_image = getmetatable(rb.lcd_framebuffer())
|
|
local BSAND = 8 -- blits color to dst if src <> 0
|
|
local _NIL = nil -- nil placeholder
|
|
|
|
local _abs = math.abs
|
|
local _clear = rocklib_image.clear
|
|
local _copy = rocklib_image.copy
|
|
local _line = rocklib_image.line
|
|
local _newimg = rb.new_image
|
|
local flood_fill
|
|
|
|
local function scale_val_none(val, scale)
|
|
return val
|
|
end
|
|
local function scale_val_up(val, scale)
|
|
return val * scale
|
|
end
|
|
local function scale_val_dn(val, scale)
|
|
return val / scale
|
|
end
|
|
|
|
local function get_scale_fn(scale)
|
|
local scale_fn, fn
|
|
if (scale < 0) then
|
|
scale = -scale
|
|
scale_fn = scale_val_dn
|
|
elseif scale > 0 then
|
|
scale_fn = scale_val_up
|
|
else
|
|
scale_fn = scale_val_none
|
|
end
|
|
return scale + 1, scale_fn
|
|
end
|
|
|
|
local function polyline_size_only(img, x, y, t_pts, scale_x, scale_y)
|
|
scale_x = scale_x or 0
|
|
scale_y = scale_y or 0
|
|
local scale_val_x, scale_val_y
|
|
|
|
scale_x, scale_val_x = get_scale_fn(scale_x)
|
|
scale_y, scale_val_y = get_scale_fn(scale_y)
|
|
|
|
local pt_first_last, pt1, pt2
|
|
local max_x, max_y = 0, 0
|
|
local len = #t_pts
|
|
if len < 4 then error("not enough points", 3) end
|
|
|
|
pt_first_last = {scale_val_x(t_pts[1], scale_x), scale_val_y(t_pts[2], scale_y)}
|
|
|
|
pt2 = {scale_val_x(t_pts[1], scale_x), scale_val_y(t_pts[2], scale_y)}
|
|
for i = 3, len + 2, 2 do
|
|
pt1 = pt2
|
|
if t_pts[i + 1] == nil then
|
|
pt2 = pt_first_last
|
|
else
|
|
pt2 = {scale_val_x(t_pts[i], scale_x), scale_val_y(t_pts[i + 1], scale_y)}
|
|
end-- first and last point
|
|
if pt1[1] > max_x then max_x = pt1[1] end
|
|
if pt1[2] > max_y then max_y = pt1[2] end
|
|
end
|
|
if pt2[1] > max_x then max_x = pt2[1] end
|
|
if pt2[2] > max_y then max_y = pt2[2] end
|
|
return max_x + x, max_y + y
|
|
end
|
|
|
|
-- draws a non-filled figure based on points in t-points
|
|
local function polyline(img, x, y, t_pts, color, bClosed, bClip, scale_x, scale_y)
|
|
local draw_fn = _line
|
|
scale_x = scale_x or 1
|
|
scale_y = scale_y or 1
|
|
local scale_val_x, scale_val_y
|
|
|
|
scale_x, scale_val_x = get_scale_fn(scale_x)
|
|
scale_y, scale_val_y = get_scale_fn(scale_y)
|
|
|
|
local pt_first_last, pt1, pt2
|
|
|
|
local len = #t_pts
|
|
if len < 4 then error("not enough points", 3) end
|
|
|
|
if bClosed then
|
|
pt_first_last = {scale_val_x(t_pts[1], scale_x), scale_val_y(t_pts[2], scale_y)}
|
|
else
|
|
pt_first_last = {scale_val_x(t_pts[len - 1], scale_x), scale_val_y(t_pts[len], scale_y)}
|
|
end
|
|
|
|
pt2 = {scale_val_x(t_pts[1], scale_x), scale_val_y(t_pts[2], scale_y)}
|
|
for i = 3, len + 2, 2 do
|
|
pt1 = pt2
|
|
if t_pts[i + 1] == nil then
|
|
pt2 = pt_first_last
|
|
else
|
|
pt2 = {scale_val_x(t_pts[i], scale_x), scale_val_y(t_pts[i + 1], scale_y)}
|
|
end-- first and last point
|
|
draw_fn(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip)
|
|
end
|
|
end
|
|
|
|
-- draws a closed figure based on points in t_pts
|
|
_poly.polygon = function(img, x, y, t_pts, color, fillcolor, bClip, scale_x, scale_y)
|
|
scale_x = scale_x or 1
|
|
scale_y = scale_y or 1
|
|
if #t_pts < 2 then error("not enough points", 3) end
|
|
|
|
if fillcolor then
|
|
flood_fill = flood_fill or require("draw_floodfill")
|
|
local x_min, x_max = _lcd.W, 0
|
|
local y_min, y_max = _lcd.H, 0
|
|
local w, h = 0, 0
|
|
local pt1, pt2
|
|
-- find boundries of polygon
|
|
for i = 1, #t_pts, 2 do
|
|
if t_pts[i] < x_min then x_min = t_pts[i] end
|
|
if t_pts[i] > x_max then x_max = t_pts[i] end
|
|
|
|
if t_pts[i+1] < y_min then y_min = t_pts[i+1] end
|
|
if t_pts[i+1] > y_max then y_max = t_pts[i+1] end
|
|
end
|
|
|
|
local scale
|
|
if (scale_x < 0) then
|
|
scale = -scale_x + 1
|
|
x_max = x_max / scale
|
|
x_min = x_min / scale
|
|
else
|
|
scale = scale_x + 1
|
|
x_max = x_max * scale
|
|
x_min = x_min * scale
|
|
end
|
|
|
|
if (scale_y < 0) then
|
|
scale = -scale_y + 1
|
|
y_max = y_max / -scale_y
|
|
y_min = y_min / -scale_y
|
|
else
|
|
scale = scale_y + 1
|
|
y_max = y_max * scale
|
|
y_min = y_min * scale
|
|
end
|
|
|
|
w = _abs(x_max) + _abs(x_min)
|
|
if w > _lcd.W then w = _lcd.W end
|
|
|
|
h = _abs(y_max) + _abs(y_min)
|
|
if h > _lcd.H then h = _lcd.H end
|
|
|
|
if x_min < _lcd.W and y_min < _lcd.H then
|
|
-- hack so we don't waste time drawing off screen
|
|
x_min = 0
|
|
y_min = 0
|
|
x_min = -(x_min - 2) -- leave a border to use flood_fill
|
|
y_min = -(y_min - 2)
|
|
|
|
local fill_img = _newimg(w + 3, h + 3)
|
|
_clear(fill_img, 0x1)
|
|
|
|
polyline(fill_img, x_min, y_min, t_pts, 0x0, true, bClip, scale_x, scale_y)
|
|
-- flood the outside of the figure with 0 the inside will be fillcolor
|
|
flood_fill(fill_img, fill_img:width(), fill_img:height() , 0x1, 0x0)
|
|
_copy(img, fill_img, x - 1, y - 1,
|
|
_NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor)
|
|
end
|
|
|
|
end
|
|
|
|
polyline(img, x, y, t_pts, color, true, bClip, scale_x, scale_y)
|
|
end
|
|
|
|
-- expose internal functions to the outside through _poly table
|
|
_poly.polyline = polyline
|
|
_poly.polyline_size_only = polyline_size_only
|
|
end
|
|
|
|
-- $Rb - Vectors, each is an (x,y) pair lines get drawn between them
|
|
local cross_left_pts = {8, 0, 8, 26, 8, 5, 4, 5, 36, 5}
|
|
|
|
local R_outline_pts = {12, 10, 43, 10, 47, 11, 50, 13, 54, 16, 56, 20,
|
|
58, 24, 58, 25, 59, 28, 59, 29, 60, 33, 60, 38,
|
|
60, 60, 57, 65, 54, 70, 50, 75, 50, 77, 70, 127,
|
|
50, 127, 34, 84, 27, 84, 26, 127, 12, 127, 12, 10}
|
|
|
|
local R_center_pts = {26, 31, 26, 63, 38, 63, 39, 61, 41, 60, 43, 58,
|
|
44, 55, 44, 39, 43, 35, 40, 32, 39, 31, 26, 31}
|
|
|
|
local R_shadow_pts = {26, 126, 35, 126, 32, 126, 32, 128, 32,
|
|
59, 37, 57, 40, 56, 41, 40, 38, 36, 27, 35}
|
|
|
|
local b_outline_pts = {59, 38, 79, 38, 79, 61, 83, 59, 87, 58, 90, 57, 98, 57,
|
|
101, 57, 105, 58, 110, 60, 114, 63, 117, 66, 121, 70, 124,
|
|
75, 126, 80, 127, 85, 128, 87, 128, 98, 127, 101, 126, 106,
|
|
124, 110, 121, 114, 115, 120, 106, 125, 100, 126, 96, 126,
|
|
88, 126, 82, 125, 78, 122, 76, 125, 59, 125, 59, 38}
|
|
|
|
local b_center_pts = {92, 77, 100, 77, 101, 78, 103, 78, 105, 80, 107, 81,
|
|
108, 83, 109, 84, 110, 86, 111, 89, 112, 90, 112, 95,
|
|
111, 97, 110, 100, 108, 103, 105, 105, 102, 106, 98,
|
|
107, 95, 107, 90, 106, 87, 104, 83, 100, 82, 97, 81,
|
|
94, 81, 88, 83, 85, 84, 83, 86, 81, 89, 79, 93, 77}
|
|
|
|
local clef_pts = {6, 46, 7, 44, 10, 44, 11, 45, 13, 46, 14, 47, 16, 49, 17,
|
|
50, 18, 52, 18, 54, 17, 59, 17, 60, 16, 62, 12, 75, 12, 85,
|
|
13, 87, 14, 88, 16, 90, 18, 91, 21, 91, 24, 91, 28, 89, 29,
|
|
86, 28, 82, 24, 79, 23, 80, 23, 84, 29, 106, 29, 114, 28,
|
|
116, 25, 117, 24, 116, 23, 114, 23, 112, 25, 111, 26, 113,
|
|
27, 113, 27, 107, 26, 102, 24, 94, 20, 79, 16, 83, 15, 83,
|
|
20, 77, 6, 50, 6, 47, 9, 48, 11, 48, 13, 50, 15, 52, 15, 55,
|
|
14, 57, 9, 76, 9, 86, 10, 90, 13, 94, 19, 95, 23, 94, 29, 90,
|
|
31, 86, 31, 82, 29, 79, 26, 77, 24, 77, 22, 77, 8, 49}
|
|
|
|
local clef_void_1_pts = {13, 59, 8, 48, 13, 50, 14, 54, 14, 58}
|
|
|
|
local clef_void_2_pts = {15, 69, 13, 76, 12, 79, 12, 86, 13, 88, 17, 91, 21,
|
|
91, 23, 91, 20, 81, 16, 83, 15, 82, 18, 78, 16, 71}
|
|
|
|
local clef_void_3_pts = {23, 80, 26, 90, 28, 86, 28, 83, 27, 81, 23, 79}
|
|
|
|
local max_x = 1
|
|
local max_y = 1
|
|
--memorize the rotated points but let them still get collected if ram is needed
|
|
local rot_memoized = setmetatable({}, { __mode = 'k' }) --Keys are weak
|
|
|
|
local function rb_logo_sz(sx, sy)
|
|
local x, y
|
|
local t_pts = {cross_left_pts, R_outline_pts, R_shadow_pts, b_outline_pts, clef_pts}
|
|
for k, points_t in pairs(t_pts) do
|
|
x, y = _poly.polyline_size_only(_LCD, 0, 0, points_t, sx, sy)
|
|
if x > max_x then max_x = x end
|
|
if y > max_y then max_y = y end
|
|
end
|
|
end
|
|
|
|
local function Rot(t_pts, rot)
|
|
local count = #t_pts
|
|
local nw = max_x
|
|
local nh = max_y
|
|
|
|
--rot = rot % 7
|
|
if rot == 0 then
|
|
return t_pts
|
|
end
|
|
|
|
-- convert to string keys
|
|
rot = tostring(rot)
|
|
local pts = tostring(t_pts)
|
|
|
|
if not rot_memoized[rot] then
|
|
rot_memoized[rot] = {}
|
|
end
|
|
|
|
if not rot_memoized[rot][pts] then
|
|
rot_memoized[rot][pts] = {}
|
|
else
|
|
return rot_memoized[rot][pts]
|
|
end
|
|
|
|
if rot == "1" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = t_pts[i]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = nw - t_pts[i+1]
|
|
end
|
|
elseif rot == "2" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = nh - t_pts[i+1]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = nw-t_pts[i]
|
|
end
|
|
elseif rot == "3" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = nh - t_pts[i]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = t_pts[i+1]
|
|
end
|
|
elseif rot == "4" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = nh - t_pts[i+1]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = t_pts[i]
|
|
end
|
|
elseif rot == "5" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = nh - t_pts[i]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = nw-t_pts[i+1]
|
|
end
|
|
elseif rot == "6" then
|
|
for i = 1, count, 2 do
|
|
rot_memoized[rot][pts][count + 1 - i] = t_pts[i+1]
|
|
rot_memoized[rot][pts][count + 1 - (i + 1)] = nw-t_pts[i]
|
|
end
|
|
end
|
|
|
|
return rot_memoized[rot][pts]
|
|
end
|
|
|
|
local function rb_logo_rot(x, y, sx, sy, rot)
|
|
local rot_m = rot % 7
|
|
local rot_next = rot + 1
|
|
local polygon = _poly.polygon
|
|
_lcd:clear(BLACK)
|
|
_poly.polyline(_LCD, x, y, Rot(cross_left_pts, rot_m), WHITE, false, true, sx, sy)
|
|
_poly.polyline(_LCD, x, y, Rot(R_shadow_pts, rot_m), WHITE, false, true, sx, sy)
|
|
repeat
|
|
polygon(_LCD, x, y, Rot(R_outline_pts, rot_m), BLACK, YELLOW, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(R_center_pts, rot_m), BLACK, BLACK, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(b_outline_pts, rot_m), BLACK, GREY, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(b_center_pts, rot_m), BLACK, BLACK, true, sx, sy)
|
|
|
|
polygon(_LCD, x, y, Rot(clef_pts, rot_m), WHITE, WHITE, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(clef_void_1_pts, rot_m), WHITE, BLACK, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(clef_void_2_pts, rot_m), WHITE, YELLOW, true, sx, sy)
|
|
polygon(_LCD, x, y, Rot(clef_void_3_pts, rot_m), WHITE, YELLOW, true, sx, sy)
|
|
polygon = function() end -- don't draw but memoize the next point
|
|
rot = rot + 1
|
|
rot_m = rot % 7
|
|
until rot > rot_next;
|
|
end
|
|
|
|
-- we want the size of everything @ 1:1 scale so we can use that to flip/rotate the figure
|
|
rb_logo_sz(0, 0)
|
|
|
|
local action
|
|
local redraw = true;
|
|
local rot = 0
|
|
local sx = -2
|
|
local sy = -2
|
|
local max_sx = (rb.LCD_WIDTH / max_x) * 3
|
|
local max_sy = (rb.LCD_HEIGHT / max_y) * 3
|
|
|
|
|
|
do
|
|
local act = rb.actions
|
|
local quit = false
|
|
|
|
function action_event(action)
|
|
local event
|
|
|
|
if action == actions.CANCEL or action == actions.EXIT then
|
|
quit = true
|
|
end
|
|
|
|
if action == 0 then --timer timeout
|
|
rot = rot + 1
|
|
redraw = true
|
|
local prot = (rot) % 7
|
|
if prot > 0 then -- erase the previous rot
|
|
prot = prot - 1
|
|
if prot == 0 then prot = 6 end
|
|
rot_memoized[tostring(prot)] = nil
|
|
end
|
|
end
|
|
|
|
if redraw then
|
|
--do nothing till redrawn
|
|
elseif action == actions.LEFT then
|
|
sx = sx - 1
|
|
elseif action == actions.LEFTR then
|
|
sx = sx - 1
|
|
sy = sy - 1
|
|
elseif action == actions.RIGHT then
|
|
sx = sx + 1
|
|
elseif action == actions.RIGHTR then
|
|
sx = sx + 1
|
|
sy = sy + 1
|
|
elseif action == actions.UP then
|
|
sy = sy - 1
|
|
elseif action == actions.UPR then
|
|
sy = sy - 1
|
|
sx = sy
|
|
elseif action == actions.DOWN then
|
|
sy = sy + 1
|
|
elseif action == actions.DOWNR then
|
|
sy = sy + 1
|
|
sx = sy
|
|
elseif action == actions.SELR then
|
|
rot = rot + 1
|
|
count = 0;
|
|
redraw = true
|
|
else
|
|
return
|
|
end
|
|
if sx > max_sx then sx = max_sx end
|
|
if sy > max_sy then sy = max_sy end
|
|
redraw = true
|
|
end
|
|
|
|
function action_set_quit(bQuit)
|
|
quit = bQuit
|
|
end
|
|
|
|
function action_quit()
|
|
return quit
|
|
end
|
|
end
|
|
|
|
local eva = rockev.register("action", action_event)
|
|
local evt = rockev.register("timer", action_event, rb.HZ * 5)
|
|
|
|
--[[ Main loop ]]
|
|
while not action_quit() do
|
|
if redraw then
|
|
rb_logo_rot(0,0, sx, sy, rot)
|
|
_lcd:update()
|
|
redraw = false
|
|
end
|
|
rb.yield()
|
|
end --wend
|
|
|
|
local used, allocd, free = rb.mem_stats()
|
|
|
|
collectgarbage("collect")
|
|
local lu = collectgarbage("count")
|
|
local fmt = function(t, v) return string.format("%s: %d Kb\n", t, v /1024) end
|
|
|
|
-- this is how lua recommends to concat strings rather than ..
|
|
local s_t = {}
|
|
s_t[1] = "rockbox:\n"
|
|
s_t[2] = fmt("Used ", used)
|
|
s_t[3] = fmt("Allocd ", allocd)
|
|
s_t[4] = fmt("Free ", free)
|
|
s_t[5] = "\nlua:\n"
|
|
s_t[6] = fmt("Used", lu * 1024)
|
|
s_t[7] = "\n\nNote that the rockbox used count is a high watermark\n"
|
|
rb.splash_scroller(10 * rb.HZ, table.concat(s_t))
|