summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Scarratt <mmmm@rockbox.org>2007-04-15 13:56:21 +0000
committerMartin Scarratt <mmmm@rockbox.org>2007-04-15 13:56:21 +0000
commit49952325c9d4a74225b3099eb61860bf4592022c (patch)
tree70302ab68faf2d231ee491c201dcc47736f852b4
parent3c6e46ce64297697bbd6c713da3d0ba7856d6ea9 (diff)
downloadrockbox-49952325c9d4a74225b3099eb61860bf4592022c.tar.gz
rockbox-49952325c9d4a74225b3099eb61860bf4592022c.zip
Recording countdown timer and repeat timer - see FS #6297 for more details
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13165 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/gui/statusbar.c104
-rw-r--r--apps/gui/statusbar.h8
-rw-r--r--apps/keymaps/keymap-h10.c7
-rw-r--r--apps/keymaps/keymap-h1x0_h3x0.c11
-rw-r--r--apps/keymaps/keymap-x5.c3
-rw-r--r--apps/lang/english.lang100
-rw-r--r--apps/menus/recording_menu.c73
-rw-r--r--apps/recorder/icons.c10
-rw-r--r--apps/recorder/icons.h7
-rw-r--r--apps/recorder/recording.c152
-rw-r--r--apps/recorder/recording.h17
-rw-r--r--apps/settings.c188
-rw-r--r--apps/settings.h9
13 files changed, 670 insertions, 19 deletions
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index e082063a6f..157224f77d 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -33,6 +33,7 @@
33#include "action.h" /* for keys_locked */ 33#include "action.h" /* for keys_locked */
34#include "statusbar.h" 34#include "statusbar.h"
35#ifdef HAVE_RECORDING 35#ifdef HAVE_RECORDING
36#include "recording.h"
36#include "audio.h" 37#include "audio.h"
37#include "recording.h" 38#include "recording.h"
38#endif 39#endif
@@ -113,7 +114,11 @@
113#define STATUSBAR_LOCKR_WIDTH 5 114#define STATUSBAR_LOCKR_WIDTH 5
114 115
115#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 116#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
117#ifdef HAVE_MMC
116#define STATUSBAR_DISK_WIDTH 12 118#define STATUSBAR_DISK_WIDTH 12
119#else
120#define STATUSBAR_DISK_WIDTH 7
121#endif
117#define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \ 122#define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \
118 STATUSBAR_DISK_WIDTH 123 STATUSBAR_DISK_WIDTH
119#else 124#else
@@ -121,6 +126,15 @@
121#endif 126#endif
122#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ 127#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \
123 STATUSBAR_DISK_WIDTH 128 STATUSBAR_DISK_WIDTH
129#ifdef HAVE_RECORDING
130#define TIMER_ICON_WIDTH 7
131#if CONFIG_RTC
132#define CLOCK_WIDTH 35
133#else
134#define CLOCK_WIDTH 0
135#endif
136#endif
137
124struct gui_syncstatusbar statusbars; 138struct gui_syncstatusbar statusbars;
125 139
126/* Prototypes */ 140/* Prototypes */
@@ -140,9 +154,11 @@ static void gui_statusbar_led(struct screen * display);
140#endif 154#endif
141#ifdef HAVE_RECORDING 155#ifdef HAVE_RECORDING
142static void gui_statusbar_icon_recording_info(struct screen * display); 156static void gui_statusbar_icon_recording_info(struct screen * display);
157static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn, int sc, bool recscreen);
158static void gui_statusbar_timer_rep(struct screen * display);
143#endif 159#endif
144#if CONFIG_RTC 160#if CONFIG_RTC
145static void gui_statusbar_time(struct screen * display, int hour, int minute); 161static void gui_statusbar_time(struct screen * display, int hour, int minute, bool timer_display);
146#endif 162#endif
147#endif 163#endif
148 164
@@ -245,6 +261,21 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw)
245 bar->info.minute = tm->tm_min; 261 bar->info.minute = tm->tm_min;
246 } 262 }
247#endif /* CONFIG_RTC */ 263#endif /* CONFIG_RTC */
264#ifdef HAVE_RECORDING
265 struct timer* timer = get_timerstat();
266 bar->info.timer_day = timer->days;
267 bar->info.timer_hour = timer->hrs;
268 bar->info.timer_min = timer->mins;
269 /* avoid an update every second unless less than one
270 minute remains on the timer */
271 if (!bar->info.timer_day && !bar->info.timer_hour && !bar->info.timer_min)
272 bar->info.timer_sec = timer->secs;
273 else
274 bar->info.timer_sec = 0;
275
276 bar->info.timer_display = timer->timer_display;
277 bar->info.timer_repeat = timer->repeater;
278#endif
248 279
249 /* only redraw if forced to, or info has changed */ 280 /* only redraw if forced to, or info has changed */
250 if (force_redraw || bar->redraw_volume || 281 if (force_redraw || bar->redraw_volume ||
@@ -316,8 +347,16 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw)
316 if (bar->info.keylockremote) 347 if (bar->info.keylockremote)
317 gui_statusbar_icon_lock_remote(display); 348 gui_statusbar_icon_lock_remote(display);
318#endif 349#endif
350#ifdef HAVE_RECORDING
351 if (bar->info.timer_display)
352 gui_statusbar_timer(display, bar->info.timer_day, bar->info.timer_hour,
353 bar->info.timer_min, bar->info.timer_sec, recscreen_on);
354 else if ((bar->info.timer_repeat) && (recscreen_on))
355 gui_statusbar_timer_rep(display);
356#endif
319#if CONFIG_RTC 357#if CONFIG_RTC
320 gui_statusbar_time(display, bar->info.hour, bar->info.minute); 358 gui_statusbar_time(display, bar->info.hour, bar->info.minute,
359 bar->info.timer_display);
321#endif /* CONFIG_RTC */ 360#endif /* CONFIG_RTC */
322#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 361#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
323 if(!display->has_disk_led && bar->info.led) 362 if(!display->has_disk_led && bar->info.led)
@@ -577,7 +616,8 @@ static void gui_statusbar_led(struct screen * display)
577/* 616/*
578 * Print time to status bar 617 * Print time to status bar
579 */ 618 */
580static void gui_statusbar_time(struct screen * display, int hour, int minute) 619static void gui_statusbar_time(struct screen * display, int hour, int minute,
620 bool timer_display)
581{ 621{
582 unsigned char buffer[6]; 622 unsigned char buffer[6];
583 unsigned int width, height; 623 unsigned int width, height;
@@ -599,15 +639,73 @@ static void gui_statusbar_time(struct screen * display, int hour, int minute)
599 display->setfont(FONT_SYSFIXED); 639 display->setfont(FONT_SYSFIXED);
600 display->getstringsize(buffer, &width, &height); 640 display->getstringsize(buffer, &width, &height);
601 if (height <= STATUSBAR_HEIGHT) { 641 if (height <= STATUSBAR_HEIGHT) {
642#ifdef HAVE_RECORDING
643 if (timer_display)
644 display->set_drawmode(DRMODE_INVERSEVID);
645#else
646 (void)timer_display;
647#endif
602 display->putsxy(STATUSBAR_TIME_X_END(display->width) - width, 648 display->putsxy(STATUSBAR_TIME_X_END(display->width) - width,
603 STATUSBAR_Y_POS, buffer); 649 STATUSBAR_Y_POS, buffer);
604 } 650 }
651 display->set_drawmode(DRMODE_SOLID);
605 display->setfont(FONT_UI); 652 display->setfont(FONT_UI);
606 653
607} 654}
608#endif 655#endif
609 656
610#ifdef HAVE_RECORDING 657#ifdef HAVE_RECORDING
658static void gui_statusbar_timer(struct screen * display, int dy, int hr, int mn,
659 int sc, bool recscreen)
660{
661 unsigned char buffer[8];
662 int width, height;
663
664 /* vary the display depending on the remaining time to save space */
665 if (dy)
666 snprintf(buffer, sizeof(buffer), " %dd%02dh", hr > 58 ? dy + 1 : dy,
667 hr > 58 ? 0 : hr + 1);
668 else if (!hr && !mn)
669 snprintf(buffer, sizeof(buffer), "%02ds", sc);
670 else
671 snprintf(buffer, sizeof(buffer), "%02dh%02dm", mn > 58 ? hr + 1: hr,
672 mn > 58 ? 0 : mn + 1);
673
674 display->setfont(FONT_SYSFIXED);
675 display->getstringsize(buffer, &width, &height);
676
677 if (height <= STATUSBAR_HEIGHT)
678 {
679 if(((display->width) >= (STATUSBAR_LOCKR_X_POS + STATUSBAR_LOCKR_WIDTH +
680 STATUSBAR_DISK_WIDTH + width + CLOCK_WIDTH + 1))
681 && !recscreen)
682 display->putsxy(STATUSBAR_TIME_X_END(display->width) - width -
683 CLOCK_WIDTH, STATUSBAR_Y_POS, buffer);
684 /* display only an icon for small screens or when in recording screen*/
685 else if ((display->width) >= (STATUSBAR_LOCKR_X_POS +
686 STATUSBAR_LOCKR_WIDTH +
687 STATUSBAR_DISK_WIDTH +
688 TIMER_ICON_WIDTH + CLOCK_WIDTH + 1))
689 display->mono_bitmap(bitmap_icons_7x7[Icon_Timer],
690 STATUSBAR_TIME_X_END(display->width) -
691 TIMER_ICON_WIDTH - CLOCK_WIDTH,
692 STATUSBAR_Y_POS,
693 TIMER_ICON_WIDTH, STATUSBAR_HEIGHT);
694 }
695
696 display->setfont(FONT_UI);
697
698}
699
700static void gui_statusbar_timer_rep(struct screen * display)
701{
702 display->mono_bitmap(bitmap_icons_7x7[Icon_Timer_rep],
703 STATUSBAR_TIME_X_END(display->width) -
704 TIMER_ICON_WIDTH - CLOCK_WIDTH,
705 STATUSBAR_Y_POS,
706 TIMER_ICON_WIDTH, STATUSBAR_HEIGHT);
707}
708
611#if CONFIG_CODEC == SWCODEC 709#if CONFIG_CODEC == SWCODEC
612/** 710/**
613 * Write a number to the display using bitmaps and return new position 711 * Write a number to the display using bitmaps and return new position
diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h
index 21f98336d0..660c657f29 100644
--- a/apps/gui/statusbar.h
+++ b/apps/gui/statusbar.h
@@ -37,6 +37,14 @@ struct status_info {
37 int hour; 37 int hour;
38 int minute; 38 int minute;
39#endif 39#endif
40#ifdef HAVE_RECORDING
41 int timer_day;
42 int timer_hour;
43 int timer_min;
44 int timer_sec;
45 int timer_repeat;
46#endif
47 int timer_display;
40 48
41#if CONFIG_CHARGING 49#if CONFIG_CHARGING
42 bool inserted; 50 bool inserted;
diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c
index 1a3c81b989..b3586413dd 100644
--- a/apps/keymaps/keymap-h10.c
+++ b/apps/keymaps/keymap-h10.c
@@ -121,7 +121,10 @@ static const struct button_mapping button_context_settings[] = {
121 { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, 121 { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
122 { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, 122 { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
123 { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, 123 { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
124 { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE }, 124 { ACTION_SETTINGS_RESET, BUTTON_POWER, BUTTON_NONE },
125 { ACTION_NONE, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT },
126 { ACTION_NONE, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT },
127 { ACTION_STD_OK, BUTTON_PLAY, BUTTON_NONE },
125 128
126 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), 129 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
127}; /* button_context_settings */ 130}; /* button_context_settings */
@@ -303,6 +306,8 @@ static const struct button_mapping button_context_bmark[] = {
303 306
304const struct button_mapping button_context_recscreen[] = { 307const struct button_mapping button_context_recscreen[] = {
305 { ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE }, 308 { ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE },
309 { ACTION_STD_CANCEL, BUTTON_REW, BUTTON_NONE },
310
306 311
307 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) 312 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
308}; /* button_context_recscreen */ 313}; /* button_context_recscreen */
diff --git a/apps/keymaps/keymap-h1x0_h3x0.c b/apps/keymaps/keymap-h1x0_h3x0.c
index bbec420846..d3d5f8d35f 100644
--- a/apps/keymaps/keymap-h1x0_h3x0.c
+++ b/apps/keymaps/keymap-h1x0_h3x0.c
@@ -439,6 +439,10 @@ static const struct button_mapping button_context_settings_h100remote[] = {
439 { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, 439 { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
440 { ACTION_SETTINGS_DEC, BUTTON_RC_FF, BUTTON_NONE }, 440 { ACTION_SETTINGS_DEC, BUTTON_RC_FF, BUTTON_NONE },
441 { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, 441 { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE },
442 { ACTION_STD_PREV, BUTTON_RC_SOURCE, BUTTON_NONE },
443 { ACTION_STD_PREVREPEAT, BUTTON_RC_SOURCE|BUTTON_REPEAT, BUTTON_NONE },
444 { ACTION_STD_NEXT, BUTTON_RC_BITRATE, BUTTON_NONE },
445 { ACTION_STD_NEXTREPEAT, BUTTON_RC_BITRATE|BUTTON_REPEAT, BUTTON_NONE },
442/* { ACTION_NONE, BUTTON_RC_ON, BUTTON_NONE }, 446/* { ACTION_NONE, BUTTON_RC_ON, BUTTON_NONE },
443 { ACTION_NONE, BUTTON_RC_STOP, BUTTON_NONE }, 447 { ACTION_NONE, BUTTON_RC_STOP, BUTTON_NONE },
444 { ACTION_NONE, BUTTON_RC_MENU|BUTTON_REL, BUTTON_NONE }, 448 { ACTION_NONE, BUTTON_RC_MENU|BUTTON_REL, BUTTON_NONE },
@@ -451,8 +455,11 @@ static const struct button_mapping button_context_settings_h300lcdremote[] = {
451 { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, 455 { ACTION_SETTINGS_INCREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
452 { ACTION_SETTINGS_DEC, BUTTON_RC_VOL_DOWN, BUTTON_NONE }, 456 { ACTION_SETTINGS_DEC, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
453 { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, 457 { ACTION_SETTINGS_DECREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
454 { ACTION_NONE, BUTTON_RC_REW, BUTTON_NONE }, 458 { ACTION_STD_PREV, BUTTON_RC_REW, BUTTON_NONE },
455 { ACTION_NONE, BUTTON_RC_FF, BUTTON_NONE }, 459 { ACTION_STD_PREVREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
460 { ACTION_STD_NEXT, BUTTON_RC_FF, BUTTON_NONE },
461 { ACTION_STD_NEXTREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE },
462 { ACTION_SETTINGS_RESET, BUTTON_RC_ON, BUTTON_NONE },
456 463
457 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) 464 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
458}; /* button_context_settings */ 465}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-x5.c b/apps/keymaps/keymap-x5.c
index b637e1ddd1..3dc69d767c 100644
--- a/apps/keymaps/keymap-x5.c
+++ b/apps/keymaps/keymap-x5.c
@@ -219,6 +219,9 @@ static const struct button_mapping button_context_settings[] = {
219 { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE }, 219 { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE },
220 { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, 220 { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
221 { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE }, 221 { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE },
222 { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
223 { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
224 { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
222 { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE }, 225 { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE },
223 226
224 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) 227 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 69900c5e6a..66b864e0cc 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -2720,16 +2720,16 @@
2720</phrase> 2720</phrase>
2721<phrase> 2721<phrase>
2722 id: LANG_RECORD_TIMESPLIT 2722 id: LANG_RECORD_TIMESPLIT
2723 desc: Record split menu 2723 desc: Record timer menu
2724 user: 2724 user:
2725 <source> 2725 <source>
2726 *: "File Split Options" 2726 *: "File Split Options"
2727 </source> 2727 </source>
2728 <dest> 2728 <dest>
2729 *: "File Split Options" 2729 *: "Timer Options"
2730 </dest> 2730 </dest>
2731 <voice> 2731 <voice>
2732 *: "File Split Options" 2732 *: "Timer Options"
2733 </voice> 2733 </voice>
2734</phrase> 2734</phrase>
2735<phrase> 2735<phrase>
@@ -10741,3 +10741,97 @@
10741 *: "Context Menu" 10741 *: "Context Menu"
10742 </voice> 10742 </voice>
10743</phrase> 10743</phrase>
10744<phrase>
10745 id: LANG_MULTIINT_CONFIRM
10746 desc: Confirm string for multi_int settings
10747 user:
10748 <source>
10749 *: "Press PLAY to confirm"
10750 </source>
10751 <dest>
10752 *: "Press PLAY to confirm"
10753 h100,h120,h300: "Press NAVI to confirm"
10754 ipod*,x5,gigabeat: "Press SELECT to confirm"
10755 </dest>
10756 <voice>
10757 *: ""
10758 </voice>
10759</phrase>
10760<phrase>
10761 id: LANG_TIMER_SET
10762 desc: Recording timer menu
10763 <source>
10764 *: "Set countdown timer"
10765 </source>
10766 <dest>
10767 *: "Set countdown timer"
10768 </dest>
10769 <voice>
10770 *: "Set countdown timer"
10771 </voice>
10772</phrase>
10773<phrase>
10774 id: LANG_TIMER_REPEAT
10775 desc: Recording timer menu
10776 <source>
10777 *: "Record repeat timer"
10778 </source>
10779 <dest>
10780 *: "Record repeat timer"
10781 </dest>
10782 <voice>
10783 *: "Record repeat timer"
10784 </voice>
10785</phrase>
10786<phrase>
10787 id: LANG_TIMER_DAYS
10788 desc: recording timer settings string
10789 <source>
10790 *: "Days"
10791 </source>
10792 <dest>
10793 *: "Days"
10794 </dest>
10795 <voice>
10796 *: "Days"
10797 </voice>
10798</phrase>
10799<phrase>
10800 id: LANG_TIMER_HRS
10801 desc: recording timer settings string
10802 <source>
10803 *: "Hrs"
10804 </source>
10805 <dest>
10806 *: "Hrs"
10807 </dest>
10808 <voice>
10809 *: "Hours"
10810 </voice>
10811</phrase>
10812<phrase>
10813 id: LANG_TIMER_MINS
10814 desc: recording timer settings string
10815 <source>
10816 *: "Mins"
10817 </source>
10818 <dest>
10819 *: "Mins"
10820 </dest>
10821 <voice>
10822 *: "Minutes"
10823 </voice>
10824</phrase>
10825<phrase>
10826 id: LANG_REC_TIMER
10827 desc: recording screen timer string
10828 <source>
10829 *: "Timer"
10830 </source>
10831 <dest>
10832 *: "Timer"
10833 </dest>
10834 <voice>
10835 *: "Timer"
10836 </voice>
10837</phrase>
diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c
index 1bc84e90d2..d37fe39bfe 100644
--- a/apps/menus/recording_menu.c
+++ b/apps/menus/recording_menu.c
@@ -42,6 +42,7 @@
42#include "sound.h" 42#include "sound.h"
43#ifdef HAVE_RECORDING 43#ifdef HAVE_RECORDING
44#include "audio.h" 44#include "audio.h"
45#include "recording.h"
45#if CONFIG_TUNER 46#if CONFIG_TUNER
46#include "radio.h" 47#include "radio.h"
47#endif 48#endif
@@ -305,12 +306,78 @@ MENUITEM_SETTING(rec_quality, &global_settings.rec_quality, NULL);
305MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL); 306MENUITEM_SETTING(rec_editable, &global_settings.rec_editable, NULL);
306#endif 307#endif
307 308
309/* Displays a menu for changing the countdown timer settings */
310static int countdown_timer_func(void)
311{
312 bool retval;
313 bool changed = false;
314 struct timer* timer = get_timerstat();
315
316 static const struct opt_items names[] = {
317 { STR(LANG_TIMER_DAYS) },
318 { STR(LANG_TIMER_HRS) },
319 { STR(LANG_TIMER_MINS) }
320 };
321
322 struct opt_settings settings[] = {
323 { &timer->days, 6 },
324 { &timer->hrs, 23 },
325 { &timer->mins, 59 }
326 };
327
328 retval = set_multi_int(str(LANG_TIMER_SET), names, settings, 3, &changed);
329
330 if (changed)
331 {
332 timer->countdown = false;
333 timer->secs = 0;
334 timer->timer_display = false;
335 }
336
337 return retval;
338}
339
340static int countdown_timer_repeat_func(void)
341{
342 struct timer* timer = get_timerstat();
343 bool retval;
344
345 static const struct opt_items names[] = {
346 { STR(LANG_TIMER_DAYS) },
347 { STR(LANG_TIMER_HRS) },
348 { STR(LANG_TIMER_MINS) }
349 };
350
351 struct opt_settings settings[] = {
352 { &timer->days_rpt, 6 },
353 { &timer->hrs_rpt, 23 },
354 { &timer->mins_rpt, 59 }
355 };
356 retval = set_multi_int(str(LANG_TIMER_REPEAT), names, settings, 3, NULL);
357
358 /* automatically select settings necessary for repeated recording */
359 if (timer->days_rpt || timer->hrs_rpt || timer->mins_rpt)
360 {
361 global_settings.rec_split_type = 1; /* Stop */
362 global_settings.rec_split_method = 0; /* Time */
363 global_settings.rec_trigger_mode = 0; /* The repeat timer isn't
364 compatible with the trigger */
365 }
366
367 return retval;
368}
369
370MENUITEM_FUNCTION(countdown_timer, 0, ID2P(LANG_TIMER_SET),
371 countdown_timer_func, NULL, NULL, Icon_Menu_setting);
372MENUITEM_FUNCTION(countdown_timer_repeat, 0, ID2P(LANG_TIMER_REPEAT),
373 countdown_timer_repeat_func, NULL, NULL, Icon_Menu_setting);
308MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL); 374MENUITEM_SETTING(rec_split_type, &global_settings.rec_split_type, NULL);
309MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL); 375MENUITEM_SETTING(rec_split_method, &global_settings.rec_split_method, NULL);
310MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL); 376MENUITEM_SETTING(rec_timesplit, &global_settings.rec_timesplit, NULL);
311MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL); 377MENUITEM_SETTING(rec_sizesplit, &global_settings.rec_sizesplit, NULL);
312MAKE_MENU(filesplitoptionsmenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON, 378MAKE_MENU(timermenu, ID2P(LANG_RECORD_TIMESPLIT), NULL, Icon_NOICON,
313 &rec_split_method, &rec_split_type, &rec_timesplit, &rec_sizesplit); 379 &countdown_timer, &countdown_timer_repeat, &rec_split_method,
380 &rec_split_type, &rec_timesplit, &rec_sizesplit);
314 381
315 382
316MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL); 383MENUITEM_SETTING(rec_prerecord_time, &global_settings.rec_prerecord_time, NULL);
@@ -819,7 +886,7 @@ MAKE_MENU(recording_setting_menu, ID2P(LANG_RECORDING_SETTINGS), NULL, Icon_Reco
819#if CONFIG_CODEC == MAS3587F 886#if CONFIG_CODEC == MAS3587F
820 &rec_editable, 887 &rec_editable,
821#endif 888#endif
822 &filesplitoptionsmenu, 889 &timermenu,
823 &rec_prerecord_time, 890 &rec_prerecord_time,
824 &recdirectory, 891 &recdirectory,
825#ifdef HAVE_BACKLIGHT 892#ifdef HAVE_BACKLIGHT
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index ccb42d5919..bf6500fb1f 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -44,6 +44,14 @@ const unsigned char bitmap_icons_5x8[][5] =
44#endif 44#endif
45}; 45};
46 46
47const unsigned char bitmap_icons_7x7[][7] =
48{
49 [Icon_Timer] =
50 {0x1c, 0x22, 0x41, 0x4f, 0x49, 0x22, 0x1d}, /* Recording timer icon */
51 [Icon_Timer_rep]=
52 {0x17, 0x26, 0x45, 0x41, 0x51, 0x32, 0x74}, /* Recording repeat timer icon */
53};
54
47const unsigned char bitmap_icons_6x8[][6] = 55const unsigned char bitmap_icons_6x8[][6] =
48{ 56{
49 { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */ 57 { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */
@@ -159,7 +167,7 @@ const unsigned char bitmap_icon_disk[12] =
159#ifdef HAVE_MMC 167#ifdef HAVE_MMC
160 {0x15,0x3f,0x7d,0x7B,0x77,0x67,0x79,0x7b,0x57,0x4f,0x47,0x7f}; 168 {0x15,0x3f,0x7d,0x7B,0x77,0x67,0x79,0x7b,0x57,0x4f,0x47,0x7f};
161#else 169#else
162 {0x00,0x00,0x00,0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00}; 170 {0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00,0x00,0x00,0x00};
163#endif 171#endif
164 172
165/* 173/*
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 7682d44733..09aadf0888 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -49,6 +49,12 @@ enum icons_5x8 {
49 Icon5x8Last 49 Icon5x8Last
50}; 50};
51 51
52enum icons_7x7 {
53 Icon_Timer,
54 Icon_Timer_rep,
55 Icon7x7Last
56};
57
52/* If any icons are added to this enum, they must be 58/* If any icons are added to this enum, they must be
53 added to the unused_but_needed enum in ../player/icons.h */ 59 added to the unused_but_needed enum in ../player/icons.h */
54enum icons_6x8 { 60enum icons_6x8 {
@@ -144,6 +150,7 @@ extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18];
144#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ 150#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
145 151
146extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; 152extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5];
153extern const unsigned char bitmap_icons_7x7[Icon7x7Last][7];
147extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; 154extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6];
148extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; 155extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7];
149extern const unsigned char bitmap_icon_disk[]; 156extern const unsigned char bitmap_icon_disk[];
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 025480cf91..7a332228e5 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -70,6 +70,8 @@
70#include "radio.h" 70#include "radio.h"
71#ifdef HAVE_RECORDING 71#ifdef HAVE_RECORDING
72 72
73static struct timer timer;
74
73static bool in_screen = false; 75static bool in_screen = false;
74 76
75bool in_recording_screen(void) 77bool in_recording_screen(void)
@@ -745,6 +747,37 @@ static void trigger_listener(int trigger_status)
745 } 747 }
746} 748}
747 749
750/* countdown timer tick task */
751void timer_tick_task(void)
752{
753 static int mini_tick = 0;
754
755 mini_tick ++;
756 /* the countdown */
757 if ((mini_tick >= HZ) && (timer.countdown))
758 {
759 mini_tick = 0;
760 if (timer.secs) timer.secs -= 1;
761 else{
762 timer.secs = 59;
763 if (timer.mins) timer.mins -= 1;
764 else{
765 timer.mins = 59;
766 if (timer.hrs) timer.hrs -= 1;
767 else{
768 timer.hrs = 23;
769 if (timer.days) timer.days -= 1;
770 else{
771 timer.days = timer.hrs = timer.mins = timer.secs = 0;
772 /* switch timer display on/off when countdown finished */
773 timer.timer_display = !timer.timer_display;
774 }
775 }
776 }
777 }
778 }
779}
780
748bool recording_start_automatic = false; 781bool recording_start_automatic = false;
749 782
750bool recording_screen(bool no_source) 783bool recording_screen(bool no_source)
@@ -756,7 +789,7 @@ bool recording_screen(bool no_source)
756 int w, h; 789 int w, h;
757 int update_countdown = 1; 790 int update_countdown = 1;
758 bool have_recorded = false; 791 bool have_recorded = false;
759 unsigned int seconds; 792 unsigned int seconds, prerec = 0;
760 int hours, minutes; 793 int hours, minutes;
761 char filename[13]; 794 char filename[13];
762 bool been_in_usb_mode = false; 795 bool been_in_usb_mode = false;
@@ -793,6 +826,9 @@ bool recording_screen(bool no_source)
793 int trig_xpos[NB_SCREENS]; 826 int trig_xpos[NB_SCREENS];
794 int trig_ypos[NB_SCREENS]; 827 int trig_ypos[NB_SCREENS];
795 int trig_width[NB_SCREENS]; 828 int trig_width[NB_SCREENS];
829 int countdown_offset = 0;
830 bool repeat_timer_start = false;
831 unsigned int repeat_timer;
796 832
797 static const unsigned char *byte_units[] = { 833 static const unsigned char *byte_units[] = {
798 ID2P(LANG_BYTE), 834 ID2P(LANG_BYTE),
@@ -804,6 +840,11 @@ bool recording_screen(bool no_source)
804 struct audio_recording_options rec_options; 840 struct audio_recording_options rec_options;
805 841
806 in_screen = true; 842 in_screen = true;
843
844 /* Stop countdown if countdown settings changed */
845 if (!timer.countdown)
846 tick_remove_task(timer_tick_task);
847
807 cursor = 0; 848 cursor = 0;
808#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) 849#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
809 ata_set_led_enabled(false); 850 ata_set_led_enabled(false);
@@ -937,6 +978,25 @@ bool recording_screen(bool no_source)
937 last_audio_stat = audio_stat; 978 last_audio_stat = audio_stat;
938 } 979 }
939 980
981 /* repeat_timer is the repeat time in seconds */
982 repeat_timer = (timer.mins_rpt * 60 + timer.hrs_rpt *
983 3600 + timer.days_rpt * 3600 * 24);
984
985 /* decide on repeat timer status */
986 if ((repeat_timer > rec_timesplit_seconds()) &&
987 global_settings.rec_timesplit)
988 timer.repeater = true;
989 else
990 timer.repeater = false;
991
992 /* When countdown timer reaches zero fake a new file button press */
993 if (timer.countdown && !timer.days && !timer.hrs && !timer.mins &&
994 !timer.secs)
995 {
996 tick_remove_task(timer_tick_task);
997 button = ACTION_REC_NEWFILE;
998 timer.countdown = false;
999 }
940 1000
941 if (recording_start_automatic) 1001 if (recording_start_automatic)
942 { 1002 {
@@ -991,7 +1051,27 @@ bool recording_screen(bool no_source)
991 case ACTION_REC_NEWFILE: 1051 case ACTION_REC_NEWFILE:
992 /* Only act if the mpeg is stopped */ 1052 /* Only act if the mpeg is stopped */
993 if(!(audio_stat & AUDIO_STATUS_RECORD)) 1053 if(!(audio_stat & AUDIO_STATUS_RECORD))
994 { 1054 { /* if countdown timer is set, start countdown */
1055 if (timer.days || timer.hrs || timer.mins || timer.secs)
1056 {
1057 if (button == ACTION_REC_PAUSE)
1058 {
1059 timer.countdown = !timer.countdown;
1060 if (timer.countdown)
1061 tick_add_task(timer_tick_task);
1062 else
1063 tick_remove_task(timer_tick_task);
1064 break;
1065 }
1066 else
1067 {
1068 /* if newfile button pressed and countdown timer is on,
1069 start new file and reset timer */
1070 tick_remove_task(timer_tick_task);
1071 timer.days = timer.hrs = timer.mins = timer.secs = 0;
1072 timer.countdown = false;
1073 }
1074 }
995 /* is this manual or triggered recording? */ 1075 /* is this manual or triggered recording? */
996 if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) || 1076 if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) ||
997 (peak_meter_trigger_status() != TRIG_OFF)) 1077 (peak_meter_trigger_status() != TRIG_OFF))
@@ -999,6 +1079,11 @@ bool recording_screen(bool no_source)
999 /* manual recording */ 1079 /* manual recording */
1000 have_recorded = true; 1080 have_recorded = true;
1001 rec_record(); 1081 rec_record();
1082 repeat_timer_start = true; /* allow access to repeat timer
1083 code */
1084 /* amount of file that has been prerecorded - needed for
1085 syncing repeat timer */
1086 prerec = audio_recorded_time() / HZ;
1002 last_seconds = 0; 1087 last_seconds = 0;
1003 if (talk_menu) 1088 if (talk_menu)
1004 { /* no voice possible here, but a beep */ 1089 { /* no voice possible here, but a beep */
@@ -1197,7 +1282,6 @@ bool recording_screen(bool no_source)
1197#ifdef HAVE_FMRADIO_IN 1282#ifdef HAVE_FMRADIO_IN
1198 const int prev_rec_source = global_settings.rec_source; 1283 const int prev_rec_source = global_settings.rec_source;
1199#endif 1284#endif
1200
1201#if (CONFIG_LED == LED_REAL) 1285#if (CONFIG_LED == LED_REAL)
1202 /* led is restored at begin of loop / end of function */ 1286 /* led is restored at begin of loop / end of function */
1203 led(false); 1287 led(false);
@@ -1221,6 +1305,10 @@ bool recording_screen(bool no_source)
1221 && prev_rec_source == AUDIO_SRC_FMRADIO) 1305 && prev_rec_source == AUDIO_SRC_FMRADIO)
1222 radio_status = FMRADIO_OFF; 1306 radio_status = FMRADIO_OFF;
1223#endif 1307#endif
1308 /* if countdown timer settings changed in menu,
1309 stop counting and reset */
1310 if (!timer.countdown)
1311 tick_remove_task(timer_tick_task);
1224 1312
1225#if CONFIG_CODEC == SWCODEC 1313#if CONFIG_CODEC == SWCODEC
1226 /* reinit after submenu exit */ 1314 /* reinit after submenu exit */
@@ -1319,6 +1407,9 @@ bool recording_screen(bool no_source)
1319 break; 1407 break;
1320 } /* end switch */ 1408 } /* end switch */
1321 1409
1410 /* display timer status in status bar if countdown enabled */
1411 timer.timer_display = timer.countdown;
1412
1322#ifdef HAVE_AGC 1413#ifdef HAVE_AGC
1323 peak_read = !peak_read; 1414 peak_read = !peak_read;
1324 if (peak_read) { /* every 2nd run of loop */ 1415 if (peak_read) { /* every 2nd run of loop */
@@ -1369,11 +1460,13 @@ bool recording_screen(bool no_source)
1369#endif /* CONFIG_CODEC == SWCODEC */ 1460#endif /* CONFIG_CODEC == SWCODEC */
1370 if ((global_settings.rec_sizesplit) && (global_settings.rec_split_method)) 1461 if ((global_settings.rec_sizesplit) && (global_settings.rec_split_method))
1371 { 1462 {
1463 countdown_offset = 1;
1372 dmb = dsize/1024/1024; 1464 dmb = dsize/1024/1024;
1373 snprintf(buf, sizeof(buf), "%s %dMB", 1465 snprintf(buf, sizeof(buf), "%s %dMB",
1374 str(LANG_SYSFONT_SPLIT_SIZE), dmb); 1466 str(LANG_SYSFONT_SPLIT_SIZE), dmb);
1375 } 1467 }
1376 else 1468 /* only display recording time if countdown timer is off */
1469 else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs)
1377 { 1470 {
1378 hours = seconds / 3600; 1471 hours = seconds / 3600;
1379 minutes = (seconds - (hours * 3600)) / 60; 1472 minutes = (seconds - (hours * 3600)) / 60;
@@ -1381,6 +1474,11 @@ bool recording_screen(bool no_source)
1381 str(LANG_SYSFONT_RECORDING_TIME), 1474 str(LANG_SYSFONT_RECORDING_TIME),
1382 hours, minutes, seconds%60); 1475 hours, minutes, seconds%60);
1383 } 1476 }
1477 else
1478 {
1479 countdown_offset = 0;
1480 snprintf(buf, 32, "");
1481 }
1384 1482
1385 for(i = 0; i < screen_update; i++) 1483 for(i = 0; i < screen_update; i++)
1386 screens[i].puts(0, 0, buf); 1484 screens[i].puts(0, 0, buf);
@@ -1404,7 +1502,8 @@ bool recording_screen(bool no_source)
1404 str(LANG_SYSFONT_RECORD_TIMESPLIT_REC), 1502 str(LANG_SYSFONT_RECORD_TIMESPLIT_REC),
1405 dhours, dminutes); 1503 dhours, dminutes);
1406 } 1504 }
1407 else 1505 /* only display recording size if countdown timer is off */
1506 else if (!timer.days && !timer.hrs && !timer.mins && !timer.secs)
1408 { 1507 {
1409 output_dyn_value(buf2, sizeof buf2, 1508 output_dyn_value(buf2, sizeof buf2,
1410 num_recorded_bytes, 1509 num_recorded_bytes,
@@ -1416,6 +1515,16 @@ bool recording_screen(bool no_source)
1416 for(i = 0; i < screen_update; i++) 1515 for(i = 0; i < screen_update; i++)
1417 screens[i].puts(0, 1, buf); 1516 screens[i].puts(0, 1, buf);
1418 1517
1518 /* display countdown timer if set */
1519 if (timer.days || timer.hrs || timer.mins || timer.secs)
1520 {
1521 snprintf(buf, 32, "%s %d:%02d:%02d:%02d", str(LANG_REC_TIMER),
1522 timer.days, timer.hrs, timer.mins, timer.secs);
1523
1524 for(i = 0; i < screen_update; i++)
1525 screens[i].puts(0, countdown_offset, buf);
1526 }
1527
1419 for(i = 0; i < screen_update; i++) 1528 for(i = 0; i < screen_update; i++)
1420 { 1529 {
1421 if (filename_offset[i] > 0) 1530 if (filename_offset[i] > 0)
@@ -1449,11 +1558,36 @@ bool recording_screen(bool no_source)
1449 rec_new_file(); 1558 rec_new_file();
1450 last_seconds = 0; 1559 last_seconds = 0;
1451 } 1560 }
1452 else 1561 else if (repeat_timer_start)
1453 { 1562 {
1454 peak_meter_trigger(false); 1563 peak_meter_trigger(false);
1455 peak_meter_set_trigger_listener(NULL); 1564 peak_meter_set_trigger_listener(NULL);
1456 audio_stop_recording(); 1565 audio_stop_recording();
1566
1567 /* stop any more attempts to access this code until a new
1568 recording is started */
1569 repeat_timer_start = false;
1570
1571 /* start repeat countdown if set and only if
1572 stop time < repeat time */
1573 if (timer.repeater)
1574 {
1575 repeat_timer -= dseconds;
1576 timer.days = repeat_timer / (3600 * 24);
1577 timer.hrs = (repeat_timer - (timer.days * 3600 * 24)) /
1578 3600;
1579 timer.mins = (repeat_timer - (timer.hrs * 3600)) / 60;
1580 timer.secs = prerec; /* add prerecorded time to timer */
1581
1582 /* This is not really a toggle so much as a safety feature
1583 so that it is impossible to start the timer more than
1584 once */
1585 timer.countdown = !timer.countdown;
1586 if (timer.countdown)
1587 tick_add_task(timer_tick_task);
1588 else
1589 tick_remove_task(timer_tick_task);
1590 }
1457 } 1591 }
1458 update_countdown = 1; 1592 update_countdown = 1;
1459 } 1593 }
@@ -2035,6 +2169,12 @@ static bool f3_rec_screen(void)
2035} 2169}
2036#endif /* CONFIG_KEYPAD == RECORDER_PAD */ 2170#endif /* CONFIG_KEYPAD == RECORDER_PAD */
2037 2171
2172struct timer *get_timerstat(void)
2173{
2174 return &timer;
2175}
2176
2177
2038#if CONFIG_CODEC == SWCODEC 2178#if CONFIG_CODEC == SWCODEC
2039void audio_beep(int duration) 2179void audio_beep(int duration)
2040{ 2180{
diff --git a/apps/recorder/recording.h b/apps/recorder/recording.h
index 3ca1f35834..4fba37b68a 100644
--- a/apps/recorder/recording.h
+++ b/apps/recorder/recording.h
@@ -25,6 +25,22 @@ bool recording_screen(bool no_source);
25char *rec_create_filename(char *buf); 25char *rec_create_filename(char *buf);
26int rec_create_directory(void); 26int rec_create_directory(void);
27 27
28struct timer
29{
30 bool countdown;
31 bool timer_display;
32 unsigned int days;
33 unsigned int hrs;
34 unsigned int mins;
35 unsigned int secs;
36 unsigned int days_rpt;
37 unsigned int hrs_rpt;
38 unsigned int mins_rpt;
39 bool repeater;
40};
41
42struct timer *get_timerstat(void);
43
28/* If true, start recording automatically when recording_sreen() is entered */ 44/* If true, start recording automatically when recording_sreen() is entered */
29extern bool recording_start_automatic; 45extern bool recording_start_automatic;
30 46
@@ -33,6 +49,7 @@ extern bool recording_start_automatic;
33void rec_set_source(int source, unsigned flags); 49void rec_set_source(int source, unsigned flags);
34#endif /* CONFIG_CODEC == SW_CODEC */ 50#endif /* CONFIG_CODEC == SW_CODEC */
35 51
52struct audio_recording_options;
36/* Initializes a recording_options structure with global settings. 53/* Initializes a recording_options structure with global settings.
37 pass returned data to audio_set_recording_options or 54 pass returned data to audio_set_recording_options or
38 rec_set_recording_options */ 55 rec_set_recording_options */
diff --git a/apps/settings.c b/apps/settings.c
index 23b81173bd..e8963b05df 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -1245,6 +1245,194 @@ bool set_int(const unsigned char* string,
1245 return set_int_ex(string, unit, voice_unit, variable, function, 1245 return set_int_ex(string, unit, voice_unit, variable, function,
1246 step, min, max, formatter, NULL); 1246 step, min, max, formatter, NULL);
1247} 1247}
1248
1249/* Useful for time and other multi integer settings */
1250bool set_multi_int(const char* string,
1251 const struct opt_items * names,
1252 struct opt_settings * variable,
1253 int varcount,
1254 bool *changes_accepted)
1255{
1256 int i, j, w, h;
1257 char buf[32];
1258 long button;
1259 int cursor = 0;
1260 bool done = false;
1261 int value[varcount];
1262 int pos = 0;
1263
1264 /* store current values in temp array */
1265 for(j = 0; j < varcount; j++)
1266 value[j] = *(int*)variable[j].setting;
1267
1268 /* initialize screen */
1269 FOR_NB_SCREENS(i)
1270 {
1271 screens[i].clear_display();
1272#ifdef HAVE_LCD_BITMAP
1273 screens[i].setmargins(0, 8);
1274#endif
1275 }
1276
1277 gui_syncstatusbar_draw(&statusbars, true);
1278
1279 FOR_NB_SCREENS(i)
1280 screens[i].getstringsize("3", &w, &h);
1281
1282 /* print title */
1283 snprintf(buf, sizeof(buf), "%s", string);
1284 FOR_NB_SCREENS(i)
1285 screens[i].puts(0, 0, buf);
1286
1287 /* print variable names */
1288 for(j = 0; j < varcount ; j++)
1289 {
1290 if (j > 0)
1291 {
1292 snprintf(buf, sizeof(buf), ":");
1293 FOR_NB_SCREENS(i)
1294 screens[i].puts(pos - 2, 1, buf);
1295 }
1296
1297 snprintf(buf, sizeof(buf), "%s", P2STR(names[j].string));
1298 FOR_NB_SCREENS(i)
1299 screens[i].puts(pos, 1, buf);
1300
1301 pos += strlen(buf) + 3;
1302 }
1303
1304 /* print button instructions */
1305 snprintf(buf, sizeof(buf), "%s", str(LANG_MULTIINT_CONFIRM));
1306 FOR_NB_SCREENS(i)
1307 screens[i].puts(0, 5, buf);
1308
1309 while(!done)
1310 {
1311 pos = 0;
1312
1313 /* print variables */
1314 for(j = 0; j < varcount; j++)
1315 {
1316 if (j > 0)
1317 {
1318 snprintf(buf, sizeof(buf), " :");
1319 FOR_NB_SCREENS(i)
1320 screens[i].puts(pos - 3, 3, buf);
1321 }
1322
1323 snprintf(buf, sizeof(buf), "%d", value[j]);
1324
1325 FOR_NB_SCREENS(i)
1326 screens[i].puts(pos, 3, buf);
1327
1328 snprintf(buf, sizeof(buf), "%d", variable[j].setting_max);
1329
1330#ifdef HAVE_LCD_BITMAP
1331 /* highlight currently selected integer */
1332 if (cursor == j)
1333 {
1334 FOR_NB_SCREENS(i)
1335 {
1336 screens[i].set_drawmode(DRMODE_COMPLEMENT);
1337 screens[i].fillrect(pos * w - 1, 8 + 3 * h,
1338 strlen(buf)*w + 1, h);
1339 screens[i].set_drawmode(DRMODE_SOLID);
1340 }
1341 }
1342#endif
1343
1344 pos += strlen(buf) + 3;
1345 }
1346
1347#ifdef HAVE_LCD_BITMAP
1348 FOR_NB_SCREENS(i)
1349 screens[i].update();
1350#endif
1351
1352 button = get_action(CONTEXT_SETTINGS, TIMEOUT_BLOCK);
1353
1354 switch (button)
1355 {
1356 case ACTION_STD_NEXT:
1357 cursor ++;
1358
1359 if (cursor >= varcount)
1360 cursor = varcount - 1;
1361
1362 if (global_settings.talk_menu)
1363 talk_id(names[cursor].voice_id, false);
1364 break;
1365
1366 case ACTION_STD_PREV:
1367 /* cancel if pressing left when cursor
1368 is already at the far left */
1369 if (cursor == 0)
1370 {
1371 *changes_accepted = false;
1372 gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
1373 done = true;
1374 }
1375 else
1376 {
1377 cursor --;
1378
1379 if (cursor < 0)
1380 cursor = 0;
1381
1382 if (global_settings.talk_menu)
1383 talk_id(names[cursor].voice_id, false);
1384 }
1385 break;
1386
1387 case ACTION_SETTINGS_INC:
1388 case ACTION_SETTINGS_INCREPEAT:
1389 value[cursor] += 1;
1390
1391 if (value[cursor] > variable[cursor].setting_max)
1392 value[cursor] = 0;
1393
1394 if (global_settings.talk_menu)
1395 talk_unit(INT, value[cursor], NULL);
1396 break;
1397
1398 case ACTION_SETTINGS_DEC:
1399 case ACTION_SETTINGS_DECREPEAT:
1400 value[cursor] -= 1;
1401
1402 if (value[cursor] < 0)
1403 value[cursor] = variable[cursor].setting_max;
1404
1405 if (global_settings.talk_menu)
1406 talk_unit(INT, value[cursor], NULL);
1407 break;
1408
1409 case ACTION_STD_OK:
1410 *changes_accepted = true;
1411 done = true;
1412 break;
1413
1414 case ACTION_STD_CANCEL:
1415 *changes_accepted = false;
1416 gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
1417 done = true;
1418
1419 default:
1420 if (default_event_handler(button) == SYS_USB_CONNECTED)
1421 return true;
1422 }
1423 }
1424 /* store values if accepted */
1425 if(*changes_accepted)
1426 {
1427 for(j = 0; j < varcount; j++)
1428 *(int*)variable[j].setting = value[j];
1429 }
1430
1431 action_signalscreenchange();
1432
1433 return false;
1434}
1435
1248/* NOTE: the 'type' parameter specifies the actual type of the variable 1436/* NOTE: the 'type' parameter specifies the actual type of the variable
1249 that 'variable' points to. not the value within. Only variables with 1437 that 'variable' points to. not the value within. Only variables with
1250 type 'bool' should use parameter BOOL. 1438 type 'bool' should use parameter BOOL.
diff --git a/apps/settings.h b/apps/settings.h
index 33dfb8546a..9b1124dbae 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -247,6 +247,12 @@ struct opt_items {
247 unsigned const char* string; 247 unsigned const char* string;
248 long voice_id; 248 long voice_id;
249}; 249};
250
251struct opt_settings {
252 int* setting;
253 int setting_max;
254};
255
250const struct settings_list* find_setting(void* variable, int *id); 256const struct settings_list* find_setting(void* variable, int *id);
251bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len); 257bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len);
252void talk_setting(void *global_settings_variable); 258void talk_setting(void *global_settings_variable);
@@ -264,6 +270,9 @@ bool set_int(const unsigned char* string, const char* unit, int voice_unit,
264 int* variable, 270 int* variable,
265 void (*function)(int), int step, int min, int max, 271 void (*function)(int), int step, int min, int max,
266 void (*formatter)(char*, int, int, const char*) ); 272 void (*formatter)(char*, int, int, const char*) );
273bool set_multi_int(const char* string, const struct opt_items * names,
274 struct opt_settings * variable, int varcount,
275 bool * changes_accepted);
267/* use this one if you need to create a lang from the value (i.e with TALK_ID()) */ 276/* use this one if you need to create a lang from the value (i.e with TALK_ID()) */
268bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit, 277bool set_int_ex(const unsigned char* string, const char* unit, int voice_unit,
269 int* variable, 278 int* variable,