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
This commit is contained in:
Jonathan Gordon 2011-11-15 13:22:02 +00:00
parent e7e4b131d0
commit 101693fd30
17 changed files with 628 additions and 22 deletions

View file

@ -52,6 +52,7 @@ root_menu.c
screens.c screens.c
settings.c settings.c
settings_list.c settings_list.c
shortcuts.c
status.c status.c
cuesheet.c cuesheet.c
talk.c talk.c

View file

@ -25,6 +25,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include "lcd.h" #include "lcd.h"
#include "lang.h"
#include "menu.h" #include "menu.h"
#include "debug_menu.h" #include "debug_menu.h"
#include "kernel.h" #include "kernel.h"
@ -45,6 +46,7 @@
#include "screens.h" #include "screens.h"
#include "misc.h" #include "misc.h"
#include "splash.h" #include "splash.h"
#include "shortcuts.h"
#include "dircache.h" #include "dircache.h"
#include "viewport.h" #include "viewport.h"
#ifdef HAVE_TAGCACHE #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) static int menu_action_callback(int btn, struct gui_synclist *lists)
{ {
int selection = gui_synclist_get_sel_pos(lists);
if (btn == ACTION_STD_OK) if (btn == ACTION_STD_OK)
{ {
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
viewportmanager_theme_enable(i, false, NULL); viewportmanager_theme_enable(i, false, NULL);
menuitems[gui_synclist_get_sel_pos(lists)].function(); menuitems[selection].function();
btn = ACTION_REDRAW; btn = ACTION_REDRAW;
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
viewportmanager_theme_undo(i, false); 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; return btn;
} }
@ -2148,3 +2158,22 @@ bool debug_menu(void)
info.get_name = dbg_menu_getname; info.get_name = dbg_menu_getname;
return simplelist_show_list(&info); return simplelist_show_list(&info);
} }
bool run_debug_screen(char* screen)
{
unsigned i;
for (i=0; i<ARRAYLEN(menuitems); i++)
{
if (!strcmp(screen, menuitems[i].desc))
{
FOR_NB_SCREENS(j)
viewportmanager_theme_enable(j, false, NULL);
menuitems[i].function();
FOR_NB_SCREENS(j)
viewportmanager_theme_undo(j, false);
return true;
}
}
return false;
}

View file

@ -22,6 +22,7 @@
#define _DEBUG_MENU_H #define _DEBUG_MENU_H
bool debug_menu(void); bool debug_menu(void);
bool run_debug_screen(char* screen);
#ifndef SIMULATOR #ifndef SIMULATOR
extern bool dbg_ports(void); extern bool dbg_ports(void);

View file

@ -12903,3 +12903,17 @@
*: "Cancel Sleep Timer" *: "Cancel Sleep Timer"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_SHORTCUTS
desc: Title in the shortcuts menu
user: core
<source>
*: "Shortcuts"
</source>
<dest>
*: "Shortcuts"
</dest>
<voice>
*: "Shortcuts"
</voice>
</phrase>

View file

@ -79,6 +79,7 @@
#if (CONFIG_PLATFORM & PLATFORM_ANDROID) #if (CONFIG_PLATFORM & PLATFORM_ANDROID)
#include "notification.h" #include "notification.h"
#endif #endif
#include "shortcuts.h"
#ifdef IPOD_ACCESSORY_PROTOCOL #ifdef IPOD_ACCESSORY_PROTOCOL
#include "iap.h" #include "iap.h"
@ -387,6 +388,7 @@ static void init(void)
filetype_init(); filetype_init();
playlist_init(); playlist_init();
theme_init_buffer(); theme_init_buffer();
shortcuts_init();
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
mp3_init( global_settings.volume, mp3_init( global_settings.volume,
@ -667,6 +669,7 @@ static void init(void)
filetype_init(); filetype_init();
scrobbler_init(); scrobbler_init();
theme_init_buffer(); theme_init_buffer();
shortcuts_init();
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
/* No buffer allocation (see buffer.c) may take place after the call to /* No buffer allocation (see buffer.c) may take place after the call to

View file

@ -52,6 +52,7 @@
#include "audio.h" #include "audio.h"
#include "viewport.h" #include "viewport.h"
#include "quickscreen.h" #include "quickscreen.h"
#include "shortcuts.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
#include "icons.h" #include "icons.h"
@ -280,19 +281,10 @@ static int talk_menu_item(int selected_item, void *data)
return 0; return 0;
} }
void do_setting_from_menu(const struct menu_item_ex *temp, void do_setting_screen(const struct settings_list *setting, const char * title,
struct viewport parent[NB_SCREENS]) 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]; 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 /* Pad the title string by repeating it. This is needed
so the scroll settings title can actually be used to so the scroll settings title can actually be used to
test the setting */ 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, 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 */ /* 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_TOP_QS_ITEM),
ID2P(LANG_LEFT_QS_ITEM), ID2P(LANG_LEFT_QS_ITEM),
ID2P(LANG_BOTTOM_QS_ITEM), ID2P(LANG_BOTTOM_QS_ITEM),
ID2P(LANG_RIGHT_QS_ITEM)); ID2P(LANG_RIGHT_QS_ITEM),
ID2P(LANG_ADD_TO_FAVES));
#endif #endif
MENUITEM_STRINGLIST(notquickscreen_able_option, MENUITEM_STRINGLIST(notquickscreen_able_option,
ID2P(LANG_ONPLAY_MENU_TITLE), NULL, 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 */ case 4: /* set as right QS item */
set_as_qs_item(setting, QUICKSCREEN_RIGHT); set_as_qs_item(setting, QUICKSCREEN_RIGHT);
break; 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 #endif
} /* swicth(do_menu()) */ } /* swicth(do_menu()) */
redraw_lists = true; redraw_lists = true;

View file

@ -26,6 +26,7 @@
#include "icon.h" #include "icon.h"
#include "icons.h" #include "icons.h"
#include "root_menu.h" /* needed for MENU_* return codes */ #include "root_menu.h" /* needed for MENU_* return codes */
#include "settings_list.h"
enum menu_item_type { enum menu_item_type {
@ -103,6 +104,8 @@ typedef int (*menu_callback_type)(int action,
const struct menu_item_ex *this_item); const struct menu_item_ex *this_item);
void do_setting_from_menu(const struct menu_item_ex *temp, void do_setting_from_menu(const struct menu_item_ex *temp,
struct viewport parent[NB_SCREENS]); 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) int do_menu(const struct menu_item_ex *menu, int *start_selected)

View file

@ -119,7 +119,8 @@ enum current_activity {
ACTIVITY_CONTEXTMENU, ACTIVITY_CONTEXTMENU,
ACTIVITY_SYSTEMSCREEN, ACTIVITY_SYSTEMSCREEN,
ACTIVITY_TIMEDATESCREEN, ACTIVITY_TIMEDATESCREEN,
ACTIVITY_BOOKMARKSLIST ACTIVITY_BOOKMARKSLIST,
ACTIVITY_SHORTCUTSMENU
}; };
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC

View file

@ -63,6 +63,7 @@
#include "pitchscreen.h" #include "pitchscreen.h"
#include "viewport.h" #include "viewport.h"
#include "filefuncs.h" #include "filefuncs.h"
#include "shortcuts.h"
static int context; static int context;
static char* selected_file = NULL; static char* selected_file = NULL;
@ -382,10 +383,13 @@ static int treeplaylist_callback(int action,
return action; return action;
} }
void onplay_show_playlist_menu(char* track_name) void onplay_show_playlist_menu(char* path)
{ {
selected_file = track_name; selected_file = path;
selected_file_attr = FILE_ATTR_AUDIO; 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); 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), MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES),
onplay_load_plugin, (void *)"properties", onplay_load_plugin, (void *)"properties",
clipboard_callback, Icon_NOICON); clipboard_callback, Icon_NOICON);
MENUITEM_FUNCTION(add_to_faves_item, MENU_FUNC_USEPARAM, ID2P(LANG_ADD_TO_FAVES), static bool onplay_add_to_shortcuts(void)
onplay_load_plugin, (void *)"shortcuts_append", {
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); clipboard_callback, Icon_NOICON);
#if LCD_DEPTH > 1 #if LCD_DEPTH > 1

View file

@ -50,6 +50,6 @@ enum hotkey_action {
/* needed for the playlist viewer.. eventually clean this up */ /* needed for the playlist viewer.. eventually clean this up */
void onplay_show_playlist_cat_menu(char* track_name); 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 #endif

View file

@ -37,6 +37,7 @@
#include "power.h" #include "power.h"
#include "talk.h" #include "talk.h"
#include "audio.h" #include "audio.h"
#include "shortcuts.h"
#ifdef HAVE_HOTSWAP #ifdef HAVE_HOTSWAP
#include "storage.h" #include "storage.h"
@ -415,12 +416,16 @@ static const struct root_items items[] = {
&playlist_options }, &playlist_options },
[GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options }, [GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options },
[GO_TO_SYSTEM_SCREEN] = { miscscrn, &info_menu, &system_menu }, [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 const int nb_items = sizeof(items)/sizeof(*items);
static int item_callback(int action, const struct menu_item_ex *this_item) ; 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, MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER,
NULL, Icon_file_view_menu); NULL, Icon_file_view_menu);
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE
@ -492,6 +497,7 @@ MAKE_MENU(root_menu_, ID2P(LANG_ROCKBOX_TITLE),
#if CONFIG_KEYPAD == PLAYER_PAD #if CONFIG_KEYPAD == PLAYER_PAD
,&do_shutdown_item ,&do_shutdown_item
#endif #endif
,&shortcut_menu
); );
static int item_callback(int action, const struct menu_item_ex *this_item) static int item_callback(int action, const struct menu_item_ex *this_item)

View file

@ -58,6 +58,7 @@ enum {
GO_TO_PLAYLISTS_SCREEN, GO_TO_PLAYLISTS_SCREEN,
GO_TO_PLAYLIST_VIEWER, GO_TO_PLAYLIST_VIEWER,
GO_TO_SYSTEM_SCREEN, GO_TO_SYSTEM_SCREEN,
GO_TO_SHORTCUTMENU
}; };
extern const struct menu_item_ex root_menu_; extern const struct menu_item_ex root_menu_;

421
apps/shortcuts.c Normal file
View file

@ -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 <stdbool.h>
#include <stdlib.h>
#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; t<SHORTCUT_TYPE_COUNT && sc->type == 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, &param, 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;
}

43
apps/shortcuts.h Normal file
View file

@ -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 <stdbool.h>
#include <stdlib.h>
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

View file

@ -1000,7 +1000,10 @@ int rockbox_browse(struct browse_context *browse)
tc.browse = browse; tc.browse = browse;
strcpy(current, browse->root); strcpy(current, browse->root);
set_current_file(current); set_current_file(current);
ret_val = dirbrowse(); if (browse->flags&BROWSE_RUNFILE)
ret_val = ft_enter(&tc);
else
ret_val = dirbrowse();
} }
backup_count--; backup_count--;
if (backup_count >= 0) if (backup_count >= 0)

View file

@ -36,8 +36,10 @@ struct entry {
#define BROWSE_SELECTONLY 0x0001 /* exit on selecting a file */ #define BROWSE_SELECTONLY 0x0001 /* exit on selecting a file */
#define BROWSE_NO_CONTEXT_MENU 0x0002 /* disable context menu */ #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 */ #define BROWSE_SELECTED 0x0100 /* this bit is set if user selected item */
struct tree_context; struct tree_context;
struct tree_cache { struct tree_cache {

View file

@ -265,3 +265,60 @@ pages of information.}
quickscreen, then pressing up and down will cycle through this setting in quickscreen, then pressing up and down will cycle through this setting in
opposite directions. 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: <specify the shortcut type/action>
data: <what the shortcut actually links to>
name: <what you want the shortcut to be displayed as>
icon: <number of the theme icon to use (see http://www.rockbox.org/wiki/CustomIcons)>
\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.