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:
parent
e7e4b131d0
commit
101693fd30
|
@ -52,6 +52,7 @@ root_menu.c
|
|||
screens.c
|
||||
settings.c
|
||||
settings_list.c
|
||||
shortcuts.c
|
||||
status.c
|
||||
cuesheet.c
|
||||
talk.c
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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<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;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define _DEBUG_MENU_H
|
||||
|
||||
bool debug_menu(void);
|
||||
bool run_debug_screen(char* screen);
|
||||
|
||||
#ifndef SIMULATOR
|
||||
extern bool dbg_ports(void);
|
||||
|
|
|
@ -12903,3 +12903,17 @@
|
|||
*: "Cancel Sleep Timer"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_SHORTCUTS
|
||||
desc: Title in the shortcuts menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Shortcuts"
|
||||
</source>
|
||||
<dest>
|
||||
*: "Shortcuts"
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Shortcuts"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
@ -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
|
||||
|
|
38
apps/menu.c
38
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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -119,7 +119,8 @@ enum current_activity {
|
|||
ACTIVITY_CONTEXTMENU,
|
||||
ACTIVITY_SYSTEMSCREEN,
|
||||
ACTIVITY_TIMEDATESCREEN,
|
||||
ACTIVITY_BOOKMARKSLIST
|
||||
ACTIVITY_BOOKMARKSLIST,
|
||||
ACTIVITY_SHORTCUTSMENU
|
||||
};
|
||||
|
||||
#if CONFIG_CODEC == SWCODEC
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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_;
|
||||
|
|
421
apps/shortcuts.c
Normal file
421
apps/shortcuts.c
Normal 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, ¶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;
|
||||
}
|
43
apps/shortcuts.h
Normal file
43
apps/shortcuts.h
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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: <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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user