Beispiel #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;
}
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);
}
Beispiel #3
0
/*
 * Check for touchscreen presses as per sketch above in this file
 * 
 * goes through each row of the, checks whether the touchscreen
 * was pressed in it. Then it looks the columns of each row for specific actions
 */
static int pitchscreen_do_touchscreen(struct viewport vps[])
{
    short x, y;
    struct viewport *this_vp = &vps[PITCH_TOP];
    int ret;
    static bool wait_for_release = false;
    ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);

    /* top row */
    if (ret > ACTION_UNKNOWN)
    {   /* press on top row, left or right column
         * only toggle mode if released */
        int column = this_vp->width / 3;
        if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
            return ACTION_PS_TOGGLE_MODE;

        
        else if (x >= column && x <= (2*column))
        {   /* center column pressed */
            if (ret == BUTTON_REPEAT)
                return ACTION_PS_INC_BIG;
            else if (ret & BUTTON_REL)
                return ACTION_PS_INC_SMALL;
        }
        return ACTION_NONE;
    }

    /* now the center row */
    this_vp = &vps[PITCH_MID];
    ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);

    if (ret > ACTION_UNKNOWN)
    {
        int column = this_vp->width / 3;

        if (x < column)
        {   /* left column */
            if (ret & BUTTON_REL)
            {
                wait_for_release = false;
                return ACTION_PS_NUDGE_LEFTOFF;
            }
            else if (ret & BUTTON_REPEAT)
                return ACTION_PS_SLOWER;
            if (!wait_for_release)
            {
                wait_for_release = true;
                return ACTION_PS_NUDGE_LEFT;
            }
        }
        else if (x > (2*column))
        {   /* right column */
            if (ret & BUTTON_REL)
            {
                wait_for_release = false;
                return ACTION_PS_NUDGE_RIGHTOFF;
            }
            else if (ret & BUTTON_REPEAT)
                return ACTION_PS_FASTER;
            if (!wait_for_release)
            {
                wait_for_release = true;
                return ACTION_PS_NUDGE_RIGHT;
            }
        }
        else
            /* center column was pressed */
            return ACTION_PS_RESET;
    }

    /* now the bottom row */
    this_vp = &vps[PITCH_BOTTOM];
    ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);

    if (ret > ACTION_UNKNOWN)
    {
        int column = this_vp->width / 3;

        /* left or right column is exit */
        if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
            return ACTION_PS_EXIT;
        else if (x >= column && x <= (2*column))
        {   /* center column was pressed */
            if (ret & BUTTON_REPEAT)
                return ACTION_PS_DEC_BIG;
            else if (ret & BUTTON_REL)
                return ACTION_PS_DEC_SMALL;
        }
        return ACTION_NONE;
    }
    return ACTION_NONE;
}
static int touchscreen_slider(struct screen *display,
                                struct rgb_pick *rgb,
                                int *selected_slider)
{
    short     x, y;
    int       char_height, line_height;
    int       max_label_width;
    int       text_top, slider_x, slider_width;
    bool      display_three_rows;
    int       button;
    int       pressed_slider;
    struct viewport vp;

    viewport_set_defaults(&vp, display->screen_type);
    display->set_viewport(&vp);

    button = action_get_touchscreen_press_in_vp(&x, &y, &vp);
    if (button == ACTION_UNKNOWN || button == BUTTON_NONE)
        return ACTION_NONE;
    /* Get slider positions and top starting position
     * need vp.y here, because of the statusbar, since touchscreen
     * coordinates are absolute */
    max_label_width = label_get_max_width(display);
    char_height  = display->getcharheight();
    text_top     = MARGIN_TOP + char_height +
                   TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
    slider_x     = SELECTOR_WIDTH + max_label_width + SLIDER_TEXT_MARGIN;
    slider_width = vp.width - slider_x*2 - max_label_width;
    line_height  = char_height + 2*SELECTOR_TB_MARGIN;

    /* same logic as in draw_screen */
    /* Find out if there's enough room for three sliders or just
       enough to display the selected slider - calculate total height
       of display with three sliders present */
    display_three_rows =
        vp.height >=
            text_top + line_height*3  + /* Title + 3 sliders     */
            SWATCH_TOP_MARGIN         + /* at least 2 lines      */
            char_height*2             + /*  + margins for bottom */
            MARGIN_BOTTOM;              /* colored rectangle     */

    display->set_viewport(NULL);

    if (y < text_top)
    {
        if (button == BUTTON_REL)
            return ACTION_STD_CANCEL;
        else
            return ACTION_NONE;
    }

    if (y >= text_top + line_height * (display_three_rows ? 3:1))
    {   /* touching the color area means accept */
        if (button == BUTTON_REL)
            return ACTION_STD_OK;
        else
            return ACTION_NONE;
    }
    /* y is relative to the original viewport */
    pressed_slider = (y - text_top)/line_height;
    if (pressed_slider != *selected_slider)
        *selected_slider = pressed_slider;
    /* add max_label_width to overcome integer division limits,
     * cap value later since that may lead to an overflow */
    if (x < slider_x + (slider_width+max_label_width) && x > slider_x)
    {
        char computed_val;
        x -= slider_x;
        computed_val = (x*rgb_max[pressed_slider]/(slider_width));
        rgb->rgb_val[pressed_slider] =
                        MIN(computed_val,rgb_max[pressed_slider]);
        pack_rgb(rgb);
    }
    return ACTION_NONE;
}