From df9b04c6eadb08187802eb460e6719dc7157a98b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 24 Jul 2003 09:47:46 +0000 Subject: Garrett Derner's word wrap fix for the text viewer git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3873 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/viewer.c | 970 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 744 insertions(+), 226 deletions(-) diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c index f8dc309a6e..61469fb7ff 100644 --- a/apps/plugins/viewer.c +++ b/apps/plugins/viewer.c @@ -6,9 +6,9 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ - * $Id$ * - * Copyright (C) 2002 Gilles Roux + * + * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. @@ -19,175 +19,614 @@ ****************************************************************************/ #include "plugin.h" -#define BUFFER_SIZE 1024 -#define OUTSIDE_BUFFER -10 -#define OUTSIDE_FILE -11 - -static int fd; -static int file_size; +#ifdef HAVE_LCD_BITMAP +#include "recorder/widgets.h" +#endif -static char buffer[BUFFER_SIZE+1]; -static int buffer_pos; /* Position of the buffer in the file */ +#include +#include -static char display_lines; /* number of lines on the display */ -static char display_columns; /* number of columns on the display */ -static int begin_line; /* Index of the first line displayed on the lcd */ -static int end_line; /* Index of the last line displayed on the lcd */ -static int begin_line_pos; /* Position of the first_line in the bufffer */ -static int end_line_pos; /* Position of the last_line in the buffer */ -static struct plugin_api* rb; +#if PLUGIN_API_VERSION < 3 +#error Scrollbar function requires PLUGIN_API_VERSION 3 at least +#endif -/* - * Known issue: The caching algorithm will fail (display incoherent data) if - * the total space of the lines that are displayed on the screen exceeds the - * buffer size (only happens with very long lines). - */ +#define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */ +#define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */ +#define MAX_WIDTH 910 /* Max line length in WIDE mode */ +#define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */ +#define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */ +#define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */ +#define BUFFER_SIZE 0x3000 /* 12k: Mem reserved for buffered file data */ +#define TOP_SECTOR buffer +#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE) +#define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE)) + +/* Out-Of-Bounds test for any pointer to data in the buffer */ +#define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end) + +/* Does the buffer contain the beginning of the file? */ +#define BUFFER_BOF() (file_pos==0) + +/* Does the buffer contain the end of the file? */ +#define BUFFER_EOF() (file_size-file_pos <= BUFFER_SIZE) + +/* Formula for the endpoint address outside of buffer data */ +#define BUFFER_END() \ + ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+BUFFER_SIZE)) + +/* Is the entire file being shown in one screen? */ +#define ONE_SCREEN_FITS_ALL() \ + (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF()) + +/* Is a scrollbar called for on the current screen? */ +#define NEED_SCROLLBAR() ((!(ONE_SCREEN_FITS_ALL())) && \ + (view_mode==WIDE? scrollbar_mode[WIDE]==SB_ON: scrollbar_mode[NARROW]==SB_ON)) + +enum { + WRAP=0, + CHOP, + WORD_MODES +} word_mode = 0; +static unsigned char *word_mode_str[] = {"wrap", "chop", "words"}; + +enum { + NORMAL=0, + JOIN, + EXPAND, + LINE_MODES +} line_mode = 0; +static unsigned char *line_mode_str[] = {"normal", "join", "expand", "lines"}; + +enum { + NARROW=0, + WIDE, + VIEW_MODES +} view_mode = 0; +static unsigned char *view_mode_str[] = {"narrow", "wide", "view"}; -static void display_line_count(void) -{ #ifdef HAVE_LCD_BITMAP - int w,h; - rb->lcd_getstringsize("M", &w, &h); - display_lines = LCD_HEIGHT / h; - display_columns = LCD_WIDTH / w; -#else - display_lines = 2; - display_columns = 11; +enum { + SB_OFF=0, + SB_ON, + SCROLLBAR_MODES +} scrollbar_mode[VIEW_MODES] = {SB_OFF, SB_ON}; +static unsigned char *scrollbar_mode_str[] = {"off", "on", "scrollbar"}; +static bool need_scrollbar; +enum { + NO_OVERLAP=0, + OVERLAP, + PAGE_MODES +} page_mode = 0; +static unsigned char *page_mode_str[] = {"don't overlap", "overlap", "pages"}; #endif -} -static int find_next_line(int pos) +static unsigned char buffer[BUFFER_SIZE + 1]; +static unsigned char line_break[] = {0,0x20,'-',9,0xB,0xC}; +static int display_columns; /* number of columns on the display */ +static int display_lines; /* number of lines on the display */ +static int fd; +static long file_size; +static bool mac_text; +static long file_pos; /* Position of the top of the buffer in the file */ +static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/ +static int max_line_len; +static unsigned char *screen_top_ptr; +static unsigned char *next_screen_ptr; +static unsigned char *next_screen_to_draw_ptr; +static unsigned char *next_line_ptr; +static struct plugin_api* rb; + +static unsigned char* find_first_feed(const unsigned char* p, int size) { int i; - if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) - return pos; + for (i=0; i < size; i++) + if (p[i] == 0) + return (unsigned char*) p+i; - i = pos; - if (buffer_pos+i>=file_size) { - return OUTSIDE_FILE; - } - while (1) { - i++; - if (buffer_pos+i==file_size) { - return i; - } - if (i>=BUFFER_SIZE) { - return OUTSIDE_BUFFER; - } - if (buffer[i]==0) { - return i; - } - } + return NULL; } -static int find_prev_line(int pos) +static unsigned char* find_last_feed(const unsigned char* p, int size) { int i; - if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) - return pos; + for (i=size-1; i>=0; i--) + if (p[i] == 0) + return (unsigned char*) p+i; + + return NULL; +} + +static unsigned char* find_last_space(const unsigned char* p, int size) +{ + int i, j, k; + + k = line_mode==JOIN? 0:1; + + for (i=size-1; i>=0; i--) + for (j=k; j < (int) sizeof(line_break); j++) + if (p[i] == line_break[j]) + return (unsigned char*) p+i; + + return NULL; +} - i = pos; - if (buffer_pos+i<0) { - return OUTSIDE_FILE; +static unsigned char* find_next_line(const unsigned char* cur_line) +{ + const unsigned char *next_line = NULL; + int size, i, j, k, chop_len, search_len, spaces, newlines, draw_columns; + unsigned char c; + + if BUFFER_OOB(cur_line) + return NULL; + +#ifdef HAVE_LCD_BITMAP + draw_columns = need_scrollbar? display_columns-1: display_columns; +#else + draw_columns = display_columns; +#endif + + if (view_mode == WIDE) { + search_len = chop_len = MAX_WIDTH; } - while (1) { - i--; - if (buffer_pos+i<0) { - return i; - } - if (i<0) { - return OUTSIDE_BUFFER; - } - if (buffer[i]==0) { - return i; + else { /* view_mode == NARROW */ + chop_len = draw_columns; + search_len = chop_len + 1; + } + + size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len; + + if (line_mode == JOIN) { + /* Need to scan ahead and possibly increase search_len and size, + or possibly set next_line at second hard return in a row. */ + next_line = NULL; + for (j=k=spaces=newlines=0; j < size; j++) { + if (k == MAX_COLUMNS) + break; + + c = cur_line[j]; + switch (c) { + case ' ': + spaces++; + break; + + case 0: + if (newlines > 0) { + size = j; + next_line = cur_line + size - spaces - 1; + if (next_line != cur_line) + return (unsigned char*) next_line; + break; + } + newlines++; + size += spaces; + if (BUFFER_OOB(cur_line+size) || size > 2*search_len) + return NULL; + + search_len = size; + spaces = 0; + k++; + break; + + default: + newlines = 0; + while (spaces) { + spaces--; + k++; + if (k == MAX_COLUMNS - 1) + break; + } + k++; + break; + } } } + else { + /* find first hard return */ + next_line = find_first_feed(cur_line, size); + } + + if (next_line == NULL) + if (size == search_len) { + if (word_mode == WRAP) /* Find last space */ + next_line = find_last_space(cur_line, size); + + if (next_line == NULL) + next_line = cur_line + chop_len; + else + if (word_mode == WRAP) + for (i=0; + ilcd_clear_display(); - - line_pos = begin_line_pos; - - for (i=0; i <= end_line - begin_line; i++) { - if (line_pos == OUTSIDE_BUFFER || - line_pos == OUTSIDE_FILE) - break; - str = buffer + line_pos + 1; - for (j=0; jlcd_puts(0, i, str); - line_pos = find_next_line(line_pos); + const unsigned char *prev_line = NULL; + const unsigned char *p; + + if BUFFER_OOB(cur_line) + return NULL; + + /* To wrap consistently at the same places, we must + start with a known hard return, then work downwards. + We can either search backwards for a hard return, + or simply start wrapping downwards from top of buffer. + If current line is not near top of buffer, this is + a file with long lines (paragraphs). We would need to + read earlier sectors before we could decide how to + properly wrap the lines above the current line, but + it probably is not worth the disk access. Instead, + start with top of buffer and wrap down from there. + This may result in some lines wrapping at different + points from where they wrap when scrolling down. + If buffer is at top of file, start at top of buffer. */ + + if (line_mode == JOIN) + prev_line = p = NULL; + else + prev_line = p = find_last_feed(buffer, cur_line-buffer-1); + /* Null means no line feeds in buffer above current line. */ + + if (prev_line == NULL) + if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE) + prev_line = p = buffer; + /* (else return NULL and read previous block) */ + + /* Wrap downwards until too far, then use the one before. */ + while (p < cur_line && p != NULL) { + prev_line = p; + p = find_next_line(prev_line); } -#ifdef HAVE_LCD_BITMAP - rb->lcd_update(); -#endif + + if (BUFFER_OOB(prev_line)) + return NULL; + + return (unsigned char*) prev_line; } -static void fill_buffer(int pos) +static void fill_buffer(long pos, unsigned char* buf, unsigned size) { - int i; - int numread; - - if (pos>=file_size-BUFFER_SIZE) - pos = file_size-BUFFER_SIZE; - if (pos<0) - pos = 0; + /* Read from file and preprocess the data */ + /* To minimize disk access, always read on sector boundaries */ + unsigned numread, i; + bool found_CR = false; rb->lseek(fd, pos, SEEK_SET); - numread = rb->read(fd, buffer, BUFFER_SIZE); + numread = rb->read(fd, buf, size); + while (rb->button_get(false)); /* clear button queue */ - begin_line_pos -= pos - buffer_pos; - end_line_pos -= pos - buffer_pos; - buffer_pos = pos; - - buffer[numread] = 0; - for(i=0;imemcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE); + rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE); + } + else /* down */ { + if (view_mode == WIDE) { + /* WIDE mode needs more buffer so we have to read smaller blocks */ + move_size = SMALL_BLOCK_SIZE; + offset = LARGE_BLOCK_SIZE; + fill_buf = BOTTOM_SECTOR; + rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE); + rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE); + } + else { + move_size = LARGE_BLOCK_SIZE; + offset = SMALL_BLOCK_SIZE; + fill_buf = MID_SECTOR; + rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE); + } + } + move_vector = direction * move_size; + screen_top_ptr -= move_vector; + file_pos += move_vector; + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + fill_buffer(file_pos + offset, fill_buf, move_size); + return move_vector; +} + +static void viewer_scroll_up(void) +{ + unsigned char *p; + + p = find_prev_line(screen_top_ptr); + if (p == NULL && !BUFFER_BOF()) { + read_and_synch(-1); + p = find_prev_line(screen_top_ptr); + } + if (p != NULL) + screen_top_ptr = p; +} + +#ifdef HAVE_LCD_BITMAP +static void viewer_scrollbar(void) { + int w, h, items, min_shown, max_shown; + + rb->lcd_getstringsize("o", &w, &h); + items = (int) file_size; /* (SH1 int is same as long) */ + min_shown = (int) file_pos + (screen_top_ptr - buffer); + + if (next_screen_ptr == NULL) + max_shown = items; + else + max_shown = min_shown + (next_screen_ptr - screen_top_ptr); + + rb->scrollbar(0, 0, w-1, LCD_HEIGHT, items, min_shown, max_shown, VERTICAL); +} +#endif + +static void viewer_draw(int col) +{ + int i, j, k, line_len, resynch_move, spaces, left_col=0; + unsigned char *line_begin; + unsigned char *line_end; + unsigned char c; + unsigned char scratch_buffer[MAX_COLUMNS + 1]; + + /* If col==-1 do all calculations but don't display */ + if (col != -1) { +#ifdef HAVE_LCD_BITMAP + left_col = need_scrollbar? 1:0; +#else + left_col = 0; +#endif + rb->lcd_clear_display(); + } + max_line_len = 0; + line_begin = line_end = screen_top_ptr; + + for (i = 0; i < display_lines; i++) { + if (BUFFER_OOB(line_end)) + break; /* Happens after display last line at BUFFER_EOF() */ + + line_begin = line_end; + line_end = find_next_line(line_begin); + + if (line_end == NULL) { + if (BUFFER_EOF()) { + if (i < display_lines - 1 && !BUFFER_BOF()) { + if (col != -1) + rb->lcd_clear_display(); + + for (; i < display_lines - 1; i++) + viewer_scroll_up(); + + line_begin = line_end = screen_top_ptr; + i = -1; + continue; + } + else { + line_end = buffer_end; + } + } + else { + resynch_move = read_and_synch(1); /* Read block & move ptrs */ + line_begin -= resynch_move; + if (i > 0) + next_line_ptr -= resynch_move; + + line_end = find_next_line(line_begin); + if (line_end == NULL) /* Should not really happen */ + break; + } + } + line_len = line_end - line_begin; + + if (line_mode == JOIN) { + if (line_begin[0] == 0) { + line_begin++; + if (word_mode == CHOP) + line_end++; + } + for (j=k=spaces=0; j < line_len; j++) { + if (k == MAX_COLUMNS) + break; + + c = line_begin[j]; + switch (c) { + case ' ': + spaces++; + break; + case 0: + spaces = 0; + scratch_buffer[k++] = ' '; + break; + default: + while (spaces) { + spaces--; + scratch_buffer[k++] = ' '; + if (k == MAX_COLUMNS - 1) + break; + } + scratch_buffer[k++] = c; + break; + } + } + if (col != -1) + if (k > col) { + scratch_buffer[k] = 0; + rb->lcd_puts(left_col, i, scratch_buffer + col); + } + } + else { + if (col != -1) + if (line_len > col) { + c = line_end[0]; + line_end[0] = 0; + rb->lcd_puts(left_col, i, line_begin + col); + line_end[0] = c; + } + } + if (line_len > max_line_len) + max_line_len = line_len; + + if (i == 0) + next_line_ptr = line_end; + } + next_screen_ptr = line_end; + if (BUFFER_OOB(next_screen_ptr)) + next_screen_ptr = NULL; + +#ifdef HAVE_LCD_BITMAP + next_screen_to_draw_ptr = page_mode==OVERLAP? line_begin: next_screen_ptr; + + if (need_scrollbar) + viewer_scrollbar(); + + if (col != -1) + rb->lcd_update(); +#else + next_screen_to_draw_ptr = next_screen_ptr; +#endif +} + +static void viewer_top(void) +{ + /* Read top of file into buffer + and point screen pointer to top */ + file_pos = 0; + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + screen_top_ptr = buffer; + fill_buffer(0, buffer, BUFFER_SIZE); +} + +static void viewer_bottom(void) +{ + /* Read bottom of file into buffer + and point screen pointer to bottom */ + long last_sectors; + + if (file_size > BUFFER_SIZE) { + /* Find last buffer in file, round up to next sector boundary */ + last_sectors = file_size - BUFFER_SIZE + SMALL_BLOCK_SIZE; + last_sectors /= SMALL_BLOCK_SIZE; + last_sectors *= SMALL_BLOCK_SIZE; + } + else { + last_sectors = 0; + } + file_pos = last_sectors; + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + screen_top_ptr = buffer_end-1; + fill_buffer(last_sectors, buffer, BUFFER_SIZE); +} + +#ifdef HAVE_LCD_BITMAP +static void init_need_scrollbar(void) { + /* Call viewer_draw in quiet mode to initialize next_screen_ptr, + and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */ + viewer_draw(-1); + need_scrollbar = NEED_SCROLLBAR(); +} +#endif + static bool viewer_init(char* file) { - int i; - int ret; +#ifdef HAVE_LCD_BITMAP + int w,h; + + rb->lcd_getstringsize("o", &w, &h); + display_lines = LCD_HEIGHT / h; + display_columns = LCD_WIDTH / w; +#else + display_lines = 2; + display_columns = 11; +#endif + /********************* + * (Could re-initialize settings here, if you + * wanted viewer to start the same way every time) + word_mode = WRAP; + line_mode = NORMAL; + view_mode = NARROW; +#ifdef HAVE_LCD_BITMAP + page_mode = NO_OVERLAP; + scrollbar_mode[NARROW] = SB_OFF; + scrollbar_mode[WIDE] = SB_ON; +#endif + **********************/ fd = rb->open(file, O_RDONLY); if (fd==-1) return false; - file_size = rb->lseek(fd, 0, SEEK_END); - - buffer_pos = 0; - begin_line = 0; - begin_line_pos = -1; - end_line = -1; - end_line_pos = -1; - fill_buffer(0); - display_line_count(); - for (i=0; ifilesize(fd); + if (file_size==-1) + return false; + + /* Init mac_text value used in processing buffer */ + mac_text = false; + + /* Read top of file into buffer; + init file_pos, buffer_end, screen_top_ptr */ + viewer_top(); + +#ifdef HAVE_LCD_BITMAP + /* Init need_scrollbar value */ + init_need_scrollbar(); +#endif return true; } @@ -197,130 +636,101 @@ static void viewer_exit(void) rb->close(fd); } -static void viewer_scroll_down(void) +static int col_limit(int col) { - int ret; - - ret = find_next_line(end_line_pos); - switch ( ret ) { - case OUTSIDE_BUFFER: - begin_line_pos = find_next_line(begin_line_pos); - fill_buffer(begin_line_pos+buffer_pos); - end_line_pos = find_next_line(end_line_pos); - break; - - case OUTSIDE_FILE: - return; - - default: - begin_line_pos = find_next_line(begin_line_pos); - end_line_pos = ret; - break; - } - begin_line++; - end_line++; -} + if (col < 0) + col = 0; + else + if (col > max_line_len - 2) + col = max_line_len - 2; -static void viewer_scroll_up(void) -{ - int ret; - - ret = find_prev_line(begin_line_pos); - switch ( ret ) { - case OUTSIDE_BUFFER: - end_line_pos = find_prev_line(end_line_pos); - fill_buffer(buffer_pos+end_line_pos-BUFFER_SIZE); - begin_line_pos = find_prev_line(begin_line_pos); - break; - - case OUTSIDE_FILE: - return; - - default: - end_line_pos = find_prev_line(end_line_pos); - begin_line_pos = ret; - break; - } - begin_line--; - end_line--; + return col; } -static int pagescroll(int col) +#ifdef HAVE_LCD_BITMAP +static int viewer_recorder_on_button(int col) { bool exit = false; - int i; while (!exit) { switch (rb->button_get(true)) { -#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_ON | BUTTON_F1: + /* Page-overlap mode */ + if (++page_mode == PAGE_MODES) + page_mode = 0; + + rb->splash(HZ, 0, true, "%s %s", + page_mode_str[page_mode], page_mode_str[PAGE_MODES]); + + viewer_draw(col); + break; + + case BUTTON_ON | BUTTON_F3: + /* Show-scrollbar mode for current view-width mode */ + if (!(ONE_SCREEN_FITS_ALL())) { + if (++scrollbar_mode[view_mode] == SCROLLBAR_MODES) + scrollbar_mode[view_mode] = 0; + + init_need_scrollbar(); + viewer_draw(col); + + rb->splash(HZ, 0, true, "%s %s (%s %s)", + scrollbar_mode_str[SCROLLBAR_MODES], + scrollbar_mode_str[scrollbar_mode[view_mode]], + view_mode_str[view_mode], view_mode_str[VIEW_MODES]); + } + viewer_draw(col); + break; + case BUTTON_ON | BUTTON_UP: case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: -#else - case BUTTON_ON | BUTTON_LEFT: - case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: -#endif - for (i=0; ibutton_get(true); - - switch ( button ) { + while (!exit) { + switch (rb->button_get(true)) { #ifdef HAVE_RECORDER_KEYPAD - case BUTTON_F1: case BUTTON_OFF: #else case BUTTON_STOP: @@ -352,6 +759,90 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) exit = true; break; +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_F1: +#else + case BUTTON_ON | BUTTON_LEFT: +#endif + /* Word-wrap mode: WRAP or CHOP */ + if (++word_mode == WORD_MODES) + word_mode = 0; + +#ifdef HAVE_LCD_BITMAP + init_need_scrollbar(); +#endif + viewer_draw(col); + + rb->splash(HZ, 0, true, "%s %s", + word_mode_str[word_mode], word_mode_str[WORD_MODES]); + + viewer_draw(col); + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_F2: +#else + case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT: +#endif + /* Line-paragraph mode: NORMAL, JOIN or EXPAND */ + if (++line_mode == LINE_MODES) + line_mode = 0; + + if (view_mode == WIDE) + if (line_mode == JOIN) + if (++line_mode == LINE_MODES) + line_mode = 0; + +#ifdef HAVE_LCD_BITMAP + init_need_scrollbar(); +#endif + viewer_draw(col); + + rb->splash(HZ, 0, true, "%s %s", + line_mode_str[line_mode], line_mode_str[LINE_MODES]); + + viewer_draw(col); + break; + +#ifdef HAVE_RECORDER_KEYPAD + case BUTTON_F3: +#else + case BUTTON_ON | BUTTON_RIGHT: +#endif + /* View-width mode: NARROW or WIDE */ + if (line_mode == JOIN) + rb->splash(HZ, 0, true, "(no %s %s)", + view_mode_str[WIDE], line_mode_str[JOIN]); + else + if (++view_mode == VIEW_MODES) + view_mode = 0; + + col = 0; + + /***** Could do this after change of word-wrap mode + * and after change of view-width mode, to normalize + * view: + if (screen_top_ptr > buffer + BUFFER_SIZE/2) { + screen_top_ptr = find_prev_line(screen_top_ptr); + screen_top_ptr = find_next_line(screen_top_ptr); + } + else { + screen_top_ptr = find_next_line(screen_top_ptr); + screen_top_ptr = find_prev_line(screen_top_ptr); + } + ***********/ + +#ifdef HAVE_LCD_BITMAP + init_need_scrollbar(); +#endif + viewer_draw(col); + + rb->splash(HZ, 0, true, "%s %s", + view_mode_str[view_mode], view_mode_str[VIEW_MODES]); + + viewer_draw(col); + break; + #ifdef HAVE_RECORDER_KEYPAD case BUTTON_UP: case BUTTON_UP | BUTTON_REPEAT: @@ -359,7 +850,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) case BUTTON_LEFT: case BUTTON_LEFT | BUTTON_REPEAT: #endif - viewer_scroll_up(); + /* Page up */ +#ifdef HAVE_LCD_BITMAP + for (i = page_mode==OVERLAP? 1:0; i < display_lines; i++) +#else + for (i = 0; i < display_lines; i++) +#endif + viewer_scroll_up(); + viewer_draw(col); break; @@ -370,7 +868,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) case BUTTON_RIGHT: case BUTTON_RIGHT | BUTTON_REPEAT: #endif - viewer_scroll_down(); + /* Page down */ + if (next_screen_ptr != NULL) + screen_top_ptr = next_screen_to_draw_ptr; + viewer_draw(col); break; @@ -381,9 +882,16 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) case BUTTON_MENU | BUTTON_LEFT: case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT: #endif - col--; - if (col < 0) - col = 0; + if (view_mode == WIDE) { + /* Screen left */ + col -= display_columns; + col = col_limit(col); + } + else { /* view_mode == NARROW */ + /* Top of file */ + viewer_top(); + } + viewer_draw(col); break; @@ -394,18 +902,28 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) case BUTTON_MENU | BUTTON_RIGHT: case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT: #endif - col++; + if (view_mode == WIDE) { + /* Screen right */ + col += display_columns; + col = col_limit(col); + } + else { /* view_mode == NARROW */ + /* Bottom of file */ + viewer_bottom(); + } + viewer_draw(col); break; +#ifdef HAVE_RECORDER_KEYPAD case BUTTON_ON: -#ifdef HAVE_PLAYER_KEYPAD - case BUTTON_ON | BUTTON_MENU: -#endif - col = pagescroll(col); + /*Go to On-btn combinations */ + col = viewer_recorder_on_button(col); break; +#endif case SYS_USB_CONNECTED: + /* Release control to USB functions */ rb->usb_screen(); viewer_exit(); return PLUGIN_USB_CONNECTED; -- cgit v1.2.3