forked from len0rd/rockbox
[Feature] File Picker Plugin
allows viewers to pop a file browser to let the user pick a relevant file which then gets run by the viewer (only lua so far) Change-Id: I7e6b4c2827fab5e9f596d336f546100636c4b871
This commit is contained in:
parent
ef9490f683
commit
e3097bf92c
5 changed files with 328 additions and 0 deletions
|
@ -16486,3 +16486,17 @@
|
||||||
*: none
|
*: none
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_CHOOSE_FILE
|
||||||
|
desc: file_picker plugin ask user to select a file
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "Choose File"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "Choose File"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "Choose File"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
|
|
@ -35,6 +35,7 @@ doom,games
|
||||||
duke3d,games
|
duke3d,games
|
||||||
euroconverter,apps
|
euroconverter,apps
|
||||||
fft,demos
|
fft,demos
|
||||||
|
file_picker,viewers
|
||||||
fire,demos
|
fire,demos
|
||||||
fireworks,demos
|
fireworks,demos
|
||||||
firmware_flash,apps
|
firmware_flash,apps
|
||||||
|
|
|
@ -12,6 +12,7 @@ cube.c
|
||||||
cue_playlist.c
|
cue_playlist.c
|
||||||
dart_scorer.c
|
dart_scorer.c
|
||||||
dict.c
|
dict.c
|
||||||
|
file_picker.c
|
||||||
jackpot.c
|
jackpot.c
|
||||||
keybox.c
|
keybox.c
|
||||||
keyremap.c
|
keyremap.c
|
||||||
|
|
295
apps/plugins/file_picker.c
Normal file
295
apps/plugins/file_picker.c
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/*File Picker Plugin
|
||||||
|
|
||||||
|
FPP accepts several arguments to help in your file picking adventure
|
||||||
|
* NOTE: anything with spaces should be quoted, -f and -l can't be used together *
|
||||||
|
-r "<GOTO_PLUGIN_NAME>" doesn't need to be a full path demos/file.rock works
|
||||||
|
the file (if choosen, cancel exits) will be passed as a parameter
|
||||||
|
-t "<TITLE ( max 64 chars )>"
|
||||||
|
-s "<START DIR>"
|
||||||
|
-f "<.EXT (max 64 chars) >" the extension of the files you are looking for
|
||||||
|
must have the '.' and ".*" accepts any file
|
||||||
|
-l "<.EXT.EXT,.EXT .EXT (max 64 chars) >" list of extensions for files you are looking for
|
||||||
|
each must have the '.' spaces and commas are ignored
|
||||||
|
-a attrib flags eg FILE_ATTR_AUDIO
|
||||||
|
-d disallow changing directories (hide directories doesn't allow changing from start dir)
|
||||||
|
*/
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "lang_enum.h"
|
||||||
|
#include "lib/arg_helper.h"
|
||||||
|
|
||||||
|
#if defined(DEBUG) || defined(SIMULATOR)
|
||||||
|
#define logf(...) rb->debugf(__VA_ARGS__); rb->debugf("\n")
|
||||||
|
#elif defined(ROCKBOX_HAS_LOGF)
|
||||||
|
#define logf rb->logf
|
||||||
|
#else
|
||||||
|
#define logf(...) do { } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FIND_NODIRS 0x01
|
||||||
|
#define FIND_ATTRIB 0x02
|
||||||
|
#define FIND_WILDCARD 0x04
|
||||||
|
#define FIND_EXT 0x08
|
||||||
|
#define FIND_EXT_IN_LIST 0x10
|
||||||
|
|
||||||
|
static struct fpp
|
||||||
|
{
|
||||||
|
char return_plugin[MAX_PATH];
|
||||||
|
char start_dir[MAX_PATH];
|
||||||
|
char file_ext[64];
|
||||||
|
char title[64];
|
||||||
|
int tree_attr;
|
||||||
|
int flags;
|
||||||
|
}fpp;
|
||||||
|
|
||||||
|
static int arg_callback(char argchar, const char **parameter, void *userdata)
|
||||||
|
{
|
||||||
|
struct fpp *pfp = userdata;
|
||||||
|
int ret;
|
||||||
|
long num;
|
||||||
|
const char* start = *parameter;
|
||||||
|
while (*parameter[0] > '/' && ispunct(*parameter[0])) (*parameter)++;
|
||||||
|
switch (tolower(argchar))
|
||||||
|
{
|
||||||
|
case 'd' :
|
||||||
|
pfp->flags |= FIND_NODIRS;
|
||||||
|
logf ("Find no dirs");
|
||||||
|
break;
|
||||||
|
case 'r' : /*return_plugin*/
|
||||||
|
logf ("trying PLUGIN_DIR...");
|
||||||
|
size_t l = rb->strlcpy(pfp->return_plugin,
|
||||||
|
PLUGIN_DIR,
|
||||||
|
sizeof(pfp->return_plugin));
|
||||||
|
|
||||||
|
ret = string_parse(parameter,
|
||||||
|
pfp->return_plugin + l,
|
||||||
|
sizeof(pfp->return_plugin) - l);
|
||||||
|
|
||||||
|
if (ret && !rb->file_exists(pfp->return_plugin))
|
||||||
|
{
|
||||||
|
logf("Failed");
|
||||||
|
*parameter = start;
|
||||||
|
string_parse(parameter, pfp->return_plugin,
|
||||||
|
sizeof(pfp->return_plugin));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
logf ("Ret plugin: Val: %s\n", pfp->return_plugin);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't' : /* title */
|
||||||
|
ret = string_parse(parameter, pfp->title, sizeof(pfp->title));
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
logf ("Title: Val: %s\n", pfp->title);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's' : /* start directory */
|
||||||
|
ret = string_parse(parameter, pfp->start_dir, sizeof(pfp->start_dir));
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
if (!rb->dir_exists(pfp->start_dir))
|
||||||
|
{
|
||||||
|
rb->strlcpy(pfp->start_dir, PATH_ROOTSTR, sizeof(pfp->start_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
logf ("Start dir: Val: %s\n", pfp->start_dir);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'f' : /* file extension */
|
||||||
|
if (pfp->flags & FIND_EXT_IN_LIST)
|
||||||
|
{
|
||||||
|
rb->splash(HZ*5, "list extensions already active -f ignored");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = string_parse(parameter, pfp->file_ext, sizeof(pfp->file_ext));
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
if (pfp->file_ext[1] == '*')
|
||||||
|
pfp->flags |= FIND_WILDCARD;
|
||||||
|
else
|
||||||
|
pfp->flags |= FIND_EXT;
|
||||||
|
logf ("Extension: Val: %s\n", pfp->file_ext);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l' : /* file extension list */
|
||||||
|
if (pfp->flags & FIND_EXT)
|
||||||
|
{
|
||||||
|
rb->splash(HZ*5, "extension already active -l ignored");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = string_parse(parameter, pfp->file_ext, sizeof(pfp->file_ext));
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
char *wr = pfp->file_ext;
|
||||||
|
char *rd = pfp->file_ext;
|
||||||
|
while (*rd != '\0') /* copy the extensions */
|
||||||
|
{
|
||||||
|
if (*rd == ' ' || *rd == ',' || *rd == ';')
|
||||||
|
{
|
||||||
|
/* ignore spaces, commas, and semicolons */
|
||||||
|
rd++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*wr++ = *rd++;
|
||||||
|
}
|
||||||
|
*wr = '\0';
|
||||||
|
pfp->flags |= FIND_EXT_IN_LIST;
|
||||||
|
logf ("Extension List: Val: %s\n", pfp->file_ext);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'a' : /* tree attribute */
|
||||||
|
ret = longnum_parse(parameter, &num, NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
pfp->tree_attr = (num)&FILE_ATTR_MASK;
|
||||||
|
pfp->flags |= FIND_ATTRIB;
|
||||||
|
logf ("Attrib: Val: 0x%x\n", (uint32_t)num);
|
||||||
|
logf("ate %d chars\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
rb->splashf(HZ, "Unknown switch '%c'",argchar);
|
||||||
|
logf("Unknown switch '%c'",argchar);
|
||||||
|
//return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cb_show_item(char *name, int attr, struct tree_context *tc)
|
||||||
|
{
|
||||||
|
static int dirlevel = -1;
|
||||||
|
if(attr & ATTR_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (fpp.flags & FIND_NODIRS)
|
||||||
|
{
|
||||||
|
if (tc->dirlevel == dirlevel)
|
||||||
|
return false;
|
||||||
|
dirlevel = tc->dirlevel;
|
||||||
|
if (rb->strcasestr(tc->currdir, fpp.start_dir) == NULL)
|
||||||
|
{
|
||||||
|
tc->is_browsing = false; /* exit immediately */
|
||||||
|
logf("exiting %d", tc->dirlevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fpp.flags & FIND_WILDCARD)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((fpp.flags & FIND_ATTRIB) && (fpp.tree_attr & attr) != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fpp.flags & FIND_EXT)
|
||||||
|
{
|
||||||
|
const char *p = rb->strrchr(name, '.' );
|
||||||
|
if (p != NULL && !rb->strcasecmp( p, fpp.file_ext))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpp.flags & FIND_EXT_IN_LIST)
|
||||||
|
{
|
||||||
|
const char *p = rb->strrchr(name, '.' );
|
||||||
|
if (p != NULL && rb->strcasestr(fpp.file_ext, p) != NULL)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logf("Excluded: %s", name);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int browse_file_dir(struct fpp *pfp)
|
||||||
|
{
|
||||||
|
char buf[MAX_PATH];
|
||||||
|
struct browse_context browse = {
|
||||||
|
.dirfilter = SHOW_ALL,
|
||||||
|
.flags = BROWSE_SELECTONLY | BROWSE_DIRFILTER,
|
||||||
|
.title = pfp->title,
|
||||||
|
.icon = Icon_Playlist,
|
||||||
|
.buf = buf,
|
||||||
|
.bufsize = sizeof(buf),
|
||||||
|
.root = pfp->start_dir,
|
||||||
|
.callback_show_item = &cb_show_item,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS)
|
||||||
|
{
|
||||||
|
if (rb->file_exists(buf))
|
||||||
|
{
|
||||||
|
logf("Loading %s", buf);
|
||||||
|
return rb->plugin_open(pfp->return_plugin, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("Error opening %s", buf);
|
||||||
|
rb->splashf(HZ *2, "Error Opening %s", buf);
|
||||||
|
return PLUGIN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PLUGIN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum plugin_status plugin_start(const void* parameter)
|
||||||
|
{
|
||||||
|
if (!parameter)
|
||||||
|
{
|
||||||
|
rb->splash(HZ *2, "No Args");
|
||||||
|
return PLUGIN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
argparse((const char*) parameter, -1, &fpp, &arg_callback);
|
||||||
|
|
||||||
|
if (fpp.title[0] == '\0')
|
||||||
|
{
|
||||||
|
if (rb->global_settings->talk_menu)
|
||||||
|
rb->talk_id(LANG_CHOOSE_FILE, true);
|
||||||
|
|
||||||
|
if ((fpp.flags & FIND_EXT) || (fpp.flags & FIND_EXT_IN_LIST))
|
||||||
|
{
|
||||||
|
rb->snprintf(fpp.title, sizeof(fpp.title),
|
||||||
|
"%s (%s)", rb->str(LANG_CHOOSE_FILE), fpp.file_ext);
|
||||||
|
if (rb->global_settings->talk_menu)
|
||||||
|
rb->talk_spell(fpp.file_ext, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rb->snprintf(fpp.title, sizeof(fpp.title), "%s", rb->str(LANG_CHOOSE_FILE));
|
||||||
|
}
|
||||||
|
rb->talk_force_enqueue_next();
|
||||||
|
}
|
||||||
|
if (fpp.start_dir[0] == '\0' || !rb->dir_exists(fpp.start_dir))
|
||||||
|
rb->strcpy(fpp.start_dir, PATH_ROOTSTR);
|
||||||
|
|
||||||
|
return browse_file_dir(&fpp);
|
||||||
|
}
|
|
@ -241,6 +241,20 @@ static void display_traceback(const char *errstr)
|
||||||
rb->splash(10 * HZ, errstr);
|
rb->splash(10 * HZ, errstr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int browse_scripts(void)
|
||||||
|
{
|
||||||
|
static char buf[MAX_PATH];
|
||||||
|
const char *fname = rb->plugin_get_current_filename();
|
||||||
|
/* strip plugin dir to save space in the param buffer */
|
||||||
|
if (rb->strncmp(fname, PLUGIN_DIR, sizeof(PLUGIN_DIR) - 1) == 0)
|
||||||
|
fname += sizeof(PLUGIN_DIR) - 1; /* leave slash */
|
||||||
|
/* -r return to this plugin, -f looking for lua files,
|
||||||
|
-s start in lua_scripts, -d lock to that directory */
|
||||||
|
snprintf(buf, sizeof(buf), "-r'%s'-f'.lua'-s'%s'-d",
|
||||||
|
fname, PLUGIN_DEMOS_DIR"/lua_scripts/");
|
||||||
|
return rb->plugin_open(VIEWERS_DIR "/file_picker.rock", buf);
|
||||||
|
}
|
||||||
/***************** Plugin Entry Point *****************/
|
/***************** Plugin Entry Point *****************/
|
||||||
enum plugin_status plugin_start(const void* parameter)
|
enum plugin_status plugin_start(const void* parameter)
|
||||||
{
|
{
|
||||||
|
@ -249,7 +263,10 @@ enum plugin_status plugin_start(const void* parameter)
|
||||||
if (parameter == NULL)
|
if (parameter == NULL)
|
||||||
{
|
{
|
||||||
if (!Ls)
|
if (!Ls)
|
||||||
|
{
|
||||||
rb->splash(HZ, "Play a .lua file!");
|
rb->splash(HZ, "Play a .lua file!");
|
||||||
|
return browse_scripts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue