diff --git a/apps/gui/wps.c b/apps/gui/wps.c index 78e49ac4f8..0e52323dc2 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -829,6 +829,8 @@ long gui_wps_show(void) if (retval == ONPLAY_MAINMENU || !audio_status()) return GO_TO_ROOT; + else if (retval == ONPLAY_REVEAL_FILE) + return GO_TO_FILEBROWSER; else if (retval == ONPLAY_PLAYLIST) return GO_TO_PLAYLIST_VIEWER; else if (retval == ONPLAY_PLUGIN) diff --git a/apps/lang/english-us.lang b/apps/lang/english-us.lang index db078e77af..d1f8c108ce 100644 --- a/apps/lang/english-us.lang +++ b/apps/lang/english-us.lang @@ -16984,3 +16984,73 @@ *: "U S B" + + id: LANG_COUNTDOWN_TIMER_SET + desc: countdown_timer plugin - header shown on the setup screen where the user enters the countdown duration + user: core + + *: "SET TIMER" + + + *: "SET TIMER" + + + *: "Set timer" + + + + id: LANG_COUNTDOWN_TIMER_RUNNING + desc: countdown_timer plugin - status label shown while the countdown is active + user: core + + *: "RUNNING" + + + *: "RUNNING" + + + *: "Running" + + + + id: LANG_COUNTDOWN_TIMER_PAUSED + desc: countdown_timer plugin - status label shown while the countdown is paused + user: core + + *: "PAUSED" + + + *: "PAUSED" + + + *: "Paused" + + + + id: LANG_COUNTDOWN_TIMER_OVERTIME + desc: countdown_timer plugin - status label shown when the countdown has passed zero and is counting up + user: core + + *: "OVERTIME" + + + *: "OVERTIME" + + + *: "Overtime" + + + + id: LANG_COUNTDOWN_TIMER_FINISHED + desc: countdown_timer plugin - status label shown at the moment the countdown expires + user: core + + *: "FINISHED" + + + *: "FINISHED" + + + *: "Finished" + + diff --git a/apps/lang/english.lang b/apps/lang/english.lang index aeedbc2541..45ed8938fc 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -17057,3 +17057,115 @@ *: "U S B" + + id: LANG_FILE_NOT_FOUND + desc: When file does not exist + user: core + + *: "File not found" + + + *: "File not found" + + + *: "File not found" + + + + id: LANG_SHOW_IN_FILES + desc: Reveal item in File Browser + user: core + + *: "Show in Files" + + + *: "Show in Files" + + + *: "Show in Files" + + + + id: LANG_CHANNEL_SWAP + desc: in sound_settings + user: core + + *: "Swap Left & Right" + + + *: "Swap Left & Right" + + + *: "Swap Left & Right" + + + + id: LANG_COUNTDOWN_TIMER_SET + desc: countdown_timer plugin - header shown on the setup screen where the user enters the countdown duration + user: core + + *: "SET TIMER" + + + *: "SET TIMER" + + + *: "Set timer" + + + + id: LANG_COUNTDOWN_TIMER_RUNNING + desc: countdown_timer plugin - status label shown while the countdown is active + user: core + + *: "RUNNING" + + + *: "RUNNING" + + + *: "Running" + + + + id: LANG_COUNTDOWN_TIMER_PAUSED + desc: countdown_timer plugin - status label shown while the countdown is paused + user: core + + *: "PAUSED" + + + *: "PAUSED" + + + *: "Paused" + + + + id: LANG_COUNTDOWN_TIMER_OVERTIME + desc: countdown_timer plugin - status label shown when the countdown has passed zero and is counting up + user: core + + *: "OVERTIME" + + + *: "OVERTIME" + + + *: "Overtime" + + + + id: LANG_COUNTDOWN_TIMER_FINISHED + desc: countdown_timer plugin - status label shown at the moment the countdown expires + user: core + + *: "FINISHED" + + + *: "FINISHED" + + + *: "Finished" + + diff --git a/apps/onplay.c b/apps/onplay.c index 15b519871f..82b5ab8931 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -897,6 +897,26 @@ static bool onplay_load_plugin(void *param) return false; } +static int reveal(void) +{ +#ifdef HAVE_TAGCACHE + if (!prepare_database_sel(NULL)) + return 0; +#endif + if (!file_exists(selected_file.path)) + { + splash(HZ*2, ID2P(LANG_FILE_NOT_FOUND)); + return 0; + } + + strmemccpy(global_status.browse_last_folder, selected_file.path, + sizeof global_status.browse_last_folder); + onplay_result = ONPLAY_REVEAL_FILE; + return 0; +} + +MENUITEM_FUNCTION(reveal_item, 0, ID2P(LANG_SHOW_IN_FILES), + reveal, clipboard_callback, Icon_file_view_menu); MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH), list_viewers, clipboard_callback, Icon_NOICON); MENUITEM_FUNCTION_W_PARAM(properties_item, 0, ID2P(LANG_PROPERTIES), @@ -1033,7 +1053,8 @@ static int clipboard_callback(int action, if (selected_file.context == CONTEXT_ID3DB) { if (this_item == &track_info_item || - this_item == &pictureflow_item) + this_item == &pictureflow_item || + this_item == &reveal_item) return action; return ACTION_EXIT_MENUITEM; } @@ -1088,7 +1109,9 @@ static int clipboard_callback(int action, if (*tree_get_context()->dirfilter != SHOW_M3U) return action; } - else if (this_item == &delete_file_item) + else if (this_item == &delete_file_item || + (this_item == &reveal_item && + selected_file.context == CONTEXT_WPS)) return action; #if LCD_DEPTH > 1 else if (this_item == &set_backdrop_item) @@ -1124,8 +1147,8 @@ MAKE_ONPLAYMENU( wps_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), #endif &bookmark_menu, &plugin_item, - &browse_id3_item, &list_viewers_item, - &delete_file_item, &view_cue_item, + &browse_id3_item, + &reveal_item, &view_cue_item, #ifdef HAVE_PITCHCONTROL &pitch_menu, #endif @@ -1162,6 +1185,7 @@ MAKE_ONPLAYMENU( tree_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), &rename_file_item, &clipboard_cut_item, &clipboard_copy_item, &clipboard_paste_item, &delete_file_item, &delete_dir_item, &list_viewers_item, &create_dir_item, &properties_item, &track_info_item, + &reveal_item, #ifdef HAVE_TAGCACHE &pictureflow_item, #endif diff --git a/apps/onplay.h b/apps/onplay.h index 26b1247f7b..4e5e6eeb69 100644 --- a/apps/onplay.h +++ b/apps/onplay.h @@ -38,6 +38,7 @@ enum { ONPLAY_MAINMENU = -1, ONPLAY_OK = 0, ONPLAY_RELOAD_DIR, + ONPLAY_REVEAL_FILE, ONPLAY_START_PLAY, ONPLAY_PLAYLIST, ONPLAY_PLUGIN, diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 88f2590c3e..392131a8a9 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c @@ -515,9 +515,15 @@ static void format_line(struct playlist_entry* track, char* str, int len) { char *id3viewc = NULL; - char *skipped = ""; + char *skipped, *prefix, *suffix; + skipped = prefix = suffix = ""; if (track->attr & PLAYLIST_ATTR_SKIPPED) skipped = "(ERR) "; + if (track->index == viewer.current_playing_track) + { + prefix = "["; + suffix = "]"; + } if (!(track->attr & PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED) && (global_settings.playlist_viewer_track_display == PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM || @@ -591,9 +597,10 @@ static void format_line(struct playlist_entry* track, char* str, format_name(name, track->name, sizeof(name)); if (global_settings.playlist_viewer_indices) /* Display playlist index */ - snprintf(str, len, "%d. %s%s", track->display_index, skipped, name); + snprintf(str, len, "%s%d. %s%s%s", + prefix, track->display_index, skipped, name, suffix); else - snprintf(str, len, "%s%s", skipped, name); + snprintf(str, len, "%s%s%s%s", prefix, skipped, name, suffix); } else { @@ -603,9 +610,10 @@ static void format_line(struct playlist_entry* track, char* str, } if (global_settings.playlist_viewer_indices) /* Display playlist index */ - snprintf(str, len, "%d. %s%s", track->display_index, skipped, id3viewc); + snprintf(str, len, "%s%d. %s%s%s", + prefix, track->display_index, skipped, id3viewc, suffix); else - snprintf(str, len, "%s%s", skipped, id3viewc); + snprintf(str, len, "%s%s%s%s", prefix, skipped, id3viewc, suffix); } } diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index c9b1781a15..bf646a5bf9 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -21,6 +21,7 @@ chopper,games clix,games clock,apps codebuster,games +countdown_timer,apps credits,viewers cube,demos cue_playlist,viewers diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 3a57e3f9e5..797601e4dd 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -7,6 +7,7 @@ db_folder_select.c tagcache/tagcache.c #endif chessclock.c +countdown_timer.c credits.c cube.c cue_playlist.c diff --git a/apps/plugins/countdown_timer.c b/apps/plugins/countdown_timer.c new file mode 100644 index 0000000000..b520047bf3 --- /dev/null +++ b/apps/plugins/countdown_timer.c @@ -0,0 +1,242 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2026 Teun van Dalen + * + * 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 "plugin.h" +#include "lib/pluginlib_actions.h" +#include "lib/pluginlib_exit.h" + +const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; + +#define MAX_MINUTES 99 +#define MAX_SECONDS 59 + +typedef enum { + STATE_SETUP, + STATE_RUNNING, + STATE_PAUSED, + STATE_FINISHED, +} timer_state_t; + +typedef struct { + int set_minutes; + int set_seconds; + int current_field; + long remaining_ticks; + long last_tick; + timer_state_t state; +} timer_ctx_t; + +static inline int get_button(void) +{ + return pluginlib_getaction(HZ / 10, plugin_contexts, + ARRAYLEN(plugin_contexts)); +} + +static void draw(const timer_ctx_t *ctx) +{ + char time_str[12]; + const char *status_str; + int disp_min, disp_sec; + int w, h, x, y; + + rb->lcd_clear_display(); + + if (ctx->state == STATE_SETUP) { + disp_min = ctx->set_minutes; + disp_sec = ctx->set_seconds; + if (ctx->current_field == 0) + rb->snprintf(time_str, sizeof(time_str), "[%02d]:%02d", + disp_min, disp_sec); + else + rb->snprintf(time_str, sizeof(time_str), "%02d:[%02d]", + disp_min, disp_sec); + status_str = rb->str(LANG_COUNTDOWN_TIMER_SET); + } else if (ctx->state == STATE_FINISHED) { + rb->snprintf(time_str, sizeof(time_str), "00:00"); + status_str = rb->str(LANG_COUNTDOWN_TIMER_FINISHED); + } else { + if (ctx->remaining_ticks >= 0) { + int remaining_secs = (ctx->remaining_ticks + HZ - 1) / HZ; + disp_min = remaining_secs / 60; + disp_sec = remaining_secs % 60; + rb->snprintf(time_str, sizeof(time_str), "%02d:%02d", + disp_min, disp_sec); + } else { + int over_secs = ((-ctx->remaining_ticks) + HZ - 1) / HZ; + disp_min = over_secs / 60; + disp_sec = over_secs % 60; + rb->snprintf(time_str, sizeof(time_str), "-%02d:%02d", + disp_min, disp_sec); + } + + if (ctx->state == STATE_RUNNING && ctx->remaining_ticks < 0) + status_str = rb->str(LANG_COUNTDOWN_TIMER_OVERTIME); + else if (ctx->state == STATE_RUNNING) + status_str = rb->str(LANG_COUNTDOWN_TIMER_RUNNING); + else + status_str = rb->str(LANG_COUNTDOWN_TIMER_PAUSED); + } + + /* Draw status string above center */ + rb->lcd_getstringsize(status_str, &w, &h); + x = (LCD_WIDTH - w) / 2; + y = (LCD_HEIGHT / 2) - h - 2; + rb->lcd_putsxy(x, y, status_str); + + /* Draw time string at center */ + rb->lcd_getstringsize(time_str, &w, &h); + x = (LCD_WIDTH - w) / 2; + y = LCD_HEIGHT / 2; + rb->lcd_putsxy(x, y, time_str); + + rb->lcd_update(); +} + +enum plugin_status plugin_start(const void *parameter) +{ + timer_ctx_t ctx = { + .set_minutes = 10, + .set_seconds = 0, + .current_field = 0, + .remaining_ticks = 60 * HZ, + .last_tick = 0, + .state = STATE_SETUP, + }; + bool overtime_alerted = false; + int button; + + (void)parameter; + + while (true) { + if (ctx.state == STATE_RUNNING) { + long now = *rb->current_tick; + ctx.remaining_ticks -= now - ctx.last_tick; + ctx.last_tick = now; + + if (ctx.remaining_ticks < 0 && !overtime_alerted) { + overtime_alerted = true; + ctx.state = STATE_FINISHED; + draw(&ctx); + rb->audio_pause(); +#ifdef HAVE_BACKLIGHT + rb->backlight_on(); +#endif + rb->beep_play(1000, 200, 1000); + rb->sleep(HZ / 4); + rb->beep_play(1000, 200, 1000); + rb->sleep(HZ / 4); + rb->beep_play(1000, 400, 1000); + rb->sleep(HZ + HZ / 2); + rb->audio_resume(); + ctx.state = STATE_RUNNING; + /* Reset last_tick so the beep/sleep time is not counted + * against remaining_ticks on the next iteration. */ + ctx.last_tick = *rb->current_tick; + } + } + + draw(&ctx); + button = get_button(); + + switch (ctx.state) { + case STATE_SETUP: { + bool time_changed = false; + switch (button) { +#ifdef HAVE_SCROLLWHEEL + case PLA_SCROLL_FWD: + case PLA_SCROLL_FWD_REPEAT: +#endif + case PLA_UP: + case PLA_UP_REPEAT: + if (ctx.current_field == 0) + ctx.set_minutes = (ctx.set_minutes + 1) % (MAX_MINUTES + 1); + else + ctx.set_seconds = (ctx.set_seconds + 1) % (MAX_SECONDS + 1); + time_changed = true; + break; +#ifdef HAVE_SCROLLWHEEL + case PLA_SCROLL_BACK: + case PLA_SCROLL_BACK_REPEAT: +#endif + case PLA_DOWN: + case PLA_DOWN_REPEAT: + if (ctx.current_field == 0) + ctx.set_minutes = (ctx.set_minutes + MAX_MINUTES) % (MAX_MINUTES + 1); + else + ctx.set_seconds = (ctx.set_seconds + MAX_SECONDS) % (MAX_SECONDS + 1); + time_changed = true; + break; + case PLA_LEFT: + case PLA_LEFT_REPEAT: + case PLA_RIGHT: + case PLA_RIGHT_REPEAT: + ctx.current_field = (ctx.current_field + 1) % 2; + break; + case PLA_SELECT: + if (ctx.set_minutes > 0 || ctx.set_seconds > 0) { + ctx.remaining_ticks = (ctx.set_minutes * 60 + ctx.set_seconds) * HZ; + ctx.last_tick = *rb->current_tick; + ctx.state = STATE_RUNNING; + } + break; + default: + exit_on_usb(button); + break; + } + if (time_changed) + ctx.remaining_ticks = (ctx.set_minutes * 60 + ctx.set_seconds) * HZ; + break; + } + + case STATE_RUNNING: + switch (button) { + case PLA_SELECT: + ctx.state = STATE_PAUSED; + break; + default: + exit_on_usb(button); + break; + } + break; + + case STATE_FINISHED: + exit_on_usb(button); + break; + + case STATE_PAUSED: + switch (button) { + case PLA_SELECT: + ctx.last_tick = *rb->current_tick; + ctx.state = STATE_RUNNING; + break; + case PLA_UP: + case PLA_UP_REPEAT: + case PLA_CANCEL: + case PLA_EXIT: + return PLUGIN_OK; + default: + exit_on_usb(button); + break; + } + break; + } + } +} diff --git a/apps/settings_list.c b/apps/settings_list.c index 826f85825d..59fd4537a0 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1060,11 +1060,12 @@ const struct settings_list settings[] = { /* 3-d enhancement effect */ CHOICE_SETTING(0, channel_config, LANG_CHANNEL_CONFIGURATION, 0,"channels", - "stereo,mono,custom,mono left,mono right,karaoke", - sound_set_channels, 6, + "stereo,mono,custom,mono left,mono right,karaoke,swap", + sound_set_channels, 7, ID2P(LANG_CHANNEL_STEREO), ID2P(LANG_CHANNEL_MONO), ID2P(LANG_CHANNEL_CUSTOM), ID2P(LANG_CHANNEL_LEFT), - ID2P(LANG_CHANNEL_RIGHT), ID2P(LANG_CHANNEL_KARAOKE)), + ID2P(LANG_CHANNEL_RIGHT), ID2P(LANG_CHANNEL_KARAOKE), + ID2P(LANG_CHANNEL_SWAP)), SOUND_SETTING(0, stereo_width, LANG_STEREO_WIDTH, "stereo_width", SOUND_STEREO_WIDTH), #ifdef AUDIOHW_HAVE_DEPTH_3D diff --git a/apps/tree.c b/apps/tree.c index 5df204bbf2..387a070e3a 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -975,6 +975,10 @@ static int dirbrowse(void) return exit_to_new_screen(GO_TO_ROOT); break; + case ONPLAY_REVEAL_FILE: + return exit_to_new_screen(GO_TO_FILEBROWSER); + break; + case ONPLAY_OK: restore = do_restore_display; break; diff --git a/docs/CREDITS b/docs/CREDITS index 06045db966..f1affc6eb8 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -760,6 +760,7 @@ Yegor Chernyshov Javier Gutiérrez Gertrúdix Sergey Puskov Eivind Ødegård +Teun van Dalen The libmad team The wavpack team diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 65570abb5b..ec465ca7b7 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -674,6 +674,7 @@ enum AUDIOHW_CHANNEL_CONFIG SOUND_CHAN_MONO_LEFT, SOUND_CHAN_MONO_RIGHT, SOUND_CHAN_KARAOKE, + SOUND_CHAN_SWAP, SOUND_CHAN_NUM_MODES, }; diff --git a/lib/rbcodec/dsp/channel_mode.c b/lib/rbcodec/dsp/channel_mode.c index 7a83236648..86dc02e3a4 100644 --- a/lib/rbcodec/dsp/channel_mode.c +++ b/lib/rbcodec/dsp/channel_mode.c @@ -43,6 +43,8 @@ void channel_mode_proc_custom(struct dsp_proc_entry *this, struct dsp_buffer **buf_p); void channel_mode_proc_karaoke(struct dsp_proc_entry *this, struct dsp_buffer **buf_p); +void channel_mode_proc_swap(struct dsp_proc_entry *this, + struct dsp_buffer **buf_p); static struct channel_mode_data { @@ -131,6 +133,25 @@ void channel_mode_proc_karaoke(struct dsp_proc_entry *this, } #endif /* CPU */ +void channel_mode_proc_swap(struct dsp_proc_entry *this, + struct dsp_buffer **buf_p) +{ + struct dsp_buffer *buf = *buf_p; + int32_t *sl = buf->p32[0]; + int32_t *sr = buf->p32[1]; + int count = buf->remcount; + + do + { + int32_t l = *sl; + *sl++ = *sr; + *sr++ = l; + } + while (--count > 0); + + (void)this; +} + void channel_mode_proc_mono_left(struct dsp_proc_entry *this, struct dsp_buffer **buf_p) { @@ -194,6 +215,7 @@ static void update_process_fn(struct dsp_proc_entry *this) [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left, [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right, [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke, + [SOUND_CHAN_SWAP] = channel_mode_proc_swap, }; this->process = fns[((struct channel_mode_data *)this->data)->mode]; diff --git a/manual/configure_rockbox/sound_settings.tex b/manual/configure_rockbox/sound_settings.tex index f9c85b6fbb..a8e94737b9 100644 --- a/manual/configure_rockbox/sound_settings.tex +++ b/manual/configure_rockbox/sound_settings.tex @@ -178,6 +178,9 @@ change to customise your listening experience. to make the singer sound centrally placed, this often (but not always) has the effect of removing the voice track from a song. This setting also very often has other undesirable effects on the sound. + \item[Swap Left \& Right.] + Plays the left channel in the right stereo channel, and the right + channel in the left stereo channel. \end{description} \section{Stereo Width} diff --git a/manual/plugins/countdown_timer.tex b/manual/plugins/countdown_timer.tex new file mode 100644 index 0000000000..c022203a92 --- /dev/null +++ b/manual/plugins/countdown_timer.tex @@ -0,0 +1,51 @@ +% $Id$ % +\subsection{Countdown_timer} + +A countdown timer. Set the desired duration, start the countdown, and the +\dap{} will alert you with a beep sequence when time is up. The timer +defaults to 10 minutes on launch. + +\subsubsection{Setting the timer} + +When the plugin starts, the display shows the time to count down from with +the active field highlighted in brackets (e.g.\ \texttt{[10]:00}). + +\begin{btnmap} + \opt{scrollwheel}{\PluginScrollFwd{} / \PluginScrollBack{} or } + \PluginUp{} / \PluginDown + \opt{HAVEREMOTEKEYMAP}{& \PluginRCUp{} / \PluginRCDown} + & Increase / decrease the selected field \\ + + \PluginLeft{} / \PluginRight + \opt{HAVEREMOTEKEYMAP}{& \PluginRCLeft{} / \PluginRCRight} + & Switch between the minutes and seconds fields \\ + + \PluginSelect + \opt{HAVEREMOTEKEYMAP}{& \PluginRCSelect} + & Start the countdown \\ +\end{btnmap} + +Minutes can be set from 0 to 99 and seconds from 0 to 59. The timer cannot +be started if both fields are zero. Values wrap around when incremented or +decremented past their limits. + +\subsubsection{Running the timer} + +Once started, the remaining time counts down in \texttt{MM:SS} format. + +\begin{btnmap} + \PluginSelect + \opt{HAVEREMOTEKEYMAP}{& \PluginRCSelect} + & Pause / resume the timer \\ + + \nopt{IPOD_4G_PAD,IPOD_3G_PAD}{\PluginCancel} + \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu} + \opt{HAVEREMOTEKEYMAP}{& \PluginRCCancel} + & Quit (only available while paused) \\ +\end{btnmap} + +When the countdown reaches zero the \dap{} pauses playback, turns on the +backlight, and plays three beeps. After the alert the timer continues +running into overtime, displaying the elapsed overtime as +\texttt{-MM:SS}. Playback resumes automatically after the beep sequence. +The timer can be quit by pausing it and pressing the quit button. diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex index d6601b8a5b..8ca4b86e6b 100644 --- a/manual/plugins/main.tex +++ b/manual/plugins/main.tex @@ -297,3 +297,5 @@ option from the \setting{Context Menu} (see \reference{ref:Contextmenu}).} \input{plugins/stopwatch.tex} \input{plugins/text_editor.tex} + +\input{plugins/countdown_timer.tex} diff --git a/manual/rockbox_interface/browsing_and_playing.tex b/manual/rockbox_interface/browsing_and_playing.tex index 45a145ad3a..c6443a9351 100644 --- a/manual/rockbox_interface/browsing_and_playing.tex +++ b/manual/rockbox_interface/browsing_and_playing.tex @@ -143,7 +143,9 @@ each option pertains both to files and directories): Deletes the currently selected file. This option applies only to files, and not to directories. Rockbox will ask for confirmation before deleting a file. Press \ActionYesNoAccept{} - to confirm deletion or any other key to cancel. + to confirm deletion or any other key to cancel. When deleting a currently + playing file, the part of the file that has already been buffered (i.e. read + into the \daps\ memory) will continue playing. This may even be the whole track. \item [Delete Directory.] Deletes the currently selected directory and all of the files and subdirectories it may contain. Deleted directories cannot be recovered. Use this feature with diff --git a/manual/rockbox_interface/wps.tex b/manual/rockbox_interface/wps.tex index 3ed0d961e6..918d62a436 100644 --- a/manual/rockbox_interface/wps.tex +++ b/manual/rockbox_interface/wps.tex @@ -254,15 +254,8 @@ from the WPS, % \setting{Context Menu}. Then select \setting{Show Track Info}. The same steps work in the Playlist Viewer as well.} -\subsubsection{Open With...} -This \setting{Open With} function is the same as the \setting{Open With} -function in the file browser's \setting{Context Menu}. - -\subsubsection{Delete} -Delete the currently playing file. The file will be deleted but the playback -of the file will not stop immediately. Instead, the part of the file that -has already been buffered (i.e. read into the \daps\ memory) will be played. -This may even be the whole track. +\subsubsection{Show in Files} +Reveal the currently playing track in the \setting{File Browser}. \opt{pitchscreen}{ \subsubsection{\label{sec:pitchscreen}Pitch}