mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 10:37:38 -04:00
lua add demo scripts, atexit handler, gui_scrollbar_draw
Change-Id: Ie8794e8a487f73952dae43e036787b6972fdbbee
This commit is contained in:
parent
60c5a29408
commit
90118f14cf
22 changed files with 2374 additions and 22 deletions
385
apps/plugins/lua/include_lua/printtable.lua
Normal file
385
apps/plugins/lua/include_lua/printtable.lua
Normal file
|
@ -0,0 +1,385 @@
|
|||
--[[
|
||||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2017 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
]]
|
||||
if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
|
||||
|
||||
require("actions") -- Contains rb.actions & rb.contexts
|
||||
|
||||
local _clr = require("color")
|
||||
local _print = require("print")
|
||||
local _timer = require("timer")
|
||||
|
||||
-- Button definitions --
|
||||
local EXIT_BUTTON = rb.PLA_EXIT
|
||||
local CANCEL_BUTTON = rb.actions.PLA_CANCEL
|
||||
local DOWN_BUTTON = rb.actions.PLA_DOWN
|
||||
local DOWNR_BUTTON = rb.actions.PLA_DOWN_REPEAT
|
||||
local EXIT_BUTTON = rb.actions.PLA_EXIT
|
||||
local LEFT_BUTTON = rb.actions.PLA_LEFT
|
||||
local LEFTR_BUTTON = rb.actions.PLA_LEFT_REPEAT
|
||||
local RIGHT_BUTTON = rb.actions.PLA_RIGHT
|
||||
local RIGHTR_BUTTON = rb.actions.PLA_RIGHT_REPEAT
|
||||
local SEL_BUTTON = rb.actions.PLA_SELECT
|
||||
local SELREL_BUTTON = rb.actions.PLA_SELECT_REL
|
||||
local SELR_BUTTON = rb.actions.PLA_SELECT_REPEAT
|
||||
local UP_BUTTON = rb.actions.PLA_UP
|
||||
local UPR_BUTTON = rb.actions.PLA_UP_REPEAT
|
||||
|
||||
-- clamps value to >= min and <= max
|
||||
local function clamp(iVal, iMin, iMax)
|
||||
if iMin > iMax then
|
||||
local swap = iMin
|
||||
iMin, iMax = iMax, swap
|
||||
end
|
||||
|
||||
if iVal < iMin then
|
||||
return iMin
|
||||
elseif iVal < iMax then
|
||||
return iVal
|
||||
end
|
||||
|
||||
return iMax
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--[[ cursor style button routine
|
||||
-- left / right are x, xi is increment xir is increment when repeat
|
||||
-- up / down are y, yi is increment yir is increment when repeat
|
||||
-- cancel is returned as 0,1
|
||||
-- select as 0, 1, 2, 3 (none, pressed, repeat, relesed)
|
||||
-- x_chg and y_chg are the amount x or y changed
|
||||
-- timeout == nil or -1 loop waits indefinitely till button is pressed
|
||||
-- time since last button press is returned in ticks..
|
||||
-- make xi, xir, yi, yir negative to flip direction...
|
||||
]]
|
||||
|
||||
local function dpad(x, xi, xir, y, yi, yir, timeout)
|
||||
_timer("dpad") -- start a persistant timer; keeps time between button events
|
||||
if timeout == nil then timeout = -1 end
|
||||
local cancel, select = 0, 0
|
||||
local x_chg, y_chg = 0, 0
|
||||
local button
|
||||
while true do
|
||||
button = rb.get_plugin_action(timeout)
|
||||
|
||||
if button == CANCEL_BUTTON then
|
||||
cancel = 1
|
||||
break;
|
||||
elseif button == EXIT_BUTTON then
|
||||
cancel = 1
|
||||
break;
|
||||
elseif button == SEL_BUTTON then
|
||||
select = 1
|
||||
timeout = timeout + 1
|
||||
elseif button == SELR_BUTTON then
|
||||
select = 2
|
||||
timeout = timeout + 1
|
||||
elseif button == SELREL_BUTTON then
|
||||
select = -1
|
||||
timeout = timeout + 1
|
||||
elseif button == LEFT_BUTTON then
|
||||
x_chg = x_chg - xi
|
||||
elseif button == LEFTR_BUTTON then
|
||||
x_chg = x_chg - xir
|
||||
elseif button == RIGHT_BUTTON then
|
||||
x_chg = x_chg + xi
|
||||
elseif button == RIGHTR_BUTTON then
|
||||
x_chg = x_chg + xir
|
||||
elseif button == UP_BUTTON then
|
||||
y_chg = y_chg + yi
|
||||
elseif button == UPR_BUTTON then
|
||||
y_chg = y_chg + yir
|
||||
elseif button == DOWN_BUTTON then
|
||||
y_chg = y_chg - yi
|
||||
elseif button == DOWNR_BUTTON then
|
||||
y_chg = y_chg - yir
|
||||
elseif timeout >= 0 then--and rb.button_queue_count() < 1 then
|
||||
break;
|
||||
end
|
||||
|
||||
if x_chg ~= 0 or y_chg ~= 0 then
|
||||
timeout = timeout + 1
|
||||
end
|
||||
end
|
||||
|
||||
x = x + x_chg
|
||||
y = y + y_chg
|
||||
|
||||
return cancel, select, x_chg, x, y_chg, y, _timer.check("dpad", true)
|
||||
end -- dpad
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--[[ prints a scrollable table to the screen;
|
||||
-- requires a contiguous table with only strings;
|
||||
-- 1st item in table is the title if hasheader == true
|
||||
-- returns select item indice if NOT m_sel..
|
||||
-- if m_sel == true a table of selected indices are returned ]]
|
||||
--------------------------------------------------------------------------------
|
||||
-- SECOND MODE OF OPERATION -- if co_routine is defined...
|
||||
-- prints values returned from a resumable factory in a coroutine this allows
|
||||
-- very large files etc to be displayed.. the downside is it takes time
|
||||
-- to load data when scrolling also NO multiple selection is allowed
|
||||
-- table is passed along with the final count t_count
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function print_table(t, t_count, settings)
|
||||
-- (table, t_count, {hasheader, wrap, m_sel, start, curpos, justify, co_routine})
|
||||
|
||||
if type(t) ~= "table" then
|
||||
rb.splash(rb.HZ * 5, "table expected got ".. type(t))
|
||||
return
|
||||
end
|
||||
|
||||
local wrap, justify, start, curpos, co_routine, hasheader, m_sel
|
||||
local header_fgc, header_bgc, item_fgc, item_bgc, item_selc
|
||||
do
|
||||
local s = settings or _print.get_settings()
|
||||
wrap, justify = s.wrap, s.justify
|
||||
start, curpos = s.start, s.curpos
|
||||
co_routine = s.co_routine
|
||||
hasheader = s.hasheader
|
||||
m_sel = false
|
||||
if co_routine == nil then
|
||||
--no multi select in incremental mode
|
||||
m_sel = s.msel
|
||||
end
|
||||
header_fgc = s.hfgc or _clr.set( 0, 000, 000, 000)
|
||||
header_bgc = s.hbgc or _clr.set(-1, 255, 255, 255)
|
||||
item_fgc = s.ifgc or _clr.set(-1, 000, 255, 060)
|
||||
item_bgc = s.ibgc or _clr.set( 0, 000, 000, 000)
|
||||
item_selc = s.iselc or _clr.set( 1, 000, 200, 100)
|
||||
end
|
||||
|
||||
local table_p, line, maxline
|
||||
|
||||
local function set_vsb() end -- forward declaration; initialized below
|
||||
|
||||
local function init_position(acc_ticks, acc_steps)
|
||||
if not acc_ticks then acc_ticks = 15 end-- accelerate scroll every this many ticks
|
||||
if not acc_steps then acc_steps = 5 end -- default steps for an accelerated scroll
|
||||
|
||||
return {row = 1, row_scrl= acc_steps,
|
||||
col = 0, col_scrl = acc_steps,
|
||||
vcursor = 1, vcursor_min = 1,
|
||||
acc_ticks = acc_ticks,
|
||||
acc_steps = acc_steps}
|
||||
end
|
||||
|
||||
local function set_accel(time, scrl, t_p)
|
||||
if time < t_p.acc_ticks then -- accelerate scroll
|
||||
scrl = scrl + 1
|
||||
else
|
||||
scrl = t_p.acc_steps
|
||||
end
|
||||
return scrl
|
||||
end
|
||||
|
||||
--adds or removes \0 from end of table entry to mark selected items
|
||||
local function select_item(item)
|
||||
if item < 1 then item = 1 end
|
||||
if not t[item] then return end
|
||||
if t[item]:sub(-1) == "\0" then
|
||||
t[item] = t[item]:sub(1, -2) -- de-select
|
||||
else
|
||||
t[item] = t[item] .. "\0" -- select
|
||||
end
|
||||
end
|
||||
|
||||
-- displays header text at top
|
||||
local function disp_header(hstr)
|
||||
local header = header or hstr
|
||||
local opts = _print.opt.get()
|
||||
_print.opt.overflow("none") -- don't scroll header; colors change
|
||||
_print.opt.color(header_fgc, header_bgc)
|
||||
_print.opt.line(1)
|
||||
|
||||
_print.f()
|
||||
local line = _print.f(header)
|
||||
|
||||
_print.opt.set(opts)
|
||||
_print.opt.line(2)
|
||||
return 2
|
||||
end
|
||||
|
||||
-- gets user input to select items, quit, scroll
|
||||
local function get_input(t_p)
|
||||
set_vsb(t_p.row + t_p.vcursor - 1)--t_p.row)
|
||||
rb.lcd_update()
|
||||
|
||||
local quit, select, x_chg, xi, y_chg, yi, timeb =
|
||||
dpad(t_p.col, -1, -t_p.col_scrl, t_p.row, -1, -t_p.row_scrl)
|
||||
|
||||
t_p.vcursor = t_p.vcursor + y_chg
|
||||
|
||||
if t_p.vcursor > maxline or t_p.vcursor < t_p.vcursor_min then
|
||||
t_p.row = yi
|
||||
end
|
||||
|
||||
if wrap == true and (y_chg == 1 or y_chg == -1) then
|
||||
|
||||
-- wraps list, stops at end if accelerated
|
||||
if t_p.row < t_p.vcursor_min - 1 then
|
||||
t_p.row = t_count - maxline + 1
|
||||
t_p.vcursor = maxline
|
||||
elseif t_p.row + maxline - 1 > t_count then
|
||||
t_p.row, t_p.vcursor = t_p.vcursor_min - 1, t_p.vcursor_min - 1
|
||||
end
|
||||
end
|
||||
|
||||
t_p.row = clamp(t_p.row, 1, math.max(t_count - maxline + 1, 1))
|
||||
t_p.vcursor = clamp(t_p.vcursor, t_p.vcursor_min, maxline)
|
||||
|
||||
if x_chg ~= 0 then
|
||||
|
||||
if x_chg ~= 1 and x_chg ~= -1 then --stop at the center if accelerated
|
||||
if (t_p.col <= 0 and xi > 0) or (t_p.col >= 0 and xi < 0) then
|
||||
xi = 0
|
||||
end
|
||||
end
|
||||
t_p.col = xi
|
||||
|
||||
t_p.col_scrl = set_accel(timeb, t_p.col_scrl, t_p)
|
||||
|
||||
elseif y_chg ~= 0 then
|
||||
--t_p.col = 0 -- reset column to the beginning
|
||||
_print.clear()
|
||||
_print.opt.sel_line(t_p.vcursor)
|
||||
|
||||
t_p.row_scrl = set_accel(timeb, t_p.row_scrl, t_p)
|
||||
|
||||
end
|
||||
|
||||
if select > 0 and timeb > 15 then --select may be sent multiple times
|
||||
if m_sel == true then
|
||||
select_item(t_p.row + t_p.vcursor - 1)
|
||||
else
|
||||
return -1, 0, 0, (t_p.row + t_p.vcursor - 1)
|
||||
end
|
||||
end
|
||||
if quit > 0 then return -2, 0, 0, 0 end
|
||||
return t_p.row, x_chg, y_chg, 0
|
||||
end
|
||||
|
||||
-- displays the actual table
|
||||
local function display_table(table_p, col_c, row_c, sel)
|
||||
local i = table_p.row
|
||||
while i >= 1 and i <= t_count do
|
||||
|
||||
-- only print if beginning or user scrolled up/down
|
||||
if row_c ~= 0 then
|
||||
|
||||
if t[i] == nil and co_routine then
|
||||
--value has been garbage collected or not created yet
|
||||
coroutine.resume(co_routine, i)
|
||||
end
|
||||
|
||||
if t[i] == nil then
|
||||
rb.splash(1, string.format("ERROR %d is nil", i))
|
||||
t[i] = "???"
|
||||
if rb.get_plugin_action(10) == CANCEL_BUTTON then return 0 end
|
||||
end
|
||||
|
||||
if m_sel == true and t[i]:sub(-1) == "\0" then
|
||||
_print.opt.sel_line(line)
|
||||
end
|
||||
|
||||
if i == 1 and hasheader == true then
|
||||
line = disp_header(t[1])
|
||||
else
|
||||
line = _print.f("%s", tostring(t[i]))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
i = i + 1 -- important!
|
||||
|
||||
if line == 1 or i > t_count or col_c ~= 0 then
|
||||
_print.opt.column(table_p.col)
|
||||
i, col_c, row_c, sel = get_input(table_p)
|
||||
end
|
||||
|
||||
rb.button_clear_queue() -- keep the button queue from overflowing
|
||||
end
|
||||
return sel
|
||||
end -- display_table
|
||||
--============================================================================--
|
||||
|
||||
_print.opt.defaults()
|
||||
_print.opt.autoupdate(false)
|
||||
_print.opt.color(item_fgc, item_bgc, item_selc)
|
||||
|
||||
table_p = init_position(15, 5)
|
||||
line, maxline = _print.opt.area(5, 1, rb.LCD_WIDTH - 10, rb.LCD_HEIGHT - 2)
|
||||
maxline = math.min(maxline, t_count)
|
||||
|
||||
-- allow user to start at a position other than the beginning
|
||||
if start ~= nil then table_p.row = clamp(start, 1, t_count + 1) end
|
||||
|
||||
if hasheader == true then
|
||||
table_p.vcursor_min = 2 -- lowest selectable item
|
||||
table_p.vcursor = 2
|
||||
end
|
||||
|
||||
table_p.vcursor = curpos or table_p.vcursor_min
|
||||
|
||||
if table_p.vcursor < 1 or table_p.vcursor > maxline then
|
||||
table_p.vcursor = table_p.vcursor_min
|
||||
end
|
||||
|
||||
_print.opt.sel_line(table_p.vcursor)
|
||||
_print.opt.overflow("manual")
|
||||
_print.opt.justify(justify)
|
||||
|
||||
-- initialize vertical scrollbar
|
||||
set_vsb(); do
|
||||
local vsb =_print.opt.get()
|
||||
if rb.LCD_DEPTH == 2 then -- invert 2-bit screens
|
||||
vsb.fg_pattern = 3 - vsb.fg_pattern
|
||||
vsb.bg_pattern = 3 - vsb.bg_pattern
|
||||
end
|
||||
|
||||
set_vsb = function (item)
|
||||
if t_count > (maxline or t_count) then
|
||||
rb.set_viewport(vsb)
|
||||
item = item or 0
|
||||
local m = maxline / 2 + 1
|
||||
rb.gui_scrollbar_draw(vsb.width - 5, vsb.y, 5, vsb.height,
|
||||
t_count, math.max(0, item - m),
|
||||
math.min(item + m, t_count), 0)
|
||||
end
|
||||
end
|
||||
end -- set_vsb
|
||||
local selected = display_table(table_p, 0, 1, 0)
|
||||
|
||||
_print.opt.defaults()
|
||||
|
||||
if m_sel == true then -- walk the table to get selected items
|
||||
selected = {}
|
||||
for i = 1, t_count do
|
||||
if t[i]:sub(-1) == "\0" then table.insert(selected, i) end
|
||||
end
|
||||
end
|
||||
--rb.splash(100, string.format("#1 %d, %d, %d", row, vcursor_pos, sel))
|
||||
return selected, table_p.row, table_p.vcursor
|
||||
end --print_table
|
Loading…
Add table
Add a link
Reference in a new issue