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); }