text viewer: reworks screen access logics and some bugs fix.

- screen access logics separte from tv_window. (new tv_display.[ch])
- using multi screen api.
- (bug fix) the head of the each line is not normally displayed when the alignment is RIGHT.
- (bug fix) unnecessary blank line is not displayed. (a part of FS#11400).
- (bug fix) the order by which callback functions were called was not correct. (FIFO->FILO)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27138 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Yoshihisa Uchida 2010-06-26 09:14:53 +00:00
parent be70fd89be
commit ac622c6d67
6 changed files with 567 additions and 156 deletions

View file

@ -1,6 +1,7 @@
text_viewer.c
tv_action.c
tv_bookmark.c
tv_display.c
tv_menu.c
tv_pager.c
tv_preferences.c

View file

@ -0,0 +1,344 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Yoshihisa Uchida
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "tv_display.h"
#include "tv_preferences.h"
/*
* display layout
*
* when is defined HAVE_LCD_BITMAP
* +-------------------------+
* |statusbar (1) |
* +-------------------------+
* |filename (2) |
* +---+---------------------+
* |s | |
* |c | |
* |r | draw area |
* |o | |
* |l | |
* |l | |
* |b | |
* |a | |
* |r | |
* |(3)| |
* +---+---------------------+
* | |scrollbar (4) |
* +---+---------------------+
* |page (5) |
* +-------------------------+
* |statusbar (6) |
* +-------------------------+
*
* (1) displays when rb->global_settings->statusbar == STATUSBAR_TOP
* and preferences->header_mode is HD_SBAR or HD_BOTH.
* (2) displays when preferences->header_mode is HD_PATH or HD_BOTH.
* (3) displays when preferences->vertical_scrollbar is SB_ON.
* (4) displays when preferences->horizontal_scrollbar is SB_ON.
* (5) displays when preferences->footer_mode is FT_PAGE or FT_BOTH.
* (6) displays when rb->global_settings->statusbar == STATUSBAR_BOTTOM
* and preferences->footer_mode is FT_SBAR or FT_BOTH.
*
*
* when isn't defined HAVE_LCD_BITMAP
* +---+---------------------+
* | | |
* |(7)| draw area |
* | | |
* +---+---------------------+
* (7) bookmark
*/
#define TV_SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
#define TV_SCROLLBAR_HEIGHT 4
#ifndef HAVE_LCD_BITMAP
#define TV_BOOKMARK_ICON 0xe101
#endif
struct tv_rect {
int x;
int y;
int w;
int h;
};
static struct viewport vp_info;
static bool is_initialized_vp = false;
#ifdef HAVE_LCD_BITMAP
static int drawmode = DRMODE_SOLID;
static int totalsize;
static bool show_vertical_scrollbar;
#endif
static struct screen* display;
/* layout */
#ifdef HAVE_LCD_BITMAP
static struct tv_rect header;
static struct tv_rect footer;
static struct tv_rect horizontal_scrollbar;
static struct tv_rect vertical_scrollbar;
#else
static struct tv_rect bookmark;
#endif
static struct tv_rect drawarea;
static int display_columns;
static int display_rows;
static int col_width;
static int row_height;
#ifdef HAVE_LCD_BITMAP
void tv_show_header(void)
{
unsigned header_mode = header_mode;
if (preferences->header_mode == HD_PATH || preferences->header_mode == HD_BOTH)
display->putsxy(header.x, header.y, preferences->file_name);
}
void tv_show_footer(const struct tv_screen_pos *pos)
{
unsigned char buf[12];
unsigned footer_mode = preferences->footer_mode;
if (footer_mode == FT_PAGE || footer_mode == FT_BOTH)
{
if (pos->line == 0)
rb->snprintf(buf, sizeof(buf), "%d", pos->page + 1);
else
rb->snprintf(buf, sizeof(buf), "%d - %d", pos->page + 1, pos->page + 2);
display->putsxy(footer.x, footer.y, buf);
}
}
void tv_init_scrollbar(off_t total, bool show_scrollbar)
{
totalsize = total;
show_vertical_scrollbar = show_scrollbar;
}
void tv_show_scrollbar(int window, int col, off_t cur_pos, int size)
{
int items;
int min_shown;
int max_shown;
if (preferences->horizontal_scrollbar)
{
items = preferences->windows * display_columns;
min_shown = window * display_columns + col;
max_shown = min_shown + display_columns;
rb->gui_scrollbar_draw(display,
horizontal_scrollbar.x, horizontal_scrollbar.y,
horizontal_scrollbar.w, TV_SCROLLBAR_HEIGHT,
items, min_shown, max_shown, HORIZONTAL);
}
if (show_vertical_scrollbar)
{
items = (int) totalsize;
min_shown = (int) cur_pos;
max_shown = min_shown + size;
rb->gui_scrollbar_draw(display,
vertical_scrollbar.x, vertical_scrollbar.y,
TV_SCROLLBAR_WIDTH-1, vertical_scrollbar.h,
items, min_shown, max_shown, VERTICAL);
}
}
void tv_fillrect(int col, int row, int rows)
{
display->fillrect(drawarea.x + col * col_width, drawarea.y + row * row_height,
drawarea.w - col * col_width, rows * row_height);
}
void tv_set_drawmode(int mode)
{
rb->lcd_set_drawmode(mode);
}
#endif
void tv_draw_text(int row, const unsigned char *text, int offset)
{
int xpos = -offset * col_width;
int text_width;
if (row < 0 || row >= display_rows)
return;
if (preferences->alignment == AL_RIGHT)
{
display->getstringsize(text, &text_width, NULL);
xpos += ((offset > 0)? drawarea.w * 2 : drawarea.w) - text_width;
}
#ifdef HAVE_LCD_BITMAP
display->putsxy(drawarea.x + xpos, drawarea.y + row * row_height, text);
#else
display->puts(drawarea.x + xpos, drawarea.y + row, text);
#endif
}
#ifndef HAVE_LCD_BITMAP
void tv_put_bookmark_icon(int row)
{
display->putchar(bookmark.x, drawarea.y + row, TV_BOOKMARK_ICON);
}
#endif
void tv_init_display(void)
{
display = rb->screens[SCREEN_MAIN];
display->clear_viewport();
}
void tv_start_display(void)
{
display->set_viewport(&vp_info);
#ifdef HAVE_LCD_BITMAP
drawmode = rb->lcd_get_drawmode();
#endif
}
void tv_end_display(void)
{
#ifdef HAVE_LCD_BITMAP
rb->lcd_set_drawmode(drawmode);
#endif
display->set_viewport(NULL);
}
void tv_clear_display(void)
{
display->clear_viewport();
}
void tv_update_display(void)
{
display->update_viewport();
}
#ifdef HAVE_LCD_BITMAP
void tv_set_layout(int col_w, bool show_scrollbar)
#else
void tv_set_layout(int col_w)
#endif
{
#ifdef HAVE_LCD_BITMAP
int scrollbar_width = (show_scrollbar)? TV_SCROLLBAR_WIDTH : 0;
int scrollbar_height = (preferences->horizontal_scrollbar)? TV_SCROLLBAR_HEIGHT : 0;
unsigned header_mode = preferences->header_mode;
unsigned footer_mode = preferences->footer_mode;
row_height = preferences->font->height;
header.x = 0;
header.y = 0;
header.w = vp_info.width;
header.h = (header_mode == HD_PATH || header_mode == HD_BOTH)? row_height : 0;
footer.x = 0;
footer.w = vp_info.width;
footer.h = (footer_mode == FT_PAGE || footer_mode == FT_BOTH)? row_height : 0;
footer.y = vp_info.height - footer.h;
drawarea.x = scrollbar_width;
drawarea.y = header.y + header.h;
drawarea.w = vp_info.width - scrollbar_width;
drawarea.h = footer.y - drawarea.y - scrollbar_height;
horizontal_scrollbar.x = drawarea.x;
horizontal_scrollbar.y = footer.y - scrollbar_height;
horizontal_scrollbar.w = drawarea.w;
horizontal_scrollbar.h = scrollbar_height;
vertical_scrollbar.x = 0;
vertical_scrollbar.y = drawarea.y;
vertical_scrollbar.w = scrollbar_width;
vertical_scrollbar.h = drawarea.h;
#else
row_height = 1;
bookmark.x = 0;
bookmark.y = 0;
bookmark.w = 1;
bookmark.h = vp_info.height;
drawarea.x = 1;
drawarea.y = 0;
drawarea.w = vp_info.width - 1;
drawarea.h = vp_info.height;
#endif
col_width = col_w;
display_columns = drawarea.w / col_width;
display_rows = drawarea.h / row_height;
}
void tv_get_drawarea_info(int *width, int *cols, int *rows)
{
*width = drawarea.w;
*cols = display_columns;
*rows = display_rows;
}
void tv_change_viewport(void)
{
#ifdef HAVE_LCD_BITMAP
struct viewport vp;
bool show_statusbar = (preferences->header_mode == HD_SBAR ||
preferences->header_mode == HD_BOTH ||
preferences->footer_mode == FT_SBAR ||
preferences->footer_mode == FT_BOTH);
if (is_initialized_vp)
tv_undo_viewport();
else
is_initialized_vp = true;
rb->viewportmanager_theme_enable(SCREEN_MAIN, show_statusbar, &vp);
vp_info = vp;
vp_info.flags &= ~VP_FLAG_ALIGNMENT_MASK;
#else
if (!is_initialized_vp)
{
rb->viewport_set_defaults(&vp_info, SCREEN_MAIN);
is_initialized_vp = true;
}
#endif
}
void tv_undo_viewport(void)
{
#ifdef HAVE_LCD_BITMAP
if (is_initialized_vp)
rb->viewportmanager_theme_undo(SCREEN_MAIN, false);
#endif
}

View file

@ -0,0 +1,175 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Yoshihisa Uchida
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef PLUGIN_TEXT_VIEWER_DISPLAY_H
#define PLUGIN_TEXT_VIEWER_DISPLAY_H
#include "plugin.h"
#include "tv_screen_pos.h"
/* text viewer layout parts functions */
#ifdef HAVE_LCD_BITMAP
/* show headaer */
void tv_show_header(void);
/*
* show footer
*
* [In] pos
* the current position
*/
void tv_show_footer(const struct tv_screen_pos *pos);
/*
* initialize the scrollbar
*
* [In] total
* total text size
*
* [In] show_scrollbar
* true: show the vertical scrollbar
* false: does not show the vertical scrollbar
*/
void tv_init_scrollbar(off_t total, bool show_scrollbar);
/*
* show horizontal/vertical scrollbar
*
* [In] window
* the current window
*
* [In] col
* the current column
*
* [In] cur_pos
* the current text position
*
* [In] size
* the size of text in displayed.
*/
void tv_show_scrollbar(int window, int col, off_t cur_pos, int size);
#else
/*
* put the bookmark icon
*
* [In] row
* the row where the bookmark icon is put
*/
void tv_put_bookmark_icon(int row);
#endif
/* common display functons */
/* initialized display functions */
void tv_init_display(void);
/* start the display processing */
void tv_start_display(void);
/* end the display processing */
void tv_end_display(void);
/* clear the display */
void tv_clear_display(void);
/*update the display */
void tv_update_display(void);
#ifdef HAVE_LCD_BITMAP
/*
* set the drawmode
*
* [In] mode
* new drawmode
*/
void tv_set_drawmode(int mode);
/*
* draw the rectangle that paints out inside
*
* [In] col
* the column of the upper left
*
* [In] row
* the row of the upper left
*
* [In] row
* draw rows
*/
void tv_fillrect(int col, int row, int rows);
#endif
/*
* draw the text
*
* [In] row
* the row that displays the text
*
* [In] text
* text
*
* [In] offset
* display the text that is since offset columns
*/
void tv_draw_text(int row, const unsigned char *text, int offset);
/* layout functions */
#ifdef HAVE_LCD_BITMAP
/*
* set the layout
*
* [In] col_w
* width per column
*
* [In] show_scrollbar
* true: show the vertical scrollbar
* false: does not show the vertical scrollbar
*/
void tv_set_layout(int col_w, bool show_scrollbar);
#else
/*
* set the layout
*
* [In] col_w
* width per column
*/
void tv_set_layout(int col_w);
#endif
void tv_get_drawarea_info(int *width, int *cols, int *rows);
/* viewport functions */
/* change the viewport */
void tv_change_viewport(void);
/* undo the viewport */
void tv_undo_viewport(void);
#endif

View file

@ -62,7 +62,8 @@ static void tv_notify_change_preferences(const struct tv_preferences *oldp)
#endif
(rb->strcmp(oldp->file_name, preferences->file_name)))
{
for (i = 0; i < listner_count; i++)
/* callback functions are called as FILO */
for (i = listner_count - 1; i >= 0; i--)
listners[i](oldp);
}
}

View file

@ -512,7 +512,8 @@ int tv_create_formed_text(const unsigned char *src, ssize_t bufsize,
tv_get_ucs(src, &ch);
is_indent = (tv_isspace(ch) && !is_break_line);
if (is_indent && preferences->indent_spaces == 0 && (expand_extra_line = !expand_extra_line) == true)
if (is_indent && preferences->line_mode == LM_REFLOW && preferences->indent_spaces == 0
&& (expand_extra_line = !expand_extra_line) == true)
return 0;
for (i = 0; i < block_count; i++)

View file

@ -22,29 +22,15 @@
****************************************************************************/
#include "plugin.h"
#include "tv_bookmark.h"
#include "tv_display.h"
#include "tv_preferences.h"
#include "tv_screen_pos.h"
#include "tv_text_reader.h"
#include "tv_window.h"
#define TV_SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
#define TV_SCROLLBAR_HEIGHT 4
#ifndef HAVE_LCD_BITMAP
#define TV_BOOKMARK_ICON 0xe101
#endif
#ifdef HAVE_LCD_BITMAP
static int header_height;
static int footer_height;
static bool need_vertical_scrollbar = false;
#endif
static int start_width;
static int display_lines;
static int window_width;
static int window_columns;
static int display_lines;
static int col_width;
static int cur_window;
@ -100,96 +86,6 @@ static bool tv_check_header_and_footer(struct tv_preferences *new_prefs)
return change_prefs;
}
static void tv_show_header(void)
{
unsigned header_mode = header_mode;
if (header_mode == HD_SBAR || header_mode == HD_BOTH)
rb->gui_syncstatusbar_draw(rb->statusbars, true);
if (header_mode == HD_PATH || header_mode == HD_BOTH)
rb->lcd_putsxy(0, header_height - preferences->font->height, preferences->file_name);
}
static void tv_show_footer(const struct tv_screen_pos *pos)
{
unsigned char buf[12];
unsigned footer_mode = preferences->footer_mode;
if (footer_mode == FT_SBAR || footer_mode == FT_BOTH)
rb->gui_syncstatusbar_draw(rb->statusbars, true);
if (footer_mode == FT_PAGE || footer_mode == FT_BOTH)
{
if (pos->line == 0)
rb->snprintf(buf, sizeof(buf), "%d", pos->page + 1);
else
rb->snprintf(buf, sizeof(buf), "%d - %d", pos->page + 1, pos->page + 2);
rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf);
}
}
static void tv_show_scrollbar(off_t cur_pos, int size)
{
int items;
int min_shown;
int max_shown;
int sb_width;
int sb_height;
sb_height = LCD_HEIGHT - header_height - footer_height;
if (preferences->horizontal_scrollbar)
{
items = preferences->windows * window_columns;
min_shown = cur_window * window_columns + cur_column;
max_shown = min_shown + window_columns;
sb_width = (need_vertical_scrollbar)? TV_SCROLLBAR_WIDTH : 0;
sb_height -= TV_SCROLLBAR_HEIGHT;
rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],
sb_width,
LCD_HEIGHT - footer_height - TV_SCROLLBAR_HEIGHT,
LCD_WIDTH - sb_width, TV_SCROLLBAR_HEIGHT,
items, min_shown, max_shown, HORIZONTAL);
}
if (need_vertical_scrollbar)
{
items = (int) tv_get_total_text_size();
min_shown = (int) cur_pos;
max_shown = min_shown + size;
rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], 0, header_height,
TV_SCROLLBAR_WIDTH-1, sb_height,
items, min_shown, max_shown, VERTICAL);
}
}
static int tv_calc_display_lines(void)
{
int scrollbar_height = preferences->horizontal_scrollbar ? TV_SCROLLBAR_HEIGHT : 0;
unsigned header_mode = preferences->header_mode;
unsigned footer_mode = preferences->footer_mode;
header_height = (header_mode == HD_SBAR || header_mode == HD_BOTH)?
STATUSBAR_HEIGHT : 0;
footer_height = (footer_mode == FT_SBAR || footer_mode == FT_BOTH)?
STATUSBAR_HEIGHT : 0;
if (header_mode == HD_NONE || header_mode == HD_PATH ||
footer_mode == FT_NONE || footer_mode == FT_PAGE)
rb->gui_syncstatusbar_draw(rb->statusbars, false);
if (header_mode == HD_PATH || header_mode == HD_BOTH)
header_height += preferences->font->height;
if (footer_mode == FT_PAGE || footer_mode == FT_BOTH)
footer_height += preferences->font->height;
return (LCD_HEIGHT - header_height - footer_height - scrollbar_height) / preferences->font->height;
}
#endif
static void tv_show_bookmarks(const struct tv_screen_pos *top_pos)
@ -199,8 +95,9 @@ static void tv_show_bookmarks(const struct tv_screen_pos *top_pos)
int line;
#ifdef HAVE_LCD_BITMAP
rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
tv_set_drawmode(DRMODE_COMPLEMENT);
#endif
while (count--)
{
line = (bookmarks[count].page - top_pos->page) * display_lines
@ -208,66 +105,51 @@ static void tv_show_bookmarks(const struct tv_screen_pos *top_pos)
if (line >= 0 && line < display_lines)
{
#ifdef HAVE_LCD_BITMAP
rb->lcd_fillrect(start_width, header_height + line * preferences->font->height,
window_width, preferences->font->height);
tv_fillrect(0, line, 1);
#else
rb->lcd_putc(start_width - 1, line, TV_BOOKMARK_ICON);
tv_put_bookmark_icon(line);
#endif
}
}
#ifdef HAVE_LCD_BITMAP
rb->lcd_set_drawmode(DRMODE_SOLID);
#endif
}
void tv_draw_window(void)
{
struct tv_screen_pos pos;
const unsigned char *line_buf;
const unsigned char *text_buf;
int line;
int offset = cur_column * col_width;
int size = 0;
int line_width;
int draw_width = (preferences->windows - cur_window) * LCD_WIDTH - offset;
int dx = start_width - offset;
tv_copy_screen_pos(&pos);
rb->lcd_clear_display();
if (preferences->alignment == AL_LEFT)
tv_start_display();
#ifdef HAVE_LCD_BITMAP
tv_set_drawmode(DRMODE_SOLID);
#endif
tv_clear_display();
tv_read_start(cur_window, (cur_column > 0));
else
tv_read_start(0, preferences->windows > 1);
for (line = 0; line < display_lines; line++)
{
if (!tv_get_next_line(&line_buf))
if (!tv_get_next_line(&text_buf))
break;
if (preferences->alignment == AL_RIGHT)
{
rb->lcd_getstringsize(line_buf, &line_width, NULL);
dx = draw_width - line_width;
}
#ifdef HAVE_LCD_BITMAP
rb->lcd_putsxy(dx, header_height + line * preferences->font->height, line_buf);
#else
rb->lcd_puts(dx, line, line_buf);
#endif
tv_draw_text(line, text_buf, cur_column);
}
size = tv_read_end();
tv_show_bookmarks(&pos);
#ifdef HAVE_LCD_BITMAP
tv_show_scrollbar(pos.file_pos, size);
tv_show_scrollbar(cur_window, cur_column, pos.file_pos, size);
tv_show_header();
tv_show_footer(&pos);
#endif
tv_show_bookmarks(&pos);
rb->lcd_update();
tv_update_display();
tv_end_display();
}
bool tv_traverse_lines(void)
@ -290,10 +172,13 @@ bool tv_traverse_lines(void)
static void tv_change_preferences(const struct tv_preferences *oldp)
{
#ifdef HAVE_LCD_BITMAP
#ifndef HAVE_LCD_BITMAP
(void)oldp;
#else
static bool font_changing = false;
const unsigned char *font_str;
bool change_prefs = false;
bool need_vertical_scrollbar;
struct tv_preferences new_prefs;
tv_copy_preferences(&new_prefs);
@ -317,14 +202,6 @@ static void tv_change_preferences(const struct tv_preferences *oldp)
}
font_changing = false;
/* calculates display lines */
display_lines = tv_calc_display_lines();
#else
(void)oldp;
/* REAL fixed pitch :) all chars use up 1 cell */
display_lines = 2;
#endif
#ifdef HAVE_LCD_BITMAP
@ -336,27 +213,36 @@ static void tv_change_preferences(const struct tv_preferences *oldp)
if (cur_window >= preferences->windows)
cur_window = 0;
window_width = LCD_WIDTH;
/* change viewport */
tv_change_viewport();
#ifdef HAVE_LCD_BITMAP
need_vertical_scrollbar = false;
start_width = 0;
tv_set_layout(col_width, need_vertical_scrollbar);
tv_get_drawarea_info(&window_width, &window_columns, &display_lines);
tv_seek_top();
tv_set_read_conditions(preferences->windows, window_width);
if (tv_traverse_lines() && preferences->vertical_scrollbar)
{
need_vertical_scrollbar = true;
start_width = TV_SCROLLBAR_WIDTH;
tv_set_layout(col_width, need_vertical_scrollbar);
tv_get_drawarea_info(&window_width, &window_columns, &display_lines);
}
tv_seek_top();
#else
start_width = 1;
tv_set_layout(col_width);
tv_get_drawarea_info(&window_width, &window_columns, &display_lines);
#endif
window_width -= start_width;
window_columns = window_width / col_width;
window_columns = window_width / col_width;
cur_column = 0;
tv_set_read_conditions(preferences->windows, window_width);
tv_init_display();
#ifdef HAVE_LCD_BITMAP
tv_init_scrollbar(tv_get_total_text_size(), need_vertical_scrollbar);
#endif
}
bool tv_init_window(unsigned char **buf, size_t *size)
@ -375,6 +261,9 @@ void tv_finalize_window(void)
{
tv_set_font(rb->global_settings->font_file);
}
/* undo viewport */
tv_undo_viewport();
#endif
}