Пример #1
0
unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
{
    short x, y;
    const enum screen_type screen = SCREEN_MAIN;
    struct viewport *info_vp = sb_skin_get_info_vp(screen);
    const int button = action_get_touchscreen_press_in_vp(&x, &y, info_vp);
    const int list_start_item = gui_list->start_item[screen];
    const int line_height = font_get(gui_list->parent[screen]->font)->height;
    const struct viewport *list_text_vp = &list_text[screen];
    const bool old_released = released;
    const bool show_title = list_display_title(gui_list, screen);
    const bool show_cursor = !global_settings.cursor_style &&
                        gui_list->show_selection_marker;
    const bool on_title_clicked = show_title && y < line_height && (button&BUTTON_REL);
    const bool cancelled_kinetic = (scroll_mode == SCROLL_KINETIC
                        && button != ACTION_NONE && button != ACTION_UNKNOWN
                        && !is_kinetic_over());
    int icon_width = 0;
    int line, list_width = list_text_vp->width;

    released = (button&BUTTON_REL) != 0;

    if (button == ACTION_NONE || button == ACTION_UNKNOWN)
    {
        /* this happens when we hit edges of the list while kinetic scrolling,
         * but not when manually cancelling */
        if (scroll_mode == SCROLL_KINETIC)
            return ACTION_REDRAW;
        return ACTION_NONE;
    }

    /* x and y are relative to info_vp */
    if (gui_list->callback_get_item_icon != NULL)
        icon_width += get_icon_width(screen);
    if (show_cursor)
        icon_width += get_icon_width(screen);

    if (on_title_clicked)
    {
        if (scroll_mode == SCROLL_NONE || is_kinetic_over())
        {
            if (x < icon_width)
            {
                /* Top left corner is GO_TO_ROOT */
                if (button == BUTTON_REL)
                    return ACTION_STD_MENU;
                else if (button == (BUTTON_REPEAT|BUTTON_REL))
                    return ACTION_STD_CONTEXT;
                return ACTION_NONE;
            }
            else /* click on title text is cancel */
                if (button == BUTTON_REL)
                    return ACTION_STD_CANCEL;
        }
        /* do this after the above so the scrolling stops without
         * going back in the list with the same touch */
        if (scroll_mode == SCROLL_KINETIC)
        {
            kinetic_force_stop();
            scroll_mode = SCROLL_NONE;
        }
    }
    else /* list area clicked (or not released) */
    {
        const int actual_y = y - (show_title ? line_height : 0);
        bool on_scrollbar_clicked;
        switch (global_settings.scrollbar)
        {
            case SCROLLBAR_LEFT:
                on_scrollbar_clicked = x <= SCROLLBAR_WIDTH; break;
            case SCROLLBAR_RIGHT:
                on_scrollbar_clicked = x > (icon_width + list_width); break;
            default:
                on_scrollbar_clicked = false; break;
        }
        /* conditions for scrollbar scrolling:
         *    * pen is on the scrollbar
         *      AND scrollbar is on the right (left case is handled above)
         * OR * pen is in the somewhere else but we did scrollbar scrolling before
         *
         * scrollbar scrolling must end if the pen is released
         * scrollbar scrolling must not happen if we're currently scrolling
         * via swiping the screen
         **/

        if (!released && scroll_mode != SCROLL_SWIPE &&
            (on_scrollbar_clicked || scroll_mode == SCROLL_BAR))
        {
            if (scroll_mode == SCROLL_KINETIC)
                kinetic_force_stop();
            scroll_mode = SCROLL_BAR;
            return scrollbar_scroll(gui_list, y);
        }

        /* |--------------------------------------------------------|
         * | Description of the touchscreen list interface:         |
         * |--------------------------------------------------------|
         * | Pressing an item will select it and "enter" it.        |
         * |                                                        |
         * | Pressing and holding your pen down will scroll through |
         * | the list of items.                                     |
         * |                                                        |
         * | Pressing and holding your pen down on a single item    |
         * | will bring up the context menu of it.                  |
         * |--------------------------------------------------------|
         */
        if (actual_y > 0 || button & BUTTON_REPEAT)
        {
            /* selection needs to be corrected if an items are only
             * partially visible */
            line = (actual_y - y_offset) / line_height;

            if (cancelled_kinetic)
            {
                kinetic_force_stop();
                scroll_mode = SCROLL_SWIPE;
            }

            /* Pressed below the list*/
            if (list_start_item + line >= gui_list->nb_items)
            {
                /* don't collect last_position outside of the list area
                 * it'd break selecting after such a situation */
                last_position = 0;
                return ACTION_NONE;
            }

            if (button & BUTTON_REPEAT && scroll_mode == SCROLL_NONE)
            {
                /* held a single line for a while, bring up the context menu */
                gui_synclist_select_item(gui_list, list_start_item + line);
                /* don't sent context repeatedly */
                action_wait_for_release();
                last_position = 0;
                return ACTION_STD_CONTEXT;
            }
            if (released && !cancelled_kinetic)
            {
                /* Pen was released anywhere on the screen */
                last_position = 0;
                if (scroll_mode == SCROLL_NONE)
                {
                    /* select current line */
                    gui_synclist_select_item(gui_list, list_start_item + line);
                    return ACTION_STD_OK;
                }
                else
                {
                    /* we were scrolling
                     *  -> reset scrolling but do nothing else */
                    if (scroll_mode == SCROLL_SWIPE)
                    {
                        if (kinetic_setup_scroll(gui_list))
                            scroll_mode = SCROLL_KINETIC;
                    }
                    if (scroll_mode != SCROLL_KINETIC)
                        scroll_mode = SCROLL_NONE;
                    return ACTION_NONE;
                }
            }
            else
            {   /* pen is on the screen */
                bool redraw = false, result = false;
                /* beginning of list interaction denoted by release in
                 * the previous call */
                if (old_released || is_kinetic_over())
                {
                    scroll_mode = SCROLL_NONE;
                    redraw = true;
                }
                
                /* select current item; gui_synclist_select_item()
                 * is not called because it has side effects that
                 * disturb kinetic scrolling */
                gui_list->selected_item = list_start_item+line;
                gui_synclist_speak_item(gui_list);
                if (last_position == 0)
                {
                    redraw = true;
                    last_position = actual_y;
                }
                else
                {
                    /* record speed data in case we do kinetic scrolling */
                    int diff = actual_y - last_position;
                    kinetic_stats_collect(diff);
                    result = swipe_scroll(gui_list, line_height, diff);
                }

                /* Start scrolling once the pen is moved without
                 * releasing it inbetween */
                if (result)
                {
                    redraw = true;
                    scroll_mode = SCROLL_SWIPE;
                }
                last_position = actual_y;

                return redraw ? ACTION_REDRAW:ACTION_NONE;
            }
        }
    }
    return ACTION_REDRAW;
}
Пример #2
0
enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
                                 const struct text_message * yes_message,
                                 const struct text_message * no_message)
{
    int button;
    int result=-1;
    bool result_displayed;
    struct gui_yesno yn[NB_SCREENS];
    struct viewport vp[NB_SCREENS];
    long talked_tick = 0;
    FOR_NB_SCREENS(i)
    {
        yn[i].main_message=main_message;
        yn[i].result_message[YESNO_YES]=yes_message;
        yn[i].result_message[YESNO_NO]=no_message;
        yn[i].display=&screens[i];
        yn[i].vp = &vp[i];
#ifdef HAVE_LCD_CHARCELLS
        /* Quick fix. Viewports should really be enabled proper for charcell */
        viewport_set_defaults(yn[i].vp, i);
#else
        viewportmanager_theme_enable(i, true, yn[i].vp);
#endif
        screens[i].stop_scroll();
        gui_yesno_draw(&(yn[i]));
    }
    /* make sure to eat any extranous keypresses */
    while (get_action(CONTEXT_STD+99, TIMEOUT_NOBLOCK))
        action_wait_for_release();
    while (result==-1)
    {
        /* Repeat the question every 5secs (more or less) */
        if (global_settings.talk_menu
                && (talked_tick==0 || TIME_AFTER(current_tick, talked_tick+HZ*5)))
        {
            talked_tick = current_tick;
            talk_text_message(main_message, false);
        }
        button = get_action(CONTEXT_YESNOSCREEN, HZ*5);
        switch (button)
        {
#ifdef HAVE_TOUCHSCREEN
        case ACTION_TOUCHSCREEN:
        {
            short int x, y;
            if (action_get_touchscreen_press_in_vp(&x, &y, yn[0].vp) == BUTTON_TOUCHSCREEN)
            {
                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:
        case SYS_CHARGER_DISCONNECTED:
        case SYS_BATTERY_UPDATE:
            /* ignore some SYS events that can happen */
            continue;
        default:
            if(default_event_handler(button) == SYS_USB_CONNECTED)
                return(YESNO_USB);
            result = YESNO_NO;
        }
    }

    FOR_NB_SCREENS(i)
    result_displayed=gui_yesno_draw_result(&(yn[i]), result);

    if (global_settings.talk_menu)
    {
        talk_text_message((result == YESNO_YES) ? yes_message
                          : no_message, false);
        talk_force_enqueue_next();
    }
    if(result_displayed)
        sleep(HZ);

    FOR_NB_SCREENS(i)
    {
        screens[i].scroll_stop(yn[i].vp);
        viewportmanager_theme_undo(i, true);
    }
    return(result);
}