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/open_plugins.c | 823 | ||||
-rw-r--r-- | apps/plugins/plugins.make | 5 | ||||
-rw-r--r-- | apps/plugins/viewers.config | 2 |
5 files changed, 832 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 07bc4df847..d3093689f9 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -67,6 +67,7 @@ mosaique,demos mp3_encoder,apps mpegplayer,viewers nim,games +open_plugins,viewers oscilloscope,demos otp,apps pacbox,games diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 46a3c61537..408dc6bc67 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -137,6 +137,7 @@ chopper.c demystify.c jewels.c minesweeper.c +open_plugins.c oscilloscope.c pegbox.c periodic_table.c diff --git a/apps/plugins/open_plugins.c b/apps/plugins/open_plugins.c new file mode 100644 index 0000000000..f06a790d02 --- /dev/null +++ b/apps/plugins/open_plugins.c @@ -0,0 +1,823 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ / + * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) ( + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2020 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. + * + ****************************************************************************/ + +/* open_plugins.rock interfaces with the open_plugin core + * + * When opened directly it acts as a viewer for the plugin.dat file + * this allows you to edit the paths and parameters for + * core shortcuts as well as your added plugins + * + * If a plugin is supplied to the viewer it is added to the dat file + * + * If instead the plugin has previously been added then it is run + * with the parameters previously supplied + */ + +#include "plugin.h" +#include "lang_enum.h" +#include "../open_plugin.h" + +#define ROCK_EXT "rock" +#define OP_EXT "opx" + +#define OP_PLUGIN_RESTART (PLUGIN_GOTO_PLUGIN | 0x8000) + +#define MENU_ID_MAIN "0" +#define MENU_ID_EDIT "1" + +static int fd_dat; +static struct gui_synclist lists; +struct open_plugin_entry_t op_entry; +const off_t op_entry_sz = sizeof(struct open_plugin_entry_t); + +/* we only need the names for the first menu so don't bother reading paths yet */ +const off_t op_name_sz = OPEN_PLUGIN_NAMESZ + (op_entry.name - (char*)&op_entry); + +static uint32_t op_entry_add_path(const char *key, const char *plugin, const char *parameter); + +static bool _yesno_pop(const char* text) +{ + const char *lines[]={text}; + const struct text_message message={lines, 1}; + bool ret = (rb->gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES); + FOR_NB_SCREENS(i) + rb->screens[i]->clear_viewport(); + return ret; +} + +static size_t pathbasename(const char *name, const char **nameptr) +{ + const char *p = name; + const char *q = p; + const char *r = q; + + while (*(p = GOBBLE_PATH_SEPCH(p))) + { + q = p; + p = GOBBLE_PATH_COMP(++p); + r = p; + } + + if (r == name && p > name) + q = p, r = q--; /* root - return last slash */ + /* else path is an empty string */ + + *nameptr = q; + return r - q; +} + +static bool op_entry_read(int fd, int selected_item, off_t data_sz) +{ + rb->memset(&op_entry, 0, op_entry_sz); + op_entry.lang_id = -1; + return ((selected_item >= 0) && + (rb->lseek(fd, selected_item * op_entry_sz, SEEK_SET) >= 0) && + (rb->read(fd, &op_entry, data_sz) == data_sz)); +} + +static bool op_entry_read_name(int fd, int selected_item) +{ + return op_entry_read(fd, selected_item, op_name_sz); +} + +static void op_entry_export(int selection) +{ + int len; + int fd = -1; + char filename [MAX_PATH + 1]; + + if (!op_entry_read(fd_dat, selection, op_entry_sz)) + goto failure; + + rb->snprintf(filename, MAX_PATH, "%s/%s", PLUGIN_APPS_DIR, op_entry.name); + + if( !rb->kbd_input( filename, MAX_PATH, NULL ) ) + { + len = rb->strlen(filename); + if(len > 4 && filename[len] != PATH_SEPCH && + rb->strcasecmp(&((filename)[len-4]), "." OP_EXT) != 0) + { + rb->strcat(filename, "." OP_EXT); + } + + fd = rb->open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + + if (fd >= 0 && rb->write(fd, &op_entry, op_entry_sz) == op_entry_sz) + { + rb->close(fd); + rb->splashf( 1*HZ, "File Saved (%s)", filename ); + return; + } + rb->close(fd); + } + +failure: + rb->splashf( 2*HZ, "Save Failed (%s)", filename ); + +} + +static void op_entry_set_name(void) +{ + char tmp_buf[OPEN_PLUGIN_NAMESZ+1]; + rb->strlcpy(tmp_buf, op_entry.name, OPEN_PLUGIN_NAMESZ); + if (rb->kbd_input(tmp_buf, OPEN_PLUGIN_NAMESZ, NULL) >= 0) + rb->strlcpy(op_entry.name, tmp_buf, OPEN_PLUGIN_NAMESZ); +} + +static int op_entry_set_path(void) +{ + int ret = 0; + struct browse_context browse; + char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; + + if (op_entry.path[0] == '\0') + rb->strcpy(op_entry.path, PLUGIN_DIR"/"); + + rb->browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "", + Icon_Plugin, op_entry.path, NULL); + + browse.buf = tmp_buf; + browse.bufsize = OPEN_PLUGIN_BUFSZ; + + if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) + { + ret = rb->strlcpy(op_entry.path, tmp_buf, OPEN_PLUGIN_BUFSZ); + if (ret > OPEN_PLUGIN_BUFSZ) + ret = 0; + } + return ret; +} + +static int op_entry_set_param_path(void) +{ + int ret = 0; + struct browse_context browse; + char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; + + if (op_entry.param[0] == '\0') + rb->strcpy(tmp_buf, "/"); + else + rb->strcpy(tmp_buf, op_entry.param); + + rb->browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "", + Icon_Plugin, tmp_buf, NULL); + + browse.buf = tmp_buf; + browse.bufsize = OPEN_PLUGIN_BUFSZ; + + if (rb->rockbox_browse(&browse) == GO_TO_PREVIOUS) + { + ret = rb->strlcpy(op_entry.param, tmp_buf, OPEN_PLUGIN_BUFSZ); + if (ret > OPEN_PLUGIN_BUFSZ) + ret = 0; + } + return ret; +} + +static void op_entry_set_param(void) +{ + if (_yesno_pop(ID2P(LANG_BROWSE))) + op_entry_set_param_path(); + + char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; + rb->strlcpy(tmp_buf, op_entry.param, OPEN_PLUGIN_BUFSZ); + if (rb->kbd_input(tmp_buf, OPEN_PLUGIN_BUFSZ, NULL) >= 0) + rb->strlcpy(op_entry.param, tmp_buf, OPEN_PLUGIN_BUFSZ); +} + +static int op_et_exclude_hash(struct open_plugin_entry_t *op_entry, int item, void *data) +{ + (void)item; + + if (op_entry->hash == 0 || op_entry->name[0] == '\0') + return 0; + + if (data) + { + uint32_t *hash = data; + if (op_entry->hash != *hash) + return 1; + } + return 0; +} + +static int op_et_exclude_builtin(struct open_plugin_entry_t *op_entry, int item, void *data) +{ + (void)item; + (void)data; + + if (op_entry->lang_id >= 0) + return 0; + else if(op_entry->hash == 0 || op_entry->name[0] == '\0') + return 0; + + return 1; +} + +static int op_et_exclude_user(struct open_plugin_entry_t *op_entry, int item, void *data) +{ + (void)item; + (void)data; + + if (op_entry->lang_id < 0) + return 0; + else if (op_entry->hash == 0 || op_entry->name[0] == '\0') + return 0; + + return 1; +} + +static int op_entry_transfer(int fd, int fd_tmp, + int(*compfn)(struct open_plugin_entry_t*, int, void*), + void *data) +{ + int entries = -1; + if (fd_tmp && fd && rb->lseek(fd, 0, SEEK_SET) == 0) + { + entries = 0; + while (rb->read(fd, &op_entry, op_entry_sz) == op_entry_sz) + { + if (compfn && compfn(&op_entry, entries, data) > 0) + { + rb->write(fd_tmp, &op_entry, op_entry_sz); + entries++; + } + } + } + return entries + 1; +} + +static uint32_t op_entry_add_path(const char *key, const char *plugin, const char *parameter) +{ + int len; + uint32_t hash; + char *pos = "";; + int fd_tmp = -1; + + if (key) + { + open_plugin_get_hash(key, &hash); + op_entry.hash = hash; + } + else if (op_entry.lang_id < 0 && plugin) + { + /* need to keep the old hash so we can remove the old entry */ + hash = op_entry.hash; + open_plugin_get_hash(plugin, &op_entry.hash); + } + else + hash = op_entry.hash; + + if (plugin) + { + /* name */ + if (pathbasename(plugin, (const char **)&pos) == 0) + pos = "\0"; + if (op_entry.name[0] == '\0' || op_entry.lang_id >= 0) + rb->strlcpy(op_entry.name, pos, OPEN_PLUGIN_NAMESZ); + + len = rb->strlen(pos); + if(len > 5 && rb->strcasecmp(&(pos[len-5]), "." ROCK_EXT) == 0) + { + fd_tmp = rb->open(OPEN_PLUGIN_DAT ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd_tmp < 0) + return 0; + + /* path */ + if (plugin != op_entry.path) + rb->strlcpy(op_entry.path, plugin, OPEN_PLUGIN_BUFSZ); + + if(parameter) + { + if (parameter[0] == '\0' && + _yesno_pop(ID2P(LANG_PARAMETER))) + { + op_entry_set_param(); + } + else + rb->strlcpy(op_entry.param, parameter, OPEN_PLUGIN_BUFSZ); + } + + rb->write(fd_tmp, &op_entry, op_entry_sz); /* add new entry first */ + } + else + { + if (op_entry.lang_id != LANG_SHORTCUTS) + rb->splashf(HZ / 2, rb->str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos); + return 0; + } + } + + if (op_entry_transfer(fd_dat, fd_tmp, op_et_exclude_hash, &hash) > 0) + { + rb->close(fd_tmp); + rb->close(fd_dat); + rb->remove(OPEN_PLUGIN_DAT); + rb->rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); + } + else + { + rb->close(fd_tmp); + rb->remove(OPEN_PLUGIN_DAT ".tmp"); + hash = 0; + } + + return hash; +} + +void op_entry_browse_add(int selection) +{ + char* key; + op_entry_read(fd_dat, selection, op_entry_sz); + if (op_entry_set_path() > 0) + { + if (op_entry.lang_id >= 0) + key = rb->str(op_entry.lang_id); + else + key = op_entry.path; + + op_entry_add_path(key, op_entry.path, NULL); + } +} + +static void op_entry_remove(int selection) +{ + + int entries = rb->lseek(fd_dat, 0, SEEK_END) / op_entry_sz; + int32_t hash = 0; + int lang_id = -1; + + if (entries > 0 && _yesno_pop(ID2P(LANG_REMOVE))) + { + op_entry_read(fd_dat, selection, op_entry_sz); + if (rb->lseek(fd_dat, selection * op_entry_sz, SEEK_SET) >= 0) + { + if (op_entry.lang_id >= 0) + { + lang_id = op_entry.lang_id; + hash = op_entry.hash; + } + rb->memset(&op_entry, 0, op_entry_sz); + op_entry.lang_id = lang_id; + op_entry.hash = hash; + rb->write(fd_dat, &op_entry, op_entry_sz); + } + } +} + +static void op_entry_remove_empty(void) +{ + bool resave = false; + if (fd_dat && rb->lseek(fd_dat, 0, SEEK_SET) == 0) + { + while (resave == false && + rb->read(fd_dat, &op_entry, op_entry_sz) == op_entry_sz) + { + if (op_entry.hash == 0) + resave = true; + } + } + + if (resave) + { + int fd_tmp = rb->open(OPEN_PLUGIN_DAT ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd_tmp < 0) + return; + + if ((op_entry_transfer(fd_dat, fd_tmp, &op_et_exclude_builtin, NULL) + + op_entry_transfer(fd_dat, fd_tmp, &op_et_exclude_user, NULL)) > 0) + { + rb->close(fd_tmp); + rb->close(fd_dat); + rb->remove(OPEN_PLUGIN_DAT); + rb->rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); + } + else + { + rb->close(fd_tmp); + rb->remove(OPEN_PLUGIN_DAT ".tmp"); + } + } + +} + +static int op_entry_run(void) +{ + int ret = PLUGIN_ERROR; + char* path; + char* param; + if (op_entry.hash != 0 && op_entry.path[0] != '\0') + { + rb->splash(1, ID2P(LANG_OPEN_PLUGIN)); + path = op_entry.path; + param = op_entry.param; + if (param[0] == '\0') + param = NULL; + + ret = rb->plugin_open(path, param); + } + return ret; +} + +static const char* list_get_name_cb(int selected_item, void* data, + char* buf, size_t buf_len) +{ + /*TODO memoize names so we don't keep reading the disk when not necessary */ + if (data == &MENU_ID_MAIN) + { + if (op_entry_read_name(fd_dat, selected_item)) + { + if (op_entry.lang_id >= 0) + rb->snprintf(buf, buf_len, "%s [%s] ", + rb->str(op_entry.lang_id), op_entry.name); + else if (rb->strlcpy(buf, op_entry.name, buf_len) >= buf_len) + rb->strcpy(&buf[buf_len-10], " ..."); + } + else + return "?"; + } + else /* op_entry should already be loaded */ + { + switch(selected_item) + { + case 0: + return ID2P(LANG_NAME); + case 1: + if (op_entry.lang_id >= 0) + rb->snprintf(buf, buf_len, "%s [%s] ", + rb->str(op_entry.lang_id), op_entry.name); + else if (rb->strlcpy(buf, op_entry.name, buf_len) >= buf_len) + rb->strcpy(&buf[buf_len-10], " ..."); + break; + case 2: + return ID2P(LANG_DISPLAY_FULL_PATH); + case 3: + if (rb->strlcpy(buf, op_entry.path, buf_len) >= buf_len) + rb->strcpy(&buf[buf_len-10], " ..."); + break; + case 4: + return ID2P(LANG_PARAMETER); + case 5: + if (op_entry.param[0] == '\0') + return "[NULL]"; + else if (rb->strlcpy(buf, op_entry.param, buf_len) >= buf_len) + rb->strcpy(&buf[buf_len-10], " ..."); + break; + case 6: + return ""; + case 7: + return ID2P(LANG_BACK); + default: + return "?"; + } + } + + return buf; +} + +static int list_voice_cb(int list_index, void* data) +{ + if (data == &MENU_ID_MAIN) + { + if (op_entry_read_name(fd_dat, list_index)) + { + if (op_entry.lang_id >= 0) + { + rb->talk_id(op_entry.lang_id, false); + rb->talk_id(VOICE_PAUSE, true); + rb->talk_force_enqueue_next(); + } + return rb->talk_spell(op_entry.name, false); + } + } + else + { + switch(list_index) + { + case 0: + rb->talk_id(LANG_NAME, false); + rb->talk_id(VOICE_PAUSE, true); + + if (op_entry.lang_id >= 0) + { + rb->talk_id(op_entry.lang_id, true); + rb->talk_id(VOICE_PAUSE, true); + rb->talk_force_enqueue_next(); + } + return rb->talk_spell(op_entry.name, false); + case 2: + return rb->talk_id(LANG_DISPLAY_FULL_PATH, false); + case 4: + return rb->talk_id(LANG_PARAMETER, false); + case 6: + return rb->talk_id(LANG_BACK, false); + default: + return 0; + } + } + + return 0; +} + +static void synclist_set(char* menu_id, int selection, int items, int sel_size) +{ + if (selection < 0) + selection = 0; + + rb->gui_synclist_init(&lists,list_get_name_cb, + menu_id, false, sel_size, NULL); + + rb->gui_synclist_set_icon_callback(&lists,NULL); + rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); + rb->gui_synclist_set_nb_items(&lists,items); + rb->gui_synclist_limit_scroll(&lists,true); + rb->gui_synclist_select_item(&lists, selection); + list_voice_cb(selection, menu_id); +} + +static int context_menu_cb(int action, + const struct menu_item_ex *this_item, + struct gui_synclist *this_list) +{ + (void)this_item; + + int selection = rb->gui_synclist_get_sel_pos(this_list); + + if(action == ACTION_ENTER_MENUITEM) + { + if (selection == 0 && + op_entry.lang_id >= 0 && op_entry.lang_id != LANG_OPEN_PLUGIN) + { + rb->gui_synclist_set_title(this_list, + rb->str(op_entry.lang_id), 0); + } + } + else if ((action == ACTION_STD_OK)) + { + /*Run, Edit, Remove, Export, Blank, Import, Add, Back*/ + switch(selection) + { + case 0:case 1:case 2:case 3:case 5: + return ACTION_STD_OK; + case 4: /*blank*/ + break; + default: + return ACTION_STD_CANCEL; + } + rb->gui_synclist_draw(this_list); /* redraw */ + return 0; + } + + return action; +} + +static void edit_menu(int selection) +{ + int selected_item; + bool exit = false; + int action = 0; + + if (!op_entry_read(fd_dat, selection, op_entry_sz)) + return; + + uint32_t crc = rb->crc_32(&op_entry, op_entry_sz, 0xffffffff); + + synclist_set(MENU_ID_EDIT, 2, 8, 2); + rb->gui_synclist_draw(&lists); + + while (!exit) + { + action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); + + if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + continue; + selected_item = rb->gui_synclist_get_sel_pos(&lists); + switch (action) + { + case ACTION_STD_OK: + if (selected_item == 0) + op_entry_set_name(); + else if (selected_item == 2) + op_entry_set_path(); + else if (selected_item == 4) + op_entry_set_param(); + else + exit = true; + + rb->gui_synclist_draw(&lists); + break; + case ACTION_STD_CANCEL: + exit = true; + break; + } + } + + if (crc != rb->crc_32(&op_entry, op_entry_sz, 0xffffffff) && + _yesno_pop(ID2P(LANG_SAVE)) == true) + { + char *param = op_entry.param; + if (param[0] == '\0') + param = NULL; + + op_entry_add_path(NULL, op_entry.path, param); + fd_dat = rb->open(OPEN_PLUGIN_DAT, O_RDWR, 0666); + } +} + +static int context_menu(int selection) +{ + int selected_item; + if (op_entry_read(fd_dat, selection, op_entry_sz)) + { + MENUITEM_STRINGLIST(menu, op_entry.name, context_menu_cb, + ID2P(LANG_RUN), ID2P(LANG_EDIT), ID2P(LANG_REMOVE), ID2P(LANG_EXPORT), + ID2P(VOICE_BLANK), ID2P(LANG_ADD), ID2P(LANG_BACK)); + + selected_item = rb->do_menu(&menu, 0, NULL, false); + switch (selected_item) + { + case 0: /*run*/ + return PLUGIN_GOTO_PLUGIN; + case 1: /*edit*/ + edit_menu(selection); + break; + case 2: /*remove*/ + op_entry_remove(selection); + break; + case 3: /*export*/ + op_entry_export(selection); + break; + case 4: /*blank*/ + break; + case 5: /*add*/ + op_entry_browse_add(-1); + rb->plugin_open(rb->plugin_get_current_filename(), "\0"); + return OP_PLUGIN_RESTART; + default: + break; + + } + return PLUGIN_OK; + } + return PLUGIN_ERROR; +} + +enum plugin_status plugin_start(const void* parameter) +{ + int ret = PLUGIN_OK; + uint32_t hash = 0; + int item = -1; + int selection = -1; + int action; + int items; + int len; + int fd_opx; + off_t filesize; + char *path; + bool exit = false; + + const int creat_flags = O_RDWR | O_CREAT; + fd_dat = rb->open(OPEN_PLUGIN_DAT, creat_flags, 0666); + if (!fd_dat) + exit = true; + + items = rb->lseek(fd_dat, 0, SEEK_END) / op_entry_sz; + if (items == 0 && !parameter) + { + rb->plugin_open(rb->plugin_get_current_filename(), NULL); + rb->close(fd_dat); + return PLUGIN_GOTO_PLUGIN; + } + + if (parameter) + { + path = (char*)parameter; + len = rb->strlen(path); + if(len > 4 && rb->strcasecmp(&((path)[len-4]), "." OP_EXT) == 0) + { + fd_opx = rb->open(path, O_RDONLY, 0666); + if (fd_opx) + { + filesize = rb->filesize(fd_opx); + if (filesize == op_entry_sz) + { + + if (op_entry_read(fd_opx, 0, op_entry_sz)) + { + exit = true; + ret = op_entry_run(); + } + else + rb->splashf(HZ, rb->str(LANG_READ_FAILED), path); + } + else if (filesize != 0) + rb->splashf(2 * HZ, rb->str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), path); + + rb->close(fd_opx); + } + } + else + { + open_plugin_get_hash(parameter, &hash); + rb->lseek(fd_dat, 0, SEEK_SET); + while (rb->read(fd_dat, &op_entry, op_entry_sz) == op_entry_sz) + { + item++; + if (op_entry.hash == hash) + { + selection = item; + break; + } + } + + if (selection >= 0) + { + if (op_entry_read(fd_dat, selection, op_entry_sz)) + { + if (op_entry_run() == PLUGIN_GOTO_PLUGIN) + return PLUGIN_GOTO_PLUGIN; + } + } + else + { + op_entry_read(fd_dat, selection, op_entry_sz); + op_entry_add_path(parameter, parameter, "\0"); + selection = 0; + items++; + fd_dat = rb->open(OPEN_PLUGIN_DAT, creat_flags, 0666); + if (!fd_dat) + exit = true; + } + }/* OP_EXT */ + + } + + if (!exit) + { + synclist_set(MENU_ID_MAIN, selection, items, 1); + rb->gui_synclist_draw(&lists); + + while (!exit) + { + action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); + + if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) + continue; + selection = rb->gui_synclist_get_sel_pos(&lists); + switch (action) + { + case ACTION_STD_CONTEXT: + ret = context_menu(selection); + if (ret == OP_PLUGIN_RESTART) + { + ret = PLUGIN_GOTO_PLUGIN; + exit = true; + break; + } + else if (ret != PLUGIN_GOTO_PLUGIN) + { + synclist_set(MENU_ID_MAIN, selection, items, 1); + rb->gui_synclist_draw(&lists); + break; + } + case ACTION_STD_OK: + if (op_entry_read(fd_dat, selection, op_entry_sz)) + { + ret = op_entry_run(); + exit = true; + } + break; + case ACTION_STD_CANCEL: + { + selection = -2; + exit = true; + break; + } + } + } + op_entry_remove_empty(); + } + rb->close(fd_dat); + if (ret != PLUGIN_OK) + return ret; + else + return PLUGIN_OK; +} diff --git a/apps/plugins/plugins.make b/apps/plugins/plugins.make index d395c00e82..71eaeb52c0 100644 --- a/apps/plugins/plugins.make +++ b/apps/plugins/plugins.make @@ -86,6 +86,11 @@ $(OVERLAYREF_LDS): $(PLUGIN_LDS) $(BUILDDIR)/credits.raw credits.raw: $(DOCSDIR)/CREDITS $(call PRINTS,Create credits.raw)perl $(APPSDIR)/plugins/credits.pl < $< > $(BUILDDIR)/$(@F) +$(BUILDDIR)/apps/plugins/open_plugins.opx: + $(call PRINTS,MK open_plugins.opx) touch $< $(BUILDDIR)/apps/plugins/open_plugins.opx + +$(BUILDDIR)/apps/plugins/open_plugins.rock: $(BUILDDIR)/apps/plugins/open_plugins.opx + # special dependencies $(BUILDDIR)/apps/plugins/wav2wv.rock: $(RBCODEC_BLD)/codecs/libwavpack.a $(PLUGIN_LIBS) diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 84f096a409..2bf052bb20 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -77,6 +77,8 @@ mpv,viewers/mpegplayer,4 m2v,viewers/mpegplayer,4 iriver,viewers/iriver_flash,3 tap,viewers/zxbox,12 +opx,viewers/open_plugins,- +rock,viewers/open_plugins,- sna,viewers/zxbox,12 tzx,viewers/zxbox,12 z80,viewers/zxbox,12 |