summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-10-17 17:38:10 +0000
committerThomas Martitz <kugel@rockbox.org>2011-10-17 17:38:10 +0000
commit3b12634e6bc966cb2b2e7f21e9a435cdd20f0bc4 (patch)
tree2f103d5b58b4a22f65e9fd02de4a720022034121
parent859cd4b627a48cab8273d8f4d04e2afeb0ee7c87 (diff)
downloadrockbox-3b12634e6bc966cb2b2e7f21e9a435cdd20f0bc4.tar.gz
rockbox-3b12634e6bc966cb2b2e7f21e9a435cdd20f0bc4.zip
Commit FS#12321 - Touchscreen: List line padding, to more easily select lines
This adds line padding to lists on touchscreens, in order to make lists reasonably useful without huge fonts. It's configurable: * Automatic (default, line height calculated using a lcd dpi aware function) * Off (status quo, line height = font height) * X pixels (from 2 to 50 in even steps) The automatic setting should/aims to Just Work Out Of The Box on all targets git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30773 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/gui/bitmap/list.c38
-rw-r--r--apps/gui/icon.c5
-rw-r--r--apps/gui/icon.h3
-rw-r--r--apps/gui/list.c34
-rw-r--r--apps/gui/viewport.c3
-rw-r--r--apps/gui/viewport.h1
-rw-r--r--apps/lang/english.lang31
-rw-r--r--apps/menus/display_menu.c13
-rw-r--r--apps/settings.h4
-rw-r--r--apps/settings_list.c29
-rw-r--r--firmware/drivers/lcd-bitmap-common.c34
-rw-r--r--firmware/export/lcd.h1
12 files changed, 154 insertions, 42 deletions
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 69cda9fa85..09a66f3386 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -102,13 +102,15 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
102 if (!list_display_title(list, screen)) 102 if (!list_display_title(list, screen))
103 return false; 103 return false;
104 *title_text_vp = *(list->parent[screen]); 104 *title_text_vp = *(list->parent[screen]);
105 title_text_vp->height = font_get(title_text_vp->font)->height; 105 title_text_vp->height = title_text_vp->line_height;
106 106
107 if (list->title_icon != Icon_NOICON && global_settings.show_icons) 107 if (list->title_icon != Icon_NOICON && global_settings.show_icons)
108 { 108 {
109 struct viewport title_icon = *title_text_vp; 109 struct viewport title_icon = *title_text_vp;
110 110
111 title_icon.width = get_icon_width(screen) + ICON_PADDING * 2; 111 title_icon.width = get_icon_width(screen) + ICON_PADDING * 2;
112 title_icon.y += (title_icon.height - get_icon_height(screen)) / 2;
113 title_icon.height = get_icon_height(screen);
112 if (VP_IS_RTL(&title_icon)) 114 if (VP_IS_RTL(&title_icon))
113 { 115 {
114 title_icon.x += title_text_vp->width - title_icon.width; 116 title_icon.x += title_text_vp->width - title_icon.width;
@@ -120,7 +122,7 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
120 title_text_vp->width -= title_icon.width; 122 title_text_vp->width -= title_icon.width;
121 123
122 display->set_viewport(&title_icon); 124 display->set_viewport(&title_icon);
123 screen_put_icon(display, 0, 0, list->title_icon); 125 screen_put_iconxy(display, 0, 0, list->title_icon);
124 } 126 }
125#ifdef HAVE_LCD_COLOR 127#ifdef HAVE_LCD_COLOR
126 if (list->title_color >= 0) 128 if (list->title_color >= 0)
@@ -136,7 +138,7 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
136void list_draw(struct screen *display, struct gui_synclist *list) 138void list_draw(struct screen *display, struct gui_synclist *list)
137{ 139{
138 struct viewport list_icons; 140 struct viewport list_icons;
139 int start, end, line_height, style, i; 141 int start, end, line_height, style, item_offset, i;
140 const int screen = display->screen_type; 142 const int screen = display->screen_type;
141 const int list_start_item = list->start_item[screen]; 143 const int list_start_item = list->start_item[screen];
142 const int icon_width = get_icon_width(screen) + ICON_PADDING; 144 const int icon_width = get_icon_width(screen) + ICON_PADDING;
@@ -147,19 +149,21 @@ void list_draw(struct screen *display, struct gui_synclist *list)
147#ifdef HAVE_LCD_COLOR 149#ifdef HAVE_LCD_COLOR
148 unsigned char cur_line = 0; 150 unsigned char cur_line = 0;
149#endif 151#endif
150 int item_offset; 152 int icon_yoffset = 0; /* to center the icon */
151 bool show_title; 153 bool show_title;
152 struct viewport *list_text_vp = &list_text[screen]; 154 struct viewport *list_text_vp = &list_text[screen];
153 155
154 line_height = font_get(parent->font)->height; 156 line_height = parent->line_height;
155 display->set_viewport(parent); 157 display->set_viewport(parent);
156 display->clear_viewport(); 158 display->clear_viewport();
157 display->scroll_stop(list_text_vp); 159 display->scroll_stop(list_text_vp);
158 *list_text_vp = *parent; 160 *list_text_vp = *parent;
161 list_text_vp->line_height = line_height;
159 if ((show_title = draw_title(display, list))) 162 if ((show_title = draw_title(display, list)))
160 { 163 {
161 list_text_vp->y += line_height; 164 int title_height = title_text[screen].height;
162 list_text_vp->height -= line_height; 165 list_text_vp->y += title_height;
166 list_text_vp->height -= title_height;
163 } 167 }
164 168
165 const int nb_lines = viewport_get_nb_lines(list_text_vp); 169 const int nb_lines = viewport_get_nb_lines(list_text_vp);
@@ -232,6 +236,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
232 list_icons.x += list_text_vp->width + ICON_PADDING; 236 list_icons.x += list_text_vp->width + ICON_PADDING;
233 else 237 else
234 list_text_vp->x += list_icons.width + ICON_PADDING; 238 list_text_vp->x += list_icons.width + ICON_PADDING;
239 icon_yoffset = (line_height - get_icon_height(screen)) / 2;
235 } 240 }
236 241
237 for (i=start; i<end && i<list->nb_items; i++) 242 for (i=start; i<end && i<list->nb_items; i++)
@@ -333,14 +338,18 @@ void list_draw(struct screen *display, struct gui_synclist *list)
333 display->set_viewport(&list_icons); 338 display->set_viewport(&list_icons);
334 if (list->callback_get_item_icon != NULL) 339 if (list->callback_get_item_icon != NULL)
335 { 340 {
336 screen_put_icon_with_offset(display, show_cursor?1:0, 341 int xoff = show_cursor ? get_icon_width(screen) + ICON_PADDING : 0;
337 (line),show_cursor?ICON_PADDING:0,draw_offset, 342 screen_put_iconxy(display, xoff,
338 list->callback_get_item_icon(i, list->data)); 343 line*line_height + draw_offset + icon_yoffset,
344 list->callback_get_item_icon(i, list->data));
339 } 345 }
346 /* do the cursor */
340 if (show_cursor && i >= list->selected_item && 347 if (show_cursor && i >= list->selected_item &&
341 i < list->selected_item + list->selected_size) 348 i < list->selected_item + list->selected_size)
342 { 349 {
343 screen_put_icon_with_offset(display, 0, line, 0, draw_offset, Icon_Cursor); 350 screen_put_iconxy(display, 0,
351 line*line_height + draw_offset + icon_yoffset,
352 Icon_Cursor);
344 } 353 }
345 } 354 }
346 display->set_viewport(parent); 355 display->set_viewport(parent);
@@ -369,8 +378,7 @@ static int scrollbar_scroll(struct gui_synclist * gui_list,
369 { 378 {
370 /* scrollbar scrolling is still line based */ 379 /* scrollbar scrolling is still line based */
371 y_offset = 0; 380 y_offset = 0;
372 int scrollbar_size = nb_lines* 381 int scrollbar_size = nb_lines*gui_list->parent[screen]->line_height;
373 font_get(gui_list->parent[screen]->font)->height;
374 int actual_y = y - list_text[screen].y; 382 int actual_y = y - list_text[screen].y;
375 383
376 int new_selection = (actual_y * gui_list->nb_items) 384 int new_selection = (actual_y * gui_list->nb_items)
@@ -558,7 +566,7 @@ static int kinetic_callback(struct timeout *tmo)
558 return 0; 566 return 0;
559 567
560 struct cb_data *data = (struct cb_data*)tmo->data; 568 struct cb_data *data = (struct cb_data*)tmo->data;
561 int line_height = font_get(data->list->parent[0]->font)->height; 569 int line_height = data->list->parent[0]->line_height;
562 /* ds = v*dt */ 570 /* ds = v*dt */
563 int pixel_diff = data->velocity * RELOAD_INTERVAL / HZ; 571 int pixel_diff = data->velocity * RELOAD_INTERVAL / HZ;
564 /* remember signedness to detect stopping */ 572 /* remember signedness to detect stopping */
@@ -627,7 +635,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
627 struct viewport *parent = gui_list->parent[screen]; 635 struct viewport *parent = gui_list->parent[screen];
628 const int button = action_get_touchscreen_press_in_vp(&x, &y, parent); 636 const int button = action_get_touchscreen_press_in_vp(&x, &y, parent);
629 const int list_start_item = gui_list->start_item[screen]; 637 const int list_start_item = gui_list->start_item[screen];
630 const int line_height = font_get(gui_list->parent[screen]->font)->height; 638 const int line_height = gui_list->parent[screen]->line_height;
631 const struct viewport *list_text_vp = &list_text[screen]; 639 const struct viewport *list_text_vp = &list_text[screen];
632 const bool old_released = released; 640 const bool old_released = released;
633 const bool show_title = list_display_title(gui_list, screen); 641 const bool show_title = list_display_title(gui_list, screen);
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
index 628196a98f..87ea0718fb 100644
--- a/apps/gui/icon.c
+++ b/apps/gui/icon.c
@@ -277,3 +277,8 @@ int get_icon_width(enum screen_type screen_type)
277{ 277{
278 return ICON_WIDTH(screen_type); 278 return ICON_WIDTH(screen_type);
279} 279}
280
281int get_icon_height(enum screen_type screen_type)
282{
283 return ICON_HEIGHT(screen_type);
284}
diff --git a/apps/gui/icon.h b/apps/gui/icon.h
index e79defe798..ca7f04841d 100644
--- a/apps/gui/icon.h
+++ b/apps/gui/icon.h
@@ -109,8 +109,11 @@ void icons_init(void);
109#ifdef HAVE_LCD_CHARCELLS 109#ifdef HAVE_LCD_CHARCELLS
110# define CURSOR_CHAR 0xe10c 110# define CURSOR_CHAR 0xe10c
111# define get_icon_width(a) 6 111# define get_icon_width(a) 6
112# define get_icon_height(a) 1 /* needs to be verified */
112#else 113#else
113int get_icon_width(enum screen_type screen_type); 114int get_icon_width(enum screen_type screen_type);
115int get_icon_height(enum screen_type screen_type);
114#endif 116#endif
115 117
118
116#endif /*_GUI_ICON_H_*/ 119#endif /*_GUI_ICON_H_*/
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 1a90ff9e40..66c3438574 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -78,6 +78,21 @@ void list_init(void)
78 add_event(GUI_EVENT_THEME_CHANGED, false, list_force_reinit); 78 add_event(GUI_EVENT_THEME_CHANGED, false, list_force_reinit);
79} 79}
80 80
81#ifdef HAVE_TOUCHSCREEN
82static int line_height_from_lcd_dpi(const struct viewport *vp)
83{
84 /* the 4/12 factor is designed for reasonable item size on a 160dpi screen */
85 return MAX(lcd_get_dpi()*4/12, (int)font_get(vp->font)->height);
86}
87
88static int list_line_height(const struct viewport *vp)
89{
90 if (global_settings.list_line_padding == -1)
91 return line_height_from_lcd_dpi(vp);
92 return font_get(vp->font)->height + global_settings.list_line_padding;
93}
94#endif
95
81static void list_init_viewports(struct gui_synclist *list) 96static void list_init_viewports(struct gui_synclist *list)
82{ 97{
83 int parent_used; 98 int parent_used;
@@ -90,6 +105,9 @@ static void list_init_viewports(struct gui_synclist *list)
90 { 105 {
91 list->parent[i] = &parent[i]; 106 list->parent[i] = &parent[i];
92 viewport_set_defaults(&parent[i], i); 107 viewport_set_defaults(&parent[i], i);
108#ifdef HAVE_TOUCHSCREEN
109 parent[i].line_height = list_line_height(list->parent[i]);
110#endif
93#ifdef HAVE_BUTTONBAR 111#ifdef HAVE_BUTTONBAR
94 if (screens[i].has_buttonbar) 112 if (screens[i].has_buttonbar)
95 list->parent[i]->height -= BUTTONBAR_HEIGHT; 113 list->parent[i]->height -= BUTTONBAR_HEIGHT;
@@ -124,13 +142,15 @@ bool list_display_title(struct gui_synclist *list, enum screen_type screen)
124 142
125static int list_get_nb_lines(struct gui_synclist *list, enum screen_type screen) 143static int list_get_nb_lines(struct gui_synclist *list, enum screen_type screen)
126{ 144{
127 struct viewport vp = *list->parent[screen]; 145 struct viewport *vp = list->parent[screen];
128 int skin_count = skinlist_get_line_count(screen, list); 146 int lines = skinlist_get_line_count(screen, list);
129 if (skin_count >= 0) 147 if (lines < 0)
130 return skin_count; 148 {
131 if (list_display_title(list, screen)) 149 lines = viewport_get_nb_lines(vp);
132 vp.height -= font_get(list->parent[screen]->font)->height; 150 if (list_display_title(list, screen))
133 return viewport_get_nb_lines(&vp); 151 lines -= 1;
152 }
153 return lines;
134} 154}
135#else 155#else
136#define list_display_title(l, i) false 156#define list_display_title(l, i) false
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c
index 2ab6c343ef..c5e44270d4 100644
--- a/apps/gui/viewport.c
+++ b/apps/gui/viewport.c
@@ -223,7 +223,7 @@ static bool is_theme_enabled(enum screen_type screen)
223int viewport_get_nb_lines(const struct viewport *vp) 223int viewport_get_nb_lines(const struct viewport *vp)
224{ 224{
225#ifdef HAVE_LCD_BITMAP 225#ifdef HAVE_LCD_BITMAP
226 return vp->height/font_get(vp->font)->height; 226 return vp->height/vp->line_height;
227#else 227#else
228 (void)vp; 228 (void)vp;
229 return 2; 229 return 2;
@@ -318,6 +318,7 @@ void viewport_set_fullscreen(struct viewport *vp,
318 set_default_align_flags(vp); 318 set_default_align_flags(vp);
319#endif 319#endif
320 vp->font = global_status.font_id[screen]; 320 vp->font = global_status.font_id[screen];
321 vp->line_height = font_get(vp->font)->height;
321 vp->drawmode = DRMODE_SOLID; 322 vp->drawmode = DRMODE_SOLID;
322#if LCD_DEPTH > 1 323#if LCD_DEPTH > 1
323#ifdef HAVE_REMOTE_LCD 324#ifdef HAVE_REMOTE_LCD
diff --git a/apps/gui/viewport.h b/apps/gui/viewport.h
index 51ab35e575..3da001e190 100644
--- a/apps/gui/viewport.h
+++ b/apps/gui/viewport.h
@@ -35,6 +35,7 @@ int viewport_get_nb_lines(const struct viewport *vp);
35#define THEME_UI_VIEWPORT (BIT_N(1)) 35#define THEME_UI_VIEWPORT (BIT_N(1))
36#define THEME_BUTTONBAR (BIT_N(2)) 36#define THEME_BUTTONBAR (BIT_N(2))
37#define THEME_LANGUAGE (BIT_N(3)) 37#define THEME_LANGUAGE (BIT_N(3))
38#define THEME_LISTS (BIT_N(3))
38#define THEME_ALL (~(0u)) 39#define THEME_ALL (~(0u))
39 40
40#ifndef __PCTOOL__ 41#ifndef __PCTOOL__
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 0e4d4bfc04..eb3c963512 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12830,3 +12830,34 @@
12830 multidrive_usb: "USB Hide Internal Drive" 12830 multidrive_usb: "USB Hide Internal Drive"
12831 </voice> 12831 </voice>
12832</phrase> 12832</phrase>
12833<phrase>
12834 id: LANG_LIST_LINE_PADDING
12835 desc: list padding, in display settings
12836 user: core
12837 <source>
12838 *: none
12839 touchscreen: "Line Padding in Lists"
12840 </source>
12841 <dest>
12842 *: none
12843 touchscreen: "Line Padding in Lists"
12844 </dest>
12845 <voice>
12846 *: none
12847 touchscreen: "Line Padding in Lists"
12848 </voice>
12849</phrase>
12850<phrase>
12851 id: LANG_AUTOMATIC
12852 desc: generic automatic
12853 user: core
12854 <source>
12855 *: "Automatic"
12856 </source>
12857 <dest>
12858 *: "Automatic"
12859 </dest>
12860 <voice>
12861 *: "Automatic"
12862 </voice>
12863</phrase>
diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c
index 7e7b5a6903..957307d8a8 100644
--- a/apps/menus/display_menu.c
+++ b/apps/menus/display_menu.c
@@ -500,14 +500,25 @@ static int touch_mode_callback(int action,const struct menu_item_ex *this_item)
500 } 500 }
501 return action; 501 return action;
502} 502}
503
504static int line_padding_callback(int action,const struct menu_item_ex *this_item)
505{
506 (void)this_item;
507
508 if (action == ACTION_EXIT_MENUITEM)
509 viewportmanager_theme_changed(THEME_LISTS);
510 return action;
511}
512
503MENUITEM_SETTING(touch_mode, &global_settings.touch_mode, touch_mode_callback); 513MENUITEM_SETTING(touch_mode, &global_settings.touch_mode, touch_mode_callback);
504 514
505MENUITEM_FUNCTION(touchscreen_menu_calibrate, 0, ID2P(LANG_TOUCHSCREEN_CALIBRATE), calibrate, 515MENUITEM_FUNCTION(touchscreen_menu_calibrate, 0, ID2P(LANG_TOUCHSCREEN_CALIBRATE), calibrate,
506 NULL, NULL, Icon_NOICON); 516 NULL, NULL, Icon_NOICON);
507MENUITEM_FUNCTION(touchscreen_menu_reset_calibration, 0, ID2P(LANG_TOUCHSCREEN_RESET_CALIBRATION), reset_mapping, 517MENUITEM_FUNCTION(touchscreen_menu_reset_calibration, 0, ID2P(LANG_TOUCHSCREEN_RESET_CALIBRATION), reset_mapping,
508 NULL, NULL, Icon_NOICON); 518 NULL, NULL, Icon_NOICON);
519MENUITEM_SETTING(list_line_padding, &global_settings.list_line_padding, line_padding_callback);
509 520
510MAKE_MENU(touchscreen_menu, ID2P(LANG_TOUCHSCREEN_SETTINGS), NULL, Icon_NOICON, &touch_mode, 521MAKE_MENU(touchscreen_menu, ID2P(LANG_TOUCHSCREEN_SETTINGS), NULL, Icon_NOICON, &list_line_padding, &touch_mode,
511 &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration); 522 &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration);
512#endif 523#endif
513 524
diff --git a/apps/settings.h b/apps/settings.h
index 36e403be1b..927b17bf08 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -562,6 +562,10 @@ struct user_settings
562 int scrollbar_width; 562 int scrollbar_width;
563#endif 563#endif
564 564
565#ifdef HAVE_TOUCHSCREEN
566 int list_line_padding;
567#endif
568
565 /* goto current song when exiting WPS */ 569 /* goto current song when exiting WPS */
566 bool browse_current; /* 1=goto current song, 570 bool browse_current; /* 1=goto current song,
567 0=goto previous location */ 571 0=goto previous location */
diff --git a/apps/settings_list.c b/apps/settings_list.c
index eb62b9b975..a3d6587d0c 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -286,6 +286,29 @@ static const char graphic_numeric[] = "graphic,numeric";
286 286
287#endif /* HAVE_RECORDING */ 287#endif /* HAVE_RECORDING */
288 288
289static const char* list_pad_formatter(char *buffer, size_t buffer_size,
290 int val, const char *unit)
291{
292 switch (val)
293 {
294 case -1: return str(LANG_AUTOMATIC);
295 case 0: return str(LANG_OFF);
296 default: break;
297 }
298 snprintf(buffer, buffer_size, "%d %s", val, unit);
299 return buffer;
300}
301
302static int32_t list_pad_getlang(int value, int unit)
303{
304 switch (value)
305 {
306 case -1: return LANG_AUTOMATIC;
307 case 0: return LANG_OFF;
308 default: return TALK_ID(value, unit);
309 }
310}
311
289static const char* formatter_unit_0_is_off(char *buffer, size_t buffer_size, 312static const char* formatter_unit_0_is_off(char *buffer, size_t buffer_size,
290 int val, const char *unit) 313 int val, const char *unit)
291{ 314{
@@ -740,6 +763,12 @@ const struct settings_list settings[] = {
740 INT_SETTING(F_THEMESETTING, scrollbar_width, LANG_SCROLLBAR_WIDTH, 6, 763 INT_SETTING(F_THEMESETTING, scrollbar_width, LANG_SCROLLBAR_WIDTH, 6,
741 "scrollbar width",UNIT_INT, 3, MAX(LCD_WIDTH/10,25), 1, 764 "scrollbar width",UNIT_INT, 3, MAX(LCD_WIDTH/10,25), 1,
742 NULL, NULL, NULL), 765 NULL, NULL, NULL),
766#ifdef HAVE_TOUCHSCREEN
767 TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, list_line_padding, LANG_LIST_LINE_PADDING,
768 -1, "list padding", "off,auto", UNIT_PIXEL, list_pad_formatter,
769 list_pad_getlang, NULL, 16,
770 -1,0,2,4,6,8,10,12,16,20,24,28,32,38,44,50),
771#endif
743#if CONFIG_KEYPAD == RECORDER_PAD 772#if CONFIG_KEYPAD == RECORDER_PAD
744 OFFON_SETTING(F_THEMESETTING,buttonbar, LANG_BUTTON_BAR ,true,"buttonbar", NULL), 773 OFFON_SETTING(F_THEMESETTING,buttonbar, LANG_BUTTON_BAR ,true,"buttonbar", NULL),
745#endif 774#endif
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index fc84fdd6a1..8d95825858 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -254,11 +254,12 @@ void LCDFN(putsxyf)(int x, int y, const unsigned char *fmt, ...)
254 254
255static void LCDFN(putsxyofs_style)(int xpos, int ypos, 255static void LCDFN(putsxyofs_style)(int xpos, int ypos,
256 const unsigned char *str, int style, 256 const unsigned char *str, int style,
257 int w, int h, int offset) 257 int h, int offset)
258{ 258{
259 int lastmode = current_vp->drawmode; 259 int lastmode = current_vp->drawmode;
260 int xrect = xpos + MAX(w - offset, 0); 260 int text_ypos = ypos;
261 int x = VP_IS_RTL(current_vp) ? xpos : xrect; 261 int line_height = font_get(current_vp->font)->height;
262 text_ypos += h/2 - line_height/2; /* center the text in the line */
262#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) 263#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
263 int oldfgcolor = current_vp->fg_pattern; 264 int oldfgcolor = current_vp->fg_pattern;
264 int oldbgcolor = current_vp->bg_pattern; 265 int oldbgcolor = current_vp->bg_pattern;
@@ -284,21 +285,21 @@ static void LCDFN(putsxyofs_style)(int xpos, int ypos,
284 current_vp->fg_pattern = current_vp->lst_pattern; 285 current_vp->fg_pattern = current_vp->lst_pattern;
285 } 286 }
286 else { 287 else {
287 lcd_fillrect(x, ypos, current_vp->width - xrect, h); 288 lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
288 current_vp->drawmode = (style & STYLE_INVERT) ? 289 current_vp->drawmode = (style & STYLE_INVERT) ?
289 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 290 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
290 } 291 }
291 if (str[0]) 292 if (str[0])
292 lcd_putsxyofs(xpos, ypos, offset, str); 293 lcd_putsxyofs(xpos, text_ypos, offset, str);
293 current_vp->fg_pattern = oldfgcolor; 294 current_vp->fg_pattern = oldfgcolor;
294 current_vp->bg_pattern = oldbgcolor; 295 current_vp->bg_pattern = oldbgcolor;
295#else 296#else
296 current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ? 297 current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ?
297 0 : DRMODE_INVERSEVID); 298 0 : DRMODE_INVERSEVID);
298 LCDFN(fillrect)(x, ypos, current_vp->width - xrect, h); 299 LCDFN(fillrect)(xpos, ypos, current_vp->width - xpos, h);
299 current_vp->drawmode ^= DRMODE_INVERSEVID; 300 current_vp->drawmode ^= DRMODE_INVERSEVID;
300 if (str[0]) 301 if (str[0])
301 LCDFN(putsxyofs)(xpos, ypos, offset, str); 302 LCDFN(putsxyofs)(xpos, text_ypos, offset, str);
302#endif 303#endif
303 current_vp->drawmode = lastmode; 304 current_vp->drawmode = lastmode;
304} 305}
@@ -309,15 +310,15 @@ static void LCDFN(putsxyofs_style)(int xpos, int ypos,
309void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str, 310void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str,
310 int style, int x_offset, int y_offset) 311 int style, int x_offset, int y_offset)
311{ 312{
312 int xpos, ypos, w, h; 313 int xpos, ypos, h;
313 LCDFN(scroll_stop_line)(current_vp, y); 314 LCDFN(scroll_stop_line)(current_vp, y);
314 if(!str) 315 if(!str)
315 return; 316 return;
316 317
317 LCDFN(getstringsize)(str, &w, &h); 318 h = current_vp->line_height ?: (int)font_get(current_vp->font)->height;
318 xpos = x * LCDFN(getstringsize)(" ", NULL, NULL); 319 xpos = x * LCDFN(getstringsize)(" ", NULL, NULL);
319 ypos = y * h + y_offset; 320 ypos = y * h + y_offset;
320 LCDFN(putsxyofs_style)(xpos, ypos, str, style, w, h, x_offset); 321 LCDFN(putsxyofs_style)(xpos, ypos, str, style, h, x_offset);
321} 322}
322 323
323void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, 324void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
@@ -436,10 +437,9 @@ void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
436 437
437void LCDFN(scroll_fn)(void) 438void LCDFN(scroll_fn)(void)
438{ 439{
439 struct font* pf;
440 struct scrollinfo* s; 440 struct scrollinfo* s;
441 int index; 441 int index;
442 int xpos, ypos; 442 int xpos, ypos, height;
443 struct viewport* old_vp = current_vp; 443 struct viewport* old_vp = current_vp;
444 bool makedelay; 444 bool makedelay;
445 445
@@ -451,15 +451,15 @@ void LCDFN(scroll_fn)(void)
451 continue; 451 continue;
452 452
453 LCDFN(set_viewport)(s->vp); 453 LCDFN(set_viewport)(s->vp);
454 height = s->vp->line_height;
454 455
455 if (s->backward) 456 if (s->backward)
456 s->offset -= LCDFN(scroll_info).step; 457 s->offset -= LCDFN(scroll_info).step;
457 else 458 else
458 s->offset += LCDFN(scroll_info).step; 459 s->offset += LCDFN(scroll_info).step;
459 460
460 pf = font_get(current_vp->font);
461 xpos = s->startx; 461 xpos = s->startx;
462 ypos = s->y * pf->height + s->y_offset; 462 ypos = s->y * height + s->y_offset;
463 463
464 makedelay = false; 464 makedelay = false;
465 if (s->bidir) { /* scroll bidirectional */ 465 if (s->bidir) { /* scroll bidirectional */
@@ -488,10 +488,8 @@ void LCDFN(scroll_fn)(void)
488 s->start_tick = current_tick + LCDFN(scroll_info).delay + 488 s->start_tick = current_tick + LCDFN(scroll_info).delay +
489 LCDFN(scroll_info).ticks; 489 LCDFN(scroll_info).ticks;
490 490
491 LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, s->width, 491 LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, height, s->offset);
492 pf->height, s->offset); 492 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width-xpos, height);
493 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos,
494 pf->height);
495 } 493 }
496 LCDFN(set_viewport)(old_vp); 494 LCDFN(set_viewport)(old_vp);
497} 495}
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index e6e19b1597..56e19ddefa 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -43,6 +43,7 @@ struct viewport {
43#ifdef HAVE_LCD_BITMAP 43#ifdef HAVE_LCD_BITMAP
44 int flags; 44 int flags;
45 int font; 45 int font;
46 int line_height;
46 int drawmode; 47 int drawmode;
47#endif 48#endif
48#if LCD_DEPTH > 1 49#if LCD_DEPTH > 1