diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/file_picker.c | 295 | ||||
-rw-r--r-- | apps/plugins/lua/rocklua.c | 17 |
4 files changed, 314 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 814fb2f130..79186b7aed 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -35,6 +35,7 @@ doom,games | |||
35 | duke3d,games | 35 | duke3d,games |
36 | euroconverter,apps | 36 | euroconverter,apps |
37 | fft,demos | 37 | fft,demos |
38 | file_picker,viewers | ||
38 | fire,demos | 39 | fire,demos |
39 | fireworks,demos | 40 | fireworks,demos |
40 | firmware_flash,apps | 41 | firmware_flash,apps |
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 0b1d48d5de..a070637a77 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -12,6 +12,7 @@ cube.c | |||
12 | cue_playlist.c | 12 | cue_playlist.c |
13 | dart_scorer.c | 13 | dart_scorer.c |
14 | dict.c | 14 | dict.c |
15 | file_picker.c | ||
15 | jackpot.c | 16 | jackpot.c |
16 | keybox.c | 17 | keybox.c |
17 | keyremap.c | 18 | keyremap.c |
diff --git a/apps/plugins/file_picker.c b/apps/plugins/file_picker.c new file mode 100644 index 0000000000..ce9d81728e --- /dev/null +++ b/apps/plugins/file_picker.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2024 William Wilgus | ||
11 | * | ||
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 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | /*File Picker Plugin | ||
22 | |||
23 | FPP accepts several arguments to help in your file picking adventure | ||
24 | * NOTE: anything with spaces should be quoted, -f and -l can't be used together * | ||
25 | -r "<GOTO_PLUGIN_NAME>" doesn't need to be a full path demos/file.rock works | ||
26 | the file (if choosen, cancel exits) will be passed as a parameter | ||
27 | -t "<TITLE ( max 64 chars )>" | ||
28 | -s "<START DIR>" | ||
29 | -f "<.EXT (max 64 chars) >" the extension of the files you are looking for | ||
30 | must have the '.' and ".*" accepts any file | ||
31 | -l "<.EXT.EXT,.EXT .EXT (max 64 chars) >" list of extensions for files you are looking for | ||
32 | each must have the '.' spaces and commas are ignored | ||
33 | -a attrib flags eg FILE_ATTR_AUDIO | ||
34 | -d disallow changing directories (hide directories doesn't allow changing from start dir) | ||
35 | */ | ||
36 | #include "plugin.h" | ||
37 | #include "lang_enum.h" | ||
38 | #include "lib/arg_helper.h" | ||
39 | |||
40 | #if defined(DEBUG) || defined(SIMULATOR) | ||
41 | #define logf(...) rb->debugf(__VA_ARGS__); rb->debugf("\n") | ||
42 | #elif defined(ROCKBOX_HAS_LOGF) | ||
43 | #define logf rb->logf | ||
44 | #else | ||
45 | #define logf(...) do { } while(0) | ||
46 | #endif | ||
47 | |||
48 | #define FIND_NODIRS 0x01 | ||
49 | #define FIND_ATTRIB 0x02 | ||
50 | #define FIND_WILDCARD 0x04 | ||
51 | #define FIND_EXT 0x08 | ||
52 | #define FIND_EXT_IN_LIST 0x10 | ||
53 | |||
54 | static struct fpp | ||
55 | { | ||
56 | char return_plugin[MAX_PATH]; | ||
57 | char start_dir[MAX_PATH]; | ||
58 | char file_ext[64]; | ||
59 | char title[64]; | ||
60 | int tree_attr; | ||
61 | int flags; | ||
62 | }fpp; | ||
63 | |||
64 | static int arg_callback(char argchar, const char **parameter, void *userdata) | ||
65 | { | ||
66 | struct fpp *pfp = userdata; | ||
67 | int ret; | ||
68 | long num; | ||
69 | const char* start = *parameter; | ||
70 | while (*parameter[0] > '/' && ispunct(*parameter[0])) (*parameter)++; | ||
71 | switch (tolower(argchar)) | ||
72 | { | ||
73 | case 'd' : | ||
74 | pfp->flags |= FIND_NODIRS; | ||
75 | logf ("Find no dirs"); | ||
76 | break; | ||
77 | case 'r' : /*return_plugin*/ | ||
78 | logf ("trying PLUGIN_DIR..."); | ||
79 | size_t l = rb->strlcpy(pfp->return_plugin, | ||
80 | PLUGIN_DIR, | ||
81 | sizeof(pfp->return_plugin)); | ||
82 | |||
83 | ret = string_parse(parameter, | ||
84 | pfp->return_plugin + l, | ||
85 | sizeof(pfp->return_plugin) - l); | ||
86 | |||
87 | if (ret && !rb->file_exists(pfp->return_plugin)) | ||
88 | { | ||
89 | logf("Failed"); | ||
90 | *parameter = start; | ||
91 | string_parse(parameter, pfp->return_plugin, | ||
92 | sizeof(pfp->return_plugin)); | ||
93 | } | ||
94 | |||
95 | if (ret) | ||
96 | { | ||
97 | logf ("Ret plugin: Val: %s\n", pfp->return_plugin); | ||
98 | logf("ate %d chars\n", ret); | ||
99 | } | ||
100 | break; | ||
101 | case 't' : /* title */ | ||
102 | ret = string_parse(parameter, pfp->title, sizeof(pfp->title)); | ||
103 | if (ret) | ||
104 | { | ||
105 | logf ("Title: Val: %s\n", pfp->title); | ||
106 | logf("ate %d chars\n", ret); | ||
107 | } | ||
108 | break; | ||
109 | case 's' : /* start directory */ | ||
110 | ret = string_parse(parameter, pfp->start_dir, sizeof(pfp->start_dir)); | ||
111 | if (ret) | ||
112 | { | ||
113 | if (!rb->dir_exists(pfp->start_dir)) | ||
114 | { | ||
115 | rb->strlcpy(pfp->start_dir, PATH_ROOTSTR, sizeof(pfp->start_dir)); | ||
116 | } | ||
117 | |||
118 | logf ("Start dir: Val: %s\n", pfp->start_dir); | ||
119 | logf("ate %d chars\n", ret); | ||
120 | } | ||
121 | break; | ||
122 | case 'f' : /* file extension */ | ||
123 | if (pfp->flags & FIND_EXT_IN_LIST) | ||
124 | { | ||
125 | rb->splash(HZ*5, "list extensions already active -f ignored"); | ||
126 | break; | ||
127 | } | ||
128 | ret = string_parse(parameter, pfp->file_ext, sizeof(pfp->file_ext)); | ||
129 | if (ret) | ||
130 | { | ||
131 | if (pfp->file_ext[1] == '*') | ||
132 | pfp->flags |= FIND_WILDCARD; | ||
133 | else | ||
134 | pfp->flags |= FIND_EXT; | ||
135 | logf ("Extension: Val: %s\n", pfp->file_ext); | ||
136 | logf("ate %d chars\n", ret); | ||
137 | } | ||
138 | break; | ||
139 | case 'l' : /* file extension list */ | ||
140 | if (pfp->flags & FIND_EXT) | ||
141 | { | ||
142 | rb->splash(HZ*5, "extension already active -l ignored"); | ||
143 | break; | ||
144 | } | ||
145 | ret = string_parse(parameter, pfp->file_ext, sizeof(pfp->file_ext)); | ||
146 | if (ret) | ||
147 | { | ||
148 | char *wr = pfp->file_ext; | ||
149 | char *rd = pfp->file_ext; | ||
150 | while (*rd != '\0') /* copy the extensions */ | ||
151 | { | ||
152 | if (*rd == ' ' || *rd == ',' || *rd == ';') | ||
153 | { | ||
154 | /* ignore spaces, commas, and semicolons */ | ||
155 | rd++; | ||
156 | continue; | ||
157 | } | ||
158 | *wr++ = *rd++; | ||
159 | } | ||
160 | *wr = '\0'; | ||
161 | pfp->flags |= FIND_EXT_IN_LIST; | ||
162 | logf ("Extension List: Val: %s\n", pfp->file_ext); | ||
163 | logf("ate %d chars\n", ret); | ||
164 | } | ||
165 | break; | ||
166 | case 'a' : /* tree attribute */ | ||
167 | ret = longnum_parse(parameter, &num, NULL); | ||
168 | if (ret) | ||
169 | { | ||
170 | pfp->tree_attr = (num)&FILE_ATTR_MASK; | ||
171 | pfp->flags |= FIND_ATTRIB; | ||
172 | logf ("Attrib: Val: 0x%x\n", (uint32_t)num); | ||
173 | logf("ate %d chars\n", ret); | ||
174 | } | ||
175 | break; | ||
176 | default : | ||
177 | rb->splashf(HZ, "Unknown switch '%c'",argchar); | ||
178 | logf("Unknown switch '%c'",argchar); | ||
179 | //return 0; | ||
180 | } | ||
181 | |||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | static bool cb_show_item(char *name, int attr, struct tree_context *tc) | ||
186 | { | ||
187 | static int dirlevel = -1; | ||
188 | if(attr & ATTR_DIRECTORY) | ||
189 | { | ||
190 | if (fpp.flags & FIND_NODIRS) | ||
191 | { | ||
192 | if (tc->dirlevel == dirlevel) | ||
193 | return false; | ||
194 | dirlevel = tc->dirlevel; | ||
195 | if (rb->strcasestr(tc->currdir, fpp.start_dir) == NULL) | ||
196 | { | ||
197 | tc->is_browsing = false; /* exit immediately */ | ||
198 | logf("exiting %d", tc->dirlevel); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return true; | ||
203 | } | ||
204 | if (fpp.flags & FIND_WILDCARD) | ||
205 | { | ||
206 | return true; | ||
207 | } | ||
208 | if ((fpp.flags & FIND_ATTRIB) && (fpp.tree_attr & attr) != 0) | ||
209 | { | ||
210 | return true; | ||
211 | } | ||
212 | if (fpp.flags & FIND_EXT) | ||
213 | { | ||
214 | const char *p = rb->strrchr(name, '.' ); | ||
215 | if (p != NULL && !rb->strcasecmp( p, fpp.file_ext)) | ||
216 | return true; | ||
217 | } | ||
218 | |||
219 | if (fpp.flags & FIND_EXT_IN_LIST) | ||
220 | { | ||
221 | const char *p = rb->strrchr(name, '.' ); | ||
222 | if (p != NULL && rb->strcasestr(fpp.file_ext, p) != NULL) | ||
223 | return true; | ||
224 | } | ||
225 | |||
226 | logf("Excluded: %s", name); | ||
227 | return false; | ||
228 | |||
229 | } | ||
230 | |||
231 | static int browse_file_dir(struct fpp *pfp) | ||
232 | { | ||
233 | char buf[MAX_PATH]; | ||
234 | struct browse_context browse = { | ||
235 | .dirfilter = SHOW_ALL, | ||
236 | .flags = BROWSE_SELECTONLY | BROWSE_DIRFILTER, | ||
237 | .title = pfp->title, | ||
238 | .icon = Icon_Playlist, | ||
239 | .buf = buf, | ||
240 | .bufsize = sizeof(buf), | ||
241 | .root = pfp->start_dir, | ||
242 | .callback_show_item = &cb_show_item, | ||
243 | }; | ||
244 | |||
245 | if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) | ||
246 | { | ||
247 | if (rb->file_exists(buf)) | ||
248 | { | ||
249 | logf("Loading %s", buf); | ||
250 | return rb->plugin_open(pfp->return_plugin, buf); | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | logf("Error opening %s", buf); | ||
255 | rb->splashf(HZ *2, "Error Opening %s", buf); | ||
256 | return PLUGIN_ERROR; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | return PLUGIN_OK; | ||
261 | } | ||
262 | |||
263 | enum plugin_status plugin_start(const void* parameter) | ||
264 | { | ||
265 | if (!parameter) | ||
266 | { | ||
267 | rb->splash(HZ *2, "No Args"); | ||
268 | return PLUGIN_ERROR; | ||
269 | } | ||
270 | |||
271 | argparse((const char*) parameter, -1, &fpp, &arg_callback); | ||
272 | |||
273 | if (fpp.title[0] == '\0') | ||
274 | { | ||
275 | if (rb->global_settings->talk_menu) | ||
276 | rb->talk_id(LANG_CHOOSE_FILE, true); | ||
277 | |||
278 | if ((fpp.flags & FIND_EXT) || (fpp.flags & FIND_EXT_IN_LIST)) | ||
279 | { | ||
280 | rb->snprintf(fpp.title, sizeof(fpp.title), | ||
281 | "%s (%s)", rb->str(LANG_CHOOSE_FILE), fpp.file_ext); | ||
282 | if (rb->global_settings->talk_menu) | ||
283 | rb->talk_spell(fpp.file_ext, true); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | rb->snprintf(fpp.title, sizeof(fpp.title), "%s", rb->str(LANG_CHOOSE_FILE)); | ||
288 | } | ||
289 | rb->talk_force_enqueue_next(); | ||
290 | } | ||
291 | if (fpp.start_dir[0] == '\0' || !rb->dir_exists(fpp.start_dir)) | ||
292 | rb->strcpy(fpp.start_dir, PATH_ROOTSTR); | ||
293 | |||
294 | return browse_file_dir(&fpp); | ||
295 | } | ||
diff --git a/apps/plugins/lua/rocklua.c b/apps/plugins/lua/rocklua.c index 3cf0fce945..650c4d6dae 100644 --- a/apps/plugins/lua/rocklua.c +++ b/apps/plugins/lua/rocklua.c | |||
@@ -241,6 +241,20 @@ static void display_traceback(const char *errstr) | |||
241 | rb->splash(10 * HZ, errstr); | 241 | rb->splash(10 * HZ, errstr); |
242 | #endif | 242 | #endif |
243 | } | 243 | } |
244 | |||
245 | int browse_scripts(void) | ||
246 | { | ||
247 | static char buf[MAX_PATH]; | ||
248 | const char *fname = rb->plugin_get_current_filename(); | ||
249 | /* strip plugin dir to save space in the param buffer */ | ||
250 | if (rb->strncmp(fname, PLUGIN_DIR, sizeof(PLUGIN_DIR) - 1) == 0) | ||
251 | fname += sizeof(PLUGIN_DIR) - 1; /* leave slash */ | ||
252 | /* -r return to this plugin, -f looking for lua files, | ||
253 | -s start in lua_scripts, -d lock to that directory */ | ||
254 | snprintf(buf, sizeof(buf), "-r'%s'-f'.lua'-s'%s'-d", | ||
255 | fname, PLUGIN_DEMOS_DIR"/lua_scripts/"); | ||
256 | return rb->plugin_open(VIEWERS_DIR "/file_picker.rock", buf); | ||
257 | } | ||
244 | /***************** Plugin Entry Point *****************/ | 258 | /***************** Plugin Entry Point *****************/ |
245 | enum plugin_status plugin_start(const void* parameter) | 259 | enum plugin_status plugin_start(const void* parameter) |
246 | { | 260 | { |
@@ -249,7 +263,10 @@ enum plugin_status plugin_start(const void* parameter) | |||
249 | if (parameter == NULL) | 263 | if (parameter == NULL) |
250 | { | 264 | { |
251 | if (!Ls) | 265 | if (!Ls) |
266 | { | ||
252 | rb->splash(HZ, "Play a .lua file!"); | 267 | rb->splash(HZ, "Play a .lua file!"); |
268 | return browse_scripts(); | ||
269 | } | ||
253 | } | 270 | } |
254 | else | 271 | else |
255 | { | 272 | { |