From 101693fd3047fb64e766580e80635a424fa25c4d Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Tue, 15 Nov 2011 13:22:02 +0000 Subject: FS#12251 - User shortcuts in the main menu. Custom shortcuts which give the user fast access to regularly used files/folders/settings/whatever. Thanks to Alexander Levin for the manual part of the patch git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30990 a1c6a512-1295-4272-9138-f99709370657 --- apps/SOURCES | 1 + apps/debug_menu.c | 31 +++- apps/debug_menu.h | 1 + apps/lang/english.lang | 14 ++ apps/main.c | 3 + apps/menu.c | 38 +++-- apps/menu.h | 3 + apps/misc.h | 3 +- apps/onplay.c | 19 ++- apps/onplay.h | 2 +- apps/root_menu.c | 6 + apps/root_menu.h | 1 + apps/shortcuts.c | 421 ++++++++++++++++++++++++++++++++++++++++++++++ apps/shortcuts.h | 43 +++++ apps/tree.c | 5 +- apps/tree.h | 2 + manual/main_menu/main.tex | 57 +++++++ 17 files changed, 628 insertions(+), 22 deletions(-) create mode 100644 apps/shortcuts.c create mode 100644 apps/shortcuts.h diff --git a/apps/SOURCES b/apps/SOURCES index 0734d3475a..7ef81a10ee 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -52,6 +52,7 @@ root_menu.c screens.c settings.c settings_list.c +shortcuts.c status.c cuesheet.c talk.c diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 442bc8b162..809644b3d2 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -25,6 +25,7 @@ #include #include #include "lcd.h" +#include "lang.h" #include "menu.h" #include "debug_menu.h" #include "kernel.h" @@ -45,6 +46,7 @@ #include "screens.h" #include "misc.h" #include "splash.h" +#include "shortcuts.h" #include "dircache.h" #include "viewport.h" #ifdef HAVE_TAGCACHE @@ -2120,15 +2122,23 @@ static const struct the_menu_item menuitems[] = { }; static int menu_action_callback(int btn, struct gui_synclist *lists) { + int selection = gui_synclist_get_sel_pos(lists); if (btn == ACTION_STD_OK) { FOR_NB_SCREENS(i) viewportmanager_theme_enable(i, false, NULL); - menuitems[gui_synclist_get_sel_pos(lists)].function(); + menuitems[selection].function(); btn = ACTION_REDRAW; FOR_NB_SCREENS(i) viewportmanager_theme_undo(i, false); } + else if (btn == ACTION_STD_CONTEXT) + { + MENUITEM_STRINGLIST(menu_items, "Debug Menu", NULL, ID2P(LANG_ADD_TO_FAVES)); + if (do_menu(&menu_items, NULL, NULL, false) == 0) + shortcuts_add(SHORTCUT_DEBUGITEM, menuitems[selection].desc); + return ACTION_STD_CANCEL; + } return btn; } @@ -2148,3 +2158,22 @@ bool debug_menu(void) info.get_name = dbg_menu_getname; return simplelist_show_list(&info); } + +bool run_debug_screen(char* screen) +{ + unsigned i; + for (i=0; i + + id: LANG_SHORTCUTS + desc: Title in the shortcuts menu + user: core + + *: "Shortcuts" + + + *: "Shortcuts" + + + *: "Shortcuts" + + diff --git a/apps/main.c b/apps/main.c index c2dfc1a435..38de780c8d 100644 --- a/apps/main.c +++ b/apps/main.c @@ -79,6 +79,7 @@ #if (CONFIG_PLATFORM & PLATFORM_ANDROID) #include "notification.h" #endif +#include "shortcuts.h" #ifdef IPOD_ACCESSORY_PROTOCOL #include "iap.h" @@ -387,6 +388,7 @@ static void init(void) filetype_init(); playlist_init(); theme_init_buffer(); + shortcuts_init(); #if CONFIG_CODEC != SWCODEC mp3_init( global_settings.volume, @@ -667,6 +669,7 @@ static void init(void) filetype_init(); scrobbler_init(); theme_init_buffer(); + shortcuts_init(); #if CONFIG_CODEC != SWCODEC /* No buffer allocation (see buffer.c) may take place after the call to diff --git a/apps/menu.c b/apps/menu.c index b4be83fc26..a1e32f4625 100644 --- a/apps/menu.c +++ b/apps/menu.c @@ -52,6 +52,7 @@ #include "audio.h" #include "viewport.h" #include "quickscreen.h" +#include "shortcuts.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" @@ -280,19 +281,10 @@ static int talk_menu_item(int selected_item, void *data) return 0; } -void do_setting_from_menu(const struct menu_item_ex *temp, - struct viewport parent[NB_SCREENS]) +void do_setting_screen(const struct settings_list *setting, const char * title, + struct viewport parent[NB_SCREENS]) { - int setting_id; - const struct settings_list *setting = - find_setting(temp->variable, &setting_id); - char *title; char padded_title[MAX_PATH]; - if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT) - title = temp->callback_and_desc->desc; - else - title = ID2P(setting->lang_id); - /* Pad the title string by repeating it. This is needed so the scroll settings title can actually be used to test the setting */ @@ -317,7 +309,22 @@ void do_setting_from_menu(const struct menu_item_ex *temp, } option_screen((struct settings_list *)setting, parent, - setting->flags&F_TEMPVAR, title); + setting->flags&F_TEMPVAR, (char*)title); +} + + +void do_setting_from_menu(const struct menu_item_ex *temp, + struct viewport parent[NB_SCREENS]) +{ + char *title; + int setting_id; + const struct settings_list *setting = + find_setting(temp->variable, &setting_id); + if (temp && ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)) + title = temp->callback_and_desc->desc; + else + title = ID2P(setting->lang_id); + do_setting_screen(setting, title, parent); } /* display a menu */ @@ -451,7 +458,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, ID2P(LANG_TOP_QS_ITEM), ID2P(LANG_LEFT_QS_ITEM), ID2P(LANG_BOTTOM_QS_ITEM), - ID2P(LANG_RIGHT_QS_ITEM)); + ID2P(LANG_RIGHT_QS_ITEM), + ID2P(LANG_ADD_TO_FAVES)); #endif MENUITEM_STRINGLIST(notquickscreen_able_option, ID2P(LANG_ONPLAY_MENU_TITLE), NULL, @@ -486,6 +494,10 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected, case 4: /* set as right QS item */ set_as_qs_item(setting, QUICKSCREEN_RIGHT); break; + case 5: /* Add to faves. Same limitation on which can be + added to the shortcuts menu as the quickscreen */ + shortcuts_add(SHORTCUT_SETTING, (void*)setting); + break; #endif } /* swicth(do_menu()) */ redraw_lists = true; diff --git a/apps/menu.h b/apps/menu.h index 2251de243c..ee2d9e7f40 100644 --- a/apps/menu.h +++ b/apps/menu.h @@ -26,6 +26,7 @@ #include "icon.h" #include "icons.h" #include "root_menu.h" /* needed for MENU_* return codes */ +#include "settings_list.h" enum menu_item_type { @@ -103,6 +104,8 @@ typedef int (*menu_callback_type)(int action, const struct menu_item_ex *this_item); void do_setting_from_menu(const struct menu_item_ex *temp, struct viewport parent[NB_SCREENS]); +void do_setting_screen(const struct settings_list *setting, const char * title, + struct viewport parent[NB_SCREENS]); /* int do_menu(const struct menu_item_ex *menu, int *start_selected) diff --git a/apps/misc.h b/apps/misc.h index bfe6e5b449..4647898889 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -119,7 +119,8 @@ enum current_activity { ACTIVITY_CONTEXTMENU, ACTIVITY_SYSTEMSCREEN, ACTIVITY_TIMEDATESCREEN, - ACTIVITY_BOOKMARKSLIST + ACTIVITY_BOOKMARKSLIST, + ACTIVITY_SHORTCUTSMENU }; #if CONFIG_CODEC == SWCODEC diff --git a/apps/onplay.c b/apps/onplay.c index aab023c846..629de93886 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -63,6 +63,7 @@ #include "pitchscreen.h" #include "viewport.h" #include "filefuncs.h" +#include "shortcuts.h" static int context; static char* selected_file = NULL; @@ -382,10 +383,13 @@ static int treeplaylist_callback(int action, return action; } -void onplay_show_playlist_menu(char* track_name) +void onplay_show_playlist_menu(char* path) { - selected_file = track_name; - selected_file_attr = FILE_ATTR_AUDIO; + selected_file = path; + if (dir_exists(path)) + selected_file_attr = ATTR_DIRECTORY; + else + selected_file_attr = filetype_get_attr(path); do_menu(&tree_playlist_menu, NULL, NULL, false); } @@ -1032,8 +1036,13 @@ MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH), MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES), onplay_load_plugin, (void *)"properties", clipboard_callback, Icon_NOICON); -MENUITEM_FUNCTION(add_to_faves_item, MENU_FUNC_USEPARAM, ID2P(LANG_ADD_TO_FAVES), - onplay_load_plugin, (void *)"shortcuts_append", +static bool onplay_add_to_shortcuts(void) +{ + shortcuts_add(SHORTCUT_BROWSER, selected_file); + return false; +} +MENUITEM_FUNCTION(add_to_faves_item, 0, ID2P(LANG_ADD_TO_FAVES), + onplay_add_to_shortcuts, NULL, clipboard_callback, Icon_NOICON); #if LCD_DEPTH > 1 diff --git a/apps/onplay.h b/apps/onplay.h index 921303cf57..d24bf567b1 100644 --- a/apps/onplay.h +++ b/apps/onplay.h @@ -50,6 +50,6 @@ enum hotkey_action { /* needed for the playlist viewer.. eventually clean this up */ void onplay_show_playlist_cat_menu(char* track_name); -void onplay_show_playlist_menu(char* track_name); +void onplay_show_playlist_menu(char* path); #endif diff --git a/apps/root_menu.c b/apps/root_menu.c index 1e9924fb44..e78c02759b 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -37,6 +37,7 @@ #include "power.h" #include "talk.h" #include "audio.h" +#include "shortcuts.h" #ifdef HAVE_HOTSWAP #include "storage.h" @@ -415,12 +416,16 @@ static const struct root_items items[] = { &playlist_options }, [GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options }, [GO_TO_SYSTEM_SCREEN] = { miscscrn, &info_menu, &system_menu }, + [GO_TO_SHORTCUTMENU] = { do_shortcut_menu, NULL, NULL }, }; static const int nb_items = sizeof(items)/sizeof(*items); static int item_callback(int action, const struct menu_item_ex *this_item) ; +MENUITEM_RETURNVALUE(shortcut_menu, ID2P(LANG_SHORTCUTS), GO_TO_SHORTCUTMENU, + NULL, Icon_Bookmark); + MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER, NULL, Icon_file_view_menu); #ifdef HAVE_TAGCACHE @@ -492,6 +497,7 @@ MAKE_MENU(root_menu_, ID2P(LANG_ROCKBOX_TITLE), #if CONFIG_KEYPAD == PLAYER_PAD ,&do_shutdown_item #endif + ,&shortcut_menu ); static int item_callback(int action, const struct menu_item_ex *this_item) diff --git a/apps/root_menu.h b/apps/root_menu.h index 2ffdcedda1..8d11d9b338 100644 --- a/apps/root_menu.h +++ b/apps/root_menu.h @@ -58,6 +58,7 @@ enum { GO_TO_PLAYLISTS_SCREEN, GO_TO_PLAYLIST_VIEWER, GO_TO_SYSTEM_SCREEN, + GO_TO_SHORTCUTMENU }; extern const struct menu_item_ex root_menu_; diff --git a/apps/shortcuts.c b/apps/shortcuts.c new file mode 100644 index 0000000000..3992068807 --- /dev/null +++ b/apps/shortcuts.c @@ -0,0 +1,421 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Jonathan Gordon + * + * 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. + * + ****************************************************************************/ + +#include +#include +#include "config.h" +#include "system.h" +#include "action.h" +#include "ata_idle_notify.h" +#include "debug_menu.h" +#include "core_alloc.h" +#include "list.h" +#include "settings.h" +#include "settings_list.h" +#include "lang.h" +#include "menu.h" +#include "misc.h" +#include "tree.h" +#include "splash.h" +#include "filefuncs.h" +#include "filetypes.h" +#include "shortcuts.h" +#include "onplay.h" + + + +#define MAX_SHORTCUT_NAME 32 +#define SHORTCUTS_FILENAME ROCKBOX_DIR "/shortcuts.txt" +char *type_strings[SHORTCUT_TYPE_COUNT] = { + [SHORTCUT_SETTING] = "setting", + [SHORTCUT_FILE] = "file", + [SHORTCUT_DEBUGITEM] = "debug", + [SHORTCUT_BROWSER] = "browse", + [SHORTCUT_PLAYLISTMENU] = "playlist menu", + [SHORTCUT_SEPARATOR] = "separator", +}; + + +struct shortcut { + enum shortcut_type type; + char name[MAX_SHORTCUT_NAME]; + int icon; + union { + char path[MAX_PATH]; + const struct settings_list *setting; + } u; +}; +#define SHORTCUTS_PER_HANDLE 32 +struct shortcut_handle { + struct shortcut shortcuts[SHORTCUTS_PER_HANDLE]; + int next_handle; +}; +static int first_handle = 0; +static int shortcut_count = 0; + +static void reset_shortcuts(void) +{ + int current_handle = first_handle; + struct shortcut_handle *h = NULL; + while (current_handle > 0) + { + int next; + h = core_get_data(current_handle); + next = h->next_handle; + core_free(current_handle); + current_handle = next; + } + first_handle = 0; + shortcut_count = 0; +} + +static struct shortcut* get_shortcut(int index) +{ + int handle_count, handle_index; + int current_handle = first_handle; + struct shortcut_handle *h = NULL; + + if (first_handle == 0) + { + first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle)); + if (first_handle <= 0) + return NULL; + h = core_get_data(first_handle); + h->next_handle = 0; + current_handle = first_handle; + } + + handle_count = index/SHORTCUTS_PER_HANDLE + 1; + handle_index = index%SHORTCUTS_PER_HANDLE; + do { + h = core_get_data(current_handle); + current_handle = h->next_handle; + handle_count--; + } while (handle_count > 0 && current_handle > 0); + if (handle_count > 0 && handle_index == 0) + { + char buf[32]; + snprintf(buf, sizeof buf, "shortcuts_%d", index/SHORTCUTS_PER_HANDLE); + h->next_handle = core_alloc(buf, sizeof(struct shortcut_handle)); + if (h->next_handle <= 0) + return NULL; + h = core_get_data(h->next_handle); + h->next_handle = 0; + } + return &h->shortcuts[handle_index]; +} + +bool verify_shortcut(struct shortcut* sc) +{ + switch (sc->type) + { + case SHORTCUT_UNDEFINED: + return false; + case SHORTCUT_BROWSER: + case SHORTCUT_FILE: + case SHORTCUT_PLAYLISTMENU: + if (sc->u.path[0] == '\0') + return false; + break; + case SHORTCUT_SETTING: + return sc->u.setting != NULL; + case SHORTCUT_DEBUGITEM: + case SHORTCUT_SEPARATOR: + default: + break; + } + return true; +} + +static void init_shortcut(struct shortcut* sc) +{ + sc->type = SHORTCUT_UNDEFINED; + sc->name[0] = '\0'; + sc->u.path[0] = '\0'; + sc->icon = Icon_NOICON; +} +static int first_idx_to_writeback = -1; +void shortcuts_ata_idle_callback(void* data) +{ + (void)data; + int fd; + char buf[MAX_PATH]; + int current_idx = first_idx_to_writeback; + if (first_idx_to_writeback < 0) + return; + fd = open(SHORTCUTS_FILENAME, O_APPEND|O_RDWR|O_CREAT, 0644); + if (fd < 0) + return; + while (current_idx < shortcut_count) + { + struct shortcut* sc = get_shortcut(current_idx++); + char *type; + int len; + if (!sc) + break; + type = type_strings[sc->type]; + len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type); + write(fd, buf, len); + if (sc->type == SHORTCUT_SETTING) + write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name)); + else + write(fd, sc->u.path, strlen(sc->u.path)); + write(fd, "\n\n", 2); + } + close(fd); + if (first_idx_to_writeback == 0) + { + /* reload all shortcuts because we appended to the shortcuts file which + * has not been read yet. + */ + reset_shortcuts(); + shortcuts_init(); + } + first_idx_to_writeback = -1; +} +void shortcuts_add(enum shortcut_type type, char* value) +{ + struct shortcut* sc = get_shortcut(shortcut_count++); + if (!sc) + return; + init_shortcut(sc); + sc->type = type; + if (type == SHORTCUT_SETTING) + sc->u.setting = (void*)value; + else + strlcpy(sc->u.path, value, MAX_PATH); + if (first_idx_to_writeback < 0) + first_idx_to_writeback = shortcut_count - 1; + register_storage_idle_func(shortcuts_ata_idle_callback); +} + + +int readline_cb(int n, char *buf, void *parameters) +{ + (void)n; + (void)parameters; + struct shortcut **param = (struct shortcut**)parameters; + struct shortcut* sc = *param; + char *name, *value; + + if (!strcasecmp(skip_whitespace(buf), "[shortcut]")) + { + if (sc && verify_shortcut(sc)) + shortcut_count++; + sc = get_shortcut(shortcut_count); + if (!sc) + return 1; + init_shortcut(sc); + *param = sc; + } + else if (sc && settings_parseline(buf, &name, &value)) + { + if (!strcmp(name, "type")) + { + int t = 0; + for (t=0; ttype == SHORTCUT_UNDEFINED; t++) + if (!strcmp(value, type_strings[t])) + sc->type = t; + } + else if (!strcmp(name, "name")) + { + strlcpy(sc->name, value, MAX_SHORTCUT_NAME); + } + else if (!strcmp(name, "data")) + { + switch (sc->type) + { + case SHORTCUT_UNDEFINED: + case SHORTCUT_TYPE_COUNT: + *param = NULL; + break; + case SHORTCUT_BROWSER: + case SHORTCUT_FILE: + case SHORTCUT_DEBUGITEM: + case SHORTCUT_PLAYLISTMENU: + strlcpy(sc->u.path, value, MAX_PATH); + break; + case SHORTCUT_SETTING: + sc->u.setting = find_setting_by_cfgname(value, NULL); + break; + case SHORTCUT_SEPARATOR: + break; + } + } + else if (!strcmp(name, "icon")) + { + if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0]) + { + sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path)); + } + else + { + sc->icon = atoi(value); + } + } + } + return 0; +} +void shortcuts_init(void) +{ + int fd; + char buf[512]; + struct shortcut *param = NULL; + struct shortcut_handle *h; + shortcut_count = 0; + fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY); + if (fd < 0) + return; + first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle)); + if (first_handle <= 0) + return; + h = core_get_data(first_handle); + h->next_handle = 0; + fast_readline(fd, buf, sizeof buf, ¶m, readline_cb); + close(fd); + if (param && verify_shortcut(param)) + shortcut_count++; +} + +const char * shortcut_menu_get_name(int selected_item, void * data, + char * buffer, size_t buffer_len) +{ + (void)data; + (void)buffer; + (void)buffer_len; + struct shortcut *sc = get_shortcut(selected_item); + if (!sc) + return ""; + if (sc->type == SHORTCUT_SETTING) + return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)); + else if (sc->type == SHORTCUT_SEPARATOR) + return sc->name; + return sc->name[0] ? sc->name : sc->u.path; +} + +int shortcut_menu_get_action(int action, struct gui_synclist *lists) +{ + (void)lists; + if (action == ACTION_STD_OK) + return ACTION_STD_CANCEL; + return action; +} +enum themable_icons shortcut_menu_get_icon(int selected_item, void * data) +{ + (void)data; + struct shortcut *sc = get_shortcut(selected_item); + if (!sc) + return Icon_NOICON; + if (sc->icon == Icon_NOICON) + { + switch (sc->type) + { + case SHORTCUT_FILE: + return filetype_get_icon(filetype_get_attr(sc->u.path)); + case SHORTCUT_BROWSER: + return Icon_Folder; + case SHORTCUT_SETTING: + return Icon_Menu_setting; + case SHORTCUT_DEBUGITEM: + return Icon_Menu_functioncall; + case SHORTCUT_PLAYLISTMENU: + return Icon_Playlist; + default: + break; + } + } + return sc->icon; +} + +int do_shortcut_menu(void *ignored) +{ + (void)ignored; + struct simplelist_info list; + struct shortcut *sc; + int done = GO_TO_PREVIOUS; + if (first_handle == 0) + shortcuts_init(); + simplelist_info_init(&list, P2STR(ID2P(LANG_SHORTCUTS)), shortcut_count, NULL); + list.get_name = shortcut_menu_get_name; + list.action_callback = shortcut_menu_get_action; + list.get_icon = shortcut_menu_get_icon; + list.title_icon = Icon_Bookmark; + + push_current_activity(ACTIVITY_SHORTCUTSMENU); + + while (done == GO_TO_PREVIOUS) + { + if (simplelist_show_list(&list)) + break; /* some error happened?! */ + if (list.selection == -1) + break; + else + { + sc = get_shortcut(list.selection); + if (!sc) + continue; + switch (sc->type) + { + case SHORTCUT_PLAYLISTMENU: + if (!file_exists(sc->u.path)) + { + splash(HZ, ID2P(LANG_NO_FILES)); + break; + } + else + { + onplay_show_playlist_menu(sc->u.path); + } + break; + case SHORTCUT_FILE: + if (!file_exists(sc->u.path)) + { + splash(HZ, ID2P(LANG_NO_FILES)); + break; + } + /* else fall through */ + case SHORTCUT_BROWSER: + { + struct browse_context browse; + browse_context_init(&browse, global_settings.dirfilter, 0, + NULL, NOICON, sc->u.path, NULL); + if (sc->type == SHORTCUT_FILE) + browse.flags |= BROWSE_RUNFILE; + done = rockbox_browse(&browse); + } + break; + case SHORTCUT_SETTING: + do_setting_screen(sc->u.setting, + sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL); + break; + case SHORTCUT_DEBUGITEM: + run_debug_screen(sc->u.path); + break; + case SHORTCUT_UNDEFINED: + default: + break; + } + } + } + pop_current_activity(); + return done; +} diff --git a/apps/shortcuts.h b/apps/shortcuts.h new file mode 100644 index 0000000000..b794a3a2f4 --- /dev/null +++ b/apps/shortcuts.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Jonathan Gordon + * + * 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. + * + ****************************************************************************/ +#ifndef __SHORTCUTS_H__ +#define __SHORTCUTS_H__ +#include +#include + +enum shortcut_type { + SHORTCUT_UNDEFINED = -1, + SHORTCUT_SETTING = 0, + SHORTCUT_FILE, + SHORTCUT_DEBUGITEM, + SHORTCUT_BROWSER, + SHORTCUT_PLAYLISTMENU, + SHORTCUT_SEPARATOR, + + SHORTCUT_TYPE_COUNT +}; + +void shortcuts_add(enum shortcut_type type, char* value); +void shortcuts_init(void); +int do_shortcut_menu(void*ignored); + +#endif diff --git a/apps/tree.c b/apps/tree.c index eb7783d4ee..3ba54bdfc6 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -1000,7 +1000,10 @@ int rockbox_browse(struct browse_context *browse) tc.browse = browse; strcpy(current, browse->root); set_current_file(current); - ret_val = dirbrowse(); + if (browse->flags&BROWSE_RUNFILE) + ret_val = ft_enter(&tc); + else + ret_val = dirbrowse(); } backup_count--; if (backup_count >= 0) diff --git a/apps/tree.h b/apps/tree.h index 2b296050d3..a12045cae4 100644 --- a/apps/tree.h +++ b/apps/tree.h @@ -36,8 +36,10 @@ struct entry { #define BROWSE_SELECTONLY 0x0001 /* exit on selecting a file */ #define BROWSE_NO_CONTEXT_MENU 0x0002 /* disable context menu */ +#define BROWSE_RUNFILE 0x0004 /* do ft_open() on the file instead of browsing */ #define BROWSE_SELECTED 0x0100 /* this bit is set if user selected item */ + struct tree_context; struct tree_cache { diff --git a/manual/main_menu/main.tex b/manual/main_menu/main.tex index 139d85f958..3d5a2be69f 100644 --- a/manual/main_menu/main.tex +++ b/manual/main_menu/main.tex @@ -265,3 +265,60 @@ pages of information.} quickscreen, then pressing up and down will cycle through this setting in opposite directions. } + +\section{\label{ref:MainMenuShortcuts}Shortcuts} + +This menu item is a container for user defined shortcuts to files, folders or +settings. The following are valid shortcuts: +\begin{itemize} + \item A file can be ``run'' (i.e. a music file played, plugin started or + a \fname{.cfg} loaded) + \item The file browser can be opened with the cursor positioned at + the specified file or folder + \item A file's or folder's ``Current Playlist'' context menu item can + be displayed + \item Most settings can be configured (any which can be added to the + \setting{Quick Screen}) + \item Any debug menu item (useful for developers mostly) +\end{itemize} + +\note{Shortcuts into the database are not possible} + +Shortcuts are loaded from the file \fname{/.rockbox/shortcuts.txt} which lists +each item to be displayed. Each shortcut looks like the following: + +\begin{example} + [shortcut] + type: + data: + name: + icon: +\end{example} + +Only ``type'' and ``data'' are required (except if type is ``separator'' in which case +``data'' is also not required). + +Available types are: +\begin{description} +\item[file] \config{data} is the filename to run +\item[browse] \config{data} is the file or the folder to open the file browser at +\item[playlist menu] \config{data} is the file or the folder to open the + ``Current Playlist'' context menu item on +\item[setting] \config{data} is the config name of the setting you want to change +\item[debug] \config{data} is the name of the debug menu item to display +\item[separator] \config{data} is ignored; name can be used to display text, + or left blank to make the list more accessible with visual gaps +\end{description} + + +If the name/icon items are not specified a sensible default will be used. + +\note{For the ``browse'' type, if you want the file browser to start \emph{inside} +a folder, make sure the data has the trailing slash (i.e \fname{/Music/} instead of +\fname {/Music}). Without the trailing slash, it will cause the file broser to open +with \fname{/Music} selected instead.} + +The file \fname{shortcuts.txt} can be edited with any text editor. Most items can +also be added to it through their context menu item ``Add to shortcuts''. +A reboot is needed for manual changes to \fname{shortcuts.txt} to be applied. + -- cgit v1.2.3