diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c index 6ce8972944..cb59dbe88d 100644 --- a/apps/gui/bitmap/list.c +++ b/apps/gui/bitmap/list.c @@ -48,11 +48,16 @@ static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS]; #ifdef HAVE_TOUCHSCREEN +/* difference in pixels between draws, above it means enough to start scrolling */ +#define SCROLL_BEGIN_THRESHOLD 3 + static enum { SCROLL_NONE, /* no scrolling */ SCROLL_BAR, /* scroll by using the scrollbar */ SCROLL_SWIPE, /* scroll by wiping over the screen */ } scroll_mode; + +static int y_offset; #endif int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width, @@ -157,9 +162,30 @@ void list_draw(struct screen *display, struct gui_synclist *list) list_text_vp->height -= line_height; } + start = list_start_item; end = start + viewport_get_nb_lines(list_text_vp); +#ifdef HAVE_TOUCHSCREEN + if (list->selected_item == 0) + y_offset = 0; /* reset in case it's a new list */ + + int draw_offset = y_offset; + /* draw some extra items to not have empty lines at the top and bottom */ + if (y_offset > 0) + { + /* make it negative for more consistent apparence when switching + * directions */ + draw_offset -= line_height; + if (start > 0) + start--; + } + else if (y_offset < 0) + end++; +#else + #define draw_offset 0 +#endif + /* draw the scrollbar if its needed */ if (global_settings.scrollbar && viewport_get_nb_lines(list_text_vp) < list->nb_items) @@ -216,6 +242,7 @@ void list_draw(struct screen *display, struct gui_synclist *list) char entry_buffer[MAX_PATH]; unsigned char *entry_name; int text_pos = 0; + int line = i - start; s = list->callback_get_item_name(i, list->data, entry_buffer, sizeof(entry_buffer)); entry_name = P2STR(s); @@ -285,36 +312,36 @@ void list_draw(struct screen *display, struct gui_synclist *list) if (item_offset> item_width - (list_text_vp->width - text_pos)) { /* don't scroll */ - display->puts_style_offset(0, i-start, entry_name, - style, item_offset); + display->puts_style_xyoffset(0, line, entry_name, + style, item_offset, draw_offset); } else { - display->puts_scroll_style_offset(0, i-start, entry_name, - style, item_offset); + display->puts_scroll_style_xyoffset(0, line, entry_name, + style, item_offset, draw_offset); } } else { if (list->scroll_all) - display->puts_scroll_style_offset(0, i-start, entry_name, - style, item_offset); + display->puts_scroll_style_xyoffset(0, line, entry_name, + style, item_offset, draw_offset); else - display->puts_style_offset(0, i-start, entry_name, - style, item_offset); + display->puts_style_xyoffset(0, line, entry_name, + style, item_offset, draw_offset); } /* do the icon */ display->set_viewport(&list_icons); if (list->callback_get_item_icon && global_settings.show_icons) { screen_put_icon_with_offset(display, show_cursor?1:0, - (i-start),show_cursor?ICON_PADDING:0,0, + (line),show_cursor?ICON_PADDING:0,draw_offset, list->callback_get_item_icon(i, list->data)); } if (show_cursor && i >= list->selected_item && i < list->selected_item + list->selected_size) { - screen_put_icon(display, 0, i-start, Icon_Cursor); + screen_put_icon_with_offset(display, 0, line, 0, draw_offset, Icon_Cursor); } } display->set_viewport(parent); @@ -343,6 +370,8 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list, if (nb_lines < gui_list->nb_items) { scroll_mode = SCROLL_BAR; + /* scrollbar scrolling is still line based */ + y_offset = 0; int scrollbar_size = nb_lines* font_get(gui_list->parent[screen]->font)->height; int actual_y = y - list_text[screen].y; @@ -365,17 +394,49 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list, } /* - * returns the number of scrolled items since the last call + * returns the number of pixel scrolled since the last call **/ -static int gui_synclist_touchscreen_scrolling(struct gui_synclist * gui_list, int position) +static int gui_synclist_touchscreen_scrolling(struct gui_synclist * gui_list, int line_height, int position) { - const int screen = screens[SCREEN_MAIN].screen_type; - const int difference = position - last_position; + /* fixme */ + const enum screen_type screen = screens[SCREEN_MAIN].screen_type; const int nb_lines = viewport_get_nb_lines(&list_text[screen]); - if(nb_lines < gui_list->nb_items && difference != 0) /* only scroll if needed */ + /* in pixels */ + const int difference = position - last_position; + + /* make selecting items easier */ + if (abs(difference) < SCROLL_BEGIN_THRESHOLD && scroll_mode == SCROLL_NONE) + return 0; + + /* does the list even scroll? if no, return but still show + * the caller that we would scroll */ + if (nb_lines >= gui_list->nb_items) + return difference; + + const int old_start = gui_list->start_item[screen]; + int new_start_item = -1; + int line_diff = 0; + + /* don't scroll at the edges of the list */ + if ((old_start == 0 && difference > 0) + || (old_start == (gui_list->nb_items - nb_lines) && difference < 0)) { - int new_start_item; - new_start_item = gui_list->start_item[screen] - difference; + y_offset = 0; + return difference; + } + + /* add up y_offset over time and translate to lines + * if scrolled enough */ + y_offset += difference; + if (abs(y_offset) > line_height) + { + line_diff = y_offset/line_height; + y_offset -= line_diff * line_height; + } + + if(line_diff != 0) + { + new_start_item = old_start - line_diff; /* check if new_start_item is bigger than list item count */ if(new_start_item > gui_list->nb_items - nb_lines) new_start_item = gui_list->nb_items - nb_lines; @@ -384,22 +445,23 @@ static int gui_synclist_touchscreen_scrolling(struct gui_synclist * gui_list, in new_start_item = 0; gui_list->start_item[screen] = new_start_item; } + return difference; } unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) { short x, y; - const int button = action_get_touchscreen_press(&x, &y); - const int screen = SCREEN_MAIN; + 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 struct viewport *list_text_vp = &list_text[screen]; const bool old_released = released; int line, list_width = list_text_vp->width; - /* make sure it is inside the UI viewport */ - if (!viewport_point_within_vp(sb_skin_get_info_vp(screen), x, y)) - return BUTTON_NONE; + if (button == ACTION_NONE || button == ACTION_UNKNOWN) + return ACTION_NONE; released = (button&BUTTON_REL) != 0; @@ -473,15 +535,18 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) int actual_y; actual_y = y - list_text_vp->y; - line = actual_y / line_height; + /* selection needs to be corrected if an items are only + * partly visible */ + line = (actual_y - y_offset) / line_height; /* 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; - - /* Pressed a border */ - if(UNLIKELY(actual_y % line_height == 0)) - return ACTION_NONE; + } if (released) { @@ -524,9 +589,9 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) /* select current item */ gui_synclist_select_item(gui_list, list_start_item+line); if (last_position == 0) - last_position = line; + last_position = actual_y; else - result = gui_synclist_touchscreen_scrolling(gui_list, line); + result = gui_synclist_touchscreen_scrolling(gui_list, line_height, actual_y); /* Start scrolling once the pen is moved without * releasing it inbetween */ @@ -536,7 +601,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) scroll_mode = SCROLL_SWIPE; } - last_position = line; + last_position = actual_y; return redraw ? ACTION_REDRAW:ACTION_NONE; } diff --git a/apps/screen_access.c b/apps/screen_access.c index 7b64c400bf..d059547402 100644 --- a/apps/screen_access.c +++ b/apps/screen_access.c @@ -168,8 +168,10 @@ struct screen screens[NB_SCREENS] = .hline=&lcd_hline, .scroll_step=&lcd_scroll_step, .puts_style_offset=&lcd_puts_style_offset, + .puts_style_xyoffset=&lcd_puts_style_xyoffset, .puts_scroll_style=&lcd_puts_scroll_style, .puts_scroll_style_offset=&lcd_puts_scroll_style_offset, + .puts_scroll_style_xyoffset=&lcd_puts_scroll_style_xyoffset, #endif /* HAVE_LCD_BITMAP */ #ifdef HAVE_LCD_CHARCELLS @@ -257,8 +259,10 @@ struct screen screens[NB_SCREENS] = .hline=&lcd_remote_hline, .scroll_step=&lcd_remote_scroll_step, .puts_style_offset=&lcd_remote_puts_style_offset, + .puts_style_xyoffset=&lcd_remote_puts_style_xyoffset, .puts_scroll_style=&lcd_remote_puts_scroll_style, .puts_scroll_style_offset=&lcd_remote_puts_scroll_style_offset, + .puts_scroll_style_xyoffset=&lcd_remote_puts_scroll_style_xyoffset, #endif /* 1 */ #if 0 /* no charcell remote LCDs so far */ diff --git a/apps/screen_access.h b/apps/screen_access.h index 463ca3fd6a..a154d20195 100644 --- a/apps/screen_access.h +++ b/apps/screen_access.h @@ -77,11 +77,15 @@ struct screen void (*scroll_step)(int pixels); void (*puts_style_offset)(int x, int y, const unsigned char *str, - int style, int offset); + int style, int x_offset); + void (*puts_style_xyoffset)(int x, int y, const unsigned char *str, + int style, int x_offset, int y_offset); void (*puts_scroll_style)(int x, int y, const unsigned char *string, int style); void (*puts_scroll_style_offset)(int x, int y, const unsigned char *string, - int style, int offset); + int style, int x_offset); + void (*puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, + int style, int x_offset, int y_offset); void (*mono_bitmap)(const unsigned char *src, int x, int y, int width, int height); void (*mono_bitmap_part)(const unsigned char *src, int src_x, int src_y, @@ -134,7 +138,9 @@ struct screen void (*puts_offset)(int x, int y, const unsigned char *str, int offset); void (*puts_scroll)(int x, int y, const unsigned char *string); void (*puts_scroll_offset)(int x, int y, const unsigned char *string, - int offset); + int x_offset); + void (*puts_scroll_xyoffset)(int x, int y, const unsigned char *string, + int x_offset, int y_offset); void (*scroll_speed)(int speed); void (*scroll_delay)(int ms); void (*stop_scroll)(void); diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c index 9f1d5fef68..2ce11e3398 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c @@ -284,8 +284,8 @@ static void LCDFN(putsxyofs_style)(int xpos, int ypos, /*** Line oriented text output ***/ /* put a string at a given char position */ -void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, - int style, int offset) +void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, + int style, int x_offset, int y_offset) { int xpos, ypos, w, h; LCDFN(scroll_stop_line)(current_vp, y); @@ -294,8 +294,14 @@ void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, LCDFN(getstringsize)(str, &w, &h); xpos = x * LCDFN(getstringsize)(" ", NULL, NULL); - ypos = y * h; - LCDFN(putsxyofs_style)(xpos, ypos, str, style, w, h, offset); + ypos = y * h + y_offset; + LCDFN(putsxyofs_style)(xpos, ypos, str, style, w, h, x_offset); +} + +void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, + int style, int x_offset) +{ + LCDFN(puts_style_xyoffset)(x, y, str, style, x_offset, 0); } void LCDFN(puts)(int x, int y, const unsigned char *str) @@ -326,8 +332,8 @@ void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset) /*** scrolling ***/ -void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, - int style, int offset) +void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string, + int style, int x_offset, int y_offset) { struct scrollinfo* s; char *end; @@ -343,7 +349,7 @@ void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return; if (!string) return; - LCDFN(puts_style_offset)(x, y, string, style, offset); + LCDFN(puts_style_xyoffset)(x, y, string, style, x_offset, y_offset); LCDFN(getstringsize)(string, &w, &h); @@ -381,8 +387,9 @@ void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, s->vp = current_vp; s->y = y; - s->offset = offset; + s->offset = x_offset; s->startx = x * LCDFN(getstringsize)(" ", NULL, NULL); + s->y_offset = y_offset; s->backward = false; LCDFN(scroll_info).lines++; @@ -429,7 +436,7 @@ void LCDFN(scroll_fn)(void) pf = font_get(current_vp->font); xpos = s->startx; - ypos = s->y * pf->height; + ypos = s->y * pf->height + s->y_offset; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -457,3 +464,9 @@ void LCDFN(scroll_fn)(void) } LCDFN(set_viewport)(old_vp); } + +void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, + int style, int x_offset) +{ + LCDFN(puts_scroll_style_xyoffset)(x, y, string, style, x_offset, 0); +} diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 1cbb286ad1..54a2f3c511 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -192,6 +192,8 @@ extern void lcd_clear_viewport(void); extern void lcd_clear_display(void); extern void lcd_putsxy(int x, int y, const unsigned char *string); extern void lcd_putsxyf(int x, int y, const unsigned char *fmt, ...); +extern void lcd_putsxy_style_offset(int x, int y, const unsigned char *str, + int style, int offset); extern void lcd_puts(int x, int y, const unsigned char *string); extern void lcd_putsf(int x, int y, const unsigned char *fmt, ...); extern void lcd_puts_style(int x, int y, const unsigned char *string, int style); @@ -480,9 +482,13 @@ extern void lcd_setfont(int font); extern int lcd_getfont(void); extern void lcd_puts_style_offset(int x, int y, const unsigned char *str, - int style, int offset); + int style, int x_offset); +extern void lcd_puts_style_xyoffset(int x, int y, const unsigned char *str, + int style, int x_offset, int y_offset); extern void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, - int style, int offset); + int style, int x_offset); +extern void lcd_puts_scroll_style_xyoffset(int x, int y, const unsigned char *string, + int style, int x_offset, int y_offset); /* low level drawing function pointer arrays */ #if LCD_DEPTH >= 8 diff --git a/firmware/export/scroll_engine.h b/firmware/export/scroll_engine.h index ca94828787..0fe6fe464a 100644 --- a/firmware/export/scroll_engine.h +++ b/firmware/export/scroll_engine.h @@ -56,6 +56,7 @@ struct scrollinfo int y; /* Position of the line on the screen (char co-ordinates) */ int offset; int startx; + int y_offset; /* y offset of the line, used for pixel-accurate list scrolling */ #ifdef HAVE_LCD_BITMAP int width; /* length of line in pixels */ int style; /* line style */