summaryrefslogtreecommitdiff
path: root/apps/plugins/viewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/viewer.c')
-rw-r--r--apps/plugins/viewer.c970
1 files 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 @@
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/ 8 * \/ \/ \/ \/ \/
9 * $Id$
10 * 9 *
11 * Copyright (C) 2002 Gilles Roux 10 *
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
12 * 12 *
13 * All files in this archive are subject to the GNU General Public License. 13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement. 14 * See the file COPYING in the source tree root for full license agreement.
@@ -19,175 +19,614 @@
19 ****************************************************************************/ 19 ****************************************************************************/
20#include "plugin.h" 20#include "plugin.h"
21 21
22#define BUFFER_SIZE 1024 22#ifdef HAVE_LCD_BITMAP
23#define OUTSIDE_BUFFER -10 23#include "recorder/widgets.h"
24#define OUTSIDE_FILE -11 24#endif
25
26static int fd;
27static int file_size;
28 25
29static char buffer[BUFFER_SIZE+1]; 26#include <ctype.h>
30static int buffer_pos; /* Position of the buffer in the file */ 27#include <ctype.c>
31 28
32static char display_lines; /* number of lines on the display */ 29#if PLUGIN_API_VERSION < 3
33static char display_columns; /* number of columns on the display */ 30#error Scrollbar function requires PLUGIN_API_VERSION 3 at least
34static int begin_line; /* Index of the first line displayed on the lcd */ 31#endif
35static int end_line; /* Index of the last line displayed on the lcd */
36static int begin_line_pos; /* Position of the first_line in the bufffer */
37static int end_line_pos; /* Position of the last_line in the buffer */
38static struct plugin_api* rb;
39 32
40/* 33#define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
41 * Known issue: The caching algorithm will fail (display incoherent data) if 34#define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
42 * the total space of the lines that are displayed on the screen exceeds the 35#define MAX_WIDTH 910 /* Max line length in WIDE mode */
43 * buffer size (only happens with very long lines). 36#define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
44 */ 37#define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
38#define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
39#define BUFFER_SIZE 0x3000 /* 12k: Mem reserved for buffered file data */
40#define TOP_SECTOR buffer
41#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
42#define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
43
44/* Out-Of-Bounds test for any pointer to data in the buffer */
45#define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
46
47/* Does the buffer contain the beginning of the file? */
48#define BUFFER_BOF() (file_pos==0)
49
50/* Does the buffer contain the end of the file? */
51#define BUFFER_EOF() (file_size-file_pos <= BUFFER_SIZE)
52
53/* Formula for the endpoint address outside of buffer data */
54#define BUFFER_END() \
55 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+BUFFER_SIZE))
56
57/* Is the entire file being shown in one screen? */
58#define ONE_SCREEN_FITS_ALL() \
59 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
60
61/* Is a scrollbar called for on the current screen? */
62#define NEED_SCROLLBAR() ((!(ONE_SCREEN_FITS_ALL())) && \
63 (view_mode==WIDE? scrollbar_mode[WIDE]==SB_ON: scrollbar_mode[NARROW]==SB_ON))
64
65enum {
66 WRAP=0,
67 CHOP,
68 WORD_MODES
69} word_mode = 0;
70static unsigned char *word_mode_str[] = {"wrap", "chop", "words"};
71
72enum {
73 NORMAL=0,
74 JOIN,
75 EXPAND,
76 LINE_MODES
77} line_mode = 0;
78static unsigned char *line_mode_str[] = {"normal", "join", "expand", "lines"};
79
80enum {
81 NARROW=0,
82 WIDE,
83 VIEW_MODES
84} view_mode = 0;
85static unsigned char *view_mode_str[] = {"narrow", "wide", "view"};
45 86
46static void display_line_count(void)
47{
48#ifdef HAVE_LCD_BITMAP 87#ifdef HAVE_LCD_BITMAP
49 int w,h; 88enum {
50 rb->lcd_getstringsize("M", &w, &h); 89 SB_OFF=0,
51 display_lines = LCD_HEIGHT / h; 90 SB_ON,
52 display_columns = LCD_WIDTH / w; 91 SCROLLBAR_MODES
53#else 92} scrollbar_mode[VIEW_MODES] = {SB_OFF, SB_ON};
54 display_lines = 2; 93static unsigned char *scrollbar_mode_str[] = {"off", "on", "scrollbar"};
55 display_columns = 11; 94static bool need_scrollbar;
95enum {
96 NO_OVERLAP=0,
97 OVERLAP,
98 PAGE_MODES
99} page_mode = 0;
100static unsigned char *page_mode_str[] = {"don't overlap", "overlap", "pages"};
56#endif 101#endif
57}
58 102
59static int find_next_line(int pos) 103static unsigned char buffer[BUFFER_SIZE + 1];
104static unsigned char line_break[] = {0,0x20,'-',9,0xB,0xC};
105static int display_columns; /* number of columns on the display */
106static int display_lines; /* number of lines on the display */
107static int fd;
108static long file_size;
109static bool mac_text;
110static long file_pos; /* Position of the top of the buffer in the file */
111static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/
112static int max_line_len;
113static unsigned char *screen_top_ptr;
114static unsigned char *next_screen_ptr;
115static unsigned char *next_screen_to_draw_ptr;
116static unsigned char *next_line_ptr;
117static struct plugin_api* rb;
118
119static unsigned char* find_first_feed(const unsigned char* p, int size)
60{ 120{
61 int i; 121 int i;
62 122
63 if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) 123 for (i=0; i < size; i++)
64 return pos; 124 if (p[i] == 0)
125 return (unsigned char*) p+i;
65 126
66 i = pos; 127 return NULL;
67 if (buffer_pos+i>=file_size) {
68 return OUTSIDE_FILE;
69 }
70 while (1) {
71 i++;
72 if (buffer_pos+i==file_size) {
73 return i;
74 }
75 if (i>=BUFFER_SIZE) {
76 return OUTSIDE_BUFFER;
77 }
78 if (buffer[i]==0) {
79 return i;
80 }
81 }
82} 128}
83 129
84static int find_prev_line(int pos) 130static unsigned char* find_last_feed(const unsigned char* p, int size)
85{ 131{
86 int i; 132 int i;
87 133
88 if (pos==OUTSIDE_BUFFER || pos==OUTSIDE_FILE) 134 for (i=size-1; i>=0; i--)
89 return pos; 135 if (p[i] == 0)
136 return (unsigned char*) p+i;
137
138 return NULL;
139}
140
141static unsigned char* find_last_space(const unsigned char* p, int size)
142{
143 int i, j, k;
144
145 k = line_mode==JOIN? 0:1;
146
147 for (i=size-1; i>=0; i--)
148 for (j=k; j < (int) sizeof(line_break); j++)
149 if (p[i] == line_break[j])
150 return (unsigned char*) p+i;
151
152 return NULL;
153}
90 154
91 i = pos; 155static unsigned char* find_next_line(const unsigned char* cur_line)
92 if (buffer_pos+i<0) { 156{
93 return OUTSIDE_FILE; 157 const unsigned char *next_line = NULL;
158 int size, i, j, k, chop_len, search_len, spaces, newlines, draw_columns;
159 unsigned char c;
160
161 if BUFFER_OOB(cur_line)
162 return NULL;
163
164#ifdef HAVE_LCD_BITMAP
165 draw_columns = need_scrollbar? display_columns-1: display_columns;
166#else
167 draw_columns = display_columns;
168#endif
169
170 if (view_mode == WIDE) {
171 search_len = chop_len = MAX_WIDTH;
94 } 172 }
95 while (1) { 173 else { /* view_mode == NARROW */
96 i--; 174 chop_len = draw_columns;
97 if (buffer_pos+i<0) { 175 search_len = chop_len + 1;
98 return i; 176 }
99 } 177
100 if (i<0) { 178 size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len;
101 return OUTSIDE_BUFFER; 179
102 } 180 if (line_mode == JOIN) {
103 if (buffer[i]==0) { 181 /* Need to scan ahead and possibly increase search_len and size,
104 return i; 182 or possibly set next_line at second hard return in a row. */
183 next_line = NULL;
184 for (j=k=spaces=newlines=0; j < size; j++) {
185 if (k == MAX_COLUMNS)
186 break;
187
188 c = cur_line[j];
189 switch (c) {
190 case ' ':
191 spaces++;
192 break;
193
194 case 0:
195 if (newlines > 0) {
196 size = j;
197 next_line = cur_line + size - spaces - 1;
198 if (next_line != cur_line)
199 return (unsigned char*) next_line;
200 break;
201 }
202 newlines++;
203 size += spaces;
204 if (BUFFER_OOB(cur_line+size) || size > 2*search_len)
205 return NULL;
206
207 search_len = size;
208 spaces = 0;
209 k++;
210 break;
211
212 default:
213 newlines = 0;
214 while (spaces) {
215 spaces--;
216 k++;
217 if (k == MAX_COLUMNS - 1)
218 break;
219 }
220 k++;
221 break;
222 }
105 } 223 }
106 } 224 }
225 else {
226 /* find first hard return */
227 next_line = find_first_feed(cur_line, size);
228 }
229
230 if (next_line == NULL)
231 if (size == search_len) {
232 if (word_mode == WRAP) /* Find last space */
233 next_line = find_last_space(cur_line, size);
234
235 if (next_line == NULL)
236 next_line = cur_line + chop_len;
237 else
238 if (word_mode == WRAP)
239 for (i=0;
240 i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line);
241 i++)
242 next_line++;
243 }
244
245 if (line_mode == EXPAND)
246 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
247 if (next_line[0] == 0)
248 if (next_line != cur_line)
249 return (unsigned char*) next_line;
250
251 /* If next_line is pointing to a zero, increment it; i.e.,
252 leave the terminator at the end of cur_line. If pointing
253 to a hyphen, increment only if there is room to display
254 the hyphen on current line (won't apply in WIDE mode,
255 since it's guarenteed there won't be room). */
256 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
257 if (next_line[0] == 0 ||
258 (next_line[0] == '-' && next_line-cur_line < draw_columns))
259 next_line++;
260
261 if (BUFFER_OOB(next_line))
262 return NULL;
263
264 return (unsigned char*) next_line;
107} 265}
108 266
109static void viewer_draw(int col) 267static unsigned char* find_prev_line(const unsigned char* cur_line)
110{ 268{
111 int i, j; 269 const unsigned char *prev_line = NULL;
112 char* str; 270 const unsigned char *p;
113 int line_pos; 271
114 272 if BUFFER_OOB(cur_line)
115 rb->lcd_clear_display(); 273 return NULL;
116 274
117 line_pos = begin_line_pos; 275 /* To wrap consistently at the same places, we must
118 276 start with a known hard return, then work downwards.
119 for (i=0; i <= end_line - begin_line; i++) { 277 We can either search backwards for a hard return,
120 if (line_pos == OUTSIDE_BUFFER || 278 or simply start wrapping downwards from top of buffer.
121 line_pos == OUTSIDE_FILE) 279 If current line is not near top of buffer, this is
122 break; 280 a file with long lines (paragraphs). We would need to
123 str = buffer + line_pos + 1; 281 read earlier sectors before we could decide how to
124 for (j=0; j<col && *str!=0; ++j) 282 properly wrap the lines above the current line, but
125 str++; 283 it probably is not worth the disk access. Instead,
126 rb->lcd_puts(0, i, str); 284 start with top of buffer and wrap down from there.
127 line_pos = find_next_line(line_pos); 285 This may result in some lines wrapping at different
286 points from where they wrap when scrolling down.
287 If buffer is at top of file, start at top of buffer. */
288
289 if (line_mode == JOIN)
290 prev_line = p = NULL;
291 else
292 prev_line = p = find_last_feed(buffer, cur_line-buffer-1);
293 /* Null means no line feeds in buffer above current line. */
294
295 if (prev_line == NULL)
296 if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE)
297 prev_line = p = buffer;
298 /* (else return NULL and read previous block) */
299
300 /* Wrap downwards until too far, then use the one before. */
301 while (p < cur_line && p != NULL) {
302 prev_line = p;
303 p = find_next_line(prev_line);
128 } 304 }
129#ifdef HAVE_LCD_BITMAP 305
130 rb->lcd_update(); 306 if (BUFFER_OOB(prev_line))
131#endif 307 return NULL;
308
309 return (unsigned char*) prev_line;
132} 310}
133 311
134static void fill_buffer(int pos) 312static void fill_buffer(long pos, unsigned char* buf, unsigned size)
135{ 313{
136 int i; 314 /* Read from file and preprocess the data */
137 int numread; 315 /* To minimize disk access, always read on sector boundaries */
138 316 unsigned numread, i;
139 if (pos>=file_size-BUFFER_SIZE) 317 bool found_CR = false;
140 pos = file_size-BUFFER_SIZE;
141 if (pos<0)
142 pos = 0;
143 318
144 rb->lseek(fd, pos, SEEK_SET); 319 rb->lseek(fd, pos, SEEK_SET);
145 numread = rb->read(fd, buffer, BUFFER_SIZE); 320 numread = rb->read(fd, buf, size);
321 while (rb->button_get(false)); /* clear button queue */
146 322
147 begin_line_pos -= pos - buffer_pos; 323 for(i = 0; i < numread; i++) {
148 end_line_pos -= pos - buffer_pos; 324 switch(buf[i]) {
149 buffer_pos = pos;
150
151 buffer[numread] = 0;
152 for(i=0;i<numread;i++) {
153 switch(buffer[i]) {
154 case '\r': 325 case '\r':
155 buffer[i] = ' '; 326 if (mac_text) {
327 buf[i] = 0;
328 }
329 else {
330 buf[i] = ' ';
331 found_CR = true;
332 }
156 break; 333 break;
334
157 case '\n': 335 case '\n':
158 buffer[i] = 0; 336 buf[i] = 0;
337 found_CR = false;
159 break; 338 break;
339
340 case 0: /* No break between case 0 and default, intentionally */
341 buf[i] = ' ';
160 default: 342 default:
343 if (found_CR) {
344 buf[i - 1] = 0;
345 found_CR = false;
346 mac_text = true;
347 }
161 break; 348 break;
162 } 349 }
163 } 350 }
164} 351}
165 352
353static int read_and_synch(int direction)
354{
355/* Read next (or prev) block, and reposition global pointers. */
356/* direction: 1 for down (i.e., further into file), -1 for up */
357 int move_size, move_vector, offset;
358 unsigned char *fill_buf;
359
360 if (direction == -1) /* up */ {
361 move_size = SMALL_BLOCK_SIZE;
362 offset = 0;
363 fill_buf = TOP_SECTOR;
364 rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
365 rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE);
366 }
367 else /* down */ {
368 if (view_mode == WIDE) {
369 /* WIDE mode needs more buffer so we have to read smaller blocks */
370 move_size = SMALL_BLOCK_SIZE;
371 offset = LARGE_BLOCK_SIZE;
372 fill_buf = BOTTOM_SECTOR;
373 rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
374 rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
375 }
376 else {
377 move_size = LARGE_BLOCK_SIZE;
378 offset = SMALL_BLOCK_SIZE;
379 fill_buf = MID_SECTOR;
380 rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
381 }
382 }
383 move_vector = direction * move_size;
384 screen_top_ptr -= move_vector;
385 file_pos += move_vector;
386 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
387 fill_buffer(file_pos + offset, fill_buf, move_size);
388 return move_vector;
389}
390
391static void viewer_scroll_up(void)
392{
393 unsigned char *p;
394
395 p = find_prev_line(screen_top_ptr);
396 if (p == NULL && !BUFFER_BOF()) {
397 read_and_synch(-1);
398 p = find_prev_line(screen_top_ptr);
399 }
400 if (p != NULL)
401 screen_top_ptr = p;
402}
403
404#ifdef HAVE_LCD_BITMAP
405static void viewer_scrollbar(void) {
406 int w, h, items, min_shown, max_shown;
407
408 rb->lcd_getstringsize("o", &w, &h);
409 items = (int) file_size; /* (SH1 int is same as long) */
410 min_shown = (int) file_pos + (screen_top_ptr - buffer);
411
412 if (next_screen_ptr == NULL)
413 max_shown = items;
414 else
415 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
416
417 rb->scrollbar(0, 0, w-1, LCD_HEIGHT, items, min_shown, max_shown, VERTICAL);
418}
419#endif
420
421static void viewer_draw(int col)
422{
423 int i, j, k, line_len, resynch_move, spaces, left_col=0;
424 unsigned char *line_begin;
425 unsigned char *line_end;
426 unsigned char c;
427 unsigned char scratch_buffer[MAX_COLUMNS + 1];
428
429 /* If col==-1 do all calculations but don't display */
430 if (col != -1) {
431#ifdef HAVE_LCD_BITMAP
432 left_col = need_scrollbar? 1:0;
433#else
434 left_col = 0;
435#endif
436 rb->lcd_clear_display();
437 }
438 max_line_len = 0;
439 line_begin = line_end = screen_top_ptr;
440
441 for (i = 0; i < display_lines; i++) {
442 if (BUFFER_OOB(line_end))
443 break; /* Happens after display last line at BUFFER_EOF() */
444
445 line_begin = line_end;
446 line_end = find_next_line(line_begin);
447
448 if (line_end == NULL) {
449 if (BUFFER_EOF()) {
450 if (i < display_lines - 1 && !BUFFER_BOF()) {
451 if (col != -1)
452 rb->lcd_clear_display();
453
454 for (; i < display_lines - 1; i++)
455 viewer_scroll_up();
456
457 line_begin = line_end = screen_top_ptr;
458 i = -1;
459 continue;
460 }
461 else {
462 line_end = buffer_end;
463 }
464 }
465 else {
466 resynch_move = read_and_synch(1); /* Read block & move ptrs */
467 line_begin -= resynch_move;
468 if (i > 0)
469 next_line_ptr -= resynch_move;
470
471 line_end = find_next_line(line_begin);
472 if (line_end == NULL) /* Should not really happen */
473 break;
474 }
475 }
476 line_len = line_end - line_begin;
477
478 if (line_mode == JOIN) {
479 if (line_begin[0] == 0) {
480 line_begin++;
481 if (word_mode == CHOP)
482 line_end++;
483 }
484 for (j=k=spaces=0; j < line_len; j++) {
485 if (k == MAX_COLUMNS)
486 break;
487
488 c = line_begin[j];
489 switch (c) {
490 case ' ':
491 spaces++;
492 break;
493 case 0:
494 spaces = 0;
495 scratch_buffer[k++] = ' ';
496 break;
497 default:
498 while (spaces) {
499 spaces--;
500 scratch_buffer[k++] = ' ';
501 if (k == MAX_COLUMNS - 1)
502 break;
503 }
504 scratch_buffer[k++] = c;
505 break;
506 }
507 }
508 if (col != -1)
509 if (k > col) {
510 scratch_buffer[k] = 0;
511 rb->lcd_puts(left_col, i, scratch_buffer + col);
512 }
513 }
514 else {
515 if (col != -1)
516 if (line_len > col) {
517 c = line_end[0];
518 line_end[0] = 0;
519 rb->lcd_puts(left_col, i, line_begin + col);
520 line_end[0] = c;
521 }
522 }
523 if (line_len > max_line_len)
524 max_line_len = line_len;
525
526 if (i == 0)
527 next_line_ptr = line_end;
528 }
529 next_screen_ptr = line_end;
530 if (BUFFER_OOB(next_screen_ptr))
531 next_screen_ptr = NULL;
532
533#ifdef HAVE_LCD_BITMAP
534 next_screen_to_draw_ptr = page_mode==OVERLAP? line_begin: next_screen_ptr;
535
536 if (need_scrollbar)
537 viewer_scrollbar();
538
539 if (col != -1)
540 rb->lcd_update();
541#else
542 next_screen_to_draw_ptr = next_screen_ptr;
543#endif
544}
545
546static void viewer_top(void)
547{
548 /* Read top of file into buffer
549 and point screen pointer to top */
550 file_pos = 0;
551 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
552 screen_top_ptr = buffer;
553 fill_buffer(0, buffer, BUFFER_SIZE);
554}
555
556static void viewer_bottom(void)
557{
558 /* Read bottom of file into buffer
559 and point screen pointer to bottom */
560 long last_sectors;
561
562 if (file_size > BUFFER_SIZE) {
563 /* Find last buffer in file, round up to next sector boundary */
564 last_sectors = file_size - BUFFER_SIZE + SMALL_BLOCK_SIZE;
565 last_sectors /= SMALL_BLOCK_SIZE;
566 last_sectors *= SMALL_BLOCK_SIZE;
567 }
568 else {
569 last_sectors = 0;
570 }
571 file_pos = last_sectors;
572 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
573 screen_top_ptr = buffer_end-1;
574 fill_buffer(last_sectors, buffer, BUFFER_SIZE);
575}
576
577#ifdef HAVE_LCD_BITMAP
578static void init_need_scrollbar(void) {
579 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
580 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
581 viewer_draw(-1);
582 need_scrollbar = NEED_SCROLLBAR();
583}
584#endif
585
166static bool viewer_init(char* file) 586static bool viewer_init(char* file)
167{ 587{
168 int i; 588#ifdef HAVE_LCD_BITMAP
169 int ret; 589 int w,h;
590
591 rb->lcd_getstringsize("o", &w, &h);
592 display_lines = LCD_HEIGHT / h;
593 display_columns = LCD_WIDTH / w;
594#else
595 display_lines = 2;
596 display_columns = 11;
597#endif
598 /*********************
599 * (Could re-initialize settings here, if you
600 * wanted viewer to start the same way every time)
601 word_mode = WRAP;
602 line_mode = NORMAL;
603 view_mode = NARROW;
604#ifdef HAVE_LCD_BITMAP
605 page_mode = NO_OVERLAP;
606 scrollbar_mode[NARROW] = SB_OFF;
607 scrollbar_mode[WIDE] = SB_ON;
608#endif
609 **********************/
170 610
171 fd = rb->open(file, O_RDONLY); 611 fd = rb->open(file, O_RDONLY);
172 if (fd==-1) 612 if (fd==-1)
173 return false; 613 return false;
174 614
175 file_size = rb->lseek(fd, 0, SEEK_END); 615 file_size = rb->filesize(fd);
176 616 if (file_size==-1)
177 buffer_pos = 0; 617 return false;
178 begin_line = 0; 618
179 begin_line_pos = -1; 619 /* Init mac_text value used in processing buffer */
180 end_line = -1; 620 mac_text = false;
181 end_line_pos = -1; 621
182 fill_buffer(0); 622 /* Read top of file into buffer;
183 display_line_count(); 623 init file_pos, buffer_end, screen_top_ptr */
184 for (i=0; i<display_lines; ++i) { 624 viewer_top();
185 ret = find_next_line(end_line_pos); 625
186 if (ret!=OUTSIDE_FILE && ret!=OUTSIDE_BUFFER) { 626#ifdef HAVE_LCD_BITMAP
187 end_line_pos = ret; 627 /* Init need_scrollbar value */
188 end_line++; 628 init_need_scrollbar();
189 } 629#endif
190 }
191 630
192 return true; 631 return true;
193} 632}
@@ -197,130 +636,101 @@ static void viewer_exit(void)
197 rb->close(fd); 636 rb->close(fd);
198} 637}
199 638
200static void viewer_scroll_down(void) 639static int col_limit(int col)
201{ 640{
202 int ret; 641 if (col < 0)
203 642 col = 0;
204 ret = find_next_line(end_line_pos); 643 else
205 switch ( ret ) { 644 if (col > max_line_len - 2)
206 case OUTSIDE_BUFFER: 645 col = max_line_len - 2;
207 begin_line_pos = find_next_line(begin_line_pos);
208 fill_buffer(begin_line_pos+buffer_pos);
209 end_line_pos = find_next_line(end_line_pos);
210 break;
211
212 case OUTSIDE_FILE:
213 return;
214
215 default:
216 begin_line_pos = find_next_line(begin_line_pos);
217 end_line_pos = ret;
218 break;
219 }
220 begin_line++;
221 end_line++;
222}
223 646
224static void viewer_scroll_up(void) 647 return col;
225{
226 int ret;
227
228 ret = find_prev_line(begin_line_pos);
229 switch ( ret ) {
230 case OUTSIDE_BUFFER:
231 end_line_pos = find_prev_line(end_line_pos);
232 fill_buffer(buffer_pos+end_line_pos-BUFFER_SIZE);
233 begin_line_pos = find_prev_line(begin_line_pos);
234 break;
235
236 case OUTSIDE_FILE:
237 return;
238
239 default:
240 end_line_pos = find_prev_line(end_line_pos);
241 begin_line_pos = ret;
242 break;
243 }
244 begin_line--;
245 end_line--;
246} 648}
247 649
248static int pagescroll(int col) 650#ifdef HAVE_LCD_BITMAP
651static int viewer_recorder_on_button(int col)
249{ 652{
250 bool exit = false; 653 bool exit = false;
251 int i;
252 654
253 while (!exit) { 655 while (!exit) {
254 switch (rb->button_get(true)) { 656 switch (rb->button_get(true)) {
255#ifdef HAVE_RECORDER_KEYPAD 657 case BUTTON_ON | BUTTON_F1:
658 /* Page-overlap mode */
659 if (++page_mode == PAGE_MODES)
660 page_mode = 0;
661
662 rb->splash(HZ, 0, true, "%s %s",
663 page_mode_str[page_mode], page_mode_str[PAGE_MODES]);
664
665 viewer_draw(col);
666 break;
667
668 case BUTTON_ON | BUTTON_F3:
669 /* Show-scrollbar mode for current view-width mode */
670 if (!(ONE_SCREEN_FITS_ALL())) {
671 if (++scrollbar_mode[view_mode] == SCROLLBAR_MODES)
672 scrollbar_mode[view_mode] = 0;
673
674 init_need_scrollbar();
675 viewer_draw(col);
676
677 rb->splash(HZ, 0, true, "%s %s (%s %s)",
678 scrollbar_mode_str[SCROLLBAR_MODES],
679 scrollbar_mode_str[scrollbar_mode[view_mode]],
680 view_mode_str[view_mode], view_mode_str[VIEW_MODES]);
681 }
682 viewer_draw(col);
683 break;
684
256 case BUTTON_ON | BUTTON_UP: 685 case BUTTON_ON | BUTTON_UP:
257 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: 686 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
258#else 687 /* Scroll up one line */
259 case BUTTON_ON | BUTTON_LEFT: 688 viewer_scroll_up();
260 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: 689 viewer_draw(col);
261#endif
262 for (i=0; i<display_lines; i++)
263 viewer_scroll_up();
264 break; 690 break;
265 691
266#ifdef HAVE_RECORDER_KEYPAD
267 case BUTTON_ON | BUTTON_DOWN: 692 case BUTTON_ON | BUTTON_DOWN:
268 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT: 693 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
269#else 694 /* Scroll down one line */
270 case BUTTON_ON | BUTTON_RIGHT: 695 if (next_screen_ptr != NULL)
271 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: 696 screen_top_ptr = next_line_ptr;
272#endif 697
273 for (i=0; i<display_lines; i++) 698 viewer_draw(col);
274 viewer_scroll_down();
275 break; 699 break;
276 700
277#ifdef HAVE_RECORDER_KEYPAD
278 case BUTTON_ON | BUTTON_LEFT: 701 case BUTTON_ON | BUTTON_LEFT:
279 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: 702 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT:
280#else 703 /* Scroll left one column */
281 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT: 704 col--;
282 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT: 705 col = col_limit(col);
283#endif 706 viewer_draw(col);
284 col -= display_columns;
285 if (col < 0)
286 col = 0;
287 break; 707 break;
288 708
289#ifdef HAVE_RECORDER_KEYPAD
290 case BUTTON_ON | BUTTON_RIGHT: 709 case BUTTON_ON | BUTTON_RIGHT:
291 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: 710 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT:
292#else 711 /* Scroll right one column */
293 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT: 712 col++;
294 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT: 713 col = col_limit(col);
295#endif 714 viewer_draw(col);
296 col += display_columns;
297 break; 715 break;
298 716
299 case BUTTON_ON | BUTTON_REL: 717 case BUTTON_ON | BUTTON_REL:
300#ifdef HAVE_RECORDER_KEYPAD
301 case BUTTON_ON | BUTTON_DOWN | BUTTON_REL: 718 case BUTTON_ON | BUTTON_DOWN | BUTTON_REL:
302 case BUTTON_ON | BUTTON_UP | BUTTON_REL: 719 case BUTTON_ON | BUTTON_UP | BUTTON_REL:
303#else 720 /* Drop out of this loop (when ON btn released) */
304 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REL:
305 case BUTTON_ON | BUTTON_LEFT | BUTTON_REL:
306 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT | BUTTON_REL:
307 case BUTTON_ON | BUTTON_MENU | BUTTON_LEFT | BUTTON_REL:
308#endif
309 exit = true; 721 exit = true;
310 break; 722 break;
311 } 723 }
312 if ( !exit )
313 viewer_draw(col);
314 } 724 }
315
316 return col; 725 return col;
317} 726}
727#endif
318 728
319enum plugin_status plugin_start(struct plugin_api* api, void* file) 729enum plugin_status plugin_start(struct plugin_api* api, void* file)
320{ 730{
321 bool exit=false; 731 bool exit=false;
322 int button;
323 int col = 0; 732 int col = 0;
733 int i;
324 int ok; 734 int ok;
325 735
326 TEST_PLUGIN_API(api); 736 TEST_PLUGIN_API(api);
@@ -337,13 +747,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
337 } 747 }
338 748
339 viewer_draw(col); 749 viewer_draw(col);
340 while (!exit) {
341 button = rb->button_get(true);
342
343 switch ( button ) {
344 750
751 while (!exit) {
752 switch (rb->button_get(true)) {
345#ifdef HAVE_RECORDER_KEYPAD 753#ifdef HAVE_RECORDER_KEYPAD
346 case BUTTON_F1:
347 case BUTTON_OFF: 754 case BUTTON_OFF:
348#else 755#else
349 case BUTTON_STOP: 756 case BUTTON_STOP:
@@ -353,13 +760,104 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
353 break; 760 break;
354 761
355#ifdef HAVE_RECORDER_KEYPAD 762#ifdef HAVE_RECORDER_KEYPAD
763 case BUTTON_F1:
764#else
765 case BUTTON_ON | BUTTON_LEFT:
766#endif
767 /* Word-wrap mode: WRAP or CHOP */
768 if (++word_mode == WORD_MODES)
769 word_mode = 0;
770
771#ifdef HAVE_LCD_BITMAP
772 init_need_scrollbar();
773#endif
774 viewer_draw(col);
775
776 rb->splash(HZ, 0, true, "%s %s",
777 word_mode_str[word_mode], word_mode_str[WORD_MODES]);
778
779 viewer_draw(col);
780 break;
781
782#ifdef HAVE_RECORDER_KEYPAD
783 case BUTTON_F2:
784#else
785 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT:
786#endif
787 /* Line-paragraph mode: NORMAL, JOIN or EXPAND */
788 if (++line_mode == LINE_MODES)
789 line_mode = 0;
790
791 if (view_mode == WIDE)
792 if (line_mode == JOIN)
793 if (++line_mode == LINE_MODES)
794 line_mode = 0;
795
796#ifdef HAVE_LCD_BITMAP
797 init_need_scrollbar();
798#endif
799 viewer_draw(col);
800
801 rb->splash(HZ, 0, true, "%s %s",
802 line_mode_str[line_mode], line_mode_str[LINE_MODES]);
803
804 viewer_draw(col);
805 break;
806
807#ifdef HAVE_RECORDER_KEYPAD
808 case BUTTON_F3:
809#else
810 case BUTTON_ON | BUTTON_RIGHT:
811#endif
812 /* View-width mode: NARROW or WIDE */
813 if (line_mode == JOIN)
814 rb->splash(HZ, 0, true, "(no %s %s)",
815 view_mode_str[WIDE], line_mode_str[JOIN]);
816 else
817 if (++view_mode == VIEW_MODES)
818 view_mode = 0;
819
820 col = 0;
821
822 /***** Could do this after change of word-wrap mode
823 * and after change of view-width mode, to normalize
824 * view:
825 if (screen_top_ptr > buffer + BUFFER_SIZE/2) {
826 screen_top_ptr = find_prev_line(screen_top_ptr);
827 screen_top_ptr = find_next_line(screen_top_ptr);
828 }
829 else {
830 screen_top_ptr = find_next_line(screen_top_ptr);
831 screen_top_ptr = find_prev_line(screen_top_ptr);
832 }
833 ***********/
834
835#ifdef HAVE_LCD_BITMAP
836 init_need_scrollbar();
837#endif
838 viewer_draw(col);
839
840 rb->splash(HZ, 0, true, "%s %s",
841 view_mode_str[view_mode], view_mode_str[VIEW_MODES]);
842
843 viewer_draw(col);
844 break;
845
846#ifdef HAVE_RECORDER_KEYPAD
356 case BUTTON_UP: 847 case BUTTON_UP:
357 case BUTTON_UP | BUTTON_REPEAT: 848 case BUTTON_UP | BUTTON_REPEAT:
358#else 849#else
359 case BUTTON_LEFT: 850 case BUTTON_LEFT:
360 case BUTTON_LEFT | BUTTON_REPEAT: 851 case BUTTON_LEFT | BUTTON_REPEAT:
361#endif 852#endif
362 viewer_scroll_up(); 853 /* Page up */
854#ifdef HAVE_LCD_BITMAP
855 for (i = page_mode==OVERLAP? 1:0; i < display_lines; i++)
856#else
857 for (i = 0; i < display_lines; i++)
858#endif
859 viewer_scroll_up();
860
363 viewer_draw(col); 861 viewer_draw(col);
364 break; 862 break;
365 863
@@ -370,7 +868,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
370 case BUTTON_RIGHT: 868 case BUTTON_RIGHT:
371 case BUTTON_RIGHT | BUTTON_REPEAT: 869 case BUTTON_RIGHT | BUTTON_REPEAT:
372#endif 870#endif
373 viewer_scroll_down(); 871 /* Page down */
872 if (next_screen_ptr != NULL)
873 screen_top_ptr = next_screen_to_draw_ptr;
874
374 viewer_draw(col); 875 viewer_draw(col);
375 break; 876 break;
376 877
@@ -381,9 +882,16 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
381 case BUTTON_MENU | BUTTON_LEFT: 882 case BUTTON_MENU | BUTTON_LEFT:
382 case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT: 883 case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT:
383#endif 884#endif
384 col--; 885 if (view_mode == WIDE) {
385 if (col < 0) 886 /* Screen left */
386 col = 0; 887 col -= display_columns;
888 col = col_limit(col);
889 }
890 else { /* view_mode == NARROW */
891 /* Top of file */
892 viewer_top();
893 }
894
387 viewer_draw(col); 895 viewer_draw(col);
388 break; 896 break;
389 897
@@ -394,18 +902,28 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
394 case BUTTON_MENU | BUTTON_RIGHT: 902 case BUTTON_MENU | BUTTON_RIGHT:
395 case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT: 903 case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT:
396#endif 904#endif
397 col++; 905 if (view_mode == WIDE) {
906 /* Screen right */
907 col += display_columns;
908 col = col_limit(col);
909 }
910 else { /* view_mode == NARROW */
911 /* Bottom of file */
912 viewer_bottom();
913 }
914
398 viewer_draw(col); 915 viewer_draw(col);
399 break; 916 break;
400 917
918#ifdef HAVE_RECORDER_KEYPAD
401 case BUTTON_ON: 919 case BUTTON_ON:
402#ifdef HAVE_PLAYER_KEYPAD 920 /*Go to On-btn combinations */
403 case BUTTON_ON | BUTTON_MENU: 921 col = viewer_recorder_on_button(col);
404#endif
405 col = pagescroll(col);
406 break; 922 break;
923#endif
407 924
408 case SYS_USB_CONNECTED: 925 case SYS_USB_CONNECTED:
926 /* Release control to USB functions */
409 rb->usb_screen(); 927 rb->usb_screen();
410 viewer_exit(); 928 viewer_exit();
411 return PLUGIN_USB_CONNECTED; 929 return PLUGIN_USB_CONNECTED;