From eec89a90ffdd077d687914fe18a9e48028f07fb4 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 20 Dec 2013 23:34:28 +0100 Subject: lists: Adapt put_line(). This enables removing large portions of code, simplifiyng the drawing routine. All of the removed code is functionaltiy now available through put_line(). Change-Id: Ib8e61772134189a8c3c6d22345c0b45e912bea76 --- apps/gui/bitmap/list.c | 270 +++++++++++++++++------------------------------ apps/gui/charcell/list.c | 67 +++++------- apps/gui/list.c | 55 +++++----- apps/gui/list.h | 2 + 4 files changed, 153 insertions(+), 241 deletions(-) diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c index b1fd474571..f1def9007d 100644 --- a/apps/gui/bitmap/list.c +++ b/apps/gui/bitmap/list.c @@ -41,8 +41,10 @@ #include "viewport.h" #include "statusbar-skinned.h" #include "debug.h" +#include "line.h" #define ICON_PADDING 1 +#define ICON_PADDING_S "1" /* these are static to make scrolling work */ static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS]; @@ -52,10 +54,12 @@ static int y_offset; static bool hide_selection; #endif +/* list-private helpers from the generic list.c (move to header?) */ int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width, int text_pos, struct screen * display, struct viewport *vp); bool list_display_title(struct gui_synclist *list, enum screen_type screen); +int list_get_nb_lines(struct gui_synclist *list, enum screen_type screen); void gui_synclist_scroll_stop(struct gui_synclist *lists) { @@ -87,16 +91,11 @@ static int list_icon_width(enum screen_type screen) return get_icon_width(screen) + ICON_PADDING * 2; } -static int list_icon_height(enum screen_type screen) -{ - return get_icon_height(screen); -} - static bool draw_title(struct screen *display, struct gui_synclist *list) { const int screen = display->screen_type; - int style = STYLE_DEFAULT; struct viewport *title_text_vp = &title_text[screen]; + struct line_desc line = LINE_DESC_DEFINIT; if (sb_set_title_text(list->title, list->title_icon, screen)) return false; /* the sbs is handling the title */ @@ -104,65 +103,46 @@ static bool draw_title(struct screen *display, struct gui_synclist *list) if (!list_display_title(list, screen)) return false; *title_text_vp = *(list->parent[screen]); - title_text_vp->height = title_text_vp->line_height; - - if (list->title_icon != Icon_NOICON && global_settings.show_icons) - { - struct viewport title_icon = *title_text_vp; - - title_icon.width = list_icon_width(screen); - title_icon.y += (title_icon.height - list_icon_height(screen)) / 2; - title_icon.height = list_icon_height(screen); - if (VP_IS_RTL(&title_icon)) - { - title_icon.x += title_text_vp->width - title_icon.width; - } - else - { - title_text_vp->x += title_icon.width; - } - title_text_vp->width -= title_icon.width; + line.height = list->line_height[screen]; + title_text_vp->height = line.height; - display->set_viewport(&title_icon); - screen_put_iconxy(display, ICON_PADDING, 0, list->title_icon); - } #ifdef HAVE_LCD_COLOR if (list->title_color >= 0) - { - style |= (STYLE_COLORED|list->title_color); - } + line.style |= (STYLE_COLORED|list->title_color); #endif + line.scroll = true; + display->set_viewport(title_text_vp); - display->puts_scroll_style(0, 0, list->title, style); + + if (list->title_icon != Icon_NOICON && global_settings.show_icons) + put_line(display, 0, 0, &line, "$"ICON_PADDING_S"I$t", + list->title_icon, list->title); + else + put_line(display, 0, 0, &line, "$t", list->title); + return true; } void list_draw(struct screen *display, struct gui_synclist *list) { - struct viewport list_icons; - int start, end, line_height, style, item_offset, i; + int start, end, item_offset, i; const int screen = display->screen_type; const int list_start_item = list->start_item[screen]; - const int icon_width = list_icon_width(screen); const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT); const bool scrollbar_in_right = (global_settings.scrollbar == SCROLLBAR_RIGHT); const bool show_cursor = !global_settings.cursor_style && list->show_selection_marker; + const bool have_icons = global_settings.show_icons && list->callback_get_item_icon; struct viewport *parent = (list->parent[screen]); -#ifdef HAVE_LCD_COLOR - unsigned char cur_line = 0; -#endif - int icon_yoffset = 0; /* to center the icon */ + struct line_desc linedes = LINE_DESC_DEFINIT; bool show_title; struct viewport *list_text_vp = &list_text[screen]; int indent = 0; - line_height = parent->line_height; display->set_viewport(parent); display->clear_viewport(); display->scroll_stop_viewport(list_text_vp); *list_text_vp = *parent; - list_text_vp->line_height = line_height; if ((show_title = draw_title(display, list))) { int title_height = title_text[screen].height; @@ -170,7 +150,10 @@ void list_draw(struct screen *display, struct gui_synclist *list) list_text_vp->height -= title_height; } - const int nb_lines = viewport_get_nb_lines(list_text_vp); + const int nb_lines = list_get_nb_lines(list, screen); + + linedes.height = list->line_height[screen]; + linedes.nlines = list->selected_size; start = list_start_item; end = start + nb_lines; @@ -185,7 +168,7 @@ void list_draw(struct screen *display, struct gui_synclist *list) { /* make it negative for more consistent apparence when switching * directions */ - draw_offset -= line_height; + draw_offset -= linedes.height; if (start > 0) start--; } @@ -196,110 +179,71 @@ void list_draw(struct screen *display, struct gui_synclist *list) #endif /* draw the scrollbar if its needed */ - if (global_settings.scrollbar && nb_lines < list->nb_items) + if (global_settings.scrollbar != SCROLLBAR_OFF) { - struct viewport vp = *list_text_vp; - vp.width = SCROLLBAR_WIDTH; - vp.height = line_height * nb_lines; - vp.x = parent->x; - list_text_vp->width -= SCROLLBAR_WIDTH; - if (scrollbar_in_left) - list_text_vp->x += SCROLLBAR_WIDTH; - else - vp.x += list_text_vp->width; - display->set_viewport(&vp); - gui_scrollbar_draw(display, - (scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height, - list->nb_items, list_start_item, list_start_item + nb_lines, - VERTICAL); - } - else if (show_title) - { - /* shift everything a bit in relation to the title... */ - if (!VP_IS_RTL(list_text_vp) && scrollbar_in_left) + /* if the scrollbar is shown the text viewport needs to shrink */ + if (nb_lines < list->nb_items) { + struct viewport vp = *list_text_vp; + vp.width = SCROLLBAR_WIDTH; + vp.height = linedes.height * nb_lines; list_text_vp->width -= SCROLLBAR_WIDTH; - list_text_vp->x += SCROLLBAR_WIDTH; + if (scrollbar_in_right) + vp.x += list_text_vp->width; + else /* left */ + list_text_vp->x += SCROLLBAR_WIDTH; + display->set_viewport(&vp); + gui_scrollbar_draw(display, + (scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height, + list->nb_items, list_start_item, list_start_item + nb_lines, + VERTICAL); } + /* shift everything a bit in relation to the title */ + else if (!VP_IS_RTL(list_text_vp) && scrollbar_in_left) + indent += SCROLLBAR_WIDTH; else if (VP_IS_RTL(list_text_vp) && scrollbar_in_right) - { - list_text_vp->width -= SCROLLBAR_WIDTH; - } - } - - /* setup icon placement */ - list_icons = *list_text_vp; - int icon_count = (list->callback_get_item_icon != NULL) ? 1 : 0; - if (show_cursor) - icon_count++; - if (icon_count) - { - list_icons.width = icon_width * icon_count; - list_text_vp->width -= list_icons.width + ICON_PADDING; - if (VP_IS_RTL(&list_icons)) - list_icons.x += list_text_vp->width + ICON_PADDING; - else - list_text_vp->x += list_icons.width + ICON_PADDING; - icon_yoffset = (line_height - list_icon_height(screen)) / 2; + indent += SCROLLBAR_WIDTH; } for (i=start; inb_items; i++) { /* do the text */ + enum themable_icons icon; unsigned const char *s; char entry_buffer[MAX_PATH]; unsigned char *entry_name; int text_pos = 0; int line = i - start; - indent = 0; + int line_indent = 0; + int style = STYLE_DEFAULT; + bool is_selected = false; + icon = list->callback_get_item_icon ? + list->callback_get_item_icon(i, list->data) : Icon_NOICON; s = list->callback_get_item_name(i, list->data, entry_buffer, sizeof(entry_buffer)); entry_name = P2STR(s); while (*entry_name == '\t') { - indent++; + line_indent++; entry_name++; } - if (indent) + if (line_indent) { - if (icon_width) - indent *= icon_width; + if (global_settings.show_icons) + line_indent *= list_icon_width(screen); else - indent *= display->getcharwidth(); - - if (VP_IS_RTL(&list_icons)) - { - list_icons.x -= indent; - } - else - { - list_icons.x += indent; - list_text_vp->x += indent; - } - list_text_vp->width -= indent; + line_indent *= display->getcharwidth(); } + line_indent += indent; display->set_viewport(list_text_vp); - style = STYLE_DEFAULT; /* position the string at the correct offset place */ int item_width,h; display->getstringsize(entry_name, &item_width, &h); item_offset = gui_list_get_item_offset(list, item_width, text_pos, display, list_text_vp); -#ifdef HAVE_LCD_COLOR - /* if the list has a color callback */ - if (list->callback_get_item_color) - { - int color = list->callback_get_item_color(i, list->data); - /* if color selected */ - if (color >= 0) - { - style |= STYLE_COLORED|color; - } - } -#endif /* draw the selected line */ if( #ifdef HAVE_TOUCHSCREEN @@ -327,73 +271,53 @@ void list_draw(struct screen *display, struct gui_synclist *list) { /* Display colour line selector */ style = STYLE_COLORBAR; + linedes.text_color = global_settings.lst_color; + linedes.line_color = global_settings.lss_color; } else if (global_settings.cursor_style == 3) { /* Display gradient line selector */ style = STYLE_GRADIENT; - - /* Make the lcd driver know how many lines the gradient should - cover and current line number */ - /* number of selected lines */ - style |= NUMLN_PACK(list->selected_size); - /* current line number, zero based */ - style |= CURLN_PACK(cur_line); - cur_line++; + linedes.text_color = global_settings.lst_color; + linedes.line_color = global_settings.lss_color; + linedes.line_end_color = global_settings.lse_color; } #endif - /* if the text is smaller than the viewport size */ - if (item_offset> item_width - (list_text_vp->width - text_pos)) - { - /* don't scroll */ - display->puts_style_xyoffset(0, line, entry_name, - style, item_offset, draw_offset); - } - else - { - display->puts_scroll_style_xyoffset(0, line, entry_name, - style, item_offset, draw_offset); - } + is_selected = true; } - else - { - if (list->scroll_all) - display->puts_scroll_style_xyoffset(0, line, entry_name, - style, item_offset, draw_offset); - else - 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 != NULL) - { - int xoff = show_cursor ? list_icon_width(screen) : ICON_PADDING; - screen_put_iconxy(display, xoff, - line*line_height + draw_offset + icon_yoffset, - list->callback_get_item_icon(i, list->data)); - } - /* do the cursor */ - if (show_cursor && i >= list->selected_item && - i < list->selected_item + list->selected_size) - { - screen_put_iconxy(display, ICON_PADDING, - line*line_height + draw_offset + icon_yoffset, - Icon_Cursor); - } - if (indent) + +#ifdef HAVE_LCD_COLOR + /* if the list has a color callback */ + if (list->callback_get_item_color) { - if (VP_IS_RTL(&list_icons)) - { - list_icons.x += indent; - } - else - { - list_icons.x -= indent; - list_text_vp->x -= indent; + int c = list->callback_get_item_color(i, list->data); + if (c >= 0) + { /* if color selected */ + linedes.text_color = c; + style |= STYLE_COLORED; } - list_text_vp->width += indent; } +#endif + + linedes.style = style; + linedes.scroll = is_selected ?: list->scroll_all; + linedes.line = i % list->selected_size; + + /* the list can have both, one of or neither of cursor and item icons, + * if both don't apply icon padding twice between the icons */ + if (show_cursor && have_icons) + put_line(display, 0, line * linedes.height + draw_offset, + &linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t", + line_indent, is_selected ? Icon_Cursor : Icon_NOICON, + icon, item_offset, entry_name); + else if (show_cursor || have_icons) + put_line(display, 0, line * linedes.height + draw_offset, + &linedes, "$*s$"ICON_PADDING_S"I$*t", line_indent, + show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon, + item_offset, entry_name); + else + put_line(display, 0, line * linedes.height + draw_offset, + &linedes, "$*s$*t", line_indent, item_offset, entry_name); } display->set_viewport(parent); display->update_viewport(); @@ -417,13 +341,13 @@ static int scrollbar_scroll(struct gui_synclist * gui_list, int y) { const int screen = screens[SCREEN_MAIN].screen_type; - const int nb_lines = viewport_get_nb_lines(&list_text[screen]); + const int nb_lines = list_get_nb_lines(gui_list, screen); if (nb_lines < gui_list->nb_items) { /* scrollbar scrolling is still line based */ y_offset = 0; - int scrollbar_size = nb_lines*gui_list->parent[screen]->line_height; + int scrollbar_size = nb_lines*gui_list->line_height[screen]; int actual_y = y - list_text[screen].y; int new_selection = (actual_y * gui_list->nb_items) @@ -547,8 +471,8 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference) { /* fixme */ const enum screen_type screen = screens[SCREEN_MAIN].screen_type; - const int nb_lines = viewport_get_nb_lines(&list_text[screen]); - const int line_height = gui_list->parent[0]->line_height; + const int nb_lines = list_get_nb_lines(gui_list, screen); + const int line_height = gui_list->line_height[screen]; if (UNLIKELY(scroll_begin_threshold == 0)) scroll_begin_threshold = touchscreen_get_scroll_threshold(); @@ -752,7 +676,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list) screen = SCREEN_MAIN; parent = list->parent[screen]; - line_height = list->parent[screen]->line_height; + line_height = list->line_height[screen]; list_start_item = list->start_item[screen]; /* start with getting the action code and finding the click location */ action = action_get_touchscreen_press(&x, &y); diff --git a/apps/gui/charcell/list.c b/apps/gui/charcell/list.c index 753b8ff853..cbee8b0d9d 100644 --- a/apps/gui/charcell/list.c +++ b/apps/gui/charcell/list.c @@ -49,9 +49,8 @@ void gui_synclist_scroll_stop(struct gui_synclist *lists) void list_draw(struct screen *display, struct gui_synclist *gui_list) { - int text_pos; bool draw_icons = (gui_list->callback_get_item_icon != NULL); - bool draw_cursor; + bool selected; int i; int start, end; @@ -61,12 +60,13 @@ void list_draw(struct screen *display, struct gui_synclist *gui_list) start = 0; end = display->getnblines(); - /* Adjust the position of icon, cursor, text for the list */ - draw_cursor = true; - if(draw_icons) - text_pos = 2; /* here it's in chars */ - else - text_pos = 1; + struct line_desc desc = { + .height = -1, + .text_color = 1, + .line_color = 1, + .line_end_color = 1, + .style = STYLE_DEFAULT + }; for (i = start; i < end; i++) { @@ -85,43 +85,26 @@ void list_draw(struct screen *display, struct gui_synclist *gui_list) sizeof(entry_buffer)); entry_name = P2STR(s); + if (gui_list->show_selection_marker && + current_item >= gui_list->selected_item && + current_item < gui_list->selected_item + gui_list->selected_size) + selected = true; /* The selected item must be displayed scrolling */ + else + selected = false; - if(gui_list->show_selection_marker && - current_item >= gui_list->selected_item && - current_item < gui_list->selected_item + gui_list->selected_size) - {/* The selected item must be displayed scrolling */ - display->puts_scroll(text_pos, i, entry_name); + desc.nlines = gui_list->selected_size, + desc.line = gui_list->selected_size > 1 ? i : 0, + desc.scroll = selected ? true : gui_list->scroll_all; - if (draw_cursor) - { - screen_put_icon_with_offset(display, 0, i, - (draw_scrollbar || SHOW_LIST_TITLE)? - SCROLLBAR_WIDTH: 0, - 0, Icon_Cursor); - } - } + if (draw_icons) + put_line(display, 0, i, &desc, "$i$i$t", + selected ? Icon_Cursor : Icon_NOICON, + gui_list->callback_get_item_icon(current_item, gui_list->data), + entry_name); else - {/* normal item */ - if(gui_list->scroll_all) - { - display->puts_scroll(text_pos, i, entry_name); - } - else - { - display->puts(text_pos, i, entry_name); - } - } - /* Icons display */ - if(draw_icons) - { - enum themable_icons icon; - icon = gui_list->callback_get_item_icon(current_item, - gui_list->data); - if(icon > Icon_NOICON) - { - screen_put_icon(display, 1, i, icon); - } - } + put_line(display, 0, i, &desc, "$i$t", + selected ? Icon_Cursor : Icon_NOICON, + entry_name); } display->update_viewport(); diff --git a/apps/gui/list.c b/apps/gui/list.c index 27032378c3..c393340c57 100644 --- a/apps/gui/list.c +++ b/apps/gui/list.c @@ -78,25 +78,6 @@ void list_init(void) add_event(GUI_EVENT_THEME_CHANGED, false, list_force_reinit); } -#ifdef HAVE_TOUCHSCREEN -static int line_height_from_lcd_dpi(const struct viewport *vp) -{ - /* the 4/12 factor is designed for reasonable item size on a 160dpi screen */ - return MAX(lcd_get_dpi()*4/12, (int)font_get(vp->font)->height); -} -#endif - -static int list_line_height(const struct viewport *vp) -{ -#ifdef HAVE_TOUCHSCREEN - if (global_settings.list_line_padding == -1) - return line_height_from_lcd_dpi(vp); - return font_get(vp->font)->height + global_settings.list_line_padding; -#else - return font_get(vp->font)->height; -#endif -} - static void list_init_viewports(struct gui_synclist *list) { bool parent_used = (*list->parent == &parent[SCREEN_MAIN]); @@ -127,29 +108,50 @@ static struct viewport parent[NB_SCREENS] = #endif #ifdef HAVE_LCD_BITMAP +static int list_nb_lines(struct gui_synclist *list, enum screen_type screen) +{ + struct viewport *vp = list->parent[screen]; + return vp->height / list->line_height[screen]; +} + bool list_display_title(struct gui_synclist *list, enum screen_type screen) { return list->title != NULL && !sb_set_title_text(list->title, list->title_icon, screen) && - viewport_get_nb_lines(list->parent[screen]) > 2; + list_nb_lines(list, screen) > 2; } -static int list_get_nb_lines(struct gui_synclist *list, enum screen_type screen) +int list_get_nb_lines(struct gui_synclist *list, enum screen_type screen) { - struct viewport *vp = list->parent[screen]; int lines = skinlist_get_line_count(screen, list); if (lines < 0) { - lines = viewport_get_nb_lines(vp); + lines = list_nb_lines(list, screen); if (list_display_title(list, screen)) lines -= 1; } return lines; } + +void list_init_item_height(struct gui_synclist *list, enum screen_type screen) +{ + struct viewport *vp = list->parent[screen]; +#ifdef HAVE_TOUCHSCREEN + /* the 4/12 factor is designed for reasonable item size on a 160dpi screen */ + if (global_settings.list_line_padding == -1) + list->line_height[screen] = MAX(lcd_get_dpi()*4/12, (int)font_get(vp->font)->height); + else + list->line_height[screen] = font_get(vp->font)->height + global_settings.list_line_padding; +#else + list->line_height[screen] = font_get(vp->font)->height; +#endif +} + #else #define list_display_title(l, i) false #define list_get_nb_lines(list, screen) \ viewport_get_nb_lines((list)->parent[(screen)]); +#define list_init_item_height(l, i) #endif /* @@ -187,6 +189,8 @@ void gui_synclist_init(struct gui_synclist * gui_list, gui_list->parent[i] = &parent[i]; } list_init_viewports(gui_list); + FOR_NB_SCREENS(i) + list_init_item_height(gui_list, i); gui_list->limit_scroll = false; gui_list->data = data; gui_list->scroll_all = scroll_all; @@ -253,6 +257,8 @@ void gui_synclist_draw(struct gui_synclist *gui_list) if (list_is_dirty(gui_list)) { list_init_viewports(gui_list); + FOR_NB_SCREENS(i) + list_init_item_height(gui_list, i); gui_synclist_select_item(gui_list, gui_list->selected_item); } FOR_NB_SCREENS(i) @@ -502,9 +508,6 @@ void gui_synclist_set_viewport_defaults(struct viewport *vp, enum screen_type screen) { viewport_set_defaults(vp, screen); -#ifdef HAVE_LCD_BITMAP - vp->line_height = list_line_height(vp); -#endif #ifdef HAVE_BUTTONBAR if (screens[screen].has_buttonbar) vp->height -= BUTTONBAR_HEIGHT; diff --git a/apps/gui/list.h b/apps/gui/list.h index 8980573aa3..0f2f51a424 100644 --- a/apps/gui/list.h +++ b/apps/gui/list.h @@ -100,6 +100,8 @@ struct gui_synclist int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */ /* the number of lines that are selected at the same time */ int selected_size; + /* the number of pixels each line occupies (including optional padding on touchscreen */ + int line_height[NB_SCREENS]; #ifdef HAVE_LCD_BITMAP int offset_position[NB_SCREENS]; /* the list's screen scroll placement in pixels */ #endif -- cgit v1.2.3