Allow first level folders in plugin menu

add sorting directories as files
move picross files to a hidden folder

use directory for lua_scripts, sgt_puzzles

make plugin browser able to handle 1st level directories

Change-Id: I30852d71dc992c378d5790756e94f06f5a2e9bef
This commit is contained in:
William Wilgus 2024-05-04 08:41:16 -04:00
parent efcea66280
commit d7c541742f
14 changed files with 1079 additions and 58 deletions

View file

@ -224,7 +224,11 @@ static int compare(const void* p1, const void* p2)
struct entry* e2 = (struct entry*)p2;
int criteria;
if (e1->attr & ATTR_DIRECTORY && e2->attr & ATTR_DIRECTORY)
if (cmp_data.sort_dir == SORT_AS_FILE)
{ /* treat as two files */
criteria = global_settings.sort_file;
}
else if (e1->attr & ATTR_DIRECTORY && e2->attr & ATTR_DIRECTORY)
{ /* two directories */
criteria = cmp_data.sort_dir;
@ -326,18 +330,17 @@ int ft_load(struct tree_context* c, const char* tempdir)
info = dir_get_info(dir, entry);
len = strlen((char *)entry->d_name);
/* skip directories . and .. */
if ((info.attribute & ATTR_DIRECTORY) &&
(((len == 1) && (!strncmp((char *)entry->d_name, ".", 1))) ||
((len == 2) && (!strncmp((char *)entry->d_name, "..", 2))))) {
continue;
}
/* Skip FAT volume ID */
if (info.attribute & ATTR_VOLUME_ID) {
continue;
}
dptr->attr = info.attribute;
int dir_attr = (dptr->attr & ATTR_DIRECTORY);
/* skip directories . and .. */
if (dir_attr && is_dotdir_name(entry->d_name))
continue;
/* filter out dotfiles and hidden files */
if (*c->dirfilter != SHOW_ALL &&
((entry->d_name[0]=='.') ||
@ -345,48 +348,45 @@ int ft_load(struct tree_context* c, const char* tempdir)
continue;
}
dptr->attr = info.attribute;
int dir_attr = (dptr->attr & ATTR_DIRECTORY);
/* check for known file types */
if ( !(dir_attr) )
dptr->attr |= filetype_get_attr((char *)entry->d_name);
int file_attr = (dptr->attr & FILE_ATTR_MASK);
#define CHK_FT(show,attr) (*c->dirfilter == (show) && file_attr != (attr))
/* filter out non-visible files */
if ((!(dir_attr) && ((*c->dirfilter == SHOW_PLAYLIST &&
file_attr != FILE_ATTR_M3U) ||
((*c->dirfilter == SHOW_MUSIC && file_attr != FILE_ATTR_AUDIO) &&
file_attr != FILE_ATTR_M3U) ||
if ((!(dir_attr) && (CHK_FT(SHOW_PLAYLIST, FILE_ATTR_M3U) ||
(CHK_FT(SHOW_MUSIC, FILE_ATTR_AUDIO) && file_attr != FILE_ATTR_M3U) ||
(*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
(*c->dirfilter == SHOW_WPS && file_attr != FILE_ATTR_WPS) ||
(*c->dirfilter == SHOW_FONT && file_attr != FILE_ATTR_FONT) ||
(*c->dirfilter == SHOW_SBS && file_attr != FILE_ATTR_SBS) ||
CHK_FT(SHOW_WPS, FILE_ATTR_WPS) ||
CHK_FT(SHOW_FONT, FILE_ATTR_FONT) ||
CHK_FT(SHOW_SBS, FILE_ATTR_SBS) ||
#if CONFIG_TUNER
(*c->dirfilter == SHOW_FMS && file_attr != FILE_ATTR_FMS) ||
CHK_FT(SHOW_FMS, FILE_ATTR_FMS) ||
CHK_FT(SHOW_FMR, FILE_ATTR_FMR) ||
#endif
#ifdef HAVE_REMOTE_LCD
(*c->dirfilter == SHOW_RWPS && file_attr != FILE_ATTR_RWPS) ||
(*c->dirfilter == SHOW_RSBS && file_attr != FILE_ATTR_RSBS) ||
CHK_FT(SHOW_RWPS, FILE_ATTR_RWPS) ||
CHK_FT(SHOW_RSBS, FILE_ATTR_RSBS) ||
#if CONFIG_TUNER
(*c->dirfilter == SHOW_RFMS && file_attr != FILE_ATTR_RFMS) ||
CHK_FT(SHOW_RFMS, FILE_ATTR_RFMS) ||
#endif
#endif
#if CONFIG_TUNER
(*c->dirfilter == SHOW_FMR && file_attr != FILE_ATTR_FMR) ||
#endif
(*c->dirfilter == SHOW_M3U && file_attr != FILE_ATTR_M3U) ||
(*c->dirfilter == SHOW_CFG && file_attr != FILE_ATTR_CFG) ||
(*c->dirfilter == SHOW_LNG && file_attr != FILE_ATTR_LNG) ||
(*c->dirfilter == SHOW_MOD && file_attr != FILE_ATTR_MOD) ||
(*c->dirfilter == SHOW_PLUGINS && file_attr != FILE_ATTR_ROCK &&
file_attr != FILE_ATTR_LUA &&
file_attr != FILE_ATTR_OPX) ||
CHK_FT(SHOW_M3U, FILE_ATTR_M3U) ||
CHK_FT(SHOW_CFG, FILE_ATTR_CFG) ||
CHK_FT(SHOW_LNG, FILE_ATTR_LNG) ||
CHK_FT(SHOW_MOD, FILE_ATTR_MOD) ||
/* show first level directories */
((!(dir_attr) || c->dirlevel > 0) &&
CHK_FT(SHOW_PLUGINS, FILE_ATTR_ROCK) &&
file_attr != FILE_ATTR_LUA &&
file_attr != FILE_ATTR_OPX) ||
(callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c)))
{
continue;
}
#undef CHK_FT
if (len > c->cache.name_buffer_size - name_buffer_used - 1) {
/* Tell the world that we ran out of buffer space */
@ -408,7 +408,9 @@ int ft_load(struct tree_context* c, const char* tempdir)
c->dirlength = files_in_dir;
closedir(dir);
cmp_data.sort_dir = c->sort_dir;
/* allow directories to be sorted into file list */
cmp_data.sort_dir = (*c->dirfilter == SHOW_PLUGINS) ? SORT_AS_FILE : c->sort_dir;
if (global_settings.sort_case)
{
if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)

View file

@ -57,7 +57,6 @@ lastfm_scrobbler_viewer,viewers
logo,demos
lrcplayer,apps
lua,viewers
lua_scripts,demos
fractals,demos
main_menu_config,apps
matrix,demos

View file

@ -117,7 +117,6 @@ metronome.c
#if PLUGIN_BUFFER_SIZE >= 0x80000
boomshine.lua
picross.lua
lua_scripts.lua
#ifdef HAVE_LCD_COLOR
pixel-painter.lua
#endif /* HAVE_LCD_COLOR */

View file

@ -0,0 +1,119 @@
-- dbgettags.lua Bilgus 2017
--[[
/***************************************************************************
* __________ __ ___.
* 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.
*
****************************************************************************/
]]
require("actions")
local CANCEL_BUTTON = rb.actions.PLA_CANCEL
local sINVALIDDATABASE = "Invalid Database"
local sERROROPENING = "Error opening"
-- tag cache header
sTCVERSION = string.char(0x10)
sTCHEADER = string.reverse("TCH" .. sTCVERSION)
DATASZ = 4 -- int32_t
TCHSIZE = 3 * DATASZ -- 3 x int32_t
-- Converts array of bytes to proper endian
function bytesLE_n(str)
str = str or ""
local tbyte={str:byte(1, -1)}
local bpos = 1
local num = 0
for k = 1,#tbyte do -- (k = #t, 1, -1 for BE)
num = num + tbyte[k] * bpos
bpos = bpos * 256
end
return num
end
-- uses database files to retrieve database tags
-- adds all unique tags into a lua table
-- ftable is optional
function get_tags(filename, hstr, ftable)
if not filename then return end
if not ftable then ftable = {} end
hstr = hstr or filename
local file = io.open('/' .. filename or "", "r") --read
if not file then rb.splash(100, sERROROPENING .. " " .. filename) return end
local fsz = file:seek("end")
local posln = 0
local tag_len = TCHSIZE
local idx
local function readchrs(count)
if posln >= fsz then return nil end
file:seek("set", posln)
posln = posln + count
return file:read(count)
end
-- check the header and get size + #entries
local tagcache_header = readchrs(DATASZ) or ""
local tagcache_sz = readchrs(DATASZ) or ""
local tagcache_entries = readchrs(DATASZ) or ""
if tagcache_header ~= sTCHEADER or
bytesLE_n(tagcache_sz) ~= (fsz - TCHSIZE) then
rb.splash(100, sINVALIDDATABASE .. " " .. filename)
return
end
-- local tag_entries = bytesLE_n(tagcache_entries)
for k, v in pairs(ftable) do ftable[k] = nil end -- clear table
ftable[1] = hstr
local tline = #ftable + 1
ftable[tline] = ""
local str = ""
while true do
tag_len = bytesLE_n(readchrs(DATASZ))
readchrs(DATASZ) -- idx = bytesLE_n(readchrs(DATASZ))
str = readchrs(tag_len) or ""
str = string.match(str, "(%Z+)%z") -- \0 terminated string
if str then
if ftable[tline - 1] ~= str then -- Remove dupes
ftable[tline] = str
tline = tline + 1
end
elseif posln >= fsz then
break
end
if rb.get_plugin_action(0) == CANCEL_BUTTON then
break
end
end
file:close()
return ftable
end -- get_tags

View file

@ -0,0 +1,241 @@
--[[
/***************************************************************************
* __________ __ ___.
* 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 ... == nil then rb.splash(rb.HZ * 3, "use 'require'") end
require("printtable")
local _lcd = require("lcd")
local _timer = require("timer")
--------------------------------------------------------------------------------
--[[ returns a sorted tables of directories and (another) of files
-- path is the starting path; norecurse == true.. only that path will be searched
-- findfile & finddir are definable search functions
-- if not defined all files/dirs are returned if false is passed.. none
-- or you can provide your own function see below..
-- f_t and d_t allow you to pass your own tables for re-use but isn't necessary
]]
local function get_files(path, norecurse, finddir, findfile, sort_by, f_t, d_t)
local quit = false
local sort_by_function -- forward declaration
local filepath_function -- forward declaration
local files = f_t or {}
local dirs = d_t or {}
local function f_filedir(name)
--default find function
-- example: return name:find(".mp3", 1, true) ~= nil
if name:len() <= 2 and (name == "." or name == "..") then
return false
end
return true
end
local function d_filedir(name)
--default discard function
return false
end
if finddir == nil then
finddir = f_filedir
elseif type(finddir) ~= "function" then
finddir = d_filedir
end
if findfile == nil then
findfile = f_filedir
elseif type(findfile) ~= "function" then
findfile = d_filedir
end
local function _get_files(path, cancelbtn)
local sep = ""
local filepath
local finfo_t
if string.sub(path, - 1) ~= "/" then sep = "/" end
for fname, isdir, finfo_t in luadir.dir(path, true) do
if isdir and finddir(fname) then
table.insert(dirs, path .. sep ..fname)
elseif not isdir and findfile(fname) then
filepath = filepath_function(path, sep, fname, finfo_t.attribute, finfo_t.size, finfo_t.time)
table.insert(files, filepath)
end
if rb.get_plugin_action(0) == cancelbtn then
return true
end
end
end
local function cmp_alphanum (op1, op2)
local type1= type(op1)
local type2 = type(op2)
if type1 ~= type2 then
return type1 < type2
else
if type1 == "string" then
op1 = op1:upper()
op2 = op2:upper()
return sort_by_function(op1, op2)
end
return op1 < op2
end
end
_lcd:splashf(1, "Searching for Files")
if sort_by == "name" then
sort_by_function = function(s1, s2) return s1 < s2 end
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s;", path, sep, fname)
end
elseif sort_by == "size" then
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s; At:%d, Sz:%d, Tm:%d", path, sep, fname, fattrib, fsize, ftime)
end
sort_by_function = function(s1, s2)
local v1, v2
v1 = string.match(s1, "SZ:(%d+)")
v2 = string.match(s2, "SZ:(%d+)")
if v1 or v2 then
return tonumber(v1 or 0) < tonumber(v2 or 0)
end
return s1 < s2
end
elseif sort_by == "date" then
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s; At:%d, Sz:%d, Tm:%d", path, sep, fname, fattrib, fsize, ftime)
end
sort_by_function = function(s1, s2)
local v1, v2
v1 = string.match(s1, "TM:(%d+)")
v2 = string.match(s2, "TM:(%d+)")
if v1 or v2 then
return tonumber(v1 or 0) < tonumber(v2 or 0)
end
return s1 < s2
end
end
table.insert(dirs, path) -- root
for key,value in pairs(dirs) do
--luadir.dir may error out so we need to do the call protected
-- _get_files(value, CANCEL_BUTTON)
_, quit = pcall(_get_files, value, CANCEL_BUTTON)
if quit == true or norecurse then
break;
end
end
table.sort(files, cmp_alphanum)
table.sort(dirs, cmp_alphanum)
return dirs, files
end -- get_files
--------------------------------------------------------------------------------
-- uses print_table and get_files to display simple file browser
-- sort_by "date" "name" "size"
-- descending true/false
function file_choose(dir, title, sort_by, descending)
local dstr, hstr = ""
if not title then
dstr = "%d items found in %0d.%02d seconds"
else
hstr = title
end
if not sort_by then sort_by = "name" end
sort_by = sort_by:lower()
-- returns whole seconds and remainder
local function tick2seconds(ticks)
local secs = (ticks / rb.HZ)
local csecs = (ticks - (secs * rb.HZ))
return secs, csecs
end
local norecurse = true
local f_finddir = nil -- function to match directories; nil all, false none
local f_findfile = nil -- function to match files; nil all, false none
local p_settings = {wrap = true, hasheader = true}
local timer
local files = {}
local dirs = {}
local item = 1
_lcd:clear()
while item > 0 do
if not title then
timer = _timer()
end
dirs, files = get_files(dir, norecurse, f_finddir, f_findfile, sort_by, dirs, files)
local parentdir = dirs[1]
for i = 1, #dirs do
dirs[i] = "\t" .. dirs[i]
end
if not descending then
for i = 1, #files do
-- only store file name .. strip attributes from end
table.insert(dirs, "\t" .. string.match(files[i], "[^;]+") or "?")
end
else
for i = #files, 1, -1 do
-- only store file name .. strip attributes from end
table.insert(dirs, "\t" .. string.match(files[i], "[^;]+") or "?")
end
end
for i=1, #files do files[i] = nil end -- empty table for reuse
if not title then
hstr = string.format(dstr, #dirs - 1, tick2seconds(timer:stop()))
end
table.insert(dirs, 1, hstr)
item = print_table(dirs, #dirs, p_settings)
-- If item was selected follow directory or return filename
if item > 0 then
dir = string.gsub(dirs[item], "%c+","")
if not rb.dir_exists("/" .. dir) then
return dir
end
end
if dir == parentdir then
dir = dir:sub(1, dir:match(".*()/") - 1)
if dir == "" then dir = "/" end
end
for i=1, #dirs do dirs[i] = nil end -- empty table for reuse
end
end -- file_choose
--------------------------------------------------------------------------------

View file

@ -0,0 +1,468 @@
--[[
/***************************************************************************
* __________ __ ___.
* 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 ... == nil then rb.splash(rb.HZ * 3, "use 'require'") end
require("printtable")
local _clr = require("color")
local _lcd = require("lcd")
local _print = require("print")
local _timer = require("timer")
require("actions")
local CANCEL_BUTTON = rb.actions.PLA_CANCEL
--------------------------------------------------------------------------------
-- builds an index of byte position of every line at each bufsz increment
-- in filename; bufsz == 1 would be every line; saves to filename.ext.idx_ext
-- lnbyte should be nil for text files and number of bytes per line for binary
local function build_file_index(filename, idx_ext, bufsz, lnbyte)
if not filename then return end
local file = io.open('/' .. filename, "r") --read
if not file then _lcd:splashf(100, "Can't open %s", filename) return end
local fsz = file:seek("end")
local fsz_kb = fsz / 1024
local count
local ltable = {0} --first index is the beginning of the file
local timer = _timer()
local fread
_lcd:splashf(100, "Indexing file %d Kb", (fsz / 1024))
if lnbyte then
fread = function(f) return f:read(lnbyte) end
else
lnbyte = -1
fread = function(f) return f:read("*l") end
end
file:seek("set", 0)
for i = 1, fsz do
if i % bufsz == 0 then
local loc = file:seek()
ltable[#ltable + 1] = loc
_lcd:splashf(1, "Parsing %d of %d Kb", loc / 1024, fsz_kb)
end
if rb.get_plugin_action(0) == CANCEL_BUTTON then
return
end
if not fread(file) then
count = i
break
end
end
local fileidx = io.open('/' .. filename .. idx_ext, "w+") -- write/erase
if fileidx then
fileidx:write(fsz .. "\n")
fileidx:write(count .. "\n")
fileidx:write(bufsz .. "\n")
fileidx:write(lnbyte .. "\n")
fileidx:write(table.concat(ltable, "\n"))
fileidx:close()
_lcd:splashf(100, "Finished in %d seconds", timer.stop() / rb.HZ)
collectgarbage("collect")
else
error("unable to save index file")
end
end -- build_file_index
--------------------------------------------------------------------------------
--- returns size of original file, total lines buffersize, and table filled
-- with line offsets in index file -> filename
local function load_index_file(filename)
local filesz, count, bufsz, lnbyte
local ltable
local fileidx = io.open('/' .. filename, "r") --read
if fileidx then
local idx = -3
ltable = {}
fileidx:seek("set", 0)
for line in fileidx:lines() do
if idx == -3 then
filesz = tonumber(line)
elseif idx == -2 then
count = tonumber(line)
elseif idx == -1 then
bufsz = tonumber(line)
elseif idx == 0 then
lnbyte = tonumber(line)
else
ltable[idx] = tonumber(line)
end
idx = idx + 1
end
fileidx:close()
end
return lnbyte, filesz, count, bufsz, ltable
end -- load_index_file
--------------------------------------------------------------------------------
-- creates a fixed index with fixed line lengths, perfect for viewing hex files
-- not so great for reading text files but works as a fallback
local function load_fixed_index(bytesperline, filesz, bufsz)
local lnbyte = bytesperline
local count = (filesz + lnbyte - 1) / lnbyte + 1
local idx_t = {} -- build index
for i = 0, filesz, bufsz do
idx_t[#idx_t + 1] = lnbyte * i
end
return lnbyte, filesz, count, bufsz, idx_t
end -- load_fixed_index
--------------------------------------------------------------------------------
-- uses print_table to display a whole file
function print_file(filename, maxlinelen, settings)
if not filename then return end
local file = io.open('/' .. filename or "", "r") --read
if not file then _lcd:splashf(100, "Can't open %s", filename) return end
maxlinelen = 33
local hstr = filename
local ftable = {}
table.insert(ftable, 1, hstr)
local tline = #ftable + 1
local remln = maxlinelen
local posln = 1
for line in file:lines() do
if line then
if maxlinelen then
if line == "" then
ftable[tline] = ftable[tline] or ""
tline = tline + 1
remln = maxlinelen
else
line = line:match("%w.+") or ""
end
local linelen = line:len()
while linelen > 0 do
local fsp = line:find("%s", posln + remln - 5) or 0x0
fsp = fsp - (posln + remln)
if fsp >= 0 then
local fspr = fsp
fsp = line:find("%s", posln + remln) or linelen
fsp = fsp - (posln + remln)
if math.abs(fspr) < fsp then fsp = fspr end
end
if fsp > 5 or fsp < -5 then fsp = 0 end
local str = line:sub(posln, posln + remln + fsp)
local slen = str:len()
ftable[tline] = ftable[tline] or ""
ftable[tline] = ftable[tline] .. str
linelen = linelen - slen
if linelen > 0 then
tline = tline + 1
posln = posln + slen
remln = maxlinelen
--loop continues
else
ftable[tline] = ftable[tline] .. " "
remln = maxlinelen - slen
posln = 1
--loop ends
end
end
else
ftable[#ftable + 1] = line
end
end
end
file:close()
_lcd:clear()
_print.clear()
if not settings then
settings = {}
settings.justify = "center"
settings.wrap = true
settings.msel = true
end
settings.hasheader = true
settings.co_routine = nil
settings.ovfl = "manual"
local sel =
print_table(ftable, #ftable, settings)
_lcd:splashf(rb.HZ * 2, "%d items {%s}", #sel, table.concat(sel, ", "))
ftable = nil
end -- print_file
--------------------------------------------------------------------------------
-- uses print_table to display a portion of a file
function print_file_increment(filename, settings)
if not filename then return end
local file = io.open('/' .. filename, "r") --read
if not file then _lcd:splashf(100, "Can't open %s", filename) return end
local fsz = file:seek("end")
local bsz = 1023
--if small file do it the easier way and load whole file to table
if fsz < 60 * 1024 then
file:close()
print_file(filename, settings)
return
end
local ext = ".idx"
local lnbyte, filesz, count, bufsz, idx_t = load_index_file(filename .. ext)
if not idx_t or fsz ~= filesz then -- build file index
build_file_index(filename, ext, bsz)
lnbyte, filesz, count, bufsz, idx_t = load_index_file(filename .. ext)
end
-- if invalid or user canceled creation fallback to a fixed index
if not idx_t or fsz ~= filesz or count <= 0 then
_lcd:splashf(rb.HZ * 5, "Unable to read file index %s", filename .. ext)
lnbyte, filesz, count, bufsz, idx_t = load_fixed_index(32, fsz, bsz)
end
if not idx_t or fsz ~= filesz or count <= 0 then
_lcd:splashf(rb.HZ * 5, "Unable to load file %s", filename)
return
end
local hstr = filename
local file_t = setmetatable({},{__mode = "kv"}) --weak keys and values
-- this allows them to be garbage collected as space is needed
-- rebuilds when needed
local ovf = 0
local lpos = 1
local timer = _timer()
file:seek("set", 0)
function print_co()
while true do
collectgarbage("step")
file_t[1] = hstr --position 1 is ALWAYS header/title
for i = 1, bufsz + ovf do
file_t[lpos + i] = file:read ("*l")
end
ovf = 0
lpos = lpos + bufsz
local bpos = coroutine.yield()
if bpos <= lpos then -- roll over or scroll up
bpos = (bpos - bufsz) + bpos % bufsz
timer:check(true)
end
lpos = bpos - bpos % bufsz
if lpos < 1 then
lpos = 1
elseif lpos > count - bufsz then -- partial fill
ovf = count - bufsz - lpos
end
--get position in file of the nearest indexed line
file:seek("set", idx_t[bpos / bufsz + 1])
-- on really large files if it has been more than 10 minutes
-- since the user scrolled up the screen wipe out the prior
-- items to free memory
if lpos % 5000 == 0 and timer:check() > rb.HZ * 600 then
for i = 1, lpos - 100 do
file_t[i] = nil
end
end
end
end
co = coroutine.create(print_co)
_lcd:clear()
_print.clear()
if not settings then
settings = {}
settings.justify = "center"
settings.wrap = true
end
settings.hasheader = true
settings.co_routine = co
settings.msel = false
settings.ovfl = "manual"
table.insert(file_t, 1, hstr) --position 1 is header/title
local sel =
print_table(file_t, count, settings)
file:close()
idx_t = nil
file_t = nil
return sel
end --print_file_increment
--------------------------------------------------------------------------------
function print_file_hex(filename, bytesperline, settings)
if not filename then return end
local file = io.open('/' .. filename, "r") --read
if not file then _lcd:splashf(100, "Can't open %s", filename) return end
local hstr = filename
local bpl = bytesperline
local fsz = file:seek("end")
--[[
local filesz = file:seek("end")
local bufsz = 1023
local lnbyte = bytesperline
local count = (filesz + lnbyte - 1) / lnbyte + 1
local idx_t = {} -- build index
for i = 0, filesz, bufsz do
idx_t[#idx_t + 1] = lnbyte * i
end]]
local lnbyte, filesz, count, bufsz, idx_t = load_fixed_index(bpl, fsz, 1023)
local file_t = setmetatable({},{__mode = "kv"}) --weak keys and values
-- this allows them to be garbage collected as space is needed
-- rebuilds when needed
local ovf = 0
local lpos = 1
local timer = _timer()
file:seek("set", 0)
function hex_co()
while true do
collectgarbage("step")
file_t[1] = hstr --position 1 is ALWAYS header/title
for i = 1, bufsz + ovf do
local pos = file:seek()
local s = file:read (lnbyte)
if not s then -- EOF
file_t[lpos + i] = ""
break;
end
local s_len = s:len()
if s_len > 0 then
local fmt = "0x%04X: " .. string.rep("%02X ", s_len)
local schrs = " " .. s:gsub("(%c)", " . ")
file_t[lpos + i] = string.format(fmt, pos, s:byte(1, s_len)) ..
schrs
else
file_t[lpos + i] = string.format("0x%04X: ", pos)
end
end
ovf = 0
lpos = lpos + bufsz
local bpos = coroutine.yield()
if bpos < lpos then -- roll over or scroll up
bpos = (bpos - bufsz) + bpos % bufsz
timer:check(true)
end
lpos = bpos - bpos % bufsz
if lpos < 1 then
lpos = 1
elseif lpos > count - bufsz then -- partial fill
ovf = count - bufsz - lpos
end
--get position in file of the nearest indexed line
file:seek("set", idx_t[bpos / bufsz + 1])
-- on really large files if it has been more than 10 minutes
-- since the user scrolled up the screen wipe out the prior
-- items to free memory
if lpos % 10000 == 0 and timer:check() > rb.HZ * 600 then
for i = 1, lpos - 100 do
file_t[i] = nil
end
end
end
end
co = coroutine.create(hex_co)
local function repl(char)
local ret = ""
if char:sub(1,2) == "0x" then
return string.format("%dd:", tonumber(char:sub(3, -2), 16))
else
return string.format("%03d ", tonumber(char, 16))
end
end
_lcd:clear()
_print.clear()
local sel, start, vcur = 1
table.insert(file_t, 1, hstr) --position 1 is header/title
if not settings then
settings = {}
settings.justify = "left"
settings.wrap = true
settings.msel = false
settings.hfgc = _clr.set( 0, 000, 000, 000)
settings.hbgc = _clr.set(-1, 255, 255, 255)
settings.ifgc = _clr.set(-1, 255, 255, 255)
settings.ibgc = _clr.set( 0, 000, 000, 000)
settings.iselc = _clr.set( 1, 000, 200, 100)
end
settings.hasheader = true
settings.co_routine = co
settings.start = start
settings.curpos = vcur
settings.ovfl = "manual"
while sel > 0 do
settings.start = start
settings.curpos = vcur
sel, start, vcur = print_table(file_t, count, settings)
if sel > 1 and file_t[sel] then -- flips between hex and decimal
local s = file_t[sel]
if s:sub(-1) == "\b" then
file_t[sel] = nil
ovf = -(bufsz - 1)
coroutine.resume(co, sel) --rebuild this item
else
s = s:gsub("(0x%x+:)", repl) .. "\b"
file_t[sel] = s:gsub("(%x%x%s)", repl) .. "\b"
end
end
end
file:close()
idx_t = nil
file_t = nil
return sel
end -- print_file_hex
--------------------------------------------------------------------------------

View file

@ -16,14 +16,7 @@ LUA_OBJ := $(call c2obj, $(LUA_SRC))
OTHER_SRC += $(LUA_SRC)
LUA_INCLUDEDIR := $(LUA_SRCDIR)/include_lua
LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua \
draw.lua draw_floodfill.lua draw_poly.lua draw_num.lua \
draw_text.lua files.lua image.lua image_save.lua lcd.lua \
math_ex.lua print.lua timer.lua playlist.lua pcm.lua \
sound.lua rbcompat.lua rbsettings.lua poly_points.lua \
printtable.lua printmenus.lua printsubmenu.lua \
menubuttons.lua menucoresettings.lua create_kbd_layout.lua \
temploader.lua)
LUA_INCLUDELIST := $(wildcard $(LUA_INCLUDEDIR)/*.lua)
ifndef APP_TYPE
ROCKS += $(LUA_BUILDDIR)/lua.rock
@ -31,6 +24,7 @@ else
### simulator
ROCKS += $(LUA_BUILDDIR)/lua.rock
endif
all: $(subst $(LUA_INCLUDEDIR)/,$(LUA_BUILDDIR)/,$(LUA_INCLUDELIST))
$(LUA_BUILDDIR)/lua.rock: $(LUA_OBJ) $(TLSFLIB) $(LUA_BUILDDIR)/actions.lua $(LUA_BUILDDIR)/buttons.lua $(LUA_BUILDDIR)/settings.lua \
$(LUA_BUILDDIR)/rocklib_aux.o $(LUA_BUILDDIR)/rb_defines.lua $(LUA_BUILDDIR)/sound_defines.lua \
@ -66,7 +60,7 @@ $(LUA_BUILDDIR)/rocklib_aux.o: $(LUA_BUILDDIR)/rocklib_aux.c
$(call PRINTS,CC $(<F))$(CC) $(INCLUDES) $(PLUGINFLAGS) -I $(LUA_SRCDIR) -c $< -o $@
$(LUA_BUILDDIR)/%.lua: $(LUA_INCLUDEDIR)/%.lua | $(LUA_BUILDDIR)
$(call PRINTS,CP $(subst $(LUA_INCLUDEDIR)/,,$<))cp $< $@
$(call PRINTS,CP $(notdir $<))cp $< $@
$(LUA_BUILDDIR)/lua.refmap: $(LUA_OBJ) $(TLSFLIB)

View file

@ -0,0 +1,172 @@
--[[
/***************************************************************************
* __________ __ ___.
* 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.
*
****************************************************************************/
]]
local scrpath = rb.current_path()
package.path = scrpath .. "/?.lua;" .. package.path --add lua_scripts directory to path
require("printmenus")
rb.actions = nil
package.loaded["actions"] = nil
--------------------------------------------------------------------------------
local Icon_Plugin = 0x9
local function get_files(path, norecurse, finddir, findfile, f_t, d_t)
local quit = false
local files = f_t or {}
local dirs = d_t or {}
local function f_filedir(name)
--default find function
-- example: return name:find(".mp3", 1, true) ~= nil
if name:len() <= 2 and (name == "." or name == "..") then
return false
end
if string.sub(name, 1, 1) == '.' then
return false
end
if string.sub(name, -4) == ".lua" then
return true
end
return false
end
local function d_filedir(name)
--default discard function
return false
end
if finddir == nil then
finddir = f_filedir
elseif type(finddir) ~= "function" then
finddir = d_filedir
end
if findfile == nil then
findfile = f_filedir
elseif type(findfile) ~= "function" then
findfile = d_filedir
end
local function _get_files(path, cancelbtn)
local sep = ""
if string.sub(path, - 1) ~= "/" then sep = "/" end
for fname, isdir in luadir.dir(path) do
if isdir and finddir(fname) then
table.insert(dirs, path .. sep ..fname)
elseif not isdir and findfile(fname) then
table.insert(files, path .. sep ..fname)
end
if rb.get_plugin_action(0) == cancelbtn then
return true
end
end
end
local function cmp_alphanum (op1, op2)
local type1= type(op1)
local type2 = type(op2)
if type1 ~= type2 then
return type1 < type2
else
if type1 == "string" then
op1 = op1:upper()
op2 = op2:upper()
end
return op1 < op2
end
end
table.insert(dirs, path) -- root
for key,value in pairs(dirs) do
--luadir.dir may error out so we need to do the call protected
_, quit = pcall(_get_files, value, CANCEL_BUTTON)
if quit == true or norecurse then
break;
end
end
table.sort(files, cmp_alphanum)
table.sort(dirs, cmp_alphanum)
return dirs, files
end -- get_files
--------------------------------------------------------------------------------
function icon_fn(item, icon)
if item ~= 0 then
icon = Icon_Plugin
else
icon = -1
end
return icon
end
-- uses print_table and get_files to display simple file browser
function script_choose(dir, title)
local dstr
local hstr = title
local norecurse = true
local f_finddir = false -- function to match directories; nil all, false none
local f_findfile = nil -- function to match files; nil all, false none
local t_linedesc = {show_icons = true, icon_fn = icon_fn}
local p_settings = {wrap = true, hasheader = true, justify = "left", linedesc = t_linedesc}
local files = {}
local dirs = {}
local item = 1
rb.lcd_clear_display()
while item > 0 do
dirs, files = get_files(dir, norecurse, f_finddir, f_findfile, dirs, files)
for i=1, #dirs do dirs[i] = nil end -- empty table for reuse
table.insert(dirs, 1, hstr)
for i = 1, #files do
table.insert(dirs, "\t" .. string.gsub(files[i], ".*/",""))
end
--print_menu(menu_t, func_t, selected, settings, copy_screen)
_, item = print_menu(dirs, nil, 0, p_settings)
-- If item was selected follow directory or return filename
item = item or -1
if item > 0 then
dir = files[item - 1]
if not rb.dir_exists("/" .. dir) then
return dir
end
end
end
end -- file_choose
--------------------------------------------------------------------------------
local script_path = script_choose(scrpath, "lua scripts")
if script_path then rb.restart_lua(script_path) end

View file

@ -10,7 +10,6 @@
LUASCR_SRCDIR := $(APPSDIR)/plugins/lua_scripts
LUASCR_BUILDDIR := $(BUILDDIR)/apps/plugins/lua_scripts
LUASCRS := $(wildcard $(LUASCR_SRCDIR)/*.lua)
#DUMMY := $(info [${LUASCRS}])
DUMMY : all
@ -18,7 +17,6 @@ DUMMY : all
all: $(subst $(LUASCR_SRCDIR)/,$(LUASCR_BUILDDIR)/,$(LUASCRS))
$(LUASCR_BUILDDIR)/%.lua: $(LUASCR_SRCDIR)/%.lua | $(LUASCR_BUILDDIR)
$(call PRINTS,CP $(subst $(LUASCR_SRCDIR)/,,$<))cp $< $@
$(call PRINTS,CP $(subst $(APPSDIR)/,,$<))cp $< $@
$(LUASCR_BUILDDIR):
$(call PRINTS,MKDIR $@)mkdir -p $(LUASCR_BUILDDIR)/

View file

@ -24,7 +24,7 @@ local _clr = require("color") -- clrset, clrinc provides device independent co
local _lcd = require("lcd") -- lcd helper functions
local plugindir = rb.PLUGIN_GAMES_DATA_DIR
local userdir = plugindir .. "/picross"
local userdir = plugindir .. "/.picross"
local wrap = rb.settings.read('global_settings', rb.system.global_settings.list_wraparound)
wrap = (wrap or 1) == 1
@ -371,7 +371,7 @@ function State:loadSave()
end
function State:loadDefault()
self:loadFile(userdir .. '/picross_default.picross')
return self:loadFile(userdir .. '/picross_default.picross')
end
function State:loadFile(path)
@ -763,7 +763,9 @@ function viewPicture()
end
if not State:loadSave() then
State:loadDefault()
if not State:loadDefault() then
return;
end
end
local act = rb.actions

View file

@ -8,7 +8,7 @@
#
PICRSCR_SRCDIR := $(APPSDIR)/plugins/picross
PICRSCR_BUILDDIR := $(BUILDDIR)/apps/plugins/picross
PICRSCR_BUILDDIR := $(BUILDDIR)/apps/plugins/.picross
PICRSCRS := $(wildcard $(PICRSCR_SRCDIR)/*.picross)
#DUMMY := $(info [${PICRSCRS}])
@ -18,7 +18,7 @@ DUMMY : all
all: $(subst $(PICRSCR_SRCDIR)/,$(PICRSCR_BUILDDIR)/,$(PICRSCRS))
$(PICRSCR_BUILDDIR)/%.picross: $(PICRSCR_SRCDIR)/%.picross | $(PICRSCR_BUILDDIR)
$(call PRINTS,CP $(subst $(PICRSCR_SRCDIR)/,,$<))cp $< $@
$(call PRINTS,CP $(subst $(APPSDIR)/,,$<))cp $< $@
$(PICRSCR_BUILDDIR):
$(call PRINTS,MKDIR $@)mkdir -p $(PICRSCR_BUILDDIR)/

View file

@ -163,7 +163,7 @@ enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB,
/* file and dir sort options */
enum { SORT_ALPHA, SORT_DATE, SORT_DATE_REVERSED, SORT_TYPE, /* available as settings */
SORT_ALPHA_REVERSED, SORT_TYPE_REVERSED }; /* internal use only */
SORT_ALPHA_REVERSED, SORT_TYPE_REVERSED, SORT_AS_FILE }; /* internal use only */
enum { SORT_INTERPRET_AS_DIGIT, SORT_INTERPRET_AS_NUMBER };
/* recursive dir insert options */

View file

@ -466,6 +466,13 @@ static int update_dir(void)
icon = tc.browse->icon;
if (icon == NOICON)
icon = filetype_get_icon(ATTR_DIRECTORY);
/* display sub directories in the title of plugin browser */
if (tc.dirlevel > 0 && *tc.dirfilter == SHOW_PLUGINS)
{
char *subdir = strrchr(tc.currdir, '/');
if (subdir)
title = subdir + 1; /* step past the separator */
}
}
else
{
@ -1056,7 +1063,7 @@ int rockbox_browse(struct browse_context *browse)
int last_context;
/* don't reset if its the same browse already loaded */
if (tc.browse != browse ||
!(tc.currdir[1] && strcmp(tc.currdir, browse->root) == 0))
!(tc.currdir[1] && strstr(tc.currdir, browse->root) != NULL))
{
tc.browse = browse;
tc.selected_item = 0;

View file

@ -167,6 +167,13 @@ sub make_install {
glob_install("$src/rocks/$t/*", "$libdir/rocks/$t", "-m 0755");
}
if(-e "$src/rocks/games/sgt_puzzles") {
unless (glob_mkdir("$libdir/rocks/games/sgt_puzzles")) {
return 0;
}
glob_install("$src/rocks/games/sgt_puzzles/*", "$libdir/rocks/games/sgt_puzzles", "-m 0755");
}
# rocks/viewers/lua
unless (glob_mkdir("$libdir/rocks/viewers/lua")) {
return 0;
@ -182,12 +189,13 @@ sub make_install {
#glob_mkdir("$temp_dir/rocks/demos/lua_scripts");
#glob_copy("$ROOT/apps/plugins/lua_scripts/*.lua", "$temp_dir/rocks/demos/lua_scripts/");
}
#lua picross puzzles
#lua picross puzzles
if(-e "$ROOT/apps/plugins/picross") {
unless (glob_mkdir("$libdir/rocks/games/picross")) {
unless (glob_mkdir("$libdir/rocks/games/.picross")) {
return 0;
}
glob_install("$ROOT/apps/plugins/picross/*.picross", "$libdir/rocks/games/picross");
glob_install("$ROOT/apps/plugins/picross/*.picross", "$libdir/rocks/games/.picross");
}
# all the rest directories
@ -451,6 +459,12 @@ sub buildzip {
glob_copy("$ROOT/apps/plugins/lua_scripts/*.lua", "$temp_dir/rocks/demos/lua_scripts/");
}
#lua picross puzzles
if(-e "$ROOT/apps/plugins/picross") {
glob_mkdir("$temp_dir/rocks/games/.picross");
glob_copy("$ROOT/apps/plugins/picross/*.picross", "$temp_dir/rocks/games/.picross/");
}
# exclude entries for the image file types not supported by the imageviewer for the target.
my $viewers = "$ROOT/apps/plugins/viewers.config";
my $c="cat $viewers | gcc $cppdef -I. -I$firmdir/export -E -P -include config.h -";
@ -512,7 +526,13 @@ sub buildzip {
foreach my $line (@rock_targetdirs) {
if ($line =~ /([^,]*),(.*)/) {
my ($plugin, $dir)=($1, $2);
move("$temp_dir/rocks/${plugin}.rock", "$temp_dir/rocks/$dir/${plugin}.rock");
if($dir eq 'games' and substr(${plugin}, 0, 4) eq "sgt-") {
glob_mkdir("$temp_dir/rocks/$dir/sgt_puzzles");
move("$temp_dir/rocks/${plugin}.rock", "$temp_dir/rocks/$dir/sgt_puzzles/${plugin}.rock");
}
else {
move("$temp_dir/rocks/${plugin}.rock", "$temp_dir/rocks/$dir/${plugin}.rock");
}
if(-e "$temp_dir/rocks/${plugin}.ovl") {
# if there's an "overlay" file for the .rock, move that as
# well