blob: e3b22115dfd6cd2c3136caeb188b028fd152ff1c [file] [log] [blame]
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Kevin Ferrare
*
* 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 "config.h"
#include "yesno.h"
#include "system.h"
#include "kernel.h"
#include "misc.h"
#include "lang.h"
#include "action.h"
#include "talk.h"
#include "settings.h"
#include "viewport.h"
#include "appevents.h"
#include "splash.h"
#include "backlight.h"
struct gui_yesno
{
struct viewport vp;
const struct text_message * main_message;
struct screen * display;
int vp_lines;
/* timeout data */
long end_tick;
enum yesno_res tmo_default_res;
};
static void talk_text_message(const struct text_message * message, bool enqueue)
{
int line;
for(line=0; line < message->nb_lines; line++)
{
long id = P2ID((unsigned char *)message->message_lines[line]);
if(id>=0)
{
talk_id(id, enqueue);
enqueue = true;
}
}
}
static int put_message(struct screen *display,
const struct text_message * message,
int start, int max_y)
{
int i;
int ct = MIN(message->nb_lines, max_y - start);
for(i=0; i < ct; i++)
{
display->puts_scroll(0, i+start,
P2STR((unsigned char *)message->message_lines[i]));
}
return i;
}
/*
* Draws the yesno
* - yn : the yesno structure
*/
static void gui_yesno_draw(struct gui_yesno * yn)
{
struct screen * display=yn->display;
struct viewport *vp = &yn->vp;
int vp_lines = yn->vp_lines;
enum yesno_res def_res = yn->tmo_default_res;
const struct text_message *main_message = yn->main_message;
int line_shift = 0;
struct viewport *last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN);
/* do our own clear to avoid stopping scrolling */
int oldmode = vp->drawmode;
vp->drawmode ^= DRMODE_INVERSEVID;
vp->drawmode |= DRMODE_SOLID;
display->fillrect(0, 0, vp->width, vp->height);
vp->drawmode = oldmode;
if(main_message->nb_lines + 3 < vp_lines)
line_shift = 1;
line_shift += put_message(display, main_message, line_shift, vp_lines);
#ifdef HAVE_TOUCHSCREEN
if (display->screen_type == SCREEN_MAIN)
{
int w,h,tmo_w;
int tm_rem = 0;
const char *btn_fmt;
int rect_w = vp->width/2, rect_h = vp->height/2;
int old_pattern = vp->fg_pattern;
vp->fg_pattern = LCD_RGBPACK(0,255,0);
display->drawrect(0, rect_h, rect_w, rect_h);
display->getstringsize(str(LANG_SET_BOOL_YES), &w, &h);
if (def_res == YESNO_YES)
{
display->getstringsize(" (00)", &tmo_w, NULL);
tm_rem = ((yn->end_tick - current_tick) / 100);
btn_fmt = "%s (%02d)";
}
else
{
btn_fmt = "%s\0%d";
tmo_w = 0;
}
display->putsxyf((rect_w-(w+tmo_w))/2, rect_h+(rect_h-h)/2,
btn_fmt, str(LANG_SET_BOOL_YES), tm_rem);
vp->fg_pattern = LCD_RGBPACK(255,0,0);
display->drawrect(rect_w, rect_h, rect_w, rect_h);
display->getstringsize(str(LANG_SET_BOOL_NO), &w, &h);
if (def_res == YESNO_NO)
{
display->getstringsize(" (00)", &tmo_w, NULL);
tm_rem = ((yn->end_tick - current_tick) / 100);
btn_fmt = "%s (%02d)";
}
else
{
btn_fmt = "%s\0%d";
tmo_w = 0;
}
display->putsxyf(rect_w + (rect_w-(w+tmo_w))/2, rect_h+(rect_h-h)/2,
btn_fmt, str(LANG_SET_BOOL_NO), tm_rem);
vp->fg_pattern = old_pattern;
}
#else
/* Space remaining for yes / no text ? */
if(line_shift + 2 <= vp_lines)
{
if(line_shift + 3 <= vp_lines)
line_shift++;
display->puts(0, line_shift, str(LANG_CONFIRM_WITH_BUTTON));
display->puts(0, line_shift+1, str(LANG_CANCEL_WITH_ANY));
if (def_res == YESNO_YES || def_res == YESNO_NO)
{
int tm_rem = ((yn->end_tick - current_tick) / 100);
if (def_res == YESNO_YES)
display->putsf(0, line_shift, "%s (%02d)",
str(LANG_CONFIRM_WITH_BUTTON), tm_rem);
else
display->putsf(0, line_shift+1, "%s (%02d)",
str(LANG_CANCEL_WITH_ANY), tm_rem);
}
}
#endif
display->update_viewport();
display->set_viewport(last_vp);
}
/*
* Draws the yesno result
* - yn : the yesno structure
* - result : the result to be displayed :
* YESNO_NO if no
* YESNO_YES if yes
*/
static void gui_yesno_draw_result(struct gui_yesno * yn, const struct text_message * message)
{
struct viewport *vp = &yn->vp;
struct screen * display=yn->display;
struct viewport *last_vp = display->set_viewport_ex(vp, VP_FLAG_VP_SET_CLEAN);
display->clear_viewport();
put_message(display, message, 0, yn->vp_lines);
display->update_viewport();
display->set_viewport(last_vp);
}
#if 0
static void gui_yesno_ui_update(unsigned short id, void *event_data, void *user_data)
{
(void)id;
(void)event_data;
struct gui_yesno* yn = (struct gui_yesno*)user_data;
FOR_NB_SCREENS(i)
{
gui_yesno_draw(&yn[i]);
}
}
#endif
/* Display a YES_NO prompt to the user
*
* ticks < HZ will be ignored and the prompt will be blocking
* tmo_default_res is the answer that is returned when the timeout expires
* a default result of YESNO_TMO will also make the prompt blocking
* if tmo_default_res is YESNO_YES or YESNO_NO a seconds countdown will
* be present next to the default option
*
* ticks - timeout if (>=HZ) otherwise ignored
* default_res - result returned on timeout YESNO_TMO creates a blocking prompt
* main_message - prompt to the user
* yes_message - displayed when YESNO_YES is choosen
* no_message - displayed when YESNO_NO is choosen
*/
enum yesno_res gui_syncyesno_run_w_tmo(int ticks, enum yesno_res tmo_default_res,
const struct text_message * main_message,
const struct text_message * yes_message,
const struct text_message * no_message)
{
#define YESNO_NONE (-1)
int action;
bool backlight_on;
bool talk_menu = global_settings.talk_menu;
int result = YESNO_NONE;
struct gui_yesno yn[NB_SCREENS];
long talked_tick = current_tick - 1;
long end_tick = current_tick + ticks;
if (ticks < HZ) /* Display a prompt with NO timeout to the user */
{
tmo_default_res = YESNO_TMO;
}
FOR_NB_SCREENS(i)
{
yn[i].end_tick = end_tick;
yn[i].tmo_default_res = tmo_default_res;
yn[i].main_message=main_message;
yn[i].display=&screens[i];
screens[i].scroll_stop();
viewportmanager_theme_enable(i, true, &(yn[i].vp));
yn[i].vp_lines = viewport_get_nb_lines(&(yn[i].vp));
}
#ifdef HAVE_TOUCHSCREEN
/* switch to point mode because that's more intuitive */
enum touchscreen_mode old_mode = touchscreen_get_mode();
touchscreen_set_mode(TOUCHSCREEN_POINT);
#endif
/* make sure to eat any extranous keypresses */
action_wait_for_release();
button_clear_queue();
/* hook into UI update events to avoid the dialog disappearing
* in case the skin decides to do a full refresh */
/*add_event_ex(GUI_EVENT_NEED_UI_UPDATE, false, gui_yesno_ui_update, &yn[0]);*/
/* probably no longer needed --Bilgus 2023*/
while (result==YESNO_NONE)
{
FOR_NB_SCREENS(i)
gui_yesno_draw(&yn[i]);
/* Repeat the question every 5secs (more or less) */
if (talk_menu && TIME_AFTER(current_tick, talked_tick))
{
talked_tick = current_tick + (HZ*5);
talk_text_message(main_message, false);
}
backlight_on = is_backlight_on(false);
action = get_action(CONTEXT_YESNOSCREEN, HZ / 2); /* for statubar and tmo */
switch (action)
{
#ifdef HAVE_TOUCHSCREEN
case ACTION_TOUCHSCREEN:
{
int btn;
short int x, y;
btn = action_get_touchscreen_press_in_vp(&x, &y, &(yn[0].vp));
if (btn == BUTTON_REL)
{
if (y > yn[0].vp.height/2)
{
if (x <= yn[0].vp.width/2)
result = YESNO_YES;
else
result = YESNO_NO;
}
}
}
break;
#endif
case ACTION_YESNO_ACCEPT:
result = YESNO_YES;
break;
case ACTION_NONE:
if(tmo_default_res != YESNO_TMO && TIME_AFTER(current_tick, end_tick))
{
splash(HZ/2, ID2P(LANG_TIMEOUT));
result = tmo_default_res;
goto exit;
}
/*fall-through*/
case ACTION_UNKNOWN:
case ACTION_REDRAW:
continue;
default:
if(default_event_handler(action) == SYS_USB_CONNECTED) {
result = YESNO_USB;
goto exit;
}
if (!IS_SYSEVENT(action)) /* ignore SYS events that can happen */
result = YESNO_NO;
}
if (!backlight_on)
result = YESNO_NONE; /* don't allow results if the screen is off */
}
exit:
/*remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]);*/
if (result == YESNO_YES || result == YESNO_NO)
{
const struct text_message * resmsg;
if (result == YESNO_YES)
resmsg = yes_message;
else
resmsg = no_message;
if (resmsg != NULL)
{
FOR_NB_SCREENS(i)
gui_yesno_draw_result(&(yn[i]), resmsg);
if (talk_menu)
{
talk_text_message(resmsg, false);
talk_force_enqueue_next();
}
sleep(HZ);
}
}
FOR_NB_SCREENS(i)
{
screens[i].scroll_stop_viewport(&(yn[i].vp));
viewportmanager_theme_undo(i, true);
}
#ifdef HAVE_TOUCHSCREEN
touchscreen_set_mode(old_mode);
#endif
return result;
}
enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
const struct text_message * yes_message,
const struct text_message * no_message)
{
return gui_syncyesno_run_w_tmo(TIMEOUT_BLOCK, YESNO_TMO,
main_message, yes_message, no_message);
}
/* Function to manipulate all yesno dialogues.
This function needs the prompt text as an argument. */
bool yesno_pop(const char* text)
{
const char *lines[]={text};
const struct text_message message={lines, 1};
bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
FOR_NB_SCREENS(i)
screens[i].clear_viewport();
return ret;
}