* removed some more unused stuff in the simulator makefile
[kugel-rb.git] / apps / plugins / viewer.c
blobd8d6b516bd81202554c59c94b679bf296d8409da
1 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
11 * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
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.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #include "plugin.h"
22 #ifdef HAVE_LCD_BITMAP
23 #include "recorder/widgets.h"
24 #endif
26 #include <ctype.h>
28 #ifndef SIMULATOR
29 #include <ctype.c>
30 #endif
32 #if PLUGIN_API_VERSION < 3
33 #error Scrollbar function requires PLUGIN_API_VERSION 3 at least
34 #endif
36 #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
37 #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */
38 #define MAX_WIDTH 910 /* Max line length in WIDE mode */
39 #define READ_PREV_ZONE 910 /* Arbitrary number less than SMALL_BLOCK_SIZE */
40 #define SMALL_BLOCK_SIZE 0x1000 /* 4k: Smallest file chunk we will read */
41 #define LARGE_BLOCK_SIZE 0x2000 /* 8k: Preferable size of file chunk to read */
42 #define BUFFER_SIZE 0x3000 /* 12k: Mem reserved for buffered file data */
43 #define TOP_SECTOR buffer
44 #define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
45 #define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
47 /* Out-Of-Bounds test for any pointer to data in the buffer */
48 #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
50 /* Does the buffer contain the beginning of the file? */
51 #define BUFFER_BOF() (file_pos==0)
53 /* Does the buffer contain the end of the file? */
54 #define BUFFER_EOF() (file_size-file_pos <= BUFFER_SIZE)
56 /* Formula for the endpoint address outside of buffer data */
57 #define BUFFER_END() \
58 ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+BUFFER_SIZE))
60 /* Is the entire file being shown in one screen? */
61 #define ONE_SCREEN_FITS_ALL() \
62 (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF())
64 /* Is a scrollbar called for on the current screen? */
65 #define NEED_SCROLLBAR() ((!(ONE_SCREEN_FITS_ALL())) && \
66 (view_mode==WIDE? scrollbar_mode[WIDE]==SB_ON: scrollbar_mode[NARROW]==SB_ON))
68 enum {
69 WRAP=0,
70 CHOP,
71 WORD_MODES
72 } word_mode = 0;
73 static unsigned char *word_mode_str[] = {"wrap", "chop", "words"};
75 enum {
76 NORMAL=0,
77 JOIN,
78 EXPAND,
79 LINE_MODES
80 } line_mode = 0;
81 static unsigned char *line_mode_str[] = {"normal", "join", "expand", "lines"};
83 enum {
84 NARROW=0,
85 WIDE,
86 VIEW_MODES
87 } view_mode = 0;
88 static unsigned char *view_mode_str[] = {"narrow", "wide", "view"};
90 #ifdef HAVE_LCD_BITMAP
91 enum {
92 SB_OFF=0,
93 SB_ON,
94 SCROLLBAR_MODES
95 } scrollbar_mode[VIEW_MODES] = {SB_OFF, SB_ON};
96 static unsigned char *scrollbar_mode_str[] = {"off", "on", "scrollbar"};
97 static bool need_scrollbar;
98 enum {
99 NO_OVERLAP=0,
100 OVERLAP,
101 PAGE_MODES
102 } page_mode = 0;
103 static unsigned char *page_mode_str[] = {"don't overlap", "overlap", "pages"};
104 #endif
106 static unsigned char buffer[BUFFER_SIZE + 1];
107 static unsigned char line_break[] = {0,0x20,'-',9,0xB,0xC};
108 static int display_columns; /* number of columns on the display */
109 static int display_lines; /* number of lines on the display */
110 static int fd;
111 static long file_size;
112 static bool mac_text;
113 static long file_pos; /* Position of the top of the buffer in the file */
114 static unsigned char *buffer_end; /*Set to BUFFER_END() when file_pos changes*/
115 static int max_line_len;
116 static unsigned char *screen_top_ptr;
117 static unsigned char *next_screen_ptr;
118 static unsigned char *next_screen_to_draw_ptr;
119 static unsigned char *next_line_ptr;
120 static struct plugin_api* rb;
122 static unsigned char* find_first_feed(const unsigned char* p, int size)
124 int i;
126 for (i=0; i < size; i++)
127 if (p[i] == 0)
128 return (unsigned char*) p+i;
130 return NULL;
133 static unsigned char* find_last_feed(const unsigned char* p, int size)
135 int i;
137 for (i=size-1; i>=0; i--)
138 if (p[i] == 0)
139 return (unsigned char*) p+i;
141 return NULL;
144 static unsigned char* find_last_space(const unsigned char* p, int size)
146 int i, j, k;
148 k = line_mode==JOIN? 0:1;
150 for (i=size-1; i>=0; i--)
151 for (j=k; j < (int) sizeof(line_break); j++)
152 if (p[i] == line_break[j])
153 return (unsigned char*) p+i;
155 return NULL;
158 static unsigned char* find_next_line(const unsigned char* cur_line)
160 const unsigned char *next_line = NULL;
161 int size, i, j, k, chop_len, search_len, spaces, newlines, draw_columns;
162 unsigned char c;
164 if BUFFER_OOB(cur_line)
165 return NULL;
167 #ifdef HAVE_LCD_BITMAP
168 draw_columns = need_scrollbar? display_columns-1: display_columns;
169 #else
170 draw_columns = display_columns;
171 #endif
173 if (view_mode == WIDE) {
174 search_len = chop_len = MAX_WIDTH;
176 else { /* view_mode == NARROW */
177 chop_len = draw_columns;
178 search_len = chop_len + 1;
181 size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len;
183 if (line_mode == JOIN) {
184 /* Need to scan ahead and possibly increase search_len and size,
185 or possibly set next_line at second hard return in a row. */
186 next_line = NULL;
187 for (j=k=spaces=newlines=0; j < size; j++) {
188 if (k == MAX_COLUMNS)
189 break;
191 c = cur_line[j];
192 switch (c) {
193 case ' ':
194 spaces++;
195 break;
197 case 0:
198 if (newlines > 0) {
199 size = j;
200 next_line = cur_line + size - spaces - 1;
201 if (next_line != cur_line)
202 return (unsigned char*) next_line;
203 break;
205 newlines++;
206 size += spaces;
207 if (BUFFER_OOB(cur_line+size) || size > 2*search_len)
208 return NULL;
210 search_len = size;
211 spaces = 0;
212 k++;
213 break;
215 default:
216 newlines = 0;
217 while (spaces) {
218 spaces--;
219 k++;
220 if (k == MAX_COLUMNS - 1)
221 break;
223 k++;
224 break;
228 else {
229 /* find first hard return */
230 next_line = find_first_feed(cur_line, size);
233 if (next_line == NULL)
234 if (size == search_len) {
235 if (word_mode == WRAP) /* Find last space */
236 next_line = find_last_space(cur_line, size);
238 if (next_line == NULL)
239 next_line = cur_line + chop_len;
240 else
241 if (word_mode == WRAP)
242 for (i=0;
243 i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line);
244 i++)
245 next_line++;
248 if (line_mode == EXPAND)
249 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
250 if (next_line[0] == 0)
251 if (next_line != cur_line)
252 return (unsigned char*) next_line;
254 /* If next_line is pointing to a zero, increment it; i.e.,
255 leave the terminator at the end of cur_line. If pointing
256 to a hyphen, increment only if there is room to display
257 the hyphen on current line (won't apply in WIDE mode,
258 since it's guarenteed there won't be room). */
259 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
260 if (next_line[0] == 0 ||
261 (next_line[0] == '-' && next_line-cur_line < draw_columns))
262 next_line++;
264 if (BUFFER_OOB(next_line))
265 return NULL;
267 return (unsigned char*) next_line;
270 static unsigned char* find_prev_line(const unsigned char* cur_line)
272 const unsigned char *prev_line = NULL;
273 const unsigned char *p;
275 if BUFFER_OOB(cur_line)
276 return NULL;
278 /* To wrap consistently at the same places, we must
279 start with a known hard return, then work downwards.
280 We can either search backwards for a hard return,
281 or simply start wrapping downwards from top of buffer.
282 If current line is not near top of buffer, this is
283 a file with long lines (paragraphs). We would need to
284 read earlier sectors before we could decide how to
285 properly wrap the lines above the current line, but
286 it probably is not worth the disk access. Instead,
287 start with top of buffer and wrap down from there.
288 This may result in some lines wrapping at different
289 points from where they wrap when scrolling down.
290 If buffer is at top of file, start at top of buffer. */
292 if (line_mode == JOIN)
293 prev_line = p = NULL;
294 else
295 prev_line = p = find_last_feed(buffer, cur_line-buffer-1);
296 /* Null means no line feeds in buffer above current line. */
298 if (prev_line == NULL)
299 if (BUFFER_BOF() || cur_line - buffer > READ_PREV_ZONE)
300 prev_line = p = buffer;
301 /* (else return NULL and read previous block) */
303 /* Wrap downwards until too far, then use the one before. */
304 while (p < cur_line && p != NULL) {
305 prev_line = p;
306 p = find_next_line(prev_line);
309 if (BUFFER_OOB(prev_line))
310 return NULL;
312 return (unsigned char*) prev_line;
315 static void fill_buffer(long pos, unsigned char* buf, unsigned size)
317 /* Read from file and preprocess the data */
318 /* To minimize disk access, always read on sector boundaries */
319 unsigned numread, i;
320 bool found_CR = false;
322 rb->lseek(fd, pos, SEEK_SET);
323 numread = rb->read(fd, buf, size);
324 while (rb->button_get(false)); /* clear button queue */
326 for(i = 0; i < numread; i++) {
327 switch(buf[i]) {
328 case '\r':
329 if (mac_text) {
330 buf[i] = 0;
332 else {
333 buf[i] = ' ';
334 found_CR = true;
336 break;
338 case '\n':
339 buf[i] = 0;
340 found_CR = false;
341 break;
343 case 0: /* No break between case 0 and default, intentionally */
344 buf[i] = ' ';
345 default:
346 if (found_CR) {
347 buf[i - 1] = 0;
348 found_CR = false;
349 mac_text = true;
351 break;
356 static int read_and_synch(int direction)
358 /* Read next (or prev) block, and reposition global pointers. */
359 /* direction: 1 for down (i.e., further into file), -1 for up */
360 int move_size, move_vector, offset;
361 unsigned char *fill_buf;
363 if (direction == -1) /* up */ {
364 move_size = SMALL_BLOCK_SIZE;
365 offset = 0;
366 fill_buf = TOP_SECTOR;
367 rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
368 rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE);
370 else /* down */ {
371 if (view_mode == WIDE) {
372 /* WIDE mode needs more buffer so we have to read smaller blocks */
373 move_size = SMALL_BLOCK_SIZE;
374 offset = LARGE_BLOCK_SIZE;
375 fill_buf = BOTTOM_SECTOR;
376 rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE);
377 rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
379 else {
380 move_size = LARGE_BLOCK_SIZE;
381 offset = SMALL_BLOCK_SIZE;
382 fill_buf = MID_SECTOR;
383 rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE);
386 move_vector = direction * move_size;
387 screen_top_ptr -= move_vector;
388 file_pos += move_vector;
389 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
390 fill_buffer(file_pos + offset, fill_buf, move_size);
391 return move_vector;
394 static void viewer_scroll_up(void)
396 unsigned char *p;
398 p = find_prev_line(screen_top_ptr);
399 if (p == NULL && !BUFFER_BOF()) {
400 read_and_synch(-1);
401 p = find_prev_line(screen_top_ptr);
403 if (p != NULL)
404 screen_top_ptr = p;
407 #ifdef HAVE_LCD_BITMAP
408 static void viewer_scrollbar(void) {
409 int w, h, items, min_shown, max_shown;
411 rb->lcd_getstringsize("o", &w, &h);
412 items = (int) file_size; /* (SH1 int is same as long) */
413 min_shown = (int) file_pos + (screen_top_ptr - buffer);
415 if (next_screen_ptr == NULL)
416 max_shown = items;
417 else
418 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
420 rb->scrollbar(0, 0, w-1, LCD_HEIGHT, items, min_shown, max_shown, VERTICAL);
422 #endif
424 static void viewer_draw(int col)
426 int i, j, k, line_len, resynch_move, spaces, left_col=0;
427 unsigned char *line_begin;
428 unsigned char *line_end;
429 unsigned char c;
430 unsigned char scratch_buffer[MAX_COLUMNS + 1];
432 /* If col==-1 do all calculations but don't display */
433 if (col != -1) {
434 #ifdef HAVE_LCD_BITMAP
435 left_col = need_scrollbar? 1:0;
436 #else
437 left_col = 0;
438 #endif
439 rb->lcd_clear_display();
441 max_line_len = 0;
442 line_begin = line_end = screen_top_ptr;
444 for (i = 0; i < display_lines; i++) {
445 if (BUFFER_OOB(line_end))
446 break; /* Happens after display last line at BUFFER_EOF() */
448 line_begin = line_end;
449 line_end = find_next_line(line_begin);
451 if (line_end == NULL) {
452 if (BUFFER_EOF()) {
453 if (i < display_lines - 1 && !BUFFER_BOF()) {
454 if (col != -1)
455 rb->lcd_clear_display();
457 for (; i < display_lines - 1; i++)
458 viewer_scroll_up();
460 line_begin = line_end = screen_top_ptr;
461 i = -1;
462 continue;
464 else {
465 line_end = buffer_end;
468 else {
469 resynch_move = read_and_synch(1); /* Read block & move ptrs */
470 line_begin -= resynch_move;
471 if (i > 0)
472 next_line_ptr -= resynch_move;
474 line_end = find_next_line(line_begin);
475 if (line_end == NULL) /* Should not really happen */
476 break;
479 line_len = line_end - line_begin;
481 if (line_mode == JOIN) {
482 if (line_begin[0] == 0) {
483 line_begin++;
484 if (word_mode == CHOP)
485 line_end++;
487 for (j=k=spaces=0; j < line_len; j++) {
488 if (k == MAX_COLUMNS)
489 break;
491 c = line_begin[j];
492 switch (c) {
493 case ' ':
494 spaces++;
495 break;
496 case 0:
497 spaces = 0;
498 scratch_buffer[k++] = ' ';
499 break;
500 default:
501 while (spaces) {
502 spaces--;
503 scratch_buffer[k++] = ' ';
504 if (k == MAX_COLUMNS - 1)
505 break;
507 scratch_buffer[k++] = c;
508 break;
511 if (col != -1)
512 if (k > col) {
513 scratch_buffer[k] = 0;
514 rb->lcd_puts(left_col, i, scratch_buffer + col);
517 else {
518 if (col != -1)
519 if (line_len > col) {
520 c = line_end[0];
521 line_end[0] = 0;
522 rb->lcd_puts(left_col, i, line_begin + col);
523 line_end[0] = c;
526 if (line_len > max_line_len)
527 max_line_len = line_len;
529 if (i == 0)
530 next_line_ptr = line_end;
532 next_screen_ptr = line_end;
533 if (BUFFER_OOB(next_screen_ptr))
534 next_screen_ptr = NULL;
536 #ifdef HAVE_LCD_BITMAP
537 next_screen_to_draw_ptr = page_mode==OVERLAP? line_begin: next_screen_ptr;
539 if (need_scrollbar)
540 viewer_scrollbar();
542 if (col != -1)
543 rb->lcd_update();
544 #else
545 next_screen_to_draw_ptr = next_screen_ptr;
546 #endif
549 static void viewer_top(void)
551 /* Read top of file into buffer
552 and point screen pointer to top */
553 file_pos = 0;
554 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
555 screen_top_ptr = buffer;
556 fill_buffer(0, buffer, BUFFER_SIZE);
559 static void viewer_bottom(void)
561 /* Read bottom of file into buffer
562 and point screen pointer to bottom */
563 long last_sectors;
565 if (file_size > BUFFER_SIZE) {
566 /* Find last buffer in file, round up to next sector boundary */
567 last_sectors = file_size - BUFFER_SIZE + SMALL_BLOCK_SIZE;
568 last_sectors /= SMALL_BLOCK_SIZE;
569 last_sectors *= SMALL_BLOCK_SIZE;
571 else {
572 last_sectors = 0;
574 file_pos = last_sectors;
575 buffer_end = BUFFER_END(); /* Update whenever file_pos changes */
576 screen_top_ptr = buffer_end-1;
577 fill_buffer(last_sectors, buffer, BUFFER_SIZE);
580 #ifdef HAVE_LCD_BITMAP
581 static void init_need_scrollbar(void) {
582 /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
583 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
584 viewer_draw(-1);
585 need_scrollbar = NEED_SCROLLBAR();
587 #endif
589 static bool viewer_init(char* file)
591 #ifdef HAVE_LCD_BITMAP
592 int w,h;
594 rb->lcd_getstringsize("o", &w, &h);
595 display_lines = LCD_HEIGHT / h;
596 display_columns = LCD_WIDTH / w;
597 #else
598 display_lines = 2;
599 display_columns = 11;
600 #endif
601 /*********************
602 * (Could re-initialize settings here, if you
603 * wanted viewer to start the same way every time)
604 word_mode = WRAP;
605 line_mode = NORMAL;
606 view_mode = NARROW;
607 #ifdef HAVE_LCD_BITMAP
608 page_mode = NO_OVERLAP;
609 scrollbar_mode[NARROW] = SB_OFF;
610 scrollbar_mode[WIDE] = SB_ON;
611 #endif
612 **********************/
614 fd = rb->open(file, O_RDONLY);
615 if (fd==-1)
616 return false;
618 file_size = rb->filesize(fd);
619 if (file_size==-1)
620 return false;
622 /* Init mac_text value used in processing buffer */
623 mac_text = false;
625 /* Read top of file into buffer;
626 init file_pos, buffer_end, screen_top_ptr */
627 viewer_top();
629 #ifdef HAVE_LCD_BITMAP
630 /* Init need_scrollbar value */
631 init_need_scrollbar();
632 #endif
634 return true;
637 static void viewer_exit(void)
639 rb->close(fd);
642 static int col_limit(int col)
644 if (col < 0)
645 col = 0;
646 else
647 if (col > max_line_len - 2)
648 col = max_line_len - 2;
650 return col;
653 #ifdef HAVE_LCD_BITMAP
654 static int viewer_recorder_on_button(int col)
656 bool exit = false;
658 while (!exit) {
659 switch (rb->button_get(true)) {
660 case BUTTON_ON | BUTTON_F1:
661 /* Page-overlap mode */
662 if (++page_mode == PAGE_MODES)
663 page_mode = 0;
665 rb->splash(HZ, true, "%s %s",
666 page_mode_str[page_mode],
667 page_mode_str[PAGE_MODES]);
669 viewer_draw(col);
670 break;
672 case BUTTON_ON | BUTTON_F3:
673 /* Show-scrollbar mode for current view-width mode */
674 if (!(ONE_SCREEN_FITS_ALL())) {
675 if (++scrollbar_mode[view_mode] == SCROLLBAR_MODES)
676 scrollbar_mode[view_mode] = 0;
678 init_need_scrollbar();
679 viewer_draw(col);
681 rb->splash(HZ, true, "%s %s (%s %s)",
682 scrollbar_mode_str[SCROLLBAR_MODES],
683 scrollbar_mode_str[scrollbar_mode[view_mode]],
684 view_mode_str[view_mode],
685 view_mode_str[VIEW_MODES]);
687 viewer_draw(col);
688 break;
690 case BUTTON_ON | BUTTON_UP:
691 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
692 /* Scroll up one line */
693 viewer_scroll_up();
694 viewer_draw(col);
695 break;
697 case BUTTON_ON | BUTTON_DOWN:
698 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
699 /* Scroll down one line */
700 if (next_screen_ptr != NULL)
701 screen_top_ptr = next_line_ptr;
703 viewer_draw(col);
704 break;
706 case BUTTON_ON | BUTTON_LEFT:
707 case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT:
708 /* Scroll left one column */
709 col--;
710 col = col_limit(col);
711 viewer_draw(col);
712 break;
714 case BUTTON_ON | BUTTON_RIGHT:
715 case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT:
716 /* Scroll right one column */
717 col++;
718 col = col_limit(col);
719 viewer_draw(col);
720 break;
722 case BUTTON_ON | BUTTON_REL:
723 case BUTTON_ON | BUTTON_DOWN | BUTTON_REL:
724 case BUTTON_ON | BUTTON_UP | BUTTON_REL:
725 /* Drop out of this loop (when ON btn released) */
726 exit = true;
727 break;
730 return col;
732 #endif
734 enum plugin_status plugin_start(struct plugin_api* api, void* file)
736 bool exit=false;
737 int col = 0;
738 int i;
739 int ok;
741 TEST_PLUGIN_API(api);
742 rb = api;
744 if (!file)
745 return PLUGIN_ERROR;
747 ok = viewer_init(file);
748 if (!ok) {
749 rb->splash(HZ, false, "Error");
750 viewer_exit();
751 return PLUGIN_OK;
754 viewer_draw(col);
756 while (!exit) {
757 switch (rb->button_get(true)) {
758 #ifdef HAVE_RECORDER_KEYPAD
759 case BUTTON_OFF:
760 #else
761 case BUTTON_STOP:
762 #endif
763 viewer_exit();
764 exit = true;
765 break;
767 #ifdef HAVE_RECORDER_KEYPAD
768 case BUTTON_F1:
769 #else
770 case BUTTON_ON | BUTTON_LEFT:
771 #endif
772 /* Word-wrap mode: WRAP or CHOP */
773 if (++word_mode == WORD_MODES)
774 word_mode = 0;
776 #ifdef HAVE_LCD_BITMAP
777 init_need_scrollbar();
778 #endif
779 viewer_draw(col);
781 rb->splash(HZ, true, "%s %s",
782 word_mode_str[word_mode],
783 word_mode_str[WORD_MODES]);
785 viewer_draw(col);
786 break;
788 #ifdef HAVE_RECORDER_KEYPAD
789 case BUTTON_F2:
790 #else
791 case BUTTON_ON | BUTTON_MENU | BUTTON_RIGHT:
792 #endif
793 /* Line-paragraph mode: NORMAL, JOIN or EXPAND */
794 if (++line_mode == LINE_MODES)
795 line_mode = 0;
797 if (view_mode == WIDE)
798 if (line_mode == JOIN)
799 if (++line_mode == LINE_MODES)
800 line_mode = 0;
802 #ifdef HAVE_LCD_BITMAP
803 init_need_scrollbar();
804 #endif
805 viewer_draw(col);
807 rb->splash(HZ, true, "%s %s",
808 line_mode_str[line_mode],
809 line_mode_str[LINE_MODES]);
811 viewer_draw(col);
812 break;
814 #ifdef HAVE_RECORDER_KEYPAD
815 case BUTTON_F3:
816 #else
817 case BUTTON_ON | BUTTON_RIGHT:
818 #endif
819 /* View-width mode: NARROW or WIDE */
820 if (line_mode == JOIN)
821 rb->splash(HZ, true, "(no %s %s)",
822 view_mode_str[WIDE],
823 line_mode_str[JOIN]);
824 else
825 if (++view_mode == VIEW_MODES)
826 view_mode = 0;
828 col = 0;
830 /***** Could do this after change of word-wrap mode
831 * and after change of view-width mode, to normalize
832 * view:
833 if (screen_top_ptr > buffer + BUFFER_SIZE/2) {
834 screen_top_ptr = find_prev_line(screen_top_ptr);
835 screen_top_ptr = find_next_line(screen_top_ptr);
837 else {
838 screen_top_ptr = find_next_line(screen_top_ptr);
839 screen_top_ptr = find_prev_line(screen_top_ptr);
841 ***********/
843 #ifdef HAVE_LCD_BITMAP
844 init_need_scrollbar();
845 #endif
846 viewer_draw(col);
848 rb->splash(HZ, true, "%s %s",
849 view_mode_str[view_mode],
850 view_mode_str[VIEW_MODES]);
852 viewer_draw(col);
853 break;
855 #ifdef HAVE_RECORDER_KEYPAD
856 case BUTTON_UP:
857 case BUTTON_UP | BUTTON_REPEAT:
858 #else
859 case BUTTON_LEFT:
860 case BUTTON_LEFT | BUTTON_REPEAT:
861 #endif
862 /* Page up */
863 #ifdef HAVE_LCD_BITMAP
864 for (i = page_mode==OVERLAP? 1:0; i < display_lines; i++)
865 #else
866 for (i = 0; i < display_lines; i++)
867 #endif
868 viewer_scroll_up();
870 viewer_draw(col);
871 break;
873 #ifdef HAVE_RECORDER_KEYPAD
874 case BUTTON_DOWN:
875 case BUTTON_DOWN | BUTTON_REPEAT:
876 #else
877 case BUTTON_RIGHT:
878 case BUTTON_RIGHT | BUTTON_REPEAT:
879 #endif
880 /* Page down */
881 if (next_screen_ptr != NULL)
882 screen_top_ptr = next_screen_to_draw_ptr;
884 viewer_draw(col);
885 break;
887 #ifdef HAVE_RECORDER_KEYPAD
888 case BUTTON_LEFT:
889 case BUTTON_LEFT | BUTTON_REPEAT:
890 #else
891 case BUTTON_MENU | BUTTON_LEFT:
892 case BUTTON_MENU | BUTTON_LEFT | BUTTON_REPEAT:
893 #endif
894 if (view_mode == WIDE) {
895 /* Screen left */
896 col -= display_columns;
897 col = col_limit(col);
899 else { /* view_mode == NARROW */
900 /* Top of file */
901 viewer_top();
904 viewer_draw(col);
905 break;
907 #ifdef HAVE_RECORDER_KEYPAD
908 case BUTTON_RIGHT:
909 case BUTTON_RIGHT | BUTTON_REPEAT:
910 #else
911 case BUTTON_MENU | BUTTON_RIGHT:
912 case BUTTON_MENU | BUTTON_RIGHT | BUTTON_REPEAT:
913 #endif
914 if (view_mode == WIDE) {
915 /* Screen right */
916 col += display_columns;
917 col = col_limit(col);
919 else { /* view_mode == NARROW */
920 /* Bottom of file */
921 viewer_bottom();
924 viewer_draw(col);
925 break;
927 #ifdef HAVE_RECORDER_KEYPAD
928 case BUTTON_ON:
929 /*Go to On-btn combinations */
930 col = viewer_recorder_on_button(col);
931 break;
932 #endif
934 case SYS_USB_CONNECTED:
935 /* Release control to USB functions */
936 rb->usb_screen();
937 viewer_exit();
938 return PLUGIN_USB_CONNECTED;
941 return PLUGIN_OK;