diff options
author | William Wilgus <wilgus.william@gmail.com> | 2023-12-01 15:09:11 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2023-12-03 10:13:19 -0500 |
commit | 9dd1b0f46da32ea019e51972715d67bf8ba77687 (patch) | |
tree | 885c48ceab9102b9acf3e24dd68a1d17b265229b | |
parent | 58ec8c62bb8c8293ae6424fe2b46c09c7e3cf70e (diff) | |
download | rockbox-9dd1b0f46da32ea019e51972715d67bf8ba77687.tar.gz rockbox-9dd1b0f46da32ea019e51972715d67bf8ba77687.zip |
[BugFix] YesNo screen scrolling
clearing the viewport stops the scroller
so instead clear the viewport ourselves
[this might cause some glitching but should be acceptable]
in testing this causes no discernible ill effect -- time will tell..
Change-Id: Ia73a459205e37c8aebdf1cd82cd742df3d803af8
-rw-r--r-- | apps/gui/yesno.c | 200 |
1 files changed, 103 insertions, 97 deletions
diff --git a/apps/gui/yesno.c b/apps/gui/yesno.c index a0fd908727..f5de0f67a3 100644 --- a/apps/gui/yesno.c +++ b/apps/gui/yesno.c | |||
@@ -30,16 +30,16 @@ | |||
30 | #include "viewport.h" | 30 | #include "viewport.h" |
31 | #include "appevents.h" | 31 | #include "appevents.h" |
32 | 32 | ||
33 | #include <stdio.h> | 33 | //#include <stdio.h> |
34 | #include "splash.h" | 34 | #include "splash.h" |
35 | #include "backlight.h" | ||
35 | 36 | ||
36 | struct gui_yesno | 37 | struct gui_yesno |
37 | { | 38 | { |
39 | struct viewport vp; | ||
38 | const struct text_message * main_message; | 40 | const struct text_message * main_message; |
39 | const struct text_message * result_message[2]; | ||
40 | |||
41 | struct viewport *vp; | ||
42 | struct screen * display; | 41 | struct screen * display; |
42 | int vp_lines; | ||
43 | /* timeout data */ | 43 | /* timeout data */ |
44 | long end_tick; | 44 | long end_tick; |
45 | enum yesno_res tmo_default_res; | 45 | enum yesno_res tmo_default_res; |
@@ -48,16 +48,13 @@ struct gui_yesno | |||
48 | static void talk_text_message(const struct text_message * message, bool enqueue) | 48 | static void talk_text_message(const struct text_message * message, bool enqueue) |
49 | { | 49 | { |
50 | int line; | 50 | int line; |
51 | if(message) | 51 | for(line=0; line < message->nb_lines; line++) |
52 | { | 52 | { |
53 | for(line=0; line<message->nb_lines; line++) | 53 | long id = P2ID((unsigned char *)message->message_lines[line]); |
54 | if(id>=0) | ||
54 | { | 55 | { |
55 | long id = P2ID((unsigned char *)message->message_lines[line]); | 56 | talk_id(id, enqueue); |
56 | if(id>=0) | 57 | enqueue = true; |
57 | { | ||
58 | talk_id(id, enqueue); | ||
59 | enqueue = true; | ||
60 | } | ||
61 | } | 58 | } |
62 | } | 59 | } |
63 | } | 60 | } |
@@ -67,7 +64,8 @@ static int put_message(struct screen *display, | |||
67 | int start, int max_y) | 64 | int start, int max_y) |
68 | { | 65 | { |
69 | int i; | 66 | int i; |
70 | for(i=0; i<message->nb_lines && i+start<max_y; i++) | 67 | int ct = MIN(message->nb_lines, max_y - start); |
68 | for(i=0; i < ct; i++) | ||
71 | { | 69 | { |
72 | display->puts_scroll(0, i+start, | 70 | display->puts_scroll(0, i+start, |
73 | P2STR((unsigned char *)message->message_lines[i])); | 71 | P2STR((unsigned char *)message->message_lines[i])); |
@@ -82,22 +80,24 @@ static int put_message(struct screen *display, | |||
82 | static void gui_yesno_draw(struct gui_yesno * yn) | 80 | static void gui_yesno_draw(struct gui_yesno * yn) |
83 | { | 81 | { |
84 | struct screen * display=yn->display; | 82 | struct screen * display=yn->display; |
85 | struct viewport *vp = yn->vp; | 83 | struct viewport *vp = &yn->vp; |
86 | int nb_lines, vp_lines, line_shift=0; | 84 | int vp_lines = yn->vp_lines; |
87 | struct viewport *last_vp; | ||
88 | enum yesno_res def_res = yn->tmo_default_res; | 85 | enum yesno_res def_res = yn->tmo_default_res; |
89 | long end_tick = yn->end_tick; | 86 | const struct text_message *main_message = yn->main_message; |
87 | int line_shift = 0; | ||
88 | struct viewport *last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN); | ||
90 | 89 | ||
91 | last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN); | 90 | /* do our own clear to avoid stopping scrolling */ |
92 | display->clear_viewport(); | 91 | int oldmode = vp->drawmode; |
93 | nb_lines = yn->main_message->nb_lines; | 92 | vp->drawmode ^= DRMODE_INVERSEVID; |
94 | vp_lines = viewport_get_nb_lines(vp); | 93 | vp->drawmode |= DRMODE_SOLID; |
94 | display->fillrect(0, 0, vp->width, vp->height); | ||
95 | vp->drawmode = oldmode; | ||
95 | 96 | ||
96 | if(nb_lines+3< vp_lines) | 97 | if(main_message->nb_lines + 3 < vp_lines) |
97 | line_shift=1; | 98 | line_shift = 1; |
98 | 99 | ||
99 | line_shift += put_message(display, yn->main_message, | 100 | line_shift += put_message(display, main_message, line_shift, vp_lines); |
100 | line_shift, vp_lines); | ||
101 | 101 | ||
102 | #ifdef HAVE_TOUCHSCREEN | 102 | #ifdef HAVE_TOUCHSCREEN |
103 | if (display->screen_type == SCREEN_MAIN) | 103 | if (display->screen_type == SCREEN_MAIN) |
@@ -113,9 +113,9 @@ static void gui_yesno_draw(struct gui_yesno * yn) | |||
113 | 113 | ||
114 | if (def_res == YESNO_YES) | 114 | if (def_res == YESNO_YES) |
115 | { | 115 | { |
116 | display->getstringsize(" (0)", &tmo_w, NULL); | 116 | display->getstringsize(" (00)", &tmo_w, NULL); |
117 | tm_rem = ((end_tick - current_tick) / 100); | 117 | tm_rem = ((yn->end_tick - current_tick) / 100); |
118 | btn_fmt = "%s (%d)"; | 118 | btn_fmt = "%s (%02d)"; |
119 | } | 119 | } |
120 | else | 120 | else |
121 | { | 121 | { |
@@ -132,9 +132,9 @@ static void gui_yesno_draw(struct gui_yesno * yn) | |||
132 | 132 | ||
133 | if (def_res == YESNO_NO) | 133 | if (def_res == YESNO_NO) |
134 | { | 134 | { |
135 | display->getstringsize(" (0)", &tmo_w, NULL); | 135 | display->getstringsize(" (00)", &tmo_w, NULL); |
136 | tm_rem = ((end_tick - current_tick) / 100); | 136 | tm_rem = ((yn->end_tick - current_tick) / 100); |
137 | btn_fmt = "%s (%d)"; | 137 | btn_fmt = "%s (%02d)"; |
138 | } | 138 | } |
139 | else | 139 | else |
140 | { | 140 | { |
@@ -149,20 +149,22 @@ static void gui_yesno_draw(struct gui_yesno * yn) | |||
149 | } | 149 | } |
150 | #else | 150 | #else |
151 | /* Space remaining for yes / no text ? */ | 151 | /* Space remaining for yes / no text ? */ |
152 | if(line_shift+2 <= vp_lines) | 152 | if(line_shift + 2 <= vp_lines) |
153 | { | 153 | { |
154 | if(line_shift+3 <= vp_lines) | 154 | if(line_shift + 3 <= vp_lines) |
155 | line_shift++; | 155 | line_shift++; |
156 | display->puts(0, line_shift, str(LANG_CONFIRM_WITH_BUTTON)); | 156 | display->puts(0, line_shift, str(LANG_CONFIRM_WITH_BUTTON)); |
157 | display->puts(0, line_shift+1, str(LANG_CANCEL_WITH_ANY)); | 157 | display->puts(0, line_shift+1, str(LANG_CANCEL_WITH_ANY)); |
158 | 158 | ||
159 | if (def_res == YESNO_YES || def_res == YESNO_NO) | 159 | if (def_res == YESNO_YES || def_res == YESNO_NO) |
160 | { | 160 | { |
161 | int tm_rem = ((end_tick - current_tick) / 100); | 161 | int tm_rem = ((yn->end_tick - current_tick) / 100); |
162 | if (def_res == YESNO_YES) | 162 | if (def_res == YESNO_YES) |
163 | display->putsf(0, line_shift, "%s (%d)", str(LANG_CONFIRM_WITH_BUTTON), tm_rem); | 163 | display->putsf(0, line_shift, "%s (%02d)", |
164 | str(LANG_CONFIRM_WITH_BUTTON), tm_rem); | ||
164 | else | 165 | else |
165 | display->putsf(0, line_shift+1, "%s (%d)", str(LANG_CANCEL_WITH_ANY), tm_rem); | 166 | display->putsf(0, line_shift+1, "%s (%02d)", |
167 | str(LANG_CANCEL_WITH_ANY), tm_rem); | ||
166 | } | 168 | } |
167 | } | 169 | } |
168 | #endif | 170 | #endif |
@@ -177,22 +179,18 @@ static void gui_yesno_draw(struct gui_yesno * yn) | |||
177 | * YESNO_NO if no | 179 | * YESNO_NO if no |
178 | * YESNO_YES if yes | 180 | * YESNO_YES if yes |
179 | */ | 181 | */ |
180 | static bool gui_yesno_draw_result(struct gui_yesno * yn, enum yesno_res result) | 182 | static void gui_yesno_draw_result(struct gui_yesno * yn, const struct text_message * message) |
181 | { | 183 | { |
182 | const struct text_message * message=yn->result_message[result]; | 184 | struct viewport *vp = &yn->vp; |
183 | struct viewport *vp = yn->vp; | ||
184 | struct screen * display=yn->display; | 185 | struct screen * display=yn->display; |
185 | struct viewport *last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN); | 186 | struct viewport *last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN); |
186 | 187 | ||
187 | if(message==NULL) | ||
188 | return false; | ||
189 | display->clear_viewport(); | 188 | display->clear_viewport(); |
190 | put_message(yn->display, message, 0, viewport_get_nb_lines(vp)); | 189 | put_message(display, message, 0, yn->vp_lines); |
191 | display->update_viewport(); | 190 | display->update_viewport(); |
192 | display->set_viewport(last_vp); | 191 | display->set_viewport(last_vp); |
193 | return(true); | ||
194 | } | 192 | } |
195 | 193 | #if 0 | |
196 | static void gui_yesno_ui_update(unsigned short id, void *event_data, void *user_data) | 194 | static void gui_yesno_ui_update(unsigned short id, void *event_data, void *user_data) |
197 | { | 195 | { |
198 | (void)id; | 196 | (void)id; |
@@ -200,11 +198,13 @@ static void gui_yesno_ui_update(unsigned short id, void *event_data, void *user_ | |||
200 | 198 | ||
201 | struct gui_yesno* yn = (struct gui_yesno*)user_data; | 199 | struct gui_yesno* yn = (struct gui_yesno*)user_data; |
202 | FOR_NB_SCREENS(i) | 200 | FOR_NB_SCREENS(i) |
201 | { | ||
203 | gui_yesno_draw(&yn[i]); | 202 | gui_yesno_draw(&yn[i]); |
203 | } | ||
204 | } | 204 | } |
205 | 205 | #endif | |
206 | /* Display a YES_NO prompt to the user | 206 | /* Display a YES_NO prompt to the user |
207 | * | 207 | * |
208 | * ticks < HZ will be ignored and the prompt will be blocking | 208 | * ticks < HZ will be ignored and the prompt will be blocking |
209 | * tmo_default_res is the answer that is returned when the timeout expires | 209 | * tmo_default_res is the answer that is returned when the timeout expires |
210 | * a default result of YESNO_TMO will also make the prompt blocking | 210 | * a default result of YESNO_TMO will also make the prompt blocking |
@@ -222,14 +222,14 @@ enum yesno_res gui_syncyesno_run_w_tmo(int ticks, enum yesno_res tmo_default_res | |||
222 | const struct text_message * yes_message, | 222 | const struct text_message * yes_message, |
223 | const struct text_message * no_message) | 223 | const struct text_message * no_message) |
224 | { | 224 | { |
225 | int button; | 225 | #define YESNO_NONE (-1) |
226 | int result=-1; | 226 | int action; |
227 | bool result_displayed = false; | 227 | bool backlight_on; |
228 | bool talk_menu = global_settings.talk_menu; | ||
229 | int result = YESNO_NONE; | ||
228 | struct gui_yesno yn[NB_SCREENS]; | 230 | struct gui_yesno yn[NB_SCREENS]; |
229 | struct viewport vp[NB_SCREENS]; | 231 | long talked_tick = current_tick - 1; |
230 | long talked_tick = 0; | ||
231 | long end_tick = current_tick + ticks; | 232 | long end_tick = current_tick + ticks; |
232 | long button_scan_tmo = HZ/2; | ||
233 | 233 | ||
234 | if (ticks < HZ) /* Display a prompt with NO timeout to the user */ | 234 | if (ticks < HZ) /* Display a prompt with NO timeout to the user */ |
235 | { | 235 | { |
@@ -240,15 +240,11 @@ enum yesno_res gui_syncyesno_run_w_tmo(int ticks, enum yesno_res tmo_default_res | |||
240 | { | 240 | { |
241 | yn[i].end_tick = end_tick; | 241 | yn[i].end_tick = end_tick; |
242 | yn[i].tmo_default_res = tmo_default_res; | 242 | yn[i].tmo_default_res = tmo_default_res; |
243 | |||
244 | yn[i].main_message=main_message; | 243 | yn[i].main_message=main_message; |
245 | yn[i].result_message[YESNO_YES]=yes_message; | ||
246 | yn[i].result_message[YESNO_NO]=no_message; | ||
247 | yn[i].display=&screens[i]; | 244 | yn[i].display=&screens[i]; |
248 | yn[i].vp = &vp[i]; | ||
249 | viewportmanager_theme_enable(i, true, yn[i].vp); | ||
250 | screens[i].scroll_stop(); | 245 | screens[i].scroll_stop(); |
251 | gui_yesno_draw(&(yn[i])); | 246 | viewportmanager_theme_enable(i, true, &(yn[i].vp)); |
247 | yn[i].vp_lines = viewport_get_nb_lines(&(yn[i].vp)); | ||
252 | } | 248 | } |
253 | 249 | ||
254 | #ifdef HAVE_TOUCHSCREEN | 250 | #ifdef HAVE_TOUCHSCREEN |
@@ -263,33 +259,36 @@ enum yesno_res gui_syncyesno_run_w_tmo(int ticks, enum yesno_res tmo_default_res | |||
263 | 259 | ||
264 | /* hook into UI update events to avoid the dialog disappearing | 260 | /* hook into UI update events to avoid the dialog disappearing |
265 | * in case the skin decides to do a full refresh */ | 261 | * in case the skin decides to do a full refresh */ |
266 | add_event_ex(GUI_EVENT_NEED_UI_UPDATE, false, gui_yesno_ui_update, &yn[0]); | 262 | /*add_event_ex(GUI_EVENT_NEED_UI_UPDATE, false, gui_yesno_ui_update, &yn[0]);*/ |
263 | /* probably no longer needed --Bilgus 2023*/ | ||
267 | 264 | ||
268 | while (result==-1) | 265 | while (result==YESNO_NONE) |
269 | { | 266 | { |
267 | |||
268 | FOR_NB_SCREENS(i) | ||
269 | gui_yesno_draw(&yn[i]); | ||
270 | |||
270 | /* Repeat the question every 5secs (more or less) */ | 271 | /* Repeat the question every 5secs (more or less) */ |
271 | if (global_settings.talk_menu | 272 | if (talk_menu && TIME_AFTER(current_tick, talked_tick)) |
272 | && (talked_tick==0 || TIME_AFTER(current_tick, talked_tick+HZ*5))) | ||
273 | { | 273 | { |
274 | talked_tick = current_tick; | 274 | talked_tick = current_tick + (HZ*5); |
275 | talk_text_message(main_message, false); | 275 | talk_text_message(main_message, false); |
276 | } | 276 | } |
277 | FOR_NB_SCREENS(i) | 277 | backlight_on = is_backlight_on(false); |
278 | gui_yesno_draw(&yn[i]); | 278 | action = get_action(CONTEXT_YESNOSCREEN, HZ / 2); /* for statubar and tmo */ |
279 | 279 | switch (action) | |
280 | button = get_action(CONTEXT_YESNOSCREEN, button_scan_tmo); | ||
281 | |||
282 | switch (button) | ||
283 | { | 280 | { |
284 | #ifdef HAVE_TOUCHSCREEN | 281 | #ifdef HAVE_TOUCHSCREEN |
285 | case ACTION_TOUCHSCREEN: | 282 | case ACTION_TOUCHSCREEN: |
286 | { | 283 | { |
284 | int btn; | ||
287 | short int x, y; | 285 | short int x, y; |
288 | if (action_get_touchscreen_press_in_vp(&x, &y, yn[0].vp) == BUTTON_REL) | 286 | btn = action_get_touchscreen_press_in_vp(&x, &y, &(yn[0].vp)) |
287 | if (btn == BUTTON_REL) | ||
289 | { | 288 | { |
290 | if (y > yn[0].vp->height/2) | 289 | if (y > yn[0].vp.height/2) |
291 | { | 290 | { |
292 | if (x <= yn[0].vp->width/2) | 291 | if (x <= yn[0].vp.width/2) |
293 | result = YESNO_YES; | 292 | result = YESNO_YES; |
294 | else | 293 | else |
295 | result = YESNO_NO; | 294 | result = YESNO_NO; |
@@ -299,55 +298,62 @@ enum yesno_res gui_syncyesno_run_w_tmo(int ticks, enum yesno_res tmo_default_res | |||
299 | break; | 298 | break; |
300 | #endif | 299 | #endif |
301 | case ACTION_YESNO_ACCEPT: | 300 | case ACTION_YESNO_ACCEPT: |
302 | result=YESNO_YES; | 301 | result = YESNO_YES; |
303 | break; | 302 | break; |
304 | case ACTION_NONE: | 303 | case ACTION_NONE: |
305 | if(tmo_default_res != YESNO_TMO && TIME_AFTER(current_tick, end_tick)) | 304 | if(tmo_default_res != YESNO_TMO && TIME_AFTER(current_tick, end_tick)) |
306 | { | 305 | { |
307 | splash(HZ/2, ID2P(LANG_TIMEOUT)); | 306 | splash(HZ/2, ID2P(LANG_TIMEOUT)); |
308 | result = tmo_default_res; | 307 | result = tmo_default_res; |
309 | break; | 308 | goto exit; |
310 | } | 309 | } |
311 | /*fall-through*/ | 310 | /*fall-through*/ |
312 | case ACTION_UNKNOWN: | 311 | case ACTION_UNKNOWN: |
313 | case SYS_CHARGER_DISCONNECTED: | 312 | case ACTION_REDRAW: |
314 | case SYS_BATTERY_UPDATE: | ||
315 | case SYS_TIMEOUT: | ||
316 | #if CONFIG_CHARGING | ||
317 | case SYS_CHARGER_CONNECTED: | ||
318 | #endif | ||
319 | /* ignore some SYS events that can happen */ | ||
320 | continue; | 313 | continue; |
321 | default: | 314 | default: |
322 | if(default_event_handler(button) == SYS_USB_CONNECTED) { | 315 | if(default_event_handler(action) == SYS_USB_CONNECTED) { |
323 | result = YESNO_USB; | 316 | result = YESNO_USB; |
324 | goto exit; | 317 | goto exit; |
325 | } | 318 | } |
326 | 319 | if (!IS_SYSEVENT(action)) /* ignore SYS events that can happen */ | |
327 | result = YESNO_NO; | 320 | result = YESNO_NO; |
328 | } | 321 | } |
322 | |||
323 | if (!backlight_on) | ||
324 | result = YESNO_NONE; /* don't allow results if the screen is off */ | ||
329 | } | 325 | } |
330 | 326 | ||
331 | FOR_NB_SCREENS(i) | 327 | exit: |
332 | result_displayed=gui_yesno_draw_result(&(yn[i]), result); | ||
333 | 328 | ||
334 | if (global_settings.talk_menu) | 329 | /*remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]);*/ |
330 | |||
331 | if (result == YESNO_YES || result == YESNO_NO) | ||
335 | { | 332 | { |
336 | talk_text_message((result == YESNO_YES) ? yes_message | 333 | const struct text_message * resmsg; |
337 | : no_message, false); | 334 | if (result == YESNO_YES) |
338 | talk_force_enqueue_next(); | 335 | resmsg = yes_message; |
339 | } | 336 | else |
337 | resmsg = no_message; | ||
340 | 338 | ||
339 | if (resmsg != NULL) | ||
340 | { | ||
341 | FOR_NB_SCREENS(i) | ||
342 | gui_yesno_draw_result(&(yn[i]), resmsg); | ||
341 | 343 | ||
342 | exit: | 344 | if (talk_menu) |
343 | remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]); | 345 | { |
346 | talk_text_message(resmsg, false); | ||
347 | talk_force_enqueue_next(); | ||
348 | } | ||
344 | 349 | ||
345 | if(result_displayed) | 350 | sleep(HZ); |
346 | sleep(HZ); | 351 | } |
352 | } | ||
347 | 353 | ||
348 | FOR_NB_SCREENS(i) | 354 | FOR_NB_SCREENS(i) |
349 | { | 355 | { |
350 | screens[i].scroll_stop_viewport(yn[i].vp); | 356 | screens[i].scroll_stop_viewport(&(yn[i].vp)); |
351 | viewportmanager_theme_undo(i, true); | 357 | viewportmanager_theme_undo(i, true); |
352 | } | 358 | } |
353 | 359 | ||
@@ -366,7 +372,7 @@ enum yesno_res gui_syncyesno_run(const struct text_message * main_message, | |||
366 | } | 372 | } |
367 | 373 | ||
368 | /* Function to manipulate all yesno dialogues. | 374 | /* Function to manipulate all yesno dialogues. |
369 | This function needs the output text as an argument. */ | 375 | This function needs the prompt text as an argument. */ |
370 | bool yesno_pop(const char* text) | 376 | bool yesno_pop(const char* text) |
371 | { | 377 | { |
372 | const char *lines[]={text}; | 378 | const char *lines[]={text}; |