diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c old mode 100644 new mode 100755 index f01afbb..366e613 --- a/apps/plugins/viewer.c +++ b/apps/plugins/viewer.c @@ -39,6 +39,7 @@ PLUGIN_HEADER #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE) #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE)) #define SCROLLBAR_WIDTH 6 +#define MAX_PAGE 9999 #define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1) @@ -356,6 +357,8 @@ PLUGIN_HEADER struct bookmarked_file_info { long file_position; int top_ptr_pos; + int page; + int line; char filename[MAX_PATH]; }; @@ -395,6 +398,18 @@ struct preferences { NO_OVERLAP=0, OVERLAP, } page_mode; + + enum { + HD_NONE = 0, + HD_SB, + HD_FP, + HD_BOTH, + } header_mode; + + enum { + FT_OFF = 0, + FT_ON + } footer_mode; #endif /* HAVE_LCD_BITMAP */ enum { @@ -422,18 +437,24 @@ static long file_size; static long start_position; /* position in the file after the viewer is started */ static bool mac_text; static long file_pos; /* Position of the top of the buffer in the file */ +static long last_file_pos; static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/ static int max_line_len; +static int cline = 1; +static int cpage = 1; +static int lpage = 0; 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 unsigned char *last_screen_top_ptr = NULL; #ifdef HAVE_LCD_BITMAP static struct font *pf; #endif +struct viewport vp; -int glyph_width(int ch) +static int glyph_width(int ch) { if (ch == 0) ch = ' '; @@ -445,7 +466,7 @@ int glyph_width(int ch) #endif } -unsigned char* get_ucs(const unsigned char* str, unsigned short* ch) +static unsigned char* get_ucs(const unsigned char* str, unsigned short* ch) { unsigned char utf8_tmp[6]; int count; @@ -798,6 +819,48 @@ static int read_and_synch(int direction) return move_vector; } +static void get_next_line_position(unsigned char **line_begin, + unsigned char **line_end, + bool *is_short) +{ + int resynch_move; + + *line_begin = *line_end; + *line_end = find_next_line(*line_begin, is_short); + + if (*line_end == NULL && !BUFFER_EOF()) + { + resynch_move = read_and_synch(1); /* Read block & move ptrs */ + *line_begin -= resynch_move; + if (next_line_ptr > buffer) + next_line_ptr -= resynch_move; + + *line_end = find_next_line(*line_begin, is_short); + } +} + +static void increment_current_line(void) +{ + if (cline < display_lines) + cline++; + else if (cpage < MAX_PAGE) + { + cpage++; + cline = 1; + } +} + +static void decrement_current_line(void) +{ + if (cline > 1) + cline--; + else if (cpage > 1) + { + cpage--; + cline = display_lines; + } +} + static void viewer_scroll_up(void) { unsigned char *p; @@ -809,17 +872,25 @@ static void viewer_scroll_up(void) } if (p != NULL) screen_top_ptr = p; + + decrement_current_line(); } -static void viewer_scroll_down(void) +static void viewer_scroll_down(bool autoscroll) { - if (next_screen_ptr != NULL) + if (cpage == lpage) + return; + + if (next_line_ptr != NULL) screen_top_ptr = next_line_ptr; + + if (prefs.scroll_mode == LINE || autoscroll) + increment_current_line(); } #ifdef HAVE_LCD_BITMAP static void viewer_scrollbar(void) { - int items, min_shown, max_shown; + int items, min_shown, max_shown, sb_begin_y, sb_height; items = (int) file_size; /* (SH1 int is same as long) */ min_shown = (int) file_pos + (screen_top_ptr - buffer); @@ -829,14 +900,53 @@ static void viewer_scrollbar(void) { else max_shown = min_shown + (next_screen_ptr - screen_top_ptr); - rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, 0, SCROLLBAR_WIDTH-1, - LCD_HEIGHT, items, min_shown, max_shown, VERTICAL); + sb_begin_y = vp.y; + if (prefs.header_mode == HD_FP || prefs.header_mode == HD_BOTH) + sb_begin_y += pf->height; + + sb_height = LCD_HEIGHT - sb_begin_y + - ((prefs.footer_mode)?pf->height:0); + + rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y, + SCROLLBAR_WIDTH-1, sb_height, + items, min_shown, max_shown, VERTICAL); +} +#endif + +#ifdef HAVE_LCD_BITMAP +static void viewer_show_header(void) +{ + if (prefs.header_mode == HD_NONE) + return; + + if (prefs.header_mode == HD_SB || prefs.header_mode == HD_BOTH) + rb->viewportmanager_set_statusbar(VP_SB_ALLSCREENS); + else + rb->viewportmanager_set_statusbar(VP_SB_HIDE_ALL); + + if (prefs.header_mode != HD_SB) + rb->lcd_putsxy(0, vp.y, file_name); +} + +static void viewer_show_footer(void) +{ + unsigned char buf[12]; + + if (prefs.footer_mode == FT_OFF) + return; + + if (cline == 1) + rb->snprintf(buf, sizeof(buf), "%d", cpage); + else + rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1); + + rb->lcd_putsxy(0, LCD_HEIGHT - pf->height, buf); } #endif static void viewer_draw(int col) { - int i, j, k, line_len, line_width, resynch_move, spaces, left_col=0; + int i, j, k, line_len, line_width, spaces, left_col=0; int width, extra_spaces, indent_spaces, spaces_per_word; bool multiple_spacing, line_is_short; unsigned short ch; @@ -862,39 +972,22 @@ static void viewer_draw(int col) 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, &line_is_short); - - 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(); + { + if (lpage == cpage) + break; /* Happens after display last line at BUFFER_EOF() */ - 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, NULL); - if (line_end == NULL) /* Should not really happen */ - break; + if (lpage == 0 && cline == 1) + { + lpage = cpage; + last_screen_top_ptr = screen_top_ptr; + last_file_pos = file_pos; } } + + get_next_line_position(&line_begin, &line_end, &line_is_short); + if (line_end == NULL) + break; + line_len = line_end - line_begin; /* calculate line_len */ @@ -1066,11 +1159,17 @@ static void viewer_draw(int col) } } if (col != -1 && line_width > col) + { #ifdef HAVE_LCD_BITMAP - rb->lcd_putsxy(left_col, i*pf->height, utf8_buffer); + int dy = i * pf->height + vp.y; + if (prefs.header_mode == HD_FP || prefs.header_mode == HD_BOTH) + dy += pf->height; + + rb->lcd_putsxy(left_col, dy, utf8_buffer); #else rb->lcd_puts(left_col, i, utf8_buffer); #endif + } if (line_width > max_line_len) max_line_len = line_width; @@ -1090,6 +1189,16 @@ static void viewer_draw(int col) next_screen_to_draw_ptr = next_screen_ptr; #endif +#ifdef HAVE_LCD_BITMAP + /* show header */ + if (prefs.header_mode) + viewer_show_header(); + + /* show footer */ + if (prefs.footer_mode) + viewer_show_footer(); +#endif + if (col != -1) rb->lcd_update(); } @@ -1100,38 +1209,52 @@ static void viewer_top(void) and point screen pointer to top */ if (file_pos != 0) { + rb->splash(0, "Loading..."); + file_pos = 0; buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ fill_buffer(0, buffer, buffer_size); } screen_top_ptr = buffer; + cpage = 1; + cline = 1; } 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; - } + unsigned char *line_begin; + unsigned char *line_end; - if (file_pos != last_sectors) + rb->splash(0, "Loading..."); + + if (last_screen_top_ptr) { - file_pos = last_sectors; - buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ - fill_buffer(last_sectors, buffer, buffer_size); + cpage = lpage; + cline = 1; + screen_top_ptr = last_screen_top_ptr; + file_pos = last_file_pos; + fill_buffer(file_pos, buffer, buffer_size); + buffer_end = BUFFER_END(); + return; } - screen_top_ptr = buffer_end-1; + line_end = screen_top_ptr; + + while (!BUFFER_EOF() || !BUFFER_OOB(line_end)) + { + get_next_line_position(&line_begin, &line_end, NULL); + if (line_end == NULL) + break; + + increment_current_line(); + if (cline == 1) + screen_top_ptr = line_end; + } + lpage = cpage; + cline = 1; + last_screen_top_ptr = screen_top_ptr; + last_file_pos = file_pos; } #ifdef HAVE_LCD_BITMAP @@ -1143,8 +1266,67 @@ static void init_need_scrollbar(void) { draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns; par_indent_spaces = draw_columns/(5*glyph_width(' ')); } + +static void calc_page(void) +{ + unsigned char *line_begin; + unsigned char *line_end; + unsigned char *old_stp = buffer; + long old_fp = file_pos + (screen_top_ptr - buffer); + + cpage = 1; + cline = 1; + file_pos = 0; + screen_top_ptr = buffer; + buffer_end = BUFFER_END(); + + rb->splash(0, "Calculating page/line number..."); + + fill_buffer(file_pos, buffer, buffer_size); + line_end = line_begin = buffer; + + while (!(line_begin <= old_stp && old_stp < line_end) || + !(file_pos <= old_fp && old_fp < file_pos + BUFFER_END() - buffer)) + { + get_next_line_position(&line_begin, &line_end, NULL); + if (line_end == NULL) + break; + + if (old_stp == buffer && + file_pos <= old_fp && old_fp < file_pos + BUFFER_END() - buffer) + old_stp = old_fp - file_pos + buffer; + + next_line_ptr = line_end; + + increment_current_line(); + if (prefs.scroll_mode == LINE || cline == 1) + screen_top_ptr = line_begin; + } + + if (prefs.scroll_mode == PAGE) + cline = 1; +} + +static void init_header_and_footer(void) +{ + if (prefs.header_mode == HD_SB || prefs.header_mode == HD_BOTH) + rb->viewportmanager_set_statusbar(VP_SB_ALLSCREENS); + else + rb->viewportmanager_set_statusbar(VP_SB_HIDE_ALL); + rb->viewport_set_defaults(&vp, 0); + + display_lines = (LCD_HEIGHT - vp.y)/pf->height - ((prefs.footer_mode)?1:0); + if (prefs.header_mode == HD_FP || prefs.header_mode == HD_BOTH) + display_lines--; + + lpage = 0; + last_file_pos = 0; + last_screen_top_ptr = NULL; +} + #else #define init_need_scrollbar() +#define init_header_and_footer() #endif static bool viewer_init(void) @@ -1153,7 +1335,6 @@ static bool viewer_init(void) pf = rb->font_get(FONT_UI); - display_lines = LCD_HEIGHT / pf->height; draw_columns = display_columns = LCD_WIDTH; #else /* REAL fixed pitch :) all chars use up 1 cell */ @@ -1185,6 +1366,8 @@ static void viewer_default_settings(void) #ifdef HAVE_LCD_BITMAP prefs.page_mode = NO_OVERLAP; prefs.scrollbar_mode = SB_OFF; + prefs.header_mode = HD_BOTH; + prefs.footer_mode = FT_ON; #endif prefs.autoscroll_speed = 1; /* Set codepage to system default */ @@ -1223,29 +1406,46 @@ static void viewer_load_settings(void) /* same name as global, but not the same rb->read(settings_fd, &data->bookmarked_files_count, sizeof(signed int)); if (data->bookmarked_files_count > MAX_BOOKMARKED_FILES) data->bookmarked_files_count = MAX_BOOKMARKED_FILES; - rb->read(settings_fd, data->bookmarks, - sizeof(struct bookmarked_file_info) * data->bookmarked_files_count); + + long size = sizeof(struct bookmarked_file_info) * + data->bookmarked_files_count; + + long rsize = rb->read(settings_fd, data->bookmarks, size); + rb->close(settings_fd); + + if (rsize != size) + { + data->bookmarked_files_count = 0; + rb->remove(BOOKMARKS_FILE); + } } file_pos = 0; screen_top_ptr = buffer; + cpage = 1; + cline = 1; /* check if current file is in list */ for (i=0; i < data->bookmarked_files_count; i++) { if (!rb->strcmp(file_name, data->bookmarks[i].filename)) { - int screen_pos = data->bookmarks[i].file_position + data->bookmarks[i].top_ptr_pos; + int screen_pos = data->bookmarks[i].file_position + + data->bookmarks[i].top_ptr_pos; int screen_top = screen_pos % buffer_size; file_pos = screen_pos - screen_top; screen_top_ptr = buffer + screen_top; + cpage = data->bookmarks[i].page; + cline = data->bookmarks[i].line; break; } } this_bookmark.file_position = file_pos; this_bookmark.top_ptr_pos = screen_top_ptr - buffer; + this_bookmark.page = cpage; + this_bookmark.line = cline; rb->memset(&this_bookmark.filename[0],0,MAX_PATH); rb->strcpy(this_bookmark.filename,file_name); @@ -1289,6 +1489,7 @@ static void viewer_load_settings(void) /* same name as global, but not the same start_position = file_pos + screen_top_ptr - buffer; init_need_scrollbar(); + init_header_and_footer(); } static void viewer_save_settings(void)/* same name as global, but not the same file.. */ @@ -1317,6 +1518,8 @@ static void viewer_save_settings(void)/* same name as global, but not the same f struct bookmarked_file_info b; b.file_position = file_pos + screen_top_ptr - buffer; b.top_ptr_pos = 0; /* this is only kept for legassy reasons */ + b.page = cpage; + b.line = cline; rb->memset(&b.filename[0],0,MAX_PATH); rb->strcpy(b.filename,file_name); rb->lseek(settings_fd,sizeof(signed int),SEEK_SET); @@ -1435,6 +1638,30 @@ static bool scrollbar_setting(void) return rb->set_option("Show Scrollbar", &prefs.scrollbar_mode, INT, names, 2, NULL); } + +static bool header_setting(void) +{ + static const struct opt_items names[] = { + {"None", -1}, + {"Status bar", -1}, + {"File path", -1}, + {"Both", -1} + }; + + return rb->set_option("Show Header", &prefs.header_mode, INT, + names, 4, NULL); +} + +static bool footer_setting(void) +{ + static const struct opt_items names[] = { + {"No", -1}, + {"Yes", -1} + }; + + return rb->set_option("Show Footer", &prefs.footer_mode, INT, + names, 2, NULL); +} #endif static bool autoscroll_speed_setting(void) @@ -1447,6 +1674,7 @@ static bool viewer_options_menu(void) { int m; bool result; + struct preferences tmp_prefs; static const struct menu_item items[] = { {"Encoding", encoding_setting }, @@ -1456,20 +1684,31 @@ static bool viewer_options_menu(void) #ifdef HAVE_LCD_BITMAP {"Show Scrollbar", scrollbar_setting }, {"Overlap Pages", page_mode_setting }, + {"Show Header", header_setting }, + {"Show Footer", footer_setting }, #endif {"Scroll Mode", scroll_mode_setting}, {"Auto-Scroll Speed", autoscroll_speed_setting }, }; + + rb->memcpy(&tmp_prefs, &prefs, sizeof(struct preferences)); + m = menu_init(items, sizeof(items) / sizeof(*items), NULL, NULL, NULL, NULL); result = menu_run(m); menu_exit(m); -#ifdef HAVE_LCD_BITMAP - /* Show-scrollbar mode for current view-width mode */ - init_need_scrollbar(); -#endif + if (rb->memcmp(&tmp_prefs, &prefs, sizeof(struct preferences))) + { + /* Show-scrollbar mode for current view-width mode */ + init_need_scrollbar(); + + init_header_and_footer(); + + calc_page(); + } + return result; } @@ -1542,13 +1781,17 @@ enum plugin_status plugin_start(const void* file) { if(old_tick <= *rb->current_tick - (110-prefs.autoscroll_speed*10)) { - viewer_scroll_down(); + viewer_scroll_down(true); viewer_draw(col); old_tick = *rb->current_tick; } } button = rb->button_get_w_tmo(HZ/10); + + if (prefs.header_mode == HD_SB || prefs.header_mode == HD_BOTH) + rb->viewportmanager_set_statusbar(VP_SB_ALLSCREENS); + switch (button) { case VIEWER_MENU: viewer_menu(); @@ -1573,6 +1816,9 @@ enum plugin_status plugin_start(const void* file) for (i = 0; i < display_lines; i++) #endif viewer_scroll_up(); + + if (cpage > 1) + cpage--; } else viewer_scroll_up(); @@ -1586,10 +1832,14 @@ enum plugin_status plugin_start(const void* file) { /* Page down */ if (next_screen_ptr != NULL) + { screen_top_ptr = next_screen_to_draw_ptr; + if (cpage < MAX_PAGE) + cpage++; + } } else - viewer_scroll_down(); + viewer_scroll_down(autoscroll); old_tick = *rb->current_tick; viewer_draw(col); break;