diff options
-rw-r--r-- | apps/gui/list.c | 91 | ||||
-rw-r--r-- | apps/gui/list.h | 31 | ||||
-rw-r--r-- | apps/lang/english.lang | 14 |
3 files changed, 132 insertions, 4 deletions
diff --git a/apps/gui/list.c b/apps/gui/list.c index 52c1e4a3b9..d9725e451a 100644 --- a/apps/gui/list.c +++ b/apps/gui/list.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "lang.h" | 36 | #include "lang.h" |
37 | #include "sound.h" | 37 | #include "sound.h" |
38 | #include "misc.h" | 38 | #include "misc.h" |
39 | #include "talk.h" | ||
39 | 40 | ||
40 | #ifdef HAVE_LCD_CHARCELLS | 41 | #ifdef HAVE_LCD_CHARCELLS |
41 | #define SCROLL_LIMIT 1 | 42 | #define SCROLL_LIMIT 1 |
@@ -78,6 +79,7 @@ static void gui_list_init(struct gui_list * gui_list, | |||
78 | { | 79 | { |
79 | gui_list->callback_get_item_icon = NULL; | 80 | gui_list->callback_get_item_icon = NULL; |
80 | gui_list->callback_get_item_name = callback_get_item_name; | 81 | gui_list->callback_get_item_name = callback_get_item_name; |
82 | gui_list->callback_speak_item = NULL; | ||
81 | gui_list->display = NULL; | 83 | gui_list->display = NULL; |
82 | gui_list_set_nb_items(gui_list, 0); | 84 | gui_list_set_nb_items(gui_list, 0); |
83 | gui_list->selected_item = 0; | 85 | gui_list->selected_item = 0; |
@@ -95,6 +97,7 @@ static void gui_list_init(struct gui_list * gui_list, | |||
95 | 97 | ||
96 | gui_list->last_displayed_selected_item = -1 ; | 98 | gui_list->last_displayed_selected_item = -1 ; |
97 | gui_list->last_displayed_start_item = -1 ; | 99 | gui_list->last_displayed_start_item = -1 ; |
100 | gui_list->scheduled_talk_tick = gui_list->last_talked_tick = 0; | ||
98 | gui_list->show_selection_marker = true; | 101 | gui_list->show_selection_marker = true; |
99 | 102 | ||
100 | #ifdef HAVE_LCD_COLOR | 103 | #ifdef HAVE_LCD_COLOR |
@@ -786,6 +789,12 @@ void gui_synclist_set_icon_callback(struct gui_synclist * lists, | |||
786 | } | 789 | } |
787 | } | 790 | } |
788 | 791 | ||
792 | void gui_synclist_set_voice_callback(struct gui_synclist * lists, | ||
793 | list_speak_item voice_callback) | ||
794 | { | ||
795 | gui_list_set_voice_callback(&(lists->gui_list[0]), voice_callback); | ||
796 | } | ||
797 | |||
789 | void gui_synclist_draw(struct gui_synclist * lists) | 798 | void gui_synclist_draw(struct gui_synclist * lists) |
790 | { | 799 | { |
791 | int i; | 800 | int i; |
@@ -863,6 +872,43 @@ static void gui_synclist_scroll_left(struct gui_synclist * lists) | |||
863 | } | 872 | } |
864 | #endif /* HAVE_LCD_BITMAP */ | 873 | #endif /* HAVE_LCD_BITMAP */ |
865 | 874 | ||
875 | static void _gui_synclist_speak_item(struct gui_synclist *lists, bool repeating) | ||
876 | { | ||
877 | struct gui_list *l = &lists->gui_list[0]; | ||
878 | list_speak_item *cb = l->callback_speak_item; | ||
879 | if(cb && gui_synclist_get_nb_items(lists) != 0) | ||
880 | { | ||
881 | int sel = gui_synclist_get_sel_pos(lists); | ||
882 | talk_shutup(); | ||
883 | /* If we got a repeating key action, or we have just very | ||
884 | recently started talking, then we want to stay silent for a | ||
885 | while until things settle. Likewise if we already had a | ||
886 | pending scheduled announcement not yet due: we need to | ||
887 | reschedule it. */ | ||
888 | if(repeating | ||
889 | || (l->scheduled_talk_tick | ||
890 | && TIME_BEFORE(current_tick, l->scheduled_talk_tick)) | ||
891 | || (l->last_talked_tick | ||
892 | && TIME_BEFORE(current_tick, l->last_talked_tick +HZ/4))) | ||
893 | { | ||
894 | l->scheduled_talk_tick = current_tick +HZ/4; | ||
895 | return; | ||
896 | } else { | ||
897 | l->scheduled_talk_tick = 0; /* work done */ | ||
898 | cb(sel, l->data); | ||
899 | l->last_talked_tick = current_tick; | ||
900 | } | ||
901 | } | ||
902 | } | ||
903 | void gui_synclist_speak_item(struct gui_synclist * lists) | ||
904 | /* The list user should call this to speak the first item on entering | ||
905 | the list, and whenever the list is updated. */ | ||
906 | { | ||
907 | if(gui_synclist_get_nb_items(lists) == 0 && global_settings.talk_menu) | ||
908 | talk_id(VOICE_EMPTY_LIST, true); | ||
909 | else _gui_synclist_speak_item(lists, false); | ||
910 | } | ||
911 | |||
866 | extern intptr_t get_action_data(void); | 912 | extern intptr_t get_action_data(void); |
867 | 913 | ||
868 | bool gui_synclist_do_button(struct gui_synclist * lists, | 914 | bool gui_synclist_do_button(struct gui_synclist * lists, |
@@ -941,9 +987,10 @@ bool gui_synclist_do_button(struct gui_synclist * lists, | |||
941 | #ifndef HAVE_SCROLLWHEEL | 987 | #ifndef HAVE_SCROLLWHEEL |
942 | if (queue_count(&button_queue) < FRAMEDROP_TRIGGER) | 988 | if (queue_count(&button_queue) < FRAMEDROP_TRIGGER) |
943 | #endif | 989 | #endif |
944 | { | ||
945 | gui_synclist_draw(lists); | 990 | gui_synclist_draw(lists); |
946 | } | 991 | _gui_synclist_speak_item(lists, |
992 | action == ACTION_STD_PREVREPEAT | ||
993 | || next_item_modifier >1); | ||
947 | yield(); | 994 | yield(); |
948 | *actionptr = ACTION_STD_PREV; | 995 | *actionptr = ACTION_STD_PREV; |
949 | return true; | 996 | return true; |
@@ -955,9 +1002,10 @@ bool gui_synclist_do_button(struct gui_synclist * lists, | |||
955 | #ifndef HAVE_SCROLLWHEEL | 1002 | #ifndef HAVE_SCROLLWHEEL |
956 | if (queue_count(&button_queue) < FRAMEDROP_TRIGGER) | 1003 | if (queue_count(&button_queue) < FRAMEDROP_TRIGGER) |
957 | #endif | 1004 | #endif |
958 | { | ||
959 | gui_synclist_draw(lists); | 1005 | gui_synclist_draw(lists); |
960 | } | 1006 | _gui_synclist_speak_item(lists, |
1007 | action == ACTION_STD_NEXTREPEAT | ||
1008 | || next_item_modifier >1); | ||
961 | yield(); | 1009 | yield(); |
962 | *actionptr = ACTION_STD_NEXT; | 1010 | *actionptr = ACTION_STD_NEXT; |
963 | return true; | 1011 | return true; |
@@ -1006,6 +1054,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, | |||
1006 | SCREEN_MAIN; | 1054 | SCREEN_MAIN; |
1007 | gui_synclist_select_previous_page(lists, screen); | 1055 | gui_synclist_select_previous_page(lists, screen); |
1008 | gui_synclist_draw(lists); | 1056 | gui_synclist_draw(lists); |
1057 | _gui_synclist_speak_item(lists, false); | ||
1009 | yield(); | 1058 | yield(); |
1010 | *actionptr = ACTION_STD_NEXT; | 1059 | *actionptr = ACTION_STD_NEXT; |
1011 | } | 1060 | } |
@@ -1021,14 +1070,48 @@ bool gui_synclist_do_button(struct gui_synclist * lists, | |||
1021 | SCREEN_MAIN; | 1070 | SCREEN_MAIN; |
1022 | gui_synclist_select_next_page(lists, screen); | 1071 | gui_synclist_select_next_page(lists, screen); |
1023 | gui_synclist_draw(lists); | 1072 | gui_synclist_draw(lists); |
1073 | _gui_synclist_speak_item(lists, false); | ||
1024 | yield(); | 1074 | yield(); |
1025 | *actionptr = ACTION_STD_PREV; | 1075 | *actionptr = ACTION_STD_PREV; |
1026 | } | 1076 | } |
1027 | return true; | 1077 | return true; |
1028 | } | 1078 | } |
1079 | if(lists->gui_list[0].scheduled_talk_tick | ||
1080 | && TIME_AFTER(current_tick, lists->gui_list[0].scheduled_talk_tick)) | ||
1081 | /* scheduled postponed item announcement is due */ | ||
1082 | _gui_synclist_speak_item(lists, false); | ||
1029 | return false; | 1083 | return false; |
1030 | } | 1084 | } |
1031 | 1085 | ||
1086 | int list_do_action_timeout(struct gui_synclist *lists, int timeout) | ||
1087 | /* Returns the lowest of timeout or the delay until a postponed | ||
1088 | scheduled announcement is due (if any). */ | ||
1089 | { | ||
1090 | if(lists->gui_list[0].scheduled_talk_tick) | ||
1091 | { | ||
1092 | long delay = lists->gui_list[0].scheduled_talk_tick -current_tick +1; | ||
1093 | /* +1 because the trigger condition uses TIME_AFTER(), which | ||
1094 | is implemented as strictly greater than. */ | ||
1095 | if(delay < 0) | ||
1096 | delay = 0; | ||
1097 | if(timeout > delay || timeout == TIMEOUT_BLOCK) | ||
1098 | timeout = delay; | ||
1099 | } | ||
1100 | return timeout; | ||
1101 | } | ||
1102 | |||
1103 | bool list_do_action(int context, int timeout, | ||
1104 | struct gui_synclist *lists, int *action, | ||
1105 | enum list_wrap wrap) | ||
1106 | /* Combines the get_action() (with possibly overridden timeout) and | ||
1107 | gui_synclist_do_button() calls. Returns the list action from | ||
1108 | do_button, and places the action from get_action in *action. */ | ||
1109 | { | ||
1110 | timeout = list_do_action_timeout(lists, timeout); | ||
1111 | *action = get_action(context, timeout); | ||
1112 | return gui_synclist_do_button(lists, action, wrap); | ||
1113 | } | ||
1114 | |||
1032 | /* Simple use list implementation */ | 1115 | /* Simple use list implementation */ |
1033 | static int simplelist_line_count = 0; | 1116 | static int simplelist_line_count = 0; |
1034 | static char simplelist_text[SIMPLELIST_MAX_LINES][SIMPLELIST_MAX_LINELENGTH]; | 1117 | static char simplelist_text[SIMPLELIST_MAX_LINES][SIMPLELIST_MAX_LINELENGTH]; |
diff --git a/apps/gui/list.h b/apps/gui/list.h index 2de67f5219..253dd9bdbf 100644 --- a/apps/gui/list.h +++ b/apps/gui/list.h | |||
@@ -62,6 +62,14 @@ typedef enum themable_icons list_get_icon(int selected_item, void * data); | |||
62 | * Returns a pointer to a string that contains the text to display | 62 | * Returns a pointer to a string that contains the text to display |
63 | */ | 63 | */ |
64 | typedef char * list_get_name(int selected_item, void * data, char * buffer); | 64 | typedef char * list_get_name(int selected_item, void * data, char * buffer); |
65 | /* | ||
66 | * Voice callback | ||
67 | * - selected_item : an integer that tells the number of the item to speak | ||
68 | * - data : a void pointer to the data you gave to the list when you | ||
69 | * initialized it | ||
70 | * Returns an integer, 0 means success, ignored really... | ||
71 | */ | ||
72 | typedef int list_speak_item(int selected_item, void * data); | ||
65 | #ifdef HAVE_LCD_COLOR | 73 | #ifdef HAVE_LCD_COLOR |
66 | /* | 74 | /* |
67 | * Color callback | 75 | * Color callback |
@@ -97,9 +105,11 @@ struct gui_list | |||
97 | #endif | 105 | #endif |
98 | /* Cache the width of the title string in pixels/characters */ | 106 | /* Cache the width of the title string in pixels/characters */ |
99 | int title_width; | 107 | int title_width; |
108 | long scheduled_talk_tick, last_talked_tick; | ||
100 | 109 | ||
101 | list_get_icon *callback_get_item_icon; | 110 | list_get_icon *callback_get_item_icon; |
102 | list_get_name *callback_get_item_name; | 111 | list_get_name *callback_get_item_name; |
112 | list_speak_item *callback_speak_item; | ||
103 | 113 | ||
104 | struct screen * display; | 114 | struct screen * display; |
105 | /* The data that will be passed to the callback function YOU implement */ | 115 | /* The data that will be passed to the callback function YOU implement */ |
@@ -140,6 +150,14 @@ struct gui_list | |||
140 | #define gui_list_set_icon_callback(gui_list, _callback) \ | 150 | #define gui_list_set_icon_callback(gui_list, _callback) \ |
141 | (gui_list)->callback_get_item_icon=_callback | 151 | (gui_list)->callback_get_item_icon=_callback |
142 | 152 | ||
153 | /* | ||
154 | * Sets the voice callback function | ||
155 | * - gui_list : the list structure | ||
156 | * - _callback : the callback function | ||
157 | */ | ||
158 | #define gui_list_set_voice_callback(gui_list, _callback) \ | ||
159 | (gui_list)->callback_speak_item=_callback | ||
160 | |||
143 | #ifdef HAVE_LCD_COLOR | 161 | #ifdef HAVE_LCD_COLOR |
144 | /* | 162 | /* |
145 | * Sets the color callback function | 163 | * Sets the color callback function |
@@ -200,6 +218,8 @@ extern void gui_synclist_init( | |||
200 | ); | 218 | ); |
201 | extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items); | 219 | extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items); |
202 | extern void gui_synclist_set_icon_callback(struct gui_synclist * lists, list_get_icon icon_callback); | 220 | extern void gui_synclist_set_icon_callback(struct gui_synclist * lists, list_get_icon icon_callback); |
221 | extern void gui_synclist_set_voice_callback(struct gui_synclist * lists, list_speak_item voice_callback); | ||
222 | extern void gui_synclist_speak_item(struct gui_synclist * lists); | ||
203 | extern int gui_synclist_get_nb_items(struct gui_synclist * lists); | 223 | extern int gui_synclist_get_nb_items(struct gui_synclist * lists); |
204 | 224 | ||
205 | extern int gui_synclist_get_sel_pos(struct gui_synclist * lists); | 225 | extern int gui_synclist_get_sel_pos(struct gui_synclist * lists); |
@@ -266,4 +286,15 @@ void simplelist_addline(int line_number, const char *fmt, ...); | |||
266 | before the list is dislplayed for the first time */ | 286 | before the list is dislplayed for the first time */ |
267 | bool simplelist_show_list(struct simplelist_info *info); | 287 | bool simplelist_show_list(struct simplelist_info *info); |
268 | 288 | ||
289 | /* If the list has a pending postponed scheduled announcement, that | ||
290 | may become due before the next get_action tmieout. This function | ||
291 | adjusts the get_action timeout appropriately. */ | ||
292 | extern int list_do_action_timeout(struct gui_synclist *lists, int timeout); | ||
293 | /* This one combines a get_action call (with timeout overridden by | ||
294 | list_do_action_timeout) with the gui_synclist_do_button call, for | ||
295 | convenience. */ | ||
296 | extern bool list_do_action(int context, int timeout, | ||
297 | struct gui_synclist *lists, int *action, | ||
298 | enum list_wrap wrap); | ||
299 | |||
269 | #endif /* _GUI_LIST_H_ */ | 300 | #endif /* _GUI_LIST_H_ */ |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 45e30a6c44..29957eceb6 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -11417,3 +11417,17 @@ | |||
11417 | *: "Blank" | 11417 | *: "Blank" |
11418 | </voice> | 11418 | </voice> |
11419 | </phrase> | 11419 | </phrase> |
11420 | <phrase> | ||
11421 | id: VOICE_EMPTY_LIST | ||
11422 | desc: spoken only, when a list dialog contains no elements | ||
11423 | user: | ||
11424 | <source> | ||
11425 | *: "" | ||
11426 | </source> | ||
11427 | <dest> | ||
11428 | *: "" | ||
11429 | </dest> | ||
11430 | <voice> | ||
11431 | *: "Empty list" | ||
11432 | </voice> | ||
11433 | </phrase> | ||